blob: 20017f73ec60c6246a8d0d8a5d1df5038d5193bf [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
Bjorn Reese70a9da52001-04-21 16:57:29 +000014#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000015
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24#ifdef HAVE_ZLIB_H
25#include <zlib.h>
26#endif
27
28#include <libxml/xmlmemory.h>
29#include <libxml/tree.h>
30#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000031#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000032#include <libxml/entities.h>
33#include <libxml/valid.h>
34#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000035#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000036#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000037
Daniel Veillard56a4cb82001-03-24 17:00:36 +000038xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
39
40/************************************************************************
41 * *
42 * A few static variables and macros *
43 * *
44 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000045/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000046const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000047/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000048const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000049 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000050/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +000051const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
52
Owen Taylor3473f882001-02-23 17:55:21 +000053static int xmlCompressMode = 0;
54static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000055
Owen Taylor3473f882001-02-23 17:55:21 +000056#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
57 xmlNodePtr ulccur = (n)->children; \
58 if (ulccur == NULL) { \
59 (n)->last = NULL; \
60 } else { \
61 while (ulccur->next != NULL) { \
62 ulccur->parent = (n); \
63 ulccur = ulccur->next; \
64 } \
65 ulccur->parent = (n); \
66 (n)->last = ulccur; \
67}}
68
69/* #define DEBUG_BUFFER */
70/* #define DEBUG_TREE */
71
72/************************************************************************
73 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +000074 * Functions to move to entities.c once the *
75 * API freeze is smoothen and they can be made public. *
76 * *
77 ************************************************************************/
78#include <libxml/hash.h>
79
80/**
81 * xmlGetEntityFromDtd:
82 * @dtd: A pointer to the DTD to search
83 * @name: The entity name
84 *
85 * Do an entity lookup in the DTD entity hash table and
86 * return the corresponding entity, if found.
87 *
88 * Returns A pointer to the entity structure or NULL if not found.
89 */
90static xmlEntityPtr
91xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
92 xmlEntitiesTablePtr table;
93
94 if((dtd != NULL) && (dtd->entities != NULL)) {
95 table = (xmlEntitiesTablePtr) dtd->entities;
96 return((xmlEntityPtr) xmlHashLookup(table, name));
97 /* return(xmlGetEntityFromTable(table, name)); */
98 }
99 return(NULL);
100}
101/**
102 * xmlGetParameterEntityFromDtd:
103 * @dtd: A pointer to the DTD to search
104 * @name: The entity name
105 *
106 * Do an entity lookup in the DTD pararmeter entity hash table and
107 * return the corresponding entity, if found.
108 *
109 * Returns A pointer to the entity structure or NULL if not found.
110 */
111static xmlEntityPtr
112xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
113 xmlEntitiesTablePtr table;
114
115 if ((dtd != NULL) && (dtd->pentities != NULL)) {
116 table = (xmlEntitiesTablePtr) dtd->pentities;
117 return((xmlEntityPtr) xmlHashLookup(table, name));
118 /* return(xmlGetEntityFromTable(table, name)); */
119 }
120 return(NULL);
121}
122
123/************************************************************************
124 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000125 * Allocation and deallocation of basic structures *
126 * *
127 ************************************************************************/
128
129/**
130 * xmlSetBufferAllocationScheme:
131 * @scheme: allocation method to use
132 *
133 * Set the buffer allocation method. Types are
134 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
135 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
136 * improves performance
137 */
138void
139xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
140 xmlBufferAllocScheme = scheme;
141}
142
143/**
144 * xmlGetBufferAllocationScheme:
145 *
146 * Types are
147 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
148 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
149 * improves performance
150 *
151 * Returns the current allocation scheme
152 */
153xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000154xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000155 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000156}
157
158/**
159 * xmlNewNs:
160 * @node: the element carrying the namespace
161 * @href: the URI associated
162 * @prefix: the prefix for the namespace
163 *
164 * Creation of a new Namespace. This function will refuse to create
165 * a namespace with a similar prefix than an existing one present on this
166 * node.
167 * We use href==NULL in the case of an element creation where the namespace
168 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000169 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000170 */
171xmlNsPtr
172xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
173 xmlNsPtr cur;
174
175 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
176 return(NULL);
177
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000178 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
179 return(NULL);
180
Owen Taylor3473f882001-02-23 17:55:21 +0000181 /*
182 * Allocate a new Namespace and fill the fields.
183 */
184 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
185 if (cur == NULL) {
186 xmlGenericError(xmlGenericErrorContext,
187 "xmlNewNs : malloc failed\n");
188 return(NULL);
189 }
190 memset(cur, 0, sizeof(xmlNs));
191 cur->type = XML_LOCAL_NAMESPACE;
192
193 if (href != NULL)
194 cur->href = xmlStrdup(href);
195 if (prefix != NULL)
196 cur->prefix = xmlStrdup(prefix);
197
198 /*
199 * Add it at the end to preserve parsing order ...
200 * and checks for existing use of the prefix
201 */
202 if (node != NULL) {
203 if (node->nsDef == NULL) {
204 node->nsDef = cur;
205 } else {
206 xmlNsPtr prev = node->nsDef;
207
208 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
209 (xmlStrEqual(prev->prefix, cur->prefix))) {
210 xmlFreeNs(cur);
211 return(NULL);
212 }
213 while (prev->next != NULL) {
214 prev = prev->next;
215 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
216 (xmlStrEqual(prev->prefix, cur->prefix))) {
217 xmlFreeNs(cur);
218 return(NULL);
219 }
220 }
221 prev->next = cur;
222 }
223 }
224 return(cur);
225}
226
227/**
228 * xmlSetNs:
229 * @node: a node in the document
230 * @ns: a namespace pointer
231 *
232 * Associate a namespace to a node, a posteriori.
233 */
234void
235xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
236 if (node == NULL) {
237#ifdef DEBUG_TREE
238 xmlGenericError(xmlGenericErrorContext,
239 "xmlSetNs: node == NULL\n");
240#endif
241 return;
242 }
243 node->ns = ns;
244}
245
246/**
247 * xmlFreeNs:
248 * @cur: the namespace pointer
249 *
250 * Free up the structures associated to a namespace
251 */
252void
253xmlFreeNs(xmlNsPtr cur) {
254 if (cur == NULL) {
255#ifdef DEBUG_TREE
256 xmlGenericError(xmlGenericErrorContext,
257 "xmlFreeNs : ns == NULL\n");
258#endif
259 return;
260 }
261 if (cur->href != NULL) xmlFree((char *) cur->href);
262 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000263 xmlFree(cur);
264}
265
266/**
267 * xmlFreeNsList:
268 * @cur: the first namespace pointer
269 *
270 * Free up all the structures associated to the chained namespaces.
271 */
272void
273xmlFreeNsList(xmlNsPtr cur) {
274 xmlNsPtr next;
275 if (cur == NULL) {
276#ifdef DEBUG_TREE
277 xmlGenericError(xmlGenericErrorContext,
278 "xmlFreeNsList : ns == NULL\n");
279#endif
280 return;
281 }
282 while (cur != NULL) {
283 next = cur->next;
284 xmlFreeNs(cur);
285 cur = next;
286 }
287}
288
289/**
290 * xmlNewDtd:
291 * @doc: the document pointer
292 * @name: the DTD name
293 * @ExternalID: the external ID
294 * @SystemID: the system ID
295 *
296 * Creation of a new DTD for the external subset. To create an
297 * internal subset, use xmlCreateIntSubset().
298 *
299 * Returns a pointer to the new DTD structure
300 */
301xmlDtdPtr
302xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
303 const xmlChar *ExternalID, const xmlChar *SystemID) {
304 xmlDtdPtr cur;
305
306 if ((doc != NULL) && (doc->extSubset != NULL)) {
307#ifdef DEBUG_TREE
308 xmlGenericError(xmlGenericErrorContext,
309 "xmlNewDtd(%s): document %s already have a DTD %s\n",
310 /* !!! */ (char *) name, doc->name,
311 /* !!! */ (char *)doc->extSubset->name);
312#endif
313 return(NULL);
314 }
315
316 /*
317 * Allocate a new DTD and fill the fields.
318 */
319 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
320 if (cur == NULL) {
321 xmlGenericError(xmlGenericErrorContext,
322 "xmlNewDtd : malloc failed\n");
323 return(NULL);
324 }
325 memset(cur, 0 , sizeof(xmlDtd));
326 cur->type = XML_DTD_NODE;
327
328 if (name != NULL)
329 cur->name = xmlStrdup(name);
330 if (ExternalID != NULL)
331 cur->ExternalID = xmlStrdup(ExternalID);
332 if (SystemID != NULL)
333 cur->SystemID = xmlStrdup(SystemID);
334 if (doc != NULL)
335 doc->extSubset = cur;
336 cur->doc = doc;
337
338 return(cur);
339}
340
341/**
342 * xmlGetIntSubset:
343 * @doc: the document pointer
344 *
345 * Get the internal subset of a document
346 * Returns a pointer to the DTD structure or NULL if not found
347 */
348
349xmlDtdPtr
350xmlGetIntSubset(xmlDocPtr doc) {
351 xmlNodePtr cur;
352
353 if (doc == NULL)
354 return(NULL);
355 cur = doc->children;
356 while (cur != NULL) {
357 if (cur->type == XML_DTD_NODE)
358 return((xmlDtdPtr) cur);
359 cur = cur->next;
360 }
361 return((xmlDtdPtr) doc->intSubset);
362}
363
364/**
365 * xmlCreateIntSubset:
366 * @doc: the document pointer
367 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000368 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000369 * @SystemID: the system ID
370 *
371 * Create the internal subset of a document
372 * Returns a pointer to the new DTD structure
373 */
374xmlDtdPtr
375xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
376 const xmlChar *ExternalID, const xmlChar *SystemID) {
377 xmlDtdPtr cur;
378
379 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
380#ifdef DEBUG_TREE
381 xmlGenericError(xmlGenericErrorContext,
382
383 "xmlCreateIntSubset(): document %s already have an internal subset\n",
384 doc->name);
385#endif
386 return(NULL);
387 }
388
389 /*
390 * Allocate a new DTD and fill the fields.
391 */
392 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
393 if (cur == NULL) {
394 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000395 "xmlCreateIntSubset : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000396 return(NULL);
397 }
398 memset(cur, 0, sizeof(xmlDtd));
399 cur->type = XML_DTD_NODE;
400
401 if (name != NULL)
402 cur->name = xmlStrdup(name);
403 if (ExternalID != NULL)
404 cur->ExternalID = xmlStrdup(ExternalID);
405 if (SystemID != NULL)
406 cur->SystemID = xmlStrdup(SystemID);
407 if (doc != NULL) {
408 doc->intSubset = cur;
409 cur->parent = doc;
410 cur->doc = doc;
411 if (doc->children == NULL) {
412 doc->children = (xmlNodePtr) cur;
413 doc->last = (xmlNodePtr) cur;
414 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000415 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000416 xmlNodePtr prev;
417
Owen Taylor3473f882001-02-23 17:55:21 +0000418 prev = doc->children;
419 prev->prev = (xmlNodePtr) cur;
420 cur->next = prev;
421 doc->children = (xmlNodePtr) cur;
422 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000423 xmlNodePtr next;
424
425 next = doc->children;
426 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
427 next = next->next;
428 if (next == NULL) {
429 cur->prev = doc->last;
430 cur->prev->next = (xmlNodePtr) cur;
431 cur->next = NULL;
432 doc->last = (xmlNodePtr) cur;
433 } else {
434 cur->next = next;
435 cur->prev = next->prev;
436 if (cur->prev == NULL)
437 doc->children = (xmlNodePtr) cur;
438 else
439 cur->prev->next = (xmlNodePtr) cur;
440 next->prev = (xmlNodePtr) cur;
441 }
Owen Taylor3473f882001-02-23 17:55:21 +0000442 }
443 }
444 }
445 return(cur);
446}
447
448/**
449 * xmlFreeDtd:
450 * @cur: the DTD structure to free up
451 *
452 * Free a DTD structure.
453 */
454void
455xmlFreeDtd(xmlDtdPtr cur) {
456 if (cur == NULL) {
457#ifdef DEBUG_TREE
458 xmlGenericError(xmlGenericErrorContext,
459 "xmlFreeDtd : DTD == NULL\n");
460#endif
461 return;
462 }
463 if (cur->children != NULL) {
464 xmlNodePtr next, c = cur->children;
465
466 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000467 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000468 * indexes.
469 */
470 while (c != NULL) {
471 next = c->next;
472 if (c->type == XML_COMMENT_NODE) {
473 xmlUnlinkNode(c);
474 xmlFreeNode(c);
475 }
476 c = next;
477 }
478 }
479 if (cur->name != NULL) xmlFree((char *) cur->name);
480 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
481 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
482 /* TODO !!! */
483 if (cur->notations != NULL)
484 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
485
486 if (cur->elements != NULL)
487 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
488 if (cur->attributes != NULL)
489 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
490 if (cur->entities != NULL)
491 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
492 if (cur->pentities != NULL)
493 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
494
Owen Taylor3473f882001-02-23 17:55:21 +0000495 xmlFree(cur);
496}
497
498/**
499 * xmlNewDoc:
500 * @version: xmlChar string giving the version of XML "1.0"
501 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000502 * Creates a new XML document
503 *
Owen Taylor3473f882001-02-23 17:55:21 +0000504 * Returns a new document
505 */
506xmlDocPtr
507xmlNewDoc(const xmlChar *version) {
508 xmlDocPtr cur;
509
510 if (version == NULL)
511 version = (const xmlChar *) "1.0";
512
513 /*
514 * Allocate a new document and fill the fields.
515 */
516 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
517 if (cur == NULL) {
518 xmlGenericError(xmlGenericErrorContext,
519 "xmlNewDoc : malloc failed\n");
520 return(NULL);
521 }
522 memset(cur, 0, sizeof(xmlDoc));
523 cur->type = XML_DOCUMENT_NODE;
524
525 cur->version = xmlStrdup(version);
526 cur->standalone = -1;
527 cur->compression = -1; /* not initialized */
528 cur->doc = cur;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000529 cur->charset = XML_CHAR_ENCODING_UTF8;
Owen Taylor3473f882001-02-23 17:55:21 +0000530 return(cur);
531}
532
533/**
534 * xmlFreeDoc:
535 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +0000536 *
537 * Free up all the structures used by a document, tree included.
538 */
539void
540xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000541 xmlDtdPtr extSubset, intSubset;
542
Owen Taylor3473f882001-02-23 17:55:21 +0000543 if (cur == NULL) {
544#ifdef DEBUG_TREE
545 xmlGenericError(xmlGenericErrorContext,
546 "xmlFreeDoc : document == NULL\n");
547#endif
548 return;
549 }
Daniel Veillard76d66f42001-05-16 21:05:17 +0000550 /*
551 * Do this before freeing the children list to avoid ID lookups
552 */
553 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
554 cur->ids = NULL;
555 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
556 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000557 extSubset = cur->extSubset;
558 intSubset = cur->intSubset;
559 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000560 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000561 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000562 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000563 }
Daniel Veillarda9142e72001-06-19 11:07:54 +0000564 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000565 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000566 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000567 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000568 }
569
570 if (cur->children != NULL) xmlFreeNodeList(cur->children);
571
Owen Taylor3473f882001-02-23 17:55:21 +0000572 if (cur->version != NULL) xmlFree((char *) cur->version);
573 if (cur->name != NULL) xmlFree((char *) cur->name);
574 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +0000575 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +0000576 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000577 xmlFree(cur);
578}
579
580/**
581 * xmlStringLenGetNodeList:
582 * @doc: the document
583 * @value: the value of the text
584 * @len: the length of the string value
585 *
586 * Parse the value string and build the node list associated. Should
587 * produce a flat tree with only TEXTs and ENTITY_REFs.
588 * Returns a pointer to the first child
589 */
590xmlNodePtr
591xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
592 xmlNodePtr ret = NULL, last = NULL;
593 xmlNodePtr node;
594 xmlChar *val;
595 const xmlChar *cur = value;
596 const xmlChar *q;
597 xmlEntityPtr ent;
598
599 if (value == NULL) return(NULL);
600
601 q = cur;
602 while ((*cur != 0) && (cur - value < len)) {
603 if (*cur == '&') {
604 /*
605 * Save the current text.
606 */
607 if (cur != q) {
608 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
609 xmlNodeAddContentLen(last, q, cur - q);
610 } else {
611 node = xmlNewDocTextLen(doc, q, cur - q);
612 if (node == NULL) return(ret);
613 if (last == NULL)
614 last = ret = node;
615 else {
616 last->next = node;
617 node->prev = last;
618 last = node;
619 }
620 }
621 }
622 /*
623 * Read the entity string
624 */
625 cur++;
626 q = cur;
627 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
628 if ((*cur == 0) || (cur - value >= len)) {
629#ifdef DEBUG_TREE
630 xmlGenericError(xmlGenericErrorContext,
631 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
632#endif
633 return(ret);
634 }
635 if (cur != q) {
636 /*
637 * Predefined entities don't generate nodes
638 */
639 val = xmlStrndup(q, cur - q);
640 ent = xmlGetDocEntity(doc, val);
641 if ((ent != NULL) &&
642 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
643 if (last == NULL) {
644 node = xmlNewDocText(doc, ent->content);
645 last = ret = node;
646 } else
647 xmlNodeAddContent(last, ent->content);
648
649 } else {
650 /*
651 * Create a new REFERENCE_REF node
652 */
653 node = xmlNewReference(doc, val);
654 if (node == NULL) {
655 if (val != NULL) xmlFree(val);
656 return(ret);
657 }
658 if (last == NULL)
659 last = ret = node;
660 else {
661 last->next = node;
662 node->prev = last;
663 last = node;
664 }
665 }
666 xmlFree(val);
667 }
668 cur++;
669 q = cur;
670 } else
671 cur++;
672 }
673 if (cur != q) {
674 /*
675 * Handle the last piece of text.
676 */
677 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
678 xmlNodeAddContentLen(last, q, cur - q);
679 } else {
680 node = xmlNewDocTextLen(doc, q, cur - q);
681 if (node == NULL) return(ret);
682 if (last == NULL)
683 last = ret = node;
684 else {
685 last->next = node;
686 node->prev = last;
687 last = node;
688 }
689 }
690 }
691 return(ret);
692}
693
694/**
695 * xmlStringGetNodeList:
696 * @doc: the document
697 * @value: the value of the attribute
698 *
699 * Parse the value string and build the node list associated. Should
700 * produce a flat tree with only TEXTs and ENTITY_REFs.
701 * Returns a pointer to the first child
702 */
703xmlNodePtr
704xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
705 xmlNodePtr ret = NULL, last = NULL;
706 xmlNodePtr node;
707 xmlChar *val;
708 const xmlChar *cur = value;
709 const xmlChar *q;
710 xmlEntityPtr ent;
711
712 if (value == NULL) return(NULL);
713
714 q = cur;
715 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000716 if (cur[0] == '&') {
717 int charval = 0;
718 xmlChar tmp;
719
Owen Taylor3473f882001-02-23 17:55:21 +0000720 /*
721 * Save the current text.
722 */
723 if (cur != q) {
724 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
725 xmlNodeAddContentLen(last, q, cur - q);
726 } else {
727 node = xmlNewDocTextLen(doc, q, cur - q);
728 if (node == NULL) return(ret);
729 if (last == NULL)
730 last = ret = node;
731 else {
732 last->next = node;
733 node->prev = last;
734 last = node;
735 }
736 }
737 }
Owen Taylor3473f882001-02-23 17:55:21 +0000738 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000739 if ((cur[1] == '#') && (cur[2] == 'x')) {
740 cur += 3;
741 tmp = *cur;
742 while (tmp != ';') { /* Non input consuming loop */
743 if ((tmp >= '0') && (tmp <= '9'))
744 charval = charval * 16 + (tmp - '0');
745 else if ((tmp >= 'a') && (tmp <= 'f'))
746 charval = charval * 16 + (tmp - 'a') + 10;
747 else if ((tmp >= 'A') && (tmp <= 'F'))
748 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +0000749 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000750 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000751 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000752 charval = 0;
753 break;
754 }
755 cur++;
756 tmp = *cur;
757 }
758 if (tmp == ';')
759 cur++;
760 q = cur;
761 } else if (cur[1] == '#') {
762 cur += 2;
763 tmp = *cur;
764 while (tmp != ';') { /* Non input consuming loops */
765 if ((tmp >= '0') && (tmp <= '9'))
766 charval = charval * 10 + (tmp - '0');
767 else {
768 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000769 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000770 charval = 0;
771 break;
772 }
773 cur++;
774 tmp = *cur;
775 }
776 if (tmp == ';')
777 cur++;
778 q = cur;
779 } else {
780 /*
781 * Read the entity string
782 */
783 cur++;
784 q = cur;
785 while ((*cur != 0) && (*cur != ';')) cur++;
786 if (*cur == 0) {
787#ifdef DEBUG_TREE
788 xmlGenericError(xmlGenericErrorContext,
789 "xmlStringGetNodeList: unterminated entity %30s\n", q);
790#endif
791 return(ret);
792 }
793 if (cur != q) {
794 /*
795 * Predefined entities don't generate nodes
796 */
797 val = xmlStrndup(q, cur - q);
798 ent = xmlGetDocEntity(doc, val);
799 if ((ent != NULL) &&
800 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
801 if (last == NULL) {
802 node = xmlNewDocText(doc, ent->content);
803 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +0000804 } else if (last->type != XML_TEXT_NODE) {
805 node = xmlNewDocText(doc, ent->content);
806 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000807 } else
808 xmlNodeAddContent(last, ent->content);
809
810 } else {
811 /*
812 * Create a new REFERENCE_REF node
813 */
814 node = xmlNewReference(doc, val);
815 if (node == NULL) {
816 if (val != NULL) xmlFree(val);
817 return(ret);
818 }
819 if (last == NULL) {
820 last = ret = node;
821 } else {
822 last = xmlAddNextSibling(last, node);
823 }
824 }
825 xmlFree(val);
826 }
827 cur++;
828 q = cur;
829 }
830 if (charval != 0) {
831 xmlChar buf[10];
832 int len;
833
834 len = xmlCopyCharMultiByte(buf, charval);
835 buf[len] = 0;
836 node = xmlNewDocText(doc, buf);
837 if (node != NULL) {
838 if (last == NULL) {
839 last = ret = node;
840 } else {
841 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000842 }
843 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000844
845 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000846 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000847 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000848 cur++;
849 }
Daniel Veillard75bea542001-05-11 17:41:21 +0000850 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000851 /*
852 * Handle the last piece of text.
853 */
854 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
855 xmlNodeAddContentLen(last, q, cur - q);
856 } else {
857 node = xmlNewDocTextLen(doc, q, cur - q);
858 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000859 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000860 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000861 } else {
862 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000863 }
864 }
865 }
866 return(ret);
867}
868
869/**
870 * xmlNodeListGetString:
871 * @doc: the document
872 * @list: a Node list
873 * @inLine: should we replace entity contents or show their external form
874 *
875 * Returns the string equivalent to the text contained in the Node list
876 * made of TEXTs and ENTITY_REFs
Daniel Veillardd1640922001-12-17 15:30:10 +0000877 * Returns a pointer to the string copy, the caller must free it.
Owen Taylor3473f882001-02-23 17:55:21 +0000878 */
879xmlChar *
880xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
881 xmlNodePtr node = list;
882 xmlChar *ret = NULL;
883 xmlEntityPtr ent;
884
885 if (list == NULL) return(NULL);
886
887 while (node != NULL) {
888 if ((node->type == XML_TEXT_NODE) ||
889 (node->type == XML_CDATA_SECTION_NODE)) {
890 if (inLine) {
891#ifndef XML_USE_BUFFER_CONTENT
892 ret = xmlStrcat(ret, node->content);
893#else
894 ret = xmlStrcat(ret, xmlBufferContent(node->content));
895#endif
896 } else {
897 xmlChar *buffer;
898
899#ifndef XML_USE_BUFFER_CONTENT
900 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
901#else
902 buffer = xmlEncodeEntitiesReentrant(doc,
903 xmlBufferContent(node->content));
904#endif
905 if (buffer != NULL) {
906 ret = xmlStrcat(ret, buffer);
907 xmlFree(buffer);
908 }
909 }
910 } else if (node->type == XML_ENTITY_REF_NODE) {
911 if (inLine) {
912 ent = xmlGetDocEntity(doc, node->name);
913 if (ent != NULL)
914 ret = xmlStrcat(ret, ent->content);
915 else {
916#ifndef XML_USE_BUFFER_CONTENT
917 ret = xmlStrcat(ret, node->content);
918#else
919 ret = xmlStrcat(ret, xmlBufferContent(node->content));
920#endif
921 }
922 } else {
923 xmlChar buf[2];
924 buf[0] = '&'; buf[1] = 0;
925 ret = xmlStrncat(ret, buf, 1);
926 ret = xmlStrcat(ret, node->name);
927 buf[0] = ';'; buf[1] = 0;
928 ret = xmlStrncat(ret, buf, 1);
929 }
930 }
931#if 0
932 else {
933 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000934 "xmlGetNodeListString : invalid node type %d\n",
Owen Taylor3473f882001-02-23 17:55:21 +0000935 node->type);
936 }
937#endif
938 node = node->next;
939 }
940 return(ret);
941}
942
943/**
944 * xmlNodeListGetRawString:
945 * @doc: the document
946 * @list: a Node list
947 * @inLine: should we replace entity contents or show their external form
948 *
949 * Returns the string equivalent to the text contained in the Node list
950 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
951 * this function doesn't do any character encoding handling.
952 *
Daniel Veillardd1640922001-12-17 15:30:10 +0000953 * Returns a pointer to the string copy, the caller must free it.
Owen Taylor3473f882001-02-23 17:55:21 +0000954 */
955xmlChar *
956xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
957 xmlNodePtr node = list;
958 xmlChar *ret = NULL;
959 xmlEntityPtr ent;
960
961 if (list == NULL) return(NULL);
962
963 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +0000964 if ((node->type == XML_TEXT_NODE) ||
965 (node->type == XML_CDATA_SECTION_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000966 if (inLine) {
967#ifndef XML_USE_BUFFER_CONTENT
968 ret = xmlStrcat(ret, node->content);
969#else
970 ret = xmlStrcat(ret, xmlBufferContent(node->content));
971#endif
972 } else {
973 xmlChar *buffer;
974
975#ifndef XML_USE_BUFFER_CONTENT
976 buffer = xmlEncodeSpecialChars(doc, node->content);
977#else
978 buffer = xmlEncodeSpecialChars(doc,
979 xmlBufferContent(node->content));
980#endif
981 if (buffer != NULL) {
982 ret = xmlStrcat(ret, buffer);
983 xmlFree(buffer);
984 }
985 }
986 } else if (node->type == XML_ENTITY_REF_NODE) {
987 if (inLine) {
988 ent = xmlGetDocEntity(doc, node->name);
989 if (ent != NULL)
990 ret = xmlStrcat(ret, ent->content);
991 else {
992#ifndef XML_USE_BUFFER_CONTENT
993 ret = xmlStrcat(ret, node->content);
994#else
995 ret = xmlStrcat(ret, xmlBufferContent(node->content));
996#endif
997 }
998 } else {
999 xmlChar buf[2];
1000 buf[0] = '&'; buf[1] = 0;
1001 ret = xmlStrncat(ret, buf, 1);
1002 ret = xmlStrcat(ret, node->name);
1003 buf[0] = ';'; buf[1] = 0;
1004 ret = xmlStrncat(ret, buf, 1);
1005 }
1006 }
1007#if 0
1008 else {
1009 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001010 "xmlGetNodeListString : invalid node type %d\n",
Owen Taylor3473f882001-02-23 17:55:21 +00001011 node->type);
1012 }
1013#endif
1014 node = node->next;
1015 }
1016 return(ret);
1017}
1018
1019/**
1020 * xmlNewProp:
1021 * @node: the holding node
1022 * @name: the name of the attribute
1023 * @value: the value of the attribute
1024 *
1025 * Create a new property carried by a node.
1026 * Returns a pointer to the attribute
1027 */
1028xmlAttrPtr
1029xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1030 xmlAttrPtr cur;
1031 xmlDocPtr doc = NULL;
1032
1033 if (name == NULL) {
1034#ifdef DEBUG_TREE
1035 xmlGenericError(xmlGenericErrorContext,
1036 "xmlNewProp : name == NULL\n");
1037#endif
1038 return(NULL);
1039 }
1040
1041 /*
1042 * Allocate a new property and fill the fields.
1043 */
1044 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1045 if (cur == NULL) {
1046 xmlGenericError(xmlGenericErrorContext,
1047 "xmlNewProp : malloc failed\n");
1048 return(NULL);
1049 }
1050 memset(cur, 0, sizeof(xmlAttr));
1051 cur->type = XML_ATTRIBUTE_NODE;
1052
1053 cur->parent = node;
1054 if (node != NULL) {
1055 doc = node->doc;
1056 cur->doc = doc;
1057 }
1058 cur->name = xmlStrdup(name);
1059 if (value != NULL) {
1060 xmlChar *buffer;
1061 xmlNodePtr tmp;
1062
1063 buffer = xmlEncodeEntitiesReentrant(doc, value);
1064 cur->children = xmlStringGetNodeList(doc, buffer);
1065 cur->last = NULL;
1066 tmp = cur->children;
1067 while (tmp != NULL) {
1068 tmp->parent = (xmlNodePtr) cur;
1069 tmp->doc = doc;
1070 if (tmp->next == NULL)
1071 cur->last = tmp;
1072 tmp = tmp->next;
1073 }
1074 xmlFree(buffer);
1075 }
1076
1077 /*
1078 * Add it at the end to preserve parsing order ...
1079 */
1080 if (node != NULL) {
1081 if (node->properties == NULL) {
1082 node->properties = cur;
1083 } else {
1084 xmlAttrPtr prev = node->properties;
1085
1086 while (prev->next != NULL) prev = prev->next;
1087 prev->next = cur;
1088 cur->prev = prev;
1089 }
1090 }
1091 return(cur);
1092}
1093
1094/**
1095 * xmlNewNsProp:
1096 * @node: the holding node
1097 * @ns: the namespace
1098 * @name: the name of the attribute
1099 * @value: the value of the attribute
1100 *
1101 * Create a new property tagged with a namespace and carried by a node.
1102 * Returns a pointer to the attribute
1103 */
1104xmlAttrPtr
1105xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1106 const xmlChar *value) {
1107 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001108 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001109
1110 if (name == NULL) {
1111#ifdef DEBUG_TREE
1112 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001113 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001114#endif
1115 return(NULL);
1116 }
1117
1118 /*
1119 * Allocate a new property and fill the fields.
1120 */
1121 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1122 if (cur == NULL) {
1123 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001124 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001125 return(NULL);
1126 }
1127 memset(cur, 0, sizeof(xmlAttr));
1128 cur->type = XML_ATTRIBUTE_NODE;
1129
1130 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001131 if (node != NULL) {
1132 doc = node->doc;
1133 cur->doc = doc;
1134 }
Owen Taylor3473f882001-02-23 17:55:21 +00001135 cur->ns = ns;
1136 cur->name = xmlStrdup(name);
1137 if (value != NULL) {
1138 xmlChar *buffer;
1139 xmlNodePtr tmp;
1140
Daniel Veillarda682b212001-06-07 19:59:42 +00001141 buffer = xmlEncodeEntitiesReentrant(doc, value);
1142 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001143 cur->last = NULL;
1144 tmp = cur->children;
1145 while (tmp != NULL) {
1146 tmp->parent = (xmlNodePtr) cur;
1147 if (tmp->next == NULL)
1148 cur->last = tmp;
1149 tmp = tmp->next;
1150 }
1151 xmlFree(buffer);
1152 }
1153
1154 /*
1155 * Add it at the end to preserve parsing order ...
1156 */
1157 if (node != NULL) {
1158 if (node->properties == NULL) {
1159 node->properties = cur;
1160 } else {
1161 xmlAttrPtr prev = node->properties;
1162
1163 while (prev->next != NULL) prev = prev->next;
1164 prev->next = cur;
1165 cur->prev = prev;
1166 }
1167 }
1168 return(cur);
1169}
1170
1171/**
1172 * xmlNewDocProp:
1173 * @doc: the document
1174 * @name: the name of the attribute
1175 * @value: the value of the attribute
1176 *
1177 * Create a new property carried by a document.
1178 * Returns a pointer to the attribute
1179 */
1180xmlAttrPtr
1181xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1182 xmlAttrPtr cur;
1183
1184 if (name == NULL) {
1185#ifdef DEBUG_TREE
1186 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001187 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001188#endif
1189 return(NULL);
1190 }
1191
1192 /*
1193 * Allocate a new property and fill the fields.
1194 */
1195 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1196 if (cur == NULL) {
1197 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001198 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001199 return(NULL);
1200 }
1201 memset(cur, 0, sizeof(xmlAttr));
1202 cur->type = XML_ATTRIBUTE_NODE;
1203
1204 cur->name = xmlStrdup(name);
1205 cur->doc = doc;
1206 if (value != NULL) {
1207 xmlNodePtr tmp;
1208
1209 cur->children = xmlStringGetNodeList(doc, value);
1210 cur->last = NULL;
1211
1212 tmp = cur->children;
1213 while (tmp != NULL) {
1214 tmp->parent = (xmlNodePtr) cur;
1215 if (tmp->next == NULL)
1216 cur->last = tmp;
1217 tmp = tmp->next;
1218 }
1219 }
1220 return(cur);
1221}
1222
1223/**
1224 * xmlFreePropList:
1225 * @cur: the first property in the list
1226 *
1227 * Free a property and all its siblings, all the children are freed too.
1228 */
1229void
1230xmlFreePropList(xmlAttrPtr cur) {
1231 xmlAttrPtr next;
1232 if (cur == NULL) {
1233#ifdef DEBUG_TREE
1234 xmlGenericError(xmlGenericErrorContext,
1235 "xmlFreePropList : property == NULL\n");
1236#endif
1237 return;
1238 }
1239 while (cur != NULL) {
1240 next = cur->next;
1241 xmlFreeProp(cur);
1242 cur = next;
1243 }
1244}
1245
1246/**
1247 * xmlFreeProp:
1248 * @cur: an attribute
1249 *
1250 * Free one attribute, all the content is freed too
1251 */
1252void
1253xmlFreeProp(xmlAttrPtr cur) {
1254 if (cur == NULL) {
1255#ifdef DEBUG_TREE
1256 xmlGenericError(xmlGenericErrorContext,
1257 "xmlFreeProp : property == NULL\n");
1258#endif
1259 return;
1260 }
1261 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001262 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1263 ((cur->parent->doc->intSubset != NULL) ||
1264 (cur->parent->doc->extSubset != NULL))) {
1265 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1266 xmlRemoveID(cur->parent->doc, cur);
1267 }
Owen Taylor3473f882001-02-23 17:55:21 +00001268 if (cur->name != NULL) xmlFree((char *) cur->name);
1269 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001270 xmlFree(cur);
1271}
1272
1273/**
1274 * xmlRemoveProp:
1275 * @cur: an attribute
1276 *
1277 * Unlink and free one attribute, all the content is freed too
1278 * Note this doesn't work for namespace definition attributes
1279 *
1280 * Returns 0 if success and -1 in case of error.
1281 */
1282int
1283xmlRemoveProp(xmlAttrPtr cur) {
1284 xmlAttrPtr tmp;
1285 if (cur == NULL) {
1286#ifdef DEBUG_TREE
1287 xmlGenericError(xmlGenericErrorContext,
1288 "xmlRemoveProp : cur == NULL\n");
1289#endif
1290 return(-1);
1291 }
1292 if (cur->parent == NULL) {
1293#ifdef DEBUG_TREE
1294 xmlGenericError(xmlGenericErrorContext,
1295 "xmlRemoveProp : cur->parent == NULL\n");
1296#endif
1297 return(-1);
1298 }
1299 tmp = cur->parent->properties;
1300 if (tmp == cur) {
1301 cur->parent->properties = cur->next;
1302 xmlFreeProp(cur);
1303 return(0);
1304 }
1305 while (tmp != NULL) {
1306 if (tmp->next == cur) {
1307 tmp->next = cur->next;
1308 if (tmp->next != NULL)
1309 tmp->next->prev = tmp;
1310 xmlFreeProp(cur);
1311 return(0);
1312 }
1313 tmp = tmp->next;
1314 }
1315#ifdef DEBUG_TREE
1316 xmlGenericError(xmlGenericErrorContext,
1317 "xmlRemoveProp : attribute not owned by its node\n");
1318#endif
1319 return(-1);
1320}
1321
1322/**
1323 * xmlNewPI:
1324 * @name: the processing instruction name
1325 * @content: the PI content
1326 *
1327 * Creation of a processing instruction element.
1328 * Returns a pointer to the new node object.
1329 */
1330xmlNodePtr
1331xmlNewPI(const xmlChar *name, const xmlChar *content) {
1332 xmlNodePtr cur;
1333
1334 if (name == NULL) {
1335#ifdef DEBUG_TREE
1336 xmlGenericError(xmlGenericErrorContext,
1337 "xmlNewPI : name == NULL\n");
1338#endif
1339 return(NULL);
1340 }
1341
1342 /*
1343 * Allocate a new node and fill the fields.
1344 */
1345 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1346 if (cur == NULL) {
1347 xmlGenericError(xmlGenericErrorContext,
1348 "xmlNewPI : malloc failed\n");
1349 return(NULL);
1350 }
1351 memset(cur, 0, sizeof(xmlNode));
1352 cur->type = XML_PI_NODE;
1353
1354 cur->name = xmlStrdup(name);
1355 if (content != NULL) {
1356#ifndef XML_USE_BUFFER_CONTENT
1357 cur->content = xmlStrdup(content);
1358#else
1359 cur->content = xmlBufferCreateSize(0);
1360 xmlBufferSetAllocationScheme(cur->content,
1361 xmlGetBufferAllocationScheme());
1362 xmlBufferAdd(cur->content, content, -1);
1363#endif
1364 }
1365 return(cur);
1366}
1367
1368/**
1369 * xmlNewNode:
1370 * @ns: namespace if any
1371 * @name: the node name
1372 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001373 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001374 *
1375 * Returns a pointer to the new node object.
1376 */
1377xmlNodePtr
1378xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1379 xmlNodePtr cur;
1380
1381 if (name == NULL) {
1382#ifdef DEBUG_TREE
1383 xmlGenericError(xmlGenericErrorContext,
1384 "xmlNewNode : name == NULL\n");
1385#endif
1386 return(NULL);
1387 }
1388
1389 /*
1390 * Allocate a new node and fill the fields.
1391 */
1392 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1393 if (cur == NULL) {
1394 xmlGenericError(xmlGenericErrorContext,
1395 "xmlNewNode : malloc failed\n");
1396 return(NULL);
1397 }
1398 memset(cur, 0, sizeof(xmlNode));
1399 cur->type = XML_ELEMENT_NODE;
1400
1401 cur->name = xmlStrdup(name);
1402 cur->ns = ns;
1403 return(cur);
1404}
1405
1406/**
1407 * xmlNewDocNode:
1408 * @doc: the document
1409 * @ns: namespace if any
1410 * @name: the node name
1411 * @content: the XML text content if any
1412 *
1413 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001414 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001415 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1416 * references, but XML special chars need to be escaped first by using
1417 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1418 * need entities support.
1419 *
1420 * Returns a pointer to the new node object.
1421 */
1422xmlNodePtr
1423xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1424 const xmlChar *name, const xmlChar *content) {
1425 xmlNodePtr cur;
1426
1427 cur = xmlNewNode(ns, name);
1428 if (cur != NULL) {
1429 cur->doc = doc;
1430 if (content != NULL) {
1431 cur->children = xmlStringGetNodeList(doc, content);
1432 UPDATE_LAST_CHILD_AND_PARENT(cur)
1433 }
1434 }
1435 return(cur);
1436}
1437
1438
1439/**
1440 * xmlNewDocRawNode:
1441 * @doc: the document
1442 * @ns: namespace if any
1443 * @name: the node name
1444 * @content: the text content if any
1445 *
1446 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001447 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001448 *
1449 * Returns a pointer to the new node object.
1450 */
1451xmlNodePtr
1452xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1453 const xmlChar *name, const xmlChar *content) {
1454 xmlNodePtr cur;
1455
1456 cur = xmlNewNode(ns, name);
1457 if (cur != NULL) {
1458 cur->doc = doc;
1459 if (content != NULL) {
1460 cur->children = xmlNewDocText(doc, content);
1461 UPDATE_LAST_CHILD_AND_PARENT(cur)
1462 }
1463 }
1464 return(cur);
1465}
1466
1467/**
1468 * xmlNewDocFragment:
1469 * @doc: the document owning the fragment
1470 *
1471 * Creation of a new Fragment node.
1472 * Returns a pointer to the new node object.
1473 */
1474xmlNodePtr
1475xmlNewDocFragment(xmlDocPtr doc) {
1476 xmlNodePtr cur;
1477
1478 /*
1479 * Allocate a new DocumentFragment node and fill the fields.
1480 */
1481 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1482 if (cur == NULL) {
1483 xmlGenericError(xmlGenericErrorContext,
1484 "xmlNewDocFragment : malloc failed\n");
1485 return(NULL);
1486 }
1487 memset(cur, 0, sizeof(xmlNode));
1488 cur->type = XML_DOCUMENT_FRAG_NODE;
1489
1490 cur->doc = doc;
1491 return(cur);
1492}
1493
1494/**
1495 * xmlNewText:
1496 * @content: the text content
1497 *
1498 * Creation of a new text node.
1499 * Returns a pointer to the new node object.
1500 */
1501xmlNodePtr
1502xmlNewText(const xmlChar *content) {
1503 xmlNodePtr cur;
1504
1505 /*
1506 * Allocate a new node and fill the fields.
1507 */
1508 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1509 if (cur == NULL) {
1510 xmlGenericError(xmlGenericErrorContext,
1511 "xmlNewText : malloc failed\n");
1512 return(NULL);
1513 }
1514 memset(cur, 0, sizeof(xmlNode));
1515 cur->type = XML_TEXT_NODE;
1516
1517 cur->name = xmlStringText;
1518 if (content != NULL) {
1519#ifndef XML_USE_BUFFER_CONTENT
1520 cur->content = xmlStrdup(content);
1521#else
1522 cur->content = xmlBufferCreateSize(0);
1523 xmlBufferSetAllocationScheme(cur->content,
1524 xmlGetBufferAllocationScheme());
1525 xmlBufferAdd(cur->content, content, -1);
1526#endif
1527 }
1528 return(cur);
1529}
1530
1531/**
1532 * xmlNewTextChild:
1533 * @parent: the parent node
1534 * @ns: a namespace if any
1535 * @name: the name of the child
1536 * @content: the text content of the child if any.
1537 *
1538 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001539 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001540 * a child TEXT node will be created containing the string content.
1541 *
1542 * Returns a pointer to the new node object.
1543 */
1544xmlNodePtr
1545xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1546 const xmlChar *name, const xmlChar *content) {
1547 xmlNodePtr cur, prev;
1548
1549 if (parent == NULL) {
1550#ifdef DEBUG_TREE
1551 xmlGenericError(xmlGenericErrorContext,
1552 "xmlNewTextChild : parent == NULL\n");
1553#endif
1554 return(NULL);
1555 }
1556
1557 if (name == NULL) {
1558#ifdef DEBUG_TREE
1559 xmlGenericError(xmlGenericErrorContext,
1560 "xmlNewTextChild : name == NULL\n");
1561#endif
1562 return(NULL);
1563 }
1564
1565 /*
1566 * Allocate a new node
1567 */
1568 if (ns == NULL)
1569 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1570 else
1571 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1572 if (cur == NULL) return(NULL);
1573
1574 /*
1575 * add the new element at the end of the children list.
1576 */
1577 cur->type = XML_ELEMENT_NODE;
1578 cur->parent = parent;
1579 cur->doc = parent->doc;
1580 if (parent->children == NULL) {
1581 parent->children = cur;
1582 parent->last = cur;
1583 } else {
1584 prev = parent->last;
1585 prev->next = cur;
1586 cur->prev = prev;
1587 parent->last = cur;
1588 }
1589
1590 return(cur);
1591}
1592
1593/**
1594 * xmlNewCharRef:
1595 * @doc: the document
1596 * @name: the char ref string, starting with # or "&# ... ;"
1597 *
1598 * Creation of a new character reference node.
1599 * Returns a pointer to the new node object.
1600 */
1601xmlNodePtr
1602xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1603 xmlNodePtr cur;
1604
1605 /*
1606 * Allocate a new node and fill the fields.
1607 */
1608 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1609 if (cur == NULL) {
1610 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001611 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001612 return(NULL);
1613 }
1614 memset(cur, 0, sizeof(xmlNode));
1615 cur->type = XML_ENTITY_REF_NODE;
1616
1617 cur->doc = doc;
1618 if (name[0] == '&') {
1619 int len;
1620 name++;
1621 len = xmlStrlen(name);
1622 if (name[len - 1] == ';')
1623 cur->name = xmlStrndup(name, len - 1);
1624 else
1625 cur->name = xmlStrndup(name, len);
1626 } else
1627 cur->name = xmlStrdup(name);
1628 return(cur);
1629}
1630
1631/**
1632 * xmlNewReference:
1633 * @doc: the document
1634 * @name: the reference name, or the reference string with & and ;
1635 *
1636 * Creation of a new reference node.
1637 * Returns a pointer to the new node object.
1638 */
1639xmlNodePtr
1640xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1641 xmlNodePtr cur;
1642 xmlEntityPtr ent;
1643
1644 /*
1645 * Allocate a new node and fill the fields.
1646 */
1647 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1648 if (cur == NULL) {
1649 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001650 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001651 return(NULL);
1652 }
1653 memset(cur, 0, sizeof(xmlNode));
1654 cur->type = XML_ENTITY_REF_NODE;
1655
1656 cur->doc = doc;
1657 if (name[0] == '&') {
1658 int len;
1659 name++;
1660 len = xmlStrlen(name);
1661 if (name[len - 1] == ';')
1662 cur->name = xmlStrndup(name, len - 1);
1663 else
1664 cur->name = xmlStrndup(name, len);
1665 } else
1666 cur->name = xmlStrdup(name);
1667
1668 ent = xmlGetDocEntity(doc, cur->name);
1669 if (ent != NULL) {
1670#ifndef XML_USE_BUFFER_CONTENT
1671 cur->content = ent->content;
1672#else
1673 /*
1674 * CJN 11.18.99 this might be a problem, since the xmlBuffer gets
1675 * a copy of this pointer. Let's hope we don't manipulate it
1676 * later
1677 */
1678 cur->content = xmlBufferCreateSize(0);
1679 xmlBufferSetAllocationScheme(cur->content,
1680 xmlGetBufferAllocationScheme());
1681 if (ent->content != NULL)
1682 xmlBufferAdd(cur->content, ent->content, -1);
1683#endif
1684 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001685 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00001686 * updated. Not sure if this is 100% correct.
1687 * -George
1688 */
1689 cur->children = (xmlNodePtr) ent;
1690 cur->last = (xmlNodePtr) ent;
1691 }
1692 return(cur);
1693}
1694
1695/**
1696 * xmlNewDocText:
1697 * @doc: the document
1698 * @content: the text content
1699 *
1700 * Creation of a new text node within a document.
1701 * Returns a pointer to the new node object.
1702 */
1703xmlNodePtr
1704xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1705 xmlNodePtr cur;
1706
1707 cur = xmlNewText(content);
1708 if (cur != NULL) cur->doc = doc;
1709 return(cur);
1710}
1711
1712/**
1713 * xmlNewTextLen:
1714 * @content: the text content
1715 * @len: the text len.
1716 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001717 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00001718 * Returns a pointer to the new node object.
1719 */
1720xmlNodePtr
1721xmlNewTextLen(const xmlChar *content, int len) {
1722 xmlNodePtr cur;
1723
1724 /*
1725 * Allocate a new node and fill the fields.
1726 */
1727 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1728 if (cur == NULL) {
1729 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001730 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001731 return(NULL);
1732 }
1733 memset(cur, 0, sizeof(xmlNode));
1734 cur->type = XML_TEXT_NODE;
1735
1736 cur->name = xmlStringText;
1737 if (content != NULL) {
1738#ifndef XML_USE_BUFFER_CONTENT
1739 cur->content = xmlStrndup(content, len);
1740#else
1741 cur->content = xmlBufferCreateSize(len);
1742 xmlBufferSetAllocationScheme(cur->content,
1743 xmlGetBufferAllocationScheme());
1744 xmlBufferAdd(cur->content, content, len);
1745#endif
1746 }
1747 return(cur);
1748}
1749
1750/**
1751 * xmlNewDocTextLen:
1752 * @doc: the document
1753 * @content: the text content
1754 * @len: the text len.
1755 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001756 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00001757 * text node pertain to a given document.
1758 * Returns a pointer to the new node object.
1759 */
1760xmlNodePtr
1761xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1762 xmlNodePtr cur;
1763
1764 cur = xmlNewTextLen(content, len);
1765 if (cur != NULL) cur->doc = doc;
1766 return(cur);
1767}
1768
1769/**
1770 * xmlNewComment:
1771 * @content: the comment content
1772 *
1773 * Creation of a new node containing a comment.
1774 * Returns a pointer to the new node object.
1775 */
1776xmlNodePtr
1777xmlNewComment(const xmlChar *content) {
1778 xmlNodePtr cur;
1779
1780 /*
1781 * Allocate a new node and fill the fields.
1782 */
1783 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1784 if (cur == NULL) {
1785 xmlGenericError(xmlGenericErrorContext,
1786 "xmlNewComment : malloc failed\n");
1787 return(NULL);
1788 }
1789 memset(cur, 0, sizeof(xmlNode));
1790 cur->type = XML_COMMENT_NODE;
1791
1792 cur->name = xmlStringComment;
1793 if (content != NULL) {
1794#ifndef XML_USE_BUFFER_CONTENT
1795 cur->content = xmlStrdup(content);
1796#else
1797 cur->content = xmlBufferCreateSize(0);
1798 xmlBufferSetAllocationScheme(cur->content,
1799 xmlGetBufferAllocationScheme());
1800 xmlBufferAdd(cur->content, content, -1);
1801#endif
1802 }
1803 return(cur);
1804}
1805
1806/**
1807 * xmlNewCDataBlock:
1808 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00001809 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00001810 * @len: the length of the block
1811 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001812 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00001813 * Returns a pointer to the new node object.
1814 */
1815xmlNodePtr
1816xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1817 xmlNodePtr cur;
1818
1819 /*
1820 * Allocate a new node and fill the fields.
1821 */
1822 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1823 if (cur == NULL) {
1824 xmlGenericError(xmlGenericErrorContext,
1825 "xmlNewCDataBlock : malloc failed\n");
1826 return(NULL);
1827 }
1828 memset(cur, 0, sizeof(xmlNode));
1829 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001830 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001831
1832 if (content != NULL) {
1833#ifndef XML_USE_BUFFER_CONTENT
1834 cur->content = xmlStrndup(content, len);
1835#else
1836 cur->content = xmlBufferCreateSize(len);
1837 xmlBufferSetAllocationScheme(cur->content,
1838 xmlGetBufferAllocationScheme());
1839 xmlBufferAdd(cur->content, content, len);
1840#endif
1841 }
1842 return(cur);
1843}
1844
1845/**
1846 * xmlNewDocComment:
1847 * @doc: the document
1848 * @content: the comment content
1849 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001850 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00001851 * Returns a pointer to the new node object.
1852 */
1853xmlNodePtr
1854xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1855 xmlNodePtr cur;
1856
1857 cur = xmlNewComment(content);
1858 if (cur != NULL) cur->doc = doc;
1859 return(cur);
1860}
1861
1862/**
1863 * xmlSetTreeDoc:
1864 * @tree: the top element
1865 * @doc: the document
1866 *
1867 * update all nodes under the tree to point to the right document
1868 */
1869void
1870xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00001871 xmlAttrPtr prop;
1872
Owen Taylor3473f882001-02-23 17:55:21 +00001873 if (tree == NULL)
1874 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001875 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00001876 if(tree->type == XML_ELEMENT_NODE) {
1877 prop = tree->properties;
1878 while (prop != NULL) {
1879 prop->doc = doc;
1880 xmlSetListDoc(prop->children, doc);
1881 prop = prop->next;
1882 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00001883 }
Owen Taylor3473f882001-02-23 17:55:21 +00001884 if (tree->children != NULL)
1885 xmlSetListDoc(tree->children, doc);
1886 tree->doc = doc;
1887 }
1888}
1889
1890/**
1891 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00001892 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00001893 * @doc: the document
1894 *
1895 * update all nodes in the list to point to the right document
1896 */
1897void
1898xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
1899 xmlNodePtr cur;
1900
1901 if (list == NULL)
1902 return;
1903 cur = list;
1904 while (cur != NULL) {
1905 if (cur->doc != doc)
1906 xmlSetTreeDoc(cur, doc);
1907 cur = cur->next;
1908 }
1909}
1910
1911
1912/**
1913 * xmlNewChild:
1914 * @parent: the parent node
1915 * @ns: a namespace if any
1916 * @name: the name of the child
1917 * @content: the XML content of the child if any.
1918 *
1919 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001920 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001921 * a child list containing the TEXTs and ENTITY_REFs node will be created.
1922 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1923 * references, but XML special chars need to be escaped first by using
1924 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
1925 * support is not needed.
1926 *
1927 * Returns a pointer to the new node object.
1928 */
1929xmlNodePtr
1930xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
1931 const xmlChar *name, const xmlChar *content) {
1932 xmlNodePtr cur, prev;
1933
1934 if (parent == NULL) {
1935#ifdef DEBUG_TREE
1936 xmlGenericError(xmlGenericErrorContext,
1937 "xmlNewChild : parent == NULL\n");
1938#endif
1939 return(NULL);
1940 }
1941
1942 if (name == NULL) {
1943#ifdef DEBUG_TREE
1944 xmlGenericError(xmlGenericErrorContext,
1945 "xmlNewChild : name == NULL\n");
1946#endif
1947 return(NULL);
1948 }
1949
1950 /*
1951 * Allocate a new node
1952 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00001953 if (parent->type == XML_ELEMENT_NODE) {
1954 if (ns == NULL)
1955 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
1956 else
1957 cur = xmlNewDocNode(parent->doc, ns, name, content);
1958 } else if ((parent->type == XML_DOCUMENT_NODE) ||
1959 (parent->type == XML_HTML_DOCUMENT_NODE)) {
1960 if (ns == NULL)
1961 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
1962 else
1963 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
1964 } else {
1965 return(NULL);
1966 }
Owen Taylor3473f882001-02-23 17:55:21 +00001967 if (cur == NULL) return(NULL);
1968
1969 /*
1970 * add the new element at the end of the children list.
1971 */
1972 cur->type = XML_ELEMENT_NODE;
1973 cur->parent = parent;
1974 cur->doc = parent->doc;
1975 if (parent->children == NULL) {
1976 parent->children = cur;
1977 parent->last = cur;
1978 } else {
1979 prev = parent->last;
1980 prev->next = cur;
1981 cur->prev = prev;
1982 parent->last = cur;
1983 }
1984
1985 return(cur);
1986}
1987
1988/**
1989 * xmlAddNextSibling:
1990 * @cur: the child node
1991 * @elem: the new node
1992 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001993 * Add a new node @elem as the next sibling of @cur
1994 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00001995 * first unlinked from its existing context.
1996 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001997 * If the new node is ATTRIBUTE, it is added into properties instead of children.
1998 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00001999 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002000 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002001 */
2002xmlNodePtr
2003xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2004 if (cur == NULL) {
2005#ifdef DEBUG_TREE
2006 xmlGenericError(xmlGenericErrorContext,
2007 "xmlAddNextSibling : cur == NULL\n");
2008#endif
2009 return(NULL);
2010 }
2011 if (elem == NULL) {
2012#ifdef DEBUG_TREE
2013 xmlGenericError(xmlGenericErrorContext,
2014 "xmlAddNextSibling : elem == NULL\n");
2015#endif
2016 return(NULL);
2017 }
2018
2019 xmlUnlinkNode(elem);
2020
2021 if (elem->type == XML_TEXT_NODE) {
2022 if (cur->type == XML_TEXT_NODE) {
2023#ifndef XML_USE_BUFFER_CONTENT
2024 xmlNodeAddContent(cur, elem->content);
2025#else
2026 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
2027#endif
2028 xmlFreeNode(elem);
2029 return(cur);
2030 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002031 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2032 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002033#ifndef XML_USE_BUFFER_CONTENT
2034 xmlChar *tmp;
2035
2036 tmp = xmlStrdup(elem->content);
2037 tmp = xmlStrcat(tmp, cur->next->content);
2038 xmlNodeSetContent(cur->next, tmp);
2039 xmlFree(tmp);
2040#else
2041 xmlBufferAddHead(cur->next->content,
2042 xmlBufferContent(elem->content),
2043 xmlBufferLength(elem->content));
2044#endif
2045 xmlFreeNode(elem);
2046 return(cur->next);
2047 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002048 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2049 /* check if an attribute with the same name exists */
2050 xmlAttrPtr attr;
2051
2052 if (elem->ns == NULL)
2053 attr = xmlHasProp(cur->parent, elem->name);
2054 else
2055 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2056 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2057 /* different instance, destroy it (attributes must be unique) */
2058 xmlFreeProp(attr);
2059 }
Owen Taylor3473f882001-02-23 17:55:21 +00002060 }
2061
2062 if (elem->doc != cur->doc) {
2063 xmlSetTreeDoc(elem, cur->doc);
2064 }
2065 elem->parent = cur->parent;
2066 elem->prev = cur;
2067 elem->next = cur->next;
2068 cur->next = elem;
2069 if (elem->next != NULL)
2070 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002071 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002072 elem->parent->last = elem;
2073 return(elem);
2074}
2075
2076/**
2077 * xmlAddPrevSibling:
2078 * @cur: the child node
2079 * @elem: the new node
2080 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002081 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002082 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002083 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002084 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002085 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2086 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002087 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002088 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002089 */
2090xmlNodePtr
2091xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2092 if (cur == NULL) {
2093#ifdef DEBUG_TREE
2094 xmlGenericError(xmlGenericErrorContext,
2095 "xmlAddPrevSibling : cur == NULL\n");
2096#endif
2097 return(NULL);
2098 }
2099 if (elem == NULL) {
2100#ifdef DEBUG_TREE
2101 xmlGenericError(xmlGenericErrorContext,
2102 "xmlAddPrevSibling : elem == NULL\n");
2103#endif
2104 return(NULL);
2105 }
2106
2107 xmlUnlinkNode(elem);
2108
2109 if (elem->type == XML_TEXT_NODE) {
2110 if (cur->type == XML_TEXT_NODE) {
2111#ifndef XML_USE_BUFFER_CONTENT
2112 xmlChar *tmp;
2113
2114 tmp = xmlStrdup(elem->content);
2115 tmp = xmlStrcat(tmp, cur->content);
2116 xmlNodeSetContent(cur, tmp);
2117 xmlFree(tmp);
2118#else
2119 xmlBufferAddHead(cur->content, xmlBufferContent(elem->content),
2120 xmlBufferLength(elem->content));
2121#endif
2122 xmlFreeNode(elem);
2123 return(cur);
2124 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002125 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2126 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002127#ifndef XML_USE_BUFFER_CONTENT
2128 xmlNodeAddContent(cur->prev, elem->content);
2129#else
2130 xmlNodeAddContent(cur->prev, xmlBufferContent(elem->content));
2131#endif
2132 xmlFreeNode(elem);
2133 return(cur->prev);
2134 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002135 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2136 /* check if an attribute with the same name exists */
2137 xmlAttrPtr attr;
2138
2139 if (elem->ns == NULL)
2140 attr = xmlHasProp(cur->parent, elem->name);
2141 else
2142 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2143 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2144 /* different instance, destroy it (attributes must be unique) */
2145 xmlFreeProp(attr);
2146 }
Owen Taylor3473f882001-02-23 17:55:21 +00002147 }
2148
2149 if (elem->doc != cur->doc) {
2150 xmlSetTreeDoc(elem, cur->doc);
2151 }
2152 elem->parent = cur->parent;
2153 elem->next = cur;
2154 elem->prev = cur->prev;
2155 cur->prev = elem;
2156 if (elem->prev != NULL)
2157 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002158 if (elem->parent != NULL) {
2159 if (elem->type == XML_ATTRIBUTE_NODE) {
2160 if (elem->parent->properties == (xmlAttrPtr) cur) {
2161 elem->parent->properties = (xmlAttrPtr) elem;
2162 }
2163 } else {
2164 if (elem->parent->children == cur) {
2165 elem->parent->children = elem;
2166 }
2167 }
2168 }
Owen Taylor3473f882001-02-23 17:55:21 +00002169 return(elem);
2170}
2171
2172/**
2173 * xmlAddSibling:
2174 * @cur: the child node
2175 * @elem: the new node
2176 *
2177 * Add a new element @elem to the list of siblings of @cur
2178 * merging adjacent TEXT nodes (@elem may be freed)
2179 * If the new element was already inserted in a document it is
2180 * first unlinked from its existing context.
2181 *
2182 * Returns the new element or NULL in case of error.
2183 */
2184xmlNodePtr
2185xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2186 xmlNodePtr parent;
2187
2188 if (cur == NULL) {
2189#ifdef DEBUG_TREE
2190 xmlGenericError(xmlGenericErrorContext,
2191 "xmlAddSibling : cur == NULL\n");
2192#endif
2193 return(NULL);
2194 }
2195
2196 if (elem == NULL) {
2197#ifdef DEBUG_TREE
2198 xmlGenericError(xmlGenericErrorContext,
2199 "xmlAddSibling : elem == NULL\n");
2200#endif
2201 return(NULL);
2202 }
2203
2204 /*
2205 * Constant time is we can rely on the ->parent->last to find
2206 * the last sibling.
2207 */
2208 if ((cur->parent != NULL) &&
2209 (cur->parent->children != NULL) &&
2210 (cur->parent->last != NULL) &&
2211 (cur->parent->last->next == NULL)) {
2212 cur = cur->parent->last;
2213 } else {
2214 while (cur->next != NULL) cur = cur->next;
2215 }
2216
2217 xmlUnlinkNode(elem);
2218
2219 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
2220#ifndef XML_USE_BUFFER_CONTENT
2221 xmlNodeAddContent(cur, elem->content);
2222#else
2223 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
2224#endif
2225 xmlFreeNode(elem);
2226 return(cur);
2227 }
2228
2229 if (elem->doc != cur->doc) {
2230 xmlSetTreeDoc(elem, cur->doc);
2231 }
2232 parent = cur->parent;
2233 elem->prev = cur;
2234 elem->next = NULL;
2235 elem->parent = parent;
2236 cur->next = elem;
2237 if (parent != NULL)
2238 parent->last = elem;
2239
2240 return(elem);
2241}
2242
2243/**
2244 * xmlAddChildList:
2245 * @parent: the parent node
2246 * @cur: the first node in the list
2247 *
2248 * Add a list of node at the end of the child list of the parent
2249 * merging adjacent TEXT nodes (@cur may be freed)
2250 *
2251 * Returns the last child or NULL in case of error.
2252 */
2253xmlNodePtr
2254xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2255 xmlNodePtr prev;
2256
2257 if (parent == NULL) {
2258#ifdef DEBUG_TREE
2259 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002260 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002261#endif
2262 return(NULL);
2263 }
2264
2265 if (cur == NULL) {
2266#ifdef DEBUG_TREE
2267 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002268 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002269#endif
2270 return(NULL);
2271 }
2272
2273 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2274 (cur->doc != parent->doc)) {
2275#ifdef DEBUG_TREE
2276 xmlGenericError(xmlGenericErrorContext,
2277 "Elements moved to a different document\n");
2278#endif
2279 }
2280
2281 /*
2282 * add the first element at the end of the children list.
2283 */
2284 if (parent->children == NULL) {
2285 parent->children = cur;
2286 } else {
2287 /*
2288 * If cur and parent->last both are TEXT nodes, then merge them.
2289 */
2290 if ((cur->type == XML_TEXT_NODE) &&
2291 (parent->last->type == XML_TEXT_NODE) &&
2292 (cur->name == parent->last->name)) {
2293#ifndef XML_USE_BUFFER_CONTENT
2294 xmlNodeAddContent(parent->last, cur->content);
2295#else
2296 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2297#endif
2298 /*
2299 * if it's the only child, nothing more to be done.
2300 */
2301 if (cur->next == NULL) {
2302 xmlFreeNode(cur);
2303 return(parent->last);
2304 }
2305 prev = cur;
2306 cur = cur->next;
2307 xmlFreeNode(prev);
2308 }
2309 prev = parent->last;
2310 prev->next = cur;
2311 cur->prev = prev;
2312 }
2313 while (cur->next != NULL) {
2314 cur->parent = parent;
2315 if (cur->doc != parent->doc) {
2316 xmlSetTreeDoc(cur, parent->doc);
2317 }
2318 cur = cur->next;
2319 }
2320 cur->parent = parent;
2321 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2322 parent->last = cur;
2323
2324 return(cur);
2325}
2326
2327/**
2328 * xmlAddChild:
2329 * @parent: the parent node
2330 * @cur: the child node
2331 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002332 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002333 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002334 * If the new node was already inserted in a document it is
2335 * first unlinked from its existing context.
2336 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2337 * If there is an attribute with equal name, it is first destroyed.
2338 *
Owen Taylor3473f882001-02-23 17:55:21 +00002339 * Returns the child or NULL in case of error.
2340 */
2341xmlNodePtr
2342xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2343 xmlNodePtr prev;
2344
2345 if (parent == NULL) {
2346#ifdef DEBUG_TREE
2347 xmlGenericError(xmlGenericErrorContext,
2348 "xmlAddChild : parent == NULL\n");
2349#endif
2350 return(NULL);
2351 }
2352
2353 if (cur == NULL) {
2354#ifdef DEBUG_TREE
2355 xmlGenericError(xmlGenericErrorContext,
2356 "xmlAddChild : child == NULL\n");
2357#endif
2358 return(NULL);
2359 }
2360
Owen Taylor3473f882001-02-23 17:55:21 +00002361 /*
2362 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002363 * cur is then freed.
2364 */
2365 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002366 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002367 (parent->content != NULL)) {
2368#ifndef XML_USE_BUFFER_CONTENT
2369 xmlNodeAddContent(parent, cur->content);
2370#else
2371 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
2372#endif
2373 xmlFreeNode(cur);
2374 return(parent);
2375 }
2376 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2377 (parent->last->name == cur->name)) {
2378#ifndef XML_USE_BUFFER_CONTENT
2379 xmlNodeAddContent(parent->last, cur->content);
2380#else
2381 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2382#endif
2383 xmlFreeNode(cur);
2384 return(parent->last);
2385 }
2386 }
2387
2388 /*
2389 * add the new element at the end of the children list.
2390 */
2391 cur->parent = parent;
2392 if (cur->doc != parent->doc) {
2393 xmlSetTreeDoc(cur, parent->doc);
2394 }
2395
2396 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002397 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002398 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002399 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002400 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002401#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard7db37732001-07-12 01:20:08 +00002402 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002403#else
Daniel Veillard7db37732001-07-12 01:20:08 +00002404 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00002405#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002406 xmlFreeNode(cur);
2407 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002408 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002409 if (cur->type == XML_ATTRIBUTE_NODE) {
2410 if (parent->properties == NULL) {
2411 parent->properties = (xmlAttrPtr) cur;
2412 } else {
2413 /* check if an attribute with the same name exists */
2414 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002415
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002416 if (cur->ns == NULL)
2417 lastattr = xmlHasProp(parent, cur->name);
2418 else
2419 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2420 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2421 /* different instance, destroy it (attributes must be unique) */
2422 xmlFreeProp(lastattr);
2423 }
2424 /* find the end */
2425 lastattr = parent->properties;
2426 while (lastattr->next != NULL) {
2427 lastattr = lastattr->next;
2428 }
2429 lastattr->next = (xmlAttrPtr) cur;
2430 ((xmlAttrPtr) cur)->prev = lastattr;
2431 }
2432 } else {
2433 if (parent->children == NULL) {
2434 parent->children = cur;
2435 parent->last = cur;
2436 } else {
2437 prev = parent->last;
2438 prev->next = cur;
2439 cur->prev = prev;
2440 parent->last = cur;
2441 }
2442 }
Owen Taylor3473f882001-02-23 17:55:21 +00002443 return(cur);
2444}
2445
2446/**
2447 * xmlGetLastChild:
2448 * @parent: the parent node
2449 *
2450 * Search the last child of a node.
2451 * Returns the last child or NULL if none.
2452 */
2453xmlNodePtr
2454xmlGetLastChild(xmlNodePtr parent) {
2455 if (parent == NULL) {
2456#ifdef DEBUG_TREE
2457 xmlGenericError(xmlGenericErrorContext,
2458 "xmlGetLastChild : parent == NULL\n");
2459#endif
2460 return(NULL);
2461 }
2462 return(parent->last);
2463}
2464
2465/**
2466 * xmlFreeNodeList:
2467 * @cur: the first node in the list
2468 *
2469 * Free a node and all its siblings, this is a recursive behaviour, all
2470 * the children are freed too.
2471 */
2472void
2473xmlFreeNodeList(xmlNodePtr cur) {
2474 xmlNodePtr next;
2475 if (cur == NULL) {
2476#ifdef DEBUG_TREE
2477 xmlGenericError(xmlGenericErrorContext,
2478 "xmlFreeNodeList : node == NULL\n");
2479#endif
2480 return;
2481 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002482 if (cur->type == XML_NAMESPACE_DECL) {
2483 xmlFreeNsList((xmlNsPtr) cur);
2484 return;
2485 }
Owen Taylor3473f882001-02-23 17:55:21 +00002486 while (cur != NULL) {
2487 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002488 /* unroll to speed up freeing the document */
2489 if (cur->type != XML_DTD_NODE) {
2490 if ((cur->children != NULL) &&
2491 (cur->type != XML_ENTITY_REF_NODE))
2492 xmlFreeNodeList(cur->children);
2493 if (cur->properties != NULL)
2494 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002495 if ((cur->type != XML_ELEMENT_NODE) &&
2496 (cur->type != XML_XINCLUDE_START) &&
2497 (cur->type != XML_XINCLUDE_END) &&
2498 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002499#ifndef XML_USE_BUFFER_CONTENT
2500 if (cur->content != NULL) xmlFree(cur->content);
2501#else
2502 if (cur->content != NULL) xmlBufferFree(cur->content);
2503#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002504 }
2505 if (((cur->type == XML_ELEMENT_NODE) ||
2506 (cur->type == XML_XINCLUDE_START) ||
2507 (cur->type == XML_XINCLUDE_END)) &&
2508 (cur->nsDef != NULL))
2509 xmlFreeNsList(cur->nsDef);
2510
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002511 /*
2512 * When a node is a text node or a comment, it uses a global static
2513 * variable for the name of the node.
2514 *
2515 * The xmlStrEqual comparisons need to be done when (happened with
2516 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002517 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002518 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002519 * the string addresses compare are not sufficient.
2520 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002521 if ((cur->name != NULL) &&
2522 (cur->name != xmlStringText) &&
2523 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002524 (cur->name != xmlStringComment)) {
2525 if (cur->type == XML_TEXT_NODE) {
2526 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2527 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2528 xmlFree((char *) cur->name);
2529 } else if (cur->type == XML_COMMENT_NODE) {
2530 if (!xmlStrEqual(cur->name, xmlStringComment))
2531 xmlFree((char *) cur->name);
2532 } else
2533 xmlFree((char *) cur->name);
2534 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002535 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002536 xmlFree(cur);
2537 }
Owen Taylor3473f882001-02-23 17:55:21 +00002538 cur = next;
2539 }
2540}
2541
2542/**
2543 * xmlFreeNode:
2544 * @cur: the node
2545 *
2546 * Free a node, this is a recursive behaviour, all the children are freed too.
2547 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2548 */
2549void
2550xmlFreeNode(xmlNodePtr cur) {
2551 if (cur == NULL) {
2552#ifdef DEBUG_TREE
2553 xmlGenericError(xmlGenericErrorContext,
2554 "xmlFreeNode : node == NULL\n");
2555#endif
2556 return;
2557 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002558 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002559 if (cur->type == XML_DTD_NODE) {
2560 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002561 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002562 }
2563 if (cur->type == XML_NAMESPACE_DECL) {
2564 xmlFreeNs((xmlNsPtr) cur);
2565 return;
2566 }
Owen Taylor3473f882001-02-23 17:55:21 +00002567 if ((cur->children != NULL) &&
2568 (cur->type != XML_ENTITY_REF_NODE))
2569 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002570 if (cur->properties != NULL)
2571 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002572 if ((cur->type != XML_ELEMENT_NODE) &&
2573 (cur->content != NULL) &&
2574 (cur->type != XML_ENTITY_REF_NODE) &&
2575 (cur->type != XML_XINCLUDE_END) &&
2576 (cur->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002577#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard7db37732001-07-12 01:20:08 +00002578 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002579#else
Daniel Veillard7db37732001-07-12 01:20:08 +00002580 xmlBufferFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002581#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002582 }
2583
Daniel Veillardacd370f2001-06-09 17:17:51 +00002584 /*
2585 * When a node is a text node or a comment, it uses a global static
2586 * variable for the name of the node.
2587 *
2588 * The xmlStrEqual comparisons need to be done when (happened with
2589 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002590 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002591 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002592 * are not sufficient.
2593 */
Owen Taylor3473f882001-02-23 17:55:21 +00002594 if ((cur->name != NULL) &&
2595 (cur->name != xmlStringText) &&
2596 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002597 (cur->name != xmlStringComment)) {
2598 if (cur->type == XML_TEXT_NODE) {
2599 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2600 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2601 xmlFree((char *) cur->name);
2602 } else if (cur->type == XML_COMMENT_NODE) {
2603 if (!xmlStrEqual(cur->name, xmlStringComment))
2604 xmlFree((char *) cur->name);
2605 } else
2606 xmlFree((char *) cur->name);
2607 }
2608
Owen Taylor3473f882001-02-23 17:55:21 +00002609 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002610 xmlFree(cur);
2611}
2612
2613/**
2614 * xmlUnlinkNode:
2615 * @cur: the node
2616 *
2617 * Unlink a node from it's current context, the node is not freed
2618 */
2619void
2620xmlUnlinkNode(xmlNodePtr cur) {
2621 if (cur == NULL) {
2622#ifdef DEBUG_TREE
2623 xmlGenericError(xmlGenericErrorContext,
2624 "xmlUnlinkNode : node == NULL\n");
2625#endif
2626 return;
2627 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002628 if (cur->type == XML_DTD_NODE) {
2629 xmlDocPtr doc;
2630 doc = cur->doc;
2631 if (doc->intSubset == (xmlDtdPtr) cur)
2632 doc->intSubset = NULL;
2633 if (doc->extSubset == (xmlDtdPtr) cur)
2634 doc->extSubset = NULL;
2635 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002636 if (cur->parent != NULL) {
2637 xmlNodePtr parent;
2638 parent = cur->parent;
2639 if (cur->type == XML_ATTRIBUTE_NODE) {
2640 if (parent->properties == (xmlAttrPtr) cur)
2641 parent->properties = ((xmlAttrPtr) cur)->next;
2642 } else {
2643 if (parent->children == cur)
2644 parent->children = cur->next;
2645 if (parent->last == cur)
2646 parent->last = cur->prev;
2647 }
2648 cur->parent = NULL;
2649 }
Owen Taylor3473f882001-02-23 17:55:21 +00002650 if (cur->next != NULL)
2651 cur->next->prev = cur->prev;
2652 if (cur->prev != NULL)
2653 cur->prev->next = cur->next;
2654 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002655}
2656
2657/**
2658 * xmlReplaceNode:
2659 * @old: the old node
2660 * @cur: the node
2661 *
2662 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002663 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002664 * first unlinked from its existing context.
2665 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002666 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002667 */
2668xmlNodePtr
2669xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2670 if (old == NULL) {
2671#ifdef DEBUG_TREE
2672 xmlGenericError(xmlGenericErrorContext,
2673 "xmlReplaceNode : old == NULL\n");
2674#endif
2675 return(NULL);
2676 }
2677 if (cur == NULL) {
2678 xmlUnlinkNode(old);
2679 return(old);
2680 }
2681 if (cur == old) {
2682 return(old);
2683 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002684 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2685#ifdef DEBUG_TREE
2686 xmlGenericError(xmlGenericErrorContext,
2687 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2688#endif
2689 return(old);
2690 }
2691 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2692#ifdef DEBUG_TREE
2693 xmlGenericError(xmlGenericErrorContext,
2694 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2695#endif
2696 return(old);
2697 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002698 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2699#ifdef DEBUG_TREE
2700 xmlGenericError(xmlGenericErrorContext,
2701 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2702#endif
2703 return(old);
2704 }
2705 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2706#ifdef DEBUG_TREE
2707 xmlGenericError(xmlGenericErrorContext,
2708 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2709#endif
2710 return(old);
2711 }
Owen Taylor3473f882001-02-23 17:55:21 +00002712 xmlUnlinkNode(cur);
2713 cur->doc = old->doc;
2714 cur->parent = old->parent;
2715 cur->next = old->next;
2716 if (cur->next != NULL)
2717 cur->next->prev = cur;
2718 cur->prev = old->prev;
2719 if (cur->prev != NULL)
2720 cur->prev->next = cur;
2721 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002722 if (cur->type == XML_ATTRIBUTE_NODE) {
2723 if (cur->parent->properties == (xmlAttrPtr)old)
2724 cur->parent->properties = ((xmlAttrPtr) cur);
2725 } else {
2726 if (cur->parent->children == old)
2727 cur->parent->children = cur;
2728 if (cur->parent->last == old)
2729 cur->parent->last = cur;
2730 }
Owen Taylor3473f882001-02-23 17:55:21 +00002731 }
2732 old->next = old->prev = NULL;
2733 old->parent = NULL;
2734 return(old);
2735}
2736
2737/************************************************************************
2738 * *
2739 * Copy operations *
2740 * *
2741 ************************************************************************/
2742
2743/**
2744 * xmlCopyNamespace:
2745 * @cur: the namespace
2746 *
2747 * Do a copy of the namespace.
2748 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002749 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002750 */
2751xmlNsPtr
2752xmlCopyNamespace(xmlNsPtr cur) {
2753 xmlNsPtr ret;
2754
2755 if (cur == NULL) return(NULL);
2756 switch (cur->type) {
2757 case XML_LOCAL_NAMESPACE:
2758 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2759 break;
2760 default:
2761#ifdef DEBUG_TREE
2762 xmlGenericError(xmlGenericErrorContext,
2763 "xmlCopyNamespace: invalid type %d\n", cur->type);
2764#endif
2765 return(NULL);
2766 }
2767 return(ret);
2768}
2769
2770/**
2771 * xmlCopyNamespaceList:
2772 * @cur: the first namespace
2773 *
2774 * Do a copy of an namespace list.
2775 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002776 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002777 */
2778xmlNsPtr
2779xmlCopyNamespaceList(xmlNsPtr cur) {
2780 xmlNsPtr ret = NULL;
2781 xmlNsPtr p = NULL,q;
2782
2783 while (cur != NULL) {
2784 q = xmlCopyNamespace(cur);
2785 if (p == NULL) {
2786 ret = p = q;
2787 } else {
2788 p->next = q;
2789 p = q;
2790 }
2791 cur = cur->next;
2792 }
2793 return(ret);
2794}
2795
2796static xmlNodePtr
2797xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2798/**
2799 * xmlCopyProp:
2800 * @target: the element where the attribute will be grafted
2801 * @cur: the attribute
2802 *
2803 * Do a copy of the attribute.
2804 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002805 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002806 */
2807xmlAttrPtr
2808xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2809 xmlAttrPtr ret;
2810
2811 if (cur == NULL) return(NULL);
2812 if (target != NULL)
2813 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2814 else if (cur->parent != NULL)
2815 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2816 else if (cur->children != NULL)
2817 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2818 else
2819 ret = xmlNewDocProp(NULL, cur->name, NULL);
2820 if (ret == NULL) return(NULL);
2821 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002822
Owen Taylor3473f882001-02-23 17:55:21 +00002823 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00002824 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002825/*
2826 * if (target->doc)
2827 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2828 * else if (cur->doc) / * target may not yet have a doc : KPI * /
2829 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
2830 * else
2831 * ns = NULL;
2832 * ret->ns = ns;
2833 */
2834 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2835 if (ns == NULL) {
2836 /*
2837 * Humm, we are copying an element whose namespace is defined
2838 * out of the new tree scope. Search it in the original tree
2839 * and add it at the top of the new tree
2840 */
2841 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
2842 if (ns != NULL) {
2843 xmlNodePtr root = target;
2844 xmlNodePtr pred = NULL;
2845
2846 while (root->parent != NULL) {
2847 pred = root;
2848 root = root->parent;
2849 }
2850 if (root == (xmlNodePtr) target->doc) {
2851 /* correct possibly cycling above the document elt */
2852 root = pred;
2853 }
2854 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
2855 }
2856 } else {
2857 /*
2858 * we have to find something appropriate here since
2859 * we cant be sure, that the namespce we found is identified
2860 * by the prefix
2861 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002862 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002863 /* this is the nice case */
2864 ret->ns = ns;
2865 } else {
2866 /*
2867 * we are in trouble: we need a new reconcilied namespace.
2868 * This is expensive
2869 */
2870 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
2871 }
2872 }
2873
Owen Taylor3473f882001-02-23 17:55:21 +00002874 } else
2875 ret->ns = NULL;
2876
2877 if (cur->children != NULL) {
2878 xmlNodePtr tmp;
2879
2880 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2881 ret->last = NULL;
2882 tmp = ret->children;
2883 while (tmp != NULL) {
2884 /* tmp->parent = (xmlNodePtr)ret; */
2885 if (tmp->next == NULL)
2886 ret->last = tmp;
2887 tmp = tmp->next;
2888 }
2889 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002890 /*
2891 * Try to handle IDs
2892 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00002893 if ((target!= NULL) && (cur!= NULL) &&
2894 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002895 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
2896 if (xmlIsID(cur->doc, cur->parent, cur)) {
2897 xmlChar *id;
2898
2899 id = xmlNodeListGetString(cur->doc, cur->children, 1);
2900 if (id != NULL) {
2901 xmlAddID(NULL, target->doc, id, ret);
2902 xmlFree(id);
2903 }
2904 }
2905 }
Owen Taylor3473f882001-02-23 17:55:21 +00002906 return(ret);
2907}
2908
2909/**
2910 * xmlCopyPropList:
2911 * @target: the element where the attributes will be grafted
2912 * @cur: the first attribute
2913 *
2914 * Do a copy of an attribute list.
2915 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002916 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002917 */
2918xmlAttrPtr
2919xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
2920 xmlAttrPtr ret = NULL;
2921 xmlAttrPtr p = NULL,q;
2922
2923 while (cur != NULL) {
2924 q = xmlCopyProp(target, cur);
2925 if (p == NULL) {
2926 ret = p = q;
2927 } else {
2928 p->next = q;
2929 q->prev = p;
2930 p = q;
2931 }
2932 cur = cur->next;
2933 }
2934 return(ret);
2935}
2936
2937/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002938 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00002939 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002940 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00002941 * tricky reason: namespaces. Doing a direct copy of a node
2942 * say RPM:Copyright without changing the namespace pointer to
2943 * something else can produce stale links. One way to do it is
2944 * to keep a reference counter but this doesn't work as soon
2945 * as one move the element or the subtree out of the scope of
2946 * the existing namespace. The actual solution seems to add
2947 * a copy of the namespace at the top of the copied tree if
2948 * not available in the subtree.
2949 * Hence two functions, the public front-end call the inner ones
2950 */
2951
2952static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002953xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00002954 int recursive) {
2955 xmlNodePtr ret;
2956
2957 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00002958 switch (node->type) {
2959 case XML_TEXT_NODE:
2960 case XML_CDATA_SECTION_NODE:
2961 case XML_ELEMENT_NODE:
2962 case XML_ENTITY_REF_NODE:
2963 case XML_ENTITY_NODE:
2964 case XML_PI_NODE:
2965 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002966 case XML_XINCLUDE_START:
2967 case XML_XINCLUDE_END:
2968 break;
2969 case XML_ATTRIBUTE_NODE:
2970 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
2971 case XML_NAMESPACE_DECL:
2972 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
2973
Daniel Veillard39196eb2001-06-19 18:09:42 +00002974 case XML_DOCUMENT_NODE:
2975 case XML_HTML_DOCUMENT_NODE:
2976#ifdef LIBXML_DOCB_ENABLED
2977 case XML_DOCB_DOCUMENT_NODE:
2978#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002979 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00002980 case XML_DOCUMENT_TYPE_NODE:
2981 case XML_DOCUMENT_FRAG_NODE:
2982 case XML_NOTATION_NODE:
2983 case XML_DTD_NODE:
2984 case XML_ELEMENT_DECL:
2985 case XML_ATTRIBUTE_DECL:
2986 case XML_ENTITY_DECL:
2987 return(NULL);
2988 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002989
Owen Taylor3473f882001-02-23 17:55:21 +00002990 /*
2991 * Allocate a new node and fill the fields.
2992 */
2993 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2994 if (ret == NULL) {
2995 xmlGenericError(xmlGenericErrorContext,
2996 "xmlStaticCopyNode : malloc failed\n");
2997 return(NULL);
2998 }
2999 memset(ret, 0, sizeof(xmlNode));
3000 ret->type = node->type;
3001
3002 ret->doc = doc;
3003 ret->parent = parent;
3004 if (node->name == xmlStringText)
3005 ret->name = xmlStringText;
3006 else if (node->name == xmlStringTextNoenc)
3007 ret->name = xmlStringTextNoenc;
3008 else if (node->name == xmlStringComment)
3009 ret->name = xmlStringComment;
3010 else if (node->name != NULL)
3011 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003012 if ((node->type != XML_ELEMENT_NODE) &&
3013 (node->content != NULL) &&
3014 (node->type != XML_ENTITY_REF_NODE) &&
3015 (node->type != XML_XINCLUDE_END) &&
3016 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003017#ifndef XML_USE_BUFFER_CONTENT
3018 ret->content = xmlStrdup(node->content);
3019#else
3020 ret->content = xmlBufferCreateSize(xmlBufferLength(node->content));
3021 xmlBufferSetAllocationScheme(ret->content,
3022 xmlGetBufferAllocationScheme());
3023 xmlBufferAdd(ret->content,
3024 xmlBufferContent(node->content),
3025 xmlBufferLength(node->content));
3026#endif
Daniel Veillard8107a222002-01-13 14:10:10 +00003027 }else{
3028 if (node->type == XML_ELEMENT_NODE)
3029 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003030 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003031 if (parent != NULL) {
3032 xmlNodePtr tmp;
3033
3034 tmp = xmlAddChild(parent, ret);
3035 /* node could have coalesced */
3036 if (tmp != ret)
3037 return(tmp);
3038 }
Owen Taylor3473f882001-02-23 17:55:21 +00003039
3040 if (!recursive) return(ret);
3041 if (node->nsDef != NULL)
3042 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3043
3044 if (node->ns != NULL) {
3045 xmlNsPtr ns;
3046
3047 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3048 if (ns == NULL) {
3049 /*
3050 * Humm, we are copying an element whose namespace is defined
3051 * out of the new tree scope. Search it in the original tree
3052 * and add it at the top of the new tree
3053 */
3054 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3055 if (ns != NULL) {
3056 xmlNodePtr root = ret;
3057
3058 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003059 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003060 }
3061 } else {
3062 /*
3063 * reference the existing namespace definition in our own tree.
3064 */
3065 ret->ns = ns;
3066 }
3067 }
3068 if (node->properties != NULL)
3069 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003070 if (node->type == XML_ENTITY_REF_NODE) {
3071 if ((doc == NULL) || (node->doc != doc)) {
3072 /*
3073 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003074 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003075 * we cannot keep the reference. Try to find it in the
3076 * target document.
3077 */
3078 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3079 } else {
3080 ret->children = node->children;
3081 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003082 ret->last = ret->children;
3083 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003084 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003085 UPDATE_LAST_CHILD_AND_PARENT(ret)
3086 }
Owen Taylor3473f882001-02-23 17:55:21 +00003087 return(ret);
3088}
3089
3090static xmlNodePtr
3091xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3092 xmlNodePtr ret = NULL;
3093 xmlNodePtr p = NULL,q;
3094
3095 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003096 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003097 if (doc == NULL) {
3098 node = node->next;
3099 continue;
3100 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003101 if (doc->intSubset == NULL) {
3102 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3103 q->doc = doc;
3104 q->parent = parent;
3105 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003106 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003107 } else {
3108 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003109 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003110 }
3111 } else
3112 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003113 if (ret == NULL) {
3114 q->prev = NULL;
3115 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003116 } else if (p != q) {
3117 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003118 p->next = q;
3119 q->prev = p;
3120 p = q;
3121 }
3122 node = node->next;
3123 }
3124 return(ret);
3125}
3126
3127/**
3128 * xmlCopyNode:
3129 * @node: the node
3130 * @recursive: if 1 do a recursive copy.
3131 *
3132 * Do a copy of the node.
3133 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003134 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003135 */
3136xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003137xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003138 xmlNodePtr ret;
3139
3140 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3141 return(ret);
3142}
3143
3144/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003145 * xmlDocCopyNode:
3146 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003147 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003148 * @recursive: if 1 do a recursive copy.
3149 *
3150 * Do a copy of the node to a given document.
3151 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003152 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003153 */
3154xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003155xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003156 xmlNodePtr ret;
3157
3158 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3159 return(ret);
3160}
3161
3162/**
Owen Taylor3473f882001-02-23 17:55:21 +00003163 * xmlCopyNodeList:
3164 * @node: the first node in the list.
3165 *
3166 * Do a recursive copy of the node list.
3167 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003168 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003169 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003170xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003171 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3172 return(ret);
3173}
3174
3175/**
Owen Taylor3473f882001-02-23 17:55:21 +00003176 * xmlCopyDtd:
3177 * @dtd: the dtd
3178 *
3179 * Do a copy of the dtd.
3180 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003181 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003182 */
3183xmlDtdPtr
3184xmlCopyDtd(xmlDtdPtr dtd) {
3185 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003186 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003187
3188 if (dtd == NULL) return(NULL);
3189 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3190 if (ret == NULL) return(NULL);
3191 if (dtd->entities != NULL)
3192 ret->entities = (void *) xmlCopyEntitiesTable(
3193 (xmlEntitiesTablePtr) dtd->entities);
3194 if (dtd->notations != NULL)
3195 ret->notations = (void *) xmlCopyNotationTable(
3196 (xmlNotationTablePtr) dtd->notations);
3197 if (dtd->elements != NULL)
3198 ret->elements = (void *) xmlCopyElementTable(
3199 (xmlElementTablePtr) dtd->elements);
3200 if (dtd->attributes != NULL)
3201 ret->attributes = (void *) xmlCopyAttributeTable(
3202 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003203 if (dtd->pentities != NULL)
3204 ret->pentities = (void *) xmlCopyEntitiesTable(
3205 (xmlEntitiesTablePtr) dtd->pentities);
3206
3207 cur = dtd->children;
3208 while (cur != NULL) {
3209 q = NULL;
3210
3211 if (cur->type == XML_ENTITY_DECL) {
3212 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3213 switch (tmp->etype) {
3214 case XML_INTERNAL_GENERAL_ENTITY:
3215 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3216 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3217 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3218 break;
3219 case XML_INTERNAL_PARAMETER_ENTITY:
3220 case XML_EXTERNAL_PARAMETER_ENTITY:
3221 q = (xmlNodePtr)
3222 xmlGetParameterEntityFromDtd(ret, tmp->name);
3223 break;
3224 case XML_INTERNAL_PREDEFINED_ENTITY:
3225 break;
3226 }
3227 } else if (cur->type == XML_ELEMENT_DECL) {
3228 xmlElementPtr tmp = (xmlElementPtr) cur;
3229 q = (xmlNodePtr)
3230 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3231 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3232 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3233 q = (xmlNodePtr)
3234 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3235 } else if (cur->type == XML_COMMENT_NODE) {
3236 q = xmlCopyNode(cur, 0);
3237 }
3238
3239 if (q == NULL) {
3240 cur = cur->next;
3241 continue;
3242 }
3243
3244 if (p == NULL)
3245 ret->children = q;
3246 else
3247 p->next = q;
3248
3249 q->prev = p;
3250 q->parent = (xmlNodePtr) ret;
3251 q->next = NULL;
3252 ret->last = q;
3253 p = q;
3254 cur = cur->next;
3255 }
3256
Owen Taylor3473f882001-02-23 17:55:21 +00003257 return(ret);
3258}
3259
3260/**
3261 * xmlCopyDoc:
3262 * @doc: the document
3263 * @recursive: if 1 do a recursive copy.
3264 *
3265 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003266 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003267 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003268 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003269 */
3270xmlDocPtr
3271xmlCopyDoc(xmlDocPtr doc, int recursive) {
3272 xmlDocPtr ret;
3273
3274 if (doc == NULL) return(NULL);
3275 ret = xmlNewDoc(doc->version);
3276 if (ret == NULL) return(NULL);
3277 if (doc->name != NULL)
3278 ret->name = xmlMemStrdup(doc->name);
3279 if (doc->encoding != NULL)
3280 ret->encoding = xmlStrdup(doc->encoding);
3281 ret->charset = doc->charset;
3282 ret->compression = doc->compression;
3283 ret->standalone = doc->standalone;
3284 if (!recursive) return(ret);
3285
Daniel Veillardb33c2012001-04-25 12:59:04 +00003286 ret->last = NULL;
3287 ret->children = NULL;
3288 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003289 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003290 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003291 ret->intSubset->parent = ret;
3292 }
Owen Taylor3473f882001-02-23 17:55:21 +00003293 if (doc->oldNs != NULL)
3294 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3295 if (doc->children != NULL) {
3296 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003297
3298 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3299 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003300 ret->last = NULL;
3301 tmp = ret->children;
3302 while (tmp != NULL) {
3303 if (tmp->next == NULL)
3304 ret->last = tmp;
3305 tmp = tmp->next;
3306 }
3307 }
3308 return(ret);
3309}
3310
3311/************************************************************************
3312 * *
3313 * Content access functions *
3314 * *
3315 ************************************************************************/
3316
3317/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003318 * xmlGetLineNo:
3319 * @node : valid node
3320 *
3321 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003322 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003323 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003324 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003325 */
3326long
3327xmlGetLineNo(xmlNodePtr node)
3328{
3329 long result = -1;
3330
3331 if (!node)
3332 return result;
3333 if (node->type == XML_ELEMENT_NODE)
3334 result = (long) node->content;
3335 else if ((node->prev != NULL) &&
3336 ((node->prev->type == XML_ELEMENT_NODE) ||
3337 (node->prev->type == XML_TEXT_NODE)))
3338 result = xmlGetLineNo(node->prev);
3339 else if ((node->parent != NULL) &&
3340 ((node->parent->type == XML_ELEMENT_NODE) ||
3341 (node->parent->type == XML_TEXT_NODE)))
3342 result = xmlGetLineNo(node->parent);
3343
3344 return result;
3345}
3346
3347/**
3348 * xmlGetNodePath:
3349 * @node: a node
3350 *
3351 * Build a structure based Path for the given node
3352 *
3353 * Returns the new path or NULL in case of error. The caller must free
3354 * the returned string
3355 */
3356xmlChar *
3357xmlGetNodePath(xmlNodePtr node)
3358{
3359 xmlNodePtr cur, tmp, next;
3360 xmlChar *buffer = NULL, *temp;
3361 size_t buf_len;
3362 xmlChar *buf;
3363 char sep;
3364 const char *name;
3365 char nametemp[100];
3366 int occur = 0;
3367
3368 if (node == NULL)
3369 return (NULL);
3370
3371 buf_len = 500;
3372 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3373 if (buffer == NULL)
3374 return (NULL);
3375 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3376 if (buf == NULL) {
3377 xmlFree(buffer);
3378 return (NULL);
3379 }
3380
3381 buffer[0] = 0;
3382 cur = node;
3383 do {
3384 name = "";
3385 sep = '?';
3386 occur = 0;
3387 if ((cur->type == XML_DOCUMENT_NODE) ||
3388 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3389 if (buffer[0] == '/')
3390 break;
3391 sep = '/';
3392 next = NULL;
3393 } else if (cur->type == XML_ELEMENT_NODE) {
3394 sep = '/';
3395 name = (const char *) cur->name;
3396 if (cur->ns) {
3397 snprintf(nametemp, sizeof(nametemp) - 1,
3398 "%s:%s", cur->ns->prefix, cur->name);
3399 nametemp[sizeof(nametemp) - 1] = 0;
3400 name = nametemp;
3401 }
3402 next = cur->parent;
3403
3404 /*
3405 * Thumbler index computation
3406 */
3407 tmp = cur->prev;
3408 while (tmp != NULL) {
3409 if (xmlStrEqual(cur->name, tmp->name))
3410 occur++;
3411 tmp = tmp->prev;
3412 }
3413 if (occur == 0) {
3414 tmp = cur->next;
3415 while (tmp != NULL) {
3416 if (xmlStrEqual(cur->name, tmp->name))
3417 occur++;
3418 tmp = tmp->next;
3419 }
3420 if (occur != 0)
3421 occur = 1;
3422 } else
3423 occur++;
3424 } else if (cur->type == XML_ATTRIBUTE_NODE) {
3425 sep = '@';
3426 name = (const char *) (((xmlAttrPtr) cur)->name);
3427 next = ((xmlAttrPtr) cur)->parent;
3428 } else {
3429 next = cur->parent;
3430 }
3431
3432 /*
3433 * Make sure there is enough room
3434 */
3435 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3436 buf_len =
3437 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3438 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3439 if (temp == NULL) {
3440 xmlFree(buf);
3441 xmlFree(buffer);
3442 return (NULL);
3443 }
3444 buffer = temp;
3445 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3446 if (temp == NULL) {
3447 xmlFree(buf);
3448 xmlFree(buffer);
3449 return (NULL);
3450 }
3451 buf = temp;
3452 }
3453 if (occur == 0)
3454 snprintf((char *) buf, buf_len, "%c%s%s",
3455 sep, name, (char *) buffer);
3456 else
3457 snprintf((char *) buf, buf_len, "%c%s[%d]%s",
3458 sep, name, occur, (char *) buffer);
3459 snprintf((char *) buffer, buf_len, "%s", buf);
3460 cur = next;
3461 } while (cur != NULL);
3462 xmlFree(buf);
3463 return (buffer);
3464}
3465
3466/**
Owen Taylor3473f882001-02-23 17:55:21 +00003467 * xmlDocGetRootElement:
3468 * @doc: the document
3469 *
3470 * Get the root element of the document (doc->children is a list
3471 * containing possibly comments, PIs, etc ...).
3472 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003473 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003474 */
3475xmlNodePtr
3476xmlDocGetRootElement(xmlDocPtr doc) {
3477 xmlNodePtr ret;
3478
3479 if (doc == NULL) return(NULL);
3480 ret = doc->children;
3481 while (ret != NULL) {
3482 if (ret->type == XML_ELEMENT_NODE)
3483 return(ret);
3484 ret = ret->next;
3485 }
3486 return(ret);
3487}
3488
3489/**
3490 * xmlDocSetRootElement:
3491 * @doc: the document
3492 * @root: the new document root element
3493 *
3494 * Set the root element of the document (doc->children is a list
3495 * containing possibly comments, PIs, etc ...).
3496 *
3497 * Returns the old root element if any was found
3498 */
3499xmlNodePtr
3500xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3501 xmlNodePtr old = NULL;
3502
3503 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00003504 if (root == NULL)
3505 return(NULL);
3506 xmlUnlinkNode(root);
3507 root->doc = doc;
3508 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00003509 old = doc->children;
3510 while (old != NULL) {
3511 if (old->type == XML_ELEMENT_NODE)
3512 break;
3513 old = old->next;
3514 }
3515 if (old == NULL) {
3516 if (doc->children == NULL) {
3517 doc->children = root;
3518 doc->last = root;
3519 } else {
3520 xmlAddSibling(doc->children, root);
3521 }
3522 } else {
3523 xmlReplaceNode(old, root);
3524 }
3525 return(old);
3526}
3527
3528/**
3529 * xmlNodeSetLang:
3530 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003531 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003532 *
3533 * Set the language of a node, i.e. the values of the xml:lang
3534 * attribute.
3535 */
3536void
3537xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003538 xmlNsPtr ns;
3539
Owen Taylor3473f882001-02-23 17:55:21 +00003540 if (cur == NULL) return;
3541 switch(cur->type) {
3542 case XML_TEXT_NODE:
3543 case XML_CDATA_SECTION_NODE:
3544 case XML_COMMENT_NODE:
3545 case XML_DOCUMENT_NODE:
3546 case XML_DOCUMENT_TYPE_NODE:
3547 case XML_DOCUMENT_FRAG_NODE:
3548 case XML_NOTATION_NODE:
3549 case XML_HTML_DOCUMENT_NODE:
3550 case XML_DTD_NODE:
3551 case XML_ELEMENT_DECL:
3552 case XML_ATTRIBUTE_DECL:
3553 case XML_ENTITY_DECL:
3554 case XML_PI_NODE:
3555 case XML_ENTITY_REF_NODE:
3556 case XML_ENTITY_NODE:
3557 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003558#ifdef LIBXML_DOCB_ENABLED
3559 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003560#endif
3561 case XML_XINCLUDE_START:
3562 case XML_XINCLUDE_END:
3563 return;
3564 case XML_ELEMENT_NODE:
3565 case XML_ATTRIBUTE_NODE:
3566 break;
3567 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003568 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3569 if (ns == NULL)
3570 return;
3571 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003572}
3573
3574/**
3575 * xmlNodeGetLang:
3576 * @cur: the node being checked
3577 *
3578 * Searches the language of a node, i.e. the values of the xml:lang
3579 * attribute or the one carried by the nearest ancestor.
3580 *
3581 * Returns a pointer to the lang value, or NULL if not found
3582 * It's up to the caller to free the memory.
3583 */
3584xmlChar *
3585xmlNodeGetLang(xmlNodePtr cur) {
3586 xmlChar *lang;
3587
3588 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003589 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003590 if (lang != NULL)
3591 return(lang);
3592 cur = cur->parent;
3593 }
3594 return(NULL);
3595}
3596
3597
3598/**
3599 * xmlNodeSetSpacePreserve:
3600 * @cur: the node being changed
3601 * @val: the xml:space value ("0": default, 1: "preserve")
3602 *
3603 * Set (or reset) the space preserving behaviour of a node, i.e. the
3604 * value of the xml:space attribute.
3605 */
3606void
3607xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003608 xmlNsPtr ns;
3609
Owen Taylor3473f882001-02-23 17:55:21 +00003610 if (cur == NULL) return;
3611 switch(cur->type) {
3612 case XML_TEXT_NODE:
3613 case XML_CDATA_SECTION_NODE:
3614 case XML_COMMENT_NODE:
3615 case XML_DOCUMENT_NODE:
3616 case XML_DOCUMENT_TYPE_NODE:
3617 case XML_DOCUMENT_FRAG_NODE:
3618 case XML_NOTATION_NODE:
3619 case XML_HTML_DOCUMENT_NODE:
3620 case XML_DTD_NODE:
3621 case XML_ELEMENT_DECL:
3622 case XML_ATTRIBUTE_DECL:
3623 case XML_ENTITY_DECL:
3624 case XML_PI_NODE:
3625 case XML_ENTITY_REF_NODE:
3626 case XML_ENTITY_NODE:
3627 case XML_NAMESPACE_DECL:
3628 case XML_XINCLUDE_START:
3629 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003630#ifdef LIBXML_DOCB_ENABLED
3631 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003632#endif
3633 return;
3634 case XML_ELEMENT_NODE:
3635 case XML_ATTRIBUTE_NODE:
3636 break;
3637 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003638 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3639 if (ns == NULL)
3640 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003641 switch (val) {
3642 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003643 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003644 break;
3645 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003646 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003647 break;
3648 }
3649}
3650
3651/**
3652 * xmlNodeGetSpacePreserve:
3653 * @cur: the node being checked
3654 *
3655 * Searches the space preserving behaviour of a node, i.e. the values
3656 * of the xml:space attribute or the one carried by the nearest
3657 * ancestor.
3658 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003659 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003660 */
3661int
3662xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3663 xmlChar *space;
3664
3665 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003666 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003667 if (space != NULL) {
3668 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3669 xmlFree(space);
3670 return(1);
3671 }
3672 if (xmlStrEqual(space, BAD_CAST "default")) {
3673 xmlFree(space);
3674 return(0);
3675 }
3676 xmlFree(space);
3677 }
3678 cur = cur->parent;
3679 }
3680 return(-1);
3681}
3682
3683/**
3684 * xmlNodeSetName:
3685 * @cur: the node being changed
3686 * @name: the new tag name
3687 *
3688 * Set (or reset) the name of a node.
3689 */
3690void
3691xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3692 if (cur == NULL) return;
3693 if (name == NULL) return;
3694 switch(cur->type) {
3695 case XML_TEXT_NODE:
3696 case XML_CDATA_SECTION_NODE:
3697 case XML_COMMENT_NODE:
3698 case XML_DOCUMENT_TYPE_NODE:
3699 case XML_DOCUMENT_FRAG_NODE:
3700 case XML_NOTATION_NODE:
3701 case XML_HTML_DOCUMENT_NODE:
3702 case XML_NAMESPACE_DECL:
3703 case XML_XINCLUDE_START:
3704 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003705#ifdef LIBXML_DOCB_ENABLED
3706 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003707#endif
3708 return;
3709 case XML_ELEMENT_NODE:
3710 case XML_ATTRIBUTE_NODE:
3711 case XML_PI_NODE:
3712 case XML_ENTITY_REF_NODE:
3713 case XML_ENTITY_NODE:
3714 case XML_DTD_NODE:
3715 case XML_DOCUMENT_NODE:
3716 case XML_ELEMENT_DECL:
3717 case XML_ATTRIBUTE_DECL:
3718 case XML_ENTITY_DECL:
3719 break;
3720 }
3721 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3722 cur->name = xmlStrdup(name);
3723}
3724
3725/**
3726 * xmlNodeSetBase:
3727 * @cur: the node being changed
3728 * @uri: the new base URI
3729 *
3730 * Set (or reset) the base URI of a node, i.e. the value of the
3731 * xml:base attribute.
3732 */
3733void
3734xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003735 xmlNsPtr ns;
3736
Owen Taylor3473f882001-02-23 17:55:21 +00003737 if (cur == NULL) return;
3738 switch(cur->type) {
3739 case XML_TEXT_NODE:
3740 case XML_CDATA_SECTION_NODE:
3741 case XML_COMMENT_NODE:
3742 case XML_DOCUMENT_NODE:
3743 case XML_DOCUMENT_TYPE_NODE:
3744 case XML_DOCUMENT_FRAG_NODE:
3745 case XML_NOTATION_NODE:
3746 case XML_HTML_DOCUMENT_NODE:
3747 case XML_DTD_NODE:
3748 case XML_ELEMENT_DECL:
3749 case XML_ATTRIBUTE_DECL:
3750 case XML_ENTITY_DECL:
3751 case XML_PI_NODE:
3752 case XML_ENTITY_REF_NODE:
3753 case XML_ENTITY_NODE:
3754 case XML_NAMESPACE_DECL:
3755 case XML_XINCLUDE_START:
3756 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003757#ifdef LIBXML_DOCB_ENABLED
3758 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003759#endif
3760 return;
3761 case XML_ELEMENT_NODE:
3762 case XML_ATTRIBUTE_NODE:
3763 break;
3764 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003765
3766 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3767 if (ns == NULL)
3768 return;
3769 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00003770}
3771
3772/**
Owen Taylor3473f882001-02-23 17:55:21 +00003773 * xmlNodeGetBase:
3774 * @doc: the document the node pertains to
3775 * @cur: the node being checked
3776 *
3777 * Searches for the BASE URL. The code should work on both XML
3778 * and HTML document even if base mechanisms are completely different.
3779 * It returns the base as defined in RFC 2396 sections
3780 * 5.1.1. Base URI within Document Content
3781 * and
3782 * 5.1.2. Base URI from the Encapsulating Entity
3783 * However it does not return the document base (5.1.3), use
3784 * xmlDocumentGetBase() for this
3785 *
3786 * Returns a pointer to the base URL, or NULL if not found
3787 * It's up to the caller to free the memory.
3788 */
3789xmlChar *
3790xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003791 xmlChar *oldbase = NULL;
3792 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003793
3794 if ((cur == NULL) && (doc == NULL))
3795 return(NULL);
3796 if (doc == NULL) doc = cur->doc;
3797 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3798 cur = doc->children;
3799 while ((cur != NULL) && (cur->name != NULL)) {
3800 if (cur->type != XML_ELEMENT_NODE) {
3801 cur = cur->next;
3802 continue;
3803 }
3804 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3805 cur = cur->children;
3806 continue;
3807 }
3808 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3809 cur = cur->children;
3810 continue;
3811 }
3812 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3813 return(xmlGetProp(cur, BAD_CAST "href"));
3814 }
3815 cur = cur->next;
3816 }
3817 return(NULL);
3818 }
3819 while (cur != NULL) {
3820 if (cur->type == XML_ENTITY_DECL) {
3821 xmlEntityPtr ent = (xmlEntityPtr) cur;
3822 return(xmlStrdup(ent->URI));
3823 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003824 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003825 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003826 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003827 if (oldbase != NULL) {
3828 newbase = xmlBuildURI(oldbase, base);
3829 if (newbase != NULL) {
3830 xmlFree(oldbase);
3831 xmlFree(base);
3832 oldbase = newbase;
3833 } else {
3834 xmlFree(oldbase);
3835 xmlFree(base);
3836 return(NULL);
3837 }
3838 } else {
3839 oldbase = base;
3840 }
3841 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3842 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3843 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3844 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003845 }
3846 }
Owen Taylor3473f882001-02-23 17:55:21 +00003847 cur = cur->parent;
3848 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003849 if ((doc != NULL) && (doc->URL != NULL)) {
3850 if (oldbase == NULL)
3851 return(xmlStrdup(doc->URL));
3852 newbase = xmlBuildURI(oldbase, doc->URL);
3853 xmlFree(oldbase);
3854 return(newbase);
3855 }
3856 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003857}
3858
3859/**
3860 * xmlNodeGetContent:
3861 * @cur: the node being read
3862 *
3863 * Read the value of a node, this can be either the text carried
3864 * directly by this node if it's a TEXT node or the aggregate string
3865 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00003866 * Entity references are substituted.
3867 * Returns a new #xmlChar * or NULL if no content is available.
Owen Taylor3473f882001-02-23 17:55:21 +00003868 * It's up to the caller to free the memory.
3869 */
3870xmlChar *
3871xmlNodeGetContent(xmlNodePtr cur) {
3872 if (cur == NULL) return(NULL);
3873 switch (cur->type) {
3874 case XML_DOCUMENT_FRAG_NODE:
3875 case XML_ELEMENT_NODE: {
3876 xmlNodePtr tmp = cur;
3877 xmlBufferPtr buffer;
3878 xmlChar *ret;
3879
3880 buffer = xmlBufferCreate();
3881 if (buffer == NULL)
3882 return(NULL);
3883 while (tmp != NULL) {
3884 switch (tmp->type) {
Daniel Veillard2d703722001-05-30 18:32:34 +00003885 case XML_CDATA_SECTION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003886 case XML_TEXT_NODE:
3887 if (tmp->content != NULL)
3888#ifndef XML_USE_BUFFER_CONTENT
3889 xmlBufferCat(buffer, tmp->content);
3890#else
3891 xmlBufferCat(buffer,
3892 xmlBufferContent(tmp->content));
3893#endif
3894 break;
3895 case XML_ENTITY_REF_NODE: {
3896 xmlEntityPtr ent;
3897
3898 ent = xmlGetDocEntity(cur->doc, tmp->name);
3899 if (ent != NULL)
3900 xmlBufferCat(buffer, ent->content);
3901 }
3902 default:
3903 break;
3904 }
3905 /*
3906 * Skip to next node
3907 */
3908 if (tmp->children != NULL) {
3909 if (tmp->children->type != XML_ENTITY_DECL) {
3910 tmp = tmp->children;
3911 continue;
3912 }
3913 }
Daniel Veillard6c831202001-03-07 15:57:53 +00003914 if (tmp == cur)
3915 break;
3916
Owen Taylor3473f882001-02-23 17:55:21 +00003917 if (tmp->next != NULL) {
3918 tmp = tmp->next;
3919 continue;
3920 }
3921
3922 do {
3923 tmp = tmp->parent;
3924 if (tmp == NULL)
3925 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00003926 if (tmp == cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003927 tmp = NULL;
3928 break;
3929 }
3930 if (tmp->next != NULL) {
3931 tmp = tmp->next;
3932 break;
3933 }
3934 } while (tmp != NULL);
3935 }
3936 ret = buffer->content;
3937 buffer->content = NULL;
3938 xmlBufferFree(buffer);
3939 return(ret);
3940 }
3941 case XML_ATTRIBUTE_NODE: {
3942 xmlAttrPtr attr = (xmlAttrPtr) cur;
3943 if (attr->parent != NULL)
3944 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
3945 else
3946 return(xmlNodeListGetString(NULL, attr->children, 1));
3947 break;
3948 }
3949 case XML_COMMENT_NODE:
3950 case XML_PI_NODE:
3951 if (cur->content != NULL)
3952#ifndef XML_USE_BUFFER_CONTENT
3953 return(xmlStrdup(cur->content));
3954#else
3955 return(xmlStrdup(xmlBufferContent(cur->content)));
3956#endif
3957 return(NULL);
3958 case XML_ENTITY_REF_NODE:
3959 /*
3960 * Locate the entity, and get it's content
3961 * @@@
3962 */
3963 return(NULL);
3964 case XML_ENTITY_NODE:
3965 case XML_DOCUMENT_NODE:
3966 case XML_HTML_DOCUMENT_NODE:
3967 case XML_DOCUMENT_TYPE_NODE:
3968 case XML_NOTATION_NODE:
3969 case XML_DTD_NODE:
3970 case XML_XINCLUDE_START:
3971 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003972#ifdef LIBXML_DOCB_ENABLED
3973 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003974#endif
3975 return(NULL);
3976 case XML_NAMESPACE_DECL:
3977 return(xmlStrdup(((xmlNsPtr)cur)->href));
3978 case XML_ELEMENT_DECL:
3979 /* TODO !!! */
3980 return(NULL);
3981 case XML_ATTRIBUTE_DECL:
3982 /* TODO !!! */
3983 return(NULL);
3984 case XML_ENTITY_DECL:
3985 /* TODO !!! */
3986 return(NULL);
3987 case XML_CDATA_SECTION_NODE:
3988 case XML_TEXT_NODE:
3989 if (cur->content != NULL)
3990#ifndef XML_USE_BUFFER_CONTENT
3991 return(xmlStrdup(cur->content));
3992#else
3993 return(xmlStrdup(xmlBufferContent(cur->content)));
3994#endif
3995 return(NULL);
3996 }
3997 return(NULL);
3998}
3999
4000/**
4001 * xmlNodeSetContent:
4002 * @cur: the node being modified
4003 * @content: the new value of the content
4004 *
4005 * Replace the content of a node.
4006 */
4007void
4008xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4009 if (cur == NULL) {
4010#ifdef DEBUG_TREE
4011 xmlGenericError(xmlGenericErrorContext,
4012 "xmlNodeSetContent : node == NULL\n");
4013#endif
4014 return;
4015 }
4016 switch (cur->type) {
4017 case XML_DOCUMENT_FRAG_NODE:
4018 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004019 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004020 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4021 cur->children = xmlStringGetNodeList(cur->doc, content);
4022 UPDATE_LAST_CHILD_AND_PARENT(cur)
4023 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004024 case XML_TEXT_NODE:
4025 case XML_CDATA_SECTION_NODE:
4026 case XML_ENTITY_REF_NODE:
4027 case XML_ENTITY_NODE:
4028 case XML_PI_NODE:
4029 case XML_COMMENT_NODE:
4030 if (cur->content != NULL) {
4031#ifndef XML_USE_BUFFER_CONTENT
4032 xmlFree(cur->content);
4033#else
4034 xmlBufferFree(cur->content);
4035#endif
4036 }
4037 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4038 cur->last = cur->children = NULL;
4039 if (content != NULL) {
4040#ifndef XML_USE_BUFFER_CONTENT
4041 cur->content = xmlStrdup(content);
4042#else
4043 cur->content = xmlBufferCreateSize(0);
4044 xmlBufferSetAllocationScheme(cur->content,
4045 xmlGetBufferAllocationScheme());
4046 xmlBufferAdd(cur->content, content, -1);
4047#endif
4048 } else
4049 cur->content = NULL;
4050 break;
4051 case XML_DOCUMENT_NODE:
4052 case XML_HTML_DOCUMENT_NODE:
4053 case XML_DOCUMENT_TYPE_NODE:
4054 case XML_XINCLUDE_START:
4055 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004056#ifdef LIBXML_DOCB_ENABLED
4057 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004058#endif
4059 break;
4060 case XML_NOTATION_NODE:
4061 break;
4062 case XML_DTD_NODE:
4063 break;
4064 case XML_NAMESPACE_DECL:
4065 break;
4066 case XML_ELEMENT_DECL:
4067 /* TODO !!! */
4068 break;
4069 case XML_ATTRIBUTE_DECL:
4070 /* TODO !!! */
4071 break;
4072 case XML_ENTITY_DECL:
4073 /* TODO !!! */
4074 break;
4075 }
4076}
4077
4078/**
4079 * xmlNodeSetContentLen:
4080 * @cur: the node being modified
4081 * @content: the new value of the content
4082 * @len: the size of @content
4083 *
4084 * Replace the content of a node.
4085 */
4086void
4087xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4088 if (cur == NULL) {
4089#ifdef DEBUG_TREE
4090 xmlGenericError(xmlGenericErrorContext,
4091 "xmlNodeSetContentLen : node == NULL\n");
4092#endif
4093 return;
4094 }
4095 switch (cur->type) {
4096 case XML_DOCUMENT_FRAG_NODE:
4097 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004098 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004099 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4100 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4101 UPDATE_LAST_CHILD_AND_PARENT(cur)
4102 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004103 case XML_TEXT_NODE:
4104 case XML_CDATA_SECTION_NODE:
4105 case XML_ENTITY_REF_NODE:
4106 case XML_ENTITY_NODE:
4107 case XML_PI_NODE:
4108 case XML_COMMENT_NODE:
4109 case XML_NOTATION_NODE:
4110 if (cur->content != NULL) {
4111#ifndef XML_USE_BUFFER_CONTENT
4112 xmlFree(cur->content);
4113#else
4114 xmlBufferFree(cur->content);
4115#endif
4116 }
4117 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4118 cur->children = cur->last = NULL;
4119 if (content != NULL) {
4120#ifndef XML_USE_BUFFER_CONTENT
4121 cur->content = xmlStrndup(content, len);
4122#else
4123 cur->content = xmlBufferCreateSize(len);
4124 xmlBufferSetAllocationScheme(cur->content,
4125 xmlGetBufferAllocationScheme());
4126 xmlBufferAdd(cur->content, content, len);
4127#endif
4128 } else
4129 cur->content = NULL;
4130 break;
4131 case XML_DOCUMENT_NODE:
4132 case XML_DTD_NODE:
4133 case XML_HTML_DOCUMENT_NODE:
4134 case XML_DOCUMENT_TYPE_NODE:
4135 case XML_NAMESPACE_DECL:
4136 case XML_XINCLUDE_START:
4137 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004138#ifdef LIBXML_DOCB_ENABLED
4139 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004140#endif
4141 break;
4142 case XML_ELEMENT_DECL:
4143 /* TODO !!! */
4144 break;
4145 case XML_ATTRIBUTE_DECL:
4146 /* TODO !!! */
4147 break;
4148 case XML_ENTITY_DECL:
4149 /* TODO !!! */
4150 break;
4151 }
4152}
4153
4154/**
4155 * xmlNodeAddContentLen:
4156 * @cur: the node being modified
4157 * @content: extra content
4158 * @len: the size of @content
4159 *
4160 * Append the extra substring to the node content.
4161 */
4162void
4163xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4164 if (cur == NULL) {
4165#ifdef DEBUG_TREE
4166 xmlGenericError(xmlGenericErrorContext,
4167 "xmlNodeAddContentLen : node == NULL\n");
4168#endif
4169 return;
4170 }
4171 if (len <= 0) return;
4172 switch (cur->type) {
4173 case XML_DOCUMENT_FRAG_NODE:
4174 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004175 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004176
Daniel Veillard7db37732001-07-12 01:20:08 +00004177 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004178 newNode = xmlNewTextLen(content, len);
4179 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004180 tmp = xmlAddChild(cur, newNode);
4181 if (tmp != newNode)
4182 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004183 if ((last != NULL) && (last->next == newNode)) {
4184 xmlTextMerge(last, newNode);
4185 }
4186 }
4187 break;
4188 }
4189 case XML_ATTRIBUTE_NODE:
4190 break;
4191 case XML_TEXT_NODE:
4192 case XML_CDATA_SECTION_NODE:
4193 case XML_ENTITY_REF_NODE:
4194 case XML_ENTITY_NODE:
4195 case XML_PI_NODE:
4196 case XML_COMMENT_NODE:
4197 case XML_NOTATION_NODE:
4198 if (content != NULL) {
4199#ifndef XML_USE_BUFFER_CONTENT
4200 cur->content = xmlStrncat(cur->content, content, len);
4201#else
4202 xmlBufferAdd(cur->content, content, len);
4203#endif
4204 }
4205 case XML_DOCUMENT_NODE:
4206 case XML_DTD_NODE:
4207 case XML_HTML_DOCUMENT_NODE:
4208 case XML_DOCUMENT_TYPE_NODE:
4209 case XML_NAMESPACE_DECL:
4210 case XML_XINCLUDE_START:
4211 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004212#ifdef LIBXML_DOCB_ENABLED
4213 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004214#endif
4215 break;
4216 case XML_ELEMENT_DECL:
4217 case XML_ATTRIBUTE_DECL:
4218 case XML_ENTITY_DECL:
4219 break;
4220 }
4221}
4222
4223/**
4224 * xmlNodeAddContent:
4225 * @cur: the node being modified
4226 * @content: extra content
4227 *
4228 * Append the extra substring to the node content.
4229 */
4230void
4231xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4232 int len;
4233
4234 if (cur == NULL) {
4235#ifdef DEBUG_TREE
4236 xmlGenericError(xmlGenericErrorContext,
4237 "xmlNodeAddContent : node == NULL\n");
4238#endif
4239 return;
4240 }
4241 if (content == NULL) return;
4242 len = xmlStrlen(content);
4243 xmlNodeAddContentLen(cur, content, len);
4244}
4245
4246/**
4247 * xmlTextMerge:
4248 * @first: the first text node
4249 * @second: the second text node being merged
4250 *
4251 * Merge two text nodes into one
4252 * Returns the first text node augmented
4253 */
4254xmlNodePtr
4255xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4256 if (first == NULL) return(second);
4257 if (second == NULL) return(first);
4258 if (first->type != XML_TEXT_NODE) return(first);
4259 if (second->type != XML_TEXT_NODE) return(first);
4260 if (second->name != first->name)
4261 return(first);
4262#ifndef XML_USE_BUFFER_CONTENT
4263 xmlNodeAddContent(first, second->content);
4264#else
4265 xmlNodeAddContent(first, xmlBufferContent(second->content));
4266#endif
4267 xmlUnlinkNode(second);
4268 xmlFreeNode(second);
4269 return(first);
4270}
4271
4272/**
4273 * xmlGetNsList:
4274 * @doc: the document
4275 * @node: the current node
4276 *
4277 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004278 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004279 * that need to be freed by the caller or NULL if no
4280 * namespace if defined
4281 */
4282xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004283xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4284{
Owen Taylor3473f882001-02-23 17:55:21 +00004285 xmlNsPtr cur;
4286 xmlNsPtr *ret = NULL;
4287 int nbns = 0;
4288 int maxns = 10;
4289 int i;
4290
4291 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004292 if (node->type == XML_ELEMENT_NODE) {
4293 cur = node->nsDef;
4294 while (cur != NULL) {
4295 if (ret == NULL) {
4296 ret =
4297 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4298 sizeof(xmlNsPtr));
4299 if (ret == NULL) {
4300 xmlGenericError(xmlGenericErrorContext,
4301 "xmlGetNsList : out of memory!\n");
4302 return (NULL);
4303 }
4304 ret[nbns] = NULL;
4305 }
4306 for (i = 0; i < nbns; i++) {
4307 if ((cur->prefix == ret[i]->prefix) ||
4308 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4309 break;
4310 }
4311 if (i >= nbns) {
4312 if (nbns >= maxns) {
4313 maxns *= 2;
4314 ret = (xmlNsPtr *) xmlRealloc(ret,
4315 (maxns +
4316 1) *
4317 sizeof(xmlNsPtr));
4318 if (ret == NULL) {
4319 xmlGenericError(xmlGenericErrorContext,
4320 "xmlGetNsList : realloc failed!\n");
4321 return (NULL);
4322 }
4323 }
4324 ret[nbns++] = cur;
4325 ret[nbns] = NULL;
4326 }
Owen Taylor3473f882001-02-23 17:55:21 +00004327
Daniel Veillard77044732001-06-29 21:31:07 +00004328 cur = cur->next;
4329 }
4330 }
4331 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004332 }
Daniel Veillard77044732001-06-29 21:31:07 +00004333 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004334}
4335
4336/**
4337 * xmlSearchNs:
4338 * @doc: the document
4339 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004340 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004341 *
4342 * Search a Ns registered under a given name space for a document.
4343 * recurse on the parents until it finds the defined namespace
4344 * or return NULL otherwise.
4345 * @nameSpace can be NULL, this is a search for the default namespace.
4346 * We don't allow to cross entities boundaries. If you don't declare
4347 * the namespace within those you will be in troubles !!! A warning
4348 * is generated to cover this case.
4349 *
4350 * Returns the namespace pointer or NULL.
4351 */
4352xmlNsPtr
4353xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4354 xmlNsPtr cur;
4355
4356 if (node == NULL) return(NULL);
4357 if ((nameSpace != NULL) &&
4358 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillardd2f23002002-01-21 13:36:00 +00004359 if (doc == NULL)
4360 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004361 if (doc->oldNs == NULL) {
4362 /*
4363 * Allocate a new Namespace and fill the fields.
4364 */
4365 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4366 if (doc->oldNs == NULL) {
4367 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004368 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004369 return(NULL);
4370 }
4371 memset(doc->oldNs, 0, sizeof(xmlNs));
4372 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4373
4374 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4375 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4376 }
4377 return(doc->oldNs);
4378 }
4379 while (node != NULL) {
4380 if ((node->type == XML_ENTITY_REF_NODE) ||
4381 (node->type == XML_ENTITY_NODE) ||
4382 (node->type == XML_ENTITY_DECL))
4383 return(NULL);
4384 if (node->type == XML_ELEMENT_NODE) {
4385 cur = node->nsDef;
4386 while (cur != NULL) {
4387 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4388 (cur->href != NULL))
4389 return(cur);
4390 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4391 (cur->href != NULL) &&
4392 (xmlStrEqual(cur->prefix, nameSpace)))
4393 return(cur);
4394 cur = cur->next;
4395 }
4396 }
4397 node = node->parent;
4398 }
4399 return(NULL);
4400}
4401
4402/**
4403 * xmlSearchNsByHref:
4404 * @doc: the document
4405 * @node: the current node
4406 * @href: the namespace value
4407 *
4408 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4409 * the defined namespace or return NULL otherwise.
4410 * Returns the namespace pointer or NULL.
4411 */
4412xmlNsPtr
4413xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4414 xmlNsPtr cur;
4415 xmlNodePtr orig = node;
4416
4417 if ((node == NULL) || (href == NULL)) return(NULL);
4418 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004419 /*
4420 * Only the document can hold the XML spec namespace.
4421 */
4422 if (doc == NULL)
4423 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004424 if (doc->oldNs == NULL) {
4425 /*
4426 * Allocate a new Namespace and fill the fields.
4427 */
4428 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4429 if (doc->oldNs == NULL) {
4430 xmlGenericError(xmlGenericErrorContext,
4431 "xmlSearchNsByHref : malloc failed\n");
4432 return(NULL);
4433 }
4434 memset(doc->oldNs, 0, sizeof(xmlNs));
4435 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4436
4437 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4438 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4439 }
4440 return(doc->oldNs);
4441 }
4442 while (node != NULL) {
4443 cur = node->nsDef;
4444 while (cur != NULL) {
4445 if ((cur->href != NULL) && (href != NULL) &&
4446 (xmlStrEqual(cur->href, href))) {
4447 /*
4448 * Check that the prefix is not shadowed between orig and node
4449 */
4450 xmlNodePtr check = orig;
4451 xmlNsPtr tst;
4452
4453 while (check != node) {
4454 tst = check->nsDef;
4455 while (tst != NULL) {
4456 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4457 goto shadowed;
4458 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4459 (xmlStrEqual(tst->prefix, cur->prefix)))
4460 goto shadowed;
4461 tst = tst->next;
4462 }
4463 check = check->parent;
4464 }
4465 return(cur);
4466 }
4467shadowed:
4468 cur = cur->next;
4469 }
4470 node = node->parent;
4471 }
4472 return(NULL);
4473}
4474
4475/**
4476 * xmlNewReconciliedNs
4477 * @doc: the document
4478 * @tree: a node expected to hold the new namespace
4479 * @ns: the original namespace
4480 *
4481 * This function tries to locate a namespace definition in a tree
4482 * ancestors, or create a new namespace definition node similar to
4483 * @ns trying to reuse the same prefix. However if the given prefix is
4484 * null (default namespace) or reused within the subtree defined by
4485 * @tree or on one of its ancestors then a new prefix is generated.
4486 * Returns the (new) namespace definition or NULL in case of error
4487 */
4488xmlNsPtr
4489xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4490 xmlNsPtr def;
4491 xmlChar prefix[50];
4492 int counter = 1;
4493
4494 if (tree == NULL) {
4495#ifdef DEBUG_TREE
4496 xmlGenericError(xmlGenericErrorContext,
4497 "xmlNewReconciliedNs : tree == NULL\n");
4498#endif
4499 return(NULL);
4500 }
4501 if (ns == NULL) {
4502#ifdef DEBUG_TREE
4503 xmlGenericError(xmlGenericErrorContext,
4504 "xmlNewReconciliedNs : ns == NULL\n");
4505#endif
4506 return(NULL);
4507 }
4508 /*
4509 * Search an existing namespace definition inherited.
4510 */
4511 def = xmlSearchNsByHref(doc, tree, ns->href);
4512 if (def != NULL)
4513 return(def);
4514
4515 /*
4516 * Find a close prefix which is not already in use.
4517 * Let's strip namespace prefixes longer than 20 chars !
4518 */
Daniel Veillardf742d342002-03-07 00:05:35 +00004519 if (ns->prefix == NULL)
4520 sprintf((char *) prefix, "default");
4521 else
4522 sprintf((char *) prefix, "%.20s", ns->prefix);
4523
Owen Taylor3473f882001-02-23 17:55:21 +00004524 def = xmlSearchNs(doc, tree, prefix);
4525 while (def != NULL) {
4526 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00004527 if (ns->prefix == NULL)
4528 sprintf((char *) prefix, "default%d", counter++);
4529 else
4530 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00004531 def = xmlSearchNs(doc, tree, prefix);
4532 }
4533
4534 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004535 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004536 */
4537 def = xmlNewNs(tree, ns->href, prefix);
4538 return(def);
4539}
4540
4541/**
4542 * xmlReconciliateNs
4543 * @doc: the document
4544 * @tree: a node defining the subtree to reconciliate
4545 *
4546 * This function checks that all the namespaces declared within the given
4547 * tree are properly declared. This is needed for example after Copy or Cut
4548 * and then paste operations. The subtree may still hold pointers to
4549 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004550 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004551 * the new environment. If not possible the new namespaces are redeclared
4552 * on @tree at the top of the given subtree.
4553 * Returns the number of namespace declarations created or -1 in case of error.
4554 */
4555int
4556xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4557 xmlNsPtr *oldNs = NULL;
4558 xmlNsPtr *newNs = NULL;
4559 int sizeCache = 0;
4560 int nbCache = 0;
4561
4562 xmlNsPtr n;
4563 xmlNodePtr node = tree;
4564 xmlAttrPtr attr;
4565 int ret = 0, i;
4566
4567 while (node != NULL) {
4568 /*
4569 * Reconciliate the node namespace
4570 */
4571 if (node->ns != NULL) {
4572 /*
4573 * initialize the cache if needed
4574 */
4575 if (sizeCache == 0) {
4576 sizeCache = 10;
4577 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4578 sizeof(xmlNsPtr));
4579 if (oldNs == NULL) {
4580 xmlGenericError(xmlGenericErrorContext,
4581 "xmlReconciliateNs : memory pbm\n");
4582 return(-1);
4583 }
4584 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4585 sizeof(xmlNsPtr));
4586 if (newNs == NULL) {
4587 xmlGenericError(xmlGenericErrorContext,
4588 "xmlReconciliateNs : memory pbm\n");
4589 xmlFree(oldNs);
4590 return(-1);
4591 }
4592 }
4593 for (i = 0;i < nbCache;i++) {
4594 if (oldNs[i] == node->ns) {
4595 node->ns = newNs[i];
4596 break;
4597 }
4598 }
4599 if (i == nbCache) {
4600 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004601 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004602 */
4603 n = xmlNewReconciliedNs(doc, tree, node->ns);
4604 if (n != NULL) { /* :-( what if else ??? */
4605 /*
4606 * check if we need to grow the cache buffers.
4607 */
4608 if (sizeCache <= nbCache) {
4609 sizeCache *= 2;
4610 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4611 sizeof(xmlNsPtr));
4612 if (oldNs == NULL) {
4613 xmlGenericError(xmlGenericErrorContext,
4614 "xmlReconciliateNs : memory pbm\n");
4615 xmlFree(newNs);
4616 return(-1);
4617 }
4618 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4619 sizeof(xmlNsPtr));
4620 if (newNs == NULL) {
4621 xmlGenericError(xmlGenericErrorContext,
4622 "xmlReconciliateNs : memory pbm\n");
4623 xmlFree(oldNs);
4624 return(-1);
4625 }
4626 }
4627 newNs[nbCache] = n;
4628 oldNs[nbCache++] = node->ns;
4629 node->ns = n;
4630 }
4631 }
4632 }
4633 /*
4634 * now check for namespace hold by attributes on the node.
4635 */
4636 attr = node->properties;
4637 while (attr != NULL) {
4638 if (attr->ns != NULL) {
4639 /*
4640 * initialize the cache if needed
4641 */
4642 if (sizeCache == 0) {
4643 sizeCache = 10;
4644 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4645 sizeof(xmlNsPtr));
4646 if (oldNs == NULL) {
4647 xmlGenericError(xmlGenericErrorContext,
4648 "xmlReconciliateNs : memory pbm\n");
4649 return(-1);
4650 }
4651 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4652 sizeof(xmlNsPtr));
4653 if (newNs == NULL) {
4654 xmlGenericError(xmlGenericErrorContext,
4655 "xmlReconciliateNs : memory pbm\n");
4656 xmlFree(oldNs);
4657 return(-1);
4658 }
4659 }
4660 for (i = 0;i < nbCache;i++) {
4661 if (oldNs[i] == attr->ns) {
4662 node->ns = newNs[i];
4663 break;
4664 }
4665 }
4666 if (i == nbCache) {
4667 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004668 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004669 */
4670 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4671 if (n != NULL) { /* :-( what if else ??? */
4672 /*
4673 * check if we need to grow the cache buffers.
4674 */
4675 if (sizeCache <= nbCache) {
4676 sizeCache *= 2;
4677 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4678 sizeof(xmlNsPtr));
4679 if (oldNs == NULL) {
4680 xmlGenericError(xmlGenericErrorContext,
4681 "xmlReconciliateNs : memory pbm\n");
4682 xmlFree(newNs);
4683 return(-1);
4684 }
4685 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4686 sizeof(xmlNsPtr));
4687 if (newNs == NULL) {
4688 xmlGenericError(xmlGenericErrorContext,
4689 "xmlReconciliateNs : memory pbm\n");
4690 xmlFree(oldNs);
4691 return(-1);
4692 }
4693 }
4694 newNs[nbCache] = n;
4695 oldNs[nbCache++] = attr->ns;
4696 attr->ns = n;
4697 }
4698 }
4699 }
4700 attr = attr->next;
4701 }
4702
4703 /*
4704 * Browse the full subtree, deep first
4705 */
4706 if (node->children != NULL) {
4707 /* deep first */
4708 node = node->children;
4709 } else if ((node != tree) && (node->next != NULL)) {
4710 /* then siblings */
4711 node = node->next;
4712 } else if (node != tree) {
4713 /* go up to parents->next if needed */
4714 while (node != tree) {
4715 if (node->parent != NULL)
4716 node = node->parent;
4717 if ((node != tree) && (node->next != NULL)) {
4718 node = node->next;
4719 break;
4720 }
4721 if (node->parent == NULL) {
4722 node = NULL;
4723 break;
4724 }
4725 }
4726 /* exit condition */
4727 if (node == tree)
4728 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00004729 } else
4730 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004731 }
Daniel Veillardf742d342002-03-07 00:05:35 +00004732 if (oldNs != NULL)
4733 xmlFree(oldNs);
4734 if (newNs != NULL)
4735 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00004736 return(ret);
4737}
4738
4739/**
4740 * xmlHasProp:
4741 * @node: the node
4742 * @name: the attribute name
4743 *
4744 * Search an attribute associated to a node
4745 * This function also looks in DTD attribute declaration for #FIXED or
4746 * default declaration values unless DTD use has been turned off.
4747 *
4748 * Returns the attribute or the attribute declaration or NULL if
4749 * neither was found.
4750 */
4751xmlAttrPtr
4752xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4753 xmlAttrPtr prop;
4754 xmlDocPtr doc;
4755
4756 if ((node == NULL) || (name == NULL)) return(NULL);
4757 /*
4758 * Check on the properties attached to the node
4759 */
4760 prop = node->properties;
4761 while (prop != NULL) {
4762 if (xmlStrEqual(prop->name, name)) {
4763 return(prop);
4764 }
4765 prop = prop->next;
4766 }
4767 if (!xmlCheckDTD) return(NULL);
4768
4769 /*
4770 * Check if there is a default declaration in the internal
4771 * or external subsets
4772 */
4773 doc = node->doc;
4774 if (doc != NULL) {
4775 xmlAttributePtr attrDecl;
4776 if (doc->intSubset != NULL) {
4777 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4778 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4779 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4780 if (attrDecl != NULL)
4781 return((xmlAttrPtr) attrDecl);
4782 }
4783 }
4784 return(NULL);
4785}
4786
4787/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004788 * xmlHasNsProp:
4789 * @node: the node
4790 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004791 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004792 *
4793 * Search for an attribute associated to a node
4794 * This attribute has to be anchored in the namespace specified.
4795 * This does the entity substitution.
4796 * This function looks in DTD attribute declaration for #FIXED or
4797 * default declaration values unless DTD use has been turned off.
4798 *
4799 * Returns the attribute or the attribute declaration or NULL
4800 * if neither was found.
4801 */
4802xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004803xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004804 xmlAttrPtr prop;
4805 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004806
4807 if (node == NULL)
4808 return(NULL);
4809
4810 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004811 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004812 return(xmlHasProp(node, name));
4813 while (prop != NULL) {
4814 /*
4815 * One need to have
4816 * - same attribute names
4817 * - and the attribute carrying that namespace
4818 * or
4819 * no namespace on the attribute and the element carrying it
4820 */
4821 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004822 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4823 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004824 }
4825 prop = prop->next;
4826 }
4827 if (!xmlCheckDTD) return(NULL);
4828
4829 /*
4830 * Check if there is a default declaration in the internal
4831 * or external subsets
4832 */
4833 doc = node->doc;
4834 if (doc != NULL) {
4835 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004836 xmlAttributePtr attrDecl = NULL;
4837 xmlNsPtr *nsList, *cur;
4838 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004839
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004840 nsList = xmlGetNsList(node->doc, node);
4841 if (nsList == NULL)
4842 return(NULL);
4843 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
4844 ename = xmlStrdup(node->ns->prefix);
4845 ename = xmlStrcat(ename, BAD_CAST ":");
4846 ename = xmlStrcat(ename, node->name);
4847 } else {
4848 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004849 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004850 if (ename == NULL) {
4851 xmlFree(nsList);
4852 return(NULL);
4853 }
4854
4855 cur = nsList;
4856 while (*cur != NULL) {
4857 if (xmlStrEqual((*cur)->href, nameSpace)) {
4858 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
4859 name, (*cur)->prefix);
4860 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4861 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
4862 name, (*cur)->prefix);
4863 }
4864 cur++;
4865 }
4866 xmlFree(nsList);
4867 xmlFree(ename);
4868 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004869 }
4870 }
4871 return(NULL);
4872}
4873
4874/**
Owen Taylor3473f882001-02-23 17:55:21 +00004875 * xmlGetProp:
4876 * @node: the node
4877 * @name: the attribute name
4878 *
4879 * Search and get the value of an attribute associated to a node
4880 * This does the entity substitution.
4881 * This function looks in DTD attribute declaration for #FIXED or
4882 * default declaration values unless DTD use has been turned off.
4883 *
4884 * Returns the attribute value or NULL if not found.
4885 * It's up to the caller to free the memory.
4886 */
4887xmlChar *
4888xmlGetProp(xmlNodePtr node, const xmlChar *name) {
4889 xmlAttrPtr prop;
4890 xmlDocPtr doc;
4891
4892 if ((node == NULL) || (name == NULL)) return(NULL);
4893 /*
4894 * Check on the properties attached to the node
4895 */
4896 prop = node->properties;
4897 while (prop != NULL) {
4898 if (xmlStrEqual(prop->name, name)) {
4899 xmlChar *ret;
4900
4901 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4902 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4903 return(ret);
4904 }
4905 prop = prop->next;
4906 }
4907 if (!xmlCheckDTD) return(NULL);
4908
4909 /*
4910 * Check if there is a default declaration in the internal
4911 * or external subsets
4912 */
4913 doc = node->doc;
4914 if (doc != NULL) {
4915 xmlAttributePtr attrDecl;
4916 if (doc->intSubset != NULL) {
4917 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4918 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4919 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4920 if (attrDecl != NULL)
4921 return(xmlStrdup(attrDecl->defaultValue));
4922 }
4923 }
4924 return(NULL);
4925}
4926
4927/**
4928 * xmlGetNsProp:
4929 * @node: the node
4930 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004931 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004932 *
4933 * Search and get the value of an attribute associated to a node
4934 * This attribute has to be anchored in the namespace specified.
4935 * This does the entity substitution.
4936 * This function looks in DTD attribute declaration for #FIXED or
4937 * default declaration values unless DTD use has been turned off.
4938 *
4939 * Returns the attribute value or NULL if not found.
4940 * It's up to the caller to free the memory.
4941 */
4942xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00004943xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00004944 xmlAttrPtr prop;
4945 xmlDocPtr doc;
4946 xmlNsPtr ns;
4947
4948 if (node == NULL)
4949 return(NULL);
4950
4951 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004952 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00004953 return(xmlGetProp(node, name));
4954 while (prop != NULL) {
4955 /*
4956 * One need to have
4957 * - same attribute names
4958 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004959 */
4960 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00004961 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00004962 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00004963 xmlChar *ret;
4964
4965 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4966 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4967 return(ret);
4968 }
4969 prop = prop->next;
4970 }
4971 if (!xmlCheckDTD) return(NULL);
4972
4973 /*
4974 * Check if there is a default declaration in the internal
4975 * or external subsets
4976 */
4977 doc = node->doc;
4978 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004979 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00004980 xmlAttributePtr attrDecl;
4981
Owen Taylor3473f882001-02-23 17:55:21 +00004982 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4983 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4984 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4985
4986 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4987 /*
4988 * The DTD declaration only allows a prefix search
4989 */
4990 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004991 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00004992 return(xmlStrdup(attrDecl->defaultValue));
4993 }
4994 }
4995 }
4996 return(NULL);
4997}
4998
4999/**
5000 * xmlSetProp:
5001 * @node: the node
5002 * @name: the attribute name
5003 * @value: the attribute value
5004 *
5005 * Set (or reset) an attribute carried by a node.
5006 * Returns the attribute pointer.
5007 */
5008xmlAttrPtr
5009xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005010 xmlAttrPtr prop;
5011 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005012
5013 if ((node == NULL) || (name == NULL))
5014 return(NULL);
5015 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005016 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005017 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005018 if ((xmlStrEqual(prop->name, name)) &&
5019 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005020 xmlNodePtr oldprop = prop->children;
5021
Owen Taylor3473f882001-02-23 17:55:21 +00005022 prop->children = NULL;
5023 prop->last = NULL;
5024 if (value != NULL) {
5025 xmlChar *buffer;
5026 xmlNodePtr tmp;
5027
5028 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5029 prop->children = xmlStringGetNodeList(node->doc, buffer);
5030 prop->last = NULL;
5031 prop->doc = doc;
5032 tmp = prop->children;
5033 while (tmp != NULL) {
5034 tmp->parent = (xmlNodePtr) prop;
5035 tmp->doc = doc;
5036 if (tmp->next == NULL)
5037 prop->last = tmp;
5038 tmp = tmp->next;
5039 }
5040 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005041 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005042 if (oldprop != NULL)
5043 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005044 return(prop);
5045 }
5046 prop = prop->next;
5047 }
5048 prop = xmlNewProp(node, name, value);
5049 return(prop);
5050}
5051
5052/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005053 * xmlUnsetProp:
5054 * @node: the node
5055 * @name: the attribute name
5056 *
5057 * Remove an attribute carried by a node.
5058 * Returns 0 if successful, -1 if not found
5059 */
5060int
5061xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
5062 xmlAttrPtr prop = node->properties, prev = NULL;;
5063
5064 if ((node == NULL) || (name == NULL))
5065 return(-1);
5066 while (prop != NULL) {
5067 if ((xmlStrEqual(prop->name, name)) &&
5068 (prop->ns == NULL)) {
5069 if (prev == NULL)
5070 node->properties = prop->next;
5071 else
5072 prev->next = prop->next;
5073 xmlFreeProp(prop);
5074 return(0);
5075 }
5076 prev = prop;
5077 prop = prop->next;
5078 }
5079 return(-1);
5080}
5081
5082/**
Owen Taylor3473f882001-02-23 17:55:21 +00005083 * xmlSetNsProp:
5084 * @node: the node
5085 * @ns: the namespace definition
5086 * @name: the attribute name
5087 * @value: the attribute value
5088 *
5089 * Set (or reset) an attribute carried by a node.
5090 * The ns structure must be in scope, this is not checked.
5091 *
5092 * Returns the attribute pointer.
5093 */
5094xmlAttrPtr
5095xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5096 const xmlChar *value) {
5097 xmlAttrPtr prop;
5098
5099 if ((node == NULL) || (name == NULL))
5100 return(NULL);
5101
5102 if (ns == NULL)
5103 return(xmlSetProp(node, name, value));
5104 if (ns->href == NULL)
5105 return(NULL);
5106 prop = node->properties;
5107
5108 while (prop != NULL) {
5109 /*
5110 * One need to have
5111 * - same attribute names
5112 * - and the attribute carrying that namespace
5113 * or
5114 * no namespace on the attribute and the element carrying it
5115 */
5116 if ((xmlStrEqual(prop->name, name)) &&
5117 (((prop->ns == NULL) && (node->ns != NULL) &&
5118 (xmlStrEqual(node->ns->href, ns->href))) ||
5119 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
5120 if (prop->children != NULL)
5121 xmlFreeNodeList(prop->children);
5122 prop->children = NULL;
5123 prop->last = NULL;
5124 prop->ns = ns;
5125 if (value != NULL) {
5126 xmlChar *buffer;
5127 xmlNodePtr tmp;
5128
5129 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5130 prop->children = xmlStringGetNodeList(node->doc, buffer);
5131 prop->last = NULL;
5132 tmp = prop->children;
5133 while (tmp != NULL) {
5134 tmp->parent = (xmlNodePtr) prop;
5135 if (tmp->next == NULL)
5136 prop->last = tmp;
5137 tmp = tmp->next;
5138 }
5139 xmlFree(buffer);
5140 }
5141 return(prop);
5142 }
5143 prop = prop->next;
5144 }
5145 prop = xmlNewNsProp(node, ns, name, value);
5146 return(prop);
5147}
5148
5149/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005150 * xmlUnsetNsProp:
5151 * @node: the node
5152 * @ns: the namespace definition
5153 * @name: the attribute name
5154 *
5155 * Remove an attribute carried by a node.
5156 * Returns 0 if successful, -1 if not found
5157 */
5158int
5159xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5160 xmlAttrPtr prop = node->properties, prev = NULL;;
5161
5162 if ((node == NULL) || (name == NULL))
5163 return(-1);
5164 if (ns == NULL)
5165 return(xmlUnsetProp(node, name));
5166 if (ns->href == NULL)
5167 return(-1);
5168 while (prop != NULL) {
5169 if ((xmlStrEqual(prop->name, name)) &&
5170 (((prop->ns == NULL) && (node->ns != NULL) &&
5171 (xmlStrEqual(node->ns->href, ns->href))) ||
5172 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
5173 if (prev == NULL)
5174 node->properties = prop->next;
5175 else
5176 prev->next = prop->next;
5177 xmlFreeProp(prop);
5178 return(0);
5179 }
5180 prev = prop;
5181 prop = prop->next;
5182 }
5183 return(-1);
5184}
5185
5186/**
Owen Taylor3473f882001-02-23 17:55:21 +00005187 * xmlNodeIsText:
5188 * @node: the node
5189 *
5190 * Is this node a Text node ?
5191 * Returns 1 yes, 0 no
5192 */
5193int
5194xmlNodeIsText(xmlNodePtr node) {
5195 if (node == NULL) return(0);
5196
5197 if (node->type == XML_TEXT_NODE) return(1);
5198 return(0);
5199}
5200
5201/**
5202 * xmlIsBlankNode:
5203 * @node: the node
5204 *
5205 * Checks whether this node is an empty or whitespace only
5206 * (and possibly ignorable) text-node.
5207 *
5208 * Returns 1 yes, 0 no
5209 */
5210int
5211xmlIsBlankNode(xmlNodePtr node) {
5212 const xmlChar *cur;
5213 if (node == NULL) return(0);
5214
Daniel Veillard7db37732001-07-12 01:20:08 +00005215 if ((node->type != XML_TEXT_NODE) &&
5216 (node->type != XML_CDATA_SECTION_NODE))
5217 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005218 if (node->content == NULL) return(1);
5219#ifndef XML_USE_BUFFER_CONTENT
5220 cur = node->content;
5221#else
5222 cur = xmlBufferContent(node->content);
5223#endif
5224 while (*cur != 0) {
5225 if (!IS_BLANK(*cur)) return(0);
5226 cur++;
5227 }
5228
5229 return(1);
5230}
5231
5232/**
5233 * xmlTextConcat:
5234 * @node: the node
5235 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005236 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005237 *
5238 * Concat the given string at the end of the existing node content
5239 */
5240
5241void
5242xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5243 if (node == NULL) return;
5244
5245 if ((node->type != XML_TEXT_NODE) &&
5246 (node->type != XML_CDATA_SECTION_NODE)) {
5247#ifdef DEBUG_TREE
5248 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005249 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005250#endif
5251 return;
5252 }
5253#ifndef XML_USE_BUFFER_CONTENT
5254 node->content = xmlStrncat(node->content, content, len);
5255#else
5256 xmlBufferAdd(node->content, content, len);
5257#endif
5258}
5259
5260/************************************************************************
5261 * *
5262 * Output : to a FILE or in memory *
5263 * *
5264 ************************************************************************/
5265
Owen Taylor3473f882001-02-23 17:55:21 +00005266/**
5267 * xmlBufferCreate:
5268 *
5269 * routine to create an XML buffer.
5270 * returns the new structure.
5271 */
5272xmlBufferPtr
5273xmlBufferCreate(void) {
5274 xmlBufferPtr ret;
5275
5276 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5277 if (ret == NULL) {
5278 xmlGenericError(xmlGenericErrorContext,
5279 "xmlBufferCreate : out of memory!\n");
5280 return(NULL);
5281 }
5282 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005283 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005284 ret->alloc = xmlBufferAllocScheme;
5285 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5286 if (ret->content == NULL) {
5287 xmlGenericError(xmlGenericErrorContext,
5288 "xmlBufferCreate : out of memory!\n");
5289 xmlFree(ret);
5290 return(NULL);
5291 }
5292 ret->content[0] = 0;
5293 return(ret);
5294}
5295
5296/**
5297 * xmlBufferCreateSize:
5298 * @size: initial size of buffer
5299 *
5300 * routine to create an XML buffer.
5301 * returns the new structure.
5302 */
5303xmlBufferPtr
5304xmlBufferCreateSize(size_t size) {
5305 xmlBufferPtr ret;
5306
5307 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5308 if (ret == NULL) {
5309 xmlGenericError(xmlGenericErrorContext,
5310 "xmlBufferCreate : out of memory!\n");
5311 return(NULL);
5312 }
5313 ret->use = 0;
5314 ret->alloc = xmlBufferAllocScheme;
5315 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5316 if (ret->size){
5317 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5318 if (ret->content == NULL) {
5319 xmlGenericError(xmlGenericErrorContext,
5320 "xmlBufferCreate : out of memory!\n");
5321 xmlFree(ret);
5322 return(NULL);
5323 }
5324 ret->content[0] = 0;
5325 } else
5326 ret->content = NULL;
5327 return(ret);
5328}
5329
5330/**
5331 * xmlBufferSetAllocationScheme:
5332 * @buf: the buffer to free
5333 * @scheme: allocation scheme to use
5334 *
5335 * Sets the allocation scheme for this buffer
5336 */
5337void
5338xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5339 xmlBufferAllocationScheme scheme) {
5340 if (buf == NULL) {
5341#ifdef DEBUG_BUFFER
5342 xmlGenericError(xmlGenericErrorContext,
5343 "xmlBufferSetAllocationScheme: buf == NULL\n");
5344#endif
5345 return;
5346 }
5347
5348 buf->alloc = scheme;
5349}
5350
5351/**
5352 * xmlBufferFree:
5353 * @buf: the buffer to free
5354 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005355 * Frees an XML buffer. It frees both the content and the structure which
5356 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005357 */
5358void
5359xmlBufferFree(xmlBufferPtr buf) {
5360 if (buf == NULL) {
5361#ifdef DEBUG_BUFFER
5362 xmlGenericError(xmlGenericErrorContext,
5363 "xmlBufferFree: buf == NULL\n");
5364#endif
5365 return;
5366 }
5367 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005368 xmlFree(buf->content);
5369 }
Owen Taylor3473f882001-02-23 17:55:21 +00005370 xmlFree(buf);
5371}
5372
5373/**
5374 * xmlBufferEmpty:
5375 * @buf: the buffer
5376 *
5377 * empty a buffer.
5378 */
5379void
5380xmlBufferEmpty(xmlBufferPtr buf) {
5381 if (buf->content == NULL) return;
5382 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005383 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005384}
5385
5386/**
5387 * xmlBufferShrink:
5388 * @buf: the buffer to dump
5389 * @len: the number of xmlChar to remove
5390 *
5391 * Remove the beginning of an XML buffer.
5392 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005393 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005394 */
5395int
5396xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5397 if (len == 0) return(0);
5398 if (len > buf->use) return(-1);
5399
5400 buf->use -= len;
5401 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5402
5403 buf->content[buf->use] = 0;
5404 return(len);
5405}
5406
5407/**
5408 * xmlBufferGrow:
5409 * @buf: the buffer
5410 * @len: the minimum free size to allocate
5411 *
5412 * Grow the available space of an XML buffer.
5413 *
5414 * Returns the new available space or -1 in case of error
5415 */
5416int
5417xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5418 int size;
5419 xmlChar *newbuf;
5420
5421 if (len + buf->use < buf->size) return(0);
5422
5423 size = buf->use + len + 100;
5424
5425 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5426 if (newbuf == NULL) return(-1);
5427 buf->content = newbuf;
5428 buf->size = size;
5429 return(buf->size - buf->use);
5430}
5431
5432/**
5433 * xmlBufferDump:
5434 * @file: the file output
5435 * @buf: the buffer to dump
5436 *
5437 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005438 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005439 */
5440int
5441xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5442 int ret;
5443
5444 if (buf == NULL) {
5445#ifdef DEBUG_BUFFER
5446 xmlGenericError(xmlGenericErrorContext,
5447 "xmlBufferDump: buf == NULL\n");
5448#endif
5449 return(0);
5450 }
5451 if (buf->content == NULL) {
5452#ifdef DEBUG_BUFFER
5453 xmlGenericError(xmlGenericErrorContext,
5454 "xmlBufferDump: buf->content == NULL\n");
5455#endif
5456 return(0);
5457 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005458 if (file == NULL)
5459 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005460 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5461 return(ret);
5462}
5463
5464/**
5465 * xmlBufferContent:
5466 * @buf: the buffer
5467 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005468 * Function to extract the content of a buffer
5469 *
Owen Taylor3473f882001-02-23 17:55:21 +00005470 * Returns the internal content
5471 */
5472
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005473const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005474xmlBufferContent(const xmlBufferPtr buf)
5475{
5476 if(!buf)
5477 return NULL;
5478
5479 return buf->content;
5480}
5481
5482/**
5483 * xmlBufferLength:
5484 * @buf: the buffer
5485 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005486 * Function to get the length of a buffer
5487 *
Owen Taylor3473f882001-02-23 17:55:21 +00005488 * Returns the length of data in the internal content
5489 */
5490
5491int
5492xmlBufferLength(const xmlBufferPtr buf)
5493{
5494 if(!buf)
5495 return 0;
5496
5497 return buf->use;
5498}
5499
5500/**
5501 * xmlBufferResize:
5502 * @buf: the buffer to resize
5503 * @size: the desired size
5504 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005505 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005506 *
5507 * Returns 0 in case of problems, 1 otherwise
5508 */
5509int
5510xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5511{
5512 unsigned int newSize;
5513 xmlChar* rebuf = NULL;
5514
5515 /*take care of empty case*/
5516 newSize = (buf->size ? buf->size*2 : size);
5517
5518 /* Don't resize if we don't have to */
5519 if (size < buf->size)
5520 return 1;
5521
5522 /* figure out new size */
5523 switch (buf->alloc){
5524 case XML_BUFFER_ALLOC_DOUBLEIT:
5525 while (size > newSize) newSize *= 2;
5526 break;
5527 case XML_BUFFER_ALLOC_EXACT:
5528 newSize = size+10;
5529 break;
5530 default:
5531 newSize = size+10;
5532 break;
5533 }
5534
5535 if (buf->content == NULL)
5536 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5537 else
5538 rebuf = (xmlChar *) xmlRealloc(buf->content,
5539 newSize * sizeof(xmlChar));
5540 if (rebuf == NULL) {
5541 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005542 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005543 return 0;
5544 }
5545 buf->content = rebuf;
5546 buf->size = newSize;
5547
5548 return 1;
5549}
5550
5551/**
5552 * xmlBufferAdd:
5553 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005554 * @str: the #xmlChar string
5555 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005556 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005557 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005558 * str is recomputed.
5559 */
5560void
5561xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5562 unsigned int needSize;
5563
5564 if (str == NULL) {
5565#ifdef DEBUG_BUFFER
5566 xmlGenericError(xmlGenericErrorContext,
5567 "xmlBufferAdd: str == NULL\n");
5568#endif
5569 return;
5570 }
5571 if (len < -1) {
5572#ifdef DEBUG_BUFFER
5573 xmlGenericError(xmlGenericErrorContext,
5574 "xmlBufferAdd: len < 0\n");
5575#endif
5576 return;
5577 }
5578 if (len == 0) return;
5579
5580 if (len < 0)
5581 len = xmlStrlen(str);
5582
5583 if (len <= 0) return;
5584
5585 needSize = buf->use + len + 2;
5586 if (needSize > buf->size){
5587 if (!xmlBufferResize(buf, needSize)){
5588 xmlGenericError(xmlGenericErrorContext,
5589 "xmlBufferAdd : out of memory!\n");
5590 return;
5591 }
5592 }
5593
5594 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5595 buf->use += len;
5596 buf->content[buf->use] = 0;
5597}
5598
5599/**
5600 * xmlBufferAddHead:
5601 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005602 * @str: the #xmlChar string
5603 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005604 *
5605 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005606 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005607 */
5608void
5609xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5610 unsigned int needSize;
5611
5612 if (str == NULL) {
5613#ifdef DEBUG_BUFFER
5614 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005615 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005616#endif
5617 return;
5618 }
5619 if (len < -1) {
5620#ifdef DEBUG_BUFFER
5621 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005622 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005623#endif
5624 return;
5625 }
5626 if (len == 0) return;
5627
5628 if (len < 0)
5629 len = xmlStrlen(str);
5630
5631 if (len <= 0) return;
5632
5633 needSize = buf->use + len + 2;
5634 if (needSize > buf->size){
5635 if (!xmlBufferResize(buf, needSize)){
5636 xmlGenericError(xmlGenericErrorContext,
5637 "xmlBufferAddHead : out of memory!\n");
5638 return;
5639 }
5640 }
5641
5642 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5643 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5644 buf->use += len;
5645 buf->content[buf->use] = 0;
5646}
5647
5648/**
5649 * xmlBufferCat:
5650 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005651 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005652 *
5653 * Append a zero terminated string to an XML buffer.
5654 */
5655void
5656xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5657 if (str != NULL)
5658 xmlBufferAdd(buf, str, -1);
5659}
5660
5661/**
5662 * xmlBufferCCat:
5663 * @buf: the buffer to dump
5664 * @str: the C char string
5665 *
5666 * Append a zero terminated C string to an XML buffer.
5667 */
5668void
5669xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5670 const char *cur;
5671
5672 if (str == NULL) {
5673#ifdef DEBUG_BUFFER
5674 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005675 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005676#endif
5677 return;
5678 }
5679 for (cur = str;*cur != 0;cur++) {
5680 if (buf->use + 10 >= buf->size) {
5681 if (!xmlBufferResize(buf, buf->use+10)){
5682 xmlGenericError(xmlGenericErrorContext,
5683 "xmlBufferCCat : out of memory!\n");
5684 return;
5685 }
5686 }
5687 buf->content[buf->use++] = *cur;
5688 }
5689 buf->content[buf->use] = 0;
5690}
5691
5692/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005693 * xmlBufferWriteXmlCHAR:
5694 * @buf: the XML buffer
5695 * @string: the string to add
5696 *
5697 * For VMS only.
5698 * routine which manages and grows an output buffer. This one adds
5699 * xmlChars at the end of the buffer.
5700 */
5701/**
Owen Taylor3473f882001-02-23 17:55:21 +00005702 * xmlBufferWriteCHAR:
5703 * @buf: the XML buffer
5704 * @string: the string to add
5705 *
5706 * routine which manages and grows an output buffer. This one adds
5707 * xmlChars at the end of the buffer.
5708 */
5709void
5710#ifdef VMS
5711xmlBufferWriteXmlCHAR
5712#else
5713xmlBufferWriteCHAR
5714#endif
5715(xmlBufferPtr buf, const xmlChar *string) {
5716 xmlBufferCat(buf, string);
5717}
5718
5719/**
5720 * xmlBufferWriteChar:
5721 * @buf: the XML buffer output
5722 * @string: the string to add
5723 *
5724 * routine which manage and grows an output buffer. This one add
5725 * C chars at the end of the array.
5726 */
5727void
5728xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5729 xmlBufferCCat(buf, string);
5730}
5731
5732
5733/**
5734 * xmlBufferWriteQuotedString:
5735 * @buf: the XML buffer output
5736 * @string: the string to add
5737 *
5738 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005739 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005740 * quote or double-quotes internally
5741 */
5742void
5743xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5744 if (xmlStrchr(string, '"')) {
5745 if (xmlStrchr(string, '\'')) {
5746#ifdef DEBUG_BUFFER
5747 xmlGenericError(xmlGenericErrorContext,
5748 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5749#endif
5750 }
5751 xmlBufferCCat(buf, "'");
5752 xmlBufferCat(buf, string);
5753 xmlBufferCCat(buf, "'");
5754 } else {
5755 xmlBufferCCat(buf, "\"");
5756 xmlBufferCat(buf, string);
5757 xmlBufferCCat(buf, "\"");
5758 }
5759}
5760
5761
5762/************************************************************************
5763 * *
5764 * Dumping XML tree content to a simple buffer *
5765 * *
5766 ************************************************************************/
5767
Owen Taylor3473f882001-02-23 17:55:21 +00005768static void
5769xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5770 int format);
5771void
5772htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5773
5774/**
5775 * xmlNsDump:
5776 * @buf: the XML buffer output
5777 * @cur: a namespace
5778 *
5779 * Dump a local Namespace definition.
5780 * Should be called in the context of attributes dumps.
5781 */
5782static void
5783xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5784 if (cur == NULL) {
5785#ifdef DEBUG_TREE
5786 xmlGenericError(xmlGenericErrorContext,
5787 "xmlNsDump : Ns == NULL\n");
5788#endif
5789 return;
5790 }
5791 if (cur->type == XML_LOCAL_NAMESPACE) {
5792 /* Within the context of an element attributes */
5793 if (cur->prefix != NULL) {
5794 xmlBufferWriteChar(buf, " xmlns:");
5795 xmlBufferWriteCHAR(buf, cur->prefix);
5796 } else
5797 xmlBufferWriteChar(buf, " xmlns");
5798 xmlBufferWriteChar(buf, "=");
5799 xmlBufferWriteQuotedString(buf, cur->href);
5800 }
5801}
5802
5803/**
5804 * xmlNsListDump:
5805 * @buf: the XML buffer output
5806 * @cur: the first namespace
5807 *
5808 * Dump a list of local Namespace definitions.
5809 * Should be called in the context of attributes dumps.
5810 */
5811static void
5812xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5813 while (cur != NULL) {
5814 xmlNsDump(buf, cur);
5815 cur = cur->next;
5816 }
5817}
5818
5819/**
5820 * xmlDtdDump:
5821 * @buf: the XML buffer output
Daniel Veillardd1640922001-12-17 15:30:10 +00005822 * @dtd: the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00005823 *
5824 * Dump the XML document DTD, if any.
5825 */
5826static void
5827xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5828 if (dtd == NULL) {
5829#ifdef DEBUG_TREE
5830 xmlGenericError(xmlGenericErrorContext,
5831 "xmlDtdDump : no internal subset\n");
5832#endif
5833 return;
5834 }
5835 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5836 xmlBufferWriteCHAR(buf, dtd->name);
5837 if (dtd->ExternalID != NULL) {
5838 xmlBufferWriteChar(buf, " PUBLIC ");
5839 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5840 xmlBufferWriteChar(buf, " ");
5841 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5842 } else if (dtd->SystemID != NULL) {
5843 xmlBufferWriteChar(buf, " SYSTEM ");
5844 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5845 }
5846 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5847 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5848 xmlBufferWriteChar(buf, ">");
5849 return;
5850 }
5851 xmlBufferWriteChar(buf, " [\n");
5852 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5853#if 0
5854 if (dtd->entities != NULL)
5855 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5856 if (dtd->notations != NULL)
5857 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5858 if (dtd->elements != NULL)
5859 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5860 if (dtd->attributes != NULL)
5861 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5862#endif
5863 xmlBufferWriteChar(buf, "]>");
5864}
5865
5866/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00005867 * xmlAttrSerializeContent:
5868 * @buf: the XML buffer output
5869 * @doc: the document
5870 * @attr: the attribute pointer
5871 *
5872 * Serialize the attribute in the buffer
5873 */
5874static void
5875xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr) {
5876 const xmlChar *cur, *base;
5877 xmlNodePtr children;
5878
5879 children = attr->children;
5880 while (children != NULL) {
5881 switch (children->type) {
5882 case XML_TEXT_NODE:
5883 base = cur = children->content;
5884 while (*cur != 0) {
5885 if (*cur == '\n') {
5886 if (base != cur)
5887 xmlBufferAdd(buf, base, cur - base);
5888 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
5889 cur++;
5890 base = cur;
5891#if 0
5892 } else if (*cur == '\'') {
5893 if (base != cur)
5894 xmlBufferAdd(buf, base, cur - base);
5895 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
5896 cur++;
5897 base = cur;
5898#endif
5899 } else if (*cur == '"') {
5900 if (base != cur)
5901 xmlBufferAdd(buf, base, cur - base);
5902 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
5903 cur++;
5904 base = cur;
5905 } else if (*cur == '<') {
5906 if (base != cur)
5907 xmlBufferAdd(buf, base, cur - base);
5908 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
5909 cur++;
5910 base = cur;
5911 } else if (*cur == '>') {
5912 if (base != cur)
5913 xmlBufferAdd(buf, base, cur - base);
5914 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
5915 cur++;
5916 base = cur;
5917 } else if (*cur == '&') {
5918 if (base != cur)
5919 xmlBufferAdd(buf, base, cur - base);
5920 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
5921 cur++;
5922 base = cur;
5923 } else if ((*cur >= 0x80) && ((doc == NULL) ||
5924 (doc->encoding == NULL))) {
5925 /*
5926 * We assume we have UTF-8 content.
5927 */
5928 char tmp[10];
5929 int val = 0, l = 1;
5930
5931 if (base != cur)
5932 xmlBufferAdd(buf, base, cur - base);
5933 if (*cur < 0xC0) {
5934 xmlGenericError(xmlGenericErrorContext,
5935 "xmlAttrSerializeContent : input not UTF-8\n");
5936 if (doc != NULL)
5937 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
5938 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
5939 tmp[sizeof(tmp) - 1] = 0;
5940 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
5941 cur++;
5942 base = cur;
5943 continue;
5944 } else if (*cur < 0xE0) {
5945 val = (cur[0]) & 0x1F;
5946 val <<= 6;
5947 val |= (cur[1]) & 0x3F;
5948 l = 2;
5949 } else if (*cur < 0xF0) {
5950 val = (cur[0]) & 0x0F;
5951 val <<= 6;
5952 val |= (cur[1]) & 0x3F;
5953 val <<= 6;
5954 val |= (cur[2]) & 0x3F;
5955 l = 3;
5956 } else if (*cur < 0xF8) {
5957 val = (cur[0]) & 0x07;
5958 val <<= 6;
5959 val |= (cur[1]) & 0x3F;
5960 val <<= 6;
5961 val |= (cur[2]) & 0x3F;
5962 val <<= 6;
5963 val |= (cur[3]) & 0x3F;
5964 l = 4;
5965 }
5966 if ((l == 1) || (!IS_CHAR(val))) {
5967 xmlGenericError(xmlGenericErrorContext,
5968 "xmlAttrSerializeContent : char out of range\n");
5969 if (doc != NULL)
5970 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
5971 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
5972 tmp[sizeof(tmp) - 1] = 0;
5973 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
5974 cur++;
5975 base = cur;
5976 continue;
5977 }
5978 /*
5979 * We could do multiple things here. Just save
5980 * as a char ref
5981 */
5982 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
5983 tmp[sizeof(tmp) - 1] = 0;
5984 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
5985 cur += l;
5986 base = cur;
5987 } else {
5988 cur++;
5989 }
5990 }
5991 if (base != cur)
5992 xmlBufferAdd(buf, base, cur - base);
5993 break;
5994 case XML_ENTITY_REF_NODE:
5995 xmlBufferAdd(buf, BAD_CAST "&", 1);
5996 xmlBufferAdd(buf, children->name, xmlStrlen(children->name));
5997 xmlBufferAdd(buf, BAD_CAST ";", 1);
5998 break;
5999 default:
6000 /* should not happen unless we have a badly built tree */
6001 break;
6002 }
6003 children = children->next;
6004 }
6005}
6006
6007/**
Owen Taylor3473f882001-02-23 17:55:21 +00006008 * xmlAttrDump:
6009 * @buf: the XML buffer output
6010 * @doc: the document
6011 * @cur: the attribute pointer
6012 *
6013 * Dump an XML attribute
6014 */
6015static void
6016xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00006017 if (cur == NULL) {
6018#ifdef DEBUG_TREE
6019 xmlGenericError(xmlGenericErrorContext,
6020 "xmlAttrDump : property == NULL\n");
6021#endif
6022 return;
6023 }
6024 xmlBufferWriteChar(buf, " ");
6025 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6026 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6027 xmlBufferWriteChar(buf, ":");
6028 }
6029 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006030 xmlBufferWriteChar(buf, "=\"");
6031 xmlAttrSerializeContent(buf, doc, cur);
6032 xmlBufferWriteChar(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006033}
6034
6035/**
6036 * xmlAttrListDump:
6037 * @buf: the XML buffer output
6038 * @doc: the document
6039 * @cur: the first attribute pointer
6040 *
6041 * Dump a list of XML attributes
6042 */
6043static void
6044xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
6045 if (cur == NULL) {
6046#ifdef DEBUG_TREE
6047 xmlGenericError(xmlGenericErrorContext,
6048 "xmlAttrListDump : property == NULL\n");
6049#endif
6050 return;
6051 }
6052 while (cur != NULL) {
6053 xmlAttrDump(buf, doc, cur);
6054 cur = cur->next;
6055 }
6056}
6057
6058
6059
6060/**
6061 * xmlNodeListDump:
6062 * @buf: the XML buffer output
6063 * @doc: the document
6064 * @cur: the first node
6065 * @level: the imbrication level for indenting
6066 * @format: is formatting allowed
6067 *
6068 * Dump an XML node list, recursive behaviour,children are printed too.
6069 */
6070static void
6071xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
6072 int format) {
6073 int i;
6074
6075 if (cur == NULL) {
6076#ifdef DEBUG_TREE
6077 xmlGenericError(xmlGenericErrorContext,
6078 "xmlNodeListDump : node == NULL\n");
6079#endif
6080 return;
6081 }
6082 while (cur != NULL) {
6083 if ((format) && (xmlIndentTreeOutput) &&
6084 (cur->type == XML_ELEMENT_NODE))
6085 for (i = 0;i < level;i++)
6086 xmlBufferWriteChar(buf, " ");
6087 xmlNodeDump(buf, doc, cur, level, format);
6088 if (format) {
6089 xmlBufferWriteChar(buf, "\n");
6090 }
6091 cur = cur->next;
6092 }
6093}
6094
6095/**
6096 * xmlNodeDump:
6097 * @buf: the XML buffer output
6098 * @doc: the document
6099 * @cur: the current node
6100 * @level: the imbrication level for indenting
6101 * @format: is formatting allowed
6102 *
6103 * Dump an XML node, recursive behaviour,children are printed too.
6104 */
6105void
6106xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
6107 int format) {
6108 int i;
6109 xmlNodePtr tmp;
6110
6111 if (cur == NULL) {
6112#ifdef DEBUG_TREE
6113 xmlGenericError(xmlGenericErrorContext,
6114 "xmlNodeDump : node == NULL\n");
6115#endif
6116 return;
6117 }
6118 if (cur->type == XML_XINCLUDE_START)
6119 return;
6120 if (cur->type == XML_XINCLUDE_END)
6121 return;
6122 if (cur->type == XML_DTD_NODE) {
6123 xmlDtdDump(buf, (xmlDtdPtr) cur);
6124 return;
6125 }
6126 if (cur->type == XML_ELEMENT_DECL) {
6127 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
6128 return;
6129 }
Daniel Veillard78d12092001-10-11 09:12:24 +00006130 if (cur->type == XML_ATTRIBUTE_NODE){
6131 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
6132 return;
6133 }
Owen Taylor3473f882001-02-23 17:55:21 +00006134 if (cur->type == XML_ATTRIBUTE_DECL) {
6135 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
6136 return;
6137 }
6138 if (cur->type == XML_ENTITY_DECL) {
6139 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
6140 return;
6141 }
6142 if (cur->type == XML_TEXT_NODE) {
6143 if (cur->content != NULL) {
6144 if ((cur->name == xmlStringText) ||
6145 (cur->name != xmlStringTextNoenc)) {
6146 xmlChar *buffer;
6147
6148#ifndef XML_USE_BUFFER_CONTENT
6149 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6150#else
6151 buffer = xmlEncodeEntitiesReentrant(doc,
6152 xmlBufferContent(cur->content));
6153#endif
6154 if (buffer != NULL) {
6155 xmlBufferWriteCHAR(buf, buffer);
6156 xmlFree(buffer);
6157 }
6158 } else {
6159 /*
6160 * Disable escaping, needed for XSLT
6161 */
6162#ifndef XML_USE_BUFFER_CONTENT
6163 xmlBufferWriteCHAR(buf, cur->content);
6164#else
6165 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
6166#endif
6167 }
6168 }
6169 return;
6170 }
6171 if (cur->type == XML_PI_NODE) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00006172 xmlBufferWriteChar(buf, "<?");
6173 xmlBufferWriteCHAR(buf, cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006174 if (cur->content != NULL) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00006175 xmlBufferWriteChar(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006176#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard2c748c62002-01-16 15:37:50 +00006177 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006178#else
Daniel Veillard2c748c62002-01-16 15:37:50 +00006179 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00006180#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006181 }
Daniel Veillard2c748c62002-01-16 15:37:50 +00006182 xmlBufferWriteChar(buf, "?>");
Owen Taylor3473f882001-02-23 17:55:21 +00006183 return;
6184 }
6185 if (cur->type == XML_COMMENT_NODE) {
6186 if (cur->content != NULL) {
6187 xmlBufferWriteChar(buf, "<!--");
6188#ifndef XML_USE_BUFFER_CONTENT
6189 xmlBufferWriteCHAR(buf, cur->content);
6190#else
6191 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
6192#endif
6193 xmlBufferWriteChar(buf, "-->");
6194 }
6195 return;
6196 }
6197 if (cur->type == XML_ENTITY_REF_NODE) {
6198 xmlBufferWriteChar(buf, "&");
6199 xmlBufferWriteCHAR(buf, cur->name);
6200 xmlBufferWriteChar(buf, ";");
6201 return;
6202 }
6203 if (cur->type == XML_CDATA_SECTION_NODE) {
6204 xmlBufferWriteChar(buf, "<![CDATA[");
6205 if (cur->content != NULL)
6206#ifndef XML_USE_BUFFER_CONTENT
6207 xmlBufferWriteCHAR(buf, cur->content);
6208#else
6209 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
6210#endif
6211 xmlBufferWriteChar(buf, "]]>");
6212 return;
6213 }
6214
6215 if (format == 1) {
6216 tmp = cur->children;
6217 while (tmp != NULL) {
6218 if ((tmp->type == XML_TEXT_NODE) ||
6219 (tmp->type == XML_ENTITY_REF_NODE)) {
6220 format = 0;
6221 break;
6222 }
6223 tmp = tmp->next;
6224 }
6225 }
6226 xmlBufferWriteChar(buf, "<");
6227 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6228 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6229 xmlBufferWriteChar(buf, ":");
6230 }
6231
6232 xmlBufferWriteCHAR(buf, cur->name);
6233 if (cur->nsDef)
6234 xmlNsListDump(buf, cur->nsDef);
6235 if (cur->properties != NULL)
6236 xmlAttrListDump(buf, doc, cur->properties);
6237
Daniel Veillard7db37732001-07-12 01:20:08 +00006238 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6239 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00006240 (!xmlSaveNoEmptyTags)) {
6241 xmlBufferWriteChar(buf, "/>");
6242 return;
6243 }
6244 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006245 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006246 xmlChar *buffer;
6247
6248#ifndef XML_USE_BUFFER_CONTENT
6249 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6250#else
6251 buffer = xmlEncodeEntitiesReentrant(doc,
6252 xmlBufferContent(cur->content));
6253#endif
6254 if (buffer != NULL) {
6255 xmlBufferWriteCHAR(buf, buffer);
6256 xmlFree(buffer);
6257 }
6258 }
6259 if (cur->children != NULL) {
6260 if (format) xmlBufferWriteChar(buf, "\n");
6261 xmlNodeListDump(buf, doc, cur->children,
6262 (level >= 0?level+1:-1), format);
6263 if ((xmlIndentTreeOutput) && (format))
6264 for (i = 0;i < level;i++)
6265 xmlBufferWriteChar(buf, " ");
6266 }
6267 xmlBufferWriteChar(buf, "</");
6268 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6269 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6270 xmlBufferWriteChar(buf, ":");
6271 }
6272
6273 xmlBufferWriteCHAR(buf, cur->name);
6274 xmlBufferWriteChar(buf, ">");
6275}
6276
6277/**
6278 * xmlElemDump:
6279 * @f: the FILE * for the output
6280 * @doc: the document
6281 * @cur: the current node
6282 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006283 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006284 */
6285void
6286xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
6287 xmlBufferPtr buf;
6288
6289 if (cur == NULL) {
6290#ifdef DEBUG_TREE
6291 xmlGenericError(xmlGenericErrorContext,
6292 "xmlElemDump : cur == NULL\n");
6293#endif
6294 return;
6295 }
Owen Taylor3473f882001-02-23 17:55:21 +00006296#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006297 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006298 xmlGenericError(xmlGenericErrorContext,
6299 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006300 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006301#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00006302
Owen Taylor3473f882001-02-23 17:55:21 +00006303 buf = xmlBufferCreate();
6304 if (buf == NULL) return;
6305 if ((doc != NULL) &&
6306 (doc->type == XML_HTML_DOCUMENT_NODE)) {
6307#ifdef LIBXML_HTML_ENABLED
6308 htmlNodeDump(buf, doc, cur);
6309#else
6310 xmlGenericError(xmlGenericErrorContext,
6311 "HTML support not compiled in\n");
6312#endif /* LIBXML_HTML_ENABLED */
6313 } else
6314 xmlNodeDump(buf, doc, cur, 0, 1);
6315 xmlBufferDump(f, buf);
6316 xmlBufferFree(buf);
6317}
6318
6319/************************************************************************
6320 * *
6321 * Dumping XML tree content to an I/O output buffer *
6322 * *
6323 ************************************************************************/
6324
Owen Taylor3473f882001-02-23 17:55:21 +00006325static void
6326xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6327 int level, int format, const char *encoding);
6328/**
6329 * xmlNsDumpOutput:
6330 * @buf: the XML buffer output
6331 * @cur: a namespace
6332 *
6333 * Dump a local Namespace definition.
6334 * Should be called in the context of attributes dumps.
6335 */
6336static void
6337xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6338 if (cur == NULL) {
6339#ifdef DEBUG_TREE
6340 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006341 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006342#endif
6343 return;
6344 }
6345 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
6346 /* Within the context of an element attributes */
6347 if (cur->prefix != NULL) {
6348 xmlOutputBufferWriteString(buf, " xmlns:");
6349 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6350 } else
6351 xmlOutputBufferWriteString(buf, " xmlns");
6352 xmlOutputBufferWriteString(buf, "=");
6353 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6354 }
6355}
6356
6357/**
6358 * xmlNsListDumpOutput:
6359 * @buf: the XML buffer output
6360 * @cur: the first namespace
6361 *
6362 * Dump a list of local Namespace definitions.
6363 * Should be called in the context of attributes dumps.
6364 */
6365static void
6366xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6367 while (cur != NULL) {
6368 xmlNsDumpOutput(buf, cur);
6369 cur = cur->next;
6370 }
6371}
6372
6373/**
6374 * xmlDtdDumpOutput:
6375 * @buf: the XML buffer output
6376 * @doc: the document
6377 * @encoding: an optional encoding string
6378 *
6379 * Dump the XML document DTD, if any.
6380 */
6381static void
6382xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6383 if (dtd == NULL) {
6384#ifdef DEBUG_TREE
6385 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006386 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006387#endif
6388 return;
6389 }
6390 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6391 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6392 if (dtd->ExternalID != NULL) {
6393 xmlOutputBufferWriteString(buf, " PUBLIC ");
6394 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6395 xmlOutputBufferWriteString(buf, " ");
6396 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6397 } else if (dtd->SystemID != NULL) {
6398 xmlOutputBufferWriteString(buf, " SYSTEM ");
6399 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6400 }
6401 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6402 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6403 xmlOutputBufferWriteString(buf, ">");
6404 return;
6405 }
6406 xmlOutputBufferWriteString(buf, " [\n");
6407 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6408 xmlOutputBufferWriteString(buf, "]>");
6409}
6410
6411/**
6412 * xmlAttrDumpOutput:
6413 * @buf: the XML buffer output
6414 * @doc: the document
6415 * @cur: the attribute pointer
6416 * @encoding: an optional encoding string
6417 *
6418 * Dump an XML attribute
6419 */
6420static void
6421xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006422 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006423 if (cur == NULL) {
6424#ifdef DEBUG_TREE
6425 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006426 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006427#endif
6428 return;
6429 }
6430 xmlOutputBufferWriteString(buf, " ");
6431 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6432 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6433 xmlOutputBufferWriteString(buf, ":");
6434 }
6435 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006436 xmlOutputBufferWriteString(buf, "=\"");
6437 xmlAttrSerializeContent(buf->buffer, doc, cur);
6438 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006439}
6440
6441/**
6442 * xmlAttrListDumpOutput:
6443 * @buf: the XML buffer output
6444 * @doc: the document
6445 * @cur: the first attribute pointer
6446 * @encoding: an optional encoding string
6447 *
6448 * Dump a list of XML attributes
6449 */
6450static void
6451xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6452 xmlAttrPtr cur, const char *encoding) {
6453 if (cur == NULL) {
6454#ifdef DEBUG_TREE
6455 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006456 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006457#endif
6458 return;
6459 }
6460 while (cur != NULL) {
6461 xmlAttrDumpOutput(buf, doc, cur, encoding);
6462 cur = cur->next;
6463 }
6464}
6465
6466
6467
6468/**
6469 * xmlNodeListDumpOutput:
6470 * @buf: the XML buffer output
6471 * @doc: the document
6472 * @cur: the first node
6473 * @level: the imbrication level for indenting
6474 * @format: is formatting allowed
6475 * @encoding: an optional encoding string
6476 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006477 * Dump an XML node list, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006478 */
6479static void
6480xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6481 xmlNodePtr cur, int level, int format, const char *encoding) {
6482 int i;
6483
6484 if (cur == NULL) {
6485#ifdef DEBUG_TREE
6486 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006487 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006488#endif
6489 return;
6490 }
6491 while (cur != NULL) {
6492 if ((format) && (xmlIndentTreeOutput) &&
6493 (cur->type == XML_ELEMENT_NODE))
6494 for (i = 0;i < level;i++)
6495 xmlOutputBufferWriteString(buf, " ");
6496 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6497 if (format) {
6498 xmlOutputBufferWriteString(buf, "\n");
6499 }
6500 cur = cur->next;
6501 }
6502}
6503
6504/**
6505 * xmlNodeDumpOutput:
6506 * @buf: the XML buffer output
6507 * @doc: the document
6508 * @cur: the current node
6509 * @level: the imbrication level for indenting
6510 * @format: is formatting allowed
6511 * @encoding: an optional encoding string
6512 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006513 * Dump an XML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006514 */
6515void
6516xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6517 int level, int format, const char *encoding) {
6518 int i;
6519 xmlNodePtr tmp;
6520
6521 if (cur == NULL) {
6522#ifdef DEBUG_TREE
6523 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006524 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006525#endif
6526 return;
6527 }
6528 if (cur->type == XML_XINCLUDE_START)
6529 return;
6530 if (cur->type == XML_XINCLUDE_END)
6531 return;
6532 if (cur->type == XML_DTD_NODE) {
6533 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6534 return;
6535 }
6536 if (cur->type == XML_ELEMENT_DECL) {
6537 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6538 return;
6539 }
6540 if (cur->type == XML_ATTRIBUTE_DECL) {
6541 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6542 return;
6543 }
6544 if (cur->type == XML_ENTITY_DECL) {
6545 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6546 return;
6547 }
6548 if (cur->type == XML_TEXT_NODE) {
6549 if (cur->content != NULL) {
6550 if ((cur->name == xmlStringText) ||
6551 (cur->name != xmlStringTextNoenc)) {
6552 xmlChar *buffer;
6553
6554#ifndef XML_USE_BUFFER_CONTENT
6555 if (encoding == NULL)
6556 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6557 else
6558 buffer = xmlEncodeSpecialChars(doc, cur->content);
6559#else
6560 if (encoding == NULL)
6561 buffer = xmlEncodeEntitiesReentrant(doc,
6562 xmlBufferContent(cur->content));
6563 else
6564 buffer = xmlEncodeSpecialChars(doc,
6565 xmlBufferContent(cur->content));
6566#endif
6567 if (buffer != NULL) {
6568 xmlOutputBufferWriteString(buf, (const char *)buffer);
6569 xmlFree(buffer);
6570 }
6571 } else {
6572 /*
6573 * Disable escaping, needed for XSLT
6574 */
6575#ifndef XML_USE_BUFFER_CONTENT
6576 xmlOutputBufferWriteString(buf, (const char *) cur->content);
6577#else
6578 xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content));
6579#endif
6580 }
6581 }
6582
6583 return;
6584 }
6585 if (cur->type == XML_PI_NODE) {
6586 if (cur->content != NULL) {
6587 xmlOutputBufferWriteString(buf, "<?");
6588 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6589 if (cur->content != NULL) {
6590 xmlOutputBufferWriteString(buf, " ");
6591#ifndef XML_USE_BUFFER_CONTENT
6592 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6593#else
6594 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6595#endif
6596 }
6597 xmlOutputBufferWriteString(buf, "?>");
6598 } else {
6599 xmlOutputBufferWriteString(buf, "<?");
6600 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6601 xmlOutputBufferWriteString(buf, "?>");
6602 }
6603 return;
6604 }
6605 if (cur->type == XML_COMMENT_NODE) {
6606 if (cur->content != NULL) {
6607 xmlOutputBufferWriteString(buf, "<!--");
6608#ifndef XML_USE_BUFFER_CONTENT
6609 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6610#else
6611 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6612#endif
6613 xmlOutputBufferWriteString(buf, "-->");
6614 }
6615 return;
6616 }
6617 if (cur->type == XML_ENTITY_REF_NODE) {
6618 xmlOutputBufferWriteString(buf, "&");
6619 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6620 xmlOutputBufferWriteString(buf, ";");
6621 return;
6622 }
6623 if (cur->type == XML_CDATA_SECTION_NODE) {
6624 xmlOutputBufferWriteString(buf, "<![CDATA[");
6625 if (cur->content != NULL)
6626#ifndef XML_USE_BUFFER_CONTENT
6627 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6628#else
6629 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6630#endif
6631 xmlOutputBufferWriteString(buf, "]]>");
6632 return;
6633 }
6634
6635 if (format == 1) {
6636 tmp = cur->children;
6637 while (tmp != NULL) {
6638 if ((tmp->type == XML_TEXT_NODE) ||
6639 (tmp->type == XML_ENTITY_REF_NODE)) {
6640 format = 0;
6641 break;
6642 }
6643 tmp = tmp->next;
6644 }
6645 }
6646 xmlOutputBufferWriteString(buf, "<");
6647 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6648 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6649 xmlOutputBufferWriteString(buf, ":");
6650 }
6651
6652 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6653 if (cur->nsDef)
6654 xmlNsListDumpOutput(buf, cur->nsDef);
6655 if (cur->properties != NULL)
6656 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6657
Daniel Veillard7db37732001-07-12 01:20:08 +00006658 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6659 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006660 xmlOutputBufferWriteString(buf, "/>");
6661 return;
6662 }
6663 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006664 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006665 xmlChar *buffer;
6666
6667#ifndef XML_USE_BUFFER_CONTENT
6668 if (encoding == NULL)
6669 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6670 else
6671 buffer = xmlEncodeSpecialChars(doc, cur->content);
6672#else
6673 if (encoding == NULL)
6674 buffer = xmlEncodeEntitiesReentrant(doc,
6675 xmlBufferContent(cur->content));
6676 else
6677 buffer = xmlEncodeSpecialChars(doc,
6678 xmlBufferContent(cur->content));
6679#endif
6680 if (buffer != NULL) {
6681 xmlOutputBufferWriteString(buf, (const char *)buffer);
6682 xmlFree(buffer);
6683 }
6684 }
6685 if (cur->children != NULL) {
6686 if (format) xmlOutputBufferWriteString(buf, "\n");
6687 xmlNodeListDumpOutput(buf, doc, cur->children,
6688 (level >= 0?level+1:-1), format, encoding);
6689 if ((xmlIndentTreeOutput) && (format))
6690 for (i = 0;i < level;i++)
6691 xmlOutputBufferWriteString(buf, " ");
6692 }
6693 xmlOutputBufferWriteString(buf, "</");
6694 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6695 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6696 xmlOutputBufferWriteString(buf, ":");
6697 }
6698
6699 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6700 xmlOutputBufferWriteString(buf, ">");
6701}
6702
6703/**
6704 * xmlDocContentDumpOutput:
6705 * @buf: the XML buffer output
6706 * @cur: the document
6707 * @encoding: an optional encoding string
6708 * @format: should formatting spaces been added
6709 *
6710 * Dump an XML document.
6711 */
6712static void
6713xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6714 const char *encoding, int format) {
6715 xmlOutputBufferWriteString(buf, "<?xml version=");
6716 if (cur->version != NULL)
6717 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6718 else
6719 xmlOutputBufferWriteString(buf, "\"1.0\"");
6720 if (encoding == NULL) {
6721 if (cur->encoding != NULL)
6722 encoding = (const char *) cur->encoding;
6723 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6724 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6725 }
6726 if (encoding != NULL) {
6727 xmlOutputBufferWriteString(buf, " encoding=");
6728 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6729 }
6730 switch (cur->standalone) {
6731 case 0:
6732 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6733 break;
6734 case 1:
6735 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6736 break;
6737 }
6738 xmlOutputBufferWriteString(buf, "?>\n");
6739 if (cur->children != NULL) {
6740 xmlNodePtr child = cur->children;
6741
6742 while (child != NULL) {
6743 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6744 xmlOutputBufferWriteString(buf, "\n");
6745 child = child->next;
6746 }
6747 }
6748}
6749
6750/************************************************************************
6751 * *
6752 * Saving functions front-ends *
6753 * *
6754 ************************************************************************/
6755
6756/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006757 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006758 * @out_doc: Document to generate XML text from
6759 * @doc_txt_ptr: Memory pointer for allocated XML text
6760 * @doc_txt_len: Length of the generated XML text
6761 * @txt_encoding: Character encoding to use when generating XML text
6762 * @format: should formatting spaces been added
6763 *
6764 * Dump the current DOM tree into memory using the character encoding specified
6765 * by the caller. Note it is up to the caller of this function to free the
6766 * allocated memory.
6767 */
6768
6769void
6770xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006771 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006772 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006773 int dummy = 0;
6774
6775 xmlCharEncoding doc_charset;
6776 xmlOutputBufferPtr out_buff = NULL;
6777 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6778
6779 if (doc_txt_len == NULL) {
6780 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6781 }
6782
6783 if (doc_txt_ptr == NULL) {
6784 *doc_txt_len = 0;
6785 xmlGenericError(xmlGenericErrorContext,
6786 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6787 return;
6788 }
6789
6790 *doc_txt_ptr = NULL;
6791 *doc_txt_len = 0;
6792
6793 if (out_doc == NULL) {
6794 /* No document, no output */
6795 xmlGenericError(xmlGenericErrorContext,
6796 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6797 return;
6798 }
6799
6800 /*
6801 * Validate the encoding value, if provided.
6802 * This logic is copied from xmlSaveFileEnc.
6803 */
6804
6805 if (txt_encoding == NULL)
6806 txt_encoding = (const char *) out_doc->encoding;
6807 if (txt_encoding != NULL) {
6808 doc_charset = xmlParseCharEncoding(txt_encoding);
6809
6810 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6811 xmlGenericError(xmlGenericErrorContext,
6812 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6813 return;
6814
6815 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6816 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6817 if ( conv_hdlr == NULL ) {
6818 xmlGenericError(xmlGenericErrorContext,
6819 "%s: %s %s '%s'\n",
6820 "xmlDocDumpFormatMemoryEnc",
6821 "Failed to identify encoding handler for",
6822 "character set",
6823 txt_encoding);
6824 return;
6825 }
6826 }
6827 }
6828
6829 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6830 xmlGenericError(xmlGenericErrorContext,
6831 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6832 return;
6833 }
6834
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006835 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006836 xmlOutputBufferFlush(out_buff);
6837 if (out_buff->conv != NULL) {
6838 *doc_txt_len = out_buff->conv->use;
6839 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6840 } else {
6841 *doc_txt_len = out_buff->buffer->use;
6842 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6843 }
6844 (void)xmlOutputBufferClose(out_buff);
6845
6846 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6847 *doc_txt_len = 0;
6848 xmlGenericError(xmlGenericErrorContext,
6849 "xmlDocDumpFormatMemoryEnc: %s\n",
6850 "Failed to allocate memory for document text representation.");
6851 }
6852
6853 return;
6854}
6855
6856/**
6857 * xmlDocDumpMemory:
6858 * @cur: the document
6859 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006860 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006861 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006862 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006863 * It's up to the caller to free the memory.
6864 */
6865void
6866xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6867 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6868}
6869
6870/**
6871 * xmlDocDumpFormatMemory:
6872 * @cur: the document
6873 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006874 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006875 * @format: should formatting spaces been added
6876 *
6877 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006878 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006879 * It's up to the caller to free the memory.
6880 */
6881void
6882xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6883 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6884}
6885
6886/**
6887 * xmlDocDumpMemoryEnc:
6888 * @out_doc: Document to generate XML text from
6889 * @doc_txt_ptr: Memory pointer for allocated XML text
6890 * @doc_txt_len: Length of the generated XML text
6891 * @txt_encoding: Character encoding to use when generating XML text
6892 *
6893 * Dump the current DOM tree into memory using the character encoding specified
6894 * by the caller. Note it is up to the caller of this function to free the
6895 * allocated memory.
6896 */
6897
6898void
6899xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6900 int * doc_txt_len, const char * txt_encoding) {
6901 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006902 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006903}
6904
6905/**
6906 * xmlGetDocCompressMode:
6907 * @doc: the document
6908 *
6909 * get the compression ratio for a document, ZLIB based
6910 * Returns 0 (uncompressed) to 9 (max compression)
6911 */
6912int
6913xmlGetDocCompressMode (xmlDocPtr doc) {
6914 if (doc == NULL) return(-1);
6915 return(doc->compression);
6916}
6917
6918/**
6919 * xmlSetDocCompressMode:
6920 * @doc: the document
6921 * @mode: the compression ratio
6922 *
6923 * set the compression ratio for a document, ZLIB based
6924 * Correct values: 0 (uncompressed) to 9 (max compression)
6925 */
6926void
6927xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6928 if (doc == NULL) return;
6929 if (mode < 0) doc->compression = 0;
6930 else if (mode > 9) doc->compression = 9;
6931 else doc->compression = mode;
6932}
6933
6934/**
6935 * xmlGetCompressMode:
6936 *
6937 * get the default compression mode used, ZLIB based.
6938 * Returns 0 (uncompressed) to 9 (max compression)
6939 */
6940int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00006941xmlGetCompressMode(void)
6942{
6943 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00006944}
6945
6946/**
6947 * xmlSetCompressMode:
6948 * @mode: the compression ratio
6949 *
6950 * set the default compression mode used, ZLIB based
6951 * Correct values: 0 (uncompressed) to 9 (max compression)
6952 */
6953void
6954xmlSetCompressMode(int mode) {
6955 if (mode < 0) xmlCompressMode = 0;
6956 else if (mode > 9) xmlCompressMode = 9;
6957 else xmlCompressMode = mode;
6958}
6959
6960/**
6961 * xmlDocDump:
6962 * @f: the FILE*
6963 * @cur: the document
6964 *
6965 * Dump an XML document to an open FILE.
6966 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006967 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006968 */
6969int
6970xmlDocDump(FILE *f, xmlDocPtr cur) {
6971 xmlOutputBufferPtr buf;
6972 const char * encoding;
6973 xmlCharEncodingHandlerPtr handler = NULL;
6974 int ret;
6975
6976 if (cur == NULL) {
6977#ifdef DEBUG_TREE
6978 xmlGenericError(xmlGenericErrorContext,
6979 "xmlDocDump : document == NULL\n");
6980#endif
6981 return(-1);
6982 }
6983 encoding = (const char *) cur->encoding;
6984
6985 if (encoding != NULL) {
6986 xmlCharEncoding enc;
6987
6988 enc = xmlParseCharEncoding(encoding);
6989
6990 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6991 xmlGenericError(xmlGenericErrorContext,
6992 "xmlDocDump: document not in UTF8\n");
6993 return(-1);
6994 }
6995 if (enc != XML_CHAR_ENCODING_UTF8) {
6996 handler = xmlFindCharEncodingHandler(encoding);
6997 if (handler == NULL) {
6998 xmlFree((char *) cur->encoding);
6999 cur->encoding = NULL;
7000 }
7001 }
7002 }
7003 buf = xmlOutputBufferCreateFile(f, handler);
7004 if (buf == NULL) return(-1);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007005 xmlDocContentDumpOutput(buf, cur, NULL, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007006
7007 ret = xmlOutputBufferClose(buf);
7008 return(ret);
7009}
7010
7011/**
7012 * xmlSaveFileTo:
7013 * @buf: an output I/O buffer
7014 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007015 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00007016 *
7017 * Dump an XML document to an I/O buffer.
7018 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007019 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007020 */
7021int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007022xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007023 int ret;
7024
7025 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007026 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007027 ret = xmlOutputBufferClose(buf);
7028 return(ret);
7029}
7030
7031/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00007032 * xmlSaveFormatFileTo:
7033 * @buf: an output I/O buffer
7034 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007035 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00007036 * @format: should formatting spaces been added
7037 *
7038 * Dump an XML document to an I/O buffer.
7039 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007040 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00007041 */
7042int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007043xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00007044 int ret;
7045
7046 if (buf == NULL) return(0);
7047 xmlDocContentDumpOutput(buf, cur, encoding, format);
7048 ret = xmlOutputBufferClose(buf);
7049 return(ret);
7050}
7051
7052/**
Daniel Veillardf012a642001-07-23 19:10:52 +00007053 * xmlSaveFormatFileEnc
7054 * @filename: the filename or URL to output
7055 * @cur: the document being saved
7056 * @encoding: the name of the encoding to use or NULL.
7057 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00007058 *
7059 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00007060 */
7061int
Daniel Veillardf012a642001-07-23 19:10:52 +00007062xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
7063 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00007064 xmlOutputBufferPtr buf;
7065 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00007066 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00007067 int ret;
7068
Daniel Veillardfb25a512002-01-13 20:32:08 +00007069 if (encoding == NULL)
7070 encoding = (const char *) cur->encoding;
7071
Owen Taylor3473f882001-02-23 17:55:21 +00007072 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007073
7074 enc = xmlParseCharEncoding(encoding);
7075 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7076 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007077 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007078 return(-1);
7079 }
7080 if (enc != XML_CHAR_ENCODING_UTF8) {
7081 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00007082 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007083 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007084 }
7085 }
7086
Daniel Veillardf012a642001-07-23 19:10:52 +00007087#ifdef HAVE_ZLIB_H
7088 if (cur->compression < 0) cur->compression = xmlCompressMode;
7089#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007090 /*
7091 * save the content to a temp buffer.
7092 */
Daniel Veillardf012a642001-07-23 19:10:52 +00007093 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00007094 if (buf == NULL) return(-1);
7095
Daniel Veillardf012a642001-07-23 19:10:52 +00007096 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007097
7098 ret = xmlOutputBufferClose(buf);
7099 return(ret);
7100}
7101
Daniel Veillardf012a642001-07-23 19:10:52 +00007102
7103/**
7104 * xmlSaveFileEnc:
7105 * @filename: the filename (or URL)
7106 * @cur: the document
7107 * @encoding: the name of an encoding (or NULL)
7108 *
7109 * Dump an XML document, converting it to the given encoding
7110 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007111 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00007112 */
7113int
7114xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
7115 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
7116}
7117
Owen Taylor3473f882001-02-23 17:55:21 +00007118/**
Daniel Veillard67fee942001-04-26 18:59:03 +00007119 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00007120 * @filename: the filename (or URL)
7121 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00007122 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007123 *
7124 * Dump an XML document to a file. Will use compression if
7125 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00007126 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00007127 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007128 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007129 */
7130int
Daniel Veillard67fee942001-04-26 18:59:03 +00007131xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007132 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00007133}
7134
Daniel Veillard67fee942001-04-26 18:59:03 +00007135/**
7136 * xmlSaveFile:
7137 * @filename: the filename (or URL)
7138 * @cur: the document
7139 *
7140 * Dump an XML document to a file. Will use compression if
7141 * compiled in and enabled. If @filename is "-" the stdout file is
7142 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00007143 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00007144 */
7145int
7146xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007147 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00007148}
7149