blob: 98fc4e963c0b0c93966f89894d78fa9f71ff42c6 [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 */
1953 if (ns == NULL)
1954 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
1955 else
1956 cur = xmlNewDocNode(parent->doc, ns, name, content);
1957 if (cur == NULL) return(NULL);
1958
1959 /*
1960 * add the new element at the end of the children list.
1961 */
1962 cur->type = XML_ELEMENT_NODE;
1963 cur->parent = parent;
1964 cur->doc = parent->doc;
1965 if (parent->children == NULL) {
1966 parent->children = cur;
1967 parent->last = cur;
1968 } else {
1969 prev = parent->last;
1970 prev->next = cur;
1971 cur->prev = prev;
1972 parent->last = cur;
1973 }
1974
1975 return(cur);
1976}
1977
1978/**
1979 * xmlAddNextSibling:
1980 * @cur: the child node
1981 * @elem: the new node
1982 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001983 * Add a new node @elem as the next sibling of @cur
1984 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00001985 * first unlinked from its existing context.
1986 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001987 * If the new node is ATTRIBUTE, it is added into properties instead of children.
1988 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00001989 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001990 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001991 */
1992xmlNodePtr
1993xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
1994 if (cur == NULL) {
1995#ifdef DEBUG_TREE
1996 xmlGenericError(xmlGenericErrorContext,
1997 "xmlAddNextSibling : cur == NULL\n");
1998#endif
1999 return(NULL);
2000 }
2001 if (elem == NULL) {
2002#ifdef DEBUG_TREE
2003 xmlGenericError(xmlGenericErrorContext,
2004 "xmlAddNextSibling : elem == NULL\n");
2005#endif
2006 return(NULL);
2007 }
2008
2009 xmlUnlinkNode(elem);
2010
2011 if (elem->type == XML_TEXT_NODE) {
2012 if (cur->type == XML_TEXT_NODE) {
2013#ifndef XML_USE_BUFFER_CONTENT
2014 xmlNodeAddContent(cur, elem->content);
2015#else
2016 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
2017#endif
2018 xmlFreeNode(elem);
2019 return(cur);
2020 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002021 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2022 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002023#ifndef XML_USE_BUFFER_CONTENT
2024 xmlChar *tmp;
2025
2026 tmp = xmlStrdup(elem->content);
2027 tmp = xmlStrcat(tmp, cur->next->content);
2028 xmlNodeSetContent(cur->next, tmp);
2029 xmlFree(tmp);
2030#else
2031 xmlBufferAddHead(cur->next->content,
2032 xmlBufferContent(elem->content),
2033 xmlBufferLength(elem->content));
2034#endif
2035 xmlFreeNode(elem);
2036 return(cur->next);
2037 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002038 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2039 /* check if an attribute with the same name exists */
2040 xmlAttrPtr attr;
2041
2042 if (elem->ns == NULL)
2043 attr = xmlHasProp(cur->parent, elem->name);
2044 else
2045 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2046 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2047 /* different instance, destroy it (attributes must be unique) */
2048 xmlFreeProp(attr);
2049 }
Owen Taylor3473f882001-02-23 17:55:21 +00002050 }
2051
2052 if (elem->doc != cur->doc) {
2053 xmlSetTreeDoc(elem, cur->doc);
2054 }
2055 elem->parent = cur->parent;
2056 elem->prev = cur;
2057 elem->next = cur->next;
2058 cur->next = elem;
2059 if (elem->next != NULL)
2060 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002061 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002062 elem->parent->last = elem;
2063 return(elem);
2064}
2065
2066/**
2067 * xmlAddPrevSibling:
2068 * @cur: the child node
2069 * @elem: the new node
2070 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002071 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002072 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002073 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002074 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002075 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2076 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002077 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002078 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002079 */
2080xmlNodePtr
2081xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2082 if (cur == NULL) {
2083#ifdef DEBUG_TREE
2084 xmlGenericError(xmlGenericErrorContext,
2085 "xmlAddPrevSibling : cur == NULL\n");
2086#endif
2087 return(NULL);
2088 }
2089 if (elem == NULL) {
2090#ifdef DEBUG_TREE
2091 xmlGenericError(xmlGenericErrorContext,
2092 "xmlAddPrevSibling : elem == NULL\n");
2093#endif
2094 return(NULL);
2095 }
2096
2097 xmlUnlinkNode(elem);
2098
2099 if (elem->type == XML_TEXT_NODE) {
2100 if (cur->type == XML_TEXT_NODE) {
2101#ifndef XML_USE_BUFFER_CONTENT
2102 xmlChar *tmp;
2103
2104 tmp = xmlStrdup(elem->content);
2105 tmp = xmlStrcat(tmp, cur->content);
2106 xmlNodeSetContent(cur, tmp);
2107 xmlFree(tmp);
2108#else
2109 xmlBufferAddHead(cur->content, xmlBufferContent(elem->content),
2110 xmlBufferLength(elem->content));
2111#endif
2112 xmlFreeNode(elem);
2113 return(cur);
2114 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002115 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2116 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002117#ifndef XML_USE_BUFFER_CONTENT
2118 xmlNodeAddContent(cur->prev, elem->content);
2119#else
2120 xmlNodeAddContent(cur->prev, xmlBufferContent(elem->content));
2121#endif
2122 xmlFreeNode(elem);
2123 return(cur->prev);
2124 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002125 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2126 /* check if an attribute with the same name exists */
2127 xmlAttrPtr attr;
2128
2129 if (elem->ns == NULL)
2130 attr = xmlHasProp(cur->parent, elem->name);
2131 else
2132 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2133 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2134 /* different instance, destroy it (attributes must be unique) */
2135 xmlFreeProp(attr);
2136 }
Owen Taylor3473f882001-02-23 17:55:21 +00002137 }
2138
2139 if (elem->doc != cur->doc) {
2140 xmlSetTreeDoc(elem, cur->doc);
2141 }
2142 elem->parent = cur->parent;
2143 elem->next = cur;
2144 elem->prev = cur->prev;
2145 cur->prev = elem;
2146 if (elem->prev != NULL)
2147 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002148 if (elem->parent != NULL) {
2149 if (elem->type == XML_ATTRIBUTE_NODE) {
2150 if (elem->parent->properties == (xmlAttrPtr) cur) {
2151 elem->parent->properties = (xmlAttrPtr) elem;
2152 }
2153 } else {
2154 if (elem->parent->children == cur) {
2155 elem->parent->children = elem;
2156 }
2157 }
2158 }
Owen Taylor3473f882001-02-23 17:55:21 +00002159 return(elem);
2160}
2161
2162/**
2163 * xmlAddSibling:
2164 * @cur: the child node
2165 * @elem: the new node
2166 *
2167 * Add a new element @elem to the list of siblings of @cur
2168 * merging adjacent TEXT nodes (@elem may be freed)
2169 * If the new element was already inserted in a document it is
2170 * first unlinked from its existing context.
2171 *
2172 * Returns the new element or NULL in case of error.
2173 */
2174xmlNodePtr
2175xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2176 xmlNodePtr parent;
2177
2178 if (cur == NULL) {
2179#ifdef DEBUG_TREE
2180 xmlGenericError(xmlGenericErrorContext,
2181 "xmlAddSibling : cur == NULL\n");
2182#endif
2183 return(NULL);
2184 }
2185
2186 if (elem == NULL) {
2187#ifdef DEBUG_TREE
2188 xmlGenericError(xmlGenericErrorContext,
2189 "xmlAddSibling : elem == NULL\n");
2190#endif
2191 return(NULL);
2192 }
2193
2194 /*
2195 * Constant time is we can rely on the ->parent->last to find
2196 * the last sibling.
2197 */
2198 if ((cur->parent != NULL) &&
2199 (cur->parent->children != NULL) &&
2200 (cur->parent->last != NULL) &&
2201 (cur->parent->last->next == NULL)) {
2202 cur = cur->parent->last;
2203 } else {
2204 while (cur->next != NULL) cur = cur->next;
2205 }
2206
2207 xmlUnlinkNode(elem);
2208
2209 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
2210#ifndef XML_USE_BUFFER_CONTENT
2211 xmlNodeAddContent(cur, elem->content);
2212#else
2213 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
2214#endif
2215 xmlFreeNode(elem);
2216 return(cur);
2217 }
2218
2219 if (elem->doc != cur->doc) {
2220 xmlSetTreeDoc(elem, cur->doc);
2221 }
2222 parent = cur->parent;
2223 elem->prev = cur;
2224 elem->next = NULL;
2225 elem->parent = parent;
2226 cur->next = elem;
2227 if (parent != NULL)
2228 parent->last = elem;
2229
2230 return(elem);
2231}
2232
2233/**
2234 * xmlAddChildList:
2235 * @parent: the parent node
2236 * @cur: the first node in the list
2237 *
2238 * Add a list of node at the end of the child list of the parent
2239 * merging adjacent TEXT nodes (@cur may be freed)
2240 *
2241 * Returns the last child or NULL in case of error.
2242 */
2243xmlNodePtr
2244xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2245 xmlNodePtr prev;
2246
2247 if (parent == NULL) {
2248#ifdef DEBUG_TREE
2249 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002250 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002251#endif
2252 return(NULL);
2253 }
2254
2255 if (cur == NULL) {
2256#ifdef DEBUG_TREE
2257 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002258 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002259#endif
2260 return(NULL);
2261 }
2262
2263 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2264 (cur->doc != parent->doc)) {
2265#ifdef DEBUG_TREE
2266 xmlGenericError(xmlGenericErrorContext,
2267 "Elements moved to a different document\n");
2268#endif
2269 }
2270
2271 /*
2272 * add the first element at the end of the children list.
2273 */
2274 if (parent->children == NULL) {
2275 parent->children = cur;
2276 } else {
2277 /*
2278 * If cur and parent->last both are TEXT nodes, then merge them.
2279 */
2280 if ((cur->type == XML_TEXT_NODE) &&
2281 (parent->last->type == XML_TEXT_NODE) &&
2282 (cur->name == parent->last->name)) {
2283#ifndef XML_USE_BUFFER_CONTENT
2284 xmlNodeAddContent(parent->last, cur->content);
2285#else
2286 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2287#endif
2288 /*
2289 * if it's the only child, nothing more to be done.
2290 */
2291 if (cur->next == NULL) {
2292 xmlFreeNode(cur);
2293 return(parent->last);
2294 }
2295 prev = cur;
2296 cur = cur->next;
2297 xmlFreeNode(prev);
2298 }
2299 prev = parent->last;
2300 prev->next = cur;
2301 cur->prev = prev;
2302 }
2303 while (cur->next != NULL) {
2304 cur->parent = parent;
2305 if (cur->doc != parent->doc) {
2306 xmlSetTreeDoc(cur, parent->doc);
2307 }
2308 cur = cur->next;
2309 }
2310 cur->parent = parent;
2311 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2312 parent->last = cur;
2313
2314 return(cur);
2315}
2316
2317/**
2318 * xmlAddChild:
2319 * @parent: the parent node
2320 * @cur: the child node
2321 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002322 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002323 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002324 * If the new node was already inserted in a document it is
2325 * first unlinked from its existing context.
2326 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2327 * If there is an attribute with equal name, it is first destroyed.
2328 *
Owen Taylor3473f882001-02-23 17:55:21 +00002329 * Returns the child or NULL in case of error.
2330 */
2331xmlNodePtr
2332xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2333 xmlNodePtr prev;
2334
2335 if (parent == NULL) {
2336#ifdef DEBUG_TREE
2337 xmlGenericError(xmlGenericErrorContext,
2338 "xmlAddChild : parent == NULL\n");
2339#endif
2340 return(NULL);
2341 }
2342
2343 if (cur == NULL) {
2344#ifdef DEBUG_TREE
2345 xmlGenericError(xmlGenericErrorContext,
2346 "xmlAddChild : child == NULL\n");
2347#endif
2348 return(NULL);
2349 }
2350
Owen Taylor3473f882001-02-23 17:55:21 +00002351 /*
2352 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002353 * cur is then freed.
2354 */
2355 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002356 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002357 (parent->content != NULL)) {
2358#ifndef XML_USE_BUFFER_CONTENT
2359 xmlNodeAddContent(parent, cur->content);
2360#else
2361 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
2362#endif
2363 xmlFreeNode(cur);
2364 return(parent);
2365 }
2366 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2367 (parent->last->name == cur->name)) {
2368#ifndef XML_USE_BUFFER_CONTENT
2369 xmlNodeAddContent(parent->last, cur->content);
2370#else
2371 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2372#endif
2373 xmlFreeNode(cur);
2374 return(parent->last);
2375 }
2376 }
2377
2378 /*
2379 * add the new element at the end of the children list.
2380 */
2381 cur->parent = parent;
2382 if (cur->doc != parent->doc) {
2383 xmlSetTreeDoc(cur, parent->doc);
2384 }
2385
2386 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002387 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002388 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002389 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002390 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002391#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard7db37732001-07-12 01:20:08 +00002392 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002393#else
Daniel Veillard7db37732001-07-12 01:20:08 +00002394 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00002395#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002396 xmlFreeNode(cur);
2397 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002398 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002399 if (cur->type == XML_ATTRIBUTE_NODE) {
2400 if (parent->properties == NULL) {
2401 parent->properties = (xmlAttrPtr) cur;
2402 } else {
2403 /* check if an attribute with the same name exists */
2404 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002405
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002406 if (cur->ns == NULL)
2407 lastattr = xmlHasProp(parent, cur->name);
2408 else
2409 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2410 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2411 /* different instance, destroy it (attributes must be unique) */
2412 xmlFreeProp(lastattr);
2413 }
2414 /* find the end */
2415 lastattr = parent->properties;
2416 while (lastattr->next != NULL) {
2417 lastattr = lastattr->next;
2418 }
2419 lastattr->next = (xmlAttrPtr) cur;
2420 ((xmlAttrPtr) cur)->prev = lastattr;
2421 }
2422 } else {
2423 if (parent->children == NULL) {
2424 parent->children = cur;
2425 parent->last = cur;
2426 } else {
2427 prev = parent->last;
2428 prev->next = cur;
2429 cur->prev = prev;
2430 parent->last = cur;
2431 }
2432 }
Owen Taylor3473f882001-02-23 17:55:21 +00002433 return(cur);
2434}
2435
2436/**
2437 * xmlGetLastChild:
2438 * @parent: the parent node
2439 *
2440 * Search the last child of a node.
2441 * Returns the last child or NULL if none.
2442 */
2443xmlNodePtr
2444xmlGetLastChild(xmlNodePtr parent) {
2445 if (parent == NULL) {
2446#ifdef DEBUG_TREE
2447 xmlGenericError(xmlGenericErrorContext,
2448 "xmlGetLastChild : parent == NULL\n");
2449#endif
2450 return(NULL);
2451 }
2452 return(parent->last);
2453}
2454
2455/**
2456 * xmlFreeNodeList:
2457 * @cur: the first node in the list
2458 *
2459 * Free a node and all its siblings, this is a recursive behaviour, all
2460 * the children are freed too.
2461 */
2462void
2463xmlFreeNodeList(xmlNodePtr cur) {
2464 xmlNodePtr next;
2465 if (cur == NULL) {
2466#ifdef DEBUG_TREE
2467 xmlGenericError(xmlGenericErrorContext,
2468 "xmlFreeNodeList : node == NULL\n");
2469#endif
2470 return;
2471 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002472 if (cur->type == XML_NAMESPACE_DECL) {
2473 xmlFreeNsList((xmlNsPtr) cur);
2474 return;
2475 }
Owen Taylor3473f882001-02-23 17:55:21 +00002476 while (cur != NULL) {
2477 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002478 /* unroll to speed up freeing the document */
2479 if (cur->type != XML_DTD_NODE) {
2480 if ((cur->children != NULL) &&
2481 (cur->type != XML_ENTITY_REF_NODE))
2482 xmlFreeNodeList(cur->children);
2483 if (cur->properties != NULL)
2484 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002485 if ((cur->type != XML_ELEMENT_NODE) &&
2486 (cur->type != XML_XINCLUDE_START) &&
2487 (cur->type != XML_XINCLUDE_END) &&
2488 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002489#ifndef XML_USE_BUFFER_CONTENT
2490 if (cur->content != NULL) xmlFree(cur->content);
2491#else
2492 if (cur->content != NULL) xmlBufferFree(cur->content);
2493#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002494 }
2495 if (((cur->type == XML_ELEMENT_NODE) ||
2496 (cur->type == XML_XINCLUDE_START) ||
2497 (cur->type == XML_XINCLUDE_END)) &&
2498 (cur->nsDef != NULL))
2499 xmlFreeNsList(cur->nsDef);
2500
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002501 /*
2502 * When a node is a text node or a comment, it uses a global static
2503 * variable for the name of the node.
2504 *
2505 * The xmlStrEqual comparisons need to be done when (happened with
2506 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002507 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002508 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002509 * the string addresses compare are not sufficient.
2510 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002511 if ((cur->name != NULL) &&
2512 (cur->name != xmlStringText) &&
2513 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002514 (cur->name != xmlStringComment)) {
2515 if (cur->type == XML_TEXT_NODE) {
2516 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2517 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2518 xmlFree((char *) cur->name);
2519 } else if (cur->type == XML_COMMENT_NODE) {
2520 if (!xmlStrEqual(cur->name, xmlStringComment))
2521 xmlFree((char *) cur->name);
2522 } else
2523 xmlFree((char *) cur->name);
2524 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002525 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002526 xmlFree(cur);
2527 }
Owen Taylor3473f882001-02-23 17:55:21 +00002528 cur = next;
2529 }
2530}
2531
2532/**
2533 * xmlFreeNode:
2534 * @cur: the node
2535 *
2536 * Free a node, this is a recursive behaviour, all the children are freed too.
2537 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2538 */
2539void
2540xmlFreeNode(xmlNodePtr cur) {
2541 if (cur == NULL) {
2542#ifdef DEBUG_TREE
2543 xmlGenericError(xmlGenericErrorContext,
2544 "xmlFreeNode : node == NULL\n");
2545#endif
2546 return;
2547 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002548 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002549 if (cur->type == XML_DTD_NODE) {
2550 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002551 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002552 }
2553 if (cur->type == XML_NAMESPACE_DECL) {
2554 xmlFreeNs((xmlNsPtr) cur);
2555 return;
2556 }
Owen Taylor3473f882001-02-23 17:55:21 +00002557 if ((cur->children != NULL) &&
2558 (cur->type != XML_ENTITY_REF_NODE))
2559 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002560 if (cur->properties != NULL)
2561 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002562 if ((cur->type != XML_ELEMENT_NODE) &&
2563 (cur->content != NULL) &&
2564 (cur->type != XML_ENTITY_REF_NODE) &&
2565 (cur->type != XML_XINCLUDE_END) &&
2566 (cur->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002567#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard7db37732001-07-12 01:20:08 +00002568 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002569#else
Daniel Veillard7db37732001-07-12 01:20:08 +00002570 xmlBufferFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002571#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002572 }
2573
Daniel Veillardacd370f2001-06-09 17:17:51 +00002574 /*
2575 * When a node is a text node or a comment, it uses a global static
2576 * variable for the name of the node.
2577 *
2578 * The xmlStrEqual comparisons need to be done when (happened with
2579 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002580 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002581 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002582 * are not sufficient.
2583 */
Owen Taylor3473f882001-02-23 17:55:21 +00002584 if ((cur->name != NULL) &&
2585 (cur->name != xmlStringText) &&
2586 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002587 (cur->name != xmlStringComment)) {
2588 if (cur->type == XML_TEXT_NODE) {
2589 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2590 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2591 xmlFree((char *) cur->name);
2592 } else if (cur->type == XML_COMMENT_NODE) {
2593 if (!xmlStrEqual(cur->name, xmlStringComment))
2594 xmlFree((char *) cur->name);
2595 } else
2596 xmlFree((char *) cur->name);
2597 }
2598
Owen Taylor3473f882001-02-23 17:55:21 +00002599 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002600 xmlFree(cur);
2601}
2602
2603/**
2604 * xmlUnlinkNode:
2605 * @cur: the node
2606 *
2607 * Unlink a node from it's current context, the node is not freed
2608 */
2609void
2610xmlUnlinkNode(xmlNodePtr cur) {
2611 if (cur == NULL) {
2612#ifdef DEBUG_TREE
2613 xmlGenericError(xmlGenericErrorContext,
2614 "xmlUnlinkNode : node == NULL\n");
2615#endif
2616 return;
2617 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002618 if (cur->type == XML_DTD_NODE) {
2619 xmlDocPtr doc;
2620 doc = cur->doc;
2621 if (doc->intSubset == (xmlDtdPtr) cur)
2622 doc->intSubset = NULL;
2623 if (doc->extSubset == (xmlDtdPtr) cur)
2624 doc->extSubset = NULL;
2625 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002626 if (cur->parent != NULL) {
2627 xmlNodePtr parent;
2628 parent = cur->parent;
2629 if (cur->type == XML_ATTRIBUTE_NODE) {
2630 if (parent->properties == (xmlAttrPtr) cur)
2631 parent->properties = ((xmlAttrPtr) cur)->next;
2632 } else {
2633 if (parent->children == cur)
2634 parent->children = cur->next;
2635 if (parent->last == cur)
2636 parent->last = cur->prev;
2637 }
2638 cur->parent = NULL;
2639 }
Owen Taylor3473f882001-02-23 17:55:21 +00002640 if (cur->next != NULL)
2641 cur->next->prev = cur->prev;
2642 if (cur->prev != NULL)
2643 cur->prev->next = cur->next;
2644 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002645}
2646
2647/**
2648 * xmlReplaceNode:
2649 * @old: the old node
2650 * @cur: the node
2651 *
2652 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002653 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002654 * first unlinked from its existing context.
2655 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002656 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002657 */
2658xmlNodePtr
2659xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2660 if (old == NULL) {
2661#ifdef DEBUG_TREE
2662 xmlGenericError(xmlGenericErrorContext,
2663 "xmlReplaceNode : old == NULL\n");
2664#endif
2665 return(NULL);
2666 }
2667 if (cur == NULL) {
2668 xmlUnlinkNode(old);
2669 return(old);
2670 }
2671 if (cur == old) {
2672 return(old);
2673 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002674 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2675#ifdef DEBUG_TREE
2676 xmlGenericError(xmlGenericErrorContext,
2677 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2678#endif
2679 return(old);
2680 }
2681 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2682#ifdef DEBUG_TREE
2683 xmlGenericError(xmlGenericErrorContext,
2684 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2685#endif
2686 return(old);
2687 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002688 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2689#ifdef DEBUG_TREE
2690 xmlGenericError(xmlGenericErrorContext,
2691 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2692#endif
2693 return(old);
2694 }
2695 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2696#ifdef DEBUG_TREE
2697 xmlGenericError(xmlGenericErrorContext,
2698 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2699#endif
2700 return(old);
2701 }
Owen Taylor3473f882001-02-23 17:55:21 +00002702 xmlUnlinkNode(cur);
2703 cur->doc = old->doc;
2704 cur->parent = old->parent;
2705 cur->next = old->next;
2706 if (cur->next != NULL)
2707 cur->next->prev = cur;
2708 cur->prev = old->prev;
2709 if (cur->prev != NULL)
2710 cur->prev->next = cur;
2711 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002712 if (cur->type == XML_ATTRIBUTE_NODE) {
2713 if (cur->parent->properties == (xmlAttrPtr)old)
2714 cur->parent->properties = ((xmlAttrPtr) cur);
2715 } else {
2716 if (cur->parent->children == old)
2717 cur->parent->children = cur;
2718 if (cur->parent->last == old)
2719 cur->parent->last = cur;
2720 }
Owen Taylor3473f882001-02-23 17:55:21 +00002721 }
2722 old->next = old->prev = NULL;
2723 old->parent = NULL;
2724 return(old);
2725}
2726
2727/************************************************************************
2728 * *
2729 * Copy operations *
2730 * *
2731 ************************************************************************/
2732
2733/**
2734 * xmlCopyNamespace:
2735 * @cur: the namespace
2736 *
2737 * Do a copy of the namespace.
2738 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002739 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002740 */
2741xmlNsPtr
2742xmlCopyNamespace(xmlNsPtr cur) {
2743 xmlNsPtr ret;
2744
2745 if (cur == NULL) return(NULL);
2746 switch (cur->type) {
2747 case XML_LOCAL_NAMESPACE:
2748 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2749 break;
2750 default:
2751#ifdef DEBUG_TREE
2752 xmlGenericError(xmlGenericErrorContext,
2753 "xmlCopyNamespace: invalid type %d\n", cur->type);
2754#endif
2755 return(NULL);
2756 }
2757 return(ret);
2758}
2759
2760/**
2761 * xmlCopyNamespaceList:
2762 * @cur: the first namespace
2763 *
2764 * Do a copy of an namespace list.
2765 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002766 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002767 */
2768xmlNsPtr
2769xmlCopyNamespaceList(xmlNsPtr cur) {
2770 xmlNsPtr ret = NULL;
2771 xmlNsPtr p = NULL,q;
2772
2773 while (cur != NULL) {
2774 q = xmlCopyNamespace(cur);
2775 if (p == NULL) {
2776 ret = p = q;
2777 } else {
2778 p->next = q;
2779 p = q;
2780 }
2781 cur = cur->next;
2782 }
2783 return(ret);
2784}
2785
2786static xmlNodePtr
2787xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2788/**
2789 * xmlCopyProp:
2790 * @target: the element where the attribute will be grafted
2791 * @cur: the attribute
2792 *
2793 * Do a copy of the attribute.
2794 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002795 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002796 */
2797xmlAttrPtr
2798xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2799 xmlAttrPtr ret;
2800
2801 if (cur == NULL) return(NULL);
2802 if (target != NULL)
2803 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2804 else if (cur->parent != NULL)
2805 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2806 else if (cur->children != NULL)
2807 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2808 else
2809 ret = xmlNewDocProp(NULL, cur->name, NULL);
2810 if (ret == NULL) return(NULL);
2811 ret->parent = target;
2812
2813 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00002814 xmlNsPtr ns;
2815 if (target->doc)
Owen Taylor3473f882001-02-23 17:55:21 +00002816 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
Daniel Veillard8107a222002-01-13 14:10:10 +00002817 else if (cur->doc) /* target may not yet have a doc : KPI */
2818 ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
2819 else
2820 ns = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002821 ret->ns = ns;
2822 } else
2823 ret->ns = NULL;
2824
2825 if (cur->children != NULL) {
2826 xmlNodePtr tmp;
2827
2828 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2829 ret->last = NULL;
2830 tmp = ret->children;
2831 while (tmp != NULL) {
2832 /* tmp->parent = (xmlNodePtr)ret; */
2833 if (tmp->next == NULL)
2834 ret->last = tmp;
2835 tmp = tmp->next;
2836 }
2837 }
2838 return(ret);
2839}
2840
2841/**
2842 * xmlCopyPropList:
2843 * @target: the element where the attributes will be grafted
2844 * @cur: the first attribute
2845 *
2846 * Do a copy of an attribute list.
2847 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002848 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002849 */
2850xmlAttrPtr
2851xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
2852 xmlAttrPtr ret = NULL;
2853 xmlAttrPtr p = NULL,q;
2854
2855 while (cur != NULL) {
2856 q = xmlCopyProp(target, cur);
2857 if (p == NULL) {
2858 ret = p = q;
2859 } else {
2860 p->next = q;
2861 q->prev = p;
2862 p = q;
2863 }
2864 cur = cur->next;
2865 }
2866 return(ret);
2867}
2868
2869/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002870 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00002871 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002872 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00002873 * tricky reason: namespaces. Doing a direct copy of a node
2874 * say RPM:Copyright without changing the namespace pointer to
2875 * something else can produce stale links. One way to do it is
2876 * to keep a reference counter but this doesn't work as soon
2877 * as one move the element or the subtree out of the scope of
2878 * the existing namespace. The actual solution seems to add
2879 * a copy of the namespace at the top of the copied tree if
2880 * not available in the subtree.
2881 * Hence two functions, the public front-end call the inner ones
2882 */
2883
2884static xmlNodePtr
2885xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2886
2887static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002888xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00002889 int recursive) {
2890 xmlNodePtr ret;
2891
2892 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00002893 switch (node->type) {
2894 case XML_TEXT_NODE:
2895 case XML_CDATA_SECTION_NODE:
2896 case XML_ELEMENT_NODE:
2897 case XML_ENTITY_REF_NODE:
2898 case XML_ENTITY_NODE:
2899 case XML_PI_NODE:
2900 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002901 case XML_XINCLUDE_START:
2902 case XML_XINCLUDE_END:
2903 break;
2904 case XML_ATTRIBUTE_NODE:
2905 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
2906 case XML_NAMESPACE_DECL:
2907 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
2908
Daniel Veillard39196eb2001-06-19 18:09:42 +00002909 case XML_DOCUMENT_NODE:
2910 case XML_HTML_DOCUMENT_NODE:
2911#ifdef LIBXML_DOCB_ENABLED
2912 case XML_DOCB_DOCUMENT_NODE:
2913#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002914 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00002915 case XML_DOCUMENT_TYPE_NODE:
2916 case XML_DOCUMENT_FRAG_NODE:
2917 case XML_NOTATION_NODE:
2918 case XML_DTD_NODE:
2919 case XML_ELEMENT_DECL:
2920 case XML_ATTRIBUTE_DECL:
2921 case XML_ENTITY_DECL:
2922 return(NULL);
2923 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002924
Owen Taylor3473f882001-02-23 17:55:21 +00002925 /*
2926 * Allocate a new node and fill the fields.
2927 */
2928 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2929 if (ret == NULL) {
2930 xmlGenericError(xmlGenericErrorContext,
2931 "xmlStaticCopyNode : malloc failed\n");
2932 return(NULL);
2933 }
2934 memset(ret, 0, sizeof(xmlNode));
2935 ret->type = node->type;
2936
2937 ret->doc = doc;
2938 ret->parent = parent;
2939 if (node->name == xmlStringText)
2940 ret->name = xmlStringText;
2941 else if (node->name == xmlStringTextNoenc)
2942 ret->name = xmlStringTextNoenc;
2943 else if (node->name == xmlStringComment)
2944 ret->name = xmlStringComment;
2945 else if (node->name != NULL)
2946 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00002947 if ((node->type != XML_ELEMENT_NODE) &&
2948 (node->content != NULL) &&
2949 (node->type != XML_ENTITY_REF_NODE) &&
2950 (node->type != XML_XINCLUDE_END) &&
2951 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002952#ifndef XML_USE_BUFFER_CONTENT
2953 ret->content = xmlStrdup(node->content);
2954#else
2955 ret->content = xmlBufferCreateSize(xmlBufferLength(node->content));
2956 xmlBufferSetAllocationScheme(ret->content,
2957 xmlGetBufferAllocationScheme());
2958 xmlBufferAdd(ret->content,
2959 xmlBufferContent(node->content),
2960 xmlBufferLength(node->content));
2961#endif
Daniel Veillard8107a222002-01-13 14:10:10 +00002962 }else{
2963 if (node->type == XML_ELEMENT_NODE)
2964 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002965 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00002966 if (parent != NULL) {
2967 xmlNodePtr tmp;
2968
2969 tmp = xmlAddChild(parent, ret);
2970 /* node could have coalesced */
2971 if (tmp != ret)
2972 return(tmp);
2973 }
Owen Taylor3473f882001-02-23 17:55:21 +00002974
2975 if (!recursive) return(ret);
2976 if (node->nsDef != NULL)
2977 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2978
2979 if (node->ns != NULL) {
2980 xmlNsPtr ns;
2981
2982 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2983 if (ns == NULL) {
2984 /*
2985 * Humm, we are copying an element whose namespace is defined
2986 * out of the new tree scope. Search it in the original tree
2987 * and add it at the top of the new tree
2988 */
2989 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2990 if (ns != NULL) {
2991 xmlNodePtr root = ret;
2992
2993 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00002994 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002995 }
2996 } else {
2997 /*
2998 * reference the existing namespace definition in our own tree.
2999 */
3000 ret->ns = ns;
3001 }
3002 }
3003 if (node->properties != NULL)
3004 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003005 if (node->type == XML_ENTITY_REF_NODE) {
3006 if ((doc == NULL) || (node->doc != doc)) {
3007 /*
3008 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003009 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003010 * we cannot keep the reference. Try to find it in the
3011 * target document.
3012 */
3013 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3014 } else {
3015 ret->children = node->children;
3016 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003017 ret->last = ret->children;
3018 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003019 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003020 UPDATE_LAST_CHILD_AND_PARENT(ret)
3021 }
Owen Taylor3473f882001-02-23 17:55:21 +00003022 return(ret);
3023}
3024
3025static xmlNodePtr
3026xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3027 xmlNodePtr ret = NULL;
3028 xmlNodePtr p = NULL,q;
3029
3030 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003031 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003032 if (doc == NULL) {
3033 node = node->next;
3034 continue;
3035 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003036 if (doc->intSubset == NULL) {
3037 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3038 q->doc = doc;
3039 q->parent = parent;
3040 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003041 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003042 } else {
3043 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003044 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003045 }
3046 } else
3047 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003048 if (ret == NULL) {
3049 q->prev = NULL;
3050 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003051 } else if (p != q) {
3052 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003053 p->next = q;
3054 q->prev = p;
3055 p = q;
3056 }
3057 node = node->next;
3058 }
3059 return(ret);
3060}
3061
3062/**
3063 * xmlCopyNode:
3064 * @node: the node
3065 * @recursive: if 1 do a recursive copy.
3066 *
3067 * Do a copy of the node.
3068 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003069 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003070 */
3071xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003072xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003073 xmlNodePtr ret;
3074
3075 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3076 return(ret);
3077}
3078
3079/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003080 * xmlDocCopyNode:
3081 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003082 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003083 * @recursive: if 1 do a recursive copy.
3084 *
3085 * Do a copy of the node to a given document.
3086 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003087 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003088 */
3089xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003090xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003091 xmlNodePtr ret;
3092
3093 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3094 return(ret);
3095}
3096
3097/**
Owen Taylor3473f882001-02-23 17:55:21 +00003098 * xmlCopyNodeList:
3099 * @node: the first node in the list.
3100 *
3101 * Do a recursive copy of the node list.
3102 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003103 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003104 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003105xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003106 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3107 return(ret);
3108}
3109
3110/**
Owen Taylor3473f882001-02-23 17:55:21 +00003111 * xmlCopyDtd:
3112 * @dtd: the dtd
3113 *
3114 * Do a copy of the dtd.
3115 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003116 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003117 */
3118xmlDtdPtr
3119xmlCopyDtd(xmlDtdPtr dtd) {
3120 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003121 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003122
3123 if (dtd == NULL) return(NULL);
3124 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3125 if (ret == NULL) return(NULL);
3126 if (dtd->entities != NULL)
3127 ret->entities = (void *) xmlCopyEntitiesTable(
3128 (xmlEntitiesTablePtr) dtd->entities);
3129 if (dtd->notations != NULL)
3130 ret->notations = (void *) xmlCopyNotationTable(
3131 (xmlNotationTablePtr) dtd->notations);
3132 if (dtd->elements != NULL)
3133 ret->elements = (void *) xmlCopyElementTable(
3134 (xmlElementTablePtr) dtd->elements);
3135 if (dtd->attributes != NULL)
3136 ret->attributes = (void *) xmlCopyAttributeTable(
3137 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003138 if (dtd->pentities != NULL)
3139 ret->pentities = (void *) xmlCopyEntitiesTable(
3140 (xmlEntitiesTablePtr) dtd->pentities);
3141
3142 cur = dtd->children;
3143 while (cur != NULL) {
3144 q = NULL;
3145
3146 if (cur->type == XML_ENTITY_DECL) {
3147 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3148 switch (tmp->etype) {
3149 case XML_INTERNAL_GENERAL_ENTITY:
3150 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3151 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3152 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3153 break;
3154 case XML_INTERNAL_PARAMETER_ENTITY:
3155 case XML_EXTERNAL_PARAMETER_ENTITY:
3156 q = (xmlNodePtr)
3157 xmlGetParameterEntityFromDtd(ret, tmp->name);
3158 break;
3159 case XML_INTERNAL_PREDEFINED_ENTITY:
3160 break;
3161 }
3162 } else if (cur->type == XML_ELEMENT_DECL) {
3163 xmlElementPtr tmp = (xmlElementPtr) cur;
3164 q = (xmlNodePtr)
3165 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3166 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3167 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3168 q = (xmlNodePtr)
3169 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3170 } else if (cur->type == XML_COMMENT_NODE) {
3171 q = xmlCopyNode(cur, 0);
3172 }
3173
3174 if (q == NULL) {
3175 cur = cur->next;
3176 continue;
3177 }
3178
3179 if (p == NULL)
3180 ret->children = q;
3181 else
3182 p->next = q;
3183
3184 q->prev = p;
3185 q->parent = (xmlNodePtr) ret;
3186 q->next = NULL;
3187 ret->last = q;
3188 p = q;
3189 cur = cur->next;
3190 }
3191
Owen Taylor3473f882001-02-23 17:55:21 +00003192 return(ret);
3193}
3194
3195/**
3196 * xmlCopyDoc:
3197 * @doc: the document
3198 * @recursive: if 1 do a recursive copy.
3199 *
3200 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003201 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003202 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003203 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003204 */
3205xmlDocPtr
3206xmlCopyDoc(xmlDocPtr doc, int recursive) {
3207 xmlDocPtr ret;
3208
3209 if (doc == NULL) return(NULL);
3210 ret = xmlNewDoc(doc->version);
3211 if (ret == NULL) return(NULL);
3212 if (doc->name != NULL)
3213 ret->name = xmlMemStrdup(doc->name);
3214 if (doc->encoding != NULL)
3215 ret->encoding = xmlStrdup(doc->encoding);
3216 ret->charset = doc->charset;
3217 ret->compression = doc->compression;
3218 ret->standalone = doc->standalone;
3219 if (!recursive) return(ret);
3220
Daniel Veillardb33c2012001-04-25 12:59:04 +00003221 ret->last = NULL;
3222 ret->children = NULL;
3223 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003224 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003225 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003226 ret->intSubset->parent = ret;
3227 }
Owen Taylor3473f882001-02-23 17:55:21 +00003228 if (doc->oldNs != NULL)
3229 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3230 if (doc->children != NULL) {
3231 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003232
3233 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3234 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003235 ret->last = NULL;
3236 tmp = ret->children;
3237 while (tmp != NULL) {
3238 if (tmp->next == NULL)
3239 ret->last = tmp;
3240 tmp = tmp->next;
3241 }
3242 }
3243 return(ret);
3244}
3245
3246/************************************************************************
3247 * *
3248 * Content access functions *
3249 * *
3250 ************************************************************************/
3251
3252/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003253 * xmlGetLineNo:
3254 * @node : valid node
3255 *
3256 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003257 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003258 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003259 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003260 */
3261long
3262xmlGetLineNo(xmlNodePtr node)
3263{
3264 long result = -1;
3265
3266 if (!node)
3267 return result;
3268 if (node->type == XML_ELEMENT_NODE)
3269 result = (long) node->content;
3270 else if ((node->prev != NULL) &&
3271 ((node->prev->type == XML_ELEMENT_NODE) ||
3272 (node->prev->type == XML_TEXT_NODE)))
3273 result = xmlGetLineNo(node->prev);
3274 else if ((node->parent != NULL) &&
3275 ((node->parent->type == XML_ELEMENT_NODE) ||
3276 (node->parent->type == XML_TEXT_NODE)))
3277 result = xmlGetLineNo(node->parent);
3278
3279 return result;
3280}
3281
3282/**
3283 * xmlGetNodePath:
3284 * @node: a node
3285 *
3286 * Build a structure based Path for the given node
3287 *
3288 * Returns the new path or NULL in case of error. The caller must free
3289 * the returned string
3290 */
3291xmlChar *
3292xmlGetNodePath(xmlNodePtr node)
3293{
3294 xmlNodePtr cur, tmp, next;
3295 xmlChar *buffer = NULL, *temp;
3296 size_t buf_len;
3297 xmlChar *buf;
3298 char sep;
3299 const char *name;
3300 char nametemp[100];
3301 int occur = 0;
3302
3303 if (node == NULL)
3304 return (NULL);
3305
3306 buf_len = 500;
3307 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3308 if (buffer == NULL)
3309 return (NULL);
3310 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3311 if (buf == NULL) {
3312 xmlFree(buffer);
3313 return (NULL);
3314 }
3315
3316 buffer[0] = 0;
3317 cur = node;
3318 do {
3319 name = "";
3320 sep = '?';
3321 occur = 0;
3322 if ((cur->type == XML_DOCUMENT_NODE) ||
3323 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3324 if (buffer[0] == '/')
3325 break;
3326 sep = '/';
3327 next = NULL;
3328 } else if (cur->type == XML_ELEMENT_NODE) {
3329 sep = '/';
3330 name = (const char *) cur->name;
3331 if (cur->ns) {
3332 snprintf(nametemp, sizeof(nametemp) - 1,
3333 "%s:%s", cur->ns->prefix, cur->name);
3334 nametemp[sizeof(nametemp) - 1] = 0;
3335 name = nametemp;
3336 }
3337 next = cur->parent;
3338
3339 /*
3340 * Thumbler index computation
3341 */
3342 tmp = cur->prev;
3343 while (tmp != NULL) {
3344 if (xmlStrEqual(cur->name, tmp->name))
3345 occur++;
3346 tmp = tmp->prev;
3347 }
3348 if (occur == 0) {
3349 tmp = cur->next;
3350 while (tmp != NULL) {
3351 if (xmlStrEqual(cur->name, tmp->name))
3352 occur++;
3353 tmp = tmp->next;
3354 }
3355 if (occur != 0)
3356 occur = 1;
3357 } else
3358 occur++;
3359 } else if (cur->type == XML_ATTRIBUTE_NODE) {
3360 sep = '@';
3361 name = (const char *) (((xmlAttrPtr) cur)->name);
3362 next = ((xmlAttrPtr) cur)->parent;
3363 } else {
3364 next = cur->parent;
3365 }
3366
3367 /*
3368 * Make sure there is enough room
3369 */
3370 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3371 buf_len =
3372 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3373 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3374 if (temp == NULL) {
3375 xmlFree(buf);
3376 xmlFree(buffer);
3377 return (NULL);
3378 }
3379 buffer = temp;
3380 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3381 if (temp == NULL) {
3382 xmlFree(buf);
3383 xmlFree(buffer);
3384 return (NULL);
3385 }
3386 buf = temp;
3387 }
3388 if (occur == 0)
3389 snprintf((char *) buf, buf_len, "%c%s%s",
3390 sep, name, (char *) buffer);
3391 else
3392 snprintf((char *) buf, buf_len, "%c%s[%d]%s",
3393 sep, name, occur, (char *) buffer);
3394 snprintf((char *) buffer, buf_len, "%s", buf);
3395 cur = next;
3396 } while (cur != NULL);
3397 xmlFree(buf);
3398 return (buffer);
3399}
3400
3401/**
Owen Taylor3473f882001-02-23 17:55:21 +00003402 * xmlDocGetRootElement:
3403 * @doc: the document
3404 *
3405 * Get the root element of the document (doc->children is a list
3406 * containing possibly comments, PIs, etc ...).
3407 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003408 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003409 */
3410xmlNodePtr
3411xmlDocGetRootElement(xmlDocPtr doc) {
3412 xmlNodePtr ret;
3413
3414 if (doc == NULL) return(NULL);
3415 ret = doc->children;
3416 while (ret != NULL) {
3417 if (ret->type == XML_ELEMENT_NODE)
3418 return(ret);
3419 ret = ret->next;
3420 }
3421 return(ret);
3422}
3423
3424/**
3425 * xmlDocSetRootElement:
3426 * @doc: the document
3427 * @root: the new document root element
3428 *
3429 * Set the root element of the document (doc->children is a list
3430 * containing possibly comments, PIs, etc ...).
3431 *
3432 * Returns the old root element if any was found
3433 */
3434xmlNodePtr
3435xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3436 xmlNodePtr old = NULL;
3437
3438 if (doc == NULL) return(NULL);
3439 old = doc->children;
3440 while (old != NULL) {
3441 if (old->type == XML_ELEMENT_NODE)
3442 break;
3443 old = old->next;
3444 }
3445 if (old == NULL) {
3446 if (doc->children == NULL) {
3447 doc->children = root;
3448 doc->last = root;
3449 } else {
3450 xmlAddSibling(doc->children, root);
3451 }
3452 } else {
3453 xmlReplaceNode(old, root);
3454 }
3455 return(old);
3456}
3457
3458/**
3459 * xmlNodeSetLang:
3460 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003461 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003462 *
3463 * Set the language of a node, i.e. the values of the xml:lang
3464 * attribute.
3465 */
3466void
3467xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003468 xmlNsPtr ns;
3469
Owen Taylor3473f882001-02-23 17:55:21 +00003470 if (cur == NULL) return;
3471 switch(cur->type) {
3472 case XML_TEXT_NODE:
3473 case XML_CDATA_SECTION_NODE:
3474 case XML_COMMENT_NODE:
3475 case XML_DOCUMENT_NODE:
3476 case XML_DOCUMENT_TYPE_NODE:
3477 case XML_DOCUMENT_FRAG_NODE:
3478 case XML_NOTATION_NODE:
3479 case XML_HTML_DOCUMENT_NODE:
3480 case XML_DTD_NODE:
3481 case XML_ELEMENT_DECL:
3482 case XML_ATTRIBUTE_DECL:
3483 case XML_ENTITY_DECL:
3484 case XML_PI_NODE:
3485 case XML_ENTITY_REF_NODE:
3486 case XML_ENTITY_NODE:
3487 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003488#ifdef LIBXML_DOCB_ENABLED
3489 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003490#endif
3491 case XML_XINCLUDE_START:
3492 case XML_XINCLUDE_END:
3493 return;
3494 case XML_ELEMENT_NODE:
3495 case XML_ATTRIBUTE_NODE:
3496 break;
3497 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003498 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3499 if (ns == NULL)
3500 return;
3501 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003502}
3503
3504/**
3505 * xmlNodeGetLang:
3506 * @cur: the node being checked
3507 *
3508 * Searches the language of a node, i.e. the values of the xml:lang
3509 * attribute or the one carried by the nearest ancestor.
3510 *
3511 * Returns a pointer to the lang value, or NULL if not found
3512 * It's up to the caller to free the memory.
3513 */
3514xmlChar *
3515xmlNodeGetLang(xmlNodePtr cur) {
3516 xmlChar *lang;
3517
3518 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003519 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003520 if (lang != NULL)
3521 return(lang);
3522 cur = cur->parent;
3523 }
3524 return(NULL);
3525}
3526
3527
3528/**
3529 * xmlNodeSetSpacePreserve:
3530 * @cur: the node being changed
3531 * @val: the xml:space value ("0": default, 1: "preserve")
3532 *
3533 * Set (or reset) the space preserving behaviour of a node, i.e. the
3534 * value of the xml:space attribute.
3535 */
3536void
3537xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
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:
3558 case XML_XINCLUDE_START:
3559 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003560#ifdef LIBXML_DOCB_ENABLED
3561 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003562#endif
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;
Owen Taylor3473f882001-02-23 17:55:21 +00003571 switch (val) {
3572 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003573 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003574 break;
3575 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003576 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003577 break;
3578 }
3579}
3580
3581/**
3582 * xmlNodeGetSpacePreserve:
3583 * @cur: the node being checked
3584 *
3585 * Searches the space preserving behaviour of a node, i.e. the values
3586 * of the xml:space attribute or the one carried by the nearest
3587 * ancestor.
3588 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003589 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003590 */
3591int
3592xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3593 xmlChar *space;
3594
3595 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003596 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003597 if (space != NULL) {
3598 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3599 xmlFree(space);
3600 return(1);
3601 }
3602 if (xmlStrEqual(space, BAD_CAST "default")) {
3603 xmlFree(space);
3604 return(0);
3605 }
3606 xmlFree(space);
3607 }
3608 cur = cur->parent;
3609 }
3610 return(-1);
3611}
3612
3613/**
3614 * xmlNodeSetName:
3615 * @cur: the node being changed
3616 * @name: the new tag name
3617 *
3618 * Set (or reset) the name of a node.
3619 */
3620void
3621xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3622 if (cur == NULL) return;
3623 if (name == NULL) return;
3624 switch(cur->type) {
3625 case XML_TEXT_NODE:
3626 case XML_CDATA_SECTION_NODE:
3627 case XML_COMMENT_NODE:
3628 case XML_DOCUMENT_TYPE_NODE:
3629 case XML_DOCUMENT_FRAG_NODE:
3630 case XML_NOTATION_NODE:
3631 case XML_HTML_DOCUMENT_NODE:
3632 case XML_NAMESPACE_DECL:
3633 case XML_XINCLUDE_START:
3634 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003635#ifdef LIBXML_DOCB_ENABLED
3636 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003637#endif
3638 return;
3639 case XML_ELEMENT_NODE:
3640 case XML_ATTRIBUTE_NODE:
3641 case XML_PI_NODE:
3642 case XML_ENTITY_REF_NODE:
3643 case XML_ENTITY_NODE:
3644 case XML_DTD_NODE:
3645 case XML_DOCUMENT_NODE:
3646 case XML_ELEMENT_DECL:
3647 case XML_ATTRIBUTE_DECL:
3648 case XML_ENTITY_DECL:
3649 break;
3650 }
3651 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3652 cur->name = xmlStrdup(name);
3653}
3654
3655/**
3656 * xmlNodeSetBase:
3657 * @cur: the node being changed
3658 * @uri: the new base URI
3659 *
3660 * Set (or reset) the base URI of a node, i.e. the value of the
3661 * xml:base attribute.
3662 */
3663void
3664xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003665 xmlNsPtr ns;
3666
Owen Taylor3473f882001-02-23 17:55:21 +00003667 if (cur == NULL) return;
3668 switch(cur->type) {
3669 case XML_TEXT_NODE:
3670 case XML_CDATA_SECTION_NODE:
3671 case XML_COMMENT_NODE:
3672 case XML_DOCUMENT_NODE:
3673 case XML_DOCUMENT_TYPE_NODE:
3674 case XML_DOCUMENT_FRAG_NODE:
3675 case XML_NOTATION_NODE:
3676 case XML_HTML_DOCUMENT_NODE:
3677 case XML_DTD_NODE:
3678 case XML_ELEMENT_DECL:
3679 case XML_ATTRIBUTE_DECL:
3680 case XML_ENTITY_DECL:
3681 case XML_PI_NODE:
3682 case XML_ENTITY_REF_NODE:
3683 case XML_ENTITY_NODE:
3684 case XML_NAMESPACE_DECL:
3685 case XML_XINCLUDE_START:
3686 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003687#ifdef LIBXML_DOCB_ENABLED
3688 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003689#endif
3690 return;
3691 case XML_ELEMENT_NODE:
3692 case XML_ATTRIBUTE_NODE:
3693 break;
3694 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003695
3696 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3697 if (ns == NULL)
3698 return;
3699 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00003700}
3701
3702/**
Owen Taylor3473f882001-02-23 17:55:21 +00003703 * xmlNodeGetBase:
3704 * @doc: the document the node pertains to
3705 * @cur: the node being checked
3706 *
3707 * Searches for the BASE URL. The code should work on both XML
3708 * and HTML document even if base mechanisms are completely different.
3709 * It returns the base as defined in RFC 2396 sections
3710 * 5.1.1. Base URI within Document Content
3711 * and
3712 * 5.1.2. Base URI from the Encapsulating Entity
3713 * However it does not return the document base (5.1.3), use
3714 * xmlDocumentGetBase() for this
3715 *
3716 * Returns a pointer to the base URL, or NULL if not found
3717 * It's up to the caller to free the memory.
3718 */
3719xmlChar *
3720xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003721 xmlChar *oldbase = NULL;
3722 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003723
3724 if ((cur == NULL) && (doc == NULL))
3725 return(NULL);
3726 if (doc == NULL) doc = cur->doc;
3727 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3728 cur = doc->children;
3729 while ((cur != NULL) && (cur->name != NULL)) {
3730 if (cur->type != XML_ELEMENT_NODE) {
3731 cur = cur->next;
3732 continue;
3733 }
3734 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3735 cur = cur->children;
3736 continue;
3737 }
3738 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3739 cur = cur->children;
3740 continue;
3741 }
3742 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3743 return(xmlGetProp(cur, BAD_CAST "href"));
3744 }
3745 cur = cur->next;
3746 }
3747 return(NULL);
3748 }
3749 while (cur != NULL) {
3750 if (cur->type == XML_ENTITY_DECL) {
3751 xmlEntityPtr ent = (xmlEntityPtr) cur;
3752 return(xmlStrdup(ent->URI));
3753 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003754 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003755 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003756 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003757 if (oldbase != NULL) {
3758 newbase = xmlBuildURI(oldbase, base);
3759 if (newbase != NULL) {
3760 xmlFree(oldbase);
3761 xmlFree(base);
3762 oldbase = newbase;
3763 } else {
3764 xmlFree(oldbase);
3765 xmlFree(base);
3766 return(NULL);
3767 }
3768 } else {
3769 oldbase = base;
3770 }
3771 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3772 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3773 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3774 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003775 }
3776 }
Owen Taylor3473f882001-02-23 17:55:21 +00003777 cur = cur->parent;
3778 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003779 if ((doc != NULL) && (doc->URL != NULL)) {
3780 if (oldbase == NULL)
3781 return(xmlStrdup(doc->URL));
3782 newbase = xmlBuildURI(oldbase, doc->URL);
3783 xmlFree(oldbase);
3784 return(newbase);
3785 }
3786 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003787}
3788
3789/**
3790 * xmlNodeGetContent:
3791 * @cur: the node being read
3792 *
3793 * Read the value of a node, this can be either the text carried
3794 * directly by this node if it's a TEXT node or the aggregate string
3795 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00003796 * Entity references are substituted.
3797 * Returns a new #xmlChar * or NULL if no content is available.
Owen Taylor3473f882001-02-23 17:55:21 +00003798 * It's up to the caller to free the memory.
3799 */
3800xmlChar *
3801xmlNodeGetContent(xmlNodePtr cur) {
3802 if (cur == NULL) return(NULL);
3803 switch (cur->type) {
3804 case XML_DOCUMENT_FRAG_NODE:
3805 case XML_ELEMENT_NODE: {
3806 xmlNodePtr tmp = cur;
3807 xmlBufferPtr buffer;
3808 xmlChar *ret;
3809
3810 buffer = xmlBufferCreate();
3811 if (buffer == NULL)
3812 return(NULL);
3813 while (tmp != NULL) {
3814 switch (tmp->type) {
Daniel Veillard2d703722001-05-30 18:32:34 +00003815 case XML_CDATA_SECTION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003816 case XML_TEXT_NODE:
3817 if (tmp->content != NULL)
3818#ifndef XML_USE_BUFFER_CONTENT
3819 xmlBufferCat(buffer, tmp->content);
3820#else
3821 xmlBufferCat(buffer,
3822 xmlBufferContent(tmp->content));
3823#endif
3824 break;
3825 case XML_ENTITY_REF_NODE: {
3826 xmlEntityPtr ent;
3827
3828 ent = xmlGetDocEntity(cur->doc, tmp->name);
3829 if (ent != NULL)
3830 xmlBufferCat(buffer, ent->content);
3831 }
3832 default:
3833 break;
3834 }
3835 /*
3836 * Skip to next node
3837 */
3838 if (tmp->children != NULL) {
3839 if (tmp->children->type != XML_ENTITY_DECL) {
3840 tmp = tmp->children;
3841 continue;
3842 }
3843 }
Daniel Veillard6c831202001-03-07 15:57:53 +00003844 if (tmp == cur)
3845 break;
3846
Owen Taylor3473f882001-02-23 17:55:21 +00003847 if (tmp->next != NULL) {
3848 tmp = tmp->next;
3849 continue;
3850 }
3851
3852 do {
3853 tmp = tmp->parent;
3854 if (tmp == NULL)
3855 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00003856 if (tmp == cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003857 tmp = NULL;
3858 break;
3859 }
3860 if (tmp->next != NULL) {
3861 tmp = tmp->next;
3862 break;
3863 }
3864 } while (tmp != NULL);
3865 }
3866 ret = buffer->content;
3867 buffer->content = NULL;
3868 xmlBufferFree(buffer);
3869 return(ret);
3870 }
3871 case XML_ATTRIBUTE_NODE: {
3872 xmlAttrPtr attr = (xmlAttrPtr) cur;
3873 if (attr->parent != NULL)
3874 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
3875 else
3876 return(xmlNodeListGetString(NULL, attr->children, 1));
3877 break;
3878 }
3879 case XML_COMMENT_NODE:
3880 case XML_PI_NODE:
3881 if (cur->content != NULL)
3882#ifndef XML_USE_BUFFER_CONTENT
3883 return(xmlStrdup(cur->content));
3884#else
3885 return(xmlStrdup(xmlBufferContent(cur->content)));
3886#endif
3887 return(NULL);
3888 case XML_ENTITY_REF_NODE:
3889 /*
3890 * Locate the entity, and get it's content
3891 * @@@
3892 */
3893 return(NULL);
3894 case XML_ENTITY_NODE:
3895 case XML_DOCUMENT_NODE:
3896 case XML_HTML_DOCUMENT_NODE:
3897 case XML_DOCUMENT_TYPE_NODE:
3898 case XML_NOTATION_NODE:
3899 case XML_DTD_NODE:
3900 case XML_XINCLUDE_START:
3901 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003902#ifdef LIBXML_DOCB_ENABLED
3903 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003904#endif
3905 return(NULL);
3906 case XML_NAMESPACE_DECL:
3907 return(xmlStrdup(((xmlNsPtr)cur)->href));
3908 case XML_ELEMENT_DECL:
3909 /* TODO !!! */
3910 return(NULL);
3911 case XML_ATTRIBUTE_DECL:
3912 /* TODO !!! */
3913 return(NULL);
3914 case XML_ENTITY_DECL:
3915 /* TODO !!! */
3916 return(NULL);
3917 case XML_CDATA_SECTION_NODE:
3918 case XML_TEXT_NODE:
3919 if (cur->content != NULL)
3920#ifndef XML_USE_BUFFER_CONTENT
3921 return(xmlStrdup(cur->content));
3922#else
3923 return(xmlStrdup(xmlBufferContent(cur->content)));
3924#endif
3925 return(NULL);
3926 }
3927 return(NULL);
3928}
3929
3930/**
3931 * xmlNodeSetContent:
3932 * @cur: the node being modified
3933 * @content: the new value of the content
3934 *
3935 * Replace the content of a node.
3936 */
3937void
3938xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
3939 if (cur == NULL) {
3940#ifdef DEBUG_TREE
3941 xmlGenericError(xmlGenericErrorContext,
3942 "xmlNodeSetContent : node == NULL\n");
3943#endif
3944 return;
3945 }
3946 switch (cur->type) {
3947 case XML_DOCUMENT_FRAG_NODE:
3948 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00003949 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003950 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3951 cur->children = xmlStringGetNodeList(cur->doc, content);
3952 UPDATE_LAST_CHILD_AND_PARENT(cur)
3953 break;
Owen Taylor3473f882001-02-23 17:55:21 +00003954 case XML_TEXT_NODE:
3955 case XML_CDATA_SECTION_NODE:
3956 case XML_ENTITY_REF_NODE:
3957 case XML_ENTITY_NODE:
3958 case XML_PI_NODE:
3959 case XML_COMMENT_NODE:
3960 if (cur->content != NULL) {
3961#ifndef XML_USE_BUFFER_CONTENT
3962 xmlFree(cur->content);
3963#else
3964 xmlBufferFree(cur->content);
3965#endif
3966 }
3967 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3968 cur->last = cur->children = NULL;
3969 if (content != NULL) {
3970#ifndef XML_USE_BUFFER_CONTENT
3971 cur->content = xmlStrdup(content);
3972#else
3973 cur->content = xmlBufferCreateSize(0);
3974 xmlBufferSetAllocationScheme(cur->content,
3975 xmlGetBufferAllocationScheme());
3976 xmlBufferAdd(cur->content, content, -1);
3977#endif
3978 } else
3979 cur->content = NULL;
3980 break;
3981 case XML_DOCUMENT_NODE:
3982 case XML_HTML_DOCUMENT_NODE:
3983 case XML_DOCUMENT_TYPE_NODE:
3984 case XML_XINCLUDE_START:
3985 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003986#ifdef LIBXML_DOCB_ENABLED
3987 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003988#endif
3989 break;
3990 case XML_NOTATION_NODE:
3991 break;
3992 case XML_DTD_NODE:
3993 break;
3994 case XML_NAMESPACE_DECL:
3995 break;
3996 case XML_ELEMENT_DECL:
3997 /* TODO !!! */
3998 break;
3999 case XML_ATTRIBUTE_DECL:
4000 /* TODO !!! */
4001 break;
4002 case XML_ENTITY_DECL:
4003 /* TODO !!! */
4004 break;
4005 }
4006}
4007
4008/**
4009 * xmlNodeSetContentLen:
4010 * @cur: the node being modified
4011 * @content: the new value of the content
4012 * @len: the size of @content
4013 *
4014 * Replace the content of a node.
4015 */
4016void
4017xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4018 if (cur == NULL) {
4019#ifdef DEBUG_TREE
4020 xmlGenericError(xmlGenericErrorContext,
4021 "xmlNodeSetContentLen : node == NULL\n");
4022#endif
4023 return;
4024 }
4025 switch (cur->type) {
4026 case XML_DOCUMENT_FRAG_NODE:
4027 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004028 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004029 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4030 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4031 UPDATE_LAST_CHILD_AND_PARENT(cur)
4032 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004033 case XML_TEXT_NODE:
4034 case XML_CDATA_SECTION_NODE:
4035 case XML_ENTITY_REF_NODE:
4036 case XML_ENTITY_NODE:
4037 case XML_PI_NODE:
4038 case XML_COMMENT_NODE:
4039 case XML_NOTATION_NODE:
4040 if (cur->content != NULL) {
4041#ifndef XML_USE_BUFFER_CONTENT
4042 xmlFree(cur->content);
4043#else
4044 xmlBufferFree(cur->content);
4045#endif
4046 }
4047 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4048 cur->children = cur->last = NULL;
4049 if (content != NULL) {
4050#ifndef XML_USE_BUFFER_CONTENT
4051 cur->content = xmlStrndup(content, len);
4052#else
4053 cur->content = xmlBufferCreateSize(len);
4054 xmlBufferSetAllocationScheme(cur->content,
4055 xmlGetBufferAllocationScheme());
4056 xmlBufferAdd(cur->content, content, len);
4057#endif
4058 } else
4059 cur->content = NULL;
4060 break;
4061 case XML_DOCUMENT_NODE:
4062 case XML_DTD_NODE:
4063 case XML_HTML_DOCUMENT_NODE:
4064 case XML_DOCUMENT_TYPE_NODE:
4065 case XML_NAMESPACE_DECL:
4066 case XML_XINCLUDE_START:
4067 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004068#ifdef LIBXML_DOCB_ENABLED
4069 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004070#endif
4071 break;
4072 case XML_ELEMENT_DECL:
4073 /* TODO !!! */
4074 break;
4075 case XML_ATTRIBUTE_DECL:
4076 /* TODO !!! */
4077 break;
4078 case XML_ENTITY_DECL:
4079 /* TODO !!! */
4080 break;
4081 }
4082}
4083
4084/**
4085 * xmlNodeAddContentLen:
4086 * @cur: the node being modified
4087 * @content: extra content
4088 * @len: the size of @content
4089 *
4090 * Append the extra substring to the node content.
4091 */
4092void
4093xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4094 if (cur == NULL) {
4095#ifdef DEBUG_TREE
4096 xmlGenericError(xmlGenericErrorContext,
4097 "xmlNodeAddContentLen : node == NULL\n");
4098#endif
4099 return;
4100 }
4101 if (len <= 0) return;
4102 switch (cur->type) {
4103 case XML_DOCUMENT_FRAG_NODE:
4104 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004105 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004106
Daniel Veillard7db37732001-07-12 01:20:08 +00004107 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004108 newNode = xmlNewTextLen(content, len);
4109 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004110 tmp = xmlAddChild(cur, newNode);
4111 if (tmp != newNode)
4112 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004113 if ((last != NULL) && (last->next == newNode)) {
4114 xmlTextMerge(last, newNode);
4115 }
4116 }
4117 break;
4118 }
4119 case XML_ATTRIBUTE_NODE:
4120 break;
4121 case XML_TEXT_NODE:
4122 case XML_CDATA_SECTION_NODE:
4123 case XML_ENTITY_REF_NODE:
4124 case XML_ENTITY_NODE:
4125 case XML_PI_NODE:
4126 case XML_COMMENT_NODE:
4127 case XML_NOTATION_NODE:
4128 if (content != NULL) {
4129#ifndef XML_USE_BUFFER_CONTENT
4130 cur->content = xmlStrncat(cur->content, content, len);
4131#else
4132 xmlBufferAdd(cur->content, content, len);
4133#endif
4134 }
4135 case XML_DOCUMENT_NODE:
4136 case XML_DTD_NODE:
4137 case XML_HTML_DOCUMENT_NODE:
4138 case XML_DOCUMENT_TYPE_NODE:
4139 case XML_NAMESPACE_DECL:
4140 case XML_XINCLUDE_START:
4141 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004142#ifdef LIBXML_DOCB_ENABLED
4143 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004144#endif
4145 break;
4146 case XML_ELEMENT_DECL:
4147 case XML_ATTRIBUTE_DECL:
4148 case XML_ENTITY_DECL:
4149 break;
4150 }
4151}
4152
4153/**
4154 * xmlNodeAddContent:
4155 * @cur: the node being modified
4156 * @content: extra content
4157 *
4158 * Append the extra substring to the node content.
4159 */
4160void
4161xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4162 int len;
4163
4164 if (cur == NULL) {
4165#ifdef DEBUG_TREE
4166 xmlGenericError(xmlGenericErrorContext,
4167 "xmlNodeAddContent : node == NULL\n");
4168#endif
4169 return;
4170 }
4171 if (content == NULL) return;
4172 len = xmlStrlen(content);
4173 xmlNodeAddContentLen(cur, content, len);
4174}
4175
4176/**
4177 * xmlTextMerge:
4178 * @first: the first text node
4179 * @second: the second text node being merged
4180 *
4181 * Merge two text nodes into one
4182 * Returns the first text node augmented
4183 */
4184xmlNodePtr
4185xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4186 if (first == NULL) return(second);
4187 if (second == NULL) return(first);
4188 if (first->type != XML_TEXT_NODE) return(first);
4189 if (second->type != XML_TEXT_NODE) return(first);
4190 if (second->name != first->name)
4191 return(first);
4192#ifndef XML_USE_BUFFER_CONTENT
4193 xmlNodeAddContent(first, second->content);
4194#else
4195 xmlNodeAddContent(first, xmlBufferContent(second->content));
4196#endif
4197 xmlUnlinkNode(second);
4198 xmlFreeNode(second);
4199 return(first);
4200}
4201
4202/**
4203 * xmlGetNsList:
4204 * @doc: the document
4205 * @node: the current node
4206 *
4207 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004208 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004209 * that need to be freed by the caller or NULL if no
4210 * namespace if defined
4211 */
4212xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004213xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4214{
Owen Taylor3473f882001-02-23 17:55:21 +00004215 xmlNsPtr cur;
4216 xmlNsPtr *ret = NULL;
4217 int nbns = 0;
4218 int maxns = 10;
4219 int i;
4220
4221 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004222 if (node->type == XML_ELEMENT_NODE) {
4223 cur = node->nsDef;
4224 while (cur != NULL) {
4225 if (ret == NULL) {
4226 ret =
4227 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4228 sizeof(xmlNsPtr));
4229 if (ret == NULL) {
4230 xmlGenericError(xmlGenericErrorContext,
4231 "xmlGetNsList : out of memory!\n");
4232 return (NULL);
4233 }
4234 ret[nbns] = NULL;
4235 }
4236 for (i = 0; i < nbns; i++) {
4237 if ((cur->prefix == ret[i]->prefix) ||
4238 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4239 break;
4240 }
4241 if (i >= nbns) {
4242 if (nbns >= maxns) {
4243 maxns *= 2;
4244 ret = (xmlNsPtr *) xmlRealloc(ret,
4245 (maxns +
4246 1) *
4247 sizeof(xmlNsPtr));
4248 if (ret == NULL) {
4249 xmlGenericError(xmlGenericErrorContext,
4250 "xmlGetNsList : realloc failed!\n");
4251 return (NULL);
4252 }
4253 }
4254 ret[nbns++] = cur;
4255 ret[nbns] = NULL;
4256 }
Owen Taylor3473f882001-02-23 17:55:21 +00004257
Daniel Veillard77044732001-06-29 21:31:07 +00004258 cur = cur->next;
4259 }
4260 }
4261 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004262 }
Daniel Veillard77044732001-06-29 21:31:07 +00004263 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004264}
4265
4266/**
4267 * xmlSearchNs:
4268 * @doc: the document
4269 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004270 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004271 *
4272 * Search a Ns registered under a given name space for a document.
4273 * recurse on the parents until it finds the defined namespace
4274 * or return NULL otherwise.
4275 * @nameSpace can be NULL, this is a search for the default namespace.
4276 * We don't allow to cross entities boundaries. If you don't declare
4277 * the namespace within those you will be in troubles !!! A warning
4278 * is generated to cover this case.
4279 *
4280 * Returns the namespace pointer or NULL.
4281 */
4282xmlNsPtr
4283xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4284 xmlNsPtr cur;
4285
4286 if (node == NULL) return(NULL);
4287 if ((nameSpace != NULL) &&
4288 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillardd2f23002002-01-21 13:36:00 +00004289 if (doc == NULL)
4290 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004291 if (doc->oldNs == NULL) {
4292 /*
4293 * Allocate a new Namespace and fill the fields.
4294 */
4295 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4296 if (doc->oldNs == NULL) {
4297 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004298 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004299 return(NULL);
4300 }
4301 memset(doc->oldNs, 0, sizeof(xmlNs));
4302 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4303
4304 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4305 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4306 }
4307 return(doc->oldNs);
4308 }
4309 while (node != NULL) {
4310 if ((node->type == XML_ENTITY_REF_NODE) ||
4311 (node->type == XML_ENTITY_NODE) ||
4312 (node->type == XML_ENTITY_DECL))
4313 return(NULL);
4314 if (node->type == XML_ELEMENT_NODE) {
4315 cur = node->nsDef;
4316 while (cur != NULL) {
4317 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4318 (cur->href != NULL))
4319 return(cur);
4320 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4321 (cur->href != NULL) &&
4322 (xmlStrEqual(cur->prefix, nameSpace)))
4323 return(cur);
4324 cur = cur->next;
4325 }
4326 }
4327 node = node->parent;
4328 }
4329 return(NULL);
4330}
4331
4332/**
4333 * xmlSearchNsByHref:
4334 * @doc: the document
4335 * @node: the current node
4336 * @href: the namespace value
4337 *
4338 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4339 * the defined namespace or return NULL otherwise.
4340 * Returns the namespace pointer or NULL.
4341 */
4342xmlNsPtr
4343xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4344 xmlNsPtr cur;
4345 xmlNodePtr orig = node;
4346
4347 if ((node == NULL) || (href == NULL)) return(NULL);
4348 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004349 /*
4350 * Only the document can hold the XML spec namespace.
4351 */
4352 if (doc == NULL)
4353 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004354 if (doc->oldNs == NULL) {
4355 /*
4356 * Allocate a new Namespace and fill the fields.
4357 */
4358 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4359 if (doc->oldNs == NULL) {
4360 xmlGenericError(xmlGenericErrorContext,
4361 "xmlSearchNsByHref : malloc failed\n");
4362 return(NULL);
4363 }
4364 memset(doc->oldNs, 0, sizeof(xmlNs));
4365 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4366
4367 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4368 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4369 }
4370 return(doc->oldNs);
4371 }
4372 while (node != NULL) {
4373 cur = node->nsDef;
4374 while (cur != NULL) {
4375 if ((cur->href != NULL) && (href != NULL) &&
4376 (xmlStrEqual(cur->href, href))) {
4377 /*
4378 * Check that the prefix is not shadowed between orig and node
4379 */
4380 xmlNodePtr check = orig;
4381 xmlNsPtr tst;
4382
4383 while (check != node) {
4384 tst = check->nsDef;
4385 while (tst != NULL) {
4386 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4387 goto shadowed;
4388 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4389 (xmlStrEqual(tst->prefix, cur->prefix)))
4390 goto shadowed;
4391 tst = tst->next;
4392 }
4393 check = check->parent;
4394 }
4395 return(cur);
4396 }
4397shadowed:
4398 cur = cur->next;
4399 }
4400 node = node->parent;
4401 }
4402 return(NULL);
4403}
4404
4405/**
4406 * xmlNewReconciliedNs
4407 * @doc: the document
4408 * @tree: a node expected to hold the new namespace
4409 * @ns: the original namespace
4410 *
4411 * This function tries to locate a namespace definition in a tree
4412 * ancestors, or create a new namespace definition node similar to
4413 * @ns trying to reuse the same prefix. However if the given prefix is
4414 * null (default namespace) or reused within the subtree defined by
4415 * @tree or on one of its ancestors then a new prefix is generated.
4416 * Returns the (new) namespace definition or NULL in case of error
4417 */
4418xmlNsPtr
4419xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4420 xmlNsPtr def;
4421 xmlChar prefix[50];
4422 int counter = 1;
4423
4424 if (tree == NULL) {
4425#ifdef DEBUG_TREE
4426 xmlGenericError(xmlGenericErrorContext,
4427 "xmlNewReconciliedNs : tree == NULL\n");
4428#endif
4429 return(NULL);
4430 }
4431 if (ns == NULL) {
4432#ifdef DEBUG_TREE
4433 xmlGenericError(xmlGenericErrorContext,
4434 "xmlNewReconciliedNs : ns == NULL\n");
4435#endif
4436 return(NULL);
4437 }
4438 /*
4439 * Search an existing namespace definition inherited.
4440 */
4441 def = xmlSearchNsByHref(doc, tree, ns->href);
4442 if (def != NULL)
4443 return(def);
4444
4445 /*
4446 * Find a close prefix which is not already in use.
4447 * Let's strip namespace prefixes longer than 20 chars !
4448 */
4449 sprintf((char *) prefix, "%.20s", ns->prefix);
4450 def = xmlSearchNs(doc, tree, prefix);
4451 while (def != NULL) {
4452 if (counter > 1000) return(NULL);
4453 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
4454 def = xmlSearchNs(doc, tree, prefix);
4455 }
4456
4457 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004458 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004459 */
4460 def = xmlNewNs(tree, ns->href, prefix);
4461 return(def);
4462}
4463
4464/**
4465 * xmlReconciliateNs
4466 * @doc: the document
4467 * @tree: a node defining the subtree to reconciliate
4468 *
4469 * This function checks that all the namespaces declared within the given
4470 * tree are properly declared. This is needed for example after Copy or Cut
4471 * and then paste operations. The subtree may still hold pointers to
4472 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004473 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004474 * the new environment. If not possible the new namespaces are redeclared
4475 * on @tree at the top of the given subtree.
4476 * Returns the number of namespace declarations created or -1 in case of error.
4477 */
4478int
4479xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4480 xmlNsPtr *oldNs = NULL;
4481 xmlNsPtr *newNs = NULL;
4482 int sizeCache = 0;
4483 int nbCache = 0;
4484
4485 xmlNsPtr n;
4486 xmlNodePtr node = tree;
4487 xmlAttrPtr attr;
4488 int ret = 0, i;
4489
4490 while (node != NULL) {
4491 /*
4492 * Reconciliate the node namespace
4493 */
4494 if (node->ns != NULL) {
4495 /*
4496 * initialize the cache if needed
4497 */
4498 if (sizeCache == 0) {
4499 sizeCache = 10;
4500 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4501 sizeof(xmlNsPtr));
4502 if (oldNs == NULL) {
4503 xmlGenericError(xmlGenericErrorContext,
4504 "xmlReconciliateNs : memory pbm\n");
4505 return(-1);
4506 }
4507 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4508 sizeof(xmlNsPtr));
4509 if (newNs == NULL) {
4510 xmlGenericError(xmlGenericErrorContext,
4511 "xmlReconciliateNs : memory pbm\n");
4512 xmlFree(oldNs);
4513 return(-1);
4514 }
4515 }
4516 for (i = 0;i < nbCache;i++) {
4517 if (oldNs[i] == node->ns) {
4518 node->ns = newNs[i];
4519 break;
4520 }
4521 }
4522 if (i == nbCache) {
4523 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004524 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004525 */
4526 n = xmlNewReconciliedNs(doc, tree, node->ns);
4527 if (n != NULL) { /* :-( what if else ??? */
4528 /*
4529 * check if we need to grow the cache buffers.
4530 */
4531 if (sizeCache <= nbCache) {
4532 sizeCache *= 2;
4533 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4534 sizeof(xmlNsPtr));
4535 if (oldNs == NULL) {
4536 xmlGenericError(xmlGenericErrorContext,
4537 "xmlReconciliateNs : memory pbm\n");
4538 xmlFree(newNs);
4539 return(-1);
4540 }
4541 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4542 sizeof(xmlNsPtr));
4543 if (newNs == NULL) {
4544 xmlGenericError(xmlGenericErrorContext,
4545 "xmlReconciliateNs : memory pbm\n");
4546 xmlFree(oldNs);
4547 return(-1);
4548 }
4549 }
4550 newNs[nbCache] = n;
4551 oldNs[nbCache++] = node->ns;
4552 node->ns = n;
4553 }
4554 }
4555 }
4556 /*
4557 * now check for namespace hold by attributes on the node.
4558 */
4559 attr = node->properties;
4560 while (attr != NULL) {
4561 if (attr->ns != NULL) {
4562 /*
4563 * initialize the cache if needed
4564 */
4565 if (sizeCache == 0) {
4566 sizeCache = 10;
4567 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4568 sizeof(xmlNsPtr));
4569 if (oldNs == NULL) {
4570 xmlGenericError(xmlGenericErrorContext,
4571 "xmlReconciliateNs : memory pbm\n");
4572 return(-1);
4573 }
4574 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4575 sizeof(xmlNsPtr));
4576 if (newNs == NULL) {
4577 xmlGenericError(xmlGenericErrorContext,
4578 "xmlReconciliateNs : memory pbm\n");
4579 xmlFree(oldNs);
4580 return(-1);
4581 }
4582 }
4583 for (i = 0;i < nbCache;i++) {
4584 if (oldNs[i] == attr->ns) {
4585 node->ns = newNs[i];
4586 break;
4587 }
4588 }
4589 if (i == nbCache) {
4590 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004591 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004592 */
4593 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4594 if (n != NULL) { /* :-( what if else ??? */
4595 /*
4596 * check if we need to grow the cache buffers.
4597 */
4598 if (sizeCache <= nbCache) {
4599 sizeCache *= 2;
4600 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4601 sizeof(xmlNsPtr));
4602 if (oldNs == NULL) {
4603 xmlGenericError(xmlGenericErrorContext,
4604 "xmlReconciliateNs : memory pbm\n");
4605 xmlFree(newNs);
4606 return(-1);
4607 }
4608 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4609 sizeof(xmlNsPtr));
4610 if (newNs == NULL) {
4611 xmlGenericError(xmlGenericErrorContext,
4612 "xmlReconciliateNs : memory pbm\n");
4613 xmlFree(oldNs);
4614 return(-1);
4615 }
4616 }
4617 newNs[nbCache] = n;
4618 oldNs[nbCache++] = attr->ns;
4619 attr->ns = n;
4620 }
4621 }
4622 }
4623 attr = attr->next;
4624 }
4625
4626 /*
4627 * Browse the full subtree, deep first
4628 */
4629 if (node->children != NULL) {
4630 /* deep first */
4631 node = node->children;
4632 } else if ((node != tree) && (node->next != NULL)) {
4633 /* then siblings */
4634 node = node->next;
4635 } else if (node != tree) {
4636 /* go up to parents->next if needed */
4637 while (node != tree) {
4638 if (node->parent != NULL)
4639 node = node->parent;
4640 if ((node != tree) && (node->next != NULL)) {
4641 node = node->next;
4642 break;
4643 }
4644 if (node->parent == NULL) {
4645 node = NULL;
4646 break;
4647 }
4648 }
4649 /* exit condition */
4650 if (node == tree)
4651 node = NULL;
4652 }
4653 }
4654 return(ret);
4655}
4656
4657/**
4658 * xmlHasProp:
4659 * @node: the node
4660 * @name: the attribute name
4661 *
4662 * Search an attribute associated to a node
4663 * This function also looks in DTD attribute declaration for #FIXED or
4664 * default declaration values unless DTD use has been turned off.
4665 *
4666 * Returns the attribute or the attribute declaration or NULL if
4667 * neither was found.
4668 */
4669xmlAttrPtr
4670xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4671 xmlAttrPtr prop;
4672 xmlDocPtr doc;
4673
4674 if ((node == NULL) || (name == NULL)) return(NULL);
4675 /*
4676 * Check on the properties attached to the node
4677 */
4678 prop = node->properties;
4679 while (prop != NULL) {
4680 if (xmlStrEqual(prop->name, name)) {
4681 return(prop);
4682 }
4683 prop = prop->next;
4684 }
4685 if (!xmlCheckDTD) return(NULL);
4686
4687 /*
4688 * Check if there is a default declaration in the internal
4689 * or external subsets
4690 */
4691 doc = node->doc;
4692 if (doc != NULL) {
4693 xmlAttributePtr attrDecl;
4694 if (doc->intSubset != NULL) {
4695 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4696 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4697 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4698 if (attrDecl != NULL)
4699 return((xmlAttrPtr) attrDecl);
4700 }
4701 }
4702 return(NULL);
4703}
4704
4705/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004706 * xmlHasNsProp:
4707 * @node: the node
4708 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004709 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004710 *
4711 * Search for an attribute associated to a node
4712 * This attribute has to be anchored in the namespace specified.
4713 * This does the entity substitution.
4714 * This function looks in DTD attribute declaration for #FIXED or
4715 * default declaration values unless DTD use has been turned off.
4716 *
4717 * Returns the attribute or the attribute declaration or NULL
4718 * if neither was found.
4719 */
4720xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004721xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004722 xmlAttrPtr prop;
4723 xmlDocPtr doc;
4724 xmlNsPtr ns;
4725
4726 if (node == NULL)
4727 return(NULL);
4728
4729 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004730 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004731 return(xmlHasProp(node, name));
4732 while (prop != NULL) {
4733 /*
4734 * One need to have
4735 * - same attribute names
4736 * - and the attribute carrying that namespace
4737 * or
4738 * no namespace on the attribute and the element carrying it
4739 */
4740 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004741 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4742 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004743 }
4744 prop = prop->next;
4745 }
4746 if (!xmlCheckDTD) return(NULL);
4747
4748 /*
4749 * Check if there is a default declaration in the internal
4750 * or external subsets
4751 */
4752 doc = node->doc;
4753 if (doc != NULL) {
4754 if (doc->intSubset != NULL) {
4755 xmlAttributePtr attrDecl;
4756
4757 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4758 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4759 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4760
4761 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4762 /*
4763 * The DTD declaration only allows a prefix search
4764 */
4765 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004766 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Daniel Veillarde95e2392001-06-06 10:46:28 +00004767 return((xmlAttrPtr) attrDecl);
4768 }
4769 }
4770 }
4771 return(NULL);
4772}
4773
4774/**
Owen Taylor3473f882001-02-23 17:55:21 +00004775 * xmlGetProp:
4776 * @node: the node
4777 * @name: the attribute name
4778 *
4779 * Search and get the value of an attribute associated to a node
4780 * This does the entity substitution.
4781 * This function looks in DTD attribute declaration for #FIXED or
4782 * default declaration values unless DTD use has been turned off.
4783 *
4784 * Returns the attribute value or NULL if not found.
4785 * It's up to the caller to free the memory.
4786 */
4787xmlChar *
4788xmlGetProp(xmlNodePtr node, const xmlChar *name) {
4789 xmlAttrPtr prop;
4790 xmlDocPtr doc;
4791
4792 if ((node == NULL) || (name == NULL)) return(NULL);
4793 /*
4794 * Check on the properties attached to the node
4795 */
4796 prop = node->properties;
4797 while (prop != NULL) {
4798 if (xmlStrEqual(prop->name, name)) {
4799 xmlChar *ret;
4800
4801 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4802 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4803 return(ret);
4804 }
4805 prop = prop->next;
4806 }
4807 if (!xmlCheckDTD) return(NULL);
4808
4809 /*
4810 * Check if there is a default declaration in the internal
4811 * or external subsets
4812 */
4813 doc = node->doc;
4814 if (doc != NULL) {
4815 xmlAttributePtr attrDecl;
4816 if (doc->intSubset != NULL) {
4817 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4818 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4819 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4820 if (attrDecl != NULL)
4821 return(xmlStrdup(attrDecl->defaultValue));
4822 }
4823 }
4824 return(NULL);
4825}
4826
4827/**
4828 * xmlGetNsProp:
4829 * @node: the node
4830 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004831 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004832 *
4833 * Search and get the value of an attribute associated to a node
4834 * This attribute has to be anchored in the namespace specified.
4835 * This does the entity substitution.
4836 * This function looks in DTD attribute declaration for #FIXED or
4837 * default declaration values unless DTD use has been turned off.
4838 *
4839 * Returns the attribute value or NULL if not found.
4840 * It's up to the caller to free the memory.
4841 */
4842xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00004843xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00004844 xmlAttrPtr prop;
4845 xmlDocPtr doc;
4846 xmlNsPtr ns;
4847
4848 if (node == NULL)
4849 return(NULL);
4850
4851 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004852 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00004853 return(xmlGetProp(node, name));
4854 while (prop != NULL) {
4855 /*
4856 * One need to have
4857 * - same attribute names
4858 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004859 */
4860 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00004861 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00004862 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00004863 xmlChar *ret;
4864
4865 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4866 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4867 return(ret);
4868 }
4869 prop = prop->next;
4870 }
4871 if (!xmlCheckDTD) return(NULL);
4872
4873 /*
4874 * Check if there is a default declaration in the internal
4875 * or external subsets
4876 */
4877 doc = node->doc;
4878 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004879 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00004880 xmlAttributePtr attrDecl;
4881
Owen Taylor3473f882001-02-23 17:55:21 +00004882 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4883 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4884 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4885
4886 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4887 /*
4888 * The DTD declaration only allows a prefix search
4889 */
4890 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004891 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00004892 return(xmlStrdup(attrDecl->defaultValue));
4893 }
4894 }
4895 }
4896 return(NULL);
4897}
4898
4899/**
4900 * xmlSetProp:
4901 * @node: the node
4902 * @name: the attribute name
4903 * @value: the attribute value
4904 *
4905 * Set (or reset) an attribute carried by a node.
4906 * Returns the attribute pointer.
4907 */
4908xmlAttrPtr
4909xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004910 xmlAttrPtr prop;
4911 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004912
4913 if ((node == NULL) || (name == NULL))
4914 return(NULL);
4915 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004916 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00004917 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00004918 if ((xmlStrEqual(prop->name, name)) &&
4919 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004920 xmlNodePtr oldprop = prop->children;
4921
Owen Taylor3473f882001-02-23 17:55:21 +00004922 prop->children = NULL;
4923 prop->last = NULL;
4924 if (value != NULL) {
4925 xmlChar *buffer;
4926 xmlNodePtr tmp;
4927
4928 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4929 prop->children = xmlStringGetNodeList(node->doc, buffer);
4930 prop->last = NULL;
4931 prop->doc = doc;
4932 tmp = prop->children;
4933 while (tmp != NULL) {
4934 tmp->parent = (xmlNodePtr) prop;
4935 tmp->doc = doc;
4936 if (tmp->next == NULL)
4937 prop->last = tmp;
4938 tmp = tmp->next;
4939 }
4940 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00004941 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004942 if (oldprop != NULL)
4943 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00004944 return(prop);
4945 }
4946 prop = prop->next;
4947 }
4948 prop = xmlNewProp(node, name, value);
4949 return(prop);
4950}
4951
4952/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004953 * xmlUnsetProp:
4954 * @node: the node
4955 * @name: the attribute name
4956 *
4957 * Remove an attribute carried by a node.
4958 * Returns 0 if successful, -1 if not found
4959 */
4960int
4961xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
4962 xmlAttrPtr prop = node->properties, prev = NULL;;
4963
4964 if ((node == NULL) || (name == NULL))
4965 return(-1);
4966 while (prop != NULL) {
4967 if ((xmlStrEqual(prop->name, name)) &&
4968 (prop->ns == NULL)) {
4969 if (prev == NULL)
4970 node->properties = prop->next;
4971 else
4972 prev->next = prop->next;
4973 xmlFreeProp(prop);
4974 return(0);
4975 }
4976 prev = prop;
4977 prop = prop->next;
4978 }
4979 return(-1);
4980}
4981
4982/**
Owen Taylor3473f882001-02-23 17:55:21 +00004983 * xmlSetNsProp:
4984 * @node: the node
4985 * @ns: the namespace definition
4986 * @name: the attribute name
4987 * @value: the attribute value
4988 *
4989 * Set (or reset) an attribute carried by a node.
4990 * The ns structure must be in scope, this is not checked.
4991 *
4992 * Returns the attribute pointer.
4993 */
4994xmlAttrPtr
4995xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
4996 const xmlChar *value) {
4997 xmlAttrPtr prop;
4998
4999 if ((node == NULL) || (name == NULL))
5000 return(NULL);
5001
5002 if (ns == NULL)
5003 return(xmlSetProp(node, name, value));
5004 if (ns->href == NULL)
5005 return(NULL);
5006 prop = node->properties;
5007
5008 while (prop != NULL) {
5009 /*
5010 * One need to have
5011 * - same attribute names
5012 * - and the attribute carrying that namespace
5013 * or
5014 * no namespace on the attribute and the element carrying it
5015 */
5016 if ((xmlStrEqual(prop->name, name)) &&
5017 (((prop->ns == NULL) && (node->ns != NULL) &&
5018 (xmlStrEqual(node->ns->href, ns->href))) ||
5019 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
5020 if (prop->children != NULL)
5021 xmlFreeNodeList(prop->children);
5022 prop->children = NULL;
5023 prop->last = NULL;
5024 prop->ns = ns;
5025 if (value != NULL) {
5026 xmlChar *buffer;
5027 xmlNodePtr tmp;
5028
5029 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5030 prop->children = xmlStringGetNodeList(node->doc, buffer);
5031 prop->last = NULL;
5032 tmp = prop->children;
5033 while (tmp != NULL) {
5034 tmp->parent = (xmlNodePtr) prop;
5035 if (tmp->next == NULL)
5036 prop->last = tmp;
5037 tmp = tmp->next;
5038 }
5039 xmlFree(buffer);
5040 }
5041 return(prop);
5042 }
5043 prop = prop->next;
5044 }
5045 prop = xmlNewNsProp(node, ns, name, value);
5046 return(prop);
5047}
5048
5049/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005050 * xmlUnsetNsProp:
5051 * @node: the node
5052 * @ns: the namespace definition
5053 * @name: the attribute name
5054 *
5055 * Remove an attribute carried by a node.
5056 * Returns 0 if successful, -1 if not found
5057 */
5058int
5059xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5060 xmlAttrPtr prop = node->properties, prev = NULL;;
5061
5062 if ((node == NULL) || (name == NULL))
5063 return(-1);
5064 if (ns == NULL)
5065 return(xmlUnsetProp(node, name));
5066 if (ns->href == NULL)
5067 return(-1);
5068 while (prop != NULL) {
5069 if ((xmlStrEqual(prop->name, name)) &&
5070 (((prop->ns == NULL) && (node->ns != NULL) &&
5071 (xmlStrEqual(node->ns->href, ns->href))) ||
5072 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
5073 if (prev == NULL)
5074 node->properties = prop->next;
5075 else
5076 prev->next = prop->next;
5077 xmlFreeProp(prop);
5078 return(0);
5079 }
5080 prev = prop;
5081 prop = prop->next;
5082 }
5083 return(-1);
5084}
5085
5086/**
Owen Taylor3473f882001-02-23 17:55:21 +00005087 * xmlNodeIsText:
5088 * @node: the node
5089 *
5090 * Is this node a Text node ?
5091 * Returns 1 yes, 0 no
5092 */
5093int
5094xmlNodeIsText(xmlNodePtr node) {
5095 if (node == NULL) return(0);
5096
5097 if (node->type == XML_TEXT_NODE) return(1);
5098 return(0);
5099}
5100
5101/**
5102 * xmlIsBlankNode:
5103 * @node: the node
5104 *
5105 * Checks whether this node is an empty or whitespace only
5106 * (and possibly ignorable) text-node.
5107 *
5108 * Returns 1 yes, 0 no
5109 */
5110int
5111xmlIsBlankNode(xmlNodePtr node) {
5112 const xmlChar *cur;
5113 if (node == NULL) return(0);
5114
Daniel Veillard7db37732001-07-12 01:20:08 +00005115 if ((node->type != XML_TEXT_NODE) &&
5116 (node->type != XML_CDATA_SECTION_NODE))
5117 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005118 if (node->content == NULL) return(1);
5119#ifndef XML_USE_BUFFER_CONTENT
5120 cur = node->content;
5121#else
5122 cur = xmlBufferContent(node->content);
5123#endif
5124 while (*cur != 0) {
5125 if (!IS_BLANK(*cur)) return(0);
5126 cur++;
5127 }
5128
5129 return(1);
5130}
5131
5132/**
5133 * xmlTextConcat:
5134 * @node: the node
5135 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005136 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005137 *
5138 * Concat the given string at the end of the existing node content
5139 */
5140
5141void
5142xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5143 if (node == NULL) return;
5144
5145 if ((node->type != XML_TEXT_NODE) &&
5146 (node->type != XML_CDATA_SECTION_NODE)) {
5147#ifdef DEBUG_TREE
5148 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005149 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005150#endif
5151 return;
5152 }
5153#ifndef XML_USE_BUFFER_CONTENT
5154 node->content = xmlStrncat(node->content, content, len);
5155#else
5156 xmlBufferAdd(node->content, content, len);
5157#endif
5158}
5159
5160/************************************************************************
5161 * *
5162 * Output : to a FILE or in memory *
5163 * *
5164 ************************************************************************/
5165
Owen Taylor3473f882001-02-23 17:55:21 +00005166/**
5167 * xmlBufferCreate:
5168 *
5169 * routine to create an XML buffer.
5170 * returns the new structure.
5171 */
5172xmlBufferPtr
5173xmlBufferCreate(void) {
5174 xmlBufferPtr ret;
5175
5176 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5177 if (ret == NULL) {
5178 xmlGenericError(xmlGenericErrorContext,
5179 "xmlBufferCreate : out of memory!\n");
5180 return(NULL);
5181 }
5182 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005183 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005184 ret->alloc = xmlBufferAllocScheme;
5185 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5186 if (ret->content == NULL) {
5187 xmlGenericError(xmlGenericErrorContext,
5188 "xmlBufferCreate : out of memory!\n");
5189 xmlFree(ret);
5190 return(NULL);
5191 }
5192 ret->content[0] = 0;
5193 return(ret);
5194}
5195
5196/**
5197 * xmlBufferCreateSize:
5198 * @size: initial size of buffer
5199 *
5200 * routine to create an XML buffer.
5201 * returns the new structure.
5202 */
5203xmlBufferPtr
5204xmlBufferCreateSize(size_t size) {
5205 xmlBufferPtr ret;
5206
5207 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5208 if (ret == NULL) {
5209 xmlGenericError(xmlGenericErrorContext,
5210 "xmlBufferCreate : out of memory!\n");
5211 return(NULL);
5212 }
5213 ret->use = 0;
5214 ret->alloc = xmlBufferAllocScheme;
5215 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5216 if (ret->size){
5217 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5218 if (ret->content == NULL) {
5219 xmlGenericError(xmlGenericErrorContext,
5220 "xmlBufferCreate : out of memory!\n");
5221 xmlFree(ret);
5222 return(NULL);
5223 }
5224 ret->content[0] = 0;
5225 } else
5226 ret->content = NULL;
5227 return(ret);
5228}
5229
5230/**
5231 * xmlBufferSetAllocationScheme:
5232 * @buf: the buffer to free
5233 * @scheme: allocation scheme to use
5234 *
5235 * Sets the allocation scheme for this buffer
5236 */
5237void
5238xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5239 xmlBufferAllocationScheme scheme) {
5240 if (buf == NULL) {
5241#ifdef DEBUG_BUFFER
5242 xmlGenericError(xmlGenericErrorContext,
5243 "xmlBufferSetAllocationScheme: buf == NULL\n");
5244#endif
5245 return;
5246 }
5247
5248 buf->alloc = scheme;
5249}
5250
5251/**
5252 * xmlBufferFree:
5253 * @buf: the buffer to free
5254 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005255 * Frees an XML buffer. It frees both the content and the structure which
5256 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005257 */
5258void
5259xmlBufferFree(xmlBufferPtr buf) {
5260 if (buf == NULL) {
5261#ifdef DEBUG_BUFFER
5262 xmlGenericError(xmlGenericErrorContext,
5263 "xmlBufferFree: buf == NULL\n");
5264#endif
5265 return;
5266 }
5267 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005268 xmlFree(buf->content);
5269 }
Owen Taylor3473f882001-02-23 17:55:21 +00005270 xmlFree(buf);
5271}
5272
5273/**
5274 * xmlBufferEmpty:
5275 * @buf: the buffer
5276 *
5277 * empty a buffer.
5278 */
5279void
5280xmlBufferEmpty(xmlBufferPtr buf) {
5281 if (buf->content == NULL) return;
5282 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005283 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005284}
5285
5286/**
5287 * xmlBufferShrink:
5288 * @buf: the buffer to dump
5289 * @len: the number of xmlChar to remove
5290 *
5291 * Remove the beginning of an XML buffer.
5292 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005293 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005294 */
5295int
5296xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5297 if (len == 0) return(0);
5298 if (len > buf->use) return(-1);
5299
5300 buf->use -= len;
5301 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5302
5303 buf->content[buf->use] = 0;
5304 return(len);
5305}
5306
5307/**
5308 * xmlBufferGrow:
5309 * @buf: the buffer
5310 * @len: the minimum free size to allocate
5311 *
5312 * Grow the available space of an XML buffer.
5313 *
5314 * Returns the new available space or -1 in case of error
5315 */
5316int
5317xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5318 int size;
5319 xmlChar *newbuf;
5320
5321 if (len + buf->use < buf->size) return(0);
5322
5323 size = buf->use + len + 100;
5324
5325 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5326 if (newbuf == NULL) return(-1);
5327 buf->content = newbuf;
5328 buf->size = size;
5329 return(buf->size - buf->use);
5330}
5331
5332/**
5333 * xmlBufferDump:
5334 * @file: the file output
5335 * @buf: the buffer to dump
5336 *
5337 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005338 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005339 */
5340int
5341xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5342 int ret;
5343
5344 if (buf == NULL) {
5345#ifdef DEBUG_BUFFER
5346 xmlGenericError(xmlGenericErrorContext,
5347 "xmlBufferDump: buf == NULL\n");
5348#endif
5349 return(0);
5350 }
5351 if (buf->content == NULL) {
5352#ifdef DEBUG_BUFFER
5353 xmlGenericError(xmlGenericErrorContext,
5354 "xmlBufferDump: buf->content == NULL\n");
5355#endif
5356 return(0);
5357 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005358 if (file == NULL)
5359 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005360 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5361 return(ret);
5362}
5363
5364/**
5365 * xmlBufferContent:
5366 * @buf: the buffer
5367 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005368 * Function to extract the content of a buffer
5369 *
Owen Taylor3473f882001-02-23 17:55:21 +00005370 * Returns the internal content
5371 */
5372
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005373const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005374xmlBufferContent(const xmlBufferPtr buf)
5375{
5376 if(!buf)
5377 return NULL;
5378
5379 return buf->content;
5380}
5381
5382/**
5383 * xmlBufferLength:
5384 * @buf: the buffer
5385 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005386 * Function to get the length of a buffer
5387 *
Owen Taylor3473f882001-02-23 17:55:21 +00005388 * Returns the length of data in the internal content
5389 */
5390
5391int
5392xmlBufferLength(const xmlBufferPtr buf)
5393{
5394 if(!buf)
5395 return 0;
5396
5397 return buf->use;
5398}
5399
5400/**
5401 * xmlBufferResize:
5402 * @buf: the buffer to resize
5403 * @size: the desired size
5404 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005405 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005406 *
5407 * Returns 0 in case of problems, 1 otherwise
5408 */
5409int
5410xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5411{
5412 unsigned int newSize;
5413 xmlChar* rebuf = NULL;
5414
5415 /*take care of empty case*/
5416 newSize = (buf->size ? buf->size*2 : size);
5417
5418 /* Don't resize if we don't have to */
5419 if (size < buf->size)
5420 return 1;
5421
5422 /* figure out new size */
5423 switch (buf->alloc){
5424 case XML_BUFFER_ALLOC_DOUBLEIT:
5425 while (size > newSize) newSize *= 2;
5426 break;
5427 case XML_BUFFER_ALLOC_EXACT:
5428 newSize = size+10;
5429 break;
5430 default:
5431 newSize = size+10;
5432 break;
5433 }
5434
5435 if (buf->content == NULL)
5436 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5437 else
5438 rebuf = (xmlChar *) xmlRealloc(buf->content,
5439 newSize * sizeof(xmlChar));
5440 if (rebuf == NULL) {
5441 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005442 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005443 return 0;
5444 }
5445 buf->content = rebuf;
5446 buf->size = newSize;
5447
5448 return 1;
5449}
5450
5451/**
5452 * xmlBufferAdd:
5453 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005454 * @str: the #xmlChar string
5455 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005456 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005457 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005458 * str is recomputed.
5459 */
5460void
5461xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5462 unsigned int needSize;
5463
5464 if (str == NULL) {
5465#ifdef DEBUG_BUFFER
5466 xmlGenericError(xmlGenericErrorContext,
5467 "xmlBufferAdd: str == NULL\n");
5468#endif
5469 return;
5470 }
5471 if (len < -1) {
5472#ifdef DEBUG_BUFFER
5473 xmlGenericError(xmlGenericErrorContext,
5474 "xmlBufferAdd: len < 0\n");
5475#endif
5476 return;
5477 }
5478 if (len == 0) return;
5479
5480 if (len < 0)
5481 len = xmlStrlen(str);
5482
5483 if (len <= 0) return;
5484
5485 needSize = buf->use + len + 2;
5486 if (needSize > buf->size){
5487 if (!xmlBufferResize(buf, needSize)){
5488 xmlGenericError(xmlGenericErrorContext,
5489 "xmlBufferAdd : out of memory!\n");
5490 return;
5491 }
5492 }
5493
5494 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5495 buf->use += len;
5496 buf->content[buf->use] = 0;
5497}
5498
5499/**
5500 * xmlBufferAddHead:
5501 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005502 * @str: the #xmlChar string
5503 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005504 *
5505 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005506 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005507 */
5508void
5509xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5510 unsigned int needSize;
5511
5512 if (str == NULL) {
5513#ifdef DEBUG_BUFFER
5514 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005515 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005516#endif
5517 return;
5518 }
5519 if (len < -1) {
5520#ifdef DEBUG_BUFFER
5521 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005522 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005523#endif
5524 return;
5525 }
5526 if (len == 0) return;
5527
5528 if (len < 0)
5529 len = xmlStrlen(str);
5530
5531 if (len <= 0) return;
5532
5533 needSize = buf->use + len + 2;
5534 if (needSize > buf->size){
5535 if (!xmlBufferResize(buf, needSize)){
5536 xmlGenericError(xmlGenericErrorContext,
5537 "xmlBufferAddHead : out of memory!\n");
5538 return;
5539 }
5540 }
5541
5542 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5543 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5544 buf->use += len;
5545 buf->content[buf->use] = 0;
5546}
5547
5548/**
5549 * xmlBufferCat:
5550 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005551 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005552 *
5553 * Append a zero terminated string to an XML buffer.
5554 */
5555void
5556xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5557 if (str != NULL)
5558 xmlBufferAdd(buf, str, -1);
5559}
5560
5561/**
5562 * xmlBufferCCat:
5563 * @buf: the buffer to dump
5564 * @str: the C char string
5565 *
5566 * Append a zero terminated C string to an XML buffer.
5567 */
5568void
5569xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5570 const char *cur;
5571
5572 if (str == NULL) {
5573#ifdef DEBUG_BUFFER
5574 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005575 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005576#endif
5577 return;
5578 }
5579 for (cur = str;*cur != 0;cur++) {
5580 if (buf->use + 10 >= buf->size) {
5581 if (!xmlBufferResize(buf, buf->use+10)){
5582 xmlGenericError(xmlGenericErrorContext,
5583 "xmlBufferCCat : out of memory!\n");
5584 return;
5585 }
5586 }
5587 buf->content[buf->use++] = *cur;
5588 }
5589 buf->content[buf->use] = 0;
5590}
5591
5592/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005593 * xmlBufferWriteXmlCHAR:
5594 * @buf: the XML buffer
5595 * @string: the string to add
5596 *
5597 * For VMS only.
5598 * routine which manages and grows an output buffer. This one adds
5599 * xmlChars at the end of the buffer.
5600 */
5601/**
Owen Taylor3473f882001-02-23 17:55:21 +00005602 * xmlBufferWriteCHAR:
5603 * @buf: the XML buffer
5604 * @string: the string to add
5605 *
5606 * routine which manages and grows an output buffer. This one adds
5607 * xmlChars at the end of the buffer.
5608 */
5609void
5610#ifdef VMS
5611xmlBufferWriteXmlCHAR
5612#else
5613xmlBufferWriteCHAR
5614#endif
5615(xmlBufferPtr buf, const xmlChar *string) {
5616 xmlBufferCat(buf, string);
5617}
5618
5619/**
5620 * xmlBufferWriteChar:
5621 * @buf: the XML buffer output
5622 * @string: the string to add
5623 *
5624 * routine which manage and grows an output buffer. This one add
5625 * C chars at the end of the array.
5626 */
5627void
5628xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5629 xmlBufferCCat(buf, string);
5630}
5631
5632
5633/**
5634 * xmlBufferWriteQuotedString:
5635 * @buf: the XML buffer output
5636 * @string: the string to add
5637 *
5638 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005639 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005640 * quote or double-quotes internally
5641 */
5642void
5643xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5644 if (xmlStrchr(string, '"')) {
5645 if (xmlStrchr(string, '\'')) {
5646#ifdef DEBUG_BUFFER
5647 xmlGenericError(xmlGenericErrorContext,
5648 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5649#endif
5650 }
5651 xmlBufferCCat(buf, "'");
5652 xmlBufferCat(buf, string);
5653 xmlBufferCCat(buf, "'");
5654 } else {
5655 xmlBufferCCat(buf, "\"");
5656 xmlBufferCat(buf, string);
5657 xmlBufferCCat(buf, "\"");
5658 }
5659}
5660
5661
5662/************************************************************************
5663 * *
5664 * Dumping XML tree content to a simple buffer *
5665 * *
5666 ************************************************************************/
5667
5668void
5669xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5670 int format);
5671static void
5672xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5673 int format);
5674void
5675htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5676
5677/**
5678 * xmlNsDump:
5679 * @buf: the XML buffer output
5680 * @cur: a namespace
5681 *
5682 * Dump a local Namespace definition.
5683 * Should be called in the context of attributes dumps.
5684 */
5685static void
5686xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5687 if (cur == NULL) {
5688#ifdef DEBUG_TREE
5689 xmlGenericError(xmlGenericErrorContext,
5690 "xmlNsDump : Ns == NULL\n");
5691#endif
5692 return;
5693 }
5694 if (cur->type == XML_LOCAL_NAMESPACE) {
5695 /* Within the context of an element attributes */
5696 if (cur->prefix != NULL) {
5697 xmlBufferWriteChar(buf, " xmlns:");
5698 xmlBufferWriteCHAR(buf, cur->prefix);
5699 } else
5700 xmlBufferWriteChar(buf, " xmlns");
5701 xmlBufferWriteChar(buf, "=");
5702 xmlBufferWriteQuotedString(buf, cur->href);
5703 }
5704}
5705
5706/**
5707 * xmlNsListDump:
5708 * @buf: the XML buffer output
5709 * @cur: the first namespace
5710 *
5711 * Dump a list of local Namespace definitions.
5712 * Should be called in the context of attributes dumps.
5713 */
5714static void
5715xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5716 while (cur != NULL) {
5717 xmlNsDump(buf, cur);
5718 cur = cur->next;
5719 }
5720}
5721
5722/**
5723 * xmlDtdDump:
5724 * @buf: the XML buffer output
Daniel Veillardd1640922001-12-17 15:30:10 +00005725 * @dtd: the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00005726 *
5727 * Dump the XML document DTD, if any.
5728 */
5729static void
5730xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5731 if (dtd == NULL) {
5732#ifdef DEBUG_TREE
5733 xmlGenericError(xmlGenericErrorContext,
5734 "xmlDtdDump : no internal subset\n");
5735#endif
5736 return;
5737 }
5738 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5739 xmlBufferWriteCHAR(buf, dtd->name);
5740 if (dtd->ExternalID != NULL) {
5741 xmlBufferWriteChar(buf, " PUBLIC ");
5742 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5743 xmlBufferWriteChar(buf, " ");
5744 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5745 } else if (dtd->SystemID != NULL) {
5746 xmlBufferWriteChar(buf, " SYSTEM ");
5747 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5748 }
5749 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5750 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5751 xmlBufferWriteChar(buf, ">");
5752 return;
5753 }
5754 xmlBufferWriteChar(buf, " [\n");
5755 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5756#if 0
5757 if (dtd->entities != NULL)
5758 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5759 if (dtd->notations != NULL)
5760 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5761 if (dtd->elements != NULL)
5762 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5763 if (dtd->attributes != NULL)
5764 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5765#endif
5766 xmlBufferWriteChar(buf, "]>");
5767}
5768
5769/**
5770 * xmlAttrDump:
5771 * @buf: the XML buffer output
5772 * @doc: the document
5773 * @cur: the attribute pointer
5774 *
5775 * Dump an XML attribute
5776 */
5777static void
5778xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5779 xmlChar *value;
5780
5781 if (cur == NULL) {
5782#ifdef DEBUG_TREE
5783 xmlGenericError(xmlGenericErrorContext,
5784 "xmlAttrDump : property == NULL\n");
5785#endif
5786 return;
5787 }
5788 xmlBufferWriteChar(buf, " ");
5789 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5790 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5791 xmlBufferWriteChar(buf, ":");
5792 }
5793 xmlBufferWriteCHAR(buf, cur->name);
5794 value = xmlNodeListGetString(doc, cur->children, 0);
5795 if (value != NULL) {
5796 xmlBufferWriteChar(buf, "=");
5797 xmlBufferWriteQuotedString(buf, value);
5798 xmlFree(value);
5799 } else {
5800 xmlBufferWriteChar(buf, "=\"\"");
5801 }
5802}
5803
5804/**
5805 * xmlAttrListDump:
5806 * @buf: the XML buffer output
5807 * @doc: the document
5808 * @cur: the first attribute pointer
5809 *
5810 * Dump a list of XML attributes
5811 */
5812static void
5813xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5814 if (cur == NULL) {
5815#ifdef DEBUG_TREE
5816 xmlGenericError(xmlGenericErrorContext,
5817 "xmlAttrListDump : property == NULL\n");
5818#endif
5819 return;
5820 }
5821 while (cur != NULL) {
5822 xmlAttrDump(buf, doc, cur);
5823 cur = cur->next;
5824 }
5825}
5826
5827
5828
5829/**
5830 * xmlNodeListDump:
5831 * @buf: the XML buffer output
5832 * @doc: the document
5833 * @cur: the first node
5834 * @level: the imbrication level for indenting
5835 * @format: is formatting allowed
5836 *
5837 * Dump an XML node list, recursive behaviour,children are printed too.
5838 */
5839static void
5840xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5841 int format) {
5842 int i;
5843
5844 if (cur == NULL) {
5845#ifdef DEBUG_TREE
5846 xmlGenericError(xmlGenericErrorContext,
5847 "xmlNodeListDump : node == NULL\n");
5848#endif
5849 return;
5850 }
5851 while (cur != NULL) {
5852 if ((format) && (xmlIndentTreeOutput) &&
5853 (cur->type == XML_ELEMENT_NODE))
5854 for (i = 0;i < level;i++)
5855 xmlBufferWriteChar(buf, " ");
5856 xmlNodeDump(buf, doc, cur, level, format);
5857 if (format) {
5858 xmlBufferWriteChar(buf, "\n");
5859 }
5860 cur = cur->next;
5861 }
5862}
5863
5864/**
5865 * xmlNodeDump:
5866 * @buf: the XML buffer output
5867 * @doc: the document
5868 * @cur: the current node
5869 * @level: the imbrication level for indenting
5870 * @format: is formatting allowed
5871 *
5872 * Dump an XML node, recursive behaviour,children are printed too.
5873 */
5874void
5875xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5876 int format) {
5877 int i;
5878 xmlNodePtr tmp;
5879
5880 if (cur == NULL) {
5881#ifdef DEBUG_TREE
5882 xmlGenericError(xmlGenericErrorContext,
5883 "xmlNodeDump : node == NULL\n");
5884#endif
5885 return;
5886 }
5887 if (cur->type == XML_XINCLUDE_START)
5888 return;
5889 if (cur->type == XML_XINCLUDE_END)
5890 return;
5891 if (cur->type == XML_DTD_NODE) {
5892 xmlDtdDump(buf, (xmlDtdPtr) cur);
5893 return;
5894 }
5895 if (cur->type == XML_ELEMENT_DECL) {
5896 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
5897 return;
5898 }
Daniel Veillard78d12092001-10-11 09:12:24 +00005899 if (cur->type == XML_ATTRIBUTE_NODE){
5900 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
5901 return;
5902 }
Owen Taylor3473f882001-02-23 17:55:21 +00005903 if (cur->type == XML_ATTRIBUTE_DECL) {
5904 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
5905 return;
5906 }
5907 if (cur->type == XML_ENTITY_DECL) {
5908 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
5909 return;
5910 }
5911 if (cur->type == XML_TEXT_NODE) {
5912 if (cur->content != NULL) {
5913 if ((cur->name == xmlStringText) ||
5914 (cur->name != xmlStringTextNoenc)) {
5915 xmlChar *buffer;
5916
5917#ifndef XML_USE_BUFFER_CONTENT
5918 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5919#else
5920 buffer = xmlEncodeEntitiesReentrant(doc,
5921 xmlBufferContent(cur->content));
5922#endif
5923 if (buffer != NULL) {
5924 xmlBufferWriteCHAR(buf, buffer);
5925 xmlFree(buffer);
5926 }
5927 } else {
5928 /*
5929 * Disable escaping, needed for XSLT
5930 */
5931#ifndef XML_USE_BUFFER_CONTENT
5932 xmlBufferWriteCHAR(buf, cur->content);
5933#else
5934 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5935#endif
5936 }
5937 }
5938 return;
5939 }
5940 if (cur->type == XML_PI_NODE) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00005941 xmlBufferWriteChar(buf, "<?");
5942 xmlBufferWriteCHAR(buf, cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005943 if (cur->content != NULL) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00005944 xmlBufferWriteChar(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00005945#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard2c748c62002-01-16 15:37:50 +00005946 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005947#else
Daniel Veillard2c748c62002-01-16 15:37:50 +00005948 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00005949#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005950 }
Daniel Veillard2c748c62002-01-16 15:37:50 +00005951 xmlBufferWriteChar(buf, "?>");
Owen Taylor3473f882001-02-23 17:55:21 +00005952 return;
5953 }
5954 if (cur->type == XML_COMMENT_NODE) {
5955 if (cur->content != NULL) {
5956 xmlBufferWriteChar(buf, "<!--");
5957#ifndef XML_USE_BUFFER_CONTENT
5958 xmlBufferWriteCHAR(buf, cur->content);
5959#else
5960 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5961#endif
5962 xmlBufferWriteChar(buf, "-->");
5963 }
5964 return;
5965 }
5966 if (cur->type == XML_ENTITY_REF_NODE) {
5967 xmlBufferWriteChar(buf, "&");
5968 xmlBufferWriteCHAR(buf, cur->name);
5969 xmlBufferWriteChar(buf, ";");
5970 return;
5971 }
5972 if (cur->type == XML_CDATA_SECTION_NODE) {
5973 xmlBufferWriteChar(buf, "<![CDATA[");
5974 if (cur->content != NULL)
5975#ifndef XML_USE_BUFFER_CONTENT
5976 xmlBufferWriteCHAR(buf, cur->content);
5977#else
5978 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5979#endif
5980 xmlBufferWriteChar(buf, "]]>");
5981 return;
5982 }
5983
5984 if (format == 1) {
5985 tmp = cur->children;
5986 while (tmp != NULL) {
5987 if ((tmp->type == XML_TEXT_NODE) ||
5988 (tmp->type == XML_ENTITY_REF_NODE)) {
5989 format = 0;
5990 break;
5991 }
5992 tmp = tmp->next;
5993 }
5994 }
5995 xmlBufferWriteChar(buf, "<");
5996 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5997 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5998 xmlBufferWriteChar(buf, ":");
5999 }
6000
6001 xmlBufferWriteCHAR(buf, cur->name);
6002 if (cur->nsDef)
6003 xmlNsListDump(buf, cur->nsDef);
6004 if (cur->properties != NULL)
6005 xmlAttrListDump(buf, doc, cur->properties);
6006
Daniel Veillard7db37732001-07-12 01:20:08 +00006007 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6008 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00006009 (!xmlSaveNoEmptyTags)) {
6010 xmlBufferWriteChar(buf, "/>");
6011 return;
6012 }
6013 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006014 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006015 xmlChar *buffer;
6016
6017#ifndef XML_USE_BUFFER_CONTENT
6018 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6019#else
6020 buffer = xmlEncodeEntitiesReentrant(doc,
6021 xmlBufferContent(cur->content));
6022#endif
6023 if (buffer != NULL) {
6024 xmlBufferWriteCHAR(buf, buffer);
6025 xmlFree(buffer);
6026 }
6027 }
6028 if (cur->children != NULL) {
6029 if (format) xmlBufferWriteChar(buf, "\n");
6030 xmlNodeListDump(buf, doc, cur->children,
6031 (level >= 0?level+1:-1), format);
6032 if ((xmlIndentTreeOutput) && (format))
6033 for (i = 0;i < level;i++)
6034 xmlBufferWriteChar(buf, " ");
6035 }
6036 xmlBufferWriteChar(buf, "</");
6037 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6038 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6039 xmlBufferWriteChar(buf, ":");
6040 }
6041
6042 xmlBufferWriteCHAR(buf, cur->name);
6043 xmlBufferWriteChar(buf, ">");
6044}
6045
6046/**
6047 * xmlElemDump:
6048 * @f: the FILE * for the output
6049 * @doc: the document
6050 * @cur: the current node
6051 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006052 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006053 */
6054void
6055xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
6056 xmlBufferPtr buf;
6057
6058 if (cur == NULL) {
6059#ifdef DEBUG_TREE
6060 xmlGenericError(xmlGenericErrorContext,
6061 "xmlElemDump : cur == NULL\n");
6062#endif
6063 return;
6064 }
Owen Taylor3473f882001-02-23 17:55:21 +00006065#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006066 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006067 xmlGenericError(xmlGenericErrorContext,
6068 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006069 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006070#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00006071
Owen Taylor3473f882001-02-23 17:55:21 +00006072 buf = xmlBufferCreate();
6073 if (buf == NULL) return;
6074 if ((doc != NULL) &&
6075 (doc->type == XML_HTML_DOCUMENT_NODE)) {
6076#ifdef LIBXML_HTML_ENABLED
6077 htmlNodeDump(buf, doc, cur);
6078#else
6079 xmlGenericError(xmlGenericErrorContext,
6080 "HTML support not compiled in\n");
6081#endif /* LIBXML_HTML_ENABLED */
6082 } else
6083 xmlNodeDump(buf, doc, cur, 0, 1);
6084 xmlBufferDump(f, buf);
6085 xmlBufferFree(buf);
6086}
6087
6088/************************************************************************
6089 * *
6090 * Dumping XML tree content to an I/O output buffer *
6091 * *
6092 ************************************************************************/
6093
6094void
6095xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6096 int level, int format, const char *encoding);
6097static void
6098xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6099 int level, int format, const char *encoding);
6100/**
6101 * xmlNsDumpOutput:
6102 * @buf: the XML buffer output
6103 * @cur: a namespace
6104 *
6105 * Dump a local Namespace definition.
6106 * Should be called in the context of attributes dumps.
6107 */
6108static void
6109xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6110 if (cur == NULL) {
6111#ifdef DEBUG_TREE
6112 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006113 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006114#endif
6115 return;
6116 }
6117 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
6118 /* Within the context of an element attributes */
6119 if (cur->prefix != NULL) {
6120 xmlOutputBufferWriteString(buf, " xmlns:");
6121 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6122 } else
6123 xmlOutputBufferWriteString(buf, " xmlns");
6124 xmlOutputBufferWriteString(buf, "=");
6125 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6126 }
6127}
6128
6129/**
6130 * xmlNsListDumpOutput:
6131 * @buf: the XML buffer output
6132 * @cur: the first namespace
6133 *
6134 * Dump a list of local Namespace definitions.
6135 * Should be called in the context of attributes dumps.
6136 */
6137static void
6138xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6139 while (cur != NULL) {
6140 xmlNsDumpOutput(buf, cur);
6141 cur = cur->next;
6142 }
6143}
6144
6145/**
6146 * xmlDtdDumpOutput:
6147 * @buf: the XML buffer output
6148 * @doc: the document
6149 * @encoding: an optional encoding string
6150 *
6151 * Dump the XML document DTD, if any.
6152 */
6153static void
6154xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6155 if (dtd == NULL) {
6156#ifdef DEBUG_TREE
6157 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006158 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006159#endif
6160 return;
6161 }
6162 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6163 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6164 if (dtd->ExternalID != NULL) {
6165 xmlOutputBufferWriteString(buf, " PUBLIC ");
6166 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6167 xmlOutputBufferWriteString(buf, " ");
6168 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6169 } else if (dtd->SystemID != NULL) {
6170 xmlOutputBufferWriteString(buf, " SYSTEM ");
6171 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6172 }
6173 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6174 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6175 xmlOutputBufferWriteString(buf, ">");
6176 return;
6177 }
6178 xmlOutputBufferWriteString(buf, " [\n");
6179 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6180 xmlOutputBufferWriteString(buf, "]>");
6181}
6182
6183/**
6184 * xmlAttrDumpOutput:
6185 * @buf: the XML buffer output
6186 * @doc: the document
6187 * @cur: the attribute pointer
6188 * @encoding: an optional encoding string
6189 *
6190 * Dump an XML attribute
6191 */
6192static void
6193xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006194 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006195 xmlChar *value;
6196
6197 if (cur == NULL) {
6198#ifdef DEBUG_TREE
6199 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006200 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006201#endif
6202 return;
6203 }
6204 xmlOutputBufferWriteString(buf, " ");
6205 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6206 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6207 xmlOutputBufferWriteString(buf, ":");
6208 }
6209 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6210 value = xmlNodeListGetString(doc, cur->children, 0);
6211 if (value) {
6212 xmlOutputBufferWriteString(buf, "=");
6213 xmlBufferWriteQuotedString(buf->buffer, value);
6214 xmlFree(value);
6215 } else {
6216 xmlOutputBufferWriteString(buf, "=\"\"");
6217 }
6218}
6219
6220/**
6221 * xmlAttrListDumpOutput:
6222 * @buf: the XML buffer output
6223 * @doc: the document
6224 * @cur: the first attribute pointer
6225 * @encoding: an optional encoding string
6226 *
6227 * Dump a list of XML attributes
6228 */
6229static void
6230xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6231 xmlAttrPtr cur, const char *encoding) {
6232 if (cur == NULL) {
6233#ifdef DEBUG_TREE
6234 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006235 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006236#endif
6237 return;
6238 }
6239 while (cur != NULL) {
6240 xmlAttrDumpOutput(buf, doc, cur, encoding);
6241 cur = cur->next;
6242 }
6243}
6244
6245
6246
6247/**
6248 * xmlNodeListDumpOutput:
6249 * @buf: the XML buffer output
6250 * @doc: the document
6251 * @cur: the first node
6252 * @level: the imbrication level for indenting
6253 * @format: is formatting allowed
6254 * @encoding: an optional encoding string
6255 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006256 * Dump an XML node list, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006257 */
6258static void
6259xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6260 xmlNodePtr cur, int level, int format, const char *encoding) {
6261 int i;
6262
6263 if (cur == NULL) {
6264#ifdef DEBUG_TREE
6265 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006266 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006267#endif
6268 return;
6269 }
6270 while (cur != NULL) {
6271 if ((format) && (xmlIndentTreeOutput) &&
6272 (cur->type == XML_ELEMENT_NODE))
6273 for (i = 0;i < level;i++)
6274 xmlOutputBufferWriteString(buf, " ");
6275 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6276 if (format) {
6277 xmlOutputBufferWriteString(buf, "\n");
6278 }
6279 cur = cur->next;
6280 }
6281}
6282
6283/**
6284 * xmlNodeDumpOutput:
6285 * @buf: the XML buffer output
6286 * @doc: the document
6287 * @cur: the current node
6288 * @level: the imbrication level for indenting
6289 * @format: is formatting allowed
6290 * @encoding: an optional encoding string
6291 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006292 * Dump an XML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006293 */
6294void
6295xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6296 int level, int format, const char *encoding) {
6297 int i;
6298 xmlNodePtr tmp;
6299
6300 if (cur == NULL) {
6301#ifdef DEBUG_TREE
6302 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006303 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006304#endif
6305 return;
6306 }
6307 if (cur->type == XML_XINCLUDE_START)
6308 return;
6309 if (cur->type == XML_XINCLUDE_END)
6310 return;
6311 if (cur->type == XML_DTD_NODE) {
6312 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6313 return;
6314 }
6315 if (cur->type == XML_ELEMENT_DECL) {
6316 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6317 return;
6318 }
6319 if (cur->type == XML_ATTRIBUTE_DECL) {
6320 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6321 return;
6322 }
6323 if (cur->type == XML_ENTITY_DECL) {
6324 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6325 return;
6326 }
6327 if (cur->type == XML_TEXT_NODE) {
6328 if (cur->content != NULL) {
6329 if ((cur->name == xmlStringText) ||
6330 (cur->name != xmlStringTextNoenc)) {
6331 xmlChar *buffer;
6332
6333#ifndef XML_USE_BUFFER_CONTENT
6334 if (encoding == NULL)
6335 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6336 else
6337 buffer = xmlEncodeSpecialChars(doc, cur->content);
6338#else
6339 if (encoding == NULL)
6340 buffer = xmlEncodeEntitiesReentrant(doc,
6341 xmlBufferContent(cur->content));
6342 else
6343 buffer = xmlEncodeSpecialChars(doc,
6344 xmlBufferContent(cur->content));
6345#endif
6346 if (buffer != NULL) {
6347 xmlOutputBufferWriteString(buf, (const char *)buffer);
6348 xmlFree(buffer);
6349 }
6350 } else {
6351 /*
6352 * Disable escaping, needed for XSLT
6353 */
6354#ifndef XML_USE_BUFFER_CONTENT
6355 xmlOutputBufferWriteString(buf, (const char *) cur->content);
6356#else
6357 xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content));
6358#endif
6359 }
6360 }
6361
6362 return;
6363 }
6364 if (cur->type == XML_PI_NODE) {
6365 if (cur->content != NULL) {
6366 xmlOutputBufferWriteString(buf, "<?");
6367 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6368 if (cur->content != NULL) {
6369 xmlOutputBufferWriteString(buf, " ");
6370#ifndef XML_USE_BUFFER_CONTENT
6371 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6372#else
6373 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6374#endif
6375 }
6376 xmlOutputBufferWriteString(buf, "?>");
6377 } else {
6378 xmlOutputBufferWriteString(buf, "<?");
6379 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6380 xmlOutputBufferWriteString(buf, "?>");
6381 }
6382 return;
6383 }
6384 if (cur->type == XML_COMMENT_NODE) {
6385 if (cur->content != NULL) {
6386 xmlOutputBufferWriteString(buf, "<!--");
6387#ifndef XML_USE_BUFFER_CONTENT
6388 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6389#else
6390 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6391#endif
6392 xmlOutputBufferWriteString(buf, "-->");
6393 }
6394 return;
6395 }
6396 if (cur->type == XML_ENTITY_REF_NODE) {
6397 xmlOutputBufferWriteString(buf, "&");
6398 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6399 xmlOutputBufferWriteString(buf, ";");
6400 return;
6401 }
6402 if (cur->type == XML_CDATA_SECTION_NODE) {
6403 xmlOutputBufferWriteString(buf, "<![CDATA[");
6404 if (cur->content != NULL)
6405#ifndef XML_USE_BUFFER_CONTENT
6406 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6407#else
6408 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6409#endif
6410 xmlOutputBufferWriteString(buf, "]]>");
6411 return;
6412 }
6413
6414 if (format == 1) {
6415 tmp = cur->children;
6416 while (tmp != NULL) {
6417 if ((tmp->type == XML_TEXT_NODE) ||
6418 (tmp->type == XML_ENTITY_REF_NODE)) {
6419 format = 0;
6420 break;
6421 }
6422 tmp = tmp->next;
6423 }
6424 }
6425 xmlOutputBufferWriteString(buf, "<");
6426 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6427 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6428 xmlOutputBufferWriteString(buf, ":");
6429 }
6430
6431 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6432 if (cur->nsDef)
6433 xmlNsListDumpOutput(buf, cur->nsDef);
6434 if (cur->properties != NULL)
6435 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6436
Daniel Veillard7db37732001-07-12 01:20:08 +00006437 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6438 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006439 xmlOutputBufferWriteString(buf, "/>");
6440 return;
6441 }
6442 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006443 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006444 xmlChar *buffer;
6445
6446#ifndef XML_USE_BUFFER_CONTENT
6447 if (encoding == NULL)
6448 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6449 else
6450 buffer = xmlEncodeSpecialChars(doc, cur->content);
6451#else
6452 if (encoding == NULL)
6453 buffer = xmlEncodeEntitiesReentrant(doc,
6454 xmlBufferContent(cur->content));
6455 else
6456 buffer = xmlEncodeSpecialChars(doc,
6457 xmlBufferContent(cur->content));
6458#endif
6459 if (buffer != NULL) {
6460 xmlOutputBufferWriteString(buf, (const char *)buffer);
6461 xmlFree(buffer);
6462 }
6463 }
6464 if (cur->children != NULL) {
6465 if (format) xmlOutputBufferWriteString(buf, "\n");
6466 xmlNodeListDumpOutput(buf, doc, cur->children,
6467 (level >= 0?level+1:-1), format, encoding);
6468 if ((xmlIndentTreeOutput) && (format))
6469 for (i = 0;i < level;i++)
6470 xmlOutputBufferWriteString(buf, " ");
6471 }
6472 xmlOutputBufferWriteString(buf, "</");
6473 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6474 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6475 xmlOutputBufferWriteString(buf, ":");
6476 }
6477
6478 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6479 xmlOutputBufferWriteString(buf, ">");
6480}
6481
6482/**
6483 * xmlDocContentDumpOutput:
6484 * @buf: the XML buffer output
6485 * @cur: the document
6486 * @encoding: an optional encoding string
6487 * @format: should formatting spaces been added
6488 *
6489 * Dump an XML document.
6490 */
6491static void
6492xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6493 const char *encoding, int format) {
6494 xmlOutputBufferWriteString(buf, "<?xml version=");
6495 if (cur->version != NULL)
6496 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6497 else
6498 xmlOutputBufferWriteString(buf, "\"1.0\"");
6499 if (encoding == NULL) {
6500 if (cur->encoding != NULL)
6501 encoding = (const char *) cur->encoding;
6502 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6503 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6504 }
6505 if (encoding != NULL) {
6506 xmlOutputBufferWriteString(buf, " encoding=");
6507 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6508 }
6509 switch (cur->standalone) {
6510 case 0:
6511 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6512 break;
6513 case 1:
6514 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6515 break;
6516 }
6517 xmlOutputBufferWriteString(buf, "?>\n");
6518 if (cur->children != NULL) {
6519 xmlNodePtr child = cur->children;
6520
6521 while (child != NULL) {
6522 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6523 xmlOutputBufferWriteString(buf, "\n");
6524 child = child->next;
6525 }
6526 }
6527}
6528
6529/************************************************************************
6530 * *
6531 * Saving functions front-ends *
6532 * *
6533 ************************************************************************/
6534
6535/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006536 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006537 * @out_doc: Document to generate XML text from
6538 * @doc_txt_ptr: Memory pointer for allocated XML text
6539 * @doc_txt_len: Length of the generated XML text
6540 * @txt_encoding: Character encoding to use when generating XML text
6541 * @format: should formatting spaces been added
6542 *
6543 * Dump the current DOM tree into memory using the character encoding specified
6544 * by the caller. Note it is up to the caller of this function to free the
6545 * allocated memory.
6546 */
6547
6548void
6549xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006550 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006551 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006552 int dummy = 0;
6553
6554 xmlCharEncoding doc_charset;
6555 xmlOutputBufferPtr out_buff = NULL;
6556 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6557
6558 if (doc_txt_len == NULL) {
6559 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6560 }
6561
6562 if (doc_txt_ptr == NULL) {
6563 *doc_txt_len = 0;
6564 xmlGenericError(xmlGenericErrorContext,
6565 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6566 return;
6567 }
6568
6569 *doc_txt_ptr = NULL;
6570 *doc_txt_len = 0;
6571
6572 if (out_doc == NULL) {
6573 /* No document, no output */
6574 xmlGenericError(xmlGenericErrorContext,
6575 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6576 return;
6577 }
6578
6579 /*
6580 * Validate the encoding value, if provided.
6581 * This logic is copied from xmlSaveFileEnc.
6582 */
6583
6584 if (txt_encoding == NULL)
6585 txt_encoding = (const char *) out_doc->encoding;
6586 if (txt_encoding != NULL) {
6587 doc_charset = xmlParseCharEncoding(txt_encoding);
6588
6589 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6590 xmlGenericError(xmlGenericErrorContext,
6591 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6592 return;
6593
6594 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6595 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6596 if ( conv_hdlr == NULL ) {
6597 xmlGenericError(xmlGenericErrorContext,
6598 "%s: %s %s '%s'\n",
6599 "xmlDocDumpFormatMemoryEnc",
6600 "Failed to identify encoding handler for",
6601 "character set",
6602 txt_encoding);
6603 return;
6604 }
6605 }
6606 }
6607
6608 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6609 xmlGenericError(xmlGenericErrorContext,
6610 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6611 return;
6612 }
6613
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006614 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006615 xmlOutputBufferFlush(out_buff);
6616 if (out_buff->conv != NULL) {
6617 *doc_txt_len = out_buff->conv->use;
6618 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6619 } else {
6620 *doc_txt_len = out_buff->buffer->use;
6621 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6622 }
6623 (void)xmlOutputBufferClose(out_buff);
6624
6625 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6626 *doc_txt_len = 0;
6627 xmlGenericError(xmlGenericErrorContext,
6628 "xmlDocDumpFormatMemoryEnc: %s\n",
6629 "Failed to allocate memory for document text representation.");
6630 }
6631
6632 return;
6633}
6634
6635/**
6636 * xmlDocDumpMemory:
6637 * @cur: the document
6638 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006639 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006640 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006641 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006642 * It's up to the caller to free the memory.
6643 */
6644void
6645xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6646 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6647}
6648
6649/**
6650 * xmlDocDumpFormatMemory:
6651 * @cur: the document
6652 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006653 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006654 * @format: should formatting spaces been added
6655 *
6656 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006657 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006658 * It's up to the caller to free the memory.
6659 */
6660void
6661xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6662 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6663}
6664
6665/**
6666 * xmlDocDumpMemoryEnc:
6667 * @out_doc: Document to generate XML text from
6668 * @doc_txt_ptr: Memory pointer for allocated XML text
6669 * @doc_txt_len: Length of the generated XML text
6670 * @txt_encoding: Character encoding to use when generating XML text
6671 *
6672 * Dump the current DOM tree into memory using the character encoding specified
6673 * by the caller. Note it is up to the caller of this function to free the
6674 * allocated memory.
6675 */
6676
6677void
6678xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6679 int * doc_txt_len, const char * txt_encoding) {
6680 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006681 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006682}
6683
6684/**
6685 * xmlGetDocCompressMode:
6686 * @doc: the document
6687 *
6688 * get the compression ratio for a document, ZLIB based
6689 * Returns 0 (uncompressed) to 9 (max compression)
6690 */
6691int
6692xmlGetDocCompressMode (xmlDocPtr doc) {
6693 if (doc == NULL) return(-1);
6694 return(doc->compression);
6695}
6696
6697/**
6698 * xmlSetDocCompressMode:
6699 * @doc: the document
6700 * @mode: the compression ratio
6701 *
6702 * set the compression ratio for a document, ZLIB based
6703 * Correct values: 0 (uncompressed) to 9 (max compression)
6704 */
6705void
6706xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6707 if (doc == NULL) return;
6708 if (mode < 0) doc->compression = 0;
6709 else if (mode > 9) doc->compression = 9;
6710 else doc->compression = mode;
6711}
6712
6713/**
6714 * xmlGetCompressMode:
6715 *
6716 * get the default compression mode used, ZLIB based.
6717 * Returns 0 (uncompressed) to 9 (max compression)
6718 */
6719int
6720 xmlGetCompressMode(void) {
6721 return(xmlCompressMode);
6722}
6723
6724/**
6725 * xmlSetCompressMode:
6726 * @mode: the compression ratio
6727 *
6728 * set the default compression mode used, ZLIB based
6729 * Correct values: 0 (uncompressed) to 9 (max compression)
6730 */
6731void
6732xmlSetCompressMode(int mode) {
6733 if (mode < 0) xmlCompressMode = 0;
6734 else if (mode > 9) xmlCompressMode = 9;
6735 else xmlCompressMode = mode;
6736}
6737
6738/**
6739 * xmlDocDump:
6740 * @f: the FILE*
6741 * @cur: the document
6742 *
6743 * Dump an XML document to an open FILE.
6744 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006745 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006746 */
6747int
6748xmlDocDump(FILE *f, xmlDocPtr cur) {
6749 xmlOutputBufferPtr buf;
6750 const char * encoding;
6751 xmlCharEncodingHandlerPtr handler = NULL;
6752 int ret;
6753
6754 if (cur == NULL) {
6755#ifdef DEBUG_TREE
6756 xmlGenericError(xmlGenericErrorContext,
6757 "xmlDocDump : document == NULL\n");
6758#endif
6759 return(-1);
6760 }
6761 encoding = (const char *) cur->encoding;
6762
6763 if (encoding != NULL) {
6764 xmlCharEncoding enc;
6765
6766 enc = xmlParseCharEncoding(encoding);
6767
6768 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6769 xmlGenericError(xmlGenericErrorContext,
6770 "xmlDocDump: document not in UTF8\n");
6771 return(-1);
6772 }
6773 if (enc != XML_CHAR_ENCODING_UTF8) {
6774 handler = xmlFindCharEncodingHandler(encoding);
6775 if (handler == NULL) {
6776 xmlFree((char *) cur->encoding);
6777 cur->encoding = NULL;
6778 }
6779 }
6780 }
6781 buf = xmlOutputBufferCreateFile(f, handler);
6782 if (buf == NULL) return(-1);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006783 xmlDocContentDumpOutput(buf, cur, NULL, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006784
6785 ret = xmlOutputBufferClose(buf);
6786 return(ret);
6787}
6788
6789/**
6790 * xmlSaveFileTo:
6791 * @buf: an output I/O buffer
6792 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00006793 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00006794 *
6795 * Dump an XML document to an I/O buffer.
6796 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006797 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006798 */
6799int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006800xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006801 int ret;
6802
6803 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006804 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006805 ret = xmlOutputBufferClose(buf);
6806 return(ret);
6807}
6808
6809/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00006810 * xmlSaveFormatFileTo:
6811 * @buf: an output I/O buffer
6812 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00006813 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00006814 * @format: should formatting spaces been added
6815 *
6816 * Dump an XML document to an I/O buffer.
6817 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006818 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00006819 */
6820int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006821xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00006822 int ret;
6823
6824 if (buf == NULL) return(0);
6825 xmlDocContentDumpOutput(buf, cur, encoding, format);
6826 ret = xmlOutputBufferClose(buf);
6827 return(ret);
6828}
6829
6830/**
Daniel Veillardf012a642001-07-23 19:10:52 +00006831 * xmlSaveFormatFileEnc
6832 * @filename: the filename or URL to output
6833 * @cur: the document being saved
6834 * @encoding: the name of the encoding to use or NULL.
6835 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00006836 *
6837 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00006838 */
6839int
Daniel Veillardf012a642001-07-23 19:10:52 +00006840xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
6841 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00006842 xmlOutputBufferPtr buf;
6843 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00006844 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00006845 int ret;
6846
Daniel Veillardfb25a512002-01-13 20:32:08 +00006847 if (encoding == NULL)
6848 encoding = (const char *) cur->encoding;
6849
Owen Taylor3473f882001-02-23 17:55:21 +00006850 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006851
6852 enc = xmlParseCharEncoding(encoding);
6853 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6854 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006855 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006856 return(-1);
6857 }
6858 if (enc != XML_CHAR_ENCODING_UTF8) {
6859 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00006860 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006861 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006862 }
6863 }
6864
Daniel Veillardf012a642001-07-23 19:10:52 +00006865#ifdef HAVE_ZLIB_H
6866 if (cur->compression < 0) cur->compression = xmlCompressMode;
6867#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006868 /*
6869 * save the content to a temp buffer.
6870 */
Daniel Veillardf012a642001-07-23 19:10:52 +00006871 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00006872 if (buf == NULL) return(-1);
6873
Daniel Veillardf012a642001-07-23 19:10:52 +00006874 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006875
6876 ret = xmlOutputBufferClose(buf);
6877 return(ret);
6878}
6879
Daniel Veillardf012a642001-07-23 19:10:52 +00006880
6881/**
6882 * xmlSaveFileEnc:
6883 * @filename: the filename (or URL)
6884 * @cur: the document
6885 * @encoding: the name of an encoding (or NULL)
6886 *
6887 * Dump an XML document, converting it to the given encoding
6888 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006889 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00006890 */
6891int
6892xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
6893 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
6894}
6895
Owen Taylor3473f882001-02-23 17:55:21 +00006896/**
Daniel Veillard67fee942001-04-26 18:59:03 +00006897 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00006898 * @filename: the filename (or URL)
6899 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00006900 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00006901 *
6902 * Dump an XML document to a file. Will use compression if
6903 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00006904 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00006905 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006906 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006907 */
6908int
Daniel Veillard67fee942001-04-26 18:59:03 +00006909xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006910 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00006911}
6912
Daniel Veillard67fee942001-04-26 18:59:03 +00006913/**
6914 * xmlSaveFile:
6915 * @filename: the filename (or URL)
6916 * @cur: the document
6917 *
6918 * Dump an XML document to a file. Will use compression if
6919 * compiled in and enabled. If @filename is "-" the stdout file is
6920 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00006921 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00006922 */
6923int
6924xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006925 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00006926}
6927