blob: 900f221967702f2cd561586132152c9b6d04e75d [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;
Daniel Veillard5997aca2002-03-18 18:36:20 +0000559 if (intSubset == extSubset)
560 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000561 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000562 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000563 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000564 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000565 }
Daniel Veillarda9142e72001-06-19 11:07:54 +0000566 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000567 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000568 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000569 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000570 }
571
572 if (cur->children != NULL) xmlFreeNodeList(cur->children);
573
Owen Taylor3473f882001-02-23 17:55:21 +0000574 if (cur->version != NULL) xmlFree((char *) cur->version);
575 if (cur->name != NULL) xmlFree((char *) cur->name);
576 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +0000577 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +0000578 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000579 xmlFree(cur);
580}
581
582/**
583 * xmlStringLenGetNodeList:
584 * @doc: the document
585 * @value: the value of the text
586 * @len: the length of the string value
587 *
588 * Parse the value string and build the node list associated. Should
589 * produce a flat tree with only TEXTs and ENTITY_REFs.
590 * Returns a pointer to the first child
591 */
592xmlNodePtr
593xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
594 xmlNodePtr ret = NULL, last = NULL;
595 xmlNodePtr node;
596 xmlChar *val;
597 const xmlChar *cur = value;
598 const xmlChar *q;
599 xmlEntityPtr ent;
600
601 if (value == NULL) return(NULL);
602
603 q = cur;
604 while ((*cur != 0) && (cur - value < len)) {
605 if (*cur == '&') {
606 /*
607 * Save the current text.
608 */
609 if (cur != q) {
610 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
611 xmlNodeAddContentLen(last, q, cur - q);
612 } else {
613 node = xmlNewDocTextLen(doc, q, cur - q);
614 if (node == NULL) return(ret);
615 if (last == NULL)
616 last = ret = node;
617 else {
618 last->next = node;
619 node->prev = last;
620 last = node;
621 }
622 }
623 }
624 /*
625 * Read the entity string
626 */
627 cur++;
628 q = cur;
629 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
630 if ((*cur == 0) || (cur - value >= len)) {
631#ifdef DEBUG_TREE
632 xmlGenericError(xmlGenericErrorContext,
633 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
634#endif
635 return(ret);
636 }
637 if (cur != q) {
638 /*
639 * Predefined entities don't generate nodes
640 */
641 val = xmlStrndup(q, cur - q);
642 ent = xmlGetDocEntity(doc, val);
643 if ((ent != NULL) &&
644 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
645 if (last == NULL) {
646 node = xmlNewDocText(doc, ent->content);
647 last = ret = node;
648 } else
649 xmlNodeAddContent(last, ent->content);
650
651 } else {
652 /*
653 * Create a new REFERENCE_REF node
654 */
655 node = xmlNewReference(doc, val);
656 if (node == NULL) {
657 if (val != NULL) xmlFree(val);
658 return(ret);
659 }
660 if (last == NULL)
661 last = ret = node;
662 else {
663 last->next = node;
664 node->prev = last;
665 last = node;
666 }
667 }
668 xmlFree(val);
669 }
670 cur++;
671 q = cur;
672 } else
673 cur++;
674 }
675 if (cur != q) {
676 /*
677 * Handle the last piece of text.
678 */
679 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
680 xmlNodeAddContentLen(last, q, cur - q);
681 } else {
682 node = xmlNewDocTextLen(doc, q, cur - q);
683 if (node == NULL) return(ret);
684 if (last == NULL)
685 last = ret = node;
686 else {
687 last->next = node;
688 node->prev = last;
689 last = node;
690 }
691 }
692 }
693 return(ret);
694}
695
696/**
697 * xmlStringGetNodeList:
698 * @doc: the document
699 * @value: the value of the attribute
700 *
701 * Parse the value string and build the node list associated. Should
702 * produce a flat tree with only TEXTs and ENTITY_REFs.
703 * Returns a pointer to the first child
704 */
705xmlNodePtr
706xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
707 xmlNodePtr ret = NULL, last = NULL;
708 xmlNodePtr node;
709 xmlChar *val;
710 const xmlChar *cur = value;
711 const xmlChar *q;
712 xmlEntityPtr ent;
713
714 if (value == NULL) return(NULL);
715
716 q = cur;
717 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000718 if (cur[0] == '&') {
719 int charval = 0;
720 xmlChar tmp;
721
Owen Taylor3473f882001-02-23 17:55:21 +0000722 /*
723 * Save the current text.
724 */
725 if (cur != q) {
726 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
727 xmlNodeAddContentLen(last, q, cur - q);
728 } else {
729 node = xmlNewDocTextLen(doc, q, cur - q);
730 if (node == NULL) return(ret);
731 if (last == NULL)
732 last = ret = node;
733 else {
734 last->next = node;
735 node->prev = last;
736 last = node;
737 }
738 }
739 }
Owen Taylor3473f882001-02-23 17:55:21 +0000740 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000741 if ((cur[1] == '#') && (cur[2] == 'x')) {
742 cur += 3;
743 tmp = *cur;
744 while (tmp != ';') { /* Non input consuming loop */
745 if ((tmp >= '0') && (tmp <= '9'))
746 charval = charval * 16 + (tmp - '0');
747 else if ((tmp >= 'a') && (tmp <= 'f'))
748 charval = charval * 16 + (tmp - 'a') + 10;
749 else if ((tmp >= 'A') && (tmp <= 'F'))
750 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +0000751 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000752 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000753 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000754 charval = 0;
755 break;
756 }
757 cur++;
758 tmp = *cur;
759 }
760 if (tmp == ';')
761 cur++;
762 q = cur;
763 } else if (cur[1] == '#') {
764 cur += 2;
765 tmp = *cur;
766 while (tmp != ';') { /* Non input consuming loops */
767 if ((tmp >= '0') && (tmp <= '9'))
768 charval = charval * 10 + (tmp - '0');
769 else {
770 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000771 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000772 charval = 0;
773 break;
774 }
775 cur++;
776 tmp = *cur;
777 }
778 if (tmp == ';')
779 cur++;
780 q = cur;
781 } else {
782 /*
783 * Read the entity string
784 */
785 cur++;
786 q = cur;
787 while ((*cur != 0) && (*cur != ';')) cur++;
788 if (*cur == 0) {
789#ifdef DEBUG_TREE
790 xmlGenericError(xmlGenericErrorContext,
791 "xmlStringGetNodeList: unterminated entity %30s\n", q);
792#endif
793 return(ret);
794 }
795 if (cur != q) {
796 /*
797 * Predefined entities don't generate nodes
798 */
799 val = xmlStrndup(q, cur - q);
800 ent = xmlGetDocEntity(doc, val);
801 if ((ent != NULL) &&
802 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
803 if (last == NULL) {
804 node = xmlNewDocText(doc, ent->content);
805 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +0000806 } else if (last->type != XML_TEXT_NODE) {
807 node = xmlNewDocText(doc, ent->content);
808 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000809 } else
810 xmlNodeAddContent(last, ent->content);
811
812 } else {
813 /*
814 * Create a new REFERENCE_REF node
815 */
816 node = xmlNewReference(doc, val);
817 if (node == NULL) {
818 if (val != NULL) xmlFree(val);
819 return(ret);
820 }
821 if (last == NULL) {
822 last = ret = node;
823 } else {
824 last = xmlAddNextSibling(last, node);
825 }
826 }
827 xmlFree(val);
828 }
829 cur++;
830 q = cur;
831 }
832 if (charval != 0) {
833 xmlChar buf[10];
834 int len;
835
836 len = xmlCopyCharMultiByte(buf, charval);
837 buf[len] = 0;
838 node = xmlNewDocText(doc, buf);
839 if (node != NULL) {
840 if (last == NULL) {
841 last = ret = node;
842 } else {
843 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000844 }
845 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000846
847 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000848 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000849 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000850 cur++;
851 }
Daniel Veillard75bea542001-05-11 17:41:21 +0000852 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000853 /*
854 * Handle the last piece of text.
855 */
856 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
857 xmlNodeAddContentLen(last, q, cur - q);
858 } else {
859 node = xmlNewDocTextLen(doc, q, cur - q);
860 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000861 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000862 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000863 } else {
864 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000865 }
866 }
867 }
868 return(ret);
869}
870
871/**
872 * xmlNodeListGetString:
873 * @doc: the document
874 * @list: a Node list
875 * @inLine: should we replace entity contents or show their external form
876 *
877 * Returns the string equivalent to the text contained in the Node list
878 * made of TEXTs and ENTITY_REFs
Daniel Veillardd1640922001-12-17 15:30:10 +0000879 * Returns a pointer to the string copy, the caller must free it.
Owen Taylor3473f882001-02-23 17:55:21 +0000880 */
881xmlChar *
882xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
883 xmlNodePtr node = list;
884 xmlChar *ret = NULL;
885 xmlEntityPtr ent;
886
887 if (list == NULL) return(NULL);
888
889 while (node != NULL) {
890 if ((node->type == XML_TEXT_NODE) ||
891 (node->type == XML_CDATA_SECTION_NODE)) {
892 if (inLine) {
Owen Taylor3473f882001-02-23 17:55:21 +0000893 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000894 } else {
895 xmlChar *buffer;
896
Owen Taylor3473f882001-02-23 17:55:21 +0000897 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000898 if (buffer != NULL) {
899 ret = xmlStrcat(ret, buffer);
900 xmlFree(buffer);
901 }
902 }
903 } else if (node->type == XML_ENTITY_REF_NODE) {
904 if (inLine) {
905 ent = xmlGetDocEntity(doc, node->name);
906 if (ent != NULL)
907 ret = xmlStrcat(ret, ent->content);
908 else {
Owen Taylor3473f882001-02-23 17:55:21 +0000909 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000910 }
911 } else {
912 xmlChar buf[2];
913 buf[0] = '&'; buf[1] = 0;
914 ret = xmlStrncat(ret, buf, 1);
915 ret = xmlStrcat(ret, node->name);
916 buf[0] = ';'; buf[1] = 0;
917 ret = xmlStrncat(ret, buf, 1);
918 }
919 }
920#if 0
921 else {
922 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000923 "xmlGetNodeListString : invalid node type %d\n",
Owen Taylor3473f882001-02-23 17:55:21 +0000924 node->type);
925 }
926#endif
927 node = node->next;
928 }
929 return(ret);
930}
931
932/**
933 * xmlNodeListGetRawString:
934 * @doc: the document
935 * @list: a Node list
936 * @inLine: should we replace entity contents or show their external form
937 *
938 * Returns the string equivalent to the text contained in the Node list
939 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
940 * this function doesn't do any character encoding handling.
941 *
Daniel Veillardd1640922001-12-17 15:30:10 +0000942 * Returns a pointer to the string copy, the caller must free it.
Owen Taylor3473f882001-02-23 17:55:21 +0000943 */
944xmlChar *
945xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
946 xmlNodePtr node = list;
947 xmlChar *ret = NULL;
948 xmlEntityPtr ent;
949
950 if (list == NULL) return(NULL);
951
952 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +0000953 if ((node->type == XML_TEXT_NODE) ||
954 (node->type == XML_CDATA_SECTION_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000955 if (inLine) {
Owen Taylor3473f882001-02-23 17:55:21 +0000956 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000957 } else {
958 xmlChar *buffer;
959
Owen Taylor3473f882001-02-23 17:55:21 +0000960 buffer = xmlEncodeSpecialChars(doc, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000961 if (buffer != NULL) {
962 ret = xmlStrcat(ret, buffer);
963 xmlFree(buffer);
964 }
965 }
966 } else if (node->type == XML_ENTITY_REF_NODE) {
967 if (inLine) {
968 ent = xmlGetDocEntity(doc, node->name);
969 if (ent != NULL)
970 ret = xmlStrcat(ret, ent->content);
971 else {
Owen Taylor3473f882001-02-23 17:55:21 +0000972 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000973 }
974 } else {
975 xmlChar buf[2];
976 buf[0] = '&'; buf[1] = 0;
977 ret = xmlStrncat(ret, buf, 1);
978 ret = xmlStrcat(ret, node->name);
979 buf[0] = ';'; buf[1] = 0;
980 ret = xmlStrncat(ret, buf, 1);
981 }
982 }
983#if 0
984 else {
985 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000986 "xmlGetNodeListString : invalid node type %d\n",
Owen Taylor3473f882001-02-23 17:55:21 +0000987 node->type);
988 }
989#endif
990 node = node->next;
991 }
992 return(ret);
993}
994
995/**
996 * xmlNewProp:
997 * @node: the holding node
998 * @name: the name of the attribute
999 * @value: the value of the attribute
1000 *
1001 * Create a new property carried by a node.
1002 * Returns a pointer to the attribute
1003 */
1004xmlAttrPtr
1005xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1006 xmlAttrPtr cur;
1007 xmlDocPtr doc = NULL;
1008
1009 if (name == NULL) {
1010#ifdef DEBUG_TREE
1011 xmlGenericError(xmlGenericErrorContext,
1012 "xmlNewProp : name == NULL\n");
1013#endif
1014 return(NULL);
1015 }
1016
1017 /*
1018 * Allocate a new property and fill the fields.
1019 */
1020 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1021 if (cur == NULL) {
1022 xmlGenericError(xmlGenericErrorContext,
1023 "xmlNewProp : malloc failed\n");
1024 return(NULL);
1025 }
1026 memset(cur, 0, sizeof(xmlAttr));
1027 cur->type = XML_ATTRIBUTE_NODE;
1028
1029 cur->parent = node;
1030 if (node != NULL) {
1031 doc = node->doc;
1032 cur->doc = doc;
1033 }
1034 cur->name = xmlStrdup(name);
1035 if (value != NULL) {
1036 xmlChar *buffer;
1037 xmlNodePtr tmp;
1038
1039 buffer = xmlEncodeEntitiesReentrant(doc, value);
1040 cur->children = xmlStringGetNodeList(doc, buffer);
1041 cur->last = NULL;
1042 tmp = cur->children;
1043 while (tmp != NULL) {
1044 tmp->parent = (xmlNodePtr) cur;
1045 tmp->doc = doc;
1046 if (tmp->next == NULL)
1047 cur->last = tmp;
1048 tmp = tmp->next;
1049 }
1050 xmlFree(buffer);
1051 }
1052
1053 /*
1054 * Add it at the end to preserve parsing order ...
1055 */
1056 if (node != NULL) {
1057 if (node->properties == NULL) {
1058 node->properties = cur;
1059 } else {
1060 xmlAttrPtr prev = node->properties;
1061
1062 while (prev->next != NULL) prev = prev->next;
1063 prev->next = cur;
1064 cur->prev = prev;
1065 }
1066 }
1067 return(cur);
1068}
1069
1070/**
1071 * xmlNewNsProp:
1072 * @node: the holding node
1073 * @ns: the namespace
1074 * @name: the name of the attribute
1075 * @value: the value of the attribute
1076 *
1077 * Create a new property tagged with a namespace and carried by a node.
1078 * Returns a pointer to the attribute
1079 */
1080xmlAttrPtr
1081xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1082 const xmlChar *value) {
1083 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001084 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001085
1086 if (name == NULL) {
1087#ifdef DEBUG_TREE
1088 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001089 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001090#endif
1091 return(NULL);
1092 }
1093
1094 /*
1095 * Allocate a new property and fill the fields.
1096 */
1097 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1098 if (cur == NULL) {
1099 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001100 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001101 return(NULL);
1102 }
1103 memset(cur, 0, sizeof(xmlAttr));
1104 cur->type = XML_ATTRIBUTE_NODE;
1105
1106 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001107 if (node != NULL) {
1108 doc = node->doc;
1109 cur->doc = doc;
1110 }
Owen Taylor3473f882001-02-23 17:55:21 +00001111 cur->ns = ns;
1112 cur->name = xmlStrdup(name);
1113 if (value != NULL) {
1114 xmlChar *buffer;
1115 xmlNodePtr tmp;
1116
Daniel Veillarda682b212001-06-07 19:59:42 +00001117 buffer = xmlEncodeEntitiesReentrant(doc, value);
1118 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001119 cur->last = NULL;
1120 tmp = cur->children;
1121 while (tmp != NULL) {
1122 tmp->parent = (xmlNodePtr) cur;
1123 if (tmp->next == NULL)
1124 cur->last = tmp;
1125 tmp = tmp->next;
1126 }
1127 xmlFree(buffer);
1128 }
1129
1130 /*
1131 * Add it at the end to preserve parsing order ...
1132 */
1133 if (node != NULL) {
1134 if (node->properties == NULL) {
1135 node->properties = cur;
1136 } else {
1137 xmlAttrPtr prev = node->properties;
1138
1139 while (prev->next != NULL) prev = prev->next;
1140 prev->next = cur;
1141 cur->prev = prev;
1142 }
1143 }
1144 return(cur);
1145}
1146
1147/**
1148 * xmlNewDocProp:
1149 * @doc: the document
1150 * @name: the name of the attribute
1151 * @value: the value of the attribute
1152 *
1153 * Create a new property carried by a document.
1154 * Returns a pointer to the attribute
1155 */
1156xmlAttrPtr
1157xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1158 xmlAttrPtr cur;
1159
1160 if (name == NULL) {
1161#ifdef DEBUG_TREE
1162 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001163 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001164#endif
1165 return(NULL);
1166 }
1167
1168 /*
1169 * Allocate a new property and fill the fields.
1170 */
1171 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1172 if (cur == NULL) {
1173 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001174 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001175 return(NULL);
1176 }
1177 memset(cur, 0, sizeof(xmlAttr));
1178 cur->type = XML_ATTRIBUTE_NODE;
1179
1180 cur->name = xmlStrdup(name);
1181 cur->doc = doc;
1182 if (value != NULL) {
1183 xmlNodePtr tmp;
1184
1185 cur->children = xmlStringGetNodeList(doc, value);
1186 cur->last = NULL;
1187
1188 tmp = cur->children;
1189 while (tmp != NULL) {
1190 tmp->parent = (xmlNodePtr) cur;
1191 if (tmp->next == NULL)
1192 cur->last = tmp;
1193 tmp = tmp->next;
1194 }
1195 }
1196 return(cur);
1197}
1198
1199/**
1200 * xmlFreePropList:
1201 * @cur: the first property in the list
1202 *
1203 * Free a property and all its siblings, all the children are freed too.
1204 */
1205void
1206xmlFreePropList(xmlAttrPtr cur) {
1207 xmlAttrPtr next;
1208 if (cur == NULL) {
1209#ifdef DEBUG_TREE
1210 xmlGenericError(xmlGenericErrorContext,
1211 "xmlFreePropList : property == NULL\n");
1212#endif
1213 return;
1214 }
1215 while (cur != NULL) {
1216 next = cur->next;
1217 xmlFreeProp(cur);
1218 cur = next;
1219 }
1220}
1221
1222/**
1223 * xmlFreeProp:
1224 * @cur: an attribute
1225 *
1226 * Free one attribute, all the content is freed too
1227 */
1228void
1229xmlFreeProp(xmlAttrPtr cur) {
1230 if (cur == NULL) {
1231#ifdef DEBUG_TREE
1232 xmlGenericError(xmlGenericErrorContext,
1233 "xmlFreeProp : property == NULL\n");
1234#endif
1235 return;
1236 }
1237 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001238 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1239 ((cur->parent->doc->intSubset != NULL) ||
1240 (cur->parent->doc->extSubset != NULL))) {
1241 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1242 xmlRemoveID(cur->parent->doc, cur);
1243 }
Owen Taylor3473f882001-02-23 17:55:21 +00001244 if (cur->name != NULL) xmlFree((char *) cur->name);
1245 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001246 xmlFree(cur);
1247}
1248
1249/**
1250 * xmlRemoveProp:
1251 * @cur: an attribute
1252 *
1253 * Unlink and free one attribute, all the content is freed too
1254 * Note this doesn't work for namespace definition attributes
1255 *
1256 * Returns 0 if success and -1 in case of error.
1257 */
1258int
1259xmlRemoveProp(xmlAttrPtr cur) {
1260 xmlAttrPtr tmp;
1261 if (cur == NULL) {
1262#ifdef DEBUG_TREE
1263 xmlGenericError(xmlGenericErrorContext,
1264 "xmlRemoveProp : cur == NULL\n");
1265#endif
1266 return(-1);
1267 }
1268 if (cur->parent == NULL) {
1269#ifdef DEBUG_TREE
1270 xmlGenericError(xmlGenericErrorContext,
1271 "xmlRemoveProp : cur->parent == NULL\n");
1272#endif
1273 return(-1);
1274 }
1275 tmp = cur->parent->properties;
1276 if (tmp == cur) {
1277 cur->parent->properties = cur->next;
1278 xmlFreeProp(cur);
1279 return(0);
1280 }
1281 while (tmp != NULL) {
1282 if (tmp->next == cur) {
1283 tmp->next = cur->next;
1284 if (tmp->next != NULL)
1285 tmp->next->prev = tmp;
1286 xmlFreeProp(cur);
1287 return(0);
1288 }
1289 tmp = tmp->next;
1290 }
1291#ifdef DEBUG_TREE
1292 xmlGenericError(xmlGenericErrorContext,
1293 "xmlRemoveProp : attribute not owned by its node\n");
1294#endif
1295 return(-1);
1296}
1297
1298/**
1299 * xmlNewPI:
1300 * @name: the processing instruction name
1301 * @content: the PI content
1302 *
1303 * Creation of a processing instruction element.
1304 * Returns a pointer to the new node object.
1305 */
1306xmlNodePtr
1307xmlNewPI(const xmlChar *name, const xmlChar *content) {
1308 xmlNodePtr cur;
1309
1310 if (name == NULL) {
1311#ifdef DEBUG_TREE
1312 xmlGenericError(xmlGenericErrorContext,
1313 "xmlNewPI : name == NULL\n");
1314#endif
1315 return(NULL);
1316 }
1317
1318 /*
1319 * Allocate a new node and fill the fields.
1320 */
1321 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1322 if (cur == NULL) {
1323 xmlGenericError(xmlGenericErrorContext,
1324 "xmlNewPI : malloc failed\n");
1325 return(NULL);
1326 }
1327 memset(cur, 0, sizeof(xmlNode));
1328 cur->type = XML_PI_NODE;
1329
1330 cur->name = xmlStrdup(name);
1331 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001332 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001333 }
1334 return(cur);
1335}
1336
1337/**
1338 * xmlNewNode:
1339 * @ns: namespace if any
1340 * @name: the node name
1341 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001342 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001343 *
1344 * Returns a pointer to the new node object.
1345 */
1346xmlNodePtr
1347xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1348 xmlNodePtr cur;
1349
1350 if (name == NULL) {
1351#ifdef DEBUG_TREE
1352 xmlGenericError(xmlGenericErrorContext,
1353 "xmlNewNode : name == NULL\n");
1354#endif
1355 return(NULL);
1356 }
1357
1358 /*
1359 * Allocate a new node and fill the fields.
1360 */
1361 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1362 if (cur == NULL) {
1363 xmlGenericError(xmlGenericErrorContext,
1364 "xmlNewNode : malloc failed\n");
1365 return(NULL);
1366 }
1367 memset(cur, 0, sizeof(xmlNode));
1368 cur->type = XML_ELEMENT_NODE;
1369
1370 cur->name = xmlStrdup(name);
1371 cur->ns = ns;
1372 return(cur);
1373}
1374
1375/**
1376 * xmlNewDocNode:
1377 * @doc: the document
1378 * @ns: namespace if any
1379 * @name: the node name
1380 * @content: the XML text content if any
1381 *
1382 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001383 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001384 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1385 * references, but XML special chars need to be escaped first by using
1386 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1387 * need entities support.
1388 *
1389 * Returns a pointer to the new node object.
1390 */
1391xmlNodePtr
1392xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1393 const xmlChar *name, const xmlChar *content) {
1394 xmlNodePtr cur;
1395
1396 cur = xmlNewNode(ns, name);
1397 if (cur != NULL) {
1398 cur->doc = doc;
1399 if (content != NULL) {
1400 cur->children = xmlStringGetNodeList(doc, content);
1401 UPDATE_LAST_CHILD_AND_PARENT(cur)
1402 }
1403 }
1404 return(cur);
1405}
1406
1407
1408/**
1409 * xmlNewDocRawNode:
1410 * @doc: the document
1411 * @ns: namespace if any
1412 * @name: the node name
1413 * @content: the text content if any
1414 *
1415 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001416 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001417 *
1418 * Returns a pointer to the new node object.
1419 */
1420xmlNodePtr
1421xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1422 const xmlChar *name, const xmlChar *content) {
1423 xmlNodePtr cur;
1424
1425 cur = xmlNewNode(ns, name);
1426 if (cur != NULL) {
1427 cur->doc = doc;
1428 if (content != NULL) {
1429 cur->children = xmlNewDocText(doc, content);
1430 UPDATE_LAST_CHILD_AND_PARENT(cur)
1431 }
1432 }
1433 return(cur);
1434}
1435
1436/**
1437 * xmlNewDocFragment:
1438 * @doc: the document owning the fragment
1439 *
1440 * Creation of a new Fragment node.
1441 * Returns a pointer to the new node object.
1442 */
1443xmlNodePtr
1444xmlNewDocFragment(xmlDocPtr doc) {
1445 xmlNodePtr cur;
1446
1447 /*
1448 * Allocate a new DocumentFragment node and fill the fields.
1449 */
1450 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1451 if (cur == NULL) {
1452 xmlGenericError(xmlGenericErrorContext,
1453 "xmlNewDocFragment : malloc failed\n");
1454 return(NULL);
1455 }
1456 memset(cur, 0, sizeof(xmlNode));
1457 cur->type = XML_DOCUMENT_FRAG_NODE;
1458
1459 cur->doc = doc;
1460 return(cur);
1461}
1462
1463/**
1464 * xmlNewText:
1465 * @content: the text content
1466 *
1467 * Creation of a new text node.
1468 * Returns a pointer to the new node object.
1469 */
1470xmlNodePtr
1471xmlNewText(const xmlChar *content) {
1472 xmlNodePtr cur;
1473
1474 /*
1475 * Allocate a new node and fill the fields.
1476 */
1477 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1478 if (cur == NULL) {
1479 xmlGenericError(xmlGenericErrorContext,
1480 "xmlNewText : malloc failed\n");
1481 return(NULL);
1482 }
1483 memset(cur, 0, sizeof(xmlNode));
1484 cur->type = XML_TEXT_NODE;
1485
1486 cur->name = xmlStringText;
1487 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001488 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001489 }
1490 return(cur);
1491}
1492
1493/**
1494 * xmlNewTextChild:
1495 * @parent: the parent node
1496 * @ns: a namespace if any
1497 * @name: the name of the child
1498 * @content: the text content of the child if any.
1499 *
1500 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001501 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001502 * a child TEXT node will be created containing the string content.
1503 *
1504 * Returns a pointer to the new node object.
1505 */
1506xmlNodePtr
1507xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1508 const xmlChar *name, const xmlChar *content) {
1509 xmlNodePtr cur, prev;
1510
1511 if (parent == NULL) {
1512#ifdef DEBUG_TREE
1513 xmlGenericError(xmlGenericErrorContext,
1514 "xmlNewTextChild : parent == NULL\n");
1515#endif
1516 return(NULL);
1517 }
1518
1519 if (name == NULL) {
1520#ifdef DEBUG_TREE
1521 xmlGenericError(xmlGenericErrorContext,
1522 "xmlNewTextChild : name == NULL\n");
1523#endif
1524 return(NULL);
1525 }
1526
1527 /*
1528 * Allocate a new node
1529 */
1530 if (ns == NULL)
1531 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1532 else
1533 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1534 if (cur == NULL) return(NULL);
1535
1536 /*
1537 * add the new element at the end of the children list.
1538 */
1539 cur->type = XML_ELEMENT_NODE;
1540 cur->parent = parent;
1541 cur->doc = parent->doc;
1542 if (parent->children == NULL) {
1543 parent->children = cur;
1544 parent->last = cur;
1545 } else {
1546 prev = parent->last;
1547 prev->next = cur;
1548 cur->prev = prev;
1549 parent->last = cur;
1550 }
1551
1552 return(cur);
1553}
1554
1555/**
1556 * xmlNewCharRef:
1557 * @doc: the document
1558 * @name: the char ref string, starting with # or "&# ... ;"
1559 *
1560 * Creation of a new character reference node.
1561 * Returns a pointer to the new node object.
1562 */
1563xmlNodePtr
1564xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1565 xmlNodePtr cur;
1566
1567 /*
1568 * Allocate a new node and fill the fields.
1569 */
1570 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1571 if (cur == NULL) {
1572 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001573 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001574 return(NULL);
1575 }
1576 memset(cur, 0, sizeof(xmlNode));
1577 cur->type = XML_ENTITY_REF_NODE;
1578
1579 cur->doc = doc;
1580 if (name[0] == '&') {
1581 int len;
1582 name++;
1583 len = xmlStrlen(name);
1584 if (name[len - 1] == ';')
1585 cur->name = xmlStrndup(name, len - 1);
1586 else
1587 cur->name = xmlStrndup(name, len);
1588 } else
1589 cur->name = xmlStrdup(name);
1590 return(cur);
1591}
1592
1593/**
1594 * xmlNewReference:
1595 * @doc: the document
1596 * @name: the reference name, or the reference string with & and ;
1597 *
1598 * Creation of a new reference node.
1599 * Returns a pointer to the new node object.
1600 */
1601xmlNodePtr
1602xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1603 xmlNodePtr cur;
1604 xmlEntityPtr ent;
1605
1606 /*
1607 * Allocate a new node and fill the fields.
1608 */
1609 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1610 if (cur == NULL) {
1611 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001612 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001613 return(NULL);
1614 }
1615 memset(cur, 0, sizeof(xmlNode));
1616 cur->type = XML_ENTITY_REF_NODE;
1617
1618 cur->doc = doc;
1619 if (name[0] == '&') {
1620 int len;
1621 name++;
1622 len = xmlStrlen(name);
1623 if (name[len - 1] == ';')
1624 cur->name = xmlStrndup(name, len - 1);
1625 else
1626 cur->name = xmlStrndup(name, len);
1627 } else
1628 cur->name = xmlStrdup(name);
1629
1630 ent = xmlGetDocEntity(doc, cur->name);
1631 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001632 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00001633 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001634 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00001635 * updated. Not sure if this is 100% correct.
1636 * -George
1637 */
1638 cur->children = (xmlNodePtr) ent;
1639 cur->last = (xmlNodePtr) ent;
1640 }
1641 return(cur);
1642}
1643
1644/**
1645 * xmlNewDocText:
1646 * @doc: the document
1647 * @content: the text content
1648 *
1649 * Creation of a new text node within a document.
1650 * Returns a pointer to the new node object.
1651 */
1652xmlNodePtr
1653xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1654 xmlNodePtr cur;
1655
1656 cur = xmlNewText(content);
1657 if (cur != NULL) cur->doc = doc;
1658 return(cur);
1659}
1660
1661/**
1662 * xmlNewTextLen:
1663 * @content: the text content
1664 * @len: the text len.
1665 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001666 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00001667 * Returns a pointer to the new node object.
1668 */
1669xmlNodePtr
1670xmlNewTextLen(const xmlChar *content, int len) {
1671 xmlNodePtr cur;
1672
1673 /*
1674 * Allocate a new node and fill the fields.
1675 */
1676 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1677 if (cur == NULL) {
1678 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001679 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001680 return(NULL);
1681 }
1682 memset(cur, 0, sizeof(xmlNode));
1683 cur->type = XML_TEXT_NODE;
1684
1685 cur->name = xmlStringText;
1686 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001687 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001688 }
1689 return(cur);
1690}
1691
1692/**
1693 * xmlNewDocTextLen:
1694 * @doc: the document
1695 * @content: the text content
1696 * @len: the text len.
1697 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001698 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00001699 * text node pertain to a given document.
1700 * Returns a pointer to the new node object.
1701 */
1702xmlNodePtr
1703xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1704 xmlNodePtr cur;
1705
1706 cur = xmlNewTextLen(content, len);
1707 if (cur != NULL) cur->doc = doc;
1708 return(cur);
1709}
1710
1711/**
1712 * xmlNewComment:
1713 * @content: the comment content
1714 *
1715 * Creation of a new node containing a comment.
1716 * Returns a pointer to the new node object.
1717 */
1718xmlNodePtr
1719xmlNewComment(const xmlChar *content) {
1720 xmlNodePtr cur;
1721
1722 /*
1723 * Allocate a new node and fill the fields.
1724 */
1725 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1726 if (cur == NULL) {
1727 xmlGenericError(xmlGenericErrorContext,
1728 "xmlNewComment : malloc failed\n");
1729 return(NULL);
1730 }
1731 memset(cur, 0, sizeof(xmlNode));
1732 cur->type = XML_COMMENT_NODE;
1733
1734 cur->name = xmlStringComment;
1735 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001736 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001737 }
1738 return(cur);
1739}
1740
1741/**
1742 * xmlNewCDataBlock:
1743 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00001744 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00001745 * @len: the length of the block
1746 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001747 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00001748 * Returns a pointer to the new node object.
1749 */
1750xmlNodePtr
1751xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1752 xmlNodePtr cur;
1753
1754 /*
1755 * Allocate a new node and fill the fields.
1756 */
1757 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1758 if (cur == NULL) {
1759 xmlGenericError(xmlGenericErrorContext,
1760 "xmlNewCDataBlock : malloc failed\n");
1761 return(NULL);
1762 }
1763 memset(cur, 0, sizeof(xmlNode));
1764 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001765 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001766
1767 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001768 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001769 }
1770 return(cur);
1771}
1772
1773/**
1774 * xmlNewDocComment:
1775 * @doc: the document
1776 * @content: the comment content
1777 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001778 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00001779 * Returns a pointer to the new node object.
1780 */
1781xmlNodePtr
1782xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1783 xmlNodePtr cur;
1784
1785 cur = xmlNewComment(content);
1786 if (cur != NULL) cur->doc = doc;
1787 return(cur);
1788}
1789
1790/**
1791 * xmlSetTreeDoc:
1792 * @tree: the top element
1793 * @doc: the document
1794 *
1795 * update all nodes under the tree to point to the right document
1796 */
1797void
1798xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00001799 xmlAttrPtr prop;
1800
Owen Taylor3473f882001-02-23 17:55:21 +00001801 if (tree == NULL)
1802 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001803 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00001804 if(tree->type == XML_ELEMENT_NODE) {
1805 prop = tree->properties;
1806 while (prop != NULL) {
1807 prop->doc = doc;
1808 xmlSetListDoc(prop->children, doc);
1809 prop = prop->next;
1810 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00001811 }
Owen Taylor3473f882001-02-23 17:55:21 +00001812 if (tree->children != NULL)
1813 xmlSetListDoc(tree->children, doc);
1814 tree->doc = doc;
1815 }
1816}
1817
1818/**
1819 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00001820 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00001821 * @doc: the document
1822 *
1823 * update all nodes in the list to point to the right document
1824 */
1825void
1826xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
1827 xmlNodePtr cur;
1828
1829 if (list == NULL)
1830 return;
1831 cur = list;
1832 while (cur != NULL) {
1833 if (cur->doc != doc)
1834 xmlSetTreeDoc(cur, doc);
1835 cur = cur->next;
1836 }
1837}
1838
1839
1840/**
1841 * xmlNewChild:
1842 * @parent: the parent node
1843 * @ns: a namespace if any
1844 * @name: the name of the child
1845 * @content: the XML content of the child if any.
1846 *
1847 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001848 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001849 * a child list containing the TEXTs and ENTITY_REFs node will be created.
1850 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1851 * references, but XML special chars need to be escaped first by using
1852 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
1853 * support is not needed.
1854 *
1855 * Returns a pointer to the new node object.
1856 */
1857xmlNodePtr
1858xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
1859 const xmlChar *name, const xmlChar *content) {
1860 xmlNodePtr cur, prev;
1861
1862 if (parent == NULL) {
1863#ifdef DEBUG_TREE
1864 xmlGenericError(xmlGenericErrorContext,
1865 "xmlNewChild : parent == NULL\n");
1866#endif
1867 return(NULL);
1868 }
1869
1870 if (name == NULL) {
1871#ifdef DEBUG_TREE
1872 xmlGenericError(xmlGenericErrorContext,
1873 "xmlNewChild : name == NULL\n");
1874#endif
1875 return(NULL);
1876 }
1877
1878 /*
1879 * Allocate a new node
1880 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00001881 if (parent->type == XML_ELEMENT_NODE) {
1882 if (ns == NULL)
1883 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
1884 else
1885 cur = xmlNewDocNode(parent->doc, ns, name, content);
1886 } else if ((parent->type == XML_DOCUMENT_NODE) ||
1887 (parent->type == XML_HTML_DOCUMENT_NODE)) {
1888 if (ns == NULL)
1889 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
1890 else
1891 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
1892 } else {
1893 return(NULL);
1894 }
Owen Taylor3473f882001-02-23 17:55:21 +00001895 if (cur == NULL) return(NULL);
1896
1897 /*
1898 * add the new element at the end of the children list.
1899 */
1900 cur->type = XML_ELEMENT_NODE;
1901 cur->parent = parent;
1902 cur->doc = parent->doc;
1903 if (parent->children == NULL) {
1904 parent->children = cur;
1905 parent->last = cur;
1906 } else {
1907 prev = parent->last;
1908 prev->next = cur;
1909 cur->prev = prev;
1910 parent->last = cur;
1911 }
1912
1913 return(cur);
1914}
1915
1916/**
1917 * xmlAddNextSibling:
1918 * @cur: the child node
1919 * @elem: the new node
1920 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001921 * Add a new node @elem as the next sibling of @cur
1922 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00001923 * first unlinked from its existing context.
1924 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001925 * If the new node is ATTRIBUTE, it is added into properties instead of children.
1926 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00001927 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001928 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001929 */
1930xmlNodePtr
1931xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
1932 if (cur == NULL) {
1933#ifdef DEBUG_TREE
1934 xmlGenericError(xmlGenericErrorContext,
1935 "xmlAddNextSibling : cur == NULL\n");
1936#endif
1937 return(NULL);
1938 }
1939 if (elem == NULL) {
1940#ifdef DEBUG_TREE
1941 xmlGenericError(xmlGenericErrorContext,
1942 "xmlAddNextSibling : elem == NULL\n");
1943#endif
1944 return(NULL);
1945 }
1946
1947 xmlUnlinkNode(elem);
1948
1949 if (elem->type == XML_TEXT_NODE) {
1950 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00001951 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001952 xmlFreeNode(elem);
1953 return(cur);
1954 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00001955 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
1956 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001957 xmlChar *tmp;
1958
1959 tmp = xmlStrdup(elem->content);
1960 tmp = xmlStrcat(tmp, cur->next->content);
1961 xmlNodeSetContent(cur->next, tmp);
1962 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00001963 xmlFreeNode(elem);
1964 return(cur->next);
1965 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001966 } else if (elem->type == XML_ATTRIBUTE_NODE) {
1967 /* check if an attribute with the same name exists */
1968 xmlAttrPtr attr;
1969
1970 if (elem->ns == NULL)
1971 attr = xmlHasProp(cur->parent, elem->name);
1972 else
1973 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
1974 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
1975 /* different instance, destroy it (attributes must be unique) */
1976 xmlFreeProp(attr);
1977 }
Owen Taylor3473f882001-02-23 17:55:21 +00001978 }
1979
1980 if (elem->doc != cur->doc) {
1981 xmlSetTreeDoc(elem, cur->doc);
1982 }
1983 elem->parent = cur->parent;
1984 elem->prev = cur;
1985 elem->next = cur->next;
1986 cur->next = elem;
1987 if (elem->next != NULL)
1988 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001989 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00001990 elem->parent->last = elem;
1991 return(elem);
1992}
1993
1994/**
1995 * xmlAddPrevSibling:
1996 * @cur: the child node
1997 * @elem: the new node
1998 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001999 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002000 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002001 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002002 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002003 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2004 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002005 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002006 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002007 */
2008xmlNodePtr
2009xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2010 if (cur == NULL) {
2011#ifdef DEBUG_TREE
2012 xmlGenericError(xmlGenericErrorContext,
2013 "xmlAddPrevSibling : cur == NULL\n");
2014#endif
2015 return(NULL);
2016 }
2017 if (elem == NULL) {
2018#ifdef DEBUG_TREE
2019 xmlGenericError(xmlGenericErrorContext,
2020 "xmlAddPrevSibling : elem == NULL\n");
2021#endif
2022 return(NULL);
2023 }
2024
2025 xmlUnlinkNode(elem);
2026
2027 if (elem->type == XML_TEXT_NODE) {
2028 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002029 xmlChar *tmp;
2030
2031 tmp = xmlStrdup(elem->content);
2032 tmp = xmlStrcat(tmp, cur->content);
2033 xmlNodeSetContent(cur, tmp);
2034 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002035 xmlFreeNode(elem);
2036 return(cur);
2037 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002038 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2039 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002040 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002041 xmlFreeNode(elem);
2042 return(cur->prev);
2043 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002044 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2045 /* check if an attribute with the same name exists */
2046 xmlAttrPtr attr;
2047
2048 if (elem->ns == NULL)
2049 attr = xmlHasProp(cur->parent, elem->name);
2050 else
2051 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2052 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2053 /* different instance, destroy it (attributes must be unique) */
2054 xmlFreeProp(attr);
2055 }
Owen Taylor3473f882001-02-23 17:55:21 +00002056 }
2057
2058 if (elem->doc != cur->doc) {
2059 xmlSetTreeDoc(elem, cur->doc);
2060 }
2061 elem->parent = cur->parent;
2062 elem->next = cur;
2063 elem->prev = cur->prev;
2064 cur->prev = elem;
2065 if (elem->prev != NULL)
2066 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002067 if (elem->parent != NULL) {
2068 if (elem->type == XML_ATTRIBUTE_NODE) {
2069 if (elem->parent->properties == (xmlAttrPtr) cur) {
2070 elem->parent->properties = (xmlAttrPtr) elem;
2071 }
2072 } else {
2073 if (elem->parent->children == cur) {
2074 elem->parent->children = elem;
2075 }
2076 }
2077 }
Owen Taylor3473f882001-02-23 17:55:21 +00002078 return(elem);
2079}
2080
2081/**
2082 * xmlAddSibling:
2083 * @cur: the child node
2084 * @elem: the new node
2085 *
2086 * Add a new element @elem to the list of siblings of @cur
2087 * merging adjacent TEXT nodes (@elem may be freed)
2088 * If the new element was already inserted in a document it is
2089 * first unlinked from its existing context.
2090 *
2091 * Returns the new element or NULL in case of error.
2092 */
2093xmlNodePtr
2094xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2095 xmlNodePtr parent;
2096
2097 if (cur == NULL) {
2098#ifdef DEBUG_TREE
2099 xmlGenericError(xmlGenericErrorContext,
2100 "xmlAddSibling : cur == NULL\n");
2101#endif
2102 return(NULL);
2103 }
2104
2105 if (elem == NULL) {
2106#ifdef DEBUG_TREE
2107 xmlGenericError(xmlGenericErrorContext,
2108 "xmlAddSibling : elem == NULL\n");
2109#endif
2110 return(NULL);
2111 }
2112
2113 /*
2114 * Constant time is we can rely on the ->parent->last to find
2115 * the last sibling.
2116 */
2117 if ((cur->parent != NULL) &&
2118 (cur->parent->children != NULL) &&
2119 (cur->parent->last != NULL) &&
2120 (cur->parent->last->next == NULL)) {
2121 cur = cur->parent->last;
2122 } else {
2123 while (cur->next != NULL) cur = cur->next;
2124 }
2125
2126 xmlUnlinkNode(elem);
2127
2128 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002129 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002130 xmlFreeNode(elem);
2131 return(cur);
2132 }
2133
2134 if (elem->doc != cur->doc) {
2135 xmlSetTreeDoc(elem, cur->doc);
2136 }
2137 parent = cur->parent;
2138 elem->prev = cur;
2139 elem->next = NULL;
2140 elem->parent = parent;
2141 cur->next = elem;
2142 if (parent != NULL)
2143 parent->last = elem;
2144
2145 return(elem);
2146}
2147
2148/**
2149 * xmlAddChildList:
2150 * @parent: the parent node
2151 * @cur: the first node in the list
2152 *
2153 * Add a list of node at the end of the child list of the parent
2154 * merging adjacent TEXT nodes (@cur may be freed)
2155 *
2156 * Returns the last child or NULL in case of error.
2157 */
2158xmlNodePtr
2159xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2160 xmlNodePtr prev;
2161
2162 if (parent == NULL) {
2163#ifdef DEBUG_TREE
2164 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002165 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002166#endif
2167 return(NULL);
2168 }
2169
2170 if (cur == NULL) {
2171#ifdef DEBUG_TREE
2172 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002173 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002174#endif
2175 return(NULL);
2176 }
2177
2178 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2179 (cur->doc != parent->doc)) {
2180#ifdef DEBUG_TREE
2181 xmlGenericError(xmlGenericErrorContext,
2182 "Elements moved to a different document\n");
2183#endif
2184 }
2185
2186 /*
2187 * add the first element at the end of the children list.
2188 */
2189 if (parent->children == NULL) {
2190 parent->children = cur;
2191 } else {
2192 /*
2193 * If cur and parent->last both are TEXT nodes, then merge them.
2194 */
2195 if ((cur->type == XML_TEXT_NODE) &&
2196 (parent->last->type == XML_TEXT_NODE) &&
2197 (cur->name == parent->last->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002198 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002199 /*
2200 * if it's the only child, nothing more to be done.
2201 */
2202 if (cur->next == NULL) {
2203 xmlFreeNode(cur);
2204 return(parent->last);
2205 }
2206 prev = cur;
2207 cur = cur->next;
2208 xmlFreeNode(prev);
2209 }
2210 prev = parent->last;
2211 prev->next = cur;
2212 cur->prev = prev;
2213 }
2214 while (cur->next != NULL) {
2215 cur->parent = parent;
2216 if (cur->doc != parent->doc) {
2217 xmlSetTreeDoc(cur, parent->doc);
2218 }
2219 cur = cur->next;
2220 }
2221 cur->parent = parent;
2222 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2223 parent->last = cur;
2224
2225 return(cur);
2226}
2227
2228/**
2229 * xmlAddChild:
2230 * @parent: the parent node
2231 * @cur: the child node
2232 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002233 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002234 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002235 * If the new node was already inserted in a document it is
2236 * first unlinked from its existing context.
2237 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2238 * If there is an attribute with equal name, it is first destroyed.
2239 *
Owen Taylor3473f882001-02-23 17:55:21 +00002240 * Returns the child or NULL in case of error.
2241 */
2242xmlNodePtr
2243xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2244 xmlNodePtr prev;
2245
2246 if (parent == NULL) {
2247#ifdef DEBUG_TREE
2248 xmlGenericError(xmlGenericErrorContext,
2249 "xmlAddChild : parent == NULL\n");
2250#endif
2251 return(NULL);
2252 }
2253
2254 if (cur == NULL) {
2255#ifdef DEBUG_TREE
2256 xmlGenericError(xmlGenericErrorContext,
2257 "xmlAddChild : child == NULL\n");
2258#endif
2259 return(NULL);
2260 }
2261
Owen Taylor3473f882001-02-23 17:55:21 +00002262 /*
2263 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002264 * cur is then freed.
2265 */
2266 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002267 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002268 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002269 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002270 xmlFreeNode(cur);
2271 return(parent);
2272 }
2273 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2274 (parent->last->name == cur->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002275 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002276 xmlFreeNode(cur);
2277 return(parent->last);
2278 }
2279 }
2280
2281 /*
2282 * add the new element at the end of the children list.
2283 */
2284 cur->parent = parent;
2285 if (cur->doc != parent->doc) {
2286 xmlSetTreeDoc(cur, parent->doc);
2287 }
2288
2289 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002290 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002291 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002292 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002293 (parent->content != NULL)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002294 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002295 xmlFreeNode(cur);
2296 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002297 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002298 if (cur->type == XML_ATTRIBUTE_NODE) {
2299 if (parent->properties == NULL) {
2300 parent->properties = (xmlAttrPtr) cur;
2301 } else {
2302 /* check if an attribute with the same name exists */
2303 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002304
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002305 if (cur->ns == NULL)
2306 lastattr = xmlHasProp(parent, cur->name);
2307 else
2308 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2309 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2310 /* different instance, destroy it (attributes must be unique) */
2311 xmlFreeProp(lastattr);
2312 }
2313 /* find the end */
2314 lastattr = parent->properties;
2315 while (lastattr->next != NULL) {
2316 lastattr = lastattr->next;
2317 }
2318 lastattr->next = (xmlAttrPtr) cur;
2319 ((xmlAttrPtr) cur)->prev = lastattr;
2320 }
2321 } else {
2322 if (parent->children == NULL) {
2323 parent->children = cur;
2324 parent->last = cur;
2325 } else {
2326 prev = parent->last;
2327 prev->next = cur;
2328 cur->prev = prev;
2329 parent->last = cur;
2330 }
2331 }
Owen Taylor3473f882001-02-23 17:55:21 +00002332 return(cur);
2333}
2334
2335/**
2336 * xmlGetLastChild:
2337 * @parent: the parent node
2338 *
2339 * Search the last child of a node.
2340 * Returns the last child or NULL if none.
2341 */
2342xmlNodePtr
2343xmlGetLastChild(xmlNodePtr parent) {
2344 if (parent == NULL) {
2345#ifdef DEBUG_TREE
2346 xmlGenericError(xmlGenericErrorContext,
2347 "xmlGetLastChild : parent == NULL\n");
2348#endif
2349 return(NULL);
2350 }
2351 return(parent->last);
2352}
2353
2354/**
2355 * xmlFreeNodeList:
2356 * @cur: the first node in the list
2357 *
2358 * Free a node and all its siblings, this is a recursive behaviour, all
2359 * the children are freed too.
2360 */
2361void
2362xmlFreeNodeList(xmlNodePtr cur) {
2363 xmlNodePtr next;
2364 if (cur == NULL) {
2365#ifdef DEBUG_TREE
2366 xmlGenericError(xmlGenericErrorContext,
2367 "xmlFreeNodeList : node == NULL\n");
2368#endif
2369 return;
2370 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002371 if (cur->type == XML_NAMESPACE_DECL) {
2372 xmlFreeNsList((xmlNsPtr) cur);
2373 return;
2374 }
Owen Taylor3473f882001-02-23 17:55:21 +00002375 while (cur != NULL) {
2376 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002377 /* unroll to speed up freeing the document */
2378 if (cur->type != XML_DTD_NODE) {
2379 if ((cur->children != NULL) &&
2380 (cur->type != XML_ENTITY_REF_NODE))
2381 xmlFreeNodeList(cur->children);
2382 if (cur->properties != NULL)
2383 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002384 if ((cur->type != XML_ELEMENT_NODE) &&
2385 (cur->type != XML_XINCLUDE_START) &&
2386 (cur->type != XML_XINCLUDE_END) &&
2387 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002388 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002389 }
2390 if (((cur->type == XML_ELEMENT_NODE) ||
2391 (cur->type == XML_XINCLUDE_START) ||
2392 (cur->type == XML_XINCLUDE_END)) &&
2393 (cur->nsDef != NULL))
2394 xmlFreeNsList(cur->nsDef);
2395
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002396 /*
2397 * When a node is a text node or a comment, it uses a global static
2398 * variable for the name of the node.
2399 *
2400 * The xmlStrEqual comparisons need to be done when (happened with
2401 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002402 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002403 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002404 * the string addresses compare are not sufficient.
2405 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002406 if ((cur->name != NULL) &&
2407 (cur->name != xmlStringText) &&
2408 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002409 (cur->name != xmlStringComment)) {
2410 if (cur->type == XML_TEXT_NODE) {
2411 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2412 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2413 xmlFree((char *) cur->name);
2414 } else if (cur->type == XML_COMMENT_NODE) {
2415 if (!xmlStrEqual(cur->name, xmlStringComment))
2416 xmlFree((char *) cur->name);
2417 } else
2418 xmlFree((char *) cur->name);
2419 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002420 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002421 xmlFree(cur);
2422 }
Owen Taylor3473f882001-02-23 17:55:21 +00002423 cur = next;
2424 }
2425}
2426
2427/**
2428 * xmlFreeNode:
2429 * @cur: the node
2430 *
2431 * Free a node, this is a recursive behaviour, all the children are freed too.
2432 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2433 */
2434void
2435xmlFreeNode(xmlNodePtr cur) {
2436 if (cur == NULL) {
2437#ifdef DEBUG_TREE
2438 xmlGenericError(xmlGenericErrorContext,
2439 "xmlFreeNode : node == NULL\n");
2440#endif
2441 return;
2442 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002443 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002444 if (cur->type == XML_DTD_NODE) {
2445 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002446 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002447 }
2448 if (cur->type == XML_NAMESPACE_DECL) {
2449 xmlFreeNs((xmlNsPtr) cur);
2450 return;
2451 }
Owen Taylor3473f882001-02-23 17:55:21 +00002452 if ((cur->children != NULL) &&
2453 (cur->type != XML_ENTITY_REF_NODE))
2454 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002455 if (cur->properties != NULL)
2456 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002457 if ((cur->type != XML_ELEMENT_NODE) &&
2458 (cur->content != NULL) &&
2459 (cur->type != XML_ENTITY_REF_NODE) &&
2460 (cur->type != XML_XINCLUDE_END) &&
2461 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002462 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002463 }
2464
Daniel Veillardacd370f2001-06-09 17:17:51 +00002465 /*
2466 * When a node is a text node or a comment, it uses a global static
2467 * variable for the name of the node.
2468 *
2469 * The xmlStrEqual comparisons need to be done when (happened with
2470 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002471 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002472 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002473 * are not sufficient.
2474 */
Owen Taylor3473f882001-02-23 17:55:21 +00002475 if ((cur->name != NULL) &&
2476 (cur->name != xmlStringText) &&
2477 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002478 (cur->name != xmlStringComment)) {
2479 if (cur->type == XML_TEXT_NODE) {
2480 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2481 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2482 xmlFree((char *) cur->name);
2483 } else if (cur->type == XML_COMMENT_NODE) {
2484 if (!xmlStrEqual(cur->name, xmlStringComment))
2485 xmlFree((char *) cur->name);
2486 } else
2487 xmlFree((char *) cur->name);
2488 }
2489
Owen Taylor3473f882001-02-23 17:55:21 +00002490 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002491 xmlFree(cur);
2492}
2493
2494/**
2495 * xmlUnlinkNode:
2496 * @cur: the node
2497 *
2498 * Unlink a node from it's current context, the node is not freed
2499 */
2500void
2501xmlUnlinkNode(xmlNodePtr cur) {
2502 if (cur == NULL) {
2503#ifdef DEBUG_TREE
2504 xmlGenericError(xmlGenericErrorContext,
2505 "xmlUnlinkNode : node == NULL\n");
2506#endif
2507 return;
2508 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002509 if (cur->type == XML_DTD_NODE) {
2510 xmlDocPtr doc;
2511 doc = cur->doc;
2512 if (doc->intSubset == (xmlDtdPtr) cur)
2513 doc->intSubset = NULL;
2514 if (doc->extSubset == (xmlDtdPtr) cur)
2515 doc->extSubset = NULL;
2516 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002517 if (cur->parent != NULL) {
2518 xmlNodePtr parent;
2519 parent = cur->parent;
2520 if (cur->type == XML_ATTRIBUTE_NODE) {
2521 if (parent->properties == (xmlAttrPtr) cur)
2522 parent->properties = ((xmlAttrPtr) cur)->next;
2523 } else {
2524 if (parent->children == cur)
2525 parent->children = cur->next;
2526 if (parent->last == cur)
2527 parent->last = cur->prev;
2528 }
2529 cur->parent = NULL;
2530 }
Owen Taylor3473f882001-02-23 17:55:21 +00002531 if (cur->next != NULL)
2532 cur->next->prev = cur->prev;
2533 if (cur->prev != NULL)
2534 cur->prev->next = cur->next;
2535 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002536}
2537
2538/**
2539 * xmlReplaceNode:
2540 * @old: the old node
2541 * @cur: the node
2542 *
2543 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002544 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002545 * first unlinked from its existing context.
2546 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002547 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002548 */
2549xmlNodePtr
2550xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2551 if (old == NULL) {
2552#ifdef DEBUG_TREE
2553 xmlGenericError(xmlGenericErrorContext,
2554 "xmlReplaceNode : old == NULL\n");
2555#endif
2556 return(NULL);
2557 }
2558 if (cur == NULL) {
2559 xmlUnlinkNode(old);
2560 return(old);
2561 }
2562 if (cur == old) {
2563 return(old);
2564 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002565 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2566#ifdef DEBUG_TREE
2567 xmlGenericError(xmlGenericErrorContext,
2568 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2569#endif
2570 return(old);
2571 }
2572 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2573#ifdef DEBUG_TREE
2574 xmlGenericError(xmlGenericErrorContext,
2575 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2576#endif
2577 return(old);
2578 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002579 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2580#ifdef DEBUG_TREE
2581 xmlGenericError(xmlGenericErrorContext,
2582 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2583#endif
2584 return(old);
2585 }
2586 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2587#ifdef DEBUG_TREE
2588 xmlGenericError(xmlGenericErrorContext,
2589 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2590#endif
2591 return(old);
2592 }
Owen Taylor3473f882001-02-23 17:55:21 +00002593 xmlUnlinkNode(cur);
2594 cur->doc = old->doc;
2595 cur->parent = old->parent;
2596 cur->next = old->next;
2597 if (cur->next != NULL)
2598 cur->next->prev = cur;
2599 cur->prev = old->prev;
2600 if (cur->prev != NULL)
2601 cur->prev->next = cur;
2602 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002603 if (cur->type == XML_ATTRIBUTE_NODE) {
2604 if (cur->parent->properties == (xmlAttrPtr)old)
2605 cur->parent->properties = ((xmlAttrPtr) cur);
2606 } else {
2607 if (cur->parent->children == old)
2608 cur->parent->children = cur;
2609 if (cur->parent->last == old)
2610 cur->parent->last = cur;
2611 }
Owen Taylor3473f882001-02-23 17:55:21 +00002612 }
2613 old->next = old->prev = NULL;
2614 old->parent = NULL;
2615 return(old);
2616}
2617
2618/************************************************************************
2619 * *
2620 * Copy operations *
2621 * *
2622 ************************************************************************/
2623
2624/**
2625 * xmlCopyNamespace:
2626 * @cur: the namespace
2627 *
2628 * Do a copy of the namespace.
2629 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002630 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002631 */
2632xmlNsPtr
2633xmlCopyNamespace(xmlNsPtr cur) {
2634 xmlNsPtr ret;
2635
2636 if (cur == NULL) return(NULL);
2637 switch (cur->type) {
2638 case XML_LOCAL_NAMESPACE:
2639 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2640 break;
2641 default:
2642#ifdef DEBUG_TREE
2643 xmlGenericError(xmlGenericErrorContext,
2644 "xmlCopyNamespace: invalid type %d\n", cur->type);
2645#endif
2646 return(NULL);
2647 }
2648 return(ret);
2649}
2650
2651/**
2652 * xmlCopyNamespaceList:
2653 * @cur: the first namespace
2654 *
2655 * Do a copy of an namespace list.
2656 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002657 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002658 */
2659xmlNsPtr
2660xmlCopyNamespaceList(xmlNsPtr cur) {
2661 xmlNsPtr ret = NULL;
2662 xmlNsPtr p = NULL,q;
2663
2664 while (cur != NULL) {
2665 q = xmlCopyNamespace(cur);
2666 if (p == NULL) {
2667 ret = p = q;
2668 } else {
2669 p->next = q;
2670 p = q;
2671 }
2672 cur = cur->next;
2673 }
2674 return(ret);
2675}
2676
2677static xmlNodePtr
2678xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2679/**
2680 * xmlCopyProp:
2681 * @target: the element where the attribute will be grafted
2682 * @cur: the attribute
2683 *
2684 * Do a copy of the attribute.
2685 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002686 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002687 */
2688xmlAttrPtr
2689xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2690 xmlAttrPtr ret;
2691
2692 if (cur == NULL) return(NULL);
2693 if (target != NULL)
2694 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2695 else if (cur->parent != NULL)
2696 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2697 else if (cur->children != NULL)
2698 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2699 else
2700 ret = xmlNewDocProp(NULL, cur->name, NULL);
2701 if (ret == NULL) return(NULL);
2702 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002703
Owen Taylor3473f882001-02-23 17:55:21 +00002704 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00002705 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002706/*
2707 * if (target->doc)
2708 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2709 * else if (cur->doc) / * target may not yet have a doc : KPI * /
2710 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
2711 * else
2712 * ns = NULL;
2713 * ret->ns = ns;
2714 */
2715 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2716 if (ns == NULL) {
2717 /*
2718 * Humm, we are copying an element whose namespace is defined
2719 * out of the new tree scope. Search it in the original tree
2720 * and add it at the top of the new tree
2721 */
2722 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
2723 if (ns != NULL) {
2724 xmlNodePtr root = target;
2725 xmlNodePtr pred = NULL;
2726
2727 while (root->parent != NULL) {
2728 pred = root;
2729 root = root->parent;
2730 }
2731 if (root == (xmlNodePtr) target->doc) {
2732 /* correct possibly cycling above the document elt */
2733 root = pred;
2734 }
2735 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
2736 }
2737 } else {
2738 /*
2739 * we have to find something appropriate here since
2740 * we cant be sure, that the namespce we found is identified
2741 * by the prefix
2742 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002743 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002744 /* this is the nice case */
2745 ret->ns = ns;
2746 } else {
2747 /*
2748 * we are in trouble: we need a new reconcilied namespace.
2749 * This is expensive
2750 */
2751 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
2752 }
2753 }
2754
Owen Taylor3473f882001-02-23 17:55:21 +00002755 } else
2756 ret->ns = NULL;
2757
2758 if (cur->children != NULL) {
2759 xmlNodePtr tmp;
2760
2761 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2762 ret->last = NULL;
2763 tmp = ret->children;
2764 while (tmp != NULL) {
2765 /* tmp->parent = (xmlNodePtr)ret; */
2766 if (tmp->next == NULL)
2767 ret->last = tmp;
2768 tmp = tmp->next;
2769 }
2770 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002771 /*
2772 * Try to handle IDs
2773 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00002774 if ((target!= NULL) && (cur!= NULL) &&
2775 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002776 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
2777 if (xmlIsID(cur->doc, cur->parent, cur)) {
2778 xmlChar *id;
2779
2780 id = xmlNodeListGetString(cur->doc, cur->children, 1);
2781 if (id != NULL) {
2782 xmlAddID(NULL, target->doc, id, ret);
2783 xmlFree(id);
2784 }
2785 }
2786 }
Owen Taylor3473f882001-02-23 17:55:21 +00002787 return(ret);
2788}
2789
2790/**
2791 * xmlCopyPropList:
2792 * @target: the element where the attributes will be grafted
2793 * @cur: the first attribute
2794 *
2795 * Do a copy of an attribute list.
2796 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002797 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002798 */
2799xmlAttrPtr
2800xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
2801 xmlAttrPtr ret = NULL;
2802 xmlAttrPtr p = NULL,q;
2803
2804 while (cur != NULL) {
2805 q = xmlCopyProp(target, cur);
2806 if (p == NULL) {
2807 ret = p = q;
2808 } else {
2809 p->next = q;
2810 q->prev = p;
2811 p = q;
2812 }
2813 cur = cur->next;
2814 }
2815 return(ret);
2816}
2817
2818/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002819 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00002820 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002821 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00002822 * tricky reason: namespaces. Doing a direct copy of a node
2823 * say RPM:Copyright without changing the namespace pointer to
2824 * something else can produce stale links. One way to do it is
2825 * to keep a reference counter but this doesn't work as soon
2826 * as one move the element or the subtree out of the scope of
2827 * the existing namespace. The actual solution seems to add
2828 * a copy of the namespace at the top of the copied tree if
2829 * not available in the subtree.
2830 * Hence two functions, the public front-end call the inner ones
2831 */
2832
2833static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002834xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00002835 int recursive) {
2836 xmlNodePtr ret;
2837
2838 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00002839 switch (node->type) {
2840 case XML_TEXT_NODE:
2841 case XML_CDATA_SECTION_NODE:
2842 case XML_ELEMENT_NODE:
2843 case XML_ENTITY_REF_NODE:
2844 case XML_ENTITY_NODE:
2845 case XML_PI_NODE:
2846 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002847 case XML_XINCLUDE_START:
2848 case XML_XINCLUDE_END:
2849 break;
2850 case XML_ATTRIBUTE_NODE:
2851 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
2852 case XML_NAMESPACE_DECL:
2853 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
2854
Daniel Veillard39196eb2001-06-19 18:09:42 +00002855 case XML_DOCUMENT_NODE:
2856 case XML_HTML_DOCUMENT_NODE:
2857#ifdef LIBXML_DOCB_ENABLED
2858 case XML_DOCB_DOCUMENT_NODE:
2859#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002860 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00002861 case XML_DOCUMENT_TYPE_NODE:
2862 case XML_DOCUMENT_FRAG_NODE:
2863 case XML_NOTATION_NODE:
2864 case XML_DTD_NODE:
2865 case XML_ELEMENT_DECL:
2866 case XML_ATTRIBUTE_DECL:
2867 case XML_ENTITY_DECL:
2868 return(NULL);
2869 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002870
Owen Taylor3473f882001-02-23 17:55:21 +00002871 /*
2872 * Allocate a new node and fill the fields.
2873 */
2874 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2875 if (ret == NULL) {
2876 xmlGenericError(xmlGenericErrorContext,
2877 "xmlStaticCopyNode : malloc failed\n");
2878 return(NULL);
2879 }
2880 memset(ret, 0, sizeof(xmlNode));
2881 ret->type = node->type;
2882
2883 ret->doc = doc;
2884 ret->parent = parent;
2885 if (node->name == xmlStringText)
2886 ret->name = xmlStringText;
2887 else if (node->name == xmlStringTextNoenc)
2888 ret->name = xmlStringTextNoenc;
2889 else if (node->name == xmlStringComment)
2890 ret->name = xmlStringComment;
2891 else if (node->name != NULL)
2892 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00002893 if ((node->type != XML_ELEMENT_NODE) &&
2894 (node->content != NULL) &&
2895 (node->type != XML_ENTITY_REF_NODE) &&
2896 (node->type != XML_XINCLUDE_END) &&
2897 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002898 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00002899 }else{
2900 if (node->type == XML_ELEMENT_NODE)
2901 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002902 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00002903 if (parent != NULL) {
2904 xmlNodePtr tmp;
2905
2906 tmp = xmlAddChild(parent, ret);
2907 /* node could have coalesced */
2908 if (tmp != ret)
2909 return(tmp);
2910 }
Owen Taylor3473f882001-02-23 17:55:21 +00002911
2912 if (!recursive) return(ret);
2913 if (node->nsDef != NULL)
2914 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2915
2916 if (node->ns != NULL) {
2917 xmlNsPtr ns;
2918
2919 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2920 if (ns == NULL) {
2921 /*
2922 * Humm, we are copying an element whose namespace is defined
2923 * out of the new tree scope. Search it in the original tree
2924 * and add it at the top of the new tree
2925 */
2926 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2927 if (ns != NULL) {
2928 xmlNodePtr root = ret;
2929
2930 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00002931 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002932 }
2933 } else {
2934 /*
2935 * reference the existing namespace definition in our own tree.
2936 */
2937 ret->ns = ns;
2938 }
2939 }
2940 if (node->properties != NULL)
2941 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002942 if (node->type == XML_ENTITY_REF_NODE) {
2943 if ((doc == NULL) || (node->doc != doc)) {
2944 /*
2945 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00002946 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00002947 * we cannot keep the reference. Try to find it in the
2948 * target document.
2949 */
2950 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
2951 } else {
2952 ret->children = node->children;
2953 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00002954 ret->last = ret->children;
2955 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002956 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00002957 UPDATE_LAST_CHILD_AND_PARENT(ret)
2958 }
Owen Taylor3473f882001-02-23 17:55:21 +00002959 return(ret);
2960}
2961
2962static xmlNodePtr
2963xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2964 xmlNodePtr ret = NULL;
2965 xmlNodePtr p = NULL,q;
2966
2967 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002968 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00002969 if (doc == NULL) {
2970 node = node->next;
2971 continue;
2972 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002973 if (doc->intSubset == NULL) {
2974 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
2975 q->doc = doc;
2976 q->parent = parent;
2977 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00002978 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002979 } else {
2980 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00002981 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002982 }
2983 } else
2984 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002985 if (ret == NULL) {
2986 q->prev = NULL;
2987 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00002988 } else if (p != q) {
2989 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00002990 p->next = q;
2991 q->prev = p;
2992 p = q;
2993 }
2994 node = node->next;
2995 }
2996 return(ret);
2997}
2998
2999/**
3000 * xmlCopyNode:
3001 * @node: the node
3002 * @recursive: if 1 do a recursive copy.
3003 *
3004 * Do a copy of the node.
3005 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003006 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003007 */
3008xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003009xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003010 xmlNodePtr ret;
3011
3012 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3013 return(ret);
3014}
3015
3016/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003017 * xmlDocCopyNode:
3018 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003019 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003020 * @recursive: if 1 do a recursive copy.
3021 *
3022 * Do a copy of the node to a given document.
3023 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003024 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003025 */
3026xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003027xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003028 xmlNodePtr ret;
3029
3030 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3031 return(ret);
3032}
3033
3034/**
Owen Taylor3473f882001-02-23 17:55:21 +00003035 * xmlCopyNodeList:
3036 * @node: the first node in the list.
3037 *
3038 * Do a recursive copy of the node list.
3039 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003040 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003041 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003042xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003043 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3044 return(ret);
3045}
3046
3047/**
Owen Taylor3473f882001-02-23 17:55:21 +00003048 * xmlCopyDtd:
3049 * @dtd: the dtd
3050 *
3051 * Do a copy of the dtd.
3052 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003053 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003054 */
3055xmlDtdPtr
3056xmlCopyDtd(xmlDtdPtr dtd) {
3057 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003058 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003059
3060 if (dtd == NULL) return(NULL);
3061 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3062 if (ret == NULL) return(NULL);
3063 if (dtd->entities != NULL)
3064 ret->entities = (void *) xmlCopyEntitiesTable(
3065 (xmlEntitiesTablePtr) dtd->entities);
3066 if (dtd->notations != NULL)
3067 ret->notations = (void *) xmlCopyNotationTable(
3068 (xmlNotationTablePtr) dtd->notations);
3069 if (dtd->elements != NULL)
3070 ret->elements = (void *) xmlCopyElementTable(
3071 (xmlElementTablePtr) dtd->elements);
3072 if (dtd->attributes != NULL)
3073 ret->attributes = (void *) xmlCopyAttributeTable(
3074 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003075 if (dtd->pentities != NULL)
3076 ret->pentities = (void *) xmlCopyEntitiesTable(
3077 (xmlEntitiesTablePtr) dtd->pentities);
3078
3079 cur = dtd->children;
3080 while (cur != NULL) {
3081 q = NULL;
3082
3083 if (cur->type == XML_ENTITY_DECL) {
3084 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3085 switch (tmp->etype) {
3086 case XML_INTERNAL_GENERAL_ENTITY:
3087 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3088 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3089 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3090 break;
3091 case XML_INTERNAL_PARAMETER_ENTITY:
3092 case XML_EXTERNAL_PARAMETER_ENTITY:
3093 q = (xmlNodePtr)
3094 xmlGetParameterEntityFromDtd(ret, tmp->name);
3095 break;
3096 case XML_INTERNAL_PREDEFINED_ENTITY:
3097 break;
3098 }
3099 } else if (cur->type == XML_ELEMENT_DECL) {
3100 xmlElementPtr tmp = (xmlElementPtr) cur;
3101 q = (xmlNodePtr)
3102 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3103 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3104 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3105 q = (xmlNodePtr)
3106 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3107 } else if (cur->type == XML_COMMENT_NODE) {
3108 q = xmlCopyNode(cur, 0);
3109 }
3110
3111 if (q == NULL) {
3112 cur = cur->next;
3113 continue;
3114 }
3115
3116 if (p == NULL)
3117 ret->children = q;
3118 else
3119 p->next = q;
3120
3121 q->prev = p;
3122 q->parent = (xmlNodePtr) ret;
3123 q->next = NULL;
3124 ret->last = q;
3125 p = q;
3126 cur = cur->next;
3127 }
3128
Owen Taylor3473f882001-02-23 17:55:21 +00003129 return(ret);
3130}
3131
3132/**
3133 * xmlCopyDoc:
3134 * @doc: the document
3135 * @recursive: if 1 do a recursive copy.
3136 *
3137 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003138 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003139 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003140 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003141 */
3142xmlDocPtr
3143xmlCopyDoc(xmlDocPtr doc, int recursive) {
3144 xmlDocPtr ret;
3145
3146 if (doc == NULL) return(NULL);
3147 ret = xmlNewDoc(doc->version);
3148 if (ret == NULL) return(NULL);
3149 if (doc->name != NULL)
3150 ret->name = xmlMemStrdup(doc->name);
3151 if (doc->encoding != NULL)
3152 ret->encoding = xmlStrdup(doc->encoding);
3153 ret->charset = doc->charset;
3154 ret->compression = doc->compression;
3155 ret->standalone = doc->standalone;
3156 if (!recursive) return(ret);
3157
Daniel Veillardb33c2012001-04-25 12:59:04 +00003158 ret->last = NULL;
3159 ret->children = NULL;
3160 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003161 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003162 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003163 ret->intSubset->parent = ret;
3164 }
Owen Taylor3473f882001-02-23 17:55:21 +00003165 if (doc->oldNs != NULL)
3166 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3167 if (doc->children != NULL) {
3168 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003169
3170 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3171 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003172 ret->last = NULL;
3173 tmp = ret->children;
3174 while (tmp != NULL) {
3175 if (tmp->next == NULL)
3176 ret->last = tmp;
3177 tmp = tmp->next;
3178 }
3179 }
3180 return(ret);
3181}
3182
3183/************************************************************************
3184 * *
3185 * Content access functions *
3186 * *
3187 ************************************************************************/
3188
3189/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003190 * xmlGetLineNo:
3191 * @node : valid node
3192 *
3193 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003194 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003195 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003196 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003197 */
3198long
3199xmlGetLineNo(xmlNodePtr node)
3200{
3201 long result = -1;
3202
3203 if (!node)
3204 return result;
3205 if (node->type == XML_ELEMENT_NODE)
3206 result = (long) node->content;
3207 else if ((node->prev != NULL) &&
3208 ((node->prev->type == XML_ELEMENT_NODE) ||
3209 (node->prev->type == XML_TEXT_NODE)))
3210 result = xmlGetLineNo(node->prev);
3211 else if ((node->parent != NULL) &&
3212 ((node->parent->type == XML_ELEMENT_NODE) ||
3213 (node->parent->type == XML_TEXT_NODE)))
3214 result = xmlGetLineNo(node->parent);
3215
3216 return result;
3217}
3218
3219/**
3220 * xmlGetNodePath:
3221 * @node: a node
3222 *
3223 * Build a structure based Path for the given node
3224 *
3225 * Returns the new path or NULL in case of error. The caller must free
3226 * the returned string
3227 */
3228xmlChar *
3229xmlGetNodePath(xmlNodePtr node)
3230{
3231 xmlNodePtr cur, tmp, next;
3232 xmlChar *buffer = NULL, *temp;
3233 size_t buf_len;
3234 xmlChar *buf;
3235 char sep;
3236 const char *name;
3237 char nametemp[100];
3238 int occur = 0;
3239
3240 if (node == NULL)
3241 return (NULL);
3242
3243 buf_len = 500;
3244 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3245 if (buffer == NULL)
3246 return (NULL);
3247 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3248 if (buf == NULL) {
3249 xmlFree(buffer);
3250 return (NULL);
3251 }
3252
3253 buffer[0] = 0;
3254 cur = node;
3255 do {
3256 name = "";
3257 sep = '?';
3258 occur = 0;
3259 if ((cur->type == XML_DOCUMENT_NODE) ||
3260 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3261 if (buffer[0] == '/')
3262 break;
3263 sep = '/';
3264 next = NULL;
3265 } else if (cur->type == XML_ELEMENT_NODE) {
3266 sep = '/';
3267 name = (const char *) cur->name;
3268 if (cur->ns) {
3269 snprintf(nametemp, sizeof(nametemp) - 1,
3270 "%s:%s", cur->ns->prefix, cur->name);
3271 nametemp[sizeof(nametemp) - 1] = 0;
3272 name = nametemp;
3273 }
3274 next = cur->parent;
3275
3276 /*
3277 * Thumbler index computation
3278 */
3279 tmp = cur->prev;
3280 while (tmp != NULL) {
3281 if (xmlStrEqual(cur->name, tmp->name))
3282 occur++;
3283 tmp = tmp->prev;
3284 }
3285 if (occur == 0) {
3286 tmp = cur->next;
3287 while (tmp != NULL) {
3288 if (xmlStrEqual(cur->name, tmp->name))
3289 occur++;
3290 tmp = tmp->next;
3291 }
3292 if (occur != 0)
3293 occur = 1;
3294 } else
3295 occur++;
3296 } else if (cur->type == XML_ATTRIBUTE_NODE) {
3297 sep = '@';
3298 name = (const char *) (((xmlAttrPtr) cur)->name);
3299 next = ((xmlAttrPtr) cur)->parent;
3300 } else {
3301 next = cur->parent;
3302 }
3303
3304 /*
3305 * Make sure there is enough room
3306 */
3307 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3308 buf_len =
3309 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3310 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3311 if (temp == NULL) {
3312 xmlFree(buf);
3313 xmlFree(buffer);
3314 return (NULL);
3315 }
3316 buffer = temp;
3317 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3318 if (temp == NULL) {
3319 xmlFree(buf);
3320 xmlFree(buffer);
3321 return (NULL);
3322 }
3323 buf = temp;
3324 }
3325 if (occur == 0)
3326 snprintf((char *) buf, buf_len, "%c%s%s",
3327 sep, name, (char *) buffer);
3328 else
3329 snprintf((char *) buf, buf_len, "%c%s[%d]%s",
3330 sep, name, occur, (char *) buffer);
3331 snprintf((char *) buffer, buf_len, "%s", buf);
3332 cur = next;
3333 } while (cur != NULL);
3334 xmlFree(buf);
3335 return (buffer);
3336}
3337
3338/**
Owen Taylor3473f882001-02-23 17:55:21 +00003339 * xmlDocGetRootElement:
3340 * @doc: the document
3341 *
3342 * Get the root element of the document (doc->children is a list
3343 * containing possibly comments, PIs, etc ...).
3344 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003345 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003346 */
3347xmlNodePtr
3348xmlDocGetRootElement(xmlDocPtr doc) {
3349 xmlNodePtr ret;
3350
3351 if (doc == NULL) return(NULL);
3352 ret = doc->children;
3353 while (ret != NULL) {
3354 if (ret->type == XML_ELEMENT_NODE)
3355 return(ret);
3356 ret = ret->next;
3357 }
3358 return(ret);
3359}
3360
3361/**
3362 * xmlDocSetRootElement:
3363 * @doc: the document
3364 * @root: the new document root element
3365 *
3366 * Set the root element of the document (doc->children is a list
3367 * containing possibly comments, PIs, etc ...).
3368 *
3369 * Returns the old root element if any was found
3370 */
3371xmlNodePtr
3372xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3373 xmlNodePtr old = NULL;
3374
3375 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00003376 if (root == NULL)
3377 return(NULL);
3378 xmlUnlinkNode(root);
3379 root->doc = doc;
3380 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00003381 old = doc->children;
3382 while (old != NULL) {
3383 if (old->type == XML_ELEMENT_NODE)
3384 break;
3385 old = old->next;
3386 }
3387 if (old == NULL) {
3388 if (doc->children == NULL) {
3389 doc->children = root;
3390 doc->last = root;
3391 } else {
3392 xmlAddSibling(doc->children, root);
3393 }
3394 } else {
3395 xmlReplaceNode(old, root);
3396 }
3397 return(old);
3398}
3399
3400/**
3401 * xmlNodeSetLang:
3402 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003403 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003404 *
3405 * Set the language of a node, i.e. the values of the xml:lang
3406 * attribute.
3407 */
3408void
3409xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003410 xmlNsPtr ns;
3411
Owen Taylor3473f882001-02-23 17:55:21 +00003412 if (cur == NULL) return;
3413 switch(cur->type) {
3414 case XML_TEXT_NODE:
3415 case XML_CDATA_SECTION_NODE:
3416 case XML_COMMENT_NODE:
3417 case XML_DOCUMENT_NODE:
3418 case XML_DOCUMENT_TYPE_NODE:
3419 case XML_DOCUMENT_FRAG_NODE:
3420 case XML_NOTATION_NODE:
3421 case XML_HTML_DOCUMENT_NODE:
3422 case XML_DTD_NODE:
3423 case XML_ELEMENT_DECL:
3424 case XML_ATTRIBUTE_DECL:
3425 case XML_ENTITY_DECL:
3426 case XML_PI_NODE:
3427 case XML_ENTITY_REF_NODE:
3428 case XML_ENTITY_NODE:
3429 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003430#ifdef LIBXML_DOCB_ENABLED
3431 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003432#endif
3433 case XML_XINCLUDE_START:
3434 case XML_XINCLUDE_END:
3435 return;
3436 case XML_ELEMENT_NODE:
3437 case XML_ATTRIBUTE_NODE:
3438 break;
3439 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003440 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3441 if (ns == NULL)
3442 return;
3443 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003444}
3445
3446/**
3447 * xmlNodeGetLang:
3448 * @cur: the node being checked
3449 *
3450 * Searches the language of a node, i.e. the values of the xml:lang
3451 * attribute or the one carried by the nearest ancestor.
3452 *
3453 * Returns a pointer to the lang value, or NULL if not found
3454 * It's up to the caller to free the memory.
3455 */
3456xmlChar *
3457xmlNodeGetLang(xmlNodePtr cur) {
3458 xmlChar *lang;
3459
3460 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003461 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003462 if (lang != NULL)
3463 return(lang);
3464 cur = cur->parent;
3465 }
3466 return(NULL);
3467}
3468
3469
3470/**
3471 * xmlNodeSetSpacePreserve:
3472 * @cur: the node being changed
3473 * @val: the xml:space value ("0": default, 1: "preserve")
3474 *
3475 * Set (or reset) the space preserving behaviour of a node, i.e. the
3476 * value of the xml:space attribute.
3477 */
3478void
3479xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003480 xmlNsPtr ns;
3481
Owen Taylor3473f882001-02-23 17:55:21 +00003482 if (cur == NULL) return;
3483 switch(cur->type) {
3484 case XML_TEXT_NODE:
3485 case XML_CDATA_SECTION_NODE:
3486 case XML_COMMENT_NODE:
3487 case XML_DOCUMENT_NODE:
3488 case XML_DOCUMENT_TYPE_NODE:
3489 case XML_DOCUMENT_FRAG_NODE:
3490 case XML_NOTATION_NODE:
3491 case XML_HTML_DOCUMENT_NODE:
3492 case XML_DTD_NODE:
3493 case XML_ELEMENT_DECL:
3494 case XML_ATTRIBUTE_DECL:
3495 case XML_ENTITY_DECL:
3496 case XML_PI_NODE:
3497 case XML_ENTITY_REF_NODE:
3498 case XML_ENTITY_NODE:
3499 case XML_NAMESPACE_DECL:
3500 case XML_XINCLUDE_START:
3501 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003502#ifdef LIBXML_DOCB_ENABLED
3503 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003504#endif
3505 return;
3506 case XML_ELEMENT_NODE:
3507 case XML_ATTRIBUTE_NODE:
3508 break;
3509 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003510 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3511 if (ns == NULL)
3512 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003513 switch (val) {
3514 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003515 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003516 break;
3517 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003518 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003519 break;
3520 }
3521}
3522
3523/**
3524 * xmlNodeGetSpacePreserve:
3525 * @cur: the node being checked
3526 *
3527 * Searches the space preserving behaviour of a node, i.e. the values
3528 * of the xml:space attribute or the one carried by the nearest
3529 * ancestor.
3530 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003531 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003532 */
3533int
3534xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3535 xmlChar *space;
3536
3537 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003538 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003539 if (space != NULL) {
3540 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3541 xmlFree(space);
3542 return(1);
3543 }
3544 if (xmlStrEqual(space, BAD_CAST "default")) {
3545 xmlFree(space);
3546 return(0);
3547 }
3548 xmlFree(space);
3549 }
3550 cur = cur->parent;
3551 }
3552 return(-1);
3553}
3554
3555/**
3556 * xmlNodeSetName:
3557 * @cur: the node being changed
3558 * @name: the new tag name
3559 *
3560 * Set (or reset) the name of a node.
3561 */
3562void
3563xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3564 if (cur == NULL) return;
3565 if (name == NULL) return;
3566 switch(cur->type) {
3567 case XML_TEXT_NODE:
3568 case XML_CDATA_SECTION_NODE:
3569 case XML_COMMENT_NODE:
3570 case XML_DOCUMENT_TYPE_NODE:
3571 case XML_DOCUMENT_FRAG_NODE:
3572 case XML_NOTATION_NODE:
3573 case XML_HTML_DOCUMENT_NODE:
3574 case XML_NAMESPACE_DECL:
3575 case XML_XINCLUDE_START:
3576 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003577#ifdef LIBXML_DOCB_ENABLED
3578 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003579#endif
3580 return;
3581 case XML_ELEMENT_NODE:
3582 case XML_ATTRIBUTE_NODE:
3583 case XML_PI_NODE:
3584 case XML_ENTITY_REF_NODE:
3585 case XML_ENTITY_NODE:
3586 case XML_DTD_NODE:
3587 case XML_DOCUMENT_NODE:
3588 case XML_ELEMENT_DECL:
3589 case XML_ATTRIBUTE_DECL:
3590 case XML_ENTITY_DECL:
3591 break;
3592 }
3593 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3594 cur->name = xmlStrdup(name);
3595}
3596
3597/**
3598 * xmlNodeSetBase:
3599 * @cur: the node being changed
3600 * @uri: the new base URI
3601 *
3602 * Set (or reset) the base URI of a node, i.e. the value of the
3603 * xml:base attribute.
3604 */
3605void
3606xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003607 xmlNsPtr ns;
3608
Owen Taylor3473f882001-02-23 17:55:21 +00003609 if (cur == NULL) return;
3610 switch(cur->type) {
3611 case XML_TEXT_NODE:
3612 case XML_CDATA_SECTION_NODE:
3613 case XML_COMMENT_NODE:
3614 case XML_DOCUMENT_NODE:
3615 case XML_DOCUMENT_TYPE_NODE:
3616 case XML_DOCUMENT_FRAG_NODE:
3617 case XML_NOTATION_NODE:
3618 case XML_HTML_DOCUMENT_NODE:
3619 case XML_DTD_NODE:
3620 case XML_ELEMENT_DECL:
3621 case XML_ATTRIBUTE_DECL:
3622 case XML_ENTITY_DECL:
3623 case XML_PI_NODE:
3624 case XML_ENTITY_REF_NODE:
3625 case XML_ENTITY_NODE:
3626 case XML_NAMESPACE_DECL:
3627 case XML_XINCLUDE_START:
3628 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003629#ifdef LIBXML_DOCB_ENABLED
3630 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003631#endif
3632 return;
3633 case XML_ELEMENT_NODE:
3634 case XML_ATTRIBUTE_NODE:
3635 break;
3636 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003637
3638 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3639 if (ns == NULL)
3640 return;
3641 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00003642}
3643
3644/**
Owen Taylor3473f882001-02-23 17:55:21 +00003645 * xmlNodeGetBase:
3646 * @doc: the document the node pertains to
3647 * @cur: the node being checked
3648 *
3649 * Searches for the BASE URL. The code should work on both XML
3650 * and HTML document even if base mechanisms are completely different.
3651 * It returns the base as defined in RFC 2396 sections
3652 * 5.1.1. Base URI within Document Content
3653 * and
3654 * 5.1.2. Base URI from the Encapsulating Entity
3655 * However it does not return the document base (5.1.3), use
3656 * xmlDocumentGetBase() for this
3657 *
3658 * Returns a pointer to the base URL, or NULL if not found
3659 * It's up to the caller to free the memory.
3660 */
3661xmlChar *
3662xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003663 xmlChar *oldbase = NULL;
3664 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003665
3666 if ((cur == NULL) && (doc == NULL))
3667 return(NULL);
3668 if (doc == NULL) doc = cur->doc;
3669 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3670 cur = doc->children;
3671 while ((cur != NULL) && (cur->name != NULL)) {
3672 if (cur->type != XML_ELEMENT_NODE) {
3673 cur = cur->next;
3674 continue;
3675 }
3676 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3677 cur = cur->children;
3678 continue;
3679 }
3680 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3681 cur = cur->children;
3682 continue;
3683 }
3684 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3685 return(xmlGetProp(cur, BAD_CAST "href"));
3686 }
3687 cur = cur->next;
3688 }
3689 return(NULL);
3690 }
3691 while (cur != NULL) {
3692 if (cur->type == XML_ENTITY_DECL) {
3693 xmlEntityPtr ent = (xmlEntityPtr) cur;
3694 return(xmlStrdup(ent->URI));
3695 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003696 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003697 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003698 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003699 if (oldbase != NULL) {
3700 newbase = xmlBuildURI(oldbase, base);
3701 if (newbase != NULL) {
3702 xmlFree(oldbase);
3703 xmlFree(base);
3704 oldbase = newbase;
3705 } else {
3706 xmlFree(oldbase);
3707 xmlFree(base);
3708 return(NULL);
3709 }
3710 } else {
3711 oldbase = base;
3712 }
3713 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3714 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3715 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3716 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003717 }
3718 }
Owen Taylor3473f882001-02-23 17:55:21 +00003719 cur = cur->parent;
3720 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003721 if ((doc != NULL) && (doc->URL != NULL)) {
3722 if (oldbase == NULL)
3723 return(xmlStrdup(doc->URL));
3724 newbase = xmlBuildURI(oldbase, doc->URL);
3725 xmlFree(oldbase);
3726 return(newbase);
3727 }
3728 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003729}
3730
3731/**
3732 * xmlNodeGetContent:
3733 * @cur: the node being read
3734 *
3735 * Read the value of a node, this can be either the text carried
3736 * directly by this node if it's a TEXT node or the aggregate string
3737 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00003738 * Entity references are substituted.
3739 * Returns a new #xmlChar * or NULL if no content is available.
Owen Taylor3473f882001-02-23 17:55:21 +00003740 * It's up to the caller to free the memory.
3741 */
3742xmlChar *
3743xmlNodeGetContent(xmlNodePtr cur) {
3744 if (cur == NULL) return(NULL);
3745 switch (cur->type) {
3746 case XML_DOCUMENT_FRAG_NODE:
3747 case XML_ELEMENT_NODE: {
3748 xmlNodePtr tmp = cur;
3749 xmlBufferPtr buffer;
3750 xmlChar *ret;
3751
3752 buffer = xmlBufferCreate();
3753 if (buffer == NULL)
3754 return(NULL);
3755 while (tmp != NULL) {
3756 switch (tmp->type) {
Daniel Veillard2d703722001-05-30 18:32:34 +00003757 case XML_CDATA_SECTION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003758 case XML_TEXT_NODE:
3759 if (tmp->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00003760 xmlBufferCat(buffer, tmp->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003761 break;
3762 case XML_ENTITY_REF_NODE: {
3763 xmlEntityPtr ent;
3764
3765 ent = xmlGetDocEntity(cur->doc, tmp->name);
3766 if (ent != NULL)
3767 xmlBufferCat(buffer, ent->content);
3768 }
3769 default:
3770 break;
3771 }
3772 /*
3773 * Skip to next node
3774 */
3775 if (tmp->children != NULL) {
3776 if (tmp->children->type != XML_ENTITY_DECL) {
3777 tmp = tmp->children;
3778 continue;
3779 }
3780 }
Daniel Veillard6c831202001-03-07 15:57:53 +00003781 if (tmp == cur)
3782 break;
3783
Owen Taylor3473f882001-02-23 17:55:21 +00003784 if (tmp->next != NULL) {
3785 tmp = tmp->next;
3786 continue;
3787 }
3788
3789 do {
3790 tmp = tmp->parent;
3791 if (tmp == NULL)
3792 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00003793 if (tmp == cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003794 tmp = NULL;
3795 break;
3796 }
3797 if (tmp->next != NULL) {
3798 tmp = tmp->next;
3799 break;
3800 }
3801 } while (tmp != NULL);
3802 }
3803 ret = buffer->content;
3804 buffer->content = NULL;
3805 xmlBufferFree(buffer);
3806 return(ret);
3807 }
3808 case XML_ATTRIBUTE_NODE: {
3809 xmlAttrPtr attr = (xmlAttrPtr) cur;
3810 if (attr->parent != NULL)
3811 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
3812 else
3813 return(xmlNodeListGetString(NULL, attr->children, 1));
3814 break;
3815 }
3816 case XML_COMMENT_NODE:
3817 case XML_PI_NODE:
3818 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00003819 return(xmlStrdup(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00003820 return(NULL);
3821 case XML_ENTITY_REF_NODE:
3822 /*
3823 * Locate the entity, and get it's content
3824 * @@@
3825 */
3826 return(NULL);
3827 case XML_ENTITY_NODE:
3828 case XML_DOCUMENT_NODE:
3829 case XML_HTML_DOCUMENT_NODE:
3830 case XML_DOCUMENT_TYPE_NODE:
3831 case XML_NOTATION_NODE:
3832 case XML_DTD_NODE:
3833 case XML_XINCLUDE_START:
3834 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003835#ifdef LIBXML_DOCB_ENABLED
3836 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003837#endif
3838 return(NULL);
3839 case XML_NAMESPACE_DECL:
3840 return(xmlStrdup(((xmlNsPtr)cur)->href));
3841 case XML_ELEMENT_DECL:
3842 /* TODO !!! */
3843 return(NULL);
3844 case XML_ATTRIBUTE_DECL:
3845 /* TODO !!! */
3846 return(NULL);
3847 case XML_ENTITY_DECL:
3848 /* TODO !!! */
3849 return(NULL);
3850 case XML_CDATA_SECTION_NODE:
3851 case XML_TEXT_NODE:
3852 if (cur->content != NULL)
Daniel Veillard9ff88172002-03-11 09:15:32 +00003853 return(xmlStrdup(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00003854 return(NULL);
3855 }
3856 return(NULL);
3857}
3858
3859/**
3860 * xmlNodeSetContent:
3861 * @cur: the node being modified
3862 * @content: the new value of the content
3863 *
3864 * Replace the content of a node.
3865 */
3866void
3867xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
3868 if (cur == NULL) {
3869#ifdef DEBUG_TREE
3870 xmlGenericError(xmlGenericErrorContext,
3871 "xmlNodeSetContent : node == NULL\n");
3872#endif
3873 return;
3874 }
3875 switch (cur->type) {
3876 case XML_DOCUMENT_FRAG_NODE:
3877 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00003878 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003879 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3880 cur->children = xmlStringGetNodeList(cur->doc, content);
3881 UPDATE_LAST_CHILD_AND_PARENT(cur)
3882 break;
Owen Taylor3473f882001-02-23 17:55:21 +00003883 case XML_TEXT_NODE:
3884 case XML_CDATA_SECTION_NODE:
3885 case XML_ENTITY_REF_NODE:
3886 case XML_ENTITY_NODE:
3887 case XML_PI_NODE:
3888 case XML_COMMENT_NODE:
3889 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003890 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003891 }
3892 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3893 cur->last = cur->children = NULL;
3894 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003895 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00003896 } else
3897 cur->content = NULL;
3898 break;
3899 case XML_DOCUMENT_NODE:
3900 case XML_HTML_DOCUMENT_NODE:
3901 case XML_DOCUMENT_TYPE_NODE:
3902 case XML_XINCLUDE_START:
3903 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003904#ifdef LIBXML_DOCB_ENABLED
3905 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003906#endif
3907 break;
3908 case XML_NOTATION_NODE:
3909 break;
3910 case XML_DTD_NODE:
3911 break;
3912 case XML_NAMESPACE_DECL:
3913 break;
3914 case XML_ELEMENT_DECL:
3915 /* TODO !!! */
3916 break;
3917 case XML_ATTRIBUTE_DECL:
3918 /* TODO !!! */
3919 break;
3920 case XML_ENTITY_DECL:
3921 /* TODO !!! */
3922 break;
3923 }
3924}
3925
3926/**
3927 * xmlNodeSetContentLen:
3928 * @cur: the node being modified
3929 * @content: the new value of the content
3930 * @len: the size of @content
3931 *
3932 * Replace the content of a node.
3933 */
3934void
3935xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3936 if (cur == NULL) {
3937#ifdef DEBUG_TREE
3938 xmlGenericError(xmlGenericErrorContext,
3939 "xmlNodeSetContentLen : node == NULL\n");
3940#endif
3941 return;
3942 }
3943 switch (cur->type) {
3944 case XML_DOCUMENT_FRAG_NODE:
3945 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00003946 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003947 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3948 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
3949 UPDATE_LAST_CHILD_AND_PARENT(cur)
3950 break;
Owen Taylor3473f882001-02-23 17:55:21 +00003951 case XML_TEXT_NODE:
3952 case XML_CDATA_SECTION_NODE:
3953 case XML_ENTITY_REF_NODE:
3954 case XML_ENTITY_NODE:
3955 case XML_PI_NODE:
3956 case XML_COMMENT_NODE:
3957 case XML_NOTATION_NODE:
3958 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003959 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003960 }
3961 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3962 cur->children = cur->last = NULL;
3963 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003964 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00003965 } else
3966 cur->content = NULL;
3967 break;
3968 case XML_DOCUMENT_NODE:
3969 case XML_DTD_NODE:
3970 case XML_HTML_DOCUMENT_NODE:
3971 case XML_DOCUMENT_TYPE_NODE:
3972 case XML_NAMESPACE_DECL:
3973 case XML_XINCLUDE_START:
3974 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003975#ifdef LIBXML_DOCB_ENABLED
3976 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003977#endif
3978 break;
3979 case XML_ELEMENT_DECL:
3980 /* TODO !!! */
3981 break;
3982 case XML_ATTRIBUTE_DECL:
3983 /* TODO !!! */
3984 break;
3985 case XML_ENTITY_DECL:
3986 /* TODO !!! */
3987 break;
3988 }
3989}
3990
3991/**
3992 * xmlNodeAddContentLen:
3993 * @cur: the node being modified
3994 * @content: extra content
3995 * @len: the size of @content
3996 *
3997 * Append the extra substring to the node content.
3998 */
3999void
4000xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4001 if (cur == NULL) {
4002#ifdef DEBUG_TREE
4003 xmlGenericError(xmlGenericErrorContext,
4004 "xmlNodeAddContentLen : node == NULL\n");
4005#endif
4006 return;
4007 }
4008 if (len <= 0) return;
4009 switch (cur->type) {
4010 case XML_DOCUMENT_FRAG_NODE:
4011 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004012 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004013
Daniel Veillard7db37732001-07-12 01:20:08 +00004014 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004015 newNode = xmlNewTextLen(content, len);
4016 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004017 tmp = xmlAddChild(cur, newNode);
4018 if (tmp != newNode)
4019 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004020 if ((last != NULL) && (last->next == newNode)) {
4021 xmlTextMerge(last, newNode);
4022 }
4023 }
4024 break;
4025 }
4026 case XML_ATTRIBUTE_NODE:
4027 break;
4028 case XML_TEXT_NODE:
4029 case XML_CDATA_SECTION_NODE:
4030 case XML_ENTITY_REF_NODE:
4031 case XML_ENTITY_NODE:
4032 case XML_PI_NODE:
4033 case XML_COMMENT_NODE:
4034 case XML_NOTATION_NODE:
4035 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004036 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004037 }
4038 case XML_DOCUMENT_NODE:
4039 case XML_DTD_NODE:
4040 case XML_HTML_DOCUMENT_NODE:
4041 case XML_DOCUMENT_TYPE_NODE:
4042 case XML_NAMESPACE_DECL:
4043 case XML_XINCLUDE_START:
4044 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004045#ifdef LIBXML_DOCB_ENABLED
4046 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004047#endif
4048 break;
4049 case XML_ELEMENT_DECL:
4050 case XML_ATTRIBUTE_DECL:
4051 case XML_ENTITY_DECL:
4052 break;
4053 }
4054}
4055
4056/**
4057 * xmlNodeAddContent:
4058 * @cur: the node being modified
4059 * @content: extra content
4060 *
4061 * Append the extra substring to the node content.
4062 */
4063void
4064xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4065 int len;
4066
4067 if (cur == NULL) {
4068#ifdef DEBUG_TREE
4069 xmlGenericError(xmlGenericErrorContext,
4070 "xmlNodeAddContent : node == NULL\n");
4071#endif
4072 return;
4073 }
4074 if (content == NULL) return;
4075 len = xmlStrlen(content);
4076 xmlNodeAddContentLen(cur, content, len);
4077}
4078
4079/**
4080 * xmlTextMerge:
4081 * @first: the first text node
4082 * @second: the second text node being merged
4083 *
4084 * Merge two text nodes into one
4085 * Returns the first text node augmented
4086 */
4087xmlNodePtr
4088xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4089 if (first == NULL) return(second);
4090 if (second == NULL) return(first);
4091 if (first->type != XML_TEXT_NODE) return(first);
4092 if (second->type != XML_TEXT_NODE) return(first);
4093 if (second->name != first->name)
4094 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004095 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004096 xmlUnlinkNode(second);
4097 xmlFreeNode(second);
4098 return(first);
4099}
4100
4101/**
4102 * xmlGetNsList:
4103 * @doc: the document
4104 * @node: the current node
4105 *
4106 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004107 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004108 * that need to be freed by the caller or NULL if no
4109 * namespace if defined
4110 */
4111xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004112xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4113{
Owen Taylor3473f882001-02-23 17:55:21 +00004114 xmlNsPtr cur;
4115 xmlNsPtr *ret = NULL;
4116 int nbns = 0;
4117 int maxns = 10;
4118 int i;
4119
4120 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004121 if (node->type == XML_ELEMENT_NODE) {
4122 cur = node->nsDef;
4123 while (cur != NULL) {
4124 if (ret == NULL) {
4125 ret =
4126 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4127 sizeof(xmlNsPtr));
4128 if (ret == NULL) {
4129 xmlGenericError(xmlGenericErrorContext,
4130 "xmlGetNsList : out of memory!\n");
4131 return (NULL);
4132 }
4133 ret[nbns] = NULL;
4134 }
4135 for (i = 0; i < nbns; i++) {
4136 if ((cur->prefix == ret[i]->prefix) ||
4137 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4138 break;
4139 }
4140 if (i >= nbns) {
4141 if (nbns >= maxns) {
4142 maxns *= 2;
4143 ret = (xmlNsPtr *) xmlRealloc(ret,
4144 (maxns +
4145 1) *
4146 sizeof(xmlNsPtr));
4147 if (ret == NULL) {
4148 xmlGenericError(xmlGenericErrorContext,
4149 "xmlGetNsList : realloc failed!\n");
4150 return (NULL);
4151 }
4152 }
4153 ret[nbns++] = cur;
4154 ret[nbns] = NULL;
4155 }
Owen Taylor3473f882001-02-23 17:55:21 +00004156
Daniel Veillard77044732001-06-29 21:31:07 +00004157 cur = cur->next;
4158 }
4159 }
4160 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004161 }
Daniel Veillard77044732001-06-29 21:31:07 +00004162 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004163}
4164
4165/**
4166 * xmlSearchNs:
4167 * @doc: the document
4168 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004169 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004170 *
4171 * Search a Ns registered under a given name space for a document.
4172 * recurse on the parents until it finds the defined namespace
4173 * or return NULL otherwise.
4174 * @nameSpace can be NULL, this is a search for the default namespace.
4175 * We don't allow to cross entities boundaries. If you don't declare
4176 * the namespace within those you will be in troubles !!! A warning
4177 * is generated to cover this case.
4178 *
4179 * Returns the namespace pointer or NULL.
4180 */
4181xmlNsPtr
4182xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4183 xmlNsPtr cur;
4184
4185 if (node == NULL) return(NULL);
4186 if ((nameSpace != NULL) &&
4187 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillardd2f23002002-01-21 13:36:00 +00004188 if (doc == NULL)
4189 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004190 if (doc->oldNs == NULL) {
4191 /*
4192 * Allocate a new Namespace and fill the fields.
4193 */
4194 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4195 if (doc->oldNs == NULL) {
4196 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004197 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004198 return(NULL);
4199 }
4200 memset(doc->oldNs, 0, sizeof(xmlNs));
4201 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4202
4203 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4204 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4205 }
4206 return(doc->oldNs);
4207 }
4208 while (node != NULL) {
4209 if ((node->type == XML_ENTITY_REF_NODE) ||
4210 (node->type == XML_ENTITY_NODE) ||
4211 (node->type == XML_ENTITY_DECL))
4212 return(NULL);
4213 if (node->type == XML_ELEMENT_NODE) {
4214 cur = node->nsDef;
4215 while (cur != NULL) {
4216 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4217 (cur->href != NULL))
4218 return(cur);
4219 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4220 (cur->href != NULL) &&
4221 (xmlStrEqual(cur->prefix, nameSpace)))
4222 return(cur);
4223 cur = cur->next;
4224 }
4225 }
4226 node = node->parent;
4227 }
4228 return(NULL);
4229}
4230
4231/**
4232 * xmlSearchNsByHref:
4233 * @doc: the document
4234 * @node: the current node
4235 * @href: the namespace value
4236 *
4237 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4238 * the defined namespace or return NULL otherwise.
4239 * Returns the namespace pointer or NULL.
4240 */
4241xmlNsPtr
4242xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4243 xmlNsPtr cur;
4244 xmlNodePtr orig = node;
4245
4246 if ((node == NULL) || (href == NULL)) return(NULL);
4247 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004248 /*
4249 * Only the document can hold the XML spec namespace.
4250 */
4251 if (doc == NULL)
4252 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004253 if (doc->oldNs == NULL) {
4254 /*
4255 * Allocate a new Namespace and fill the fields.
4256 */
4257 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4258 if (doc->oldNs == NULL) {
4259 xmlGenericError(xmlGenericErrorContext,
4260 "xmlSearchNsByHref : malloc failed\n");
4261 return(NULL);
4262 }
4263 memset(doc->oldNs, 0, sizeof(xmlNs));
4264 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4265
4266 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4267 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4268 }
4269 return(doc->oldNs);
4270 }
4271 while (node != NULL) {
4272 cur = node->nsDef;
4273 while (cur != NULL) {
4274 if ((cur->href != NULL) && (href != NULL) &&
4275 (xmlStrEqual(cur->href, href))) {
4276 /*
4277 * Check that the prefix is not shadowed between orig and node
4278 */
4279 xmlNodePtr check = orig;
4280 xmlNsPtr tst;
4281
4282 while (check != node) {
4283 tst = check->nsDef;
4284 while (tst != NULL) {
4285 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4286 goto shadowed;
4287 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4288 (xmlStrEqual(tst->prefix, cur->prefix)))
4289 goto shadowed;
4290 tst = tst->next;
4291 }
4292 check = check->parent;
4293 }
4294 return(cur);
4295 }
4296shadowed:
4297 cur = cur->next;
4298 }
4299 node = node->parent;
4300 }
4301 return(NULL);
4302}
4303
4304/**
4305 * xmlNewReconciliedNs
4306 * @doc: the document
4307 * @tree: a node expected to hold the new namespace
4308 * @ns: the original namespace
4309 *
4310 * This function tries to locate a namespace definition in a tree
4311 * ancestors, or create a new namespace definition node similar to
4312 * @ns trying to reuse the same prefix. However if the given prefix is
4313 * null (default namespace) or reused within the subtree defined by
4314 * @tree or on one of its ancestors then a new prefix is generated.
4315 * Returns the (new) namespace definition or NULL in case of error
4316 */
4317xmlNsPtr
4318xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4319 xmlNsPtr def;
4320 xmlChar prefix[50];
4321 int counter = 1;
4322
4323 if (tree == NULL) {
4324#ifdef DEBUG_TREE
4325 xmlGenericError(xmlGenericErrorContext,
4326 "xmlNewReconciliedNs : tree == NULL\n");
4327#endif
4328 return(NULL);
4329 }
4330 if (ns == NULL) {
4331#ifdef DEBUG_TREE
4332 xmlGenericError(xmlGenericErrorContext,
4333 "xmlNewReconciliedNs : ns == NULL\n");
4334#endif
4335 return(NULL);
4336 }
4337 /*
4338 * Search an existing namespace definition inherited.
4339 */
4340 def = xmlSearchNsByHref(doc, tree, ns->href);
4341 if (def != NULL)
4342 return(def);
4343
4344 /*
4345 * Find a close prefix which is not already in use.
4346 * Let's strip namespace prefixes longer than 20 chars !
4347 */
Daniel Veillardf742d342002-03-07 00:05:35 +00004348 if (ns->prefix == NULL)
4349 sprintf((char *) prefix, "default");
4350 else
4351 sprintf((char *) prefix, "%.20s", ns->prefix);
4352
Owen Taylor3473f882001-02-23 17:55:21 +00004353 def = xmlSearchNs(doc, tree, prefix);
4354 while (def != NULL) {
4355 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00004356 if (ns->prefix == NULL)
4357 sprintf((char *) prefix, "default%d", counter++);
4358 else
4359 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00004360 def = xmlSearchNs(doc, tree, prefix);
4361 }
4362
4363 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004364 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004365 */
4366 def = xmlNewNs(tree, ns->href, prefix);
4367 return(def);
4368}
4369
4370/**
4371 * xmlReconciliateNs
4372 * @doc: the document
4373 * @tree: a node defining the subtree to reconciliate
4374 *
4375 * This function checks that all the namespaces declared within the given
4376 * tree are properly declared. This is needed for example after Copy or Cut
4377 * and then paste operations. The subtree may still hold pointers to
4378 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004379 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004380 * the new environment. If not possible the new namespaces are redeclared
4381 * on @tree at the top of the given subtree.
4382 * Returns the number of namespace declarations created or -1 in case of error.
4383 */
4384int
4385xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4386 xmlNsPtr *oldNs = NULL;
4387 xmlNsPtr *newNs = NULL;
4388 int sizeCache = 0;
4389 int nbCache = 0;
4390
4391 xmlNsPtr n;
4392 xmlNodePtr node = tree;
4393 xmlAttrPtr attr;
4394 int ret = 0, i;
4395
4396 while (node != NULL) {
4397 /*
4398 * Reconciliate the node namespace
4399 */
4400 if (node->ns != NULL) {
4401 /*
4402 * initialize the cache if needed
4403 */
4404 if (sizeCache == 0) {
4405 sizeCache = 10;
4406 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4407 sizeof(xmlNsPtr));
4408 if (oldNs == NULL) {
4409 xmlGenericError(xmlGenericErrorContext,
4410 "xmlReconciliateNs : memory pbm\n");
4411 return(-1);
4412 }
4413 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4414 sizeof(xmlNsPtr));
4415 if (newNs == NULL) {
4416 xmlGenericError(xmlGenericErrorContext,
4417 "xmlReconciliateNs : memory pbm\n");
4418 xmlFree(oldNs);
4419 return(-1);
4420 }
4421 }
4422 for (i = 0;i < nbCache;i++) {
4423 if (oldNs[i] == node->ns) {
4424 node->ns = newNs[i];
4425 break;
4426 }
4427 }
4428 if (i == nbCache) {
4429 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004430 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004431 */
4432 n = xmlNewReconciliedNs(doc, tree, node->ns);
4433 if (n != NULL) { /* :-( what if else ??? */
4434 /*
4435 * check if we need to grow the cache buffers.
4436 */
4437 if (sizeCache <= nbCache) {
4438 sizeCache *= 2;
4439 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4440 sizeof(xmlNsPtr));
4441 if (oldNs == NULL) {
4442 xmlGenericError(xmlGenericErrorContext,
4443 "xmlReconciliateNs : memory pbm\n");
4444 xmlFree(newNs);
4445 return(-1);
4446 }
4447 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4448 sizeof(xmlNsPtr));
4449 if (newNs == NULL) {
4450 xmlGenericError(xmlGenericErrorContext,
4451 "xmlReconciliateNs : memory pbm\n");
4452 xmlFree(oldNs);
4453 return(-1);
4454 }
4455 }
4456 newNs[nbCache] = n;
4457 oldNs[nbCache++] = node->ns;
4458 node->ns = n;
4459 }
4460 }
4461 }
4462 /*
4463 * now check for namespace hold by attributes on the node.
4464 */
4465 attr = node->properties;
4466 while (attr != NULL) {
4467 if (attr->ns != NULL) {
4468 /*
4469 * initialize the cache if needed
4470 */
4471 if (sizeCache == 0) {
4472 sizeCache = 10;
4473 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4474 sizeof(xmlNsPtr));
4475 if (oldNs == NULL) {
4476 xmlGenericError(xmlGenericErrorContext,
4477 "xmlReconciliateNs : memory pbm\n");
4478 return(-1);
4479 }
4480 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4481 sizeof(xmlNsPtr));
4482 if (newNs == NULL) {
4483 xmlGenericError(xmlGenericErrorContext,
4484 "xmlReconciliateNs : memory pbm\n");
4485 xmlFree(oldNs);
4486 return(-1);
4487 }
4488 }
4489 for (i = 0;i < nbCache;i++) {
4490 if (oldNs[i] == attr->ns) {
4491 node->ns = newNs[i];
4492 break;
4493 }
4494 }
4495 if (i == nbCache) {
4496 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004497 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004498 */
4499 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4500 if (n != NULL) { /* :-( what if else ??? */
4501 /*
4502 * check if we need to grow the cache buffers.
4503 */
4504 if (sizeCache <= nbCache) {
4505 sizeCache *= 2;
4506 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4507 sizeof(xmlNsPtr));
4508 if (oldNs == NULL) {
4509 xmlGenericError(xmlGenericErrorContext,
4510 "xmlReconciliateNs : memory pbm\n");
4511 xmlFree(newNs);
4512 return(-1);
4513 }
4514 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4515 sizeof(xmlNsPtr));
4516 if (newNs == NULL) {
4517 xmlGenericError(xmlGenericErrorContext,
4518 "xmlReconciliateNs : memory pbm\n");
4519 xmlFree(oldNs);
4520 return(-1);
4521 }
4522 }
4523 newNs[nbCache] = n;
4524 oldNs[nbCache++] = attr->ns;
4525 attr->ns = n;
4526 }
4527 }
4528 }
4529 attr = attr->next;
4530 }
4531
4532 /*
4533 * Browse the full subtree, deep first
4534 */
4535 if (node->children != NULL) {
4536 /* deep first */
4537 node = node->children;
4538 } else if ((node != tree) && (node->next != NULL)) {
4539 /* then siblings */
4540 node = node->next;
4541 } else if (node != tree) {
4542 /* go up to parents->next if needed */
4543 while (node != tree) {
4544 if (node->parent != NULL)
4545 node = node->parent;
4546 if ((node != tree) && (node->next != NULL)) {
4547 node = node->next;
4548 break;
4549 }
4550 if (node->parent == NULL) {
4551 node = NULL;
4552 break;
4553 }
4554 }
4555 /* exit condition */
4556 if (node == tree)
4557 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00004558 } else
4559 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004560 }
Daniel Veillardf742d342002-03-07 00:05:35 +00004561 if (oldNs != NULL)
4562 xmlFree(oldNs);
4563 if (newNs != NULL)
4564 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00004565 return(ret);
4566}
4567
4568/**
4569 * xmlHasProp:
4570 * @node: the node
4571 * @name: the attribute name
4572 *
4573 * Search an attribute associated to a node
4574 * This function also looks in DTD attribute declaration for #FIXED or
4575 * default declaration values unless DTD use has been turned off.
4576 *
4577 * Returns the attribute or the attribute declaration or NULL if
4578 * neither was found.
4579 */
4580xmlAttrPtr
4581xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4582 xmlAttrPtr prop;
4583 xmlDocPtr doc;
4584
4585 if ((node == NULL) || (name == NULL)) return(NULL);
4586 /*
4587 * Check on the properties attached to the node
4588 */
4589 prop = node->properties;
4590 while (prop != NULL) {
4591 if (xmlStrEqual(prop->name, name)) {
4592 return(prop);
4593 }
4594 prop = prop->next;
4595 }
4596 if (!xmlCheckDTD) return(NULL);
4597
4598 /*
4599 * Check if there is a default declaration in the internal
4600 * or external subsets
4601 */
4602 doc = node->doc;
4603 if (doc != NULL) {
4604 xmlAttributePtr attrDecl;
4605 if (doc->intSubset != NULL) {
4606 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4607 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4608 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4609 if (attrDecl != NULL)
4610 return((xmlAttrPtr) attrDecl);
4611 }
4612 }
4613 return(NULL);
4614}
4615
4616/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004617 * xmlHasNsProp:
4618 * @node: the node
4619 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004620 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004621 *
4622 * Search for an attribute associated to a node
4623 * This attribute has to be anchored in the namespace specified.
4624 * This does the entity substitution.
4625 * This function looks in DTD attribute declaration for #FIXED or
4626 * default declaration values unless DTD use has been turned off.
4627 *
4628 * Returns the attribute or the attribute declaration or NULL
4629 * if neither was found.
4630 */
4631xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004632xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004633 xmlAttrPtr prop;
4634 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004635
4636 if (node == NULL)
4637 return(NULL);
4638
4639 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004640 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004641 return(xmlHasProp(node, name));
4642 while (prop != NULL) {
4643 /*
4644 * One need to have
4645 * - same attribute names
4646 * - and the attribute carrying that namespace
4647 * or
4648 * no namespace on the attribute and the element carrying it
4649 */
4650 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004651 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4652 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004653 }
4654 prop = prop->next;
4655 }
4656 if (!xmlCheckDTD) return(NULL);
4657
4658 /*
4659 * Check if there is a default declaration in the internal
4660 * or external subsets
4661 */
4662 doc = node->doc;
4663 if (doc != NULL) {
4664 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004665 xmlAttributePtr attrDecl = NULL;
4666 xmlNsPtr *nsList, *cur;
4667 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004668
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004669 nsList = xmlGetNsList(node->doc, node);
4670 if (nsList == NULL)
4671 return(NULL);
4672 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
4673 ename = xmlStrdup(node->ns->prefix);
4674 ename = xmlStrcat(ename, BAD_CAST ":");
4675 ename = xmlStrcat(ename, node->name);
4676 } else {
4677 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004678 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004679 if (ename == NULL) {
4680 xmlFree(nsList);
4681 return(NULL);
4682 }
4683
4684 cur = nsList;
4685 while (*cur != NULL) {
4686 if (xmlStrEqual((*cur)->href, nameSpace)) {
4687 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
4688 name, (*cur)->prefix);
4689 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4690 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
4691 name, (*cur)->prefix);
4692 }
4693 cur++;
4694 }
4695 xmlFree(nsList);
4696 xmlFree(ename);
4697 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004698 }
4699 }
4700 return(NULL);
4701}
4702
4703/**
Owen Taylor3473f882001-02-23 17:55:21 +00004704 * xmlGetProp:
4705 * @node: the node
4706 * @name: the attribute name
4707 *
4708 * Search and get the value of an attribute associated to a node
4709 * This does the entity substitution.
4710 * This function looks in DTD attribute declaration for #FIXED or
4711 * default declaration values unless DTD use has been turned off.
4712 *
4713 * Returns the attribute value or NULL if not found.
4714 * It's up to the caller to free the memory.
4715 */
4716xmlChar *
4717xmlGetProp(xmlNodePtr node, const xmlChar *name) {
4718 xmlAttrPtr prop;
4719 xmlDocPtr doc;
4720
4721 if ((node == NULL) || (name == NULL)) return(NULL);
4722 /*
4723 * Check on the properties attached to the node
4724 */
4725 prop = node->properties;
4726 while (prop != NULL) {
4727 if (xmlStrEqual(prop->name, name)) {
4728 xmlChar *ret;
4729
4730 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4731 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4732 return(ret);
4733 }
4734 prop = prop->next;
4735 }
4736 if (!xmlCheckDTD) return(NULL);
4737
4738 /*
4739 * Check if there is a default declaration in the internal
4740 * or external subsets
4741 */
4742 doc = node->doc;
4743 if (doc != NULL) {
4744 xmlAttributePtr attrDecl;
4745 if (doc->intSubset != NULL) {
4746 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4747 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4748 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4749 if (attrDecl != NULL)
4750 return(xmlStrdup(attrDecl->defaultValue));
4751 }
4752 }
4753 return(NULL);
4754}
4755
4756/**
4757 * xmlGetNsProp:
4758 * @node: the node
4759 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004760 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004761 *
4762 * Search and get the value of an attribute associated to a node
4763 * This attribute has to be anchored in the namespace specified.
4764 * This does the entity substitution.
4765 * This function looks in DTD attribute declaration for #FIXED or
4766 * default declaration values unless DTD use has been turned off.
4767 *
4768 * Returns the attribute value or NULL if not found.
4769 * It's up to the caller to free the memory.
4770 */
4771xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00004772xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00004773 xmlAttrPtr prop;
4774 xmlDocPtr doc;
4775 xmlNsPtr ns;
4776
4777 if (node == NULL)
4778 return(NULL);
4779
4780 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004781 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00004782 return(xmlGetProp(node, name));
4783 while (prop != NULL) {
4784 /*
4785 * One need to have
4786 * - same attribute names
4787 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004788 */
4789 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00004790 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00004791 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00004792 xmlChar *ret;
4793
4794 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4795 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4796 return(ret);
4797 }
4798 prop = prop->next;
4799 }
4800 if (!xmlCheckDTD) return(NULL);
4801
4802 /*
4803 * Check if there is a default declaration in the internal
4804 * or external subsets
4805 */
4806 doc = node->doc;
4807 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004808 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00004809 xmlAttributePtr attrDecl;
4810
Owen Taylor3473f882001-02-23 17:55:21 +00004811 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4812 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4813 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4814
4815 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4816 /*
4817 * The DTD declaration only allows a prefix search
4818 */
4819 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004820 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00004821 return(xmlStrdup(attrDecl->defaultValue));
4822 }
4823 }
4824 }
4825 return(NULL);
4826}
4827
4828/**
4829 * xmlSetProp:
4830 * @node: the node
4831 * @name: the attribute name
4832 * @value: the attribute value
4833 *
4834 * Set (or reset) an attribute carried by a node.
4835 * Returns the attribute pointer.
4836 */
4837xmlAttrPtr
4838xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004839 xmlAttrPtr prop;
4840 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004841
4842 if ((node == NULL) || (name == NULL))
4843 return(NULL);
4844 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004845 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00004846 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00004847 if ((xmlStrEqual(prop->name, name)) &&
4848 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004849 xmlNodePtr oldprop = prop->children;
4850
Owen Taylor3473f882001-02-23 17:55:21 +00004851 prop->children = NULL;
4852 prop->last = NULL;
4853 if (value != NULL) {
4854 xmlChar *buffer;
4855 xmlNodePtr tmp;
4856
4857 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4858 prop->children = xmlStringGetNodeList(node->doc, buffer);
4859 prop->last = NULL;
4860 prop->doc = doc;
4861 tmp = prop->children;
4862 while (tmp != NULL) {
4863 tmp->parent = (xmlNodePtr) prop;
4864 tmp->doc = doc;
4865 if (tmp->next == NULL)
4866 prop->last = tmp;
4867 tmp = tmp->next;
4868 }
4869 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00004870 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004871 if (oldprop != NULL)
4872 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00004873 return(prop);
4874 }
4875 prop = prop->next;
4876 }
4877 prop = xmlNewProp(node, name, value);
4878 return(prop);
4879}
4880
4881/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004882 * xmlUnsetProp:
4883 * @node: the node
4884 * @name: the attribute name
4885 *
4886 * Remove an attribute carried by a node.
4887 * Returns 0 if successful, -1 if not found
4888 */
4889int
4890xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
4891 xmlAttrPtr prop = node->properties, prev = NULL;;
4892
4893 if ((node == NULL) || (name == NULL))
4894 return(-1);
4895 while (prop != NULL) {
4896 if ((xmlStrEqual(prop->name, name)) &&
4897 (prop->ns == NULL)) {
4898 if (prev == NULL)
4899 node->properties = prop->next;
4900 else
4901 prev->next = prop->next;
4902 xmlFreeProp(prop);
4903 return(0);
4904 }
4905 prev = prop;
4906 prop = prop->next;
4907 }
4908 return(-1);
4909}
4910
4911/**
Owen Taylor3473f882001-02-23 17:55:21 +00004912 * xmlSetNsProp:
4913 * @node: the node
4914 * @ns: the namespace definition
4915 * @name: the attribute name
4916 * @value: the attribute value
4917 *
4918 * Set (or reset) an attribute carried by a node.
4919 * The ns structure must be in scope, this is not checked.
4920 *
4921 * Returns the attribute pointer.
4922 */
4923xmlAttrPtr
4924xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
4925 const xmlChar *value) {
4926 xmlAttrPtr prop;
4927
4928 if ((node == NULL) || (name == NULL))
4929 return(NULL);
4930
4931 if (ns == NULL)
4932 return(xmlSetProp(node, name, value));
4933 if (ns->href == NULL)
4934 return(NULL);
4935 prop = node->properties;
4936
4937 while (prop != NULL) {
4938 /*
4939 * One need to have
4940 * - same attribute names
4941 * - and the attribute carrying that namespace
4942 * or
4943 * no namespace on the attribute and the element carrying it
4944 */
4945 if ((xmlStrEqual(prop->name, name)) &&
4946 (((prop->ns == NULL) && (node->ns != NULL) &&
4947 (xmlStrEqual(node->ns->href, ns->href))) ||
4948 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4949 if (prop->children != NULL)
4950 xmlFreeNodeList(prop->children);
4951 prop->children = NULL;
4952 prop->last = NULL;
4953 prop->ns = ns;
4954 if (value != NULL) {
4955 xmlChar *buffer;
4956 xmlNodePtr tmp;
4957
4958 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4959 prop->children = xmlStringGetNodeList(node->doc, buffer);
4960 prop->last = NULL;
4961 tmp = prop->children;
4962 while (tmp != NULL) {
4963 tmp->parent = (xmlNodePtr) prop;
4964 if (tmp->next == NULL)
4965 prop->last = tmp;
4966 tmp = tmp->next;
4967 }
4968 xmlFree(buffer);
4969 }
4970 return(prop);
4971 }
4972 prop = prop->next;
4973 }
4974 prop = xmlNewNsProp(node, ns, name, value);
4975 return(prop);
4976}
4977
4978/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004979 * xmlUnsetNsProp:
4980 * @node: the node
4981 * @ns: the namespace definition
4982 * @name: the attribute name
4983 *
4984 * Remove an attribute carried by a node.
4985 * Returns 0 if successful, -1 if not found
4986 */
4987int
4988xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
4989 xmlAttrPtr prop = node->properties, prev = NULL;;
4990
4991 if ((node == NULL) || (name == NULL))
4992 return(-1);
4993 if (ns == NULL)
4994 return(xmlUnsetProp(node, name));
4995 if (ns->href == NULL)
4996 return(-1);
4997 while (prop != NULL) {
4998 if ((xmlStrEqual(prop->name, name)) &&
4999 (((prop->ns == NULL) && (node->ns != NULL) &&
5000 (xmlStrEqual(node->ns->href, ns->href))) ||
5001 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
5002 if (prev == NULL)
5003 node->properties = prop->next;
5004 else
5005 prev->next = prop->next;
5006 xmlFreeProp(prop);
5007 return(0);
5008 }
5009 prev = prop;
5010 prop = prop->next;
5011 }
5012 return(-1);
5013}
5014
5015/**
Owen Taylor3473f882001-02-23 17:55:21 +00005016 * xmlNodeIsText:
5017 * @node: the node
5018 *
5019 * Is this node a Text node ?
5020 * Returns 1 yes, 0 no
5021 */
5022int
5023xmlNodeIsText(xmlNodePtr node) {
5024 if (node == NULL) return(0);
5025
5026 if (node->type == XML_TEXT_NODE) return(1);
5027 return(0);
5028}
5029
5030/**
5031 * xmlIsBlankNode:
5032 * @node: the node
5033 *
5034 * Checks whether this node is an empty or whitespace only
5035 * (and possibly ignorable) text-node.
5036 *
5037 * Returns 1 yes, 0 no
5038 */
5039int
5040xmlIsBlankNode(xmlNodePtr node) {
5041 const xmlChar *cur;
5042 if (node == NULL) return(0);
5043
Daniel Veillard7db37732001-07-12 01:20:08 +00005044 if ((node->type != XML_TEXT_NODE) &&
5045 (node->type != XML_CDATA_SECTION_NODE))
5046 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005047 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005048 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005049 while (*cur != 0) {
5050 if (!IS_BLANK(*cur)) return(0);
5051 cur++;
5052 }
5053
5054 return(1);
5055}
5056
5057/**
5058 * xmlTextConcat:
5059 * @node: the node
5060 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005061 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005062 *
5063 * Concat the given string at the end of the existing node content
5064 */
5065
5066void
5067xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5068 if (node == NULL) return;
5069
5070 if ((node->type != XML_TEXT_NODE) &&
5071 (node->type != XML_CDATA_SECTION_NODE)) {
5072#ifdef DEBUG_TREE
5073 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005074 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005075#endif
5076 return;
5077 }
Owen Taylor3473f882001-02-23 17:55:21 +00005078 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005079}
5080
5081/************************************************************************
5082 * *
5083 * Output : to a FILE or in memory *
5084 * *
5085 ************************************************************************/
5086
Owen Taylor3473f882001-02-23 17:55:21 +00005087/**
5088 * xmlBufferCreate:
5089 *
5090 * routine to create an XML buffer.
5091 * returns the new structure.
5092 */
5093xmlBufferPtr
5094xmlBufferCreate(void) {
5095 xmlBufferPtr ret;
5096
5097 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5098 if (ret == NULL) {
5099 xmlGenericError(xmlGenericErrorContext,
5100 "xmlBufferCreate : out of memory!\n");
5101 return(NULL);
5102 }
5103 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005104 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005105 ret->alloc = xmlBufferAllocScheme;
5106 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5107 if (ret->content == NULL) {
5108 xmlGenericError(xmlGenericErrorContext,
5109 "xmlBufferCreate : out of memory!\n");
5110 xmlFree(ret);
5111 return(NULL);
5112 }
5113 ret->content[0] = 0;
5114 return(ret);
5115}
5116
5117/**
5118 * xmlBufferCreateSize:
5119 * @size: initial size of buffer
5120 *
5121 * routine to create an XML buffer.
5122 * returns the new structure.
5123 */
5124xmlBufferPtr
5125xmlBufferCreateSize(size_t size) {
5126 xmlBufferPtr ret;
5127
5128 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5129 if (ret == NULL) {
5130 xmlGenericError(xmlGenericErrorContext,
5131 "xmlBufferCreate : out of memory!\n");
5132 return(NULL);
5133 }
5134 ret->use = 0;
5135 ret->alloc = xmlBufferAllocScheme;
5136 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5137 if (ret->size){
5138 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5139 if (ret->content == NULL) {
5140 xmlGenericError(xmlGenericErrorContext,
5141 "xmlBufferCreate : out of memory!\n");
5142 xmlFree(ret);
5143 return(NULL);
5144 }
5145 ret->content[0] = 0;
5146 } else
5147 ret->content = NULL;
5148 return(ret);
5149}
5150
5151/**
5152 * xmlBufferSetAllocationScheme:
5153 * @buf: the buffer to free
5154 * @scheme: allocation scheme to use
5155 *
5156 * Sets the allocation scheme for this buffer
5157 */
5158void
5159xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5160 xmlBufferAllocationScheme scheme) {
5161 if (buf == NULL) {
5162#ifdef DEBUG_BUFFER
5163 xmlGenericError(xmlGenericErrorContext,
5164 "xmlBufferSetAllocationScheme: buf == NULL\n");
5165#endif
5166 return;
5167 }
5168
5169 buf->alloc = scheme;
5170}
5171
5172/**
5173 * xmlBufferFree:
5174 * @buf: the buffer to free
5175 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005176 * Frees an XML buffer. It frees both the content and the structure which
5177 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005178 */
5179void
5180xmlBufferFree(xmlBufferPtr buf) {
5181 if (buf == NULL) {
5182#ifdef DEBUG_BUFFER
5183 xmlGenericError(xmlGenericErrorContext,
5184 "xmlBufferFree: buf == NULL\n");
5185#endif
5186 return;
5187 }
5188 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005189 xmlFree(buf->content);
5190 }
Owen Taylor3473f882001-02-23 17:55:21 +00005191 xmlFree(buf);
5192}
5193
5194/**
5195 * xmlBufferEmpty:
5196 * @buf: the buffer
5197 *
5198 * empty a buffer.
5199 */
5200void
5201xmlBufferEmpty(xmlBufferPtr buf) {
5202 if (buf->content == NULL) return;
5203 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005204 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005205}
5206
5207/**
5208 * xmlBufferShrink:
5209 * @buf: the buffer to dump
5210 * @len: the number of xmlChar to remove
5211 *
5212 * Remove the beginning of an XML buffer.
5213 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005214 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005215 */
5216int
5217xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5218 if (len == 0) return(0);
5219 if (len > buf->use) return(-1);
5220
5221 buf->use -= len;
5222 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5223
5224 buf->content[buf->use] = 0;
5225 return(len);
5226}
5227
5228/**
5229 * xmlBufferGrow:
5230 * @buf: the buffer
5231 * @len: the minimum free size to allocate
5232 *
5233 * Grow the available space of an XML buffer.
5234 *
5235 * Returns the new available space or -1 in case of error
5236 */
5237int
5238xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5239 int size;
5240 xmlChar *newbuf;
5241
5242 if (len + buf->use < buf->size) return(0);
5243
5244 size = buf->use + len + 100;
5245
5246 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5247 if (newbuf == NULL) return(-1);
5248 buf->content = newbuf;
5249 buf->size = size;
5250 return(buf->size - buf->use);
5251}
5252
5253/**
5254 * xmlBufferDump:
5255 * @file: the file output
5256 * @buf: the buffer to dump
5257 *
5258 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005259 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005260 */
5261int
5262xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5263 int ret;
5264
5265 if (buf == NULL) {
5266#ifdef DEBUG_BUFFER
5267 xmlGenericError(xmlGenericErrorContext,
5268 "xmlBufferDump: buf == NULL\n");
5269#endif
5270 return(0);
5271 }
5272 if (buf->content == NULL) {
5273#ifdef DEBUG_BUFFER
5274 xmlGenericError(xmlGenericErrorContext,
5275 "xmlBufferDump: buf->content == NULL\n");
5276#endif
5277 return(0);
5278 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005279 if (file == NULL)
5280 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005281 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5282 return(ret);
5283}
5284
5285/**
5286 * xmlBufferContent:
5287 * @buf: the buffer
5288 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005289 * Function to extract the content of a buffer
5290 *
Owen Taylor3473f882001-02-23 17:55:21 +00005291 * Returns the internal content
5292 */
5293
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005294const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005295xmlBufferContent(const xmlBufferPtr buf)
5296{
5297 if(!buf)
5298 return NULL;
5299
5300 return buf->content;
5301}
5302
5303/**
5304 * xmlBufferLength:
5305 * @buf: the buffer
5306 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005307 * Function to get the length of a buffer
5308 *
Owen Taylor3473f882001-02-23 17:55:21 +00005309 * Returns the length of data in the internal content
5310 */
5311
5312int
5313xmlBufferLength(const xmlBufferPtr buf)
5314{
5315 if(!buf)
5316 return 0;
5317
5318 return buf->use;
5319}
5320
5321/**
5322 * xmlBufferResize:
5323 * @buf: the buffer to resize
5324 * @size: the desired size
5325 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005326 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005327 *
5328 * Returns 0 in case of problems, 1 otherwise
5329 */
5330int
5331xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5332{
5333 unsigned int newSize;
5334 xmlChar* rebuf = NULL;
5335
5336 /*take care of empty case*/
5337 newSize = (buf->size ? buf->size*2 : size);
5338
5339 /* Don't resize if we don't have to */
5340 if (size < buf->size)
5341 return 1;
5342
5343 /* figure out new size */
5344 switch (buf->alloc){
5345 case XML_BUFFER_ALLOC_DOUBLEIT:
5346 while (size > newSize) newSize *= 2;
5347 break;
5348 case XML_BUFFER_ALLOC_EXACT:
5349 newSize = size+10;
5350 break;
5351 default:
5352 newSize = size+10;
5353 break;
5354 }
5355
5356 if (buf->content == NULL)
5357 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5358 else
5359 rebuf = (xmlChar *) xmlRealloc(buf->content,
5360 newSize * sizeof(xmlChar));
5361 if (rebuf == NULL) {
5362 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005363 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005364 return 0;
5365 }
5366 buf->content = rebuf;
5367 buf->size = newSize;
5368
5369 return 1;
5370}
5371
5372/**
5373 * xmlBufferAdd:
5374 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005375 * @str: the #xmlChar string
5376 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005377 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005378 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005379 * str is recomputed.
5380 */
5381void
5382xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5383 unsigned int needSize;
5384
5385 if (str == NULL) {
5386#ifdef DEBUG_BUFFER
5387 xmlGenericError(xmlGenericErrorContext,
5388 "xmlBufferAdd: str == NULL\n");
5389#endif
5390 return;
5391 }
5392 if (len < -1) {
5393#ifdef DEBUG_BUFFER
5394 xmlGenericError(xmlGenericErrorContext,
5395 "xmlBufferAdd: len < 0\n");
5396#endif
5397 return;
5398 }
5399 if (len == 0) return;
5400
5401 if (len < 0)
5402 len = xmlStrlen(str);
5403
5404 if (len <= 0) return;
5405
5406 needSize = buf->use + len + 2;
5407 if (needSize > buf->size){
5408 if (!xmlBufferResize(buf, needSize)){
5409 xmlGenericError(xmlGenericErrorContext,
5410 "xmlBufferAdd : out of memory!\n");
5411 return;
5412 }
5413 }
5414
5415 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5416 buf->use += len;
5417 buf->content[buf->use] = 0;
5418}
5419
5420/**
5421 * xmlBufferAddHead:
5422 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005423 * @str: the #xmlChar string
5424 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005425 *
5426 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005427 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005428 */
5429void
5430xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5431 unsigned int needSize;
5432
5433 if (str == NULL) {
5434#ifdef DEBUG_BUFFER
5435 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005436 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005437#endif
5438 return;
5439 }
5440 if (len < -1) {
5441#ifdef DEBUG_BUFFER
5442 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005443 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005444#endif
5445 return;
5446 }
5447 if (len == 0) return;
5448
5449 if (len < 0)
5450 len = xmlStrlen(str);
5451
5452 if (len <= 0) return;
5453
5454 needSize = buf->use + len + 2;
5455 if (needSize > buf->size){
5456 if (!xmlBufferResize(buf, needSize)){
5457 xmlGenericError(xmlGenericErrorContext,
5458 "xmlBufferAddHead : out of memory!\n");
5459 return;
5460 }
5461 }
5462
5463 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5464 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5465 buf->use += len;
5466 buf->content[buf->use] = 0;
5467}
5468
5469/**
5470 * xmlBufferCat:
5471 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005472 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005473 *
5474 * Append a zero terminated string to an XML buffer.
5475 */
5476void
5477xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5478 if (str != NULL)
5479 xmlBufferAdd(buf, str, -1);
5480}
5481
5482/**
5483 * xmlBufferCCat:
5484 * @buf: the buffer to dump
5485 * @str: the C char string
5486 *
5487 * Append a zero terminated C string to an XML buffer.
5488 */
5489void
5490xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5491 const char *cur;
5492
5493 if (str == NULL) {
5494#ifdef DEBUG_BUFFER
5495 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005496 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005497#endif
5498 return;
5499 }
5500 for (cur = str;*cur != 0;cur++) {
5501 if (buf->use + 10 >= buf->size) {
5502 if (!xmlBufferResize(buf, buf->use+10)){
5503 xmlGenericError(xmlGenericErrorContext,
5504 "xmlBufferCCat : out of memory!\n");
5505 return;
5506 }
5507 }
5508 buf->content[buf->use++] = *cur;
5509 }
5510 buf->content[buf->use] = 0;
5511}
5512
5513/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005514 * xmlBufferWriteXmlCHAR:
5515 * @buf: the XML buffer
5516 * @string: the string to add
5517 *
5518 * For VMS only.
5519 * routine which manages and grows an output buffer. This one adds
5520 * xmlChars at the end of the buffer.
5521 */
5522/**
Owen Taylor3473f882001-02-23 17:55:21 +00005523 * xmlBufferWriteCHAR:
5524 * @buf: the XML buffer
5525 * @string: the string to add
5526 *
5527 * routine which manages and grows an output buffer. This one adds
5528 * xmlChars at the end of the buffer.
5529 */
5530void
5531#ifdef VMS
5532xmlBufferWriteXmlCHAR
5533#else
5534xmlBufferWriteCHAR
5535#endif
5536(xmlBufferPtr buf, const xmlChar *string) {
5537 xmlBufferCat(buf, string);
5538}
5539
5540/**
5541 * xmlBufferWriteChar:
5542 * @buf: the XML buffer output
5543 * @string: the string to add
5544 *
5545 * routine which manage and grows an output buffer. This one add
5546 * C chars at the end of the array.
5547 */
5548void
5549xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5550 xmlBufferCCat(buf, string);
5551}
5552
5553
5554/**
5555 * xmlBufferWriteQuotedString:
5556 * @buf: the XML buffer output
5557 * @string: the string to add
5558 *
5559 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005560 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005561 * quote or double-quotes internally
5562 */
5563void
5564xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5565 if (xmlStrchr(string, '"')) {
5566 if (xmlStrchr(string, '\'')) {
5567#ifdef DEBUG_BUFFER
5568 xmlGenericError(xmlGenericErrorContext,
5569 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5570#endif
5571 }
5572 xmlBufferCCat(buf, "'");
5573 xmlBufferCat(buf, string);
5574 xmlBufferCCat(buf, "'");
5575 } else {
5576 xmlBufferCCat(buf, "\"");
5577 xmlBufferCat(buf, string);
5578 xmlBufferCCat(buf, "\"");
5579 }
5580}
5581
5582
5583/************************************************************************
5584 * *
5585 * Dumping XML tree content to a simple buffer *
5586 * *
5587 ************************************************************************/
5588
Owen Taylor3473f882001-02-23 17:55:21 +00005589static void
5590xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5591 int format);
5592void
5593htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5594
5595/**
5596 * xmlNsDump:
5597 * @buf: the XML buffer output
5598 * @cur: a namespace
5599 *
5600 * Dump a local Namespace definition.
5601 * Should be called in the context of attributes dumps.
5602 */
5603static void
5604xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5605 if (cur == NULL) {
5606#ifdef DEBUG_TREE
5607 xmlGenericError(xmlGenericErrorContext,
5608 "xmlNsDump : Ns == NULL\n");
5609#endif
5610 return;
5611 }
5612 if (cur->type == XML_LOCAL_NAMESPACE) {
5613 /* Within the context of an element attributes */
5614 if (cur->prefix != NULL) {
5615 xmlBufferWriteChar(buf, " xmlns:");
5616 xmlBufferWriteCHAR(buf, cur->prefix);
5617 } else
5618 xmlBufferWriteChar(buf, " xmlns");
5619 xmlBufferWriteChar(buf, "=");
5620 xmlBufferWriteQuotedString(buf, cur->href);
5621 }
5622}
5623
5624/**
5625 * xmlNsListDump:
5626 * @buf: the XML buffer output
5627 * @cur: the first namespace
5628 *
5629 * Dump a list of local Namespace definitions.
5630 * Should be called in the context of attributes dumps.
5631 */
5632static void
5633xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5634 while (cur != NULL) {
5635 xmlNsDump(buf, cur);
5636 cur = cur->next;
5637 }
5638}
5639
5640/**
5641 * xmlDtdDump:
5642 * @buf: the XML buffer output
Daniel Veillardd1640922001-12-17 15:30:10 +00005643 * @dtd: the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00005644 *
5645 * Dump the XML document DTD, if any.
5646 */
5647static void
5648xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5649 if (dtd == NULL) {
5650#ifdef DEBUG_TREE
5651 xmlGenericError(xmlGenericErrorContext,
5652 "xmlDtdDump : no internal subset\n");
5653#endif
5654 return;
5655 }
5656 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5657 xmlBufferWriteCHAR(buf, dtd->name);
5658 if (dtd->ExternalID != NULL) {
5659 xmlBufferWriteChar(buf, " PUBLIC ");
5660 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5661 xmlBufferWriteChar(buf, " ");
5662 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5663 } else if (dtd->SystemID != NULL) {
5664 xmlBufferWriteChar(buf, " SYSTEM ");
5665 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5666 }
5667 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5668 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5669 xmlBufferWriteChar(buf, ">");
5670 return;
5671 }
5672 xmlBufferWriteChar(buf, " [\n");
5673 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5674#if 0
5675 if (dtd->entities != NULL)
5676 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5677 if (dtd->notations != NULL)
5678 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5679 if (dtd->elements != NULL)
5680 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5681 if (dtd->attributes != NULL)
5682 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5683#endif
5684 xmlBufferWriteChar(buf, "]>");
5685}
5686
5687/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00005688 * xmlAttrSerializeContent:
5689 * @buf: the XML buffer output
5690 * @doc: the document
5691 * @attr: the attribute pointer
5692 *
5693 * Serialize the attribute in the buffer
5694 */
5695static void
5696xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr) {
5697 const xmlChar *cur, *base;
5698 xmlNodePtr children;
5699
5700 children = attr->children;
5701 while (children != NULL) {
5702 switch (children->type) {
5703 case XML_TEXT_NODE:
5704 base = cur = children->content;
5705 while (*cur != 0) {
5706 if (*cur == '\n') {
5707 if (base != cur)
5708 xmlBufferAdd(buf, base, cur - base);
5709 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
5710 cur++;
5711 base = cur;
5712#if 0
5713 } else if (*cur == '\'') {
5714 if (base != cur)
5715 xmlBufferAdd(buf, base, cur - base);
5716 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
5717 cur++;
5718 base = cur;
5719#endif
5720 } else if (*cur == '"') {
5721 if (base != cur)
5722 xmlBufferAdd(buf, base, cur - base);
5723 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
5724 cur++;
5725 base = cur;
5726 } else if (*cur == '<') {
5727 if (base != cur)
5728 xmlBufferAdd(buf, base, cur - base);
5729 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
5730 cur++;
5731 base = cur;
5732 } else if (*cur == '>') {
5733 if (base != cur)
5734 xmlBufferAdd(buf, base, cur - base);
5735 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
5736 cur++;
5737 base = cur;
5738 } else if (*cur == '&') {
5739 if (base != cur)
5740 xmlBufferAdd(buf, base, cur - base);
5741 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
5742 cur++;
5743 base = cur;
5744 } else if ((*cur >= 0x80) && ((doc == NULL) ||
5745 (doc->encoding == NULL))) {
5746 /*
5747 * We assume we have UTF-8 content.
5748 */
5749 char tmp[10];
5750 int val = 0, l = 1;
5751
5752 if (base != cur)
5753 xmlBufferAdd(buf, base, cur - base);
5754 if (*cur < 0xC0) {
5755 xmlGenericError(xmlGenericErrorContext,
5756 "xmlAttrSerializeContent : input not UTF-8\n");
5757 if (doc != NULL)
5758 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
5759 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
5760 tmp[sizeof(tmp) - 1] = 0;
5761 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
5762 cur++;
5763 base = cur;
5764 continue;
5765 } else if (*cur < 0xE0) {
5766 val = (cur[0]) & 0x1F;
5767 val <<= 6;
5768 val |= (cur[1]) & 0x3F;
5769 l = 2;
5770 } else if (*cur < 0xF0) {
5771 val = (cur[0]) & 0x0F;
5772 val <<= 6;
5773 val |= (cur[1]) & 0x3F;
5774 val <<= 6;
5775 val |= (cur[2]) & 0x3F;
5776 l = 3;
5777 } else if (*cur < 0xF8) {
5778 val = (cur[0]) & 0x07;
5779 val <<= 6;
5780 val |= (cur[1]) & 0x3F;
5781 val <<= 6;
5782 val |= (cur[2]) & 0x3F;
5783 val <<= 6;
5784 val |= (cur[3]) & 0x3F;
5785 l = 4;
5786 }
5787 if ((l == 1) || (!IS_CHAR(val))) {
5788 xmlGenericError(xmlGenericErrorContext,
5789 "xmlAttrSerializeContent : char out of range\n");
5790 if (doc != NULL)
5791 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
5792 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
5793 tmp[sizeof(tmp) - 1] = 0;
5794 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
5795 cur++;
5796 base = cur;
5797 continue;
5798 }
5799 /*
5800 * We could do multiple things here. Just save
5801 * as a char ref
5802 */
5803 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
5804 tmp[sizeof(tmp) - 1] = 0;
5805 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
5806 cur += l;
5807 base = cur;
5808 } else {
5809 cur++;
5810 }
5811 }
5812 if (base != cur)
5813 xmlBufferAdd(buf, base, cur - base);
5814 break;
5815 case XML_ENTITY_REF_NODE:
5816 xmlBufferAdd(buf, BAD_CAST "&", 1);
5817 xmlBufferAdd(buf, children->name, xmlStrlen(children->name));
5818 xmlBufferAdd(buf, BAD_CAST ";", 1);
5819 break;
5820 default:
5821 /* should not happen unless we have a badly built tree */
5822 break;
5823 }
5824 children = children->next;
5825 }
5826}
5827
5828/**
Owen Taylor3473f882001-02-23 17:55:21 +00005829 * xmlAttrDump:
5830 * @buf: the XML buffer output
5831 * @doc: the document
5832 * @cur: the attribute pointer
5833 *
5834 * Dump an XML attribute
5835 */
5836static void
5837xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00005838 if (cur == NULL) {
5839#ifdef DEBUG_TREE
5840 xmlGenericError(xmlGenericErrorContext,
5841 "xmlAttrDump : property == NULL\n");
5842#endif
5843 return;
5844 }
5845 xmlBufferWriteChar(buf, " ");
5846 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5847 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5848 xmlBufferWriteChar(buf, ":");
5849 }
5850 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00005851 xmlBufferWriteChar(buf, "=\"");
5852 xmlAttrSerializeContent(buf, doc, cur);
5853 xmlBufferWriteChar(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00005854}
5855
5856/**
5857 * xmlAttrListDump:
5858 * @buf: the XML buffer output
5859 * @doc: the document
5860 * @cur: the first attribute pointer
5861 *
5862 * Dump a list of XML attributes
5863 */
5864static void
5865xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5866 if (cur == NULL) {
5867#ifdef DEBUG_TREE
5868 xmlGenericError(xmlGenericErrorContext,
5869 "xmlAttrListDump : property == NULL\n");
5870#endif
5871 return;
5872 }
5873 while (cur != NULL) {
5874 xmlAttrDump(buf, doc, cur);
5875 cur = cur->next;
5876 }
5877}
5878
5879
5880
5881/**
5882 * xmlNodeListDump:
5883 * @buf: the XML buffer output
5884 * @doc: the document
5885 * @cur: the first node
5886 * @level: the imbrication level for indenting
5887 * @format: is formatting allowed
5888 *
5889 * Dump an XML node list, recursive behaviour,children are printed too.
5890 */
5891static void
5892xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5893 int format) {
5894 int i;
5895
5896 if (cur == NULL) {
5897#ifdef DEBUG_TREE
5898 xmlGenericError(xmlGenericErrorContext,
5899 "xmlNodeListDump : node == NULL\n");
5900#endif
5901 return;
5902 }
5903 while (cur != NULL) {
5904 if ((format) && (xmlIndentTreeOutput) &&
5905 (cur->type == XML_ELEMENT_NODE))
5906 for (i = 0;i < level;i++)
5907 xmlBufferWriteChar(buf, " ");
5908 xmlNodeDump(buf, doc, cur, level, format);
5909 if (format) {
5910 xmlBufferWriteChar(buf, "\n");
5911 }
5912 cur = cur->next;
5913 }
5914}
5915
5916/**
5917 * xmlNodeDump:
5918 * @buf: the XML buffer output
5919 * @doc: the document
5920 * @cur: the current node
5921 * @level: the imbrication level for indenting
5922 * @format: is formatting allowed
5923 *
5924 * Dump an XML node, recursive behaviour,children are printed too.
5925 */
5926void
5927xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5928 int format) {
5929 int i;
5930 xmlNodePtr tmp;
5931
5932 if (cur == NULL) {
5933#ifdef DEBUG_TREE
5934 xmlGenericError(xmlGenericErrorContext,
5935 "xmlNodeDump : node == NULL\n");
5936#endif
5937 return;
5938 }
5939 if (cur->type == XML_XINCLUDE_START)
5940 return;
5941 if (cur->type == XML_XINCLUDE_END)
5942 return;
5943 if (cur->type == XML_DTD_NODE) {
5944 xmlDtdDump(buf, (xmlDtdPtr) cur);
5945 return;
5946 }
5947 if (cur->type == XML_ELEMENT_DECL) {
5948 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
5949 return;
5950 }
Daniel Veillard78d12092001-10-11 09:12:24 +00005951 if (cur->type == XML_ATTRIBUTE_NODE){
5952 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
5953 return;
5954 }
Owen Taylor3473f882001-02-23 17:55:21 +00005955 if (cur->type == XML_ATTRIBUTE_DECL) {
5956 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
5957 return;
5958 }
5959 if (cur->type == XML_ENTITY_DECL) {
5960 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
5961 return;
5962 }
5963 if (cur->type == XML_TEXT_NODE) {
5964 if (cur->content != NULL) {
5965 if ((cur->name == xmlStringText) ||
5966 (cur->name != xmlStringTextNoenc)) {
5967 xmlChar *buffer;
5968
Owen Taylor3473f882001-02-23 17:55:21 +00005969 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005970 if (buffer != NULL) {
5971 xmlBufferWriteCHAR(buf, buffer);
5972 xmlFree(buffer);
5973 }
5974 } else {
5975 /*
5976 * Disable escaping, needed for XSLT
5977 */
Owen Taylor3473f882001-02-23 17:55:21 +00005978 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005979 }
5980 }
5981 return;
5982 }
5983 if (cur->type == XML_PI_NODE) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00005984 xmlBufferWriteChar(buf, "<?");
5985 xmlBufferWriteCHAR(buf, cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005986 if (cur->content != NULL) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00005987 xmlBufferWriteChar(buf, " ");
Daniel Veillard2c748c62002-01-16 15:37:50 +00005988 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005989 }
Daniel Veillard2c748c62002-01-16 15:37:50 +00005990 xmlBufferWriteChar(buf, "?>");
Owen Taylor3473f882001-02-23 17:55:21 +00005991 return;
5992 }
5993 if (cur->type == XML_COMMENT_NODE) {
5994 if (cur->content != NULL) {
5995 xmlBufferWriteChar(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00005996 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005997 xmlBufferWriteChar(buf, "-->");
5998 }
5999 return;
6000 }
6001 if (cur->type == XML_ENTITY_REF_NODE) {
6002 xmlBufferWriteChar(buf, "&");
6003 xmlBufferWriteCHAR(buf, cur->name);
6004 xmlBufferWriteChar(buf, ";");
6005 return;
6006 }
6007 if (cur->type == XML_CDATA_SECTION_NODE) {
6008 xmlBufferWriteChar(buf, "<![CDATA[");
6009 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006010 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006011 xmlBufferWriteChar(buf, "]]>");
6012 return;
6013 }
6014
6015 if (format == 1) {
6016 tmp = cur->children;
6017 while (tmp != NULL) {
6018 if ((tmp->type == XML_TEXT_NODE) ||
6019 (tmp->type == XML_ENTITY_REF_NODE)) {
6020 format = 0;
6021 break;
6022 }
6023 tmp = tmp->next;
6024 }
6025 }
6026 xmlBufferWriteChar(buf, "<");
6027 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6028 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6029 xmlBufferWriteChar(buf, ":");
6030 }
6031
6032 xmlBufferWriteCHAR(buf, cur->name);
6033 if (cur->nsDef)
6034 xmlNsListDump(buf, cur->nsDef);
6035 if (cur->properties != NULL)
6036 xmlAttrListDump(buf, doc, cur->properties);
6037
Daniel Veillard7db37732001-07-12 01:20:08 +00006038 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6039 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00006040 (!xmlSaveNoEmptyTags)) {
6041 xmlBufferWriteChar(buf, "/>");
6042 return;
6043 }
6044 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006045 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006046 xmlChar *buffer;
6047
Owen Taylor3473f882001-02-23 17:55:21 +00006048 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006049 if (buffer != NULL) {
6050 xmlBufferWriteCHAR(buf, buffer);
6051 xmlFree(buffer);
6052 }
6053 }
6054 if (cur->children != NULL) {
6055 if (format) xmlBufferWriteChar(buf, "\n");
6056 xmlNodeListDump(buf, doc, cur->children,
6057 (level >= 0?level+1:-1), format);
6058 if ((xmlIndentTreeOutput) && (format))
6059 for (i = 0;i < level;i++)
6060 xmlBufferWriteChar(buf, " ");
6061 }
6062 xmlBufferWriteChar(buf, "</");
6063 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6064 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6065 xmlBufferWriteChar(buf, ":");
6066 }
6067
6068 xmlBufferWriteCHAR(buf, cur->name);
6069 xmlBufferWriteChar(buf, ">");
6070}
6071
6072/**
6073 * xmlElemDump:
6074 * @f: the FILE * for the output
6075 * @doc: the document
6076 * @cur: the current node
6077 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006078 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006079 */
6080void
6081xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
6082 xmlBufferPtr buf;
6083
6084 if (cur == NULL) {
6085#ifdef DEBUG_TREE
6086 xmlGenericError(xmlGenericErrorContext,
6087 "xmlElemDump : cur == NULL\n");
6088#endif
6089 return;
6090 }
Owen Taylor3473f882001-02-23 17:55:21 +00006091#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006092 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006093 xmlGenericError(xmlGenericErrorContext,
6094 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006095 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006096#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00006097
Owen Taylor3473f882001-02-23 17:55:21 +00006098 buf = xmlBufferCreate();
6099 if (buf == NULL) return;
6100 if ((doc != NULL) &&
6101 (doc->type == XML_HTML_DOCUMENT_NODE)) {
6102#ifdef LIBXML_HTML_ENABLED
6103 htmlNodeDump(buf, doc, cur);
6104#else
6105 xmlGenericError(xmlGenericErrorContext,
6106 "HTML support not compiled in\n");
6107#endif /* LIBXML_HTML_ENABLED */
6108 } else
6109 xmlNodeDump(buf, doc, cur, 0, 1);
6110 xmlBufferDump(f, buf);
6111 xmlBufferFree(buf);
6112}
6113
6114/************************************************************************
6115 * *
6116 * Dumping XML tree content to an I/O output buffer *
6117 * *
6118 ************************************************************************/
6119
Owen Taylor3473f882001-02-23 17:55:21 +00006120static void
6121xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6122 int level, int format, const char *encoding);
6123/**
6124 * xmlNsDumpOutput:
6125 * @buf: the XML buffer output
6126 * @cur: a namespace
6127 *
6128 * Dump a local Namespace definition.
6129 * Should be called in the context of attributes dumps.
6130 */
6131static void
6132xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6133 if (cur == NULL) {
6134#ifdef DEBUG_TREE
6135 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006136 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006137#endif
6138 return;
6139 }
6140 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
6141 /* Within the context of an element attributes */
6142 if (cur->prefix != NULL) {
6143 xmlOutputBufferWriteString(buf, " xmlns:");
6144 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6145 } else
6146 xmlOutputBufferWriteString(buf, " xmlns");
6147 xmlOutputBufferWriteString(buf, "=");
6148 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6149 }
6150}
6151
6152/**
6153 * xmlNsListDumpOutput:
6154 * @buf: the XML buffer output
6155 * @cur: the first namespace
6156 *
6157 * Dump a list of local Namespace definitions.
6158 * Should be called in the context of attributes dumps.
6159 */
6160static void
6161xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6162 while (cur != NULL) {
6163 xmlNsDumpOutput(buf, cur);
6164 cur = cur->next;
6165 }
6166}
6167
6168/**
6169 * xmlDtdDumpOutput:
6170 * @buf: the XML buffer output
6171 * @doc: the document
6172 * @encoding: an optional encoding string
6173 *
6174 * Dump the XML document DTD, if any.
6175 */
6176static void
6177xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6178 if (dtd == NULL) {
6179#ifdef DEBUG_TREE
6180 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006181 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006182#endif
6183 return;
6184 }
6185 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6186 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6187 if (dtd->ExternalID != NULL) {
6188 xmlOutputBufferWriteString(buf, " PUBLIC ");
6189 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6190 xmlOutputBufferWriteString(buf, " ");
6191 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6192 } else if (dtd->SystemID != NULL) {
6193 xmlOutputBufferWriteString(buf, " SYSTEM ");
6194 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6195 }
6196 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6197 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6198 xmlOutputBufferWriteString(buf, ">");
6199 return;
6200 }
6201 xmlOutputBufferWriteString(buf, " [\n");
6202 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6203 xmlOutputBufferWriteString(buf, "]>");
6204}
6205
6206/**
6207 * xmlAttrDumpOutput:
6208 * @buf: the XML buffer output
6209 * @doc: the document
6210 * @cur: the attribute pointer
6211 * @encoding: an optional encoding string
6212 *
6213 * Dump an XML attribute
6214 */
6215static void
6216xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006217 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006218 if (cur == NULL) {
6219#ifdef DEBUG_TREE
6220 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006221 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006222#endif
6223 return;
6224 }
6225 xmlOutputBufferWriteString(buf, " ");
6226 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6227 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6228 xmlOutputBufferWriteString(buf, ":");
6229 }
6230 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006231 xmlOutputBufferWriteString(buf, "=\"");
6232 xmlAttrSerializeContent(buf->buffer, doc, cur);
6233 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006234}
6235
6236/**
6237 * xmlAttrListDumpOutput:
6238 * @buf: the XML buffer output
6239 * @doc: the document
6240 * @cur: the first attribute pointer
6241 * @encoding: an optional encoding string
6242 *
6243 * Dump a list of XML attributes
6244 */
6245static void
6246xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6247 xmlAttrPtr cur, const char *encoding) {
6248 if (cur == NULL) {
6249#ifdef DEBUG_TREE
6250 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006251 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006252#endif
6253 return;
6254 }
6255 while (cur != NULL) {
6256 xmlAttrDumpOutput(buf, doc, cur, encoding);
6257 cur = cur->next;
6258 }
6259}
6260
6261
6262
6263/**
6264 * xmlNodeListDumpOutput:
6265 * @buf: the XML buffer output
6266 * @doc: the document
6267 * @cur: the first node
6268 * @level: the imbrication level for indenting
6269 * @format: is formatting allowed
6270 * @encoding: an optional encoding string
6271 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006272 * Dump an XML node list, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006273 */
6274static void
6275xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6276 xmlNodePtr cur, int level, int format, const char *encoding) {
6277 int i;
6278
6279 if (cur == NULL) {
6280#ifdef DEBUG_TREE
6281 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006282 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006283#endif
6284 return;
6285 }
6286 while (cur != NULL) {
6287 if ((format) && (xmlIndentTreeOutput) &&
6288 (cur->type == XML_ELEMENT_NODE))
6289 for (i = 0;i < level;i++)
6290 xmlOutputBufferWriteString(buf, " ");
6291 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6292 if (format) {
6293 xmlOutputBufferWriteString(buf, "\n");
6294 }
6295 cur = cur->next;
6296 }
6297}
6298
6299/**
6300 * xmlNodeDumpOutput:
6301 * @buf: the XML buffer output
6302 * @doc: the document
6303 * @cur: the current node
6304 * @level: the imbrication level for indenting
6305 * @format: is formatting allowed
6306 * @encoding: an optional encoding string
6307 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006308 * Dump an XML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006309 */
6310void
6311xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6312 int level, int format, const char *encoding) {
6313 int i;
6314 xmlNodePtr tmp;
6315
6316 if (cur == NULL) {
6317#ifdef DEBUG_TREE
6318 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006319 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006320#endif
6321 return;
6322 }
6323 if (cur->type == XML_XINCLUDE_START)
6324 return;
6325 if (cur->type == XML_XINCLUDE_END)
6326 return;
6327 if (cur->type == XML_DTD_NODE) {
6328 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6329 return;
6330 }
6331 if (cur->type == XML_ELEMENT_DECL) {
6332 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6333 return;
6334 }
6335 if (cur->type == XML_ATTRIBUTE_DECL) {
6336 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6337 return;
6338 }
6339 if (cur->type == XML_ENTITY_DECL) {
6340 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6341 return;
6342 }
6343 if (cur->type == XML_TEXT_NODE) {
6344 if (cur->content != NULL) {
6345 if ((cur->name == xmlStringText) ||
6346 (cur->name != xmlStringTextNoenc)) {
6347 xmlChar *buffer;
6348
Owen Taylor3473f882001-02-23 17:55:21 +00006349 if (encoding == NULL)
6350 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6351 else
6352 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006353 if (buffer != NULL) {
6354 xmlOutputBufferWriteString(buf, (const char *)buffer);
6355 xmlFree(buffer);
6356 }
6357 } else {
6358 /*
6359 * Disable escaping, needed for XSLT
6360 */
Owen Taylor3473f882001-02-23 17:55:21 +00006361 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006362 }
6363 }
6364
6365 return;
6366 }
6367 if (cur->type == XML_PI_NODE) {
6368 if (cur->content != NULL) {
6369 xmlOutputBufferWriteString(buf, "<?");
6370 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6371 if (cur->content != NULL) {
6372 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006373 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006374 }
6375 xmlOutputBufferWriteString(buf, "?>");
6376 } else {
6377 xmlOutputBufferWriteString(buf, "<?");
6378 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6379 xmlOutputBufferWriteString(buf, "?>");
6380 }
6381 return;
6382 }
6383 if (cur->type == XML_COMMENT_NODE) {
6384 if (cur->content != NULL) {
6385 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006386 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006387 xmlOutputBufferWriteString(buf, "-->");
6388 }
6389 return;
6390 }
6391 if (cur->type == XML_ENTITY_REF_NODE) {
6392 xmlOutputBufferWriteString(buf, "&");
6393 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6394 xmlOutputBufferWriteString(buf, ";");
6395 return;
6396 }
6397 if (cur->type == XML_CDATA_SECTION_NODE) {
6398 xmlOutputBufferWriteString(buf, "<![CDATA[");
6399 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006400 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006401 xmlOutputBufferWriteString(buf, "]]>");
6402 return;
6403 }
6404
6405 if (format == 1) {
6406 tmp = cur->children;
6407 while (tmp != NULL) {
6408 if ((tmp->type == XML_TEXT_NODE) ||
6409 (tmp->type == XML_ENTITY_REF_NODE)) {
6410 format = 0;
6411 break;
6412 }
6413 tmp = tmp->next;
6414 }
6415 }
6416 xmlOutputBufferWriteString(buf, "<");
6417 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6418 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6419 xmlOutputBufferWriteString(buf, ":");
6420 }
6421
6422 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6423 if (cur->nsDef)
6424 xmlNsListDumpOutput(buf, cur->nsDef);
6425 if (cur->properties != NULL)
6426 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6427
Daniel Veillard7db37732001-07-12 01:20:08 +00006428 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6429 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006430 xmlOutputBufferWriteString(buf, "/>");
6431 return;
6432 }
6433 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006434 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006435 xmlChar *buffer;
6436
Owen Taylor3473f882001-02-23 17:55:21 +00006437 if (encoding == NULL)
6438 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6439 else
6440 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006441 if (buffer != NULL) {
6442 xmlOutputBufferWriteString(buf, (const char *)buffer);
6443 xmlFree(buffer);
6444 }
6445 }
6446 if (cur->children != NULL) {
6447 if (format) xmlOutputBufferWriteString(buf, "\n");
6448 xmlNodeListDumpOutput(buf, doc, cur->children,
6449 (level >= 0?level+1:-1), format, encoding);
6450 if ((xmlIndentTreeOutput) && (format))
6451 for (i = 0;i < level;i++)
6452 xmlOutputBufferWriteString(buf, " ");
6453 }
6454 xmlOutputBufferWriteString(buf, "</");
6455 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6456 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6457 xmlOutputBufferWriteString(buf, ":");
6458 }
6459
6460 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6461 xmlOutputBufferWriteString(buf, ">");
6462}
6463
6464/**
6465 * xmlDocContentDumpOutput:
6466 * @buf: the XML buffer output
6467 * @cur: the document
6468 * @encoding: an optional encoding string
6469 * @format: should formatting spaces been added
6470 *
6471 * Dump an XML document.
6472 */
6473static void
6474xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6475 const char *encoding, int format) {
6476 xmlOutputBufferWriteString(buf, "<?xml version=");
6477 if (cur->version != NULL)
6478 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6479 else
6480 xmlOutputBufferWriteString(buf, "\"1.0\"");
6481 if (encoding == NULL) {
6482 if (cur->encoding != NULL)
6483 encoding = (const char *) cur->encoding;
6484 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6485 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6486 }
6487 if (encoding != NULL) {
6488 xmlOutputBufferWriteString(buf, " encoding=");
6489 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6490 }
6491 switch (cur->standalone) {
6492 case 0:
6493 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6494 break;
6495 case 1:
6496 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6497 break;
6498 }
6499 xmlOutputBufferWriteString(buf, "?>\n");
6500 if (cur->children != NULL) {
6501 xmlNodePtr child = cur->children;
6502
6503 while (child != NULL) {
6504 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6505 xmlOutputBufferWriteString(buf, "\n");
6506 child = child->next;
6507 }
6508 }
6509}
6510
6511/************************************************************************
6512 * *
6513 * Saving functions front-ends *
6514 * *
6515 ************************************************************************/
6516
6517/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006518 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006519 * @out_doc: Document to generate XML text from
6520 * @doc_txt_ptr: Memory pointer for allocated XML text
6521 * @doc_txt_len: Length of the generated XML text
6522 * @txt_encoding: Character encoding to use when generating XML text
6523 * @format: should formatting spaces been added
6524 *
6525 * Dump the current DOM tree into memory using the character encoding specified
6526 * by the caller. Note it is up to the caller of this function to free the
6527 * allocated memory.
6528 */
6529
6530void
6531xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006532 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006533 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006534 int dummy = 0;
6535
6536 xmlCharEncoding doc_charset;
6537 xmlOutputBufferPtr out_buff = NULL;
6538 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6539
6540 if (doc_txt_len == NULL) {
6541 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6542 }
6543
6544 if (doc_txt_ptr == NULL) {
6545 *doc_txt_len = 0;
6546 xmlGenericError(xmlGenericErrorContext,
6547 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6548 return;
6549 }
6550
6551 *doc_txt_ptr = NULL;
6552 *doc_txt_len = 0;
6553
6554 if (out_doc == NULL) {
6555 /* No document, no output */
6556 xmlGenericError(xmlGenericErrorContext,
6557 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6558 return;
6559 }
6560
6561 /*
6562 * Validate the encoding value, if provided.
6563 * This logic is copied from xmlSaveFileEnc.
6564 */
6565
6566 if (txt_encoding == NULL)
6567 txt_encoding = (const char *) out_doc->encoding;
6568 if (txt_encoding != NULL) {
6569 doc_charset = xmlParseCharEncoding(txt_encoding);
6570
6571 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6572 xmlGenericError(xmlGenericErrorContext,
6573 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6574 return;
6575
6576 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6577 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6578 if ( conv_hdlr == NULL ) {
6579 xmlGenericError(xmlGenericErrorContext,
6580 "%s: %s %s '%s'\n",
6581 "xmlDocDumpFormatMemoryEnc",
6582 "Failed to identify encoding handler for",
6583 "character set",
6584 txt_encoding);
6585 return;
6586 }
6587 }
6588 }
6589
6590 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6591 xmlGenericError(xmlGenericErrorContext,
6592 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6593 return;
6594 }
6595
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006596 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006597 xmlOutputBufferFlush(out_buff);
6598 if (out_buff->conv != NULL) {
6599 *doc_txt_len = out_buff->conv->use;
6600 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6601 } else {
6602 *doc_txt_len = out_buff->buffer->use;
6603 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6604 }
6605 (void)xmlOutputBufferClose(out_buff);
6606
6607 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6608 *doc_txt_len = 0;
6609 xmlGenericError(xmlGenericErrorContext,
6610 "xmlDocDumpFormatMemoryEnc: %s\n",
6611 "Failed to allocate memory for document text representation.");
6612 }
6613
6614 return;
6615}
6616
6617/**
6618 * xmlDocDumpMemory:
6619 * @cur: the document
6620 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006621 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006622 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006623 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006624 * It's up to the caller to free the memory.
6625 */
6626void
6627xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6628 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6629}
6630
6631/**
6632 * xmlDocDumpFormatMemory:
6633 * @cur: the document
6634 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006635 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006636 * @format: should formatting spaces been added
6637 *
6638 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006639 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006640 * It's up to the caller to free the memory.
6641 */
6642void
6643xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6644 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6645}
6646
6647/**
6648 * xmlDocDumpMemoryEnc:
6649 * @out_doc: Document to generate XML text from
6650 * @doc_txt_ptr: Memory pointer for allocated XML text
6651 * @doc_txt_len: Length of the generated XML text
6652 * @txt_encoding: Character encoding to use when generating XML text
6653 *
6654 * Dump the current DOM tree into memory using the character encoding specified
6655 * by the caller. Note it is up to the caller of this function to free the
6656 * allocated memory.
6657 */
6658
6659void
6660xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6661 int * doc_txt_len, const char * txt_encoding) {
6662 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006663 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006664}
6665
6666/**
6667 * xmlGetDocCompressMode:
6668 * @doc: the document
6669 *
6670 * get the compression ratio for a document, ZLIB based
6671 * Returns 0 (uncompressed) to 9 (max compression)
6672 */
6673int
6674xmlGetDocCompressMode (xmlDocPtr doc) {
6675 if (doc == NULL) return(-1);
6676 return(doc->compression);
6677}
6678
6679/**
6680 * xmlSetDocCompressMode:
6681 * @doc: the document
6682 * @mode: the compression ratio
6683 *
6684 * set the compression ratio for a document, ZLIB based
6685 * Correct values: 0 (uncompressed) to 9 (max compression)
6686 */
6687void
6688xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6689 if (doc == NULL) return;
6690 if (mode < 0) doc->compression = 0;
6691 else if (mode > 9) doc->compression = 9;
6692 else doc->compression = mode;
6693}
6694
6695/**
6696 * xmlGetCompressMode:
6697 *
6698 * get the default compression mode used, ZLIB based.
6699 * Returns 0 (uncompressed) to 9 (max compression)
6700 */
6701int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00006702xmlGetCompressMode(void)
6703{
6704 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00006705}
6706
6707/**
6708 * xmlSetCompressMode:
6709 * @mode: the compression ratio
6710 *
6711 * set the default compression mode used, ZLIB based
6712 * Correct values: 0 (uncompressed) to 9 (max compression)
6713 */
6714void
6715xmlSetCompressMode(int mode) {
6716 if (mode < 0) xmlCompressMode = 0;
6717 else if (mode > 9) xmlCompressMode = 9;
6718 else xmlCompressMode = mode;
6719}
6720
6721/**
6722 * xmlDocDump:
6723 * @f: the FILE*
6724 * @cur: the document
6725 *
6726 * Dump an XML document to an open FILE.
6727 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006728 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006729 */
6730int
6731xmlDocDump(FILE *f, xmlDocPtr cur) {
6732 xmlOutputBufferPtr buf;
6733 const char * encoding;
6734 xmlCharEncodingHandlerPtr handler = NULL;
6735 int ret;
6736
6737 if (cur == NULL) {
6738#ifdef DEBUG_TREE
6739 xmlGenericError(xmlGenericErrorContext,
6740 "xmlDocDump : document == NULL\n");
6741#endif
6742 return(-1);
6743 }
6744 encoding = (const char *) cur->encoding;
6745
6746 if (encoding != NULL) {
6747 xmlCharEncoding enc;
6748
6749 enc = xmlParseCharEncoding(encoding);
6750
6751 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6752 xmlGenericError(xmlGenericErrorContext,
6753 "xmlDocDump: document not in UTF8\n");
6754 return(-1);
6755 }
6756 if (enc != XML_CHAR_ENCODING_UTF8) {
6757 handler = xmlFindCharEncodingHandler(encoding);
6758 if (handler == NULL) {
6759 xmlFree((char *) cur->encoding);
6760 cur->encoding = NULL;
6761 }
6762 }
6763 }
6764 buf = xmlOutputBufferCreateFile(f, handler);
6765 if (buf == NULL) return(-1);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006766 xmlDocContentDumpOutput(buf, cur, NULL, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006767
6768 ret = xmlOutputBufferClose(buf);
6769 return(ret);
6770}
6771
6772/**
6773 * xmlSaveFileTo:
6774 * @buf: an output I/O buffer
6775 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00006776 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00006777 *
6778 * Dump an XML document to an I/O buffer.
6779 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006780 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006781 */
6782int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006783xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006784 int ret;
6785
6786 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006787 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006788 ret = xmlOutputBufferClose(buf);
6789 return(ret);
6790}
6791
6792/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00006793 * xmlSaveFormatFileTo:
6794 * @buf: an output I/O buffer
6795 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00006796 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00006797 * @format: should formatting spaces been added
6798 *
6799 * Dump an XML document to an I/O buffer.
6800 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006801 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00006802 */
6803int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006804xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00006805 int ret;
6806
6807 if (buf == NULL) return(0);
6808 xmlDocContentDumpOutput(buf, cur, encoding, format);
6809 ret = xmlOutputBufferClose(buf);
6810 return(ret);
6811}
6812
6813/**
Daniel Veillardf012a642001-07-23 19:10:52 +00006814 * xmlSaveFormatFileEnc
6815 * @filename: the filename or URL to output
6816 * @cur: the document being saved
6817 * @encoding: the name of the encoding to use or NULL.
6818 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00006819 *
6820 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00006821 */
6822int
Daniel Veillardf012a642001-07-23 19:10:52 +00006823xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
6824 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00006825 xmlOutputBufferPtr buf;
6826 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00006827 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00006828 int ret;
6829
Daniel Veillardfb25a512002-01-13 20:32:08 +00006830 if (encoding == NULL)
6831 encoding = (const char *) cur->encoding;
6832
Owen Taylor3473f882001-02-23 17:55:21 +00006833 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006834
6835 enc = xmlParseCharEncoding(encoding);
6836 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6837 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006838 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006839 return(-1);
6840 }
6841 if (enc != XML_CHAR_ENCODING_UTF8) {
6842 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00006843 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006844 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006845 }
6846 }
6847
Daniel Veillardf012a642001-07-23 19:10:52 +00006848#ifdef HAVE_ZLIB_H
6849 if (cur->compression < 0) cur->compression = xmlCompressMode;
6850#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006851 /*
6852 * save the content to a temp buffer.
6853 */
Daniel Veillardf012a642001-07-23 19:10:52 +00006854 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00006855 if (buf == NULL) return(-1);
6856
Daniel Veillardf012a642001-07-23 19:10:52 +00006857 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006858
6859 ret = xmlOutputBufferClose(buf);
6860 return(ret);
6861}
6862
Daniel Veillardf012a642001-07-23 19:10:52 +00006863
6864/**
6865 * xmlSaveFileEnc:
6866 * @filename: the filename (or URL)
6867 * @cur: the document
6868 * @encoding: the name of an encoding (or NULL)
6869 *
6870 * Dump an XML document, converting it to the given encoding
6871 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006872 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00006873 */
6874int
6875xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
6876 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
6877}
6878
Owen Taylor3473f882001-02-23 17:55:21 +00006879/**
Daniel Veillard67fee942001-04-26 18:59:03 +00006880 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00006881 * @filename: the filename (or URL)
6882 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00006883 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00006884 *
6885 * Dump an XML document to a file. Will use compression if
6886 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00006887 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00006888 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006889 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006890 */
6891int
Daniel Veillard67fee942001-04-26 18:59:03 +00006892xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006893 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00006894}
6895
Daniel Veillard67fee942001-04-26 18:59:03 +00006896/**
6897 * xmlSaveFile:
6898 * @filename: the filename (or URL)
6899 * @cur: the document
6900 *
6901 * Dump an XML document to a file. Will use compression if
6902 * compiled in and enabled. If @filename is "-" the stdout file is
6903 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00006904 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00006905 */
6906int
6907xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006908 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00006909}
6910