blob: 4c05747cf6c6be18537f15bffa5973816a921735 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00006 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00007 *
8 * 14 Nov 2000 ht - Changed the name of function xmlBufferWriteChar under VMS
9 * as it was similar to xmlBufferWriteCHAR when compiling without case
10 * sensitivity.
11 *
12 */
13
Daniel Veillard34ce8be2002-03-18 19:37:11 +000014#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000015#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000016
Owen Taylor3473f882001-02-23 17:55:21 +000017#include <string.h> /* for memset() only ! */
18
19#ifdef HAVE_CTYPE_H
20#include <ctype.h>
21#endif
22#ifdef HAVE_STDLIB_H
23#include <stdlib.h>
24#endif
25#ifdef HAVE_ZLIB_H
26#include <zlib.h>
27#endif
28
29#include <libxml/xmlmemory.h>
30#include <libxml/tree.h>
31#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000032#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000033#include <libxml/entities.h>
34#include <libxml/valid.h>
35#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000036#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000037#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000038
Daniel Veillard56a4cb82001-03-24 17:00:36 +000039xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
40
41/************************************************************************
42 * *
43 * A few static variables and macros *
44 * *
45 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000046/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000047const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000048/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000049const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000050 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000051/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +000052const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
53
Owen Taylor3473f882001-02-23 17:55:21 +000054static int xmlCompressMode = 0;
55static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000056
Owen Taylor3473f882001-02-23 17:55:21 +000057#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
58 xmlNodePtr ulccur = (n)->children; \
59 if (ulccur == NULL) { \
60 (n)->last = NULL; \
61 } else { \
62 while (ulccur->next != NULL) { \
63 ulccur->parent = (n); \
64 ulccur = ulccur->next; \
65 } \
66 ulccur->parent = (n); \
67 (n)->last = ulccur; \
68}}
69
70/* #define DEBUG_BUFFER */
71/* #define DEBUG_TREE */
72
73/************************************************************************
74 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +000075 * Functions to move to entities.c once the *
76 * API freeze is smoothen and they can be made public. *
77 * *
78 ************************************************************************/
79#include <libxml/hash.h>
80
81/**
82 * xmlGetEntityFromDtd:
83 * @dtd: A pointer to the DTD to search
84 * @name: The entity name
85 *
86 * Do an entity lookup in the DTD entity hash table and
87 * return the corresponding entity, if found.
88 *
89 * Returns A pointer to the entity structure or NULL if not found.
90 */
91static xmlEntityPtr
92xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
93 xmlEntitiesTablePtr table;
94
95 if((dtd != NULL) && (dtd->entities != NULL)) {
96 table = (xmlEntitiesTablePtr) dtd->entities;
97 return((xmlEntityPtr) xmlHashLookup(table, name));
98 /* return(xmlGetEntityFromTable(table, name)); */
99 }
100 return(NULL);
101}
102/**
103 * xmlGetParameterEntityFromDtd:
104 * @dtd: A pointer to the DTD to search
105 * @name: The entity name
106 *
107 * Do an entity lookup in the DTD pararmeter entity hash table and
108 * return the corresponding entity, if found.
109 *
110 * Returns A pointer to the entity structure or NULL if not found.
111 */
112static xmlEntityPtr
113xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
114 xmlEntitiesTablePtr table;
115
116 if ((dtd != NULL) && (dtd->pentities != NULL)) {
117 table = (xmlEntitiesTablePtr) dtd->pentities;
118 return((xmlEntityPtr) xmlHashLookup(table, name));
119 /* return(xmlGetEntityFromTable(table, name)); */
120 }
121 return(NULL);
122}
123
124/************************************************************************
125 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000126 * Allocation and deallocation of basic structures *
127 * *
128 ************************************************************************/
129
130/**
131 * xmlSetBufferAllocationScheme:
132 * @scheme: allocation method to use
133 *
134 * Set the buffer allocation method. Types are
135 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
136 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
137 * improves performance
138 */
139void
140xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
141 xmlBufferAllocScheme = scheme;
142}
143
144/**
145 * xmlGetBufferAllocationScheme:
146 *
147 * Types are
148 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
149 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
150 * improves performance
151 *
152 * Returns the current allocation scheme
153 */
154xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000155xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000156 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000157}
158
159/**
160 * xmlNewNs:
161 * @node: the element carrying the namespace
162 * @href: the URI associated
163 * @prefix: the prefix for the namespace
164 *
165 * Creation of a new Namespace. This function will refuse to create
166 * a namespace with a similar prefix than an existing one present on this
167 * node.
168 * We use href==NULL in the case of an element creation where the namespace
169 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000170 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000171 */
172xmlNsPtr
173xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
174 xmlNsPtr cur;
175
176 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
177 return(NULL);
178
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000179 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
180 return(NULL);
181
Owen Taylor3473f882001-02-23 17:55:21 +0000182 /*
183 * Allocate a new Namespace and fill the fields.
184 */
185 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
186 if (cur == NULL) {
187 xmlGenericError(xmlGenericErrorContext,
188 "xmlNewNs : malloc failed\n");
189 return(NULL);
190 }
191 memset(cur, 0, sizeof(xmlNs));
192 cur->type = XML_LOCAL_NAMESPACE;
193
194 if (href != NULL)
195 cur->href = xmlStrdup(href);
196 if (prefix != NULL)
197 cur->prefix = xmlStrdup(prefix);
198
199 /*
200 * Add it at the end to preserve parsing order ...
201 * and checks for existing use of the prefix
202 */
203 if (node != NULL) {
204 if (node->nsDef == NULL) {
205 node->nsDef = cur;
206 } else {
207 xmlNsPtr prev = node->nsDef;
208
209 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
210 (xmlStrEqual(prev->prefix, cur->prefix))) {
211 xmlFreeNs(cur);
212 return(NULL);
213 }
214 while (prev->next != NULL) {
215 prev = prev->next;
216 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
217 (xmlStrEqual(prev->prefix, cur->prefix))) {
218 xmlFreeNs(cur);
219 return(NULL);
220 }
221 }
222 prev->next = cur;
223 }
224 }
225 return(cur);
226}
227
228/**
229 * xmlSetNs:
230 * @node: a node in the document
231 * @ns: a namespace pointer
232 *
233 * Associate a namespace to a node, a posteriori.
234 */
235void
236xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
237 if (node == NULL) {
238#ifdef DEBUG_TREE
239 xmlGenericError(xmlGenericErrorContext,
240 "xmlSetNs: node == NULL\n");
241#endif
242 return;
243 }
244 node->ns = ns;
245}
246
247/**
248 * xmlFreeNs:
249 * @cur: the namespace pointer
250 *
251 * Free up the structures associated to a namespace
252 */
253void
254xmlFreeNs(xmlNsPtr cur) {
255 if (cur == NULL) {
256#ifdef DEBUG_TREE
257 xmlGenericError(xmlGenericErrorContext,
258 "xmlFreeNs : ns == NULL\n");
259#endif
260 return;
261 }
262 if (cur->href != NULL) xmlFree((char *) cur->href);
263 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000264 xmlFree(cur);
265}
266
267/**
268 * xmlFreeNsList:
269 * @cur: the first namespace pointer
270 *
271 * Free up all the structures associated to the chained namespaces.
272 */
273void
274xmlFreeNsList(xmlNsPtr cur) {
275 xmlNsPtr next;
276 if (cur == NULL) {
277#ifdef DEBUG_TREE
278 xmlGenericError(xmlGenericErrorContext,
279 "xmlFreeNsList : ns == NULL\n");
280#endif
281 return;
282 }
283 while (cur != NULL) {
284 next = cur->next;
285 xmlFreeNs(cur);
286 cur = next;
287 }
288}
289
290/**
291 * xmlNewDtd:
292 * @doc: the document pointer
293 * @name: the DTD name
294 * @ExternalID: the external ID
295 * @SystemID: the system ID
296 *
297 * Creation of a new DTD for the external subset. To create an
298 * internal subset, use xmlCreateIntSubset().
299 *
300 * Returns a pointer to the new DTD structure
301 */
302xmlDtdPtr
303xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
304 const xmlChar *ExternalID, const xmlChar *SystemID) {
305 xmlDtdPtr cur;
306
307 if ((doc != NULL) && (doc->extSubset != NULL)) {
308#ifdef DEBUG_TREE
309 xmlGenericError(xmlGenericErrorContext,
310 "xmlNewDtd(%s): document %s already have a DTD %s\n",
311 /* !!! */ (char *) name, doc->name,
312 /* !!! */ (char *)doc->extSubset->name);
313#endif
314 return(NULL);
315 }
316
317 /*
318 * Allocate a new DTD and fill the fields.
319 */
320 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
321 if (cur == NULL) {
322 xmlGenericError(xmlGenericErrorContext,
323 "xmlNewDtd : malloc failed\n");
324 return(NULL);
325 }
326 memset(cur, 0 , sizeof(xmlDtd));
327 cur->type = XML_DTD_NODE;
328
329 if (name != NULL)
330 cur->name = xmlStrdup(name);
331 if (ExternalID != NULL)
332 cur->ExternalID = xmlStrdup(ExternalID);
333 if (SystemID != NULL)
334 cur->SystemID = xmlStrdup(SystemID);
335 if (doc != NULL)
336 doc->extSubset = cur;
337 cur->doc = doc;
338
339 return(cur);
340}
341
342/**
343 * xmlGetIntSubset:
344 * @doc: the document pointer
345 *
346 * Get the internal subset of a document
347 * Returns a pointer to the DTD structure or NULL if not found
348 */
349
350xmlDtdPtr
351xmlGetIntSubset(xmlDocPtr doc) {
352 xmlNodePtr cur;
353
354 if (doc == NULL)
355 return(NULL);
356 cur = doc->children;
357 while (cur != NULL) {
358 if (cur->type == XML_DTD_NODE)
359 return((xmlDtdPtr) cur);
360 cur = cur->next;
361 }
362 return((xmlDtdPtr) doc->intSubset);
363}
364
365/**
366 * xmlCreateIntSubset:
367 * @doc: the document pointer
368 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000369 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000370 * @SystemID: the system ID
371 *
372 * Create the internal subset of a document
373 * Returns a pointer to the new DTD structure
374 */
375xmlDtdPtr
376xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
377 const xmlChar *ExternalID, const xmlChar *SystemID) {
378 xmlDtdPtr cur;
379
380 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
381#ifdef DEBUG_TREE
382 xmlGenericError(xmlGenericErrorContext,
383
384 "xmlCreateIntSubset(): document %s already have an internal subset\n",
385 doc->name);
386#endif
387 return(NULL);
388 }
389
390 /*
391 * Allocate a new DTD and fill the fields.
392 */
393 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
394 if (cur == NULL) {
395 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000396 "xmlCreateIntSubset : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000397 return(NULL);
398 }
399 memset(cur, 0, sizeof(xmlDtd));
400 cur->type = XML_DTD_NODE;
401
402 if (name != NULL)
403 cur->name = xmlStrdup(name);
404 if (ExternalID != NULL)
405 cur->ExternalID = xmlStrdup(ExternalID);
406 if (SystemID != NULL)
407 cur->SystemID = xmlStrdup(SystemID);
408 if (doc != NULL) {
409 doc->intSubset = cur;
410 cur->parent = doc;
411 cur->doc = doc;
412 if (doc->children == NULL) {
413 doc->children = (xmlNodePtr) cur;
414 doc->last = (xmlNodePtr) cur;
415 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000416 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000417 xmlNodePtr prev;
418
Owen Taylor3473f882001-02-23 17:55:21 +0000419 prev = doc->children;
420 prev->prev = (xmlNodePtr) cur;
421 cur->next = prev;
422 doc->children = (xmlNodePtr) cur;
423 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000424 xmlNodePtr next;
425
426 next = doc->children;
427 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
428 next = next->next;
429 if (next == NULL) {
430 cur->prev = doc->last;
431 cur->prev->next = (xmlNodePtr) cur;
432 cur->next = NULL;
433 doc->last = (xmlNodePtr) cur;
434 } else {
435 cur->next = next;
436 cur->prev = next->prev;
437 if (cur->prev == NULL)
438 doc->children = (xmlNodePtr) cur;
439 else
440 cur->prev->next = (xmlNodePtr) cur;
441 next->prev = (xmlNodePtr) cur;
442 }
Owen Taylor3473f882001-02-23 17:55:21 +0000443 }
444 }
445 }
446 return(cur);
447}
448
449/**
450 * xmlFreeDtd:
451 * @cur: the DTD structure to free up
452 *
453 * Free a DTD structure.
454 */
455void
456xmlFreeDtd(xmlDtdPtr cur) {
457 if (cur == NULL) {
458#ifdef DEBUG_TREE
459 xmlGenericError(xmlGenericErrorContext,
460 "xmlFreeDtd : DTD == NULL\n");
461#endif
462 return;
463 }
464 if (cur->children != NULL) {
465 xmlNodePtr next, c = cur->children;
466
467 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000468 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000469 * indexes.
470 */
471 while (c != NULL) {
472 next = c->next;
473 if (c->type == XML_COMMENT_NODE) {
474 xmlUnlinkNode(c);
475 xmlFreeNode(c);
476 }
477 c = next;
478 }
479 }
480 if (cur->name != NULL) xmlFree((char *) cur->name);
481 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
482 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
483 /* TODO !!! */
484 if (cur->notations != NULL)
485 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
486
487 if (cur->elements != NULL)
488 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
489 if (cur->attributes != NULL)
490 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
491 if (cur->entities != NULL)
492 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
493 if (cur->pentities != NULL)
494 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
495
Owen Taylor3473f882001-02-23 17:55:21 +0000496 xmlFree(cur);
497}
498
499/**
500 * xmlNewDoc:
501 * @version: xmlChar string giving the version of XML "1.0"
502 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000503 * Creates a new XML document
504 *
Owen Taylor3473f882001-02-23 17:55:21 +0000505 * Returns a new document
506 */
507xmlDocPtr
508xmlNewDoc(const xmlChar *version) {
509 xmlDocPtr cur;
510
511 if (version == NULL)
512 version = (const xmlChar *) "1.0";
513
514 /*
515 * Allocate a new document and fill the fields.
516 */
517 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
518 if (cur == NULL) {
519 xmlGenericError(xmlGenericErrorContext,
520 "xmlNewDoc : malloc failed\n");
521 return(NULL);
522 }
523 memset(cur, 0, sizeof(xmlDoc));
524 cur->type = XML_DOCUMENT_NODE;
525
526 cur->version = xmlStrdup(version);
527 cur->standalone = -1;
528 cur->compression = -1; /* not initialized */
529 cur->doc = cur;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000530 cur->charset = XML_CHAR_ENCODING_UTF8;
Owen Taylor3473f882001-02-23 17:55:21 +0000531 return(cur);
532}
533
534/**
535 * xmlFreeDoc:
536 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +0000537 *
538 * Free up all the structures used by a document, tree included.
539 */
540void
541xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000542 xmlDtdPtr extSubset, intSubset;
543
Owen Taylor3473f882001-02-23 17:55:21 +0000544 if (cur == NULL) {
545#ifdef DEBUG_TREE
546 xmlGenericError(xmlGenericErrorContext,
547 "xmlFreeDoc : document == NULL\n");
548#endif
549 return;
550 }
Daniel Veillard76d66f42001-05-16 21:05:17 +0000551 /*
552 * Do this before freeing the children list to avoid ID lookups
553 */
554 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
555 cur->ids = NULL;
556 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
557 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000558 extSubset = cur->extSubset;
559 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +0000560 if (intSubset == extSubset)
561 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000562 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000563 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000564 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000565 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000566 }
Daniel Veillarda9142e72001-06-19 11:07:54 +0000567 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000568 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000569 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000570 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000571 }
572
573 if (cur->children != NULL) xmlFreeNodeList(cur->children);
574
Owen Taylor3473f882001-02-23 17:55:21 +0000575 if (cur->version != NULL) xmlFree((char *) cur->version);
576 if (cur->name != NULL) xmlFree((char *) cur->name);
577 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +0000578 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +0000579 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000580 xmlFree(cur);
581}
582
583/**
584 * xmlStringLenGetNodeList:
585 * @doc: the document
586 * @value: the value of the text
587 * @len: the length of the string value
588 *
589 * Parse the value string and build the node list associated. Should
590 * produce a flat tree with only TEXTs and ENTITY_REFs.
591 * Returns a pointer to the first child
592 */
593xmlNodePtr
594xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
595 xmlNodePtr ret = NULL, last = NULL;
596 xmlNodePtr node;
597 xmlChar *val;
598 const xmlChar *cur = value;
599 const xmlChar *q;
600 xmlEntityPtr ent;
601
602 if (value == NULL) return(NULL);
603
604 q = cur;
605 while ((*cur != 0) && (cur - value < len)) {
606 if (*cur == '&') {
607 /*
608 * Save the current text.
609 */
610 if (cur != q) {
611 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
612 xmlNodeAddContentLen(last, q, cur - q);
613 } else {
614 node = xmlNewDocTextLen(doc, q, cur - q);
615 if (node == NULL) return(ret);
616 if (last == NULL)
617 last = ret = node;
618 else {
619 last->next = node;
620 node->prev = last;
621 last = node;
622 }
623 }
624 }
625 /*
626 * Read the entity string
627 */
628 cur++;
629 q = cur;
630 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
631 if ((*cur == 0) || (cur - value >= len)) {
632#ifdef DEBUG_TREE
633 xmlGenericError(xmlGenericErrorContext,
634 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
635#endif
636 return(ret);
637 }
638 if (cur != q) {
639 /*
640 * Predefined entities don't generate nodes
641 */
642 val = xmlStrndup(q, cur - q);
643 ent = xmlGetDocEntity(doc, val);
644 if ((ent != NULL) &&
645 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
646 if (last == NULL) {
647 node = xmlNewDocText(doc, ent->content);
648 last = ret = node;
649 } else
650 xmlNodeAddContent(last, ent->content);
651
652 } else {
653 /*
654 * Create a new REFERENCE_REF node
655 */
656 node = xmlNewReference(doc, val);
657 if (node == NULL) {
658 if (val != NULL) xmlFree(val);
659 return(ret);
660 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000661 else if ((ent != NULL) && (ent->children == NULL)) {
662 xmlNodePtr tmp;
663
664 ent->children =
665 xmlStringGetNodeList(doc, (const xmlChar*)node->content);
666 tmp = ent->children;
667 while (tmp) {
668 tmp->parent = (xmlNodePtr)ent;
669 tmp = tmp->next;
670 }
671 }
Owen Taylor3473f882001-02-23 17:55:21 +0000672 if (last == NULL)
673 last = ret = node;
674 else {
675 last->next = node;
676 node->prev = last;
677 last = node;
678 }
679 }
680 xmlFree(val);
681 }
682 cur++;
683 q = cur;
684 } else
685 cur++;
686 }
687 if (cur != q) {
688 /*
689 * Handle the last piece of text.
690 */
691 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
692 xmlNodeAddContentLen(last, q, cur - q);
693 } else {
694 node = xmlNewDocTextLen(doc, q, cur - q);
695 if (node == NULL) return(ret);
696 if (last == NULL)
697 last = ret = node;
698 else {
699 last->next = node;
700 node->prev = last;
701 last = node;
702 }
703 }
704 }
705 return(ret);
706}
707
708/**
709 * xmlStringGetNodeList:
710 * @doc: the document
711 * @value: the value of the attribute
712 *
713 * Parse the value string and build the node list associated. Should
714 * produce a flat tree with only TEXTs and ENTITY_REFs.
715 * Returns a pointer to the first child
716 */
717xmlNodePtr
718xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
719 xmlNodePtr ret = NULL, last = NULL;
720 xmlNodePtr node;
721 xmlChar *val;
722 const xmlChar *cur = value;
723 const xmlChar *q;
724 xmlEntityPtr ent;
725
726 if (value == NULL) return(NULL);
727
728 q = cur;
729 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000730 if (cur[0] == '&') {
731 int charval = 0;
732 xmlChar tmp;
733
Owen Taylor3473f882001-02-23 17:55:21 +0000734 /*
735 * Save the current text.
736 */
737 if (cur != q) {
738 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
739 xmlNodeAddContentLen(last, q, cur - q);
740 } else {
741 node = xmlNewDocTextLen(doc, q, cur - q);
742 if (node == NULL) return(ret);
743 if (last == NULL)
744 last = ret = node;
745 else {
746 last->next = node;
747 node->prev = last;
748 last = node;
749 }
750 }
751 }
Owen Taylor3473f882001-02-23 17:55:21 +0000752 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000753 if ((cur[1] == '#') && (cur[2] == 'x')) {
754 cur += 3;
755 tmp = *cur;
756 while (tmp != ';') { /* Non input consuming loop */
757 if ((tmp >= '0') && (tmp <= '9'))
758 charval = charval * 16 + (tmp - '0');
759 else if ((tmp >= 'a') && (tmp <= 'f'))
760 charval = charval * 16 + (tmp - 'a') + 10;
761 else if ((tmp >= 'A') && (tmp <= 'F'))
762 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +0000763 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000764 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000765 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000766 charval = 0;
767 break;
768 }
769 cur++;
770 tmp = *cur;
771 }
772 if (tmp == ';')
773 cur++;
774 q = cur;
775 } else if (cur[1] == '#') {
776 cur += 2;
777 tmp = *cur;
778 while (tmp != ';') { /* Non input consuming loops */
779 if ((tmp >= '0') && (tmp <= '9'))
780 charval = charval * 10 + (tmp - '0');
781 else {
782 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000783 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000784 charval = 0;
785 break;
786 }
787 cur++;
788 tmp = *cur;
789 }
790 if (tmp == ';')
791 cur++;
792 q = cur;
793 } else {
794 /*
795 * Read the entity string
796 */
797 cur++;
798 q = cur;
799 while ((*cur != 0) && (*cur != ';')) cur++;
800 if (*cur == 0) {
801#ifdef DEBUG_TREE
802 xmlGenericError(xmlGenericErrorContext,
803 "xmlStringGetNodeList: unterminated entity %30s\n", q);
804#endif
805 return(ret);
806 }
807 if (cur != q) {
808 /*
809 * Predefined entities don't generate nodes
810 */
811 val = xmlStrndup(q, cur - q);
812 ent = xmlGetDocEntity(doc, val);
813 if ((ent != NULL) &&
814 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
815 if (last == NULL) {
816 node = xmlNewDocText(doc, ent->content);
817 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +0000818 } else if (last->type != XML_TEXT_NODE) {
819 node = xmlNewDocText(doc, ent->content);
820 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000821 } else
822 xmlNodeAddContent(last, ent->content);
823
824 } else {
825 /*
826 * Create a new REFERENCE_REF node
827 */
828 node = xmlNewReference(doc, val);
829 if (node == NULL) {
830 if (val != NULL) xmlFree(val);
831 return(ret);
832 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000833 else if ((ent != NULL) && (ent->children == NULL)) {
834 xmlNodePtr temp;
835
836 ent->children = xmlStringGetNodeList(doc,
837 (const xmlChar*)node->content);
838 temp = ent->children;
839 while (temp) {
840 temp->parent = (xmlNodePtr)ent;
841 temp = temp->next;
842 }
843 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000844 if (last == NULL) {
845 last = ret = node;
846 } else {
847 last = xmlAddNextSibling(last, node);
848 }
849 }
850 xmlFree(val);
851 }
852 cur++;
853 q = cur;
854 }
855 if (charval != 0) {
856 xmlChar buf[10];
857 int len;
858
859 len = xmlCopyCharMultiByte(buf, charval);
860 buf[len] = 0;
861 node = xmlNewDocText(doc, buf);
862 if (node != NULL) {
863 if (last == NULL) {
864 last = ret = node;
865 } else {
866 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000867 }
868 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000869
870 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000871 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000872 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000873 cur++;
874 }
Daniel Veillard75bea542001-05-11 17:41:21 +0000875 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000876 /*
877 * Handle the last piece of text.
878 */
879 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
880 xmlNodeAddContentLen(last, q, cur - q);
881 } else {
882 node = xmlNewDocTextLen(doc, q, cur - q);
883 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000884 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000885 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000886 } else {
887 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000888 }
889 }
890 }
891 return(ret);
892}
893
894/**
895 * xmlNodeListGetString:
896 * @doc: the document
897 * @list: a Node list
898 * @inLine: should we replace entity contents or show their external form
899 *
900 * Returns the string equivalent to the text contained in the Node list
901 * made of TEXTs and ENTITY_REFs
Daniel Veillardd1640922001-12-17 15:30:10 +0000902 * Returns a pointer to the string copy, the caller must free it.
Owen Taylor3473f882001-02-23 17:55:21 +0000903 */
904xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +0000905xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
906{
Owen Taylor3473f882001-02-23 17:55:21 +0000907 xmlNodePtr node = list;
908 xmlChar *ret = NULL;
909 xmlEntityPtr ent;
910
Daniel Veillard7646b182002-04-20 06:41:40 +0000911 if (list == NULL)
912 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000913
914 while (node != NULL) {
915 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +0000916 (node->type == XML_CDATA_SECTION_NODE)) {
917 if (inLine) {
918 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000919 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +0000920 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +0000921
Daniel Veillard7646b182002-04-20 06:41:40 +0000922 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
923 if (buffer != NULL) {
924 ret = xmlStrcat(ret, buffer);
925 xmlFree(buffer);
926 }
927 }
928 } else if (node->type == XML_ENTITY_REF_NODE) {
929 if (inLine) {
930 ent = xmlGetDocEntity(doc, node->name);
931 if (ent != NULL) {
932 xmlChar *buffer;
933
934 /* an entity content can be any "well balanced chunk",
935 * i.e. the result of the content [43] production:
936 * http://www.w3.org/TR/REC-xml#NT-content.
937 * So it can contain text, CDATA section or nested
938 * entity reference nodes (among others).
939 * -> we recursive call xmlNodeListGetString()
940 * which handles these types */
941 buffer = xmlNodeListGetString(doc, ent->children, 1);
942 if (buffer != NULL) {
943 ret = xmlStrcat(ret, buffer);
944 xmlFree(buffer);
945 }
946 } else {
947 ret = xmlStrcat(ret, node->content);
948 }
949 } else {
950 xmlChar buf[2];
951
952 buf[0] = '&';
953 buf[1] = 0;
954 ret = xmlStrncat(ret, buf, 1);
955 ret = xmlStrcat(ret, node->name);
956 buf[0] = ';';
957 buf[1] = 0;
958 ret = xmlStrncat(ret, buf, 1);
959 }
960 }
961#if 0
962 else {
963 xmlGenericError(xmlGenericErrorContext,
964 "xmlGetNodeListString : invalid node type %d\n",
965 node->type);
966 }
967#endif
968 node = node->next;
969 }
970 return (ret);
971}
Owen Taylor3473f882001-02-23 17:55:21 +0000972/**
973 * xmlNodeListGetRawString:
974 * @doc: the document
975 * @list: a Node list
976 * @inLine: should we replace entity contents or show their external form
977 *
978 * Returns the string equivalent to the text contained in the Node list
979 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
980 * this function doesn't do any character encoding handling.
981 *
Daniel Veillardd1640922001-12-17 15:30:10 +0000982 * Returns a pointer to the string copy, the caller must free it.
Owen Taylor3473f882001-02-23 17:55:21 +0000983 */
984xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +0000985xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
986{
Owen Taylor3473f882001-02-23 17:55:21 +0000987 xmlNodePtr node = list;
988 xmlChar *ret = NULL;
989 xmlEntityPtr ent;
990
Daniel Veillard7646b182002-04-20 06:41:40 +0000991 if (list == NULL)
992 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000993
994 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +0000995 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +0000996 (node->type == XML_CDATA_SECTION_NODE)) {
997 if (inLine) {
998 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000999 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001000 xmlChar *buffer;
1001
1002 buffer = xmlEncodeSpecialChars(doc, node->content);
1003 if (buffer != NULL) {
1004 ret = xmlStrcat(ret, buffer);
1005 xmlFree(buffer);
1006 }
1007 }
1008 } else if (node->type == XML_ENTITY_REF_NODE) {
1009 if (inLine) {
1010 ent = xmlGetDocEntity(doc, node->name);
1011 if (ent != NULL) {
1012 xmlChar *buffer;
1013
1014 /* an entity content can be any "well balanced chunk",
1015 * i.e. the result of the content [43] production:
1016 * http://www.w3.org/TR/REC-xml#NT-content.
1017 * So it can contain text, CDATA section or nested
1018 * entity reference nodes (among others).
1019 * -> we recursive call xmlNodeListGetRawString()
1020 * which handles these types */
1021 buffer =
1022 xmlNodeListGetRawString(doc, ent->children, 1);
1023 if (buffer != NULL) {
1024 ret = xmlStrcat(ret, buffer);
1025 xmlFree(buffer);
1026 }
1027 } else {
1028 ret = xmlStrcat(ret, node->content);
1029 }
1030 } else {
1031 xmlChar buf[2];
1032
1033 buf[0] = '&';
1034 buf[1] = 0;
1035 ret = xmlStrncat(ret, buf, 1);
1036 ret = xmlStrcat(ret, node->name);
1037 buf[0] = ';';
1038 buf[1] = 0;
1039 ret = xmlStrncat(ret, buf, 1);
1040 }
1041 }
Owen Taylor3473f882001-02-23 17:55:21 +00001042#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001043 else {
1044 xmlGenericError(xmlGenericErrorContext,
1045 "xmlGetNodeListString : invalid node type %d\n",
1046 node->type);
1047 }
Owen Taylor3473f882001-02-23 17:55:21 +00001048#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001049 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001050 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001051 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001052}
1053
1054/**
1055 * xmlNewProp:
1056 * @node: the holding node
1057 * @name: the name of the attribute
1058 * @value: the value of the attribute
1059 *
1060 * Create a new property carried by a node.
1061 * Returns a pointer to the attribute
1062 */
1063xmlAttrPtr
1064xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1065 xmlAttrPtr cur;
1066 xmlDocPtr doc = NULL;
1067
1068 if (name == NULL) {
1069#ifdef DEBUG_TREE
1070 xmlGenericError(xmlGenericErrorContext,
1071 "xmlNewProp : name == NULL\n");
1072#endif
1073 return(NULL);
1074 }
1075
1076 /*
1077 * Allocate a new property and fill the fields.
1078 */
1079 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1080 if (cur == NULL) {
1081 xmlGenericError(xmlGenericErrorContext,
1082 "xmlNewProp : malloc failed\n");
1083 return(NULL);
1084 }
1085 memset(cur, 0, sizeof(xmlAttr));
1086 cur->type = XML_ATTRIBUTE_NODE;
1087
1088 cur->parent = node;
1089 if (node != NULL) {
1090 doc = node->doc;
1091 cur->doc = doc;
1092 }
1093 cur->name = xmlStrdup(name);
1094 if (value != NULL) {
1095 xmlChar *buffer;
1096 xmlNodePtr tmp;
1097
1098 buffer = xmlEncodeEntitiesReentrant(doc, value);
1099 cur->children = xmlStringGetNodeList(doc, buffer);
1100 cur->last = NULL;
1101 tmp = cur->children;
1102 while (tmp != NULL) {
1103 tmp->parent = (xmlNodePtr) cur;
1104 tmp->doc = doc;
1105 if (tmp->next == NULL)
1106 cur->last = tmp;
1107 tmp = tmp->next;
1108 }
1109 xmlFree(buffer);
1110 }
1111
1112 /*
1113 * Add it at the end to preserve parsing order ...
1114 */
1115 if (node != NULL) {
1116 if (node->properties == NULL) {
1117 node->properties = cur;
1118 } else {
1119 xmlAttrPtr prev = node->properties;
1120
1121 while (prev->next != NULL) prev = prev->next;
1122 prev->next = cur;
1123 cur->prev = prev;
1124 }
1125 }
1126 return(cur);
1127}
1128
1129/**
1130 * xmlNewNsProp:
1131 * @node: the holding node
1132 * @ns: the namespace
1133 * @name: the name of the attribute
1134 * @value: the value of the attribute
1135 *
1136 * Create a new property tagged with a namespace and carried by a node.
1137 * Returns a pointer to the attribute
1138 */
1139xmlAttrPtr
1140xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1141 const xmlChar *value) {
1142 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001143 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001144
1145 if (name == NULL) {
1146#ifdef DEBUG_TREE
1147 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001148 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001149#endif
1150 return(NULL);
1151 }
1152
1153 /*
1154 * Allocate a new property and fill the fields.
1155 */
1156 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1157 if (cur == NULL) {
1158 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001159 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001160 return(NULL);
1161 }
1162 memset(cur, 0, sizeof(xmlAttr));
1163 cur->type = XML_ATTRIBUTE_NODE;
1164
1165 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001166 if (node != NULL) {
1167 doc = node->doc;
1168 cur->doc = doc;
1169 }
Owen Taylor3473f882001-02-23 17:55:21 +00001170 cur->ns = ns;
1171 cur->name = xmlStrdup(name);
1172 if (value != NULL) {
1173 xmlChar *buffer;
1174 xmlNodePtr tmp;
1175
Daniel Veillarda682b212001-06-07 19:59:42 +00001176 buffer = xmlEncodeEntitiesReentrant(doc, value);
1177 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001178 cur->last = NULL;
1179 tmp = cur->children;
1180 while (tmp != NULL) {
1181 tmp->parent = (xmlNodePtr) cur;
1182 if (tmp->next == NULL)
1183 cur->last = tmp;
1184 tmp = tmp->next;
1185 }
1186 xmlFree(buffer);
1187 }
1188
1189 /*
1190 * Add it at the end to preserve parsing order ...
1191 */
1192 if (node != NULL) {
1193 if (node->properties == NULL) {
1194 node->properties = cur;
1195 } else {
1196 xmlAttrPtr prev = node->properties;
1197
1198 while (prev->next != NULL) prev = prev->next;
1199 prev->next = cur;
1200 cur->prev = prev;
1201 }
1202 }
1203 return(cur);
1204}
1205
1206/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001207 * xmlNewNsPropEatName:
1208 * @node: the holding node
1209 * @ns: the namespace
1210 * @name: the name of the attribute
1211 * @value: the value of the attribute
1212 *
1213 * Create a new property tagged with a namespace and carried by a node.
1214 * Returns a pointer to the attribute
1215 */
1216xmlAttrPtr
1217xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1218 const xmlChar *value) {
1219 xmlAttrPtr cur;
1220 xmlDocPtr doc = NULL;
1221
1222 if (name == NULL) {
1223#ifdef DEBUG_TREE
1224 xmlGenericError(xmlGenericErrorContext,
1225 "xmlNewNsPropEatName : name == NULL\n");
1226#endif
1227 return(NULL);
1228 }
1229
1230 /*
1231 * Allocate a new property and fill the fields.
1232 */
1233 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1234 if (cur == NULL) {
1235 xmlGenericError(xmlGenericErrorContext,
1236 "xmlNewNsPropEatName : malloc failed\n");
1237 return(NULL);
1238 }
1239 memset(cur, 0, sizeof(xmlAttr));
1240 cur->type = XML_ATTRIBUTE_NODE;
1241
1242 cur->parent = node;
1243 if (node != NULL) {
1244 doc = node->doc;
1245 cur->doc = doc;
1246 }
1247 cur->ns = ns;
1248 cur->name = name;
1249 if (value != NULL) {
1250 xmlChar *buffer;
1251 xmlNodePtr tmp;
1252
1253 buffer = xmlEncodeEntitiesReentrant(doc, value);
1254 cur->children = xmlStringGetNodeList(doc, buffer);
1255 cur->last = NULL;
1256 tmp = cur->children;
1257 while (tmp != NULL) {
1258 tmp->parent = (xmlNodePtr) cur;
1259 if (tmp->next == NULL)
1260 cur->last = tmp;
1261 tmp = tmp->next;
1262 }
1263 xmlFree(buffer);
1264 }
1265
1266 /*
1267 * Add it at the end to preserve parsing order ...
1268 */
1269 if (node != NULL) {
1270 if (node->properties == NULL) {
1271 node->properties = cur;
1272 } else {
1273 xmlAttrPtr prev = node->properties;
1274
1275 while (prev->next != NULL) prev = prev->next;
1276 prev->next = cur;
1277 cur->prev = prev;
1278 }
1279 }
1280 return(cur);
1281}
1282
1283/**
Owen Taylor3473f882001-02-23 17:55:21 +00001284 * xmlNewDocProp:
1285 * @doc: the document
1286 * @name: the name of the attribute
1287 * @value: the value of the attribute
1288 *
1289 * Create a new property carried by a document.
1290 * Returns a pointer to the attribute
1291 */
1292xmlAttrPtr
1293xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1294 xmlAttrPtr cur;
1295
1296 if (name == NULL) {
1297#ifdef DEBUG_TREE
1298 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001299 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001300#endif
1301 return(NULL);
1302 }
1303
1304 /*
1305 * Allocate a new property and fill the fields.
1306 */
1307 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1308 if (cur == NULL) {
1309 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001310 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001311 return(NULL);
1312 }
1313 memset(cur, 0, sizeof(xmlAttr));
1314 cur->type = XML_ATTRIBUTE_NODE;
1315
1316 cur->name = xmlStrdup(name);
1317 cur->doc = doc;
1318 if (value != NULL) {
1319 xmlNodePtr tmp;
1320
1321 cur->children = xmlStringGetNodeList(doc, value);
1322 cur->last = NULL;
1323
1324 tmp = cur->children;
1325 while (tmp != NULL) {
1326 tmp->parent = (xmlNodePtr) cur;
1327 if (tmp->next == NULL)
1328 cur->last = tmp;
1329 tmp = tmp->next;
1330 }
1331 }
1332 return(cur);
1333}
1334
1335/**
1336 * xmlFreePropList:
1337 * @cur: the first property in the list
1338 *
1339 * Free a property and all its siblings, all the children are freed too.
1340 */
1341void
1342xmlFreePropList(xmlAttrPtr cur) {
1343 xmlAttrPtr next;
1344 if (cur == NULL) {
1345#ifdef DEBUG_TREE
1346 xmlGenericError(xmlGenericErrorContext,
1347 "xmlFreePropList : property == NULL\n");
1348#endif
1349 return;
1350 }
1351 while (cur != NULL) {
1352 next = cur->next;
1353 xmlFreeProp(cur);
1354 cur = next;
1355 }
1356}
1357
1358/**
1359 * xmlFreeProp:
1360 * @cur: an attribute
1361 *
1362 * Free one attribute, all the content is freed too
1363 */
1364void
1365xmlFreeProp(xmlAttrPtr cur) {
1366 if (cur == NULL) {
1367#ifdef DEBUG_TREE
1368 xmlGenericError(xmlGenericErrorContext,
1369 "xmlFreeProp : property == NULL\n");
1370#endif
1371 return;
1372 }
1373 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001374 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1375 ((cur->parent->doc->intSubset != NULL) ||
1376 (cur->parent->doc->extSubset != NULL))) {
1377 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1378 xmlRemoveID(cur->parent->doc, cur);
1379 }
Owen Taylor3473f882001-02-23 17:55:21 +00001380 if (cur->name != NULL) xmlFree((char *) cur->name);
1381 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001382 xmlFree(cur);
1383}
1384
1385/**
1386 * xmlRemoveProp:
1387 * @cur: an attribute
1388 *
1389 * Unlink and free one attribute, all the content is freed too
1390 * Note this doesn't work for namespace definition attributes
1391 *
1392 * Returns 0 if success and -1 in case of error.
1393 */
1394int
1395xmlRemoveProp(xmlAttrPtr cur) {
1396 xmlAttrPtr tmp;
1397 if (cur == NULL) {
1398#ifdef DEBUG_TREE
1399 xmlGenericError(xmlGenericErrorContext,
1400 "xmlRemoveProp : cur == NULL\n");
1401#endif
1402 return(-1);
1403 }
1404 if (cur->parent == NULL) {
1405#ifdef DEBUG_TREE
1406 xmlGenericError(xmlGenericErrorContext,
1407 "xmlRemoveProp : cur->parent == NULL\n");
1408#endif
1409 return(-1);
1410 }
1411 tmp = cur->parent->properties;
1412 if (tmp == cur) {
1413 cur->parent->properties = cur->next;
1414 xmlFreeProp(cur);
1415 return(0);
1416 }
1417 while (tmp != NULL) {
1418 if (tmp->next == cur) {
1419 tmp->next = cur->next;
1420 if (tmp->next != NULL)
1421 tmp->next->prev = tmp;
1422 xmlFreeProp(cur);
1423 return(0);
1424 }
1425 tmp = tmp->next;
1426 }
1427#ifdef DEBUG_TREE
1428 xmlGenericError(xmlGenericErrorContext,
1429 "xmlRemoveProp : attribute not owned by its node\n");
1430#endif
1431 return(-1);
1432}
1433
1434/**
1435 * xmlNewPI:
1436 * @name: the processing instruction name
1437 * @content: the PI content
1438 *
1439 * Creation of a processing instruction element.
1440 * Returns a pointer to the new node object.
1441 */
1442xmlNodePtr
1443xmlNewPI(const xmlChar *name, const xmlChar *content) {
1444 xmlNodePtr cur;
1445
1446 if (name == NULL) {
1447#ifdef DEBUG_TREE
1448 xmlGenericError(xmlGenericErrorContext,
1449 "xmlNewPI : name == NULL\n");
1450#endif
1451 return(NULL);
1452 }
1453
1454 /*
1455 * Allocate a new node and fill the fields.
1456 */
1457 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1458 if (cur == NULL) {
1459 xmlGenericError(xmlGenericErrorContext,
1460 "xmlNewPI : malloc failed\n");
1461 return(NULL);
1462 }
1463 memset(cur, 0, sizeof(xmlNode));
1464 cur->type = XML_PI_NODE;
1465
1466 cur->name = xmlStrdup(name);
1467 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001468 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001469 }
1470 return(cur);
1471}
1472
1473/**
1474 * xmlNewNode:
1475 * @ns: namespace if any
1476 * @name: the node name
1477 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001478 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001479 *
1480 * Returns a pointer to the new node object.
1481 */
1482xmlNodePtr
1483xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1484 xmlNodePtr cur;
1485
1486 if (name == NULL) {
1487#ifdef DEBUG_TREE
1488 xmlGenericError(xmlGenericErrorContext,
1489 "xmlNewNode : name == NULL\n");
1490#endif
1491 return(NULL);
1492 }
1493
1494 /*
1495 * Allocate a new node and fill the fields.
1496 */
1497 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1498 if (cur == NULL) {
1499 xmlGenericError(xmlGenericErrorContext,
1500 "xmlNewNode : malloc failed\n");
1501 return(NULL);
1502 }
1503 memset(cur, 0, sizeof(xmlNode));
1504 cur->type = XML_ELEMENT_NODE;
1505
1506 cur->name = xmlStrdup(name);
1507 cur->ns = ns;
1508 return(cur);
1509}
1510
1511/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001512 * xmlNewNodeEatName:
1513 * @ns: namespace if any
1514 * @name: the node name
1515 *
1516 * Creation of a new node element. @ns is optional (NULL).
1517 *
1518 * Returns a pointer to the new node object.
1519 */
1520xmlNodePtr
1521xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
1522 xmlNodePtr cur;
1523
1524 if (name == NULL) {
1525#ifdef DEBUG_TREE
1526 xmlGenericError(xmlGenericErrorContext,
1527 "xmlNewNode : name == NULL\n");
1528#endif
1529 return(NULL);
1530 }
1531
1532 /*
1533 * Allocate a new node and fill the fields.
1534 */
1535 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1536 if (cur == NULL) {
1537 xmlGenericError(xmlGenericErrorContext,
1538 "xmlNewNode : malloc failed\n");
1539 return(NULL);
1540 }
1541 memset(cur, 0, sizeof(xmlNode));
1542 cur->type = XML_ELEMENT_NODE;
1543
1544 cur->name = name;
1545 cur->ns = ns;
1546 return(cur);
1547}
1548
1549/**
Owen Taylor3473f882001-02-23 17:55:21 +00001550 * xmlNewDocNode:
1551 * @doc: the document
1552 * @ns: namespace if any
1553 * @name: the node name
1554 * @content: the XML text content if any
1555 *
1556 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001557 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001558 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1559 * references, but XML special chars need to be escaped first by using
1560 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1561 * need entities support.
1562 *
1563 * Returns a pointer to the new node object.
1564 */
1565xmlNodePtr
1566xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1567 const xmlChar *name, const xmlChar *content) {
1568 xmlNodePtr cur;
1569
1570 cur = xmlNewNode(ns, name);
1571 if (cur != NULL) {
1572 cur->doc = doc;
1573 if (content != NULL) {
1574 cur->children = xmlStringGetNodeList(doc, content);
1575 UPDATE_LAST_CHILD_AND_PARENT(cur)
1576 }
1577 }
1578 return(cur);
1579}
1580
Daniel Veillard46de64e2002-05-29 08:21:33 +00001581/**
1582 * xmlNewDocNodeEatName:
1583 * @doc: the document
1584 * @ns: namespace if any
1585 * @name: the node name
1586 * @content: the XML text content if any
1587 *
1588 * Creation of a new node element within a document. @ns and @content
1589 * are optional (NULL).
1590 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1591 * references, but XML special chars need to be escaped first by using
1592 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1593 * need entities support.
1594 *
1595 * Returns a pointer to the new node object.
1596 */
1597xmlNodePtr
1598xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
1599 xmlChar *name, const xmlChar *content) {
1600 xmlNodePtr cur;
1601
1602 cur = xmlNewNodeEatName(ns, name);
1603 if (cur != NULL) {
1604 cur->doc = doc;
1605 if (content != NULL) {
1606 cur->children = xmlStringGetNodeList(doc, content);
1607 UPDATE_LAST_CHILD_AND_PARENT(cur)
1608 }
1609 }
1610 return(cur);
1611}
1612
Owen Taylor3473f882001-02-23 17:55:21 +00001613
1614/**
1615 * xmlNewDocRawNode:
1616 * @doc: the document
1617 * @ns: namespace if any
1618 * @name: the node name
1619 * @content: the text content if any
1620 *
1621 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001622 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001623 *
1624 * Returns a pointer to the new node object.
1625 */
1626xmlNodePtr
1627xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1628 const xmlChar *name, const xmlChar *content) {
1629 xmlNodePtr cur;
1630
1631 cur = xmlNewNode(ns, name);
1632 if (cur != NULL) {
1633 cur->doc = doc;
1634 if (content != NULL) {
1635 cur->children = xmlNewDocText(doc, content);
1636 UPDATE_LAST_CHILD_AND_PARENT(cur)
1637 }
1638 }
1639 return(cur);
1640}
1641
1642/**
1643 * xmlNewDocFragment:
1644 * @doc: the document owning the fragment
1645 *
1646 * Creation of a new Fragment node.
1647 * Returns a pointer to the new node object.
1648 */
1649xmlNodePtr
1650xmlNewDocFragment(xmlDocPtr doc) {
1651 xmlNodePtr cur;
1652
1653 /*
1654 * Allocate a new DocumentFragment node and fill the fields.
1655 */
1656 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1657 if (cur == NULL) {
1658 xmlGenericError(xmlGenericErrorContext,
1659 "xmlNewDocFragment : malloc failed\n");
1660 return(NULL);
1661 }
1662 memset(cur, 0, sizeof(xmlNode));
1663 cur->type = XML_DOCUMENT_FRAG_NODE;
1664
1665 cur->doc = doc;
1666 return(cur);
1667}
1668
1669/**
1670 * xmlNewText:
1671 * @content: the text content
1672 *
1673 * Creation of a new text node.
1674 * Returns a pointer to the new node object.
1675 */
1676xmlNodePtr
1677xmlNewText(const xmlChar *content) {
1678 xmlNodePtr cur;
1679
1680 /*
1681 * Allocate a new node and fill the fields.
1682 */
1683 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1684 if (cur == NULL) {
1685 xmlGenericError(xmlGenericErrorContext,
1686 "xmlNewText : malloc failed\n");
1687 return(NULL);
1688 }
1689 memset(cur, 0, sizeof(xmlNode));
1690 cur->type = XML_TEXT_NODE;
1691
1692 cur->name = xmlStringText;
1693 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001694 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001695 }
1696 return(cur);
1697}
1698
1699/**
1700 * xmlNewTextChild:
1701 * @parent: the parent node
1702 * @ns: a namespace if any
1703 * @name: the name of the child
1704 * @content: the text content of the child if any.
1705 *
1706 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001707 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001708 * a child TEXT node will be created containing the string content.
1709 *
1710 * Returns a pointer to the new node object.
1711 */
1712xmlNodePtr
1713xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1714 const xmlChar *name, const xmlChar *content) {
1715 xmlNodePtr cur, prev;
1716
1717 if (parent == NULL) {
1718#ifdef DEBUG_TREE
1719 xmlGenericError(xmlGenericErrorContext,
1720 "xmlNewTextChild : parent == NULL\n");
1721#endif
1722 return(NULL);
1723 }
1724
1725 if (name == NULL) {
1726#ifdef DEBUG_TREE
1727 xmlGenericError(xmlGenericErrorContext,
1728 "xmlNewTextChild : name == NULL\n");
1729#endif
1730 return(NULL);
1731 }
1732
1733 /*
1734 * Allocate a new node
1735 */
1736 if (ns == NULL)
1737 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1738 else
1739 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1740 if (cur == NULL) return(NULL);
1741
1742 /*
1743 * add the new element at the end of the children list.
1744 */
1745 cur->type = XML_ELEMENT_NODE;
1746 cur->parent = parent;
1747 cur->doc = parent->doc;
1748 if (parent->children == NULL) {
1749 parent->children = cur;
1750 parent->last = cur;
1751 } else {
1752 prev = parent->last;
1753 prev->next = cur;
1754 cur->prev = prev;
1755 parent->last = cur;
1756 }
1757
1758 return(cur);
1759}
1760
1761/**
1762 * xmlNewCharRef:
1763 * @doc: the document
1764 * @name: the char ref string, starting with # or "&# ... ;"
1765 *
1766 * Creation of a new character reference node.
1767 * Returns a pointer to the new node object.
1768 */
1769xmlNodePtr
1770xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1771 xmlNodePtr cur;
1772
1773 /*
1774 * Allocate a new node and fill the fields.
1775 */
1776 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1777 if (cur == NULL) {
1778 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001779 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001780 return(NULL);
1781 }
1782 memset(cur, 0, sizeof(xmlNode));
1783 cur->type = XML_ENTITY_REF_NODE;
1784
1785 cur->doc = doc;
1786 if (name[0] == '&') {
1787 int len;
1788 name++;
1789 len = xmlStrlen(name);
1790 if (name[len - 1] == ';')
1791 cur->name = xmlStrndup(name, len - 1);
1792 else
1793 cur->name = xmlStrndup(name, len);
1794 } else
1795 cur->name = xmlStrdup(name);
1796 return(cur);
1797}
1798
1799/**
1800 * xmlNewReference:
1801 * @doc: the document
1802 * @name: the reference name, or the reference string with & and ;
1803 *
1804 * Creation of a new reference node.
1805 * Returns a pointer to the new node object.
1806 */
1807xmlNodePtr
1808xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1809 xmlNodePtr cur;
1810 xmlEntityPtr ent;
1811
1812 /*
1813 * Allocate a new node and fill the fields.
1814 */
1815 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1816 if (cur == NULL) {
1817 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001818 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001819 return(NULL);
1820 }
1821 memset(cur, 0, sizeof(xmlNode));
1822 cur->type = XML_ENTITY_REF_NODE;
1823
1824 cur->doc = doc;
1825 if (name[0] == '&') {
1826 int len;
1827 name++;
1828 len = xmlStrlen(name);
1829 if (name[len - 1] == ';')
1830 cur->name = xmlStrndup(name, len - 1);
1831 else
1832 cur->name = xmlStrndup(name, len);
1833 } else
1834 cur->name = xmlStrdup(name);
1835
1836 ent = xmlGetDocEntity(doc, cur->name);
1837 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001838 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00001839 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001840 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00001841 * updated. Not sure if this is 100% correct.
1842 * -George
1843 */
1844 cur->children = (xmlNodePtr) ent;
1845 cur->last = (xmlNodePtr) ent;
1846 }
1847 return(cur);
1848}
1849
1850/**
1851 * xmlNewDocText:
1852 * @doc: the document
1853 * @content: the text content
1854 *
1855 * Creation of a new text node within a document.
1856 * Returns a pointer to the new node object.
1857 */
1858xmlNodePtr
1859xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1860 xmlNodePtr cur;
1861
1862 cur = xmlNewText(content);
1863 if (cur != NULL) cur->doc = doc;
1864 return(cur);
1865}
1866
1867/**
1868 * xmlNewTextLen:
1869 * @content: the text content
1870 * @len: the text len.
1871 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001872 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00001873 * Returns a pointer to the new node object.
1874 */
1875xmlNodePtr
1876xmlNewTextLen(const xmlChar *content, int len) {
1877 xmlNodePtr cur;
1878
1879 /*
1880 * Allocate a new node and fill the fields.
1881 */
1882 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1883 if (cur == NULL) {
1884 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001885 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001886 return(NULL);
1887 }
1888 memset(cur, 0, sizeof(xmlNode));
1889 cur->type = XML_TEXT_NODE;
1890
1891 cur->name = xmlStringText;
1892 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001893 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001894 }
1895 return(cur);
1896}
1897
1898/**
1899 * xmlNewDocTextLen:
1900 * @doc: the document
1901 * @content: the text content
1902 * @len: the text len.
1903 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001904 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00001905 * text node pertain to a given document.
1906 * Returns a pointer to the new node object.
1907 */
1908xmlNodePtr
1909xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1910 xmlNodePtr cur;
1911
1912 cur = xmlNewTextLen(content, len);
1913 if (cur != NULL) cur->doc = doc;
1914 return(cur);
1915}
1916
1917/**
1918 * xmlNewComment:
1919 * @content: the comment content
1920 *
1921 * Creation of a new node containing a comment.
1922 * Returns a pointer to the new node object.
1923 */
1924xmlNodePtr
1925xmlNewComment(const xmlChar *content) {
1926 xmlNodePtr cur;
1927
1928 /*
1929 * Allocate a new node and fill the fields.
1930 */
1931 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1932 if (cur == NULL) {
1933 xmlGenericError(xmlGenericErrorContext,
1934 "xmlNewComment : malloc failed\n");
1935 return(NULL);
1936 }
1937 memset(cur, 0, sizeof(xmlNode));
1938 cur->type = XML_COMMENT_NODE;
1939
1940 cur->name = xmlStringComment;
1941 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001942 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001943 }
1944 return(cur);
1945}
1946
1947/**
1948 * xmlNewCDataBlock:
1949 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00001950 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00001951 * @len: the length of the block
1952 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001953 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00001954 * Returns a pointer to the new node object.
1955 */
1956xmlNodePtr
1957xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1958 xmlNodePtr cur;
1959
1960 /*
1961 * Allocate a new node and fill the fields.
1962 */
1963 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1964 if (cur == NULL) {
1965 xmlGenericError(xmlGenericErrorContext,
1966 "xmlNewCDataBlock : malloc failed\n");
1967 return(NULL);
1968 }
1969 memset(cur, 0, sizeof(xmlNode));
1970 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001971 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001972
1973 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001974 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001975 }
1976 return(cur);
1977}
1978
1979/**
1980 * xmlNewDocComment:
1981 * @doc: the document
1982 * @content: the comment content
1983 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001984 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00001985 * Returns a pointer to the new node object.
1986 */
1987xmlNodePtr
1988xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1989 xmlNodePtr cur;
1990
1991 cur = xmlNewComment(content);
1992 if (cur != NULL) cur->doc = doc;
1993 return(cur);
1994}
1995
1996/**
1997 * xmlSetTreeDoc:
1998 * @tree: the top element
1999 * @doc: the document
2000 *
2001 * update all nodes under the tree to point to the right document
2002 */
2003void
2004xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002005 xmlAttrPtr prop;
2006
Owen Taylor3473f882001-02-23 17:55:21 +00002007 if (tree == NULL)
2008 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002009 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002010 if(tree->type == XML_ELEMENT_NODE) {
2011 prop = tree->properties;
2012 while (prop != NULL) {
2013 prop->doc = doc;
2014 xmlSetListDoc(prop->children, doc);
2015 prop = prop->next;
2016 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002017 }
Owen Taylor3473f882001-02-23 17:55:21 +00002018 if (tree->children != NULL)
2019 xmlSetListDoc(tree->children, doc);
2020 tree->doc = doc;
2021 }
2022}
2023
2024/**
2025 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002026 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002027 * @doc: the document
2028 *
2029 * update all nodes in the list to point to the right document
2030 */
2031void
2032xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2033 xmlNodePtr cur;
2034
2035 if (list == NULL)
2036 return;
2037 cur = list;
2038 while (cur != NULL) {
2039 if (cur->doc != doc)
2040 xmlSetTreeDoc(cur, doc);
2041 cur = cur->next;
2042 }
2043}
2044
2045
2046/**
2047 * xmlNewChild:
2048 * @parent: the parent node
2049 * @ns: a namespace if any
2050 * @name: the name of the child
2051 * @content: the XML content of the child if any.
2052 *
2053 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002054 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002055 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2056 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2057 * references, but XML special chars need to be escaped first by using
2058 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2059 * support is not needed.
2060 *
2061 * Returns a pointer to the new node object.
2062 */
2063xmlNodePtr
2064xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2065 const xmlChar *name, const xmlChar *content) {
2066 xmlNodePtr cur, prev;
2067
2068 if (parent == NULL) {
2069#ifdef DEBUG_TREE
2070 xmlGenericError(xmlGenericErrorContext,
2071 "xmlNewChild : parent == NULL\n");
2072#endif
2073 return(NULL);
2074 }
2075
2076 if (name == NULL) {
2077#ifdef DEBUG_TREE
2078 xmlGenericError(xmlGenericErrorContext,
2079 "xmlNewChild : name == NULL\n");
2080#endif
2081 return(NULL);
2082 }
2083
2084 /*
2085 * Allocate a new node
2086 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002087 if (parent->type == XML_ELEMENT_NODE) {
2088 if (ns == NULL)
2089 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2090 else
2091 cur = xmlNewDocNode(parent->doc, ns, name, content);
2092 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2093 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2094 if (ns == NULL)
2095 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2096 else
2097 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
2098 } else {
2099 return(NULL);
2100 }
Owen Taylor3473f882001-02-23 17:55:21 +00002101 if (cur == NULL) return(NULL);
2102
2103 /*
2104 * add the new element at the end of the children list.
2105 */
2106 cur->type = XML_ELEMENT_NODE;
2107 cur->parent = parent;
2108 cur->doc = parent->doc;
2109 if (parent->children == NULL) {
2110 parent->children = cur;
2111 parent->last = cur;
2112 } else {
2113 prev = parent->last;
2114 prev->next = cur;
2115 cur->prev = prev;
2116 parent->last = cur;
2117 }
2118
2119 return(cur);
2120}
2121
2122/**
2123 * xmlAddNextSibling:
2124 * @cur: the child node
2125 * @elem: the new node
2126 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002127 * Add a new node @elem as the next sibling of @cur
2128 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002129 * first unlinked from its existing context.
2130 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002131 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2132 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002133 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002134 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002135 */
2136xmlNodePtr
2137xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2138 if (cur == NULL) {
2139#ifdef DEBUG_TREE
2140 xmlGenericError(xmlGenericErrorContext,
2141 "xmlAddNextSibling : cur == NULL\n");
2142#endif
2143 return(NULL);
2144 }
2145 if (elem == NULL) {
2146#ifdef DEBUG_TREE
2147 xmlGenericError(xmlGenericErrorContext,
2148 "xmlAddNextSibling : elem == NULL\n");
2149#endif
2150 return(NULL);
2151 }
2152
2153 xmlUnlinkNode(elem);
2154
2155 if (elem->type == XML_TEXT_NODE) {
2156 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002157 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002158 xmlFreeNode(elem);
2159 return(cur);
2160 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002161 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2162 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002163 xmlChar *tmp;
2164
2165 tmp = xmlStrdup(elem->content);
2166 tmp = xmlStrcat(tmp, cur->next->content);
2167 xmlNodeSetContent(cur->next, tmp);
2168 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002169 xmlFreeNode(elem);
2170 return(cur->next);
2171 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002172 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2173 /* check if an attribute with the same name exists */
2174 xmlAttrPtr attr;
2175
2176 if (elem->ns == NULL)
2177 attr = xmlHasProp(cur->parent, elem->name);
2178 else
2179 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2180 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2181 /* different instance, destroy it (attributes must be unique) */
2182 xmlFreeProp(attr);
2183 }
Owen Taylor3473f882001-02-23 17:55:21 +00002184 }
2185
2186 if (elem->doc != cur->doc) {
2187 xmlSetTreeDoc(elem, cur->doc);
2188 }
2189 elem->parent = cur->parent;
2190 elem->prev = cur;
2191 elem->next = cur->next;
2192 cur->next = elem;
2193 if (elem->next != NULL)
2194 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002195 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002196 elem->parent->last = elem;
2197 return(elem);
2198}
2199
2200/**
2201 * xmlAddPrevSibling:
2202 * @cur: the child node
2203 * @elem: the new node
2204 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002205 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002206 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002207 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002208 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002209 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2210 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002211 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002212 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002213 */
2214xmlNodePtr
2215xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2216 if (cur == NULL) {
2217#ifdef DEBUG_TREE
2218 xmlGenericError(xmlGenericErrorContext,
2219 "xmlAddPrevSibling : cur == NULL\n");
2220#endif
2221 return(NULL);
2222 }
2223 if (elem == NULL) {
2224#ifdef DEBUG_TREE
2225 xmlGenericError(xmlGenericErrorContext,
2226 "xmlAddPrevSibling : elem == NULL\n");
2227#endif
2228 return(NULL);
2229 }
2230
2231 xmlUnlinkNode(elem);
2232
2233 if (elem->type == XML_TEXT_NODE) {
2234 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002235 xmlChar *tmp;
2236
2237 tmp = xmlStrdup(elem->content);
2238 tmp = xmlStrcat(tmp, cur->content);
2239 xmlNodeSetContent(cur, tmp);
2240 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002241 xmlFreeNode(elem);
2242 return(cur);
2243 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002244 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2245 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002246 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002247 xmlFreeNode(elem);
2248 return(cur->prev);
2249 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002250 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2251 /* check if an attribute with the same name exists */
2252 xmlAttrPtr attr;
2253
2254 if (elem->ns == NULL)
2255 attr = xmlHasProp(cur->parent, elem->name);
2256 else
2257 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2258 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2259 /* different instance, destroy it (attributes must be unique) */
2260 xmlFreeProp(attr);
2261 }
Owen Taylor3473f882001-02-23 17:55:21 +00002262 }
2263
2264 if (elem->doc != cur->doc) {
2265 xmlSetTreeDoc(elem, cur->doc);
2266 }
2267 elem->parent = cur->parent;
2268 elem->next = cur;
2269 elem->prev = cur->prev;
2270 cur->prev = elem;
2271 if (elem->prev != NULL)
2272 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002273 if (elem->parent != NULL) {
2274 if (elem->type == XML_ATTRIBUTE_NODE) {
2275 if (elem->parent->properties == (xmlAttrPtr) cur) {
2276 elem->parent->properties = (xmlAttrPtr) elem;
2277 }
2278 } else {
2279 if (elem->parent->children == cur) {
2280 elem->parent->children = elem;
2281 }
2282 }
2283 }
Owen Taylor3473f882001-02-23 17:55:21 +00002284 return(elem);
2285}
2286
2287/**
2288 * xmlAddSibling:
2289 * @cur: the child node
2290 * @elem: the new node
2291 *
2292 * Add a new element @elem to the list of siblings of @cur
2293 * merging adjacent TEXT nodes (@elem may be freed)
2294 * If the new element was already inserted in a document it is
2295 * first unlinked from its existing context.
2296 *
2297 * Returns the new element or NULL in case of error.
2298 */
2299xmlNodePtr
2300xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2301 xmlNodePtr parent;
2302
2303 if (cur == NULL) {
2304#ifdef DEBUG_TREE
2305 xmlGenericError(xmlGenericErrorContext,
2306 "xmlAddSibling : cur == NULL\n");
2307#endif
2308 return(NULL);
2309 }
2310
2311 if (elem == NULL) {
2312#ifdef DEBUG_TREE
2313 xmlGenericError(xmlGenericErrorContext,
2314 "xmlAddSibling : elem == NULL\n");
2315#endif
2316 return(NULL);
2317 }
2318
2319 /*
2320 * Constant time is we can rely on the ->parent->last to find
2321 * the last sibling.
2322 */
2323 if ((cur->parent != NULL) &&
2324 (cur->parent->children != NULL) &&
2325 (cur->parent->last != NULL) &&
2326 (cur->parent->last->next == NULL)) {
2327 cur = cur->parent->last;
2328 } else {
2329 while (cur->next != NULL) cur = cur->next;
2330 }
2331
2332 xmlUnlinkNode(elem);
2333
2334 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002335 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002336 xmlFreeNode(elem);
2337 return(cur);
2338 }
2339
2340 if (elem->doc != cur->doc) {
2341 xmlSetTreeDoc(elem, cur->doc);
2342 }
2343 parent = cur->parent;
2344 elem->prev = cur;
2345 elem->next = NULL;
2346 elem->parent = parent;
2347 cur->next = elem;
2348 if (parent != NULL)
2349 parent->last = elem;
2350
2351 return(elem);
2352}
2353
2354/**
2355 * xmlAddChildList:
2356 * @parent: the parent node
2357 * @cur: the first node in the list
2358 *
2359 * Add a list of node at the end of the child list of the parent
2360 * merging adjacent TEXT nodes (@cur may be freed)
2361 *
2362 * Returns the last child or NULL in case of error.
2363 */
2364xmlNodePtr
2365xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2366 xmlNodePtr prev;
2367
2368 if (parent == NULL) {
2369#ifdef DEBUG_TREE
2370 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002371 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002372#endif
2373 return(NULL);
2374 }
2375
2376 if (cur == NULL) {
2377#ifdef DEBUG_TREE
2378 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002379 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002380#endif
2381 return(NULL);
2382 }
2383
2384 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2385 (cur->doc != parent->doc)) {
2386#ifdef DEBUG_TREE
2387 xmlGenericError(xmlGenericErrorContext,
2388 "Elements moved to a different document\n");
2389#endif
2390 }
2391
2392 /*
2393 * add the first element at the end of the children list.
2394 */
2395 if (parent->children == NULL) {
2396 parent->children = cur;
2397 } else {
2398 /*
2399 * If cur and parent->last both are TEXT nodes, then merge them.
2400 */
2401 if ((cur->type == XML_TEXT_NODE) &&
2402 (parent->last->type == XML_TEXT_NODE) &&
2403 (cur->name == parent->last->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002404 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002405 /*
2406 * if it's the only child, nothing more to be done.
2407 */
2408 if (cur->next == NULL) {
2409 xmlFreeNode(cur);
2410 return(parent->last);
2411 }
2412 prev = cur;
2413 cur = cur->next;
2414 xmlFreeNode(prev);
2415 }
2416 prev = parent->last;
2417 prev->next = cur;
2418 cur->prev = prev;
2419 }
2420 while (cur->next != NULL) {
2421 cur->parent = parent;
2422 if (cur->doc != parent->doc) {
2423 xmlSetTreeDoc(cur, parent->doc);
2424 }
2425 cur = cur->next;
2426 }
2427 cur->parent = parent;
2428 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2429 parent->last = cur;
2430
2431 return(cur);
2432}
2433
2434/**
2435 * xmlAddChild:
2436 * @parent: the parent node
2437 * @cur: the child node
2438 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002439 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002440 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002441 * If the new node was already inserted in a document it is
2442 * first unlinked from its existing context.
2443 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2444 * If there is an attribute with equal name, it is first destroyed.
2445 *
Owen Taylor3473f882001-02-23 17:55:21 +00002446 * Returns the child or NULL in case of error.
2447 */
2448xmlNodePtr
2449xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2450 xmlNodePtr prev;
2451
2452 if (parent == NULL) {
2453#ifdef DEBUG_TREE
2454 xmlGenericError(xmlGenericErrorContext,
2455 "xmlAddChild : parent == NULL\n");
2456#endif
2457 return(NULL);
2458 }
2459
2460 if (cur == NULL) {
2461#ifdef DEBUG_TREE
2462 xmlGenericError(xmlGenericErrorContext,
2463 "xmlAddChild : child == NULL\n");
2464#endif
2465 return(NULL);
2466 }
2467
Owen Taylor3473f882001-02-23 17:55:21 +00002468 /*
2469 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002470 * cur is then freed.
2471 */
2472 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002473 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002474 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002475 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002476 xmlFreeNode(cur);
2477 return(parent);
2478 }
2479 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2480 (parent->last->name == cur->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002481 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002482 xmlFreeNode(cur);
2483 return(parent->last);
2484 }
2485 }
2486
2487 /*
2488 * add the new element at the end of the children list.
2489 */
2490 cur->parent = parent;
2491 if (cur->doc != parent->doc) {
2492 xmlSetTreeDoc(cur, parent->doc);
2493 }
2494
2495 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002496 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002497 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002498 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002499 (parent->content != NULL)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002500 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002501 xmlFreeNode(cur);
2502 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002503 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002504 if (cur->type == XML_ATTRIBUTE_NODE) {
2505 if (parent->properties == NULL) {
2506 parent->properties = (xmlAttrPtr) cur;
2507 } else {
2508 /* check if an attribute with the same name exists */
2509 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002510
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002511 if (cur->ns == NULL)
2512 lastattr = xmlHasProp(parent, cur->name);
2513 else
2514 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2515 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2516 /* different instance, destroy it (attributes must be unique) */
2517 xmlFreeProp(lastattr);
2518 }
2519 /* find the end */
2520 lastattr = parent->properties;
2521 while (lastattr->next != NULL) {
2522 lastattr = lastattr->next;
2523 }
2524 lastattr->next = (xmlAttrPtr) cur;
2525 ((xmlAttrPtr) cur)->prev = lastattr;
2526 }
2527 } else {
2528 if (parent->children == NULL) {
2529 parent->children = cur;
2530 parent->last = cur;
2531 } else {
2532 prev = parent->last;
2533 prev->next = cur;
2534 cur->prev = prev;
2535 parent->last = cur;
2536 }
2537 }
Owen Taylor3473f882001-02-23 17:55:21 +00002538 return(cur);
2539}
2540
2541/**
2542 * xmlGetLastChild:
2543 * @parent: the parent node
2544 *
2545 * Search the last child of a node.
2546 * Returns the last child or NULL if none.
2547 */
2548xmlNodePtr
2549xmlGetLastChild(xmlNodePtr parent) {
2550 if (parent == NULL) {
2551#ifdef DEBUG_TREE
2552 xmlGenericError(xmlGenericErrorContext,
2553 "xmlGetLastChild : parent == NULL\n");
2554#endif
2555 return(NULL);
2556 }
2557 return(parent->last);
2558}
2559
2560/**
2561 * xmlFreeNodeList:
2562 * @cur: the first node in the list
2563 *
2564 * Free a node and all its siblings, this is a recursive behaviour, all
2565 * the children are freed too.
2566 */
2567void
2568xmlFreeNodeList(xmlNodePtr cur) {
2569 xmlNodePtr next;
2570 if (cur == NULL) {
2571#ifdef DEBUG_TREE
2572 xmlGenericError(xmlGenericErrorContext,
2573 "xmlFreeNodeList : node == NULL\n");
2574#endif
2575 return;
2576 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002577 if (cur->type == XML_NAMESPACE_DECL) {
2578 xmlFreeNsList((xmlNsPtr) cur);
2579 return;
2580 }
Owen Taylor3473f882001-02-23 17:55:21 +00002581 while (cur != NULL) {
2582 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002583 /* unroll to speed up freeing the document */
2584 if (cur->type != XML_DTD_NODE) {
2585 if ((cur->children != NULL) &&
2586 (cur->type != XML_ENTITY_REF_NODE))
2587 xmlFreeNodeList(cur->children);
2588 if (cur->properties != NULL)
2589 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002590 if ((cur->type != XML_ELEMENT_NODE) &&
2591 (cur->type != XML_XINCLUDE_START) &&
2592 (cur->type != XML_XINCLUDE_END) &&
2593 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002594 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002595 }
2596 if (((cur->type == XML_ELEMENT_NODE) ||
2597 (cur->type == XML_XINCLUDE_START) ||
2598 (cur->type == XML_XINCLUDE_END)) &&
2599 (cur->nsDef != NULL))
2600 xmlFreeNsList(cur->nsDef);
2601
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002602 /*
2603 * When a node is a text node or a comment, it uses a global static
2604 * variable for the name of the node.
2605 *
2606 * The xmlStrEqual comparisons need to be done when (happened with
2607 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002608 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002609 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002610 * the string addresses compare are not sufficient.
2611 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002612 if ((cur->name != NULL) &&
2613 (cur->name != xmlStringText) &&
2614 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002615 (cur->name != xmlStringComment)) {
2616 if (cur->type == XML_TEXT_NODE) {
2617 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2618 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2619 xmlFree((char *) cur->name);
2620 } else if (cur->type == XML_COMMENT_NODE) {
2621 if (!xmlStrEqual(cur->name, xmlStringComment))
2622 xmlFree((char *) cur->name);
2623 } else
2624 xmlFree((char *) cur->name);
2625 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002626 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002627 xmlFree(cur);
2628 }
Owen Taylor3473f882001-02-23 17:55:21 +00002629 cur = next;
2630 }
2631}
2632
2633/**
2634 * xmlFreeNode:
2635 * @cur: the node
2636 *
2637 * Free a node, this is a recursive behaviour, all the children are freed too.
2638 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2639 */
2640void
2641xmlFreeNode(xmlNodePtr cur) {
2642 if (cur == NULL) {
2643#ifdef DEBUG_TREE
2644 xmlGenericError(xmlGenericErrorContext,
2645 "xmlFreeNode : node == NULL\n");
2646#endif
2647 return;
2648 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002649 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002650 if (cur->type == XML_DTD_NODE) {
2651 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002652 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002653 }
2654 if (cur->type == XML_NAMESPACE_DECL) {
2655 xmlFreeNs((xmlNsPtr) cur);
2656 return;
2657 }
Owen Taylor3473f882001-02-23 17:55:21 +00002658 if ((cur->children != NULL) &&
2659 (cur->type != XML_ENTITY_REF_NODE))
2660 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002661 if (cur->properties != NULL)
2662 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002663 if ((cur->type != XML_ELEMENT_NODE) &&
2664 (cur->content != NULL) &&
2665 (cur->type != XML_ENTITY_REF_NODE) &&
2666 (cur->type != XML_XINCLUDE_END) &&
2667 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002668 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002669 }
2670
Daniel Veillardacd370f2001-06-09 17:17:51 +00002671 /*
2672 * When a node is a text node or a comment, it uses a global static
2673 * variable for the name of the node.
2674 *
2675 * The xmlStrEqual comparisons need to be done when (happened with
2676 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002677 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002678 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002679 * are not sufficient.
2680 */
Owen Taylor3473f882001-02-23 17:55:21 +00002681 if ((cur->name != NULL) &&
2682 (cur->name != xmlStringText) &&
2683 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002684 (cur->name != xmlStringComment)) {
2685 if (cur->type == XML_TEXT_NODE) {
2686 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2687 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2688 xmlFree((char *) cur->name);
2689 } else if (cur->type == XML_COMMENT_NODE) {
2690 if (!xmlStrEqual(cur->name, xmlStringComment))
2691 xmlFree((char *) cur->name);
2692 } else
2693 xmlFree((char *) cur->name);
2694 }
2695
Owen Taylor3473f882001-02-23 17:55:21 +00002696 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002697 xmlFree(cur);
2698}
2699
2700/**
2701 * xmlUnlinkNode:
2702 * @cur: the node
2703 *
2704 * Unlink a node from it's current context, the node is not freed
2705 */
2706void
2707xmlUnlinkNode(xmlNodePtr cur) {
2708 if (cur == NULL) {
2709#ifdef DEBUG_TREE
2710 xmlGenericError(xmlGenericErrorContext,
2711 "xmlUnlinkNode : node == NULL\n");
2712#endif
2713 return;
2714 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002715 if (cur->type == XML_DTD_NODE) {
2716 xmlDocPtr doc;
2717 doc = cur->doc;
2718 if (doc->intSubset == (xmlDtdPtr) cur)
2719 doc->intSubset = NULL;
2720 if (doc->extSubset == (xmlDtdPtr) cur)
2721 doc->extSubset = NULL;
2722 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002723 if (cur->parent != NULL) {
2724 xmlNodePtr parent;
2725 parent = cur->parent;
2726 if (cur->type == XML_ATTRIBUTE_NODE) {
2727 if (parent->properties == (xmlAttrPtr) cur)
2728 parent->properties = ((xmlAttrPtr) cur)->next;
2729 } else {
2730 if (parent->children == cur)
2731 parent->children = cur->next;
2732 if (parent->last == cur)
2733 parent->last = cur->prev;
2734 }
2735 cur->parent = NULL;
2736 }
Owen Taylor3473f882001-02-23 17:55:21 +00002737 if (cur->next != NULL)
2738 cur->next->prev = cur->prev;
2739 if (cur->prev != NULL)
2740 cur->prev->next = cur->next;
2741 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002742}
2743
2744/**
2745 * xmlReplaceNode:
2746 * @old: the old node
2747 * @cur: the node
2748 *
2749 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002750 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002751 * first unlinked from its existing context.
2752 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002753 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002754 */
2755xmlNodePtr
2756xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2757 if (old == NULL) {
2758#ifdef DEBUG_TREE
2759 xmlGenericError(xmlGenericErrorContext,
2760 "xmlReplaceNode : old == NULL\n");
2761#endif
2762 return(NULL);
2763 }
2764 if (cur == NULL) {
2765 xmlUnlinkNode(old);
2766 return(old);
2767 }
2768 if (cur == old) {
2769 return(old);
2770 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002771 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2772#ifdef DEBUG_TREE
2773 xmlGenericError(xmlGenericErrorContext,
2774 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2775#endif
2776 return(old);
2777 }
2778 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2779#ifdef DEBUG_TREE
2780 xmlGenericError(xmlGenericErrorContext,
2781 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2782#endif
2783 return(old);
2784 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002785 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2786#ifdef DEBUG_TREE
2787 xmlGenericError(xmlGenericErrorContext,
2788 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2789#endif
2790 return(old);
2791 }
2792 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2793#ifdef DEBUG_TREE
2794 xmlGenericError(xmlGenericErrorContext,
2795 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2796#endif
2797 return(old);
2798 }
Owen Taylor3473f882001-02-23 17:55:21 +00002799 xmlUnlinkNode(cur);
2800 cur->doc = old->doc;
2801 cur->parent = old->parent;
2802 cur->next = old->next;
2803 if (cur->next != NULL)
2804 cur->next->prev = cur;
2805 cur->prev = old->prev;
2806 if (cur->prev != NULL)
2807 cur->prev->next = cur;
2808 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002809 if (cur->type == XML_ATTRIBUTE_NODE) {
2810 if (cur->parent->properties == (xmlAttrPtr)old)
2811 cur->parent->properties = ((xmlAttrPtr) cur);
2812 } else {
2813 if (cur->parent->children == old)
2814 cur->parent->children = cur;
2815 if (cur->parent->last == old)
2816 cur->parent->last = cur;
2817 }
Owen Taylor3473f882001-02-23 17:55:21 +00002818 }
2819 old->next = old->prev = NULL;
2820 old->parent = NULL;
2821 return(old);
2822}
2823
2824/************************************************************************
2825 * *
2826 * Copy operations *
2827 * *
2828 ************************************************************************/
2829
2830/**
2831 * xmlCopyNamespace:
2832 * @cur: the namespace
2833 *
2834 * Do a copy of the namespace.
2835 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002836 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002837 */
2838xmlNsPtr
2839xmlCopyNamespace(xmlNsPtr cur) {
2840 xmlNsPtr ret;
2841
2842 if (cur == NULL) return(NULL);
2843 switch (cur->type) {
2844 case XML_LOCAL_NAMESPACE:
2845 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2846 break;
2847 default:
2848#ifdef DEBUG_TREE
2849 xmlGenericError(xmlGenericErrorContext,
2850 "xmlCopyNamespace: invalid type %d\n", cur->type);
2851#endif
2852 return(NULL);
2853 }
2854 return(ret);
2855}
2856
2857/**
2858 * xmlCopyNamespaceList:
2859 * @cur: the first namespace
2860 *
2861 * Do a copy of an namespace list.
2862 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002863 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002864 */
2865xmlNsPtr
2866xmlCopyNamespaceList(xmlNsPtr cur) {
2867 xmlNsPtr ret = NULL;
2868 xmlNsPtr p = NULL,q;
2869
2870 while (cur != NULL) {
2871 q = xmlCopyNamespace(cur);
2872 if (p == NULL) {
2873 ret = p = q;
2874 } else {
2875 p->next = q;
2876 p = q;
2877 }
2878 cur = cur->next;
2879 }
2880 return(ret);
2881}
2882
2883static xmlNodePtr
2884xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2885/**
2886 * xmlCopyProp:
2887 * @target: the element where the attribute will be grafted
2888 * @cur: the attribute
2889 *
2890 * Do a copy of the attribute.
2891 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002892 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002893 */
2894xmlAttrPtr
2895xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2896 xmlAttrPtr ret;
2897
2898 if (cur == NULL) return(NULL);
2899 if (target != NULL)
2900 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2901 else if (cur->parent != NULL)
2902 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2903 else if (cur->children != NULL)
2904 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2905 else
2906 ret = xmlNewDocProp(NULL, cur->name, NULL);
2907 if (ret == NULL) return(NULL);
2908 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002909
Owen Taylor3473f882001-02-23 17:55:21 +00002910 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00002911 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002912/*
2913 * if (target->doc)
2914 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2915 * else if (cur->doc) / * target may not yet have a doc : KPI * /
2916 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
2917 * else
2918 * ns = NULL;
2919 * ret->ns = ns;
2920 */
2921 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2922 if (ns == NULL) {
2923 /*
2924 * Humm, we are copying an element whose namespace is defined
2925 * out of the new tree scope. Search it in the original tree
2926 * and add it at the top of the new tree
2927 */
2928 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
2929 if (ns != NULL) {
2930 xmlNodePtr root = target;
2931 xmlNodePtr pred = NULL;
2932
2933 while (root->parent != NULL) {
2934 pred = root;
2935 root = root->parent;
2936 }
2937 if (root == (xmlNodePtr) target->doc) {
2938 /* correct possibly cycling above the document elt */
2939 root = pred;
2940 }
2941 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
2942 }
2943 } else {
2944 /*
2945 * we have to find something appropriate here since
2946 * we cant be sure, that the namespce we found is identified
2947 * by the prefix
2948 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002949 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002950 /* this is the nice case */
2951 ret->ns = ns;
2952 } else {
2953 /*
2954 * we are in trouble: we need a new reconcilied namespace.
2955 * This is expensive
2956 */
2957 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
2958 }
2959 }
2960
Owen Taylor3473f882001-02-23 17:55:21 +00002961 } else
2962 ret->ns = NULL;
2963
2964 if (cur->children != NULL) {
2965 xmlNodePtr tmp;
2966
2967 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2968 ret->last = NULL;
2969 tmp = ret->children;
2970 while (tmp != NULL) {
2971 /* tmp->parent = (xmlNodePtr)ret; */
2972 if (tmp->next == NULL)
2973 ret->last = tmp;
2974 tmp = tmp->next;
2975 }
2976 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002977 /*
2978 * Try to handle IDs
2979 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00002980 if ((target!= NULL) && (cur!= NULL) &&
2981 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002982 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
2983 if (xmlIsID(cur->doc, cur->parent, cur)) {
2984 xmlChar *id;
2985
2986 id = xmlNodeListGetString(cur->doc, cur->children, 1);
2987 if (id != NULL) {
2988 xmlAddID(NULL, target->doc, id, ret);
2989 xmlFree(id);
2990 }
2991 }
2992 }
Owen Taylor3473f882001-02-23 17:55:21 +00002993 return(ret);
2994}
2995
2996/**
2997 * xmlCopyPropList:
2998 * @target: the element where the attributes will be grafted
2999 * @cur: the first attribute
3000 *
3001 * Do a copy of an attribute list.
3002 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003003 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003004 */
3005xmlAttrPtr
3006xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3007 xmlAttrPtr ret = NULL;
3008 xmlAttrPtr p = NULL,q;
3009
3010 while (cur != NULL) {
3011 q = xmlCopyProp(target, cur);
3012 if (p == NULL) {
3013 ret = p = q;
3014 } else {
3015 p->next = q;
3016 q->prev = p;
3017 p = q;
3018 }
3019 cur = cur->next;
3020 }
3021 return(ret);
3022}
3023
3024/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003025 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003026 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003027 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003028 * tricky reason: namespaces. Doing a direct copy of a node
3029 * say RPM:Copyright without changing the namespace pointer to
3030 * something else can produce stale links. One way to do it is
3031 * to keep a reference counter but this doesn't work as soon
3032 * as one move the element or the subtree out of the scope of
3033 * the existing namespace. The actual solution seems to add
3034 * a copy of the namespace at the top of the copied tree if
3035 * not available in the subtree.
3036 * Hence two functions, the public front-end call the inner ones
3037 */
3038
3039static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003040xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003041 int recursive) {
3042 xmlNodePtr ret;
3043
3044 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003045 switch (node->type) {
3046 case XML_TEXT_NODE:
3047 case XML_CDATA_SECTION_NODE:
3048 case XML_ELEMENT_NODE:
3049 case XML_ENTITY_REF_NODE:
3050 case XML_ENTITY_NODE:
3051 case XML_PI_NODE:
3052 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003053 case XML_XINCLUDE_START:
3054 case XML_XINCLUDE_END:
3055 break;
3056 case XML_ATTRIBUTE_NODE:
3057 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3058 case XML_NAMESPACE_DECL:
3059 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3060
Daniel Veillard39196eb2001-06-19 18:09:42 +00003061 case XML_DOCUMENT_NODE:
3062 case XML_HTML_DOCUMENT_NODE:
3063#ifdef LIBXML_DOCB_ENABLED
3064 case XML_DOCB_DOCUMENT_NODE:
3065#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003066 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003067 case XML_DOCUMENT_TYPE_NODE:
3068 case XML_DOCUMENT_FRAG_NODE:
3069 case XML_NOTATION_NODE:
3070 case XML_DTD_NODE:
3071 case XML_ELEMENT_DECL:
3072 case XML_ATTRIBUTE_DECL:
3073 case XML_ENTITY_DECL:
3074 return(NULL);
3075 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003076
Owen Taylor3473f882001-02-23 17:55:21 +00003077 /*
3078 * Allocate a new node and fill the fields.
3079 */
3080 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3081 if (ret == NULL) {
3082 xmlGenericError(xmlGenericErrorContext,
3083 "xmlStaticCopyNode : malloc failed\n");
3084 return(NULL);
3085 }
3086 memset(ret, 0, sizeof(xmlNode));
3087 ret->type = node->type;
3088
3089 ret->doc = doc;
3090 ret->parent = parent;
3091 if (node->name == xmlStringText)
3092 ret->name = xmlStringText;
3093 else if (node->name == xmlStringTextNoenc)
3094 ret->name = xmlStringTextNoenc;
3095 else if (node->name == xmlStringComment)
3096 ret->name = xmlStringComment;
3097 else if (node->name != NULL)
3098 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003099 if ((node->type != XML_ELEMENT_NODE) &&
3100 (node->content != NULL) &&
3101 (node->type != XML_ENTITY_REF_NODE) &&
3102 (node->type != XML_XINCLUDE_END) &&
3103 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003104 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003105 }else{
3106 if (node->type == XML_ELEMENT_NODE)
3107 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003108 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003109 if (parent != NULL) {
3110 xmlNodePtr tmp;
3111
3112 tmp = xmlAddChild(parent, ret);
3113 /* node could have coalesced */
3114 if (tmp != ret)
3115 return(tmp);
3116 }
Owen Taylor3473f882001-02-23 17:55:21 +00003117
3118 if (!recursive) return(ret);
3119 if (node->nsDef != NULL)
3120 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3121
3122 if (node->ns != NULL) {
3123 xmlNsPtr ns;
3124
3125 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3126 if (ns == NULL) {
3127 /*
3128 * Humm, we are copying an element whose namespace is defined
3129 * out of the new tree scope. Search it in the original tree
3130 * and add it at the top of the new tree
3131 */
3132 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3133 if (ns != NULL) {
3134 xmlNodePtr root = ret;
3135
3136 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003137 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003138 }
3139 } else {
3140 /*
3141 * reference the existing namespace definition in our own tree.
3142 */
3143 ret->ns = ns;
3144 }
3145 }
3146 if (node->properties != NULL)
3147 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003148 if (node->type == XML_ENTITY_REF_NODE) {
3149 if ((doc == NULL) || (node->doc != doc)) {
3150 /*
3151 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003152 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003153 * we cannot keep the reference. Try to find it in the
3154 * target document.
3155 */
3156 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3157 } else {
3158 ret->children = node->children;
3159 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003160 ret->last = ret->children;
3161 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003162 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003163 UPDATE_LAST_CHILD_AND_PARENT(ret)
3164 }
Owen Taylor3473f882001-02-23 17:55:21 +00003165 return(ret);
3166}
3167
3168static xmlNodePtr
3169xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3170 xmlNodePtr ret = NULL;
3171 xmlNodePtr p = NULL,q;
3172
3173 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003174 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003175 if (doc == NULL) {
3176 node = node->next;
3177 continue;
3178 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003179 if (doc->intSubset == NULL) {
3180 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3181 q->doc = doc;
3182 q->parent = parent;
3183 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003184 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003185 } else {
3186 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003187 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003188 }
3189 } else
3190 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003191 if (ret == NULL) {
3192 q->prev = NULL;
3193 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003194 } else if (p != q) {
3195 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003196 p->next = q;
3197 q->prev = p;
3198 p = q;
3199 }
3200 node = node->next;
3201 }
3202 return(ret);
3203}
3204
3205/**
3206 * xmlCopyNode:
3207 * @node: the node
3208 * @recursive: if 1 do a recursive copy.
3209 *
3210 * Do a copy of the node.
3211 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003212 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003213 */
3214xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003215xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003216 xmlNodePtr ret;
3217
3218 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3219 return(ret);
3220}
3221
3222/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003223 * xmlDocCopyNode:
3224 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003225 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003226 * @recursive: if 1 do a recursive copy.
3227 *
3228 * Do a copy of the node to a given document.
3229 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003230 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003231 */
3232xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003233xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003234 xmlNodePtr ret;
3235
3236 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3237 return(ret);
3238}
3239
3240/**
Owen Taylor3473f882001-02-23 17:55:21 +00003241 * xmlCopyNodeList:
3242 * @node: the first node in the list.
3243 *
3244 * Do a recursive copy of the node list.
3245 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003246 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003247 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003248xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003249 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3250 return(ret);
3251}
3252
3253/**
Owen Taylor3473f882001-02-23 17:55:21 +00003254 * xmlCopyDtd:
3255 * @dtd: the dtd
3256 *
3257 * Do a copy of the dtd.
3258 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003259 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003260 */
3261xmlDtdPtr
3262xmlCopyDtd(xmlDtdPtr dtd) {
3263 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003264 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003265
3266 if (dtd == NULL) return(NULL);
3267 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3268 if (ret == NULL) return(NULL);
3269 if (dtd->entities != NULL)
3270 ret->entities = (void *) xmlCopyEntitiesTable(
3271 (xmlEntitiesTablePtr) dtd->entities);
3272 if (dtd->notations != NULL)
3273 ret->notations = (void *) xmlCopyNotationTable(
3274 (xmlNotationTablePtr) dtd->notations);
3275 if (dtd->elements != NULL)
3276 ret->elements = (void *) xmlCopyElementTable(
3277 (xmlElementTablePtr) dtd->elements);
3278 if (dtd->attributes != NULL)
3279 ret->attributes = (void *) xmlCopyAttributeTable(
3280 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003281 if (dtd->pentities != NULL)
3282 ret->pentities = (void *) xmlCopyEntitiesTable(
3283 (xmlEntitiesTablePtr) dtd->pentities);
3284
3285 cur = dtd->children;
3286 while (cur != NULL) {
3287 q = NULL;
3288
3289 if (cur->type == XML_ENTITY_DECL) {
3290 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3291 switch (tmp->etype) {
3292 case XML_INTERNAL_GENERAL_ENTITY:
3293 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3294 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3295 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3296 break;
3297 case XML_INTERNAL_PARAMETER_ENTITY:
3298 case XML_EXTERNAL_PARAMETER_ENTITY:
3299 q = (xmlNodePtr)
3300 xmlGetParameterEntityFromDtd(ret, tmp->name);
3301 break;
3302 case XML_INTERNAL_PREDEFINED_ENTITY:
3303 break;
3304 }
3305 } else if (cur->type == XML_ELEMENT_DECL) {
3306 xmlElementPtr tmp = (xmlElementPtr) cur;
3307 q = (xmlNodePtr)
3308 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3309 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3310 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3311 q = (xmlNodePtr)
3312 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3313 } else if (cur->type == XML_COMMENT_NODE) {
3314 q = xmlCopyNode(cur, 0);
3315 }
3316
3317 if (q == NULL) {
3318 cur = cur->next;
3319 continue;
3320 }
3321
3322 if (p == NULL)
3323 ret->children = q;
3324 else
3325 p->next = q;
3326
3327 q->prev = p;
3328 q->parent = (xmlNodePtr) ret;
3329 q->next = NULL;
3330 ret->last = q;
3331 p = q;
3332 cur = cur->next;
3333 }
3334
Owen Taylor3473f882001-02-23 17:55:21 +00003335 return(ret);
3336}
3337
3338/**
3339 * xmlCopyDoc:
3340 * @doc: the document
3341 * @recursive: if 1 do a recursive copy.
3342 *
3343 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003344 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003345 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003346 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003347 */
3348xmlDocPtr
3349xmlCopyDoc(xmlDocPtr doc, int recursive) {
3350 xmlDocPtr ret;
3351
3352 if (doc == NULL) return(NULL);
3353 ret = xmlNewDoc(doc->version);
3354 if (ret == NULL) return(NULL);
3355 if (doc->name != NULL)
3356 ret->name = xmlMemStrdup(doc->name);
3357 if (doc->encoding != NULL)
3358 ret->encoding = xmlStrdup(doc->encoding);
3359 ret->charset = doc->charset;
3360 ret->compression = doc->compression;
3361 ret->standalone = doc->standalone;
3362 if (!recursive) return(ret);
3363
Daniel Veillardb33c2012001-04-25 12:59:04 +00003364 ret->last = NULL;
3365 ret->children = NULL;
3366 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003367 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003368 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003369 ret->intSubset->parent = ret;
3370 }
Owen Taylor3473f882001-02-23 17:55:21 +00003371 if (doc->oldNs != NULL)
3372 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3373 if (doc->children != NULL) {
3374 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003375
3376 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3377 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003378 ret->last = NULL;
3379 tmp = ret->children;
3380 while (tmp != NULL) {
3381 if (tmp->next == NULL)
3382 ret->last = tmp;
3383 tmp = tmp->next;
3384 }
3385 }
3386 return(ret);
3387}
3388
3389/************************************************************************
3390 * *
3391 * Content access functions *
3392 * *
3393 ************************************************************************/
3394
3395/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003396 * xmlGetLineNo:
3397 * @node : valid node
3398 *
3399 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003400 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003401 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003402 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003403 */
3404long
3405xmlGetLineNo(xmlNodePtr node)
3406{
3407 long result = -1;
3408
3409 if (!node)
3410 return result;
3411 if (node->type == XML_ELEMENT_NODE)
3412 result = (long) node->content;
3413 else if ((node->prev != NULL) &&
3414 ((node->prev->type == XML_ELEMENT_NODE) ||
3415 (node->prev->type == XML_TEXT_NODE)))
3416 result = xmlGetLineNo(node->prev);
3417 else if ((node->parent != NULL) &&
3418 ((node->parent->type == XML_ELEMENT_NODE) ||
3419 (node->parent->type == XML_TEXT_NODE)))
3420 result = xmlGetLineNo(node->parent);
3421
3422 return result;
3423}
3424
3425/**
3426 * xmlGetNodePath:
3427 * @node: a node
3428 *
3429 * Build a structure based Path for the given node
3430 *
3431 * Returns the new path or NULL in case of error. The caller must free
3432 * the returned string
3433 */
3434xmlChar *
3435xmlGetNodePath(xmlNodePtr node)
3436{
3437 xmlNodePtr cur, tmp, next;
3438 xmlChar *buffer = NULL, *temp;
3439 size_t buf_len;
3440 xmlChar *buf;
3441 char sep;
3442 const char *name;
3443 char nametemp[100];
3444 int occur = 0;
3445
3446 if (node == NULL)
3447 return (NULL);
3448
3449 buf_len = 500;
3450 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3451 if (buffer == NULL)
3452 return (NULL);
3453 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3454 if (buf == NULL) {
3455 xmlFree(buffer);
3456 return (NULL);
3457 }
3458
3459 buffer[0] = 0;
3460 cur = node;
3461 do {
3462 name = "";
3463 sep = '?';
3464 occur = 0;
3465 if ((cur->type == XML_DOCUMENT_NODE) ||
3466 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3467 if (buffer[0] == '/')
3468 break;
3469 sep = '/';
3470 next = NULL;
3471 } else if (cur->type == XML_ELEMENT_NODE) {
3472 sep = '/';
3473 name = (const char *) cur->name;
3474 if (cur->ns) {
3475 snprintf(nametemp, sizeof(nametemp) - 1,
3476 "%s:%s", cur->ns->prefix, cur->name);
3477 nametemp[sizeof(nametemp) - 1] = 0;
3478 name = nametemp;
3479 }
3480 next = cur->parent;
3481
3482 /*
3483 * Thumbler index computation
3484 */
3485 tmp = cur->prev;
3486 while (tmp != NULL) {
3487 if (xmlStrEqual(cur->name, tmp->name))
3488 occur++;
3489 tmp = tmp->prev;
3490 }
3491 if (occur == 0) {
3492 tmp = cur->next;
3493 while (tmp != NULL) {
3494 if (xmlStrEqual(cur->name, tmp->name))
3495 occur++;
3496 tmp = tmp->next;
3497 }
3498 if (occur != 0)
3499 occur = 1;
3500 } else
3501 occur++;
3502 } else if (cur->type == XML_ATTRIBUTE_NODE) {
3503 sep = '@';
3504 name = (const char *) (((xmlAttrPtr) cur)->name);
3505 next = ((xmlAttrPtr) cur)->parent;
3506 } else {
3507 next = cur->parent;
3508 }
3509
3510 /*
3511 * Make sure there is enough room
3512 */
3513 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3514 buf_len =
3515 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3516 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3517 if (temp == NULL) {
3518 xmlFree(buf);
3519 xmlFree(buffer);
3520 return (NULL);
3521 }
3522 buffer = temp;
3523 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3524 if (temp == NULL) {
3525 xmlFree(buf);
3526 xmlFree(buffer);
3527 return (NULL);
3528 }
3529 buf = temp;
3530 }
3531 if (occur == 0)
3532 snprintf((char *) buf, buf_len, "%c%s%s",
3533 sep, name, (char *) buffer);
3534 else
3535 snprintf((char *) buf, buf_len, "%c%s[%d]%s",
3536 sep, name, occur, (char *) buffer);
3537 snprintf((char *) buffer, buf_len, "%s", buf);
3538 cur = next;
3539 } while (cur != NULL);
3540 xmlFree(buf);
3541 return (buffer);
3542}
3543
3544/**
Owen Taylor3473f882001-02-23 17:55:21 +00003545 * xmlDocGetRootElement:
3546 * @doc: the document
3547 *
3548 * Get the root element of the document (doc->children is a list
3549 * containing possibly comments, PIs, etc ...).
3550 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003551 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003552 */
3553xmlNodePtr
3554xmlDocGetRootElement(xmlDocPtr doc) {
3555 xmlNodePtr ret;
3556
3557 if (doc == NULL) return(NULL);
3558 ret = doc->children;
3559 while (ret != NULL) {
3560 if (ret->type == XML_ELEMENT_NODE)
3561 return(ret);
3562 ret = ret->next;
3563 }
3564 return(ret);
3565}
3566
3567/**
3568 * xmlDocSetRootElement:
3569 * @doc: the document
3570 * @root: the new document root element
3571 *
3572 * Set the root element of the document (doc->children is a list
3573 * containing possibly comments, PIs, etc ...).
3574 *
3575 * Returns the old root element if any was found
3576 */
3577xmlNodePtr
3578xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3579 xmlNodePtr old = NULL;
3580
3581 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00003582 if (root == NULL)
3583 return(NULL);
3584 xmlUnlinkNode(root);
3585 root->doc = doc;
3586 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00003587 old = doc->children;
3588 while (old != NULL) {
3589 if (old->type == XML_ELEMENT_NODE)
3590 break;
3591 old = old->next;
3592 }
3593 if (old == NULL) {
3594 if (doc->children == NULL) {
3595 doc->children = root;
3596 doc->last = root;
3597 } else {
3598 xmlAddSibling(doc->children, root);
3599 }
3600 } else {
3601 xmlReplaceNode(old, root);
3602 }
3603 return(old);
3604}
3605
3606/**
3607 * xmlNodeSetLang:
3608 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003609 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003610 *
3611 * Set the language of a node, i.e. the values of the xml:lang
3612 * attribute.
3613 */
3614void
3615xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003616 xmlNsPtr ns;
3617
Owen Taylor3473f882001-02-23 17:55:21 +00003618 if (cur == NULL) return;
3619 switch(cur->type) {
3620 case XML_TEXT_NODE:
3621 case XML_CDATA_SECTION_NODE:
3622 case XML_COMMENT_NODE:
3623 case XML_DOCUMENT_NODE:
3624 case XML_DOCUMENT_TYPE_NODE:
3625 case XML_DOCUMENT_FRAG_NODE:
3626 case XML_NOTATION_NODE:
3627 case XML_HTML_DOCUMENT_NODE:
3628 case XML_DTD_NODE:
3629 case XML_ELEMENT_DECL:
3630 case XML_ATTRIBUTE_DECL:
3631 case XML_ENTITY_DECL:
3632 case XML_PI_NODE:
3633 case XML_ENTITY_REF_NODE:
3634 case XML_ENTITY_NODE:
3635 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003636#ifdef LIBXML_DOCB_ENABLED
3637 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003638#endif
3639 case XML_XINCLUDE_START:
3640 case XML_XINCLUDE_END:
3641 return;
3642 case XML_ELEMENT_NODE:
3643 case XML_ATTRIBUTE_NODE:
3644 break;
3645 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003646 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3647 if (ns == NULL)
3648 return;
3649 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003650}
3651
3652/**
3653 * xmlNodeGetLang:
3654 * @cur: the node being checked
3655 *
3656 * Searches the language of a node, i.e. the values of the xml:lang
3657 * attribute or the one carried by the nearest ancestor.
3658 *
3659 * Returns a pointer to the lang value, or NULL if not found
3660 * It's up to the caller to free the memory.
3661 */
3662xmlChar *
3663xmlNodeGetLang(xmlNodePtr cur) {
3664 xmlChar *lang;
3665
3666 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003667 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003668 if (lang != NULL)
3669 return(lang);
3670 cur = cur->parent;
3671 }
3672 return(NULL);
3673}
3674
3675
3676/**
3677 * xmlNodeSetSpacePreserve:
3678 * @cur: the node being changed
3679 * @val: the xml:space value ("0": default, 1: "preserve")
3680 *
3681 * Set (or reset) the space preserving behaviour of a node, i.e. the
3682 * value of the xml:space attribute.
3683 */
3684void
3685xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003686 xmlNsPtr ns;
3687
Owen Taylor3473f882001-02-23 17:55:21 +00003688 if (cur == NULL) return;
3689 switch(cur->type) {
3690 case XML_TEXT_NODE:
3691 case XML_CDATA_SECTION_NODE:
3692 case XML_COMMENT_NODE:
3693 case XML_DOCUMENT_NODE:
3694 case XML_DOCUMENT_TYPE_NODE:
3695 case XML_DOCUMENT_FRAG_NODE:
3696 case XML_NOTATION_NODE:
3697 case XML_HTML_DOCUMENT_NODE:
3698 case XML_DTD_NODE:
3699 case XML_ELEMENT_DECL:
3700 case XML_ATTRIBUTE_DECL:
3701 case XML_ENTITY_DECL:
3702 case XML_PI_NODE:
3703 case XML_ENTITY_REF_NODE:
3704 case XML_ENTITY_NODE:
3705 case XML_NAMESPACE_DECL:
3706 case XML_XINCLUDE_START:
3707 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003708#ifdef LIBXML_DOCB_ENABLED
3709 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003710#endif
3711 return;
3712 case XML_ELEMENT_NODE:
3713 case XML_ATTRIBUTE_NODE:
3714 break;
3715 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003716 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3717 if (ns == NULL)
3718 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003719 switch (val) {
3720 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003721 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003722 break;
3723 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003724 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003725 break;
3726 }
3727}
3728
3729/**
3730 * xmlNodeGetSpacePreserve:
3731 * @cur: the node being checked
3732 *
3733 * Searches the space preserving behaviour of a node, i.e. the values
3734 * of the xml:space attribute or the one carried by the nearest
3735 * ancestor.
3736 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003737 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003738 */
3739int
3740xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3741 xmlChar *space;
3742
3743 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003744 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003745 if (space != NULL) {
3746 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3747 xmlFree(space);
3748 return(1);
3749 }
3750 if (xmlStrEqual(space, BAD_CAST "default")) {
3751 xmlFree(space);
3752 return(0);
3753 }
3754 xmlFree(space);
3755 }
3756 cur = cur->parent;
3757 }
3758 return(-1);
3759}
3760
3761/**
3762 * xmlNodeSetName:
3763 * @cur: the node being changed
3764 * @name: the new tag name
3765 *
3766 * Set (or reset) the name of a node.
3767 */
3768void
3769xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3770 if (cur == NULL) return;
3771 if (name == NULL) return;
3772 switch(cur->type) {
3773 case XML_TEXT_NODE:
3774 case XML_CDATA_SECTION_NODE:
3775 case XML_COMMENT_NODE:
3776 case XML_DOCUMENT_TYPE_NODE:
3777 case XML_DOCUMENT_FRAG_NODE:
3778 case XML_NOTATION_NODE:
3779 case XML_HTML_DOCUMENT_NODE:
3780 case XML_NAMESPACE_DECL:
3781 case XML_XINCLUDE_START:
3782 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003783#ifdef LIBXML_DOCB_ENABLED
3784 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003785#endif
3786 return;
3787 case XML_ELEMENT_NODE:
3788 case XML_ATTRIBUTE_NODE:
3789 case XML_PI_NODE:
3790 case XML_ENTITY_REF_NODE:
3791 case XML_ENTITY_NODE:
3792 case XML_DTD_NODE:
3793 case XML_DOCUMENT_NODE:
3794 case XML_ELEMENT_DECL:
3795 case XML_ATTRIBUTE_DECL:
3796 case XML_ENTITY_DECL:
3797 break;
3798 }
3799 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3800 cur->name = xmlStrdup(name);
3801}
3802
3803/**
3804 * xmlNodeSetBase:
3805 * @cur: the node being changed
3806 * @uri: the new base URI
3807 *
3808 * Set (or reset) the base URI of a node, i.e. the value of the
3809 * xml:base attribute.
3810 */
3811void
3812xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003813 xmlNsPtr ns;
3814
Owen Taylor3473f882001-02-23 17:55:21 +00003815 if (cur == NULL) return;
3816 switch(cur->type) {
3817 case XML_TEXT_NODE:
3818 case XML_CDATA_SECTION_NODE:
3819 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003820 case XML_DOCUMENT_TYPE_NODE:
3821 case XML_DOCUMENT_FRAG_NODE:
3822 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003823 case XML_DTD_NODE:
3824 case XML_ELEMENT_DECL:
3825 case XML_ATTRIBUTE_DECL:
3826 case XML_ENTITY_DECL:
3827 case XML_PI_NODE:
3828 case XML_ENTITY_REF_NODE:
3829 case XML_ENTITY_NODE:
3830 case XML_NAMESPACE_DECL:
3831 case XML_XINCLUDE_START:
3832 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00003833 return;
3834 case XML_ELEMENT_NODE:
3835 case XML_ATTRIBUTE_NODE:
3836 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00003837 case XML_DOCUMENT_NODE:
3838#ifdef LIBXML_DOCB_ENABLED
3839 case XML_DOCB_DOCUMENT_NODE:
3840#endif
3841 case XML_HTML_DOCUMENT_NODE: {
3842 xmlDocPtr doc = (xmlDocPtr) cur;
3843
3844 if (doc->URL != NULL)
3845 xmlFree((xmlChar *) doc->URL);
3846 if (uri == NULL)
3847 doc->URL = NULL;
3848 else
3849 doc->URL = xmlStrdup(uri);
3850 return;
3851 }
Owen Taylor3473f882001-02-23 17:55:21 +00003852 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003853
3854 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3855 if (ns == NULL)
3856 return;
3857 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00003858}
3859
3860/**
Owen Taylor3473f882001-02-23 17:55:21 +00003861 * xmlNodeGetBase:
3862 * @doc: the document the node pertains to
3863 * @cur: the node being checked
3864 *
3865 * Searches for the BASE URL. The code should work on both XML
3866 * and HTML document even if base mechanisms are completely different.
3867 * It returns the base as defined in RFC 2396 sections
3868 * 5.1.1. Base URI within Document Content
3869 * and
3870 * 5.1.2. Base URI from the Encapsulating Entity
3871 * However it does not return the document base (5.1.3), use
3872 * xmlDocumentGetBase() for this
3873 *
3874 * Returns a pointer to the base URL, or NULL if not found
3875 * It's up to the caller to free the memory.
3876 */
3877xmlChar *
3878xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003879 xmlChar *oldbase = NULL;
3880 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003881
3882 if ((cur == NULL) && (doc == NULL))
3883 return(NULL);
3884 if (doc == NULL) doc = cur->doc;
3885 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3886 cur = doc->children;
3887 while ((cur != NULL) && (cur->name != NULL)) {
3888 if (cur->type != XML_ELEMENT_NODE) {
3889 cur = cur->next;
3890 continue;
3891 }
3892 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3893 cur = cur->children;
3894 continue;
3895 }
3896 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3897 cur = cur->children;
3898 continue;
3899 }
3900 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3901 return(xmlGetProp(cur, BAD_CAST "href"));
3902 }
3903 cur = cur->next;
3904 }
3905 return(NULL);
3906 }
3907 while (cur != NULL) {
3908 if (cur->type == XML_ENTITY_DECL) {
3909 xmlEntityPtr ent = (xmlEntityPtr) cur;
3910 return(xmlStrdup(ent->URI));
3911 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003912 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003913 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003914 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003915 if (oldbase != NULL) {
3916 newbase = xmlBuildURI(oldbase, base);
3917 if (newbase != NULL) {
3918 xmlFree(oldbase);
3919 xmlFree(base);
3920 oldbase = newbase;
3921 } else {
3922 xmlFree(oldbase);
3923 xmlFree(base);
3924 return(NULL);
3925 }
3926 } else {
3927 oldbase = base;
3928 }
3929 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3930 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3931 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3932 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003933 }
3934 }
Owen Taylor3473f882001-02-23 17:55:21 +00003935 cur = cur->parent;
3936 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003937 if ((doc != NULL) && (doc->URL != NULL)) {
3938 if (oldbase == NULL)
3939 return(xmlStrdup(doc->URL));
3940 newbase = xmlBuildURI(oldbase, doc->URL);
3941 xmlFree(oldbase);
3942 return(newbase);
3943 }
3944 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003945}
3946
3947/**
3948 * xmlNodeGetContent:
3949 * @cur: the node being read
3950 *
3951 * Read the value of a node, this can be either the text carried
3952 * directly by this node if it's a TEXT node or the aggregate string
3953 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00003954 * Entity references are substituted.
3955 * Returns a new #xmlChar * or NULL if no content is available.
Owen Taylor3473f882001-02-23 17:55:21 +00003956 * It's up to the caller to free the memory.
3957 */
3958xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00003959xmlNodeGetContent(xmlNodePtr cur)
3960{
3961 if (cur == NULL)
3962 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003963 switch (cur->type) {
3964 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00003965 case XML_ELEMENT_NODE:{
3966 xmlNodePtr tmp = cur;
3967 xmlBufferPtr buffer;
3968 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00003969
Daniel Veillard7646b182002-04-20 06:41:40 +00003970 buffer = xmlBufferCreate();
3971 if (buffer == NULL)
3972 return (NULL);
3973 while (tmp != NULL) {
3974 switch (tmp->type) {
3975 case XML_CDATA_SECTION_NODE:
3976 case XML_TEXT_NODE:
3977 if (tmp->content != NULL)
3978 xmlBufferCat(buffer, tmp->content);
3979 break;
3980 case XML_ENTITY_REF_NODE:{
3981 /* recursive substitution of entity references */
3982 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00003983
Daniel Veillard7646b182002-04-20 06:41:40 +00003984 if (cont) {
3985 xmlBufferCat(buffer,
3986 (const xmlChar *) cont);
3987 xmlFree(cont);
3988 }
3989 break;
3990 }
3991 default:
3992 break;
3993 }
3994 /*
3995 * Skip to next node
3996 */
3997 if (tmp->children != NULL) {
3998 if (tmp->children->type != XML_ENTITY_DECL) {
3999 tmp = tmp->children;
4000 continue;
4001 }
4002 }
4003 if (tmp == cur)
4004 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004005
Daniel Veillard7646b182002-04-20 06:41:40 +00004006 if (tmp->next != NULL) {
4007 tmp = tmp->next;
4008 continue;
4009 }
4010
4011 do {
4012 tmp = tmp->parent;
4013 if (tmp == NULL)
4014 break;
4015 if (tmp == cur) {
4016 tmp = NULL;
4017 break;
4018 }
4019 if (tmp->next != NULL) {
4020 tmp = tmp->next;
4021 break;
4022 }
4023 } while (tmp != NULL);
4024 }
4025 ret = buffer->content;
4026 buffer->content = NULL;
4027 xmlBufferFree(buffer);
4028 return (ret);
4029 }
4030 case XML_ATTRIBUTE_NODE:{
4031 xmlAttrPtr attr = (xmlAttrPtr) cur;
4032
4033 if (attr->parent != NULL)
4034 return (xmlNodeListGetString
4035 (attr->parent->doc, attr->children, 1));
4036 else
4037 return (xmlNodeListGetString(NULL, attr->children, 1));
4038 break;
4039 }
Owen Taylor3473f882001-02-23 17:55:21 +00004040 case XML_COMMENT_NODE:
4041 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004042 if (cur->content != NULL)
4043 return (xmlStrdup(cur->content));
4044 return (NULL);
4045 case XML_ENTITY_REF_NODE:{
4046 xmlEntityPtr ent;
4047 xmlNodePtr tmp;
4048 xmlBufferPtr buffer;
4049 xmlChar *ret;
4050
4051 /* lookup entity declaration */
4052 ent = xmlGetDocEntity(cur->doc, cur->name);
4053 if (ent == NULL)
4054 return (NULL);
4055
4056 buffer = xmlBufferCreate();
4057 if (buffer == NULL)
4058 return (NULL);
4059
4060 /* an entity content can be any "well balanced chunk",
4061 * i.e. the result of the content [43] production:
4062 * http://www.w3.org/TR/REC-xml#NT-content
4063 * -> we iterate through child nodes and recursive call
4064 * xmlNodeGetContent() which handles all possible node types */
4065 tmp = ent->children;
4066 while (tmp) {
4067 xmlChar *cont = xmlNodeGetContent(tmp);
4068
4069 if (cont) {
4070 xmlBufferCat(buffer, (const xmlChar *) cont);
4071 xmlFree(cont);
4072 }
4073 tmp = tmp->next;
4074 }
4075
4076 ret = buffer->content;
4077 buffer->content = NULL;
4078 xmlBufferFree(buffer);
4079 return (ret);
4080 }
Owen Taylor3473f882001-02-23 17:55:21 +00004081 case XML_ENTITY_NODE:
4082 case XML_DOCUMENT_NODE:
4083 case XML_HTML_DOCUMENT_NODE:
4084 case XML_DOCUMENT_TYPE_NODE:
4085 case XML_NOTATION_NODE:
4086 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004087 case XML_XINCLUDE_START:
4088 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004089#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004090 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004091#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00004092 return (NULL);
4093 case XML_NAMESPACE_DECL:
4094 return (xmlStrdup(((xmlNsPtr) cur)->href));
Owen Taylor3473f882001-02-23 17:55:21 +00004095 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004096 /* TODO !!! */
4097 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004098 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004099 /* TODO !!! */
4100 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004101 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004102 /* TODO !!! */
4103 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004104 case XML_CDATA_SECTION_NODE:
4105 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004106 if (cur->content != NULL)
4107 return (xmlStrdup(cur->content));
4108 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004109 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004110 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004111}
Owen Taylor3473f882001-02-23 17:55:21 +00004112/**
4113 * xmlNodeSetContent:
4114 * @cur: the node being modified
4115 * @content: the new value of the content
4116 *
4117 * Replace the content of a node.
4118 */
4119void
4120xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4121 if (cur == NULL) {
4122#ifdef DEBUG_TREE
4123 xmlGenericError(xmlGenericErrorContext,
4124 "xmlNodeSetContent : node == NULL\n");
4125#endif
4126 return;
4127 }
4128 switch (cur->type) {
4129 case XML_DOCUMENT_FRAG_NODE:
4130 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004131 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004132 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4133 cur->children = xmlStringGetNodeList(cur->doc, content);
4134 UPDATE_LAST_CHILD_AND_PARENT(cur)
4135 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004136 case XML_TEXT_NODE:
4137 case XML_CDATA_SECTION_NODE:
4138 case XML_ENTITY_REF_NODE:
4139 case XML_ENTITY_NODE:
4140 case XML_PI_NODE:
4141 case XML_COMMENT_NODE:
4142 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004143 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004144 }
4145 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4146 cur->last = cur->children = NULL;
4147 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004148 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004149 } else
4150 cur->content = NULL;
4151 break;
4152 case XML_DOCUMENT_NODE:
4153 case XML_HTML_DOCUMENT_NODE:
4154 case XML_DOCUMENT_TYPE_NODE:
4155 case XML_XINCLUDE_START:
4156 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004157#ifdef LIBXML_DOCB_ENABLED
4158 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004159#endif
4160 break;
4161 case XML_NOTATION_NODE:
4162 break;
4163 case XML_DTD_NODE:
4164 break;
4165 case XML_NAMESPACE_DECL:
4166 break;
4167 case XML_ELEMENT_DECL:
4168 /* TODO !!! */
4169 break;
4170 case XML_ATTRIBUTE_DECL:
4171 /* TODO !!! */
4172 break;
4173 case XML_ENTITY_DECL:
4174 /* TODO !!! */
4175 break;
4176 }
4177}
4178
4179/**
4180 * xmlNodeSetContentLen:
4181 * @cur: the node being modified
4182 * @content: the new value of the content
4183 * @len: the size of @content
4184 *
4185 * Replace the content of a node.
4186 */
4187void
4188xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4189 if (cur == NULL) {
4190#ifdef DEBUG_TREE
4191 xmlGenericError(xmlGenericErrorContext,
4192 "xmlNodeSetContentLen : node == NULL\n");
4193#endif
4194 return;
4195 }
4196 switch (cur->type) {
4197 case XML_DOCUMENT_FRAG_NODE:
4198 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004199 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004200 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4201 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4202 UPDATE_LAST_CHILD_AND_PARENT(cur)
4203 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004204 case XML_TEXT_NODE:
4205 case XML_CDATA_SECTION_NODE:
4206 case XML_ENTITY_REF_NODE:
4207 case XML_ENTITY_NODE:
4208 case XML_PI_NODE:
4209 case XML_COMMENT_NODE:
4210 case XML_NOTATION_NODE:
4211 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004212 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004213 }
4214 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4215 cur->children = cur->last = NULL;
4216 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004217 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004218 } else
4219 cur->content = NULL;
4220 break;
4221 case XML_DOCUMENT_NODE:
4222 case XML_DTD_NODE:
4223 case XML_HTML_DOCUMENT_NODE:
4224 case XML_DOCUMENT_TYPE_NODE:
4225 case XML_NAMESPACE_DECL:
4226 case XML_XINCLUDE_START:
4227 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004228#ifdef LIBXML_DOCB_ENABLED
4229 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004230#endif
4231 break;
4232 case XML_ELEMENT_DECL:
4233 /* TODO !!! */
4234 break;
4235 case XML_ATTRIBUTE_DECL:
4236 /* TODO !!! */
4237 break;
4238 case XML_ENTITY_DECL:
4239 /* TODO !!! */
4240 break;
4241 }
4242}
4243
4244/**
4245 * xmlNodeAddContentLen:
4246 * @cur: the node being modified
4247 * @content: extra content
4248 * @len: the size of @content
4249 *
4250 * Append the extra substring to the node content.
4251 */
4252void
4253xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4254 if (cur == NULL) {
4255#ifdef DEBUG_TREE
4256 xmlGenericError(xmlGenericErrorContext,
4257 "xmlNodeAddContentLen : node == NULL\n");
4258#endif
4259 return;
4260 }
4261 if (len <= 0) return;
4262 switch (cur->type) {
4263 case XML_DOCUMENT_FRAG_NODE:
4264 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004265 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004266
Daniel Veillard7db37732001-07-12 01:20:08 +00004267 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004268 newNode = xmlNewTextLen(content, len);
4269 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004270 tmp = xmlAddChild(cur, newNode);
4271 if (tmp != newNode)
4272 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004273 if ((last != NULL) && (last->next == newNode)) {
4274 xmlTextMerge(last, newNode);
4275 }
4276 }
4277 break;
4278 }
4279 case XML_ATTRIBUTE_NODE:
4280 break;
4281 case XML_TEXT_NODE:
4282 case XML_CDATA_SECTION_NODE:
4283 case XML_ENTITY_REF_NODE:
4284 case XML_ENTITY_NODE:
4285 case XML_PI_NODE:
4286 case XML_COMMENT_NODE:
4287 case XML_NOTATION_NODE:
4288 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004289 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004290 }
4291 case XML_DOCUMENT_NODE:
4292 case XML_DTD_NODE:
4293 case XML_HTML_DOCUMENT_NODE:
4294 case XML_DOCUMENT_TYPE_NODE:
4295 case XML_NAMESPACE_DECL:
4296 case XML_XINCLUDE_START:
4297 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004298#ifdef LIBXML_DOCB_ENABLED
4299 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004300#endif
4301 break;
4302 case XML_ELEMENT_DECL:
4303 case XML_ATTRIBUTE_DECL:
4304 case XML_ENTITY_DECL:
4305 break;
4306 }
4307}
4308
4309/**
4310 * xmlNodeAddContent:
4311 * @cur: the node being modified
4312 * @content: extra content
4313 *
4314 * Append the extra substring to the node content.
4315 */
4316void
4317xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4318 int len;
4319
4320 if (cur == NULL) {
4321#ifdef DEBUG_TREE
4322 xmlGenericError(xmlGenericErrorContext,
4323 "xmlNodeAddContent : node == NULL\n");
4324#endif
4325 return;
4326 }
4327 if (content == NULL) return;
4328 len = xmlStrlen(content);
4329 xmlNodeAddContentLen(cur, content, len);
4330}
4331
4332/**
4333 * xmlTextMerge:
4334 * @first: the first text node
4335 * @second: the second text node being merged
4336 *
4337 * Merge two text nodes into one
4338 * Returns the first text node augmented
4339 */
4340xmlNodePtr
4341xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4342 if (first == NULL) return(second);
4343 if (second == NULL) return(first);
4344 if (first->type != XML_TEXT_NODE) return(first);
4345 if (second->type != XML_TEXT_NODE) return(first);
4346 if (second->name != first->name)
4347 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004348 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004349 xmlUnlinkNode(second);
4350 xmlFreeNode(second);
4351 return(first);
4352}
4353
4354/**
4355 * xmlGetNsList:
4356 * @doc: the document
4357 * @node: the current node
4358 *
4359 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004360 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004361 * that need to be freed by the caller or NULL if no
4362 * namespace if defined
4363 */
4364xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004365xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4366{
Owen Taylor3473f882001-02-23 17:55:21 +00004367 xmlNsPtr cur;
4368 xmlNsPtr *ret = NULL;
4369 int nbns = 0;
4370 int maxns = 10;
4371 int i;
4372
4373 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004374 if (node->type == XML_ELEMENT_NODE) {
4375 cur = node->nsDef;
4376 while (cur != NULL) {
4377 if (ret == NULL) {
4378 ret =
4379 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4380 sizeof(xmlNsPtr));
4381 if (ret == NULL) {
4382 xmlGenericError(xmlGenericErrorContext,
4383 "xmlGetNsList : out of memory!\n");
4384 return (NULL);
4385 }
4386 ret[nbns] = NULL;
4387 }
4388 for (i = 0; i < nbns; i++) {
4389 if ((cur->prefix == ret[i]->prefix) ||
4390 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4391 break;
4392 }
4393 if (i >= nbns) {
4394 if (nbns >= maxns) {
4395 maxns *= 2;
4396 ret = (xmlNsPtr *) xmlRealloc(ret,
4397 (maxns +
4398 1) *
4399 sizeof(xmlNsPtr));
4400 if (ret == NULL) {
4401 xmlGenericError(xmlGenericErrorContext,
4402 "xmlGetNsList : realloc failed!\n");
4403 return (NULL);
4404 }
4405 }
4406 ret[nbns++] = cur;
4407 ret[nbns] = NULL;
4408 }
Owen Taylor3473f882001-02-23 17:55:21 +00004409
Daniel Veillard77044732001-06-29 21:31:07 +00004410 cur = cur->next;
4411 }
4412 }
4413 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004414 }
Daniel Veillard77044732001-06-29 21:31:07 +00004415 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004416}
4417
4418/**
4419 * xmlSearchNs:
4420 * @doc: the document
4421 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004422 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004423 *
4424 * Search a Ns registered under a given name space for a document.
4425 * recurse on the parents until it finds the defined namespace
4426 * or return NULL otherwise.
4427 * @nameSpace can be NULL, this is a search for the default namespace.
4428 * We don't allow to cross entities boundaries. If you don't declare
4429 * the namespace within those you will be in troubles !!! A warning
4430 * is generated to cover this case.
4431 *
4432 * Returns the namespace pointer or NULL.
4433 */
4434xmlNsPtr
4435xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4436 xmlNsPtr cur;
4437
4438 if (node == NULL) return(NULL);
4439 if ((nameSpace != NULL) &&
4440 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00004441 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4442 /*
4443 * The XML-1.0 namespace is normally held on the root
4444 * element. In this case exceptionally create it on the
4445 * node element.
4446 */
4447 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4448 if (cur == NULL) {
4449 xmlGenericError(xmlGenericErrorContext,
4450 "xmlSearchNs : malloc failed\n");
4451 return(NULL);
4452 }
4453 memset(cur, 0, sizeof(xmlNs));
4454 cur->type = XML_LOCAL_NAMESPACE;
4455 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4456 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4457 cur->next = node->nsDef;
4458 node->nsDef = cur;
4459 return(cur);
4460 }
Owen Taylor3473f882001-02-23 17:55:21 +00004461 if (doc->oldNs == NULL) {
4462 /*
4463 * Allocate a new Namespace and fill the fields.
4464 */
4465 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4466 if (doc->oldNs == NULL) {
4467 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004468 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004469 return(NULL);
4470 }
4471 memset(doc->oldNs, 0, sizeof(xmlNs));
4472 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4473
4474 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4475 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4476 }
4477 return(doc->oldNs);
4478 }
4479 while (node != NULL) {
4480 if ((node->type == XML_ENTITY_REF_NODE) ||
4481 (node->type == XML_ENTITY_NODE) ||
4482 (node->type == XML_ENTITY_DECL))
4483 return(NULL);
4484 if (node->type == XML_ELEMENT_NODE) {
4485 cur = node->nsDef;
4486 while (cur != NULL) {
4487 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4488 (cur->href != NULL))
4489 return(cur);
4490 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4491 (cur->href != NULL) &&
4492 (xmlStrEqual(cur->prefix, nameSpace)))
4493 return(cur);
4494 cur = cur->next;
4495 }
4496 }
4497 node = node->parent;
4498 }
4499 return(NULL);
4500}
4501
4502/**
4503 * xmlSearchNsByHref:
4504 * @doc: the document
4505 * @node: the current node
4506 * @href: the namespace value
4507 *
4508 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4509 * the defined namespace or return NULL otherwise.
4510 * Returns the namespace pointer or NULL.
4511 */
4512xmlNsPtr
4513xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4514 xmlNsPtr cur;
4515 xmlNodePtr orig = node;
4516
4517 if ((node == NULL) || (href == NULL)) return(NULL);
4518 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004519 /*
4520 * Only the document can hold the XML spec namespace.
4521 */
Daniel Veillardc1a0da32002-08-14 08:32:18 +00004522 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4523 /*
4524 * The XML-1.0 namespace is normally held on the root
4525 * element. In this case exceptionally create it on the
4526 * node element.
4527 */
4528 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4529 if (cur == NULL) {
4530 xmlGenericError(xmlGenericErrorContext,
4531 "xmlSearchNs : malloc failed\n");
4532 return(NULL);
4533 }
4534 memset(cur, 0, sizeof(xmlNs));
4535 cur->type = XML_LOCAL_NAMESPACE;
4536 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4537 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4538 cur->next = node->nsDef;
4539 node->nsDef = cur;
4540 return(cur);
4541 }
Owen Taylor3473f882001-02-23 17:55:21 +00004542 if (doc->oldNs == NULL) {
4543 /*
4544 * Allocate a new Namespace and fill the fields.
4545 */
4546 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4547 if (doc->oldNs == NULL) {
4548 xmlGenericError(xmlGenericErrorContext,
4549 "xmlSearchNsByHref : malloc failed\n");
4550 return(NULL);
4551 }
4552 memset(doc->oldNs, 0, sizeof(xmlNs));
4553 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4554
4555 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4556 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4557 }
4558 return(doc->oldNs);
4559 }
4560 while (node != NULL) {
4561 cur = node->nsDef;
4562 while (cur != NULL) {
4563 if ((cur->href != NULL) && (href != NULL) &&
4564 (xmlStrEqual(cur->href, href))) {
4565 /*
4566 * Check that the prefix is not shadowed between orig and node
4567 */
4568 xmlNodePtr check = orig;
4569 xmlNsPtr tst;
4570
4571 while (check != node) {
4572 tst = check->nsDef;
4573 while (tst != NULL) {
4574 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4575 goto shadowed;
4576 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4577 (xmlStrEqual(tst->prefix, cur->prefix)))
4578 goto shadowed;
4579 tst = tst->next;
4580 }
4581 check = check->parent;
4582 }
4583 return(cur);
4584 }
4585shadowed:
4586 cur = cur->next;
4587 }
4588 node = node->parent;
4589 }
4590 return(NULL);
4591}
4592
4593/**
4594 * xmlNewReconciliedNs
4595 * @doc: the document
4596 * @tree: a node expected to hold the new namespace
4597 * @ns: the original namespace
4598 *
4599 * This function tries to locate a namespace definition in a tree
4600 * ancestors, or create a new namespace definition node similar to
4601 * @ns trying to reuse the same prefix. However if the given prefix is
4602 * null (default namespace) or reused within the subtree defined by
4603 * @tree or on one of its ancestors then a new prefix is generated.
4604 * Returns the (new) namespace definition or NULL in case of error
4605 */
4606xmlNsPtr
4607xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4608 xmlNsPtr def;
4609 xmlChar prefix[50];
4610 int counter = 1;
4611
4612 if (tree == NULL) {
4613#ifdef DEBUG_TREE
4614 xmlGenericError(xmlGenericErrorContext,
4615 "xmlNewReconciliedNs : tree == NULL\n");
4616#endif
4617 return(NULL);
4618 }
4619 if (ns == NULL) {
4620#ifdef DEBUG_TREE
4621 xmlGenericError(xmlGenericErrorContext,
4622 "xmlNewReconciliedNs : ns == NULL\n");
4623#endif
4624 return(NULL);
4625 }
4626 /*
4627 * Search an existing namespace definition inherited.
4628 */
4629 def = xmlSearchNsByHref(doc, tree, ns->href);
4630 if (def != NULL)
4631 return(def);
4632
4633 /*
4634 * Find a close prefix which is not already in use.
4635 * Let's strip namespace prefixes longer than 20 chars !
4636 */
Daniel Veillardf742d342002-03-07 00:05:35 +00004637 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004638 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00004639 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004640 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00004641
Owen Taylor3473f882001-02-23 17:55:21 +00004642 def = xmlSearchNs(doc, tree, prefix);
4643 while (def != NULL) {
4644 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00004645 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004646 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00004647 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004648 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00004649 def = xmlSearchNs(doc, tree, prefix);
4650 }
4651
4652 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004653 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004654 */
4655 def = xmlNewNs(tree, ns->href, prefix);
4656 return(def);
4657}
4658
4659/**
4660 * xmlReconciliateNs
4661 * @doc: the document
4662 * @tree: a node defining the subtree to reconciliate
4663 *
4664 * This function checks that all the namespaces declared within the given
4665 * tree are properly declared. This is needed for example after Copy or Cut
4666 * and then paste operations. The subtree may still hold pointers to
4667 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004668 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004669 * the new environment. If not possible the new namespaces are redeclared
4670 * on @tree at the top of the given subtree.
4671 * Returns the number of namespace declarations created or -1 in case of error.
4672 */
4673int
4674xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4675 xmlNsPtr *oldNs = NULL;
4676 xmlNsPtr *newNs = NULL;
4677 int sizeCache = 0;
4678 int nbCache = 0;
4679
4680 xmlNsPtr n;
4681 xmlNodePtr node = tree;
4682 xmlAttrPtr attr;
4683 int ret = 0, i;
4684
4685 while (node != NULL) {
4686 /*
4687 * Reconciliate the node namespace
4688 */
4689 if (node->ns != NULL) {
4690 /*
4691 * initialize the cache if needed
4692 */
4693 if (sizeCache == 0) {
4694 sizeCache = 10;
4695 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4696 sizeof(xmlNsPtr));
4697 if (oldNs == NULL) {
4698 xmlGenericError(xmlGenericErrorContext,
4699 "xmlReconciliateNs : memory pbm\n");
4700 return(-1);
4701 }
4702 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4703 sizeof(xmlNsPtr));
4704 if (newNs == NULL) {
4705 xmlGenericError(xmlGenericErrorContext,
4706 "xmlReconciliateNs : memory pbm\n");
4707 xmlFree(oldNs);
4708 return(-1);
4709 }
4710 }
4711 for (i = 0;i < nbCache;i++) {
4712 if (oldNs[i] == node->ns) {
4713 node->ns = newNs[i];
4714 break;
4715 }
4716 }
4717 if (i == nbCache) {
4718 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004719 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004720 */
4721 n = xmlNewReconciliedNs(doc, tree, node->ns);
4722 if (n != NULL) { /* :-( what if else ??? */
4723 /*
4724 * check if we need to grow the cache buffers.
4725 */
4726 if (sizeCache <= nbCache) {
4727 sizeCache *= 2;
4728 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4729 sizeof(xmlNsPtr));
4730 if (oldNs == NULL) {
4731 xmlGenericError(xmlGenericErrorContext,
4732 "xmlReconciliateNs : memory pbm\n");
4733 xmlFree(newNs);
4734 return(-1);
4735 }
4736 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4737 sizeof(xmlNsPtr));
4738 if (newNs == NULL) {
4739 xmlGenericError(xmlGenericErrorContext,
4740 "xmlReconciliateNs : memory pbm\n");
4741 xmlFree(oldNs);
4742 return(-1);
4743 }
4744 }
4745 newNs[nbCache] = n;
4746 oldNs[nbCache++] = node->ns;
4747 node->ns = n;
4748 }
4749 }
4750 }
4751 /*
4752 * now check for namespace hold by attributes on the node.
4753 */
4754 attr = node->properties;
4755 while (attr != NULL) {
4756 if (attr->ns != NULL) {
4757 /*
4758 * initialize the cache if needed
4759 */
4760 if (sizeCache == 0) {
4761 sizeCache = 10;
4762 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4763 sizeof(xmlNsPtr));
4764 if (oldNs == NULL) {
4765 xmlGenericError(xmlGenericErrorContext,
4766 "xmlReconciliateNs : memory pbm\n");
4767 return(-1);
4768 }
4769 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4770 sizeof(xmlNsPtr));
4771 if (newNs == NULL) {
4772 xmlGenericError(xmlGenericErrorContext,
4773 "xmlReconciliateNs : memory pbm\n");
4774 xmlFree(oldNs);
4775 return(-1);
4776 }
4777 }
4778 for (i = 0;i < nbCache;i++) {
4779 if (oldNs[i] == attr->ns) {
4780 node->ns = newNs[i];
4781 break;
4782 }
4783 }
4784 if (i == nbCache) {
4785 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004786 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004787 */
4788 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4789 if (n != NULL) { /* :-( what if else ??? */
4790 /*
4791 * check if we need to grow the cache buffers.
4792 */
4793 if (sizeCache <= nbCache) {
4794 sizeCache *= 2;
4795 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4796 sizeof(xmlNsPtr));
4797 if (oldNs == NULL) {
4798 xmlGenericError(xmlGenericErrorContext,
4799 "xmlReconciliateNs : memory pbm\n");
4800 xmlFree(newNs);
4801 return(-1);
4802 }
4803 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4804 sizeof(xmlNsPtr));
4805 if (newNs == NULL) {
4806 xmlGenericError(xmlGenericErrorContext,
4807 "xmlReconciliateNs : memory pbm\n");
4808 xmlFree(oldNs);
4809 return(-1);
4810 }
4811 }
4812 newNs[nbCache] = n;
4813 oldNs[nbCache++] = attr->ns;
4814 attr->ns = n;
4815 }
4816 }
4817 }
4818 attr = attr->next;
4819 }
4820
4821 /*
4822 * Browse the full subtree, deep first
4823 */
4824 if (node->children != NULL) {
4825 /* deep first */
4826 node = node->children;
4827 } else if ((node != tree) && (node->next != NULL)) {
4828 /* then siblings */
4829 node = node->next;
4830 } else if (node != tree) {
4831 /* go up to parents->next if needed */
4832 while (node != tree) {
4833 if (node->parent != NULL)
4834 node = node->parent;
4835 if ((node != tree) && (node->next != NULL)) {
4836 node = node->next;
4837 break;
4838 }
4839 if (node->parent == NULL) {
4840 node = NULL;
4841 break;
4842 }
4843 }
4844 /* exit condition */
4845 if (node == tree)
4846 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00004847 } else
4848 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004849 }
Daniel Veillardf742d342002-03-07 00:05:35 +00004850 if (oldNs != NULL)
4851 xmlFree(oldNs);
4852 if (newNs != NULL)
4853 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00004854 return(ret);
4855}
4856
4857/**
4858 * xmlHasProp:
4859 * @node: the node
4860 * @name: the attribute name
4861 *
4862 * Search an attribute associated to a node
4863 * This function also looks in DTD attribute declaration for #FIXED or
4864 * default declaration values unless DTD use has been turned off.
4865 *
4866 * Returns the attribute or the attribute declaration or NULL if
4867 * neither was found.
4868 */
4869xmlAttrPtr
4870xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4871 xmlAttrPtr prop;
4872 xmlDocPtr doc;
4873
4874 if ((node == NULL) || (name == NULL)) return(NULL);
4875 /*
4876 * Check on the properties attached to the node
4877 */
4878 prop = node->properties;
4879 while (prop != NULL) {
4880 if (xmlStrEqual(prop->name, name)) {
4881 return(prop);
4882 }
4883 prop = prop->next;
4884 }
4885 if (!xmlCheckDTD) return(NULL);
4886
4887 /*
4888 * Check if there is a default declaration in the internal
4889 * or external subsets
4890 */
4891 doc = node->doc;
4892 if (doc != NULL) {
4893 xmlAttributePtr attrDecl;
4894 if (doc->intSubset != NULL) {
4895 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4896 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4897 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4898 if (attrDecl != NULL)
4899 return((xmlAttrPtr) attrDecl);
4900 }
4901 }
4902 return(NULL);
4903}
4904
4905/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004906 * xmlHasNsProp:
4907 * @node: the node
4908 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004909 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004910 *
4911 * Search for an attribute associated to a node
4912 * This attribute has to be anchored in the namespace specified.
4913 * This does the entity substitution.
4914 * This function looks in DTD attribute declaration for #FIXED or
4915 * default declaration values unless DTD use has been turned off.
4916 *
4917 * Returns the attribute or the attribute declaration or NULL
4918 * if neither was found.
4919 */
4920xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004921xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004922 xmlAttrPtr prop;
4923 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004924
4925 if (node == NULL)
4926 return(NULL);
4927
4928 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004929 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004930 return(xmlHasProp(node, name));
4931 while (prop != NULL) {
4932 /*
4933 * One need to have
4934 * - same attribute names
4935 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004936 */
4937 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004938 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4939 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004940 }
4941 prop = prop->next;
4942 }
4943 if (!xmlCheckDTD) return(NULL);
4944
4945 /*
4946 * Check if there is a default declaration in the internal
4947 * or external subsets
4948 */
4949 doc = node->doc;
4950 if (doc != NULL) {
4951 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004952 xmlAttributePtr attrDecl = NULL;
4953 xmlNsPtr *nsList, *cur;
4954 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004955
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004956 nsList = xmlGetNsList(node->doc, node);
4957 if (nsList == NULL)
4958 return(NULL);
4959 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
4960 ename = xmlStrdup(node->ns->prefix);
4961 ename = xmlStrcat(ename, BAD_CAST ":");
4962 ename = xmlStrcat(ename, node->name);
4963 } else {
4964 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004965 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004966 if (ename == NULL) {
4967 xmlFree(nsList);
4968 return(NULL);
4969 }
4970
4971 cur = nsList;
4972 while (*cur != NULL) {
4973 if (xmlStrEqual((*cur)->href, nameSpace)) {
4974 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
4975 name, (*cur)->prefix);
4976 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4977 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
4978 name, (*cur)->prefix);
4979 }
4980 cur++;
4981 }
4982 xmlFree(nsList);
4983 xmlFree(ename);
4984 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004985 }
4986 }
4987 return(NULL);
4988}
4989
4990/**
Owen Taylor3473f882001-02-23 17:55:21 +00004991 * xmlGetProp:
4992 * @node: the node
4993 * @name: the attribute name
4994 *
4995 * Search and get the value of an attribute associated to a node
4996 * This does the entity substitution.
4997 * This function looks in DTD attribute declaration for #FIXED or
4998 * default declaration values unless DTD use has been turned off.
4999 *
5000 * Returns the attribute value or NULL if not found.
5001 * It's up to the caller to free the memory.
5002 */
5003xmlChar *
5004xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5005 xmlAttrPtr prop;
5006 xmlDocPtr doc;
5007
5008 if ((node == NULL) || (name == NULL)) return(NULL);
5009 /*
5010 * Check on the properties attached to the node
5011 */
5012 prop = node->properties;
5013 while (prop != NULL) {
5014 if (xmlStrEqual(prop->name, name)) {
5015 xmlChar *ret;
5016
5017 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5018 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5019 return(ret);
5020 }
5021 prop = prop->next;
5022 }
5023 if (!xmlCheckDTD) return(NULL);
5024
5025 /*
5026 * Check if there is a default declaration in the internal
5027 * or external subsets
5028 */
5029 doc = node->doc;
5030 if (doc != NULL) {
5031 xmlAttributePtr attrDecl;
5032 if (doc->intSubset != NULL) {
5033 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5034 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5035 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5036 if (attrDecl != NULL)
5037 return(xmlStrdup(attrDecl->defaultValue));
5038 }
5039 }
5040 return(NULL);
5041}
5042
5043/**
5044 * xmlGetNsProp:
5045 * @node: the node
5046 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005047 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005048 *
5049 * Search and get the value of an attribute associated to a node
5050 * This attribute has to be anchored in the namespace specified.
5051 * This does the entity substitution.
5052 * This function looks in DTD attribute declaration for #FIXED or
5053 * default declaration values unless DTD use has been turned off.
5054 *
5055 * Returns the attribute value or NULL if not found.
5056 * It's up to the caller to free the memory.
5057 */
5058xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005059xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005060 xmlAttrPtr prop;
5061 xmlDocPtr doc;
5062 xmlNsPtr ns;
5063
5064 if (node == NULL)
5065 return(NULL);
5066
5067 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005068 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005069 return(xmlGetProp(node, name));
5070 while (prop != NULL) {
5071 /*
5072 * One need to have
5073 * - same attribute names
5074 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005075 */
5076 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005077 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005078 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005079 xmlChar *ret;
5080
5081 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5082 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5083 return(ret);
5084 }
5085 prop = prop->next;
5086 }
5087 if (!xmlCheckDTD) return(NULL);
5088
5089 /*
5090 * Check if there is a default declaration in the internal
5091 * or external subsets
5092 */
5093 doc = node->doc;
5094 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005095 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005096 xmlAttributePtr attrDecl;
5097
Owen Taylor3473f882001-02-23 17:55:21 +00005098 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5099 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5100 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5101
5102 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5103 /*
5104 * The DTD declaration only allows a prefix search
5105 */
5106 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005107 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005108 return(xmlStrdup(attrDecl->defaultValue));
5109 }
5110 }
5111 }
5112 return(NULL);
5113}
5114
5115/**
5116 * xmlSetProp:
5117 * @node: the node
5118 * @name: the attribute name
5119 * @value: the attribute value
5120 *
5121 * Set (or reset) an attribute carried by a node.
5122 * Returns the attribute pointer.
5123 */
5124xmlAttrPtr
5125xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005126 xmlAttrPtr prop;
5127 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005128
5129 if ((node == NULL) || (name == NULL))
5130 return(NULL);
5131 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005132 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005133 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005134 if ((xmlStrEqual(prop->name, name)) &&
5135 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005136 xmlNodePtr oldprop = prop->children;
5137
Owen Taylor3473f882001-02-23 17:55:21 +00005138 prop->children = NULL;
5139 prop->last = NULL;
5140 if (value != NULL) {
5141 xmlChar *buffer;
5142 xmlNodePtr tmp;
5143
5144 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5145 prop->children = xmlStringGetNodeList(node->doc, buffer);
5146 prop->last = NULL;
5147 prop->doc = doc;
5148 tmp = prop->children;
5149 while (tmp != NULL) {
5150 tmp->parent = (xmlNodePtr) prop;
5151 tmp->doc = doc;
5152 if (tmp->next == NULL)
5153 prop->last = tmp;
5154 tmp = tmp->next;
5155 }
5156 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005157 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005158 if (oldprop != NULL)
5159 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005160 return(prop);
5161 }
5162 prop = prop->next;
5163 }
5164 prop = xmlNewProp(node, name, value);
5165 return(prop);
5166}
5167
5168/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005169 * xmlUnsetProp:
5170 * @node: the node
5171 * @name: the attribute name
5172 *
5173 * Remove an attribute carried by a node.
5174 * Returns 0 if successful, -1 if not found
5175 */
5176int
5177xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
5178 xmlAttrPtr prop = node->properties, prev = NULL;;
5179
5180 if ((node == NULL) || (name == NULL))
5181 return(-1);
5182 while (prop != NULL) {
5183 if ((xmlStrEqual(prop->name, name)) &&
5184 (prop->ns == NULL)) {
5185 if (prev == NULL)
5186 node->properties = prop->next;
5187 else
5188 prev->next = prop->next;
5189 xmlFreeProp(prop);
5190 return(0);
5191 }
5192 prev = prop;
5193 prop = prop->next;
5194 }
5195 return(-1);
5196}
5197
5198/**
Owen Taylor3473f882001-02-23 17:55:21 +00005199 * xmlSetNsProp:
5200 * @node: the node
5201 * @ns: the namespace definition
5202 * @name: the attribute name
5203 * @value: the attribute value
5204 *
5205 * Set (or reset) an attribute carried by a node.
5206 * The ns structure must be in scope, this is not checked.
5207 *
5208 * Returns the attribute pointer.
5209 */
5210xmlAttrPtr
5211xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5212 const xmlChar *value) {
5213 xmlAttrPtr prop;
5214
5215 if ((node == NULL) || (name == NULL))
5216 return(NULL);
5217
5218 if (ns == NULL)
5219 return(xmlSetProp(node, name, value));
5220 if (ns->href == NULL)
5221 return(NULL);
5222 prop = node->properties;
5223
5224 while (prop != NULL) {
5225 /*
5226 * One need to have
5227 * - same attribute names
5228 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005229 */
5230 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00005231 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005232 if (prop->children != NULL)
5233 xmlFreeNodeList(prop->children);
5234 prop->children = NULL;
5235 prop->last = NULL;
5236 prop->ns = ns;
5237 if (value != NULL) {
5238 xmlChar *buffer;
5239 xmlNodePtr tmp;
5240
5241 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5242 prop->children = xmlStringGetNodeList(node->doc, buffer);
5243 prop->last = NULL;
5244 tmp = prop->children;
5245 while (tmp != NULL) {
5246 tmp->parent = (xmlNodePtr) prop;
5247 if (tmp->next == NULL)
5248 prop->last = tmp;
5249 tmp = tmp->next;
5250 }
5251 xmlFree(buffer);
5252 }
5253 return(prop);
5254 }
5255 prop = prop->next;
5256 }
5257 prop = xmlNewNsProp(node, ns, name, value);
5258 return(prop);
5259}
5260
5261/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005262 * xmlUnsetNsProp:
5263 * @node: the node
5264 * @ns: the namespace definition
5265 * @name: the attribute name
5266 *
5267 * Remove an attribute carried by a node.
5268 * Returns 0 if successful, -1 if not found
5269 */
5270int
5271xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5272 xmlAttrPtr prop = node->properties, prev = NULL;;
5273
5274 if ((node == NULL) || (name == NULL))
5275 return(-1);
5276 if (ns == NULL)
5277 return(xmlUnsetProp(node, name));
5278 if (ns->href == NULL)
5279 return(-1);
5280 while (prop != NULL) {
5281 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00005282 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005283 if (prev == NULL)
5284 node->properties = prop->next;
5285 else
5286 prev->next = prop->next;
5287 xmlFreeProp(prop);
5288 return(0);
5289 }
5290 prev = prop;
5291 prop = prop->next;
5292 }
5293 return(-1);
5294}
5295
5296/**
Owen Taylor3473f882001-02-23 17:55:21 +00005297 * xmlNodeIsText:
5298 * @node: the node
5299 *
5300 * Is this node a Text node ?
5301 * Returns 1 yes, 0 no
5302 */
5303int
5304xmlNodeIsText(xmlNodePtr node) {
5305 if (node == NULL) return(0);
5306
5307 if (node->type == XML_TEXT_NODE) return(1);
5308 return(0);
5309}
5310
5311/**
5312 * xmlIsBlankNode:
5313 * @node: the node
5314 *
5315 * Checks whether this node is an empty or whitespace only
5316 * (and possibly ignorable) text-node.
5317 *
5318 * Returns 1 yes, 0 no
5319 */
5320int
5321xmlIsBlankNode(xmlNodePtr node) {
5322 const xmlChar *cur;
5323 if (node == NULL) return(0);
5324
Daniel Veillard7db37732001-07-12 01:20:08 +00005325 if ((node->type != XML_TEXT_NODE) &&
5326 (node->type != XML_CDATA_SECTION_NODE))
5327 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005328 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005329 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005330 while (*cur != 0) {
5331 if (!IS_BLANK(*cur)) return(0);
5332 cur++;
5333 }
5334
5335 return(1);
5336}
5337
5338/**
5339 * xmlTextConcat:
5340 * @node: the node
5341 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005342 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005343 *
5344 * Concat the given string at the end of the existing node content
5345 */
5346
5347void
5348xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5349 if (node == NULL) return;
5350
5351 if ((node->type != XML_TEXT_NODE) &&
5352 (node->type != XML_CDATA_SECTION_NODE)) {
5353#ifdef DEBUG_TREE
5354 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005355 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005356#endif
5357 return;
5358 }
Owen Taylor3473f882001-02-23 17:55:21 +00005359 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005360}
5361
5362/************************************************************************
5363 * *
5364 * Output : to a FILE or in memory *
5365 * *
5366 ************************************************************************/
5367
Owen Taylor3473f882001-02-23 17:55:21 +00005368/**
5369 * xmlBufferCreate:
5370 *
5371 * routine to create an XML buffer.
5372 * returns the new structure.
5373 */
5374xmlBufferPtr
5375xmlBufferCreate(void) {
5376 xmlBufferPtr ret;
5377
5378 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5379 if (ret == NULL) {
5380 xmlGenericError(xmlGenericErrorContext,
5381 "xmlBufferCreate : out of memory!\n");
5382 return(NULL);
5383 }
5384 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005385 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005386 ret->alloc = xmlBufferAllocScheme;
5387 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5388 if (ret->content == NULL) {
5389 xmlGenericError(xmlGenericErrorContext,
5390 "xmlBufferCreate : out of memory!\n");
5391 xmlFree(ret);
5392 return(NULL);
5393 }
5394 ret->content[0] = 0;
5395 return(ret);
5396}
5397
5398/**
5399 * xmlBufferCreateSize:
5400 * @size: initial size of buffer
5401 *
5402 * routine to create an XML buffer.
5403 * returns the new structure.
5404 */
5405xmlBufferPtr
5406xmlBufferCreateSize(size_t size) {
5407 xmlBufferPtr ret;
5408
5409 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5410 if (ret == NULL) {
5411 xmlGenericError(xmlGenericErrorContext,
5412 "xmlBufferCreate : out of memory!\n");
5413 return(NULL);
5414 }
5415 ret->use = 0;
5416 ret->alloc = xmlBufferAllocScheme;
5417 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5418 if (ret->size){
5419 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5420 if (ret->content == NULL) {
5421 xmlGenericError(xmlGenericErrorContext,
5422 "xmlBufferCreate : out of memory!\n");
5423 xmlFree(ret);
5424 return(NULL);
5425 }
5426 ret->content[0] = 0;
5427 } else
5428 ret->content = NULL;
5429 return(ret);
5430}
5431
5432/**
5433 * xmlBufferSetAllocationScheme:
5434 * @buf: the buffer to free
5435 * @scheme: allocation scheme to use
5436 *
5437 * Sets the allocation scheme for this buffer
5438 */
5439void
5440xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5441 xmlBufferAllocationScheme scheme) {
5442 if (buf == NULL) {
5443#ifdef DEBUG_BUFFER
5444 xmlGenericError(xmlGenericErrorContext,
5445 "xmlBufferSetAllocationScheme: buf == NULL\n");
5446#endif
5447 return;
5448 }
5449
5450 buf->alloc = scheme;
5451}
5452
5453/**
5454 * xmlBufferFree:
5455 * @buf: the buffer to free
5456 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005457 * Frees an XML buffer. It frees both the content and the structure which
5458 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005459 */
5460void
5461xmlBufferFree(xmlBufferPtr buf) {
5462 if (buf == NULL) {
5463#ifdef DEBUG_BUFFER
5464 xmlGenericError(xmlGenericErrorContext,
5465 "xmlBufferFree: buf == NULL\n");
5466#endif
5467 return;
5468 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00005469 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005470 xmlFree(buf->content);
5471 }
Owen Taylor3473f882001-02-23 17:55:21 +00005472 xmlFree(buf);
5473}
5474
5475/**
5476 * xmlBufferEmpty:
5477 * @buf: the buffer
5478 *
5479 * empty a buffer.
5480 */
5481void
5482xmlBufferEmpty(xmlBufferPtr buf) {
5483 if (buf->content == NULL) return;
5484 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005485 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005486}
5487
5488/**
5489 * xmlBufferShrink:
5490 * @buf: the buffer to dump
5491 * @len: the number of xmlChar to remove
5492 *
5493 * Remove the beginning of an XML buffer.
5494 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005495 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005496 */
5497int
5498xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5499 if (len == 0) return(0);
5500 if (len > buf->use) return(-1);
5501
5502 buf->use -= len;
5503 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5504
5505 buf->content[buf->use] = 0;
5506 return(len);
5507}
5508
5509/**
5510 * xmlBufferGrow:
5511 * @buf: the buffer
5512 * @len: the minimum free size to allocate
5513 *
5514 * Grow the available space of an XML buffer.
5515 *
5516 * Returns the new available space or -1 in case of error
5517 */
5518int
5519xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5520 int size;
5521 xmlChar *newbuf;
5522
5523 if (len + buf->use < buf->size) return(0);
5524
5525 size = buf->use + len + 100;
5526
5527 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5528 if (newbuf == NULL) return(-1);
5529 buf->content = newbuf;
5530 buf->size = size;
5531 return(buf->size - buf->use);
5532}
5533
5534/**
5535 * xmlBufferDump:
5536 * @file: the file output
5537 * @buf: the buffer to dump
5538 *
5539 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005540 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005541 */
5542int
5543xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5544 int ret;
5545
5546 if (buf == NULL) {
5547#ifdef DEBUG_BUFFER
5548 xmlGenericError(xmlGenericErrorContext,
5549 "xmlBufferDump: buf == NULL\n");
5550#endif
5551 return(0);
5552 }
5553 if (buf->content == NULL) {
5554#ifdef DEBUG_BUFFER
5555 xmlGenericError(xmlGenericErrorContext,
5556 "xmlBufferDump: buf->content == NULL\n");
5557#endif
5558 return(0);
5559 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005560 if (file == NULL)
5561 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005562 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5563 return(ret);
5564}
5565
5566/**
5567 * xmlBufferContent:
5568 * @buf: the buffer
5569 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005570 * Function to extract the content of a buffer
5571 *
Owen Taylor3473f882001-02-23 17:55:21 +00005572 * Returns the internal content
5573 */
5574
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005575const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005576xmlBufferContent(const xmlBufferPtr buf)
5577{
5578 if(!buf)
5579 return NULL;
5580
5581 return buf->content;
5582}
5583
5584/**
5585 * xmlBufferLength:
5586 * @buf: the buffer
5587 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005588 * Function to get the length of a buffer
5589 *
Owen Taylor3473f882001-02-23 17:55:21 +00005590 * Returns the length of data in the internal content
5591 */
5592
5593int
5594xmlBufferLength(const xmlBufferPtr buf)
5595{
5596 if(!buf)
5597 return 0;
5598
5599 return buf->use;
5600}
5601
5602/**
5603 * xmlBufferResize:
5604 * @buf: the buffer to resize
5605 * @size: the desired size
5606 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005607 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005608 *
5609 * Returns 0 in case of problems, 1 otherwise
5610 */
5611int
5612xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5613{
5614 unsigned int newSize;
5615 xmlChar* rebuf = NULL;
5616
5617 /*take care of empty case*/
5618 newSize = (buf->size ? buf->size*2 : size);
5619
5620 /* Don't resize if we don't have to */
5621 if (size < buf->size)
5622 return 1;
5623
5624 /* figure out new size */
5625 switch (buf->alloc){
5626 case XML_BUFFER_ALLOC_DOUBLEIT:
5627 while (size > newSize) newSize *= 2;
5628 break;
5629 case XML_BUFFER_ALLOC_EXACT:
5630 newSize = size+10;
5631 break;
5632 default:
5633 newSize = size+10;
5634 break;
5635 }
5636
5637 if (buf->content == NULL)
5638 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5639 else
5640 rebuf = (xmlChar *) xmlRealloc(buf->content,
5641 newSize * sizeof(xmlChar));
5642 if (rebuf == NULL) {
5643 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005644 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005645 return 0;
5646 }
5647 buf->content = rebuf;
5648 buf->size = newSize;
5649
5650 return 1;
5651}
5652
5653/**
5654 * xmlBufferAdd:
5655 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005656 * @str: the #xmlChar string
5657 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005658 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005659 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005660 * str is recomputed.
5661 */
5662void
5663xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5664 unsigned int needSize;
5665
5666 if (str == NULL) {
5667#ifdef DEBUG_BUFFER
5668 xmlGenericError(xmlGenericErrorContext,
5669 "xmlBufferAdd: str == NULL\n");
5670#endif
5671 return;
5672 }
5673 if (len < -1) {
5674#ifdef DEBUG_BUFFER
5675 xmlGenericError(xmlGenericErrorContext,
5676 "xmlBufferAdd: len < 0\n");
5677#endif
5678 return;
5679 }
5680 if (len == 0) return;
5681
5682 if (len < 0)
5683 len = xmlStrlen(str);
5684
5685 if (len <= 0) return;
5686
5687 needSize = buf->use + len + 2;
5688 if (needSize > buf->size){
5689 if (!xmlBufferResize(buf, needSize)){
5690 xmlGenericError(xmlGenericErrorContext,
5691 "xmlBufferAdd : out of memory!\n");
5692 return;
5693 }
5694 }
5695
5696 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5697 buf->use += len;
5698 buf->content[buf->use] = 0;
5699}
5700
5701/**
5702 * xmlBufferAddHead:
5703 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005704 * @str: the #xmlChar string
5705 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005706 *
5707 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005708 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005709 */
5710void
5711xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5712 unsigned int needSize;
5713
5714 if (str == NULL) {
5715#ifdef DEBUG_BUFFER
5716 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005717 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005718#endif
5719 return;
5720 }
5721 if (len < -1) {
5722#ifdef DEBUG_BUFFER
5723 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005724 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005725#endif
5726 return;
5727 }
5728 if (len == 0) return;
5729
5730 if (len < 0)
5731 len = xmlStrlen(str);
5732
5733 if (len <= 0) return;
5734
5735 needSize = buf->use + len + 2;
5736 if (needSize > buf->size){
5737 if (!xmlBufferResize(buf, needSize)){
5738 xmlGenericError(xmlGenericErrorContext,
5739 "xmlBufferAddHead : out of memory!\n");
5740 return;
5741 }
5742 }
5743
5744 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5745 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5746 buf->use += len;
5747 buf->content[buf->use] = 0;
5748}
5749
5750/**
5751 * xmlBufferCat:
5752 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005753 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005754 *
5755 * Append a zero terminated string to an XML buffer.
5756 */
5757void
5758xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5759 if (str != NULL)
5760 xmlBufferAdd(buf, str, -1);
5761}
5762
5763/**
5764 * xmlBufferCCat:
5765 * @buf: the buffer to dump
5766 * @str: the C char string
5767 *
5768 * Append a zero terminated C string to an XML buffer.
5769 */
5770void
5771xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5772 const char *cur;
5773
5774 if (str == NULL) {
5775#ifdef DEBUG_BUFFER
5776 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005777 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005778#endif
5779 return;
5780 }
5781 for (cur = str;*cur != 0;cur++) {
5782 if (buf->use + 10 >= buf->size) {
5783 if (!xmlBufferResize(buf, buf->use+10)){
5784 xmlGenericError(xmlGenericErrorContext,
5785 "xmlBufferCCat : out of memory!\n");
5786 return;
5787 }
5788 }
5789 buf->content[buf->use++] = *cur;
5790 }
5791 buf->content[buf->use] = 0;
5792}
5793
5794/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005795 * xmlBufferWriteXmlCHAR:
5796 * @buf: the XML buffer
5797 * @string: the string to add
5798 *
5799 * For VMS only.
5800 * routine which manages and grows an output buffer. This one adds
5801 * xmlChars at the end of the buffer.
5802 */
5803/**
Owen Taylor3473f882001-02-23 17:55:21 +00005804 * xmlBufferWriteCHAR:
5805 * @buf: the XML buffer
5806 * @string: the string to add
5807 *
5808 * routine which manages and grows an output buffer. This one adds
5809 * xmlChars at the end of the buffer.
5810 */
5811void
5812#ifdef VMS
5813xmlBufferWriteXmlCHAR
5814#else
5815xmlBufferWriteCHAR
5816#endif
5817(xmlBufferPtr buf, const xmlChar *string) {
5818 xmlBufferCat(buf, string);
5819}
5820
5821/**
5822 * xmlBufferWriteChar:
5823 * @buf: the XML buffer output
5824 * @string: the string to add
5825 *
5826 * routine which manage and grows an output buffer. This one add
5827 * C chars at the end of the array.
5828 */
5829void
5830xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5831 xmlBufferCCat(buf, string);
5832}
5833
5834
5835/**
5836 * xmlBufferWriteQuotedString:
5837 * @buf: the XML buffer output
5838 * @string: the string to add
5839 *
5840 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005841 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005842 * quote or double-quotes internally
5843 */
5844void
5845xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5846 if (xmlStrchr(string, '"')) {
5847 if (xmlStrchr(string, '\'')) {
5848#ifdef DEBUG_BUFFER
5849 xmlGenericError(xmlGenericErrorContext,
5850 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5851#endif
5852 }
5853 xmlBufferCCat(buf, "'");
5854 xmlBufferCat(buf, string);
5855 xmlBufferCCat(buf, "'");
5856 } else {
5857 xmlBufferCCat(buf, "\"");
5858 xmlBufferCat(buf, string);
5859 xmlBufferCCat(buf, "\"");
5860 }
5861}
5862
5863
5864/************************************************************************
5865 * *
5866 * Dumping XML tree content to a simple buffer *
5867 * *
5868 ************************************************************************/
5869
Owen Taylor3473f882001-02-23 17:55:21 +00005870static void
5871xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5872 int format);
5873void
5874htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5875
5876/**
5877 * xmlNsDump:
5878 * @buf: the XML buffer output
5879 * @cur: a namespace
5880 *
5881 * Dump a local Namespace definition.
5882 * Should be called in the context of attributes dumps.
5883 */
5884static void
5885xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5886 if (cur == NULL) {
5887#ifdef DEBUG_TREE
5888 xmlGenericError(xmlGenericErrorContext,
5889 "xmlNsDump : Ns == NULL\n");
5890#endif
5891 return;
5892 }
5893 if (cur->type == XML_LOCAL_NAMESPACE) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005894 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
5895 return;
5896
Owen Taylor3473f882001-02-23 17:55:21 +00005897 /* Within the context of an element attributes */
5898 if (cur->prefix != NULL) {
5899 xmlBufferWriteChar(buf, " xmlns:");
5900 xmlBufferWriteCHAR(buf, cur->prefix);
5901 } else
5902 xmlBufferWriteChar(buf, " xmlns");
5903 xmlBufferWriteChar(buf, "=");
5904 xmlBufferWriteQuotedString(buf, cur->href);
5905 }
5906}
5907
5908/**
5909 * xmlNsListDump:
5910 * @buf: the XML buffer output
5911 * @cur: the first namespace
5912 *
5913 * Dump a list of local Namespace definitions.
5914 * Should be called in the context of attributes dumps.
5915 */
5916static void
5917xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5918 while (cur != NULL) {
5919 xmlNsDump(buf, cur);
5920 cur = cur->next;
5921 }
5922}
5923
5924/**
5925 * xmlDtdDump:
5926 * @buf: the XML buffer output
Daniel Veillardd1640922001-12-17 15:30:10 +00005927 * @dtd: the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00005928 *
5929 * Dump the XML document DTD, if any.
5930 */
5931static void
5932xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5933 if (dtd == NULL) {
5934#ifdef DEBUG_TREE
5935 xmlGenericError(xmlGenericErrorContext,
5936 "xmlDtdDump : no internal subset\n");
5937#endif
5938 return;
5939 }
5940 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5941 xmlBufferWriteCHAR(buf, dtd->name);
5942 if (dtd->ExternalID != NULL) {
5943 xmlBufferWriteChar(buf, " PUBLIC ");
5944 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5945 xmlBufferWriteChar(buf, " ");
5946 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5947 } else if (dtd->SystemID != NULL) {
5948 xmlBufferWriteChar(buf, " SYSTEM ");
5949 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5950 }
5951 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5952 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5953 xmlBufferWriteChar(buf, ">");
5954 return;
5955 }
5956 xmlBufferWriteChar(buf, " [\n");
5957 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5958#if 0
5959 if (dtd->entities != NULL)
5960 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5961 if (dtd->notations != NULL)
5962 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5963 if (dtd->elements != NULL)
5964 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5965 if (dtd->attributes != NULL)
5966 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5967#endif
5968 xmlBufferWriteChar(buf, "]>");
5969}
5970
5971/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00005972 * xmlAttrSerializeContent:
5973 * @buf: the XML buffer output
5974 * @doc: the document
5975 * @attr: the attribute pointer
5976 *
5977 * Serialize the attribute in the buffer
5978 */
5979static void
5980xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr) {
5981 const xmlChar *cur, *base;
5982 xmlNodePtr children;
5983
5984 children = attr->children;
5985 while (children != NULL) {
5986 switch (children->type) {
5987 case XML_TEXT_NODE:
5988 base = cur = children->content;
5989 while (*cur != 0) {
5990 if (*cur == '\n') {
5991 if (base != cur)
5992 xmlBufferAdd(buf, base, cur - base);
5993 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
5994 cur++;
5995 base = cur;
5996#if 0
5997 } else if (*cur == '\'') {
5998 if (base != cur)
5999 xmlBufferAdd(buf, base, cur - base);
6000 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
6001 cur++;
6002 base = cur;
6003#endif
6004 } else if (*cur == '"') {
6005 if (base != cur)
6006 xmlBufferAdd(buf, base, cur - base);
6007 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6008 cur++;
6009 base = cur;
6010 } else if (*cur == '<') {
6011 if (base != cur)
6012 xmlBufferAdd(buf, base, cur - base);
6013 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6014 cur++;
6015 base = cur;
6016 } else if (*cur == '>') {
6017 if (base != cur)
6018 xmlBufferAdd(buf, base, cur - base);
6019 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6020 cur++;
6021 base = cur;
6022 } else if (*cur == '&') {
6023 if (base != cur)
6024 xmlBufferAdd(buf, base, cur - base);
6025 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6026 cur++;
6027 base = cur;
6028 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6029 (doc->encoding == NULL))) {
6030 /*
6031 * We assume we have UTF-8 content.
6032 */
6033 char tmp[10];
6034 int val = 0, l = 1;
6035
6036 if (base != cur)
6037 xmlBufferAdd(buf, base, cur - base);
6038 if (*cur < 0xC0) {
6039 xmlGenericError(xmlGenericErrorContext,
6040 "xmlAttrSerializeContent : input not UTF-8\n");
6041 if (doc != NULL)
6042 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
6043 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6044 tmp[sizeof(tmp) - 1] = 0;
6045 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6046 cur++;
6047 base = cur;
6048 continue;
6049 } else if (*cur < 0xE0) {
6050 val = (cur[0]) & 0x1F;
6051 val <<= 6;
6052 val |= (cur[1]) & 0x3F;
6053 l = 2;
6054 } else if (*cur < 0xF0) {
6055 val = (cur[0]) & 0x0F;
6056 val <<= 6;
6057 val |= (cur[1]) & 0x3F;
6058 val <<= 6;
6059 val |= (cur[2]) & 0x3F;
6060 l = 3;
6061 } else if (*cur < 0xF8) {
6062 val = (cur[0]) & 0x07;
6063 val <<= 6;
6064 val |= (cur[1]) & 0x3F;
6065 val <<= 6;
6066 val |= (cur[2]) & 0x3F;
6067 val <<= 6;
6068 val |= (cur[3]) & 0x3F;
6069 l = 4;
6070 }
6071 if ((l == 1) || (!IS_CHAR(val))) {
6072 xmlGenericError(xmlGenericErrorContext,
6073 "xmlAttrSerializeContent : char out of range\n");
6074 if (doc != NULL)
6075 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
6076 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6077 tmp[sizeof(tmp) - 1] = 0;
6078 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6079 cur++;
6080 base = cur;
6081 continue;
6082 }
6083 /*
6084 * We could do multiple things here. Just save
6085 * as a char ref
6086 */
6087 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6088 tmp[sizeof(tmp) - 1] = 0;
6089 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6090 cur += l;
6091 base = cur;
6092 } else {
6093 cur++;
6094 }
6095 }
6096 if (base != cur)
6097 xmlBufferAdd(buf, base, cur - base);
6098 break;
6099 case XML_ENTITY_REF_NODE:
6100 xmlBufferAdd(buf, BAD_CAST "&", 1);
6101 xmlBufferAdd(buf, children->name, xmlStrlen(children->name));
6102 xmlBufferAdd(buf, BAD_CAST ";", 1);
6103 break;
6104 default:
6105 /* should not happen unless we have a badly built tree */
6106 break;
6107 }
6108 children = children->next;
6109 }
6110}
6111
6112/**
Owen Taylor3473f882001-02-23 17:55:21 +00006113 * xmlAttrDump:
6114 * @buf: the XML buffer output
6115 * @doc: the document
6116 * @cur: the attribute pointer
6117 *
6118 * Dump an XML attribute
6119 */
6120static void
6121xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00006122 if (cur == NULL) {
6123#ifdef DEBUG_TREE
6124 xmlGenericError(xmlGenericErrorContext,
6125 "xmlAttrDump : property == NULL\n");
6126#endif
6127 return;
6128 }
6129 xmlBufferWriteChar(buf, " ");
6130 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6131 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6132 xmlBufferWriteChar(buf, ":");
6133 }
6134 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006135 xmlBufferWriteChar(buf, "=\"");
6136 xmlAttrSerializeContent(buf, doc, cur);
6137 xmlBufferWriteChar(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006138}
6139
6140/**
6141 * xmlAttrListDump:
6142 * @buf: the XML buffer output
6143 * @doc: the document
6144 * @cur: the first attribute pointer
6145 *
6146 * Dump a list of XML attributes
6147 */
6148static void
6149xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
6150 if (cur == NULL) {
6151#ifdef DEBUG_TREE
6152 xmlGenericError(xmlGenericErrorContext,
6153 "xmlAttrListDump : property == NULL\n");
6154#endif
6155 return;
6156 }
6157 while (cur != NULL) {
6158 xmlAttrDump(buf, doc, cur);
6159 cur = cur->next;
6160 }
6161}
6162
6163
6164
6165/**
6166 * xmlNodeListDump:
6167 * @buf: the XML buffer output
6168 * @doc: the document
6169 * @cur: the first node
6170 * @level: the imbrication level for indenting
6171 * @format: is formatting allowed
6172 *
6173 * Dump an XML node list, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006174 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6175 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006176 */
6177static void
6178xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
6179 int format) {
6180 int i;
6181
6182 if (cur == NULL) {
6183#ifdef DEBUG_TREE
6184 xmlGenericError(xmlGenericErrorContext,
6185 "xmlNodeListDump : node == NULL\n");
6186#endif
6187 return;
6188 }
6189 while (cur != NULL) {
6190 if ((format) && (xmlIndentTreeOutput) &&
6191 (cur->type == XML_ELEMENT_NODE))
6192 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006193 xmlBufferWriteChar(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006194 xmlNodeDump(buf, doc, cur, level, format);
6195 if (format) {
6196 xmlBufferWriteChar(buf, "\n");
6197 }
6198 cur = cur->next;
6199 }
6200}
6201
6202/**
6203 * xmlNodeDump:
6204 * @buf: the XML buffer output
6205 * @doc: the document
6206 * @cur: the current node
6207 * @level: the imbrication level for indenting
6208 * @format: is formatting allowed
6209 *
6210 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006211 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6212 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006213 */
6214void
6215xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
6216 int format) {
6217 int i;
6218 xmlNodePtr tmp;
6219
6220 if (cur == NULL) {
6221#ifdef DEBUG_TREE
6222 xmlGenericError(xmlGenericErrorContext,
6223 "xmlNodeDump : node == NULL\n");
6224#endif
6225 return;
6226 }
6227 if (cur->type == XML_XINCLUDE_START)
6228 return;
6229 if (cur->type == XML_XINCLUDE_END)
6230 return;
6231 if (cur->type == XML_DTD_NODE) {
6232 xmlDtdDump(buf, (xmlDtdPtr) cur);
6233 return;
6234 }
6235 if (cur->type == XML_ELEMENT_DECL) {
6236 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
6237 return;
6238 }
Daniel Veillard78d12092001-10-11 09:12:24 +00006239 if (cur->type == XML_ATTRIBUTE_NODE){
6240 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
6241 return;
6242 }
Owen Taylor3473f882001-02-23 17:55:21 +00006243 if (cur->type == XML_ATTRIBUTE_DECL) {
6244 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
6245 return;
6246 }
6247 if (cur->type == XML_ENTITY_DECL) {
6248 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
6249 return;
6250 }
6251 if (cur->type == XML_TEXT_NODE) {
6252 if (cur->content != NULL) {
6253 if ((cur->name == xmlStringText) ||
6254 (cur->name != xmlStringTextNoenc)) {
6255 xmlChar *buffer;
6256
Owen Taylor3473f882001-02-23 17:55:21 +00006257 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006258 if (buffer != NULL) {
6259 xmlBufferWriteCHAR(buf, buffer);
6260 xmlFree(buffer);
6261 }
6262 } else {
6263 /*
6264 * Disable escaping, needed for XSLT
6265 */
Owen Taylor3473f882001-02-23 17:55:21 +00006266 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006267 }
6268 }
6269 return;
6270 }
6271 if (cur->type == XML_PI_NODE) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00006272 xmlBufferWriteChar(buf, "<?");
6273 xmlBufferWriteCHAR(buf, cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006274 if (cur->content != NULL) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00006275 xmlBufferWriteChar(buf, " ");
Daniel Veillard2c748c62002-01-16 15:37:50 +00006276 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006277 }
Daniel Veillard2c748c62002-01-16 15:37:50 +00006278 xmlBufferWriteChar(buf, "?>");
Owen Taylor3473f882001-02-23 17:55:21 +00006279 return;
6280 }
6281 if (cur->type == XML_COMMENT_NODE) {
6282 if (cur->content != NULL) {
6283 xmlBufferWriteChar(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006284 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006285 xmlBufferWriteChar(buf, "-->");
6286 }
6287 return;
6288 }
6289 if (cur->type == XML_ENTITY_REF_NODE) {
6290 xmlBufferWriteChar(buf, "&");
6291 xmlBufferWriteCHAR(buf, cur->name);
6292 xmlBufferWriteChar(buf, ";");
6293 return;
6294 }
6295 if (cur->type == XML_CDATA_SECTION_NODE) {
6296 xmlBufferWriteChar(buf, "<![CDATA[");
6297 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006298 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006299 xmlBufferWriteChar(buf, "]]>");
6300 return;
6301 }
6302
6303 if (format == 1) {
6304 tmp = cur->children;
6305 while (tmp != NULL) {
6306 if ((tmp->type == XML_TEXT_NODE) ||
6307 (tmp->type == XML_ENTITY_REF_NODE)) {
6308 format = 0;
6309 break;
6310 }
6311 tmp = tmp->next;
6312 }
6313 }
6314 xmlBufferWriteChar(buf, "<");
6315 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6316 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6317 xmlBufferWriteChar(buf, ":");
6318 }
6319
6320 xmlBufferWriteCHAR(buf, cur->name);
6321 if (cur->nsDef)
6322 xmlNsListDump(buf, cur->nsDef);
6323 if (cur->properties != NULL)
6324 xmlAttrListDump(buf, doc, cur->properties);
6325
Daniel Veillard7db37732001-07-12 01:20:08 +00006326 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6327 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00006328 (!xmlSaveNoEmptyTags)) {
6329 xmlBufferWriteChar(buf, "/>");
6330 return;
6331 }
6332 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006333 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006334 xmlChar *buffer;
6335
Owen Taylor3473f882001-02-23 17:55:21 +00006336 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006337 if (buffer != NULL) {
6338 xmlBufferWriteCHAR(buf, buffer);
6339 xmlFree(buffer);
6340 }
6341 }
6342 if (cur->children != NULL) {
6343 if (format) xmlBufferWriteChar(buf, "\n");
6344 xmlNodeListDump(buf, doc, cur->children,
6345 (level >= 0?level+1:-1), format);
6346 if ((xmlIndentTreeOutput) && (format))
6347 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006348 xmlBufferWriteChar(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006349 }
6350 xmlBufferWriteChar(buf, "</");
6351 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6352 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6353 xmlBufferWriteChar(buf, ":");
6354 }
6355
6356 xmlBufferWriteCHAR(buf, cur->name);
6357 xmlBufferWriteChar(buf, ">");
6358}
6359
6360/**
6361 * xmlElemDump:
6362 * @f: the FILE * for the output
6363 * @doc: the document
6364 * @cur: the current node
6365 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006366 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006367 */
6368void
6369xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
6370 xmlBufferPtr buf;
6371
6372 if (cur == NULL) {
6373#ifdef DEBUG_TREE
6374 xmlGenericError(xmlGenericErrorContext,
6375 "xmlElemDump : cur == NULL\n");
6376#endif
6377 return;
6378 }
Owen Taylor3473f882001-02-23 17:55:21 +00006379#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006380 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006381 xmlGenericError(xmlGenericErrorContext,
6382 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006383 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006384#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00006385
Owen Taylor3473f882001-02-23 17:55:21 +00006386 buf = xmlBufferCreate();
6387 if (buf == NULL) return;
6388 if ((doc != NULL) &&
6389 (doc->type == XML_HTML_DOCUMENT_NODE)) {
6390#ifdef LIBXML_HTML_ENABLED
6391 htmlNodeDump(buf, doc, cur);
6392#else
6393 xmlGenericError(xmlGenericErrorContext,
6394 "HTML support not compiled in\n");
6395#endif /* LIBXML_HTML_ENABLED */
6396 } else
6397 xmlNodeDump(buf, doc, cur, 0, 1);
6398 xmlBufferDump(f, buf);
6399 xmlBufferFree(buf);
6400}
6401
6402/************************************************************************
6403 * *
6404 * Dumping XML tree content to an I/O output buffer *
6405 * *
6406 ************************************************************************/
6407
Owen Taylor3473f882001-02-23 17:55:21 +00006408static void
6409xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6410 int level, int format, const char *encoding);
6411/**
6412 * xmlNsDumpOutput:
6413 * @buf: the XML buffer output
6414 * @cur: a namespace
6415 *
6416 * Dump a local Namespace definition.
6417 * Should be called in the context of attributes dumps.
6418 */
6419static void
6420xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6421 if (cur == NULL) {
6422#ifdef DEBUG_TREE
6423 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006424 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006425#endif
6426 return;
6427 }
6428 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006429 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6430 return;
6431
Owen Taylor3473f882001-02-23 17:55:21 +00006432 /* Within the context of an element attributes */
6433 if (cur->prefix != NULL) {
6434 xmlOutputBufferWriteString(buf, " xmlns:");
6435 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6436 } else
6437 xmlOutputBufferWriteString(buf, " xmlns");
6438 xmlOutputBufferWriteString(buf, "=");
6439 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6440 }
6441}
6442
6443/**
6444 * xmlNsListDumpOutput:
6445 * @buf: the XML buffer output
6446 * @cur: the first namespace
6447 *
6448 * Dump a list of local Namespace definitions.
6449 * Should be called in the context of attributes dumps.
6450 */
6451static void
6452xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6453 while (cur != NULL) {
6454 xmlNsDumpOutput(buf, cur);
6455 cur = cur->next;
6456 }
6457}
6458
6459/**
6460 * xmlDtdDumpOutput:
6461 * @buf: the XML buffer output
6462 * @doc: the document
6463 * @encoding: an optional encoding string
6464 *
6465 * Dump the XML document DTD, if any.
6466 */
6467static void
6468xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6469 if (dtd == NULL) {
6470#ifdef DEBUG_TREE
6471 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006472 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006473#endif
6474 return;
6475 }
6476 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6477 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6478 if (dtd->ExternalID != NULL) {
6479 xmlOutputBufferWriteString(buf, " PUBLIC ");
6480 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6481 xmlOutputBufferWriteString(buf, " ");
6482 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6483 } else if (dtd->SystemID != NULL) {
6484 xmlOutputBufferWriteString(buf, " SYSTEM ");
6485 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6486 }
6487 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6488 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6489 xmlOutputBufferWriteString(buf, ">");
6490 return;
6491 }
6492 xmlOutputBufferWriteString(buf, " [\n");
6493 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6494 xmlOutputBufferWriteString(buf, "]>");
6495}
6496
6497/**
6498 * xmlAttrDumpOutput:
6499 * @buf: the XML buffer output
6500 * @doc: the document
6501 * @cur: the attribute pointer
6502 * @encoding: an optional encoding string
6503 *
6504 * Dump an XML attribute
6505 */
6506static void
6507xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006508 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006509 if (cur == NULL) {
6510#ifdef DEBUG_TREE
6511 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006512 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006513#endif
6514 return;
6515 }
6516 xmlOutputBufferWriteString(buf, " ");
6517 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6518 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6519 xmlOutputBufferWriteString(buf, ":");
6520 }
6521 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006522 xmlOutputBufferWriteString(buf, "=\"");
6523 xmlAttrSerializeContent(buf->buffer, doc, cur);
6524 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006525}
6526
6527/**
6528 * xmlAttrListDumpOutput:
6529 * @buf: the XML buffer output
6530 * @doc: the document
6531 * @cur: the first attribute pointer
6532 * @encoding: an optional encoding string
6533 *
6534 * Dump a list of XML attributes
6535 */
6536static void
6537xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6538 xmlAttrPtr cur, const char *encoding) {
6539 if (cur == NULL) {
6540#ifdef DEBUG_TREE
6541 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006542 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006543#endif
6544 return;
6545 }
6546 while (cur != NULL) {
6547 xmlAttrDumpOutput(buf, doc, cur, encoding);
6548 cur = cur->next;
6549 }
6550}
6551
6552
6553
6554/**
6555 * xmlNodeListDumpOutput:
6556 * @buf: the XML buffer output
6557 * @doc: the document
6558 * @cur: the first node
6559 * @level: the imbrication level for indenting
6560 * @format: is formatting allowed
6561 * @encoding: an optional encoding string
6562 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006563 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006564 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6565 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006566 */
6567static void
6568xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6569 xmlNodePtr cur, int level, int format, const char *encoding) {
6570 int i;
6571
6572 if (cur == NULL) {
6573#ifdef DEBUG_TREE
6574 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006575 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006576#endif
6577 return;
6578 }
6579 while (cur != NULL) {
6580 if ((format) && (xmlIndentTreeOutput) &&
6581 (cur->type == XML_ELEMENT_NODE))
6582 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006583 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006584 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6585 if (format) {
6586 xmlOutputBufferWriteString(buf, "\n");
6587 }
6588 cur = cur->next;
6589 }
6590}
6591
6592/**
6593 * xmlNodeDumpOutput:
6594 * @buf: the XML buffer output
6595 * @doc: the document
6596 * @cur: the current node
6597 * @level: the imbrication level for indenting
6598 * @format: is formatting allowed
6599 * @encoding: an optional encoding string
6600 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006601 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006602 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6603 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006604 */
6605void
6606xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6607 int level, int format, const char *encoding) {
6608 int i;
6609 xmlNodePtr tmp;
6610
6611 if (cur == NULL) {
6612#ifdef DEBUG_TREE
6613 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006614 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006615#endif
6616 return;
6617 }
6618 if (cur->type == XML_XINCLUDE_START)
6619 return;
6620 if (cur->type == XML_XINCLUDE_END)
6621 return;
6622 if (cur->type == XML_DTD_NODE) {
6623 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6624 return;
6625 }
6626 if (cur->type == XML_ELEMENT_DECL) {
6627 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6628 return;
6629 }
6630 if (cur->type == XML_ATTRIBUTE_DECL) {
6631 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6632 return;
6633 }
6634 if (cur->type == XML_ENTITY_DECL) {
6635 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6636 return;
6637 }
6638 if (cur->type == XML_TEXT_NODE) {
6639 if (cur->content != NULL) {
6640 if ((cur->name == xmlStringText) ||
6641 (cur->name != xmlStringTextNoenc)) {
6642 xmlChar *buffer;
6643
Owen Taylor3473f882001-02-23 17:55:21 +00006644 if (encoding == NULL)
6645 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6646 else
6647 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006648 if (buffer != NULL) {
6649 xmlOutputBufferWriteString(buf, (const char *)buffer);
6650 xmlFree(buffer);
6651 }
6652 } else {
6653 /*
6654 * Disable escaping, needed for XSLT
6655 */
Owen Taylor3473f882001-02-23 17:55:21 +00006656 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006657 }
6658 }
6659
6660 return;
6661 }
6662 if (cur->type == XML_PI_NODE) {
6663 if (cur->content != NULL) {
6664 xmlOutputBufferWriteString(buf, "<?");
6665 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6666 if (cur->content != NULL) {
6667 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006668 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006669 }
6670 xmlOutputBufferWriteString(buf, "?>");
6671 } else {
6672 xmlOutputBufferWriteString(buf, "<?");
6673 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6674 xmlOutputBufferWriteString(buf, "?>");
6675 }
6676 return;
6677 }
6678 if (cur->type == XML_COMMENT_NODE) {
6679 if (cur->content != NULL) {
6680 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006681 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006682 xmlOutputBufferWriteString(buf, "-->");
6683 }
6684 return;
6685 }
6686 if (cur->type == XML_ENTITY_REF_NODE) {
6687 xmlOutputBufferWriteString(buf, "&");
6688 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6689 xmlOutputBufferWriteString(buf, ";");
6690 return;
6691 }
6692 if (cur->type == XML_CDATA_SECTION_NODE) {
6693 xmlOutputBufferWriteString(buf, "<![CDATA[");
6694 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006695 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006696 xmlOutputBufferWriteString(buf, "]]>");
6697 return;
6698 }
6699
6700 if (format == 1) {
6701 tmp = cur->children;
6702 while (tmp != NULL) {
6703 if ((tmp->type == XML_TEXT_NODE) ||
6704 (tmp->type == XML_ENTITY_REF_NODE)) {
6705 format = 0;
6706 break;
6707 }
6708 tmp = tmp->next;
6709 }
6710 }
6711 xmlOutputBufferWriteString(buf, "<");
6712 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6713 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6714 xmlOutputBufferWriteString(buf, ":");
6715 }
6716
6717 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6718 if (cur->nsDef)
6719 xmlNsListDumpOutput(buf, cur->nsDef);
6720 if (cur->properties != NULL)
6721 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6722
Daniel Veillard7db37732001-07-12 01:20:08 +00006723 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6724 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006725 xmlOutputBufferWriteString(buf, "/>");
6726 return;
6727 }
6728 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006729 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006730 xmlChar *buffer;
6731
Owen Taylor3473f882001-02-23 17:55:21 +00006732 if (encoding == NULL)
6733 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6734 else
6735 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006736 if (buffer != NULL) {
6737 xmlOutputBufferWriteString(buf, (const char *)buffer);
6738 xmlFree(buffer);
6739 }
6740 }
6741 if (cur->children != NULL) {
6742 if (format) xmlOutputBufferWriteString(buf, "\n");
6743 xmlNodeListDumpOutput(buf, doc, cur->children,
6744 (level >= 0?level+1:-1), format, encoding);
6745 if ((xmlIndentTreeOutput) && (format))
6746 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006747 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006748 }
6749 xmlOutputBufferWriteString(buf, "</");
6750 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6751 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6752 xmlOutputBufferWriteString(buf, ":");
6753 }
6754
6755 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6756 xmlOutputBufferWriteString(buf, ">");
6757}
6758
6759/**
6760 * xmlDocContentDumpOutput:
6761 * @buf: the XML buffer output
6762 * @cur: the document
6763 * @encoding: an optional encoding string
6764 * @format: should formatting spaces been added
6765 *
6766 * Dump an XML document.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006767 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6768 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006769 */
6770static void
6771xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6772 const char *encoding, int format) {
6773 xmlOutputBufferWriteString(buf, "<?xml version=");
6774 if (cur->version != NULL)
6775 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6776 else
6777 xmlOutputBufferWriteString(buf, "\"1.0\"");
6778 if (encoding == NULL) {
6779 if (cur->encoding != NULL)
6780 encoding = (const char *) cur->encoding;
6781 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6782 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6783 }
6784 if (encoding != NULL) {
6785 xmlOutputBufferWriteString(buf, " encoding=");
6786 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6787 }
6788 switch (cur->standalone) {
6789 case 0:
6790 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6791 break;
6792 case 1:
6793 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6794 break;
6795 }
6796 xmlOutputBufferWriteString(buf, "?>\n");
6797 if (cur->children != NULL) {
6798 xmlNodePtr child = cur->children;
6799
6800 while (child != NULL) {
6801 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6802 xmlOutputBufferWriteString(buf, "\n");
6803 child = child->next;
6804 }
6805 }
6806}
6807
6808/************************************************************************
6809 * *
6810 * Saving functions front-ends *
6811 * *
6812 ************************************************************************/
6813
6814/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006815 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006816 * @out_doc: Document to generate XML text from
6817 * @doc_txt_ptr: Memory pointer for allocated XML text
6818 * @doc_txt_len: Length of the generated XML text
6819 * @txt_encoding: Character encoding to use when generating XML text
6820 * @format: should formatting spaces been added
6821 *
6822 * Dump the current DOM tree into memory using the character encoding specified
6823 * by the caller. Note it is up to the caller of this function to free the
6824 * allocated memory.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006825 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6826 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006827 */
6828
6829void
6830xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006831 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006832 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006833 int dummy = 0;
6834
6835 xmlCharEncoding doc_charset;
6836 xmlOutputBufferPtr out_buff = NULL;
6837 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6838
6839 if (doc_txt_len == NULL) {
6840 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6841 }
6842
6843 if (doc_txt_ptr == NULL) {
6844 *doc_txt_len = 0;
6845 xmlGenericError(xmlGenericErrorContext,
6846 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6847 return;
6848 }
6849
6850 *doc_txt_ptr = NULL;
6851 *doc_txt_len = 0;
6852
6853 if (out_doc == NULL) {
6854 /* No document, no output */
6855 xmlGenericError(xmlGenericErrorContext,
6856 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6857 return;
6858 }
6859
6860 /*
6861 * Validate the encoding value, if provided.
6862 * This logic is copied from xmlSaveFileEnc.
6863 */
6864
6865 if (txt_encoding == NULL)
6866 txt_encoding = (const char *) out_doc->encoding;
6867 if (txt_encoding != NULL) {
6868 doc_charset = xmlParseCharEncoding(txt_encoding);
6869
6870 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6871 xmlGenericError(xmlGenericErrorContext,
6872 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6873 return;
6874
6875 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6876 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6877 if ( conv_hdlr == NULL ) {
6878 xmlGenericError(xmlGenericErrorContext,
6879 "%s: %s %s '%s'\n",
6880 "xmlDocDumpFormatMemoryEnc",
6881 "Failed to identify encoding handler for",
6882 "character set",
6883 txt_encoding);
6884 return;
6885 }
6886 }
6887 }
6888
6889 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6890 xmlGenericError(xmlGenericErrorContext,
6891 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6892 return;
6893 }
6894
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006895 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006896 xmlOutputBufferFlush(out_buff);
6897 if (out_buff->conv != NULL) {
6898 *doc_txt_len = out_buff->conv->use;
6899 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6900 } else {
6901 *doc_txt_len = out_buff->buffer->use;
6902 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6903 }
6904 (void)xmlOutputBufferClose(out_buff);
6905
6906 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6907 *doc_txt_len = 0;
6908 xmlGenericError(xmlGenericErrorContext,
6909 "xmlDocDumpFormatMemoryEnc: %s\n",
6910 "Failed to allocate memory for document text representation.");
6911 }
6912
6913 return;
6914}
6915
6916/**
6917 * xmlDocDumpMemory:
6918 * @cur: the document
6919 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006920 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006921 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006922 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006923 * It's up to the caller to free the memory.
6924 */
6925void
6926xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6927 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6928}
6929
6930/**
6931 * xmlDocDumpFormatMemory:
6932 * @cur: the document
6933 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006934 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006935 * @format: should formatting spaces been added
6936 *
6937 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006938 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006939 * It's up to the caller to free the memory.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006940 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6941 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006942 */
6943void
6944xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6945 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6946}
6947
6948/**
6949 * xmlDocDumpMemoryEnc:
6950 * @out_doc: Document to generate XML text from
6951 * @doc_txt_ptr: Memory pointer for allocated XML text
6952 * @doc_txt_len: Length of the generated XML text
6953 * @txt_encoding: Character encoding to use when generating XML text
6954 *
6955 * Dump the current DOM tree into memory using the character encoding specified
6956 * by the caller. Note it is up to the caller of this function to free the
6957 * allocated memory.
6958 */
6959
6960void
6961xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6962 int * doc_txt_len, const char * txt_encoding) {
6963 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006964 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006965}
6966
6967/**
6968 * xmlGetDocCompressMode:
6969 * @doc: the document
6970 *
6971 * get the compression ratio for a document, ZLIB based
6972 * Returns 0 (uncompressed) to 9 (max compression)
6973 */
6974int
6975xmlGetDocCompressMode (xmlDocPtr doc) {
6976 if (doc == NULL) return(-1);
6977 return(doc->compression);
6978}
6979
6980/**
6981 * xmlSetDocCompressMode:
6982 * @doc: the document
6983 * @mode: the compression ratio
6984 *
6985 * set the compression ratio for a document, ZLIB based
6986 * Correct values: 0 (uncompressed) to 9 (max compression)
6987 */
6988void
6989xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6990 if (doc == NULL) return;
6991 if (mode < 0) doc->compression = 0;
6992 else if (mode > 9) doc->compression = 9;
6993 else doc->compression = mode;
6994}
6995
6996/**
6997 * xmlGetCompressMode:
6998 *
6999 * get the default compression mode used, ZLIB based.
7000 * Returns 0 (uncompressed) to 9 (max compression)
7001 */
7002int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007003xmlGetCompressMode(void)
7004{
7005 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00007006}
7007
7008/**
7009 * xmlSetCompressMode:
7010 * @mode: the compression ratio
7011 *
7012 * set the default compression mode used, ZLIB based
7013 * Correct values: 0 (uncompressed) to 9 (max compression)
7014 */
7015void
7016xmlSetCompressMode(int mode) {
7017 if (mode < 0) xmlCompressMode = 0;
7018 else if (mode > 9) xmlCompressMode = 9;
7019 else xmlCompressMode = mode;
7020}
7021
7022/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007023 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00007024 * @f: the FILE*
7025 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00007026 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007027 *
7028 * Dump an XML document to an open FILE.
7029 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007030 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007031 */
7032int
Daniel Veillard9e412302002-06-10 15:59:44 +00007033xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007034 xmlOutputBufferPtr buf;
7035 const char * encoding;
7036 xmlCharEncodingHandlerPtr handler = NULL;
7037 int ret;
7038
7039 if (cur == NULL) {
7040#ifdef DEBUG_TREE
7041 xmlGenericError(xmlGenericErrorContext,
7042 "xmlDocDump : document == NULL\n");
7043#endif
7044 return(-1);
7045 }
7046 encoding = (const char *) cur->encoding;
7047
7048 if (encoding != NULL) {
7049 xmlCharEncoding enc;
7050
7051 enc = xmlParseCharEncoding(encoding);
7052
7053 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7054 xmlGenericError(xmlGenericErrorContext,
7055 "xmlDocDump: document not in UTF8\n");
7056 return(-1);
7057 }
7058 if (enc != XML_CHAR_ENCODING_UTF8) {
7059 handler = xmlFindCharEncodingHandler(encoding);
7060 if (handler == NULL) {
7061 xmlFree((char *) cur->encoding);
7062 cur->encoding = NULL;
7063 }
7064 }
7065 }
7066 buf = xmlOutputBufferCreateFile(f, handler);
7067 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00007068 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007069
7070 ret = xmlOutputBufferClose(buf);
7071 return(ret);
7072}
7073
7074/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007075 * xmlDocDump:
7076 * @f: the FILE*
7077 * @cur: the document
7078 *
7079 * Dump an XML document to an open FILE.
7080 *
7081 * returns: the number of bytes written or -1 in case of failure.
7082 */
7083int
7084xmlDocDump(FILE *f, xmlDocPtr cur) {
7085 return(xmlDocFormatDump (f, cur, 0));
7086}
7087
7088/**
Owen Taylor3473f882001-02-23 17:55:21 +00007089 * xmlSaveFileTo:
7090 * @buf: an output I/O buffer
7091 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007092 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00007093 *
7094 * Dump an XML document to an I/O buffer.
7095 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007096 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007097 */
7098int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007099xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007100 int ret;
7101
7102 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007103 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007104 ret = xmlOutputBufferClose(buf);
7105 return(ret);
7106}
7107
7108/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00007109 * xmlSaveFormatFileTo:
7110 * @buf: an output I/O buffer
7111 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007112 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00007113 * @format: should formatting spaces been added
7114 *
7115 * Dump an XML document to an I/O buffer.
7116 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007117 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00007118 */
7119int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007120xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00007121 int ret;
7122
7123 if (buf == NULL) return(0);
7124 xmlDocContentDumpOutput(buf, cur, encoding, format);
7125 ret = xmlOutputBufferClose(buf);
7126 return(ret);
7127}
7128
7129/**
Daniel Veillardf012a642001-07-23 19:10:52 +00007130 * xmlSaveFormatFileEnc
7131 * @filename: the filename or URL to output
7132 * @cur: the document being saved
7133 * @encoding: the name of the encoding to use or NULL.
7134 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00007135 *
7136 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00007137 */
7138int
Daniel Veillardf012a642001-07-23 19:10:52 +00007139xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
7140 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00007141 xmlOutputBufferPtr buf;
7142 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00007143 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00007144 int ret;
7145
Daniel Veillardfb25a512002-01-13 20:32:08 +00007146 if (encoding == NULL)
7147 encoding = (const char *) cur->encoding;
7148
Owen Taylor3473f882001-02-23 17:55:21 +00007149 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007150
7151 enc = xmlParseCharEncoding(encoding);
7152 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7153 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007154 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007155 return(-1);
7156 }
7157 if (enc != XML_CHAR_ENCODING_UTF8) {
7158 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00007159 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007160 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007161 }
7162 }
7163
Daniel Veillardf012a642001-07-23 19:10:52 +00007164#ifdef HAVE_ZLIB_H
7165 if (cur->compression < 0) cur->compression = xmlCompressMode;
7166#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007167 /*
7168 * save the content to a temp buffer.
7169 */
Daniel Veillardf012a642001-07-23 19:10:52 +00007170 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00007171 if (buf == NULL) return(-1);
7172
Daniel Veillardf012a642001-07-23 19:10:52 +00007173 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007174
7175 ret = xmlOutputBufferClose(buf);
7176 return(ret);
7177}
7178
Daniel Veillardf012a642001-07-23 19:10:52 +00007179
7180/**
7181 * xmlSaveFileEnc:
7182 * @filename: the filename (or URL)
7183 * @cur: the document
7184 * @encoding: the name of an encoding (or NULL)
7185 *
7186 * Dump an XML document, converting it to the given encoding
7187 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007188 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00007189 */
7190int
7191xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
7192 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
7193}
7194
Owen Taylor3473f882001-02-23 17:55:21 +00007195/**
Daniel Veillard67fee942001-04-26 18:59:03 +00007196 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00007197 * @filename: the filename (or URL)
7198 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00007199 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007200 *
7201 * Dump an XML document to a file. Will use compression if
7202 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00007203 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00007204 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007205 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007206 */
7207int
Daniel Veillard67fee942001-04-26 18:59:03 +00007208xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007209 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00007210}
7211
Daniel Veillard67fee942001-04-26 18:59:03 +00007212/**
7213 * xmlSaveFile:
7214 * @filename: the filename (or URL)
7215 * @cur: the document
7216 *
7217 * Dump an XML document to a file. Will use compression if
7218 * compiled in and enabled. If @filename is "-" the stdout file is
7219 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00007220 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00007221 */
7222int
7223xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007224 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00007225}
7226