blob: 98b5b39ffafd1351ceb5371d3479ac92c1d5fb03 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00006 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00007 *
8 * 14 Nov 2000 ht - Changed the name of function xmlBufferWriteChar under VMS
9 * as it was similar to xmlBufferWriteCHAR when compiling without case
10 * sensitivity.
11 *
12 */
13
Bjorn Reese70a9da52001-04-21 16:57:29 +000014#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000015
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24#ifdef HAVE_ZLIB_H
25#include <zlib.h>
26#endif
27
28#include <libxml/xmlmemory.h>
29#include <libxml/tree.h>
30#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000031#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000032#include <libxml/entities.h>
33#include <libxml/valid.h>
34#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000035#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000036#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000037
Daniel Veillard56a4cb82001-03-24 17:00:36 +000038xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
39
40/************************************************************************
41 * *
42 * A few static variables and macros *
43 * *
44 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000045/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000046const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000047/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000048const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000049 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000050/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +000051const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
52
Owen Taylor3473f882001-02-23 17:55:21 +000053static int xmlCompressMode = 0;
54static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000055
Owen Taylor3473f882001-02-23 17:55:21 +000056#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
57 xmlNodePtr ulccur = (n)->children; \
58 if (ulccur == NULL) { \
59 (n)->last = NULL; \
60 } else { \
61 while (ulccur->next != NULL) { \
62 ulccur->parent = (n); \
63 ulccur = ulccur->next; \
64 } \
65 ulccur->parent = (n); \
66 (n)->last = ulccur; \
67}}
68
69/* #define DEBUG_BUFFER */
70/* #define DEBUG_TREE */
71
72/************************************************************************
73 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +000074 * Functions to move to entities.c once the *
75 * API freeze is smoothen and they can be made public. *
76 * *
77 ************************************************************************/
78#include <libxml/hash.h>
79
80/**
81 * xmlGetEntityFromDtd:
82 * @dtd: A pointer to the DTD to search
83 * @name: The entity name
84 *
85 * Do an entity lookup in the DTD entity hash table and
86 * return the corresponding entity, if found.
87 *
88 * Returns A pointer to the entity structure or NULL if not found.
89 */
90static xmlEntityPtr
91xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
92 xmlEntitiesTablePtr table;
93
94 if((dtd != NULL) && (dtd->entities != NULL)) {
95 table = (xmlEntitiesTablePtr) dtd->entities;
96 return((xmlEntityPtr) xmlHashLookup(table, name));
97 /* return(xmlGetEntityFromTable(table, name)); */
98 }
99 return(NULL);
100}
101/**
102 * xmlGetParameterEntityFromDtd:
103 * @dtd: A pointer to the DTD to search
104 * @name: The entity name
105 *
106 * Do an entity lookup in the DTD pararmeter entity hash table and
107 * return the corresponding entity, if found.
108 *
109 * Returns A pointer to the entity structure or NULL if not found.
110 */
111static xmlEntityPtr
112xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
113 xmlEntitiesTablePtr table;
114
115 if ((dtd != NULL) && (dtd->pentities != NULL)) {
116 table = (xmlEntitiesTablePtr) dtd->pentities;
117 return((xmlEntityPtr) xmlHashLookup(table, name));
118 /* return(xmlGetEntityFromTable(table, name)); */
119 }
120 return(NULL);
121}
122
123/************************************************************************
124 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000125 * Allocation and deallocation of basic structures *
126 * *
127 ************************************************************************/
128
129/**
130 * xmlSetBufferAllocationScheme:
131 * @scheme: allocation method to use
132 *
133 * Set the buffer allocation method. Types are
134 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
135 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
136 * improves performance
137 */
138void
139xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
140 xmlBufferAllocScheme = scheme;
141}
142
143/**
144 * xmlGetBufferAllocationScheme:
145 *
146 * Types are
147 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
148 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
149 * improves performance
150 *
151 * Returns the current allocation scheme
152 */
153xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000154xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000155 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000156}
157
158/**
159 * xmlNewNs:
160 * @node: the element carrying the namespace
161 * @href: the URI associated
162 * @prefix: the prefix for the namespace
163 *
164 * Creation of a new Namespace. This function will refuse to create
165 * a namespace with a similar prefix than an existing one present on this
166 * node.
167 * We use href==NULL in the case of an element creation where the namespace
168 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000169 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000170 */
171xmlNsPtr
172xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
173 xmlNsPtr cur;
174
175 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
176 return(NULL);
177
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000178 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
179 return(NULL);
180
Owen Taylor3473f882001-02-23 17:55:21 +0000181 /*
182 * Allocate a new Namespace and fill the fields.
183 */
184 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
185 if (cur == NULL) {
186 xmlGenericError(xmlGenericErrorContext,
187 "xmlNewNs : malloc failed\n");
188 return(NULL);
189 }
190 memset(cur, 0, sizeof(xmlNs));
191 cur->type = XML_LOCAL_NAMESPACE;
192
193 if (href != NULL)
194 cur->href = xmlStrdup(href);
195 if (prefix != NULL)
196 cur->prefix = xmlStrdup(prefix);
197
198 /*
199 * Add it at the end to preserve parsing order ...
200 * and checks for existing use of the prefix
201 */
202 if (node != NULL) {
203 if (node->nsDef == NULL) {
204 node->nsDef = cur;
205 } else {
206 xmlNsPtr prev = node->nsDef;
207
208 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
209 (xmlStrEqual(prev->prefix, cur->prefix))) {
210 xmlFreeNs(cur);
211 return(NULL);
212 }
213 while (prev->next != NULL) {
214 prev = prev->next;
215 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
216 (xmlStrEqual(prev->prefix, cur->prefix))) {
217 xmlFreeNs(cur);
218 return(NULL);
219 }
220 }
221 prev->next = cur;
222 }
223 }
224 return(cur);
225}
226
227/**
228 * xmlSetNs:
229 * @node: a node in the document
230 * @ns: a namespace pointer
231 *
232 * Associate a namespace to a node, a posteriori.
233 */
234void
235xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
236 if (node == NULL) {
237#ifdef DEBUG_TREE
238 xmlGenericError(xmlGenericErrorContext,
239 "xmlSetNs: node == NULL\n");
240#endif
241 return;
242 }
243 node->ns = ns;
244}
245
246/**
247 * xmlFreeNs:
248 * @cur: the namespace pointer
249 *
250 * Free up the structures associated to a namespace
251 */
252void
253xmlFreeNs(xmlNsPtr cur) {
254 if (cur == NULL) {
255#ifdef DEBUG_TREE
256 xmlGenericError(xmlGenericErrorContext,
257 "xmlFreeNs : ns == NULL\n");
258#endif
259 return;
260 }
261 if (cur->href != NULL) xmlFree((char *) cur->href);
262 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000263 xmlFree(cur);
264}
265
266/**
267 * xmlFreeNsList:
268 * @cur: the first namespace pointer
269 *
270 * Free up all the structures associated to the chained namespaces.
271 */
272void
273xmlFreeNsList(xmlNsPtr cur) {
274 xmlNsPtr next;
275 if (cur == NULL) {
276#ifdef DEBUG_TREE
277 xmlGenericError(xmlGenericErrorContext,
278 "xmlFreeNsList : ns == NULL\n");
279#endif
280 return;
281 }
282 while (cur != NULL) {
283 next = cur->next;
284 xmlFreeNs(cur);
285 cur = next;
286 }
287}
288
289/**
290 * xmlNewDtd:
291 * @doc: the document pointer
292 * @name: the DTD name
293 * @ExternalID: the external ID
294 * @SystemID: the system ID
295 *
296 * Creation of a new DTD for the external subset. To create an
297 * internal subset, use xmlCreateIntSubset().
298 *
299 * Returns a pointer to the new DTD structure
300 */
301xmlDtdPtr
302xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
303 const xmlChar *ExternalID, const xmlChar *SystemID) {
304 xmlDtdPtr cur;
305
306 if ((doc != NULL) && (doc->extSubset != NULL)) {
307#ifdef DEBUG_TREE
308 xmlGenericError(xmlGenericErrorContext,
309 "xmlNewDtd(%s): document %s already have a DTD %s\n",
310 /* !!! */ (char *) name, doc->name,
311 /* !!! */ (char *)doc->extSubset->name);
312#endif
313 return(NULL);
314 }
315
316 /*
317 * Allocate a new DTD and fill the fields.
318 */
319 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
320 if (cur == NULL) {
321 xmlGenericError(xmlGenericErrorContext,
322 "xmlNewDtd : malloc failed\n");
323 return(NULL);
324 }
325 memset(cur, 0 , sizeof(xmlDtd));
326 cur->type = XML_DTD_NODE;
327
328 if (name != NULL)
329 cur->name = xmlStrdup(name);
330 if (ExternalID != NULL)
331 cur->ExternalID = xmlStrdup(ExternalID);
332 if (SystemID != NULL)
333 cur->SystemID = xmlStrdup(SystemID);
334 if (doc != NULL)
335 doc->extSubset = cur;
336 cur->doc = doc;
337
338 return(cur);
339}
340
341/**
342 * xmlGetIntSubset:
343 * @doc: the document pointer
344 *
345 * Get the internal subset of a document
346 * Returns a pointer to the DTD structure or NULL if not found
347 */
348
349xmlDtdPtr
350xmlGetIntSubset(xmlDocPtr doc) {
351 xmlNodePtr cur;
352
353 if (doc == NULL)
354 return(NULL);
355 cur = doc->children;
356 while (cur != NULL) {
357 if (cur->type == XML_DTD_NODE)
358 return((xmlDtdPtr) cur);
359 cur = cur->next;
360 }
361 return((xmlDtdPtr) doc->intSubset);
362}
363
364/**
365 * xmlCreateIntSubset:
366 * @doc: the document pointer
367 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000368 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000369 * @SystemID: the system ID
370 *
371 * Create the internal subset of a document
372 * Returns a pointer to the new DTD structure
373 */
374xmlDtdPtr
375xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
376 const xmlChar *ExternalID, const xmlChar *SystemID) {
377 xmlDtdPtr cur;
378
379 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
380#ifdef DEBUG_TREE
381 xmlGenericError(xmlGenericErrorContext,
382
383 "xmlCreateIntSubset(): document %s already have an internal subset\n",
384 doc->name);
385#endif
386 return(NULL);
387 }
388
389 /*
390 * Allocate a new DTD and fill the fields.
391 */
392 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
393 if (cur == NULL) {
394 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000395 "xmlCreateIntSubset : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000396 return(NULL);
397 }
398 memset(cur, 0, sizeof(xmlDtd));
399 cur->type = XML_DTD_NODE;
400
401 if (name != NULL)
402 cur->name = xmlStrdup(name);
403 if (ExternalID != NULL)
404 cur->ExternalID = xmlStrdup(ExternalID);
405 if (SystemID != NULL)
406 cur->SystemID = xmlStrdup(SystemID);
407 if (doc != NULL) {
408 doc->intSubset = cur;
409 cur->parent = doc;
410 cur->doc = doc;
411 if (doc->children == NULL) {
412 doc->children = (xmlNodePtr) cur;
413 doc->last = (xmlNodePtr) cur;
414 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000415 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000416 xmlNodePtr prev;
417
Owen Taylor3473f882001-02-23 17:55:21 +0000418 prev = doc->children;
419 prev->prev = (xmlNodePtr) cur;
420 cur->next = prev;
421 doc->children = (xmlNodePtr) cur;
422 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000423 xmlNodePtr next;
424
425 next = doc->children;
426 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
427 next = next->next;
428 if (next == NULL) {
429 cur->prev = doc->last;
430 cur->prev->next = (xmlNodePtr) cur;
431 cur->next = NULL;
432 doc->last = (xmlNodePtr) cur;
433 } else {
434 cur->next = next;
435 cur->prev = next->prev;
436 if (cur->prev == NULL)
437 doc->children = (xmlNodePtr) cur;
438 else
439 cur->prev->next = (xmlNodePtr) cur;
440 next->prev = (xmlNodePtr) cur;
441 }
Owen Taylor3473f882001-02-23 17:55:21 +0000442 }
443 }
444 }
445 return(cur);
446}
447
448/**
449 * xmlFreeDtd:
450 * @cur: the DTD structure to free up
451 *
452 * Free a DTD structure.
453 */
454void
455xmlFreeDtd(xmlDtdPtr cur) {
456 if (cur == NULL) {
457#ifdef DEBUG_TREE
458 xmlGenericError(xmlGenericErrorContext,
459 "xmlFreeDtd : DTD == NULL\n");
460#endif
461 return;
462 }
463 if (cur->children != NULL) {
464 xmlNodePtr next, c = cur->children;
465
466 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000467 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000468 * indexes.
469 */
470 while (c != NULL) {
471 next = c->next;
472 if (c->type == XML_COMMENT_NODE) {
473 xmlUnlinkNode(c);
474 xmlFreeNode(c);
475 }
476 c = next;
477 }
478 }
479 if (cur->name != NULL) xmlFree((char *) cur->name);
480 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
481 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
482 /* TODO !!! */
483 if (cur->notations != NULL)
484 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
485
486 if (cur->elements != NULL)
487 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
488 if (cur->attributes != NULL)
489 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
490 if (cur->entities != NULL)
491 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
492 if (cur->pentities != NULL)
493 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
494
Owen Taylor3473f882001-02-23 17:55:21 +0000495 xmlFree(cur);
496}
497
498/**
499 * xmlNewDoc:
500 * @version: xmlChar string giving the version of XML "1.0"
501 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000502 * Creates a new XML document
503 *
Owen Taylor3473f882001-02-23 17:55:21 +0000504 * Returns a new document
505 */
506xmlDocPtr
507xmlNewDoc(const xmlChar *version) {
508 xmlDocPtr cur;
509
510 if (version == NULL)
511 version = (const xmlChar *) "1.0";
512
513 /*
514 * Allocate a new document and fill the fields.
515 */
516 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
517 if (cur == NULL) {
518 xmlGenericError(xmlGenericErrorContext,
519 "xmlNewDoc : malloc failed\n");
520 return(NULL);
521 }
522 memset(cur, 0, sizeof(xmlDoc));
523 cur->type = XML_DOCUMENT_NODE;
524
525 cur->version = xmlStrdup(version);
526 cur->standalone = -1;
527 cur->compression = -1; /* not initialized */
528 cur->doc = cur;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000529 cur->charset = XML_CHAR_ENCODING_UTF8;
Owen Taylor3473f882001-02-23 17:55:21 +0000530 return(cur);
531}
532
533/**
534 * xmlFreeDoc:
535 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +0000536 *
537 * Free up all the structures used by a document, tree included.
538 */
539void
540xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000541 xmlDtdPtr extSubset, intSubset;
542
Owen Taylor3473f882001-02-23 17:55:21 +0000543 if (cur == NULL) {
544#ifdef DEBUG_TREE
545 xmlGenericError(xmlGenericErrorContext,
546 "xmlFreeDoc : document == NULL\n");
547#endif
548 return;
549 }
Daniel Veillard76d66f42001-05-16 21:05:17 +0000550 /*
551 * Do this before freeing the children list to avoid ID lookups
552 */
553 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
554 cur->ids = NULL;
555 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
556 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000557 extSubset = cur->extSubset;
558 intSubset = cur->intSubset;
559 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000560 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000561 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000562 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000563 }
Daniel Veillarda9142e72001-06-19 11:07:54 +0000564 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000565 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000566 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000567 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000568 }
569
570 if (cur->children != NULL) xmlFreeNodeList(cur->children);
571
Owen Taylor3473f882001-02-23 17:55:21 +0000572 if (cur->version != NULL) xmlFree((char *) cur->version);
573 if (cur->name != NULL) xmlFree((char *) cur->name);
574 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +0000575 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +0000576 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000577 xmlFree(cur);
578}
579
580/**
581 * xmlStringLenGetNodeList:
582 * @doc: the document
583 * @value: the value of the text
584 * @len: the length of the string value
585 *
586 * Parse the value string and build the node list associated. Should
587 * produce a flat tree with only TEXTs and ENTITY_REFs.
588 * Returns a pointer to the first child
589 */
590xmlNodePtr
591xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
592 xmlNodePtr ret = NULL, last = NULL;
593 xmlNodePtr node;
594 xmlChar *val;
595 const xmlChar *cur = value;
596 const xmlChar *q;
597 xmlEntityPtr ent;
598
599 if (value == NULL) return(NULL);
600
601 q = cur;
602 while ((*cur != 0) && (cur - value < len)) {
603 if (*cur == '&') {
604 /*
605 * Save the current text.
606 */
607 if (cur != q) {
608 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
609 xmlNodeAddContentLen(last, q, cur - q);
610 } else {
611 node = xmlNewDocTextLen(doc, q, cur - q);
612 if (node == NULL) return(ret);
613 if (last == NULL)
614 last = ret = node;
615 else {
616 last->next = node;
617 node->prev = last;
618 last = node;
619 }
620 }
621 }
622 /*
623 * Read the entity string
624 */
625 cur++;
626 q = cur;
627 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
628 if ((*cur == 0) || (cur - value >= len)) {
629#ifdef DEBUG_TREE
630 xmlGenericError(xmlGenericErrorContext,
631 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
632#endif
633 return(ret);
634 }
635 if (cur != q) {
636 /*
637 * Predefined entities don't generate nodes
638 */
639 val = xmlStrndup(q, cur - q);
640 ent = xmlGetDocEntity(doc, val);
641 if ((ent != NULL) &&
642 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
643 if (last == NULL) {
644 node = xmlNewDocText(doc, ent->content);
645 last = ret = node;
646 } else
647 xmlNodeAddContent(last, ent->content);
648
649 } else {
650 /*
651 * Create a new REFERENCE_REF node
652 */
653 node = xmlNewReference(doc, val);
654 if (node == NULL) {
655 if (val != NULL) xmlFree(val);
656 return(ret);
657 }
658 if (last == NULL)
659 last = ret = node;
660 else {
661 last->next = node;
662 node->prev = last;
663 last = node;
664 }
665 }
666 xmlFree(val);
667 }
668 cur++;
669 q = cur;
670 } else
671 cur++;
672 }
673 if (cur != q) {
674 /*
675 * Handle the last piece of text.
676 */
677 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
678 xmlNodeAddContentLen(last, q, cur - q);
679 } else {
680 node = xmlNewDocTextLen(doc, q, cur - q);
681 if (node == NULL) return(ret);
682 if (last == NULL)
683 last = ret = node;
684 else {
685 last->next = node;
686 node->prev = last;
687 last = node;
688 }
689 }
690 }
691 return(ret);
692}
693
694/**
695 * xmlStringGetNodeList:
696 * @doc: the document
697 * @value: the value of the attribute
698 *
699 * Parse the value string and build the node list associated. Should
700 * produce a flat tree with only TEXTs and ENTITY_REFs.
701 * Returns a pointer to the first child
702 */
703xmlNodePtr
704xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
705 xmlNodePtr ret = NULL, last = NULL;
706 xmlNodePtr node;
707 xmlChar *val;
708 const xmlChar *cur = value;
709 const xmlChar *q;
710 xmlEntityPtr ent;
711
712 if (value == NULL) return(NULL);
713
714 q = cur;
715 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000716 if (cur[0] == '&') {
717 int charval = 0;
718 xmlChar tmp;
719
Owen Taylor3473f882001-02-23 17:55:21 +0000720 /*
721 * Save the current text.
722 */
723 if (cur != q) {
724 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
725 xmlNodeAddContentLen(last, q, cur - q);
726 } else {
727 node = xmlNewDocTextLen(doc, q, cur - q);
728 if (node == NULL) return(ret);
729 if (last == NULL)
730 last = ret = node;
731 else {
732 last->next = node;
733 node->prev = last;
734 last = node;
735 }
736 }
737 }
Owen Taylor3473f882001-02-23 17:55:21 +0000738 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000739 if ((cur[1] == '#') && (cur[2] == 'x')) {
740 cur += 3;
741 tmp = *cur;
742 while (tmp != ';') { /* Non input consuming loop */
743 if ((tmp >= '0') && (tmp <= '9'))
744 charval = charval * 16 + (tmp - '0');
745 else if ((tmp >= 'a') && (tmp <= 'f'))
746 charval = charval * 16 + (tmp - 'a') + 10;
747 else if ((tmp >= 'A') && (tmp <= 'F'))
748 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +0000749 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000750 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000751 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000752 charval = 0;
753 break;
754 }
755 cur++;
756 tmp = *cur;
757 }
758 if (tmp == ';')
759 cur++;
760 q = cur;
761 } else if (cur[1] == '#') {
762 cur += 2;
763 tmp = *cur;
764 while (tmp != ';') { /* Non input consuming loops */
765 if ((tmp >= '0') && (tmp <= '9'))
766 charval = charval * 10 + (tmp - '0');
767 else {
768 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000769 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000770 charval = 0;
771 break;
772 }
773 cur++;
774 tmp = *cur;
775 }
776 if (tmp == ';')
777 cur++;
778 q = cur;
779 } else {
780 /*
781 * Read the entity string
782 */
783 cur++;
784 q = cur;
785 while ((*cur != 0) && (*cur != ';')) cur++;
786 if (*cur == 0) {
787#ifdef DEBUG_TREE
788 xmlGenericError(xmlGenericErrorContext,
789 "xmlStringGetNodeList: unterminated entity %30s\n", q);
790#endif
791 return(ret);
792 }
793 if (cur != q) {
794 /*
795 * Predefined entities don't generate nodes
796 */
797 val = xmlStrndup(q, cur - q);
798 ent = xmlGetDocEntity(doc, val);
799 if ((ent != NULL) &&
800 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
801 if (last == NULL) {
802 node = xmlNewDocText(doc, ent->content);
803 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +0000804 } else if (last->type != XML_TEXT_NODE) {
805 node = xmlNewDocText(doc, ent->content);
806 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000807 } else
808 xmlNodeAddContent(last, ent->content);
809
810 } else {
811 /*
812 * Create a new REFERENCE_REF node
813 */
814 node = xmlNewReference(doc, val);
815 if (node == NULL) {
816 if (val != NULL) xmlFree(val);
817 return(ret);
818 }
819 if (last == NULL) {
820 last = ret = node;
821 } else {
822 last = xmlAddNextSibling(last, node);
823 }
824 }
825 xmlFree(val);
826 }
827 cur++;
828 q = cur;
829 }
830 if (charval != 0) {
831 xmlChar buf[10];
832 int len;
833
834 len = xmlCopyCharMultiByte(buf, charval);
835 buf[len] = 0;
836 node = xmlNewDocText(doc, buf);
837 if (node != NULL) {
838 if (last == NULL) {
839 last = ret = node;
840 } else {
841 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000842 }
843 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000844
845 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000846 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000847 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000848 cur++;
849 }
Daniel Veillard75bea542001-05-11 17:41:21 +0000850 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000851 /*
852 * Handle the last piece of text.
853 */
854 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
855 xmlNodeAddContentLen(last, q, cur - q);
856 } else {
857 node = xmlNewDocTextLen(doc, q, cur - q);
858 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000859 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000860 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000861 } else {
862 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000863 }
864 }
865 }
866 return(ret);
867}
868
869/**
870 * xmlNodeListGetString:
871 * @doc: the document
872 * @list: a Node list
873 * @inLine: should we replace entity contents or show their external form
874 *
875 * Returns the string equivalent to the text contained in the Node list
876 * made of TEXTs and ENTITY_REFs
Daniel Veillardd1640922001-12-17 15:30:10 +0000877 * Returns a pointer to the string copy, the caller must free it.
Owen Taylor3473f882001-02-23 17:55:21 +0000878 */
879xmlChar *
880xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
881 xmlNodePtr node = list;
882 xmlChar *ret = NULL;
883 xmlEntityPtr ent;
884
885 if (list == NULL) return(NULL);
886
887 while (node != NULL) {
888 if ((node->type == XML_TEXT_NODE) ||
889 (node->type == XML_CDATA_SECTION_NODE)) {
890 if (inLine) {
Owen Taylor3473f882001-02-23 17:55:21 +0000891 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000892 } else {
893 xmlChar *buffer;
894
Owen Taylor3473f882001-02-23 17:55:21 +0000895 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000896 if (buffer != NULL) {
897 ret = xmlStrcat(ret, buffer);
898 xmlFree(buffer);
899 }
900 }
901 } else if (node->type == XML_ENTITY_REF_NODE) {
902 if (inLine) {
903 ent = xmlGetDocEntity(doc, node->name);
904 if (ent != NULL)
905 ret = xmlStrcat(ret, ent->content);
906 else {
Owen Taylor3473f882001-02-23 17:55:21 +0000907 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000908 }
909 } else {
910 xmlChar buf[2];
911 buf[0] = '&'; buf[1] = 0;
912 ret = xmlStrncat(ret, buf, 1);
913 ret = xmlStrcat(ret, node->name);
914 buf[0] = ';'; buf[1] = 0;
915 ret = xmlStrncat(ret, buf, 1);
916 }
917 }
918#if 0
919 else {
920 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000921 "xmlGetNodeListString : invalid node type %d\n",
Owen Taylor3473f882001-02-23 17:55:21 +0000922 node->type);
923 }
924#endif
925 node = node->next;
926 }
927 return(ret);
928}
929
930/**
931 * xmlNodeListGetRawString:
932 * @doc: the document
933 * @list: a Node list
934 * @inLine: should we replace entity contents or show their external form
935 *
936 * Returns the string equivalent to the text contained in the Node list
937 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
938 * this function doesn't do any character encoding handling.
939 *
Daniel Veillardd1640922001-12-17 15:30:10 +0000940 * Returns a pointer to the string copy, the caller must free it.
Owen Taylor3473f882001-02-23 17:55:21 +0000941 */
942xmlChar *
943xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
944 xmlNodePtr node = list;
945 xmlChar *ret = NULL;
946 xmlEntityPtr ent;
947
948 if (list == NULL) return(NULL);
949
950 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +0000951 if ((node->type == XML_TEXT_NODE) ||
952 (node->type == XML_CDATA_SECTION_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000953 if (inLine) {
Owen Taylor3473f882001-02-23 17:55:21 +0000954 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000955 } else {
956 xmlChar *buffer;
957
Owen Taylor3473f882001-02-23 17:55:21 +0000958 buffer = xmlEncodeSpecialChars(doc, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000959 if (buffer != NULL) {
960 ret = xmlStrcat(ret, buffer);
961 xmlFree(buffer);
962 }
963 }
964 } else if (node->type == XML_ENTITY_REF_NODE) {
965 if (inLine) {
966 ent = xmlGetDocEntity(doc, node->name);
967 if (ent != NULL)
968 ret = xmlStrcat(ret, ent->content);
969 else {
Owen Taylor3473f882001-02-23 17:55:21 +0000970 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000971 }
972 } else {
973 xmlChar buf[2];
974 buf[0] = '&'; buf[1] = 0;
975 ret = xmlStrncat(ret, buf, 1);
976 ret = xmlStrcat(ret, node->name);
977 buf[0] = ';'; buf[1] = 0;
978 ret = xmlStrncat(ret, buf, 1);
979 }
980 }
981#if 0
982 else {
983 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000984 "xmlGetNodeListString : invalid node type %d\n",
Owen Taylor3473f882001-02-23 17:55:21 +0000985 node->type);
986 }
987#endif
988 node = node->next;
989 }
990 return(ret);
991}
992
993/**
994 * xmlNewProp:
995 * @node: the holding node
996 * @name: the name of the attribute
997 * @value: the value of the attribute
998 *
999 * Create a new property carried by a node.
1000 * Returns a pointer to the attribute
1001 */
1002xmlAttrPtr
1003xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1004 xmlAttrPtr cur;
1005 xmlDocPtr doc = NULL;
1006
1007 if (name == NULL) {
1008#ifdef DEBUG_TREE
1009 xmlGenericError(xmlGenericErrorContext,
1010 "xmlNewProp : name == NULL\n");
1011#endif
1012 return(NULL);
1013 }
1014
1015 /*
1016 * Allocate a new property and fill the fields.
1017 */
1018 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1019 if (cur == NULL) {
1020 xmlGenericError(xmlGenericErrorContext,
1021 "xmlNewProp : malloc failed\n");
1022 return(NULL);
1023 }
1024 memset(cur, 0, sizeof(xmlAttr));
1025 cur->type = XML_ATTRIBUTE_NODE;
1026
1027 cur->parent = node;
1028 if (node != NULL) {
1029 doc = node->doc;
1030 cur->doc = doc;
1031 }
1032 cur->name = xmlStrdup(name);
1033 if (value != NULL) {
1034 xmlChar *buffer;
1035 xmlNodePtr tmp;
1036
1037 buffer = xmlEncodeEntitiesReentrant(doc, value);
1038 cur->children = xmlStringGetNodeList(doc, buffer);
1039 cur->last = NULL;
1040 tmp = cur->children;
1041 while (tmp != NULL) {
1042 tmp->parent = (xmlNodePtr) cur;
1043 tmp->doc = doc;
1044 if (tmp->next == NULL)
1045 cur->last = tmp;
1046 tmp = tmp->next;
1047 }
1048 xmlFree(buffer);
1049 }
1050
1051 /*
1052 * Add it at the end to preserve parsing order ...
1053 */
1054 if (node != NULL) {
1055 if (node->properties == NULL) {
1056 node->properties = cur;
1057 } else {
1058 xmlAttrPtr prev = node->properties;
1059
1060 while (prev->next != NULL) prev = prev->next;
1061 prev->next = cur;
1062 cur->prev = prev;
1063 }
1064 }
1065 return(cur);
1066}
1067
1068/**
1069 * xmlNewNsProp:
1070 * @node: the holding node
1071 * @ns: the namespace
1072 * @name: the name of the attribute
1073 * @value: the value of the attribute
1074 *
1075 * Create a new property tagged with a namespace and carried by a node.
1076 * Returns a pointer to the attribute
1077 */
1078xmlAttrPtr
1079xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1080 const xmlChar *value) {
1081 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001082 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001083
1084 if (name == NULL) {
1085#ifdef DEBUG_TREE
1086 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001087 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001088#endif
1089 return(NULL);
1090 }
1091
1092 /*
1093 * Allocate a new property and fill the fields.
1094 */
1095 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1096 if (cur == NULL) {
1097 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001098 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001099 return(NULL);
1100 }
1101 memset(cur, 0, sizeof(xmlAttr));
1102 cur->type = XML_ATTRIBUTE_NODE;
1103
1104 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001105 if (node != NULL) {
1106 doc = node->doc;
1107 cur->doc = doc;
1108 }
Owen Taylor3473f882001-02-23 17:55:21 +00001109 cur->ns = ns;
1110 cur->name = xmlStrdup(name);
1111 if (value != NULL) {
1112 xmlChar *buffer;
1113 xmlNodePtr tmp;
1114
Daniel Veillarda682b212001-06-07 19:59:42 +00001115 buffer = xmlEncodeEntitiesReentrant(doc, value);
1116 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001117 cur->last = NULL;
1118 tmp = cur->children;
1119 while (tmp != NULL) {
1120 tmp->parent = (xmlNodePtr) cur;
1121 if (tmp->next == NULL)
1122 cur->last = tmp;
1123 tmp = tmp->next;
1124 }
1125 xmlFree(buffer);
1126 }
1127
1128 /*
1129 * Add it at the end to preserve parsing order ...
1130 */
1131 if (node != NULL) {
1132 if (node->properties == NULL) {
1133 node->properties = cur;
1134 } else {
1135 xmlAttrPtr prev = node->properties;
1136
1137 while (prev->next != NULL) prev = prev->next;
1138 prev->next = cur;
1139 cur->prev = prev;
1140 }
1141 }
1142 return(cur);
1143}
1144
1145/**
1146 * xmlNewDocProp:
1147 * @doc: the document
1148 * @name: the name of the attribute
1149 * @value: the value of the attribute
1150 *
1151 * Create a new property carried by a document.
1152 * Returns a pointer to the attribute
1153 */
1154xmlAttrPtr
1155xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1156 xmlAttrPtr cur;
1157
1158 if (name == NULL) {
1159#ifdef DEBUG_TREE
1160 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001161 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001162#endif
1163 return(NULL);
1164 }
1165
1166 /*
1167 * Allocate a new property and fill the fields.
1168 */
1169 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1170 if (cur == NULL) {
1171 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001172 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001173 return(NULL);
1174 }
1175 memset(cur, 0, sizeof(xmlAttr));
1176 cur->type = XML_ATTRIBUTE_NODE;
1177
1178 cur->name = xmlStrdup(name);
1179 cur->doc = doc;
1180 if (value != NULL) {
1181 xmlNodePtr tmp;
1182
1183 cur->children = xmlStringGetNodeList(doc, value);
1184 cur->last = NULL;
1185
1186 tmp = cur->children;
1187 while (tmp != NULL) {
1188 tmp->parent = (xmlNodePtr) cur;
1189 if (tmp->next == NULL)
1190 cur->last = tmp;
1191 tmp = tmp->next;
1192 }
1193 }
1194 return(cur);
1195}
1196
1197/**
1198 * xmlFreePropList:
1199 * @cur: the first property in the list
1200 *
1201 * Free a property and all its siblings, all the children are freed too.
1202 */
1203void
1204xmlFreePropList(xmlAttrPtr cur) {
1205 xmlAttrPtr next;
1206 if (cur == NULL) {
1207#ifdef DEBUG_TREE
1208 xmlGenericError(xmlGenericErrorContext,
1209 "xmlFreePropList : property == NULL\n");
1210#endif
1211 return;
1212 }
1213 while (cur != NULL) {
1214 next = cur->next;
1215 xmlFreeProp(cur);
1216 cur = next;
1217 }
1218}
1219
1220/**
1221 * xmlFreeProp:
1222 * @cur: an attribute
1223 *
1224 * Free one attribute, all the content is freed too
1225 */
1226void
1227xmlFreeProp(xmlAttrPtr cur) {
1228 if (cur == NULL) {
1229#ifdef DEBUG_TREE
1230 xmlGenericError(xmlGenericErrorContext,
1231 "xmlFreeProp : property == NULL\n");
1232#endif
1233 return;
1234 }
1235 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001236 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1237 ((cur->parent->doc->intSubset != NULL) ||
1238 (cur->parent->doc->extSubset != NULL))) {
1239 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1240 xmlRemoveID(cur->parent->doc, cur);
1241 }
Owen Taylor3473f882001-02-23 17:55:21 +00001242 if (cur->name != NULL) xmlFree((char *) cur->name);
1243 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001244 xmlFree(cur);
1245}
1246
1247/**
1248 * xmlRemoveProp:
1249 * @cur: an attribute
1250 *
1251 * Unlink and free one attribute, all the content is freed too
1252 * Note this doesn't work for namespace definition attributes
1253 *
1254 * Returns 0 if success and -1 in case of error.
1255 */
1256int
1257xmlRemoveProp(xmlAttrPtr cur) {
1258 xmlAttrPtr tmp;
1259 if (cur == NULL) {
1260#ifdef DEBUG_TREE
1261 xmlGenericError(xmlGenericErrorContext,
1262 "xmlRemoveProp : cur == NULL\n");
1263#endif
1264 return(-1);
1265 }
1266 if (cur->parent == NULL) {
1267#ifdef DEBUG_TREE
1268 xmlGenericError(xmlGenericErrorContext,
1269 "xmlRemoveProp : cur->parent == NULL\n");
1270#endif
1271 return(-1);
1272 }
1273 tmp = cur->parent->properties;
1274 if (tmp == cur) {
1275 cur->parent->properties = cur->next;
1276 xmlFreeProp(cur);
1277 return(0);
1278 }
1279 while (tmp != NULL) {
1280 if (tmp->next == cur) {
1281 tmp->next = cur->next;
1282 if (tmp->next != NULL)
1283 tmp->next->prev = tmp;
1284 xmlFreeProp(cur);
1285 return(0);
1286 }
1287 tmp = tmp->next;
1288 }
1289#ifdef DEBUG_TREE
1290 xmlGenericError(xmlGenericErrorContext,
1291 "xmlRemoveProp : attribute not owned by its node\n");
1292#endif
1293 return(-1);
1294}
1295
1296/**
1297 * xmlNewPI:
1298 * @name: the processing instruction name
1299 * @content: the PI content
1300 *
1301 * Creation of a processing instruction element.
1302 * Returns a pointer to the new node object.
1303 */
1304xmlNodePtr
1305xmlNewPI(const xmlChar *name, const xmlChar *content) {
1306 xmlNodePtr cur;
1307
1308 if (name == NULL) {
1309#ifdef DEBUG_TREE
1310 xmlGenericError(xmlGenericErrorContext,
1311 "xmlNewPI : name == NULL\n");
1312#endif
1313 return(NULL);
1314 }
1315
1316 /*
1317 * Allocate a new node and fill the fields.
1318 */
1319 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1320 if (cur == NULL) {
1321 xmlGenericError(xmlGenericErrorContext,
1322 "xmlNewPI : malloc failed\n");
1323 return(NULL);
1324 }
1325 memset(cur, 0, sizeof(xmlNode));
1326 cur->type = XML_PI_NODE;
1327
1328 cur->name = xmlStrdup(name);
1329 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001330 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001331 }
1332 return(cur);
1333}
1334
1335/**
1336 * xmlNewNode:
1337 * @ns: namespace if any
1338 * @name: the node name
1339 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001340 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001341 *
1342 * Returns a pointer to the new node object.
1343 */
1344xmlNodePtr
1345xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1346 xmlNodePtr cur;
1347
1348 if (name == NULL) {
1349#ifdef DEBUG_TREE
1350 xmlGenericError(xmlGenericErrorContext,
1351 "xmlNewNode : name == NULL\n");
1352#endif
1353 return(NULL);
1354 }
1355
1356 /*
1357 * Allocate a new node and fill the fields.
1358 */
1359 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1360 if (cur == NULL) {
1361 xmlGenericError(xmlGenericErrorContext,
1362 "xmlNewNode : malloc failed\n");
1363 return(NULL);
1364 }
1365 memset(cur, 0, sizeof(xmlNode));
1366 cur->type = XML_ELEMENT_NODE;
1367
1368 cur->name = xmlStrdup(name);
1369 cur->ns = ns;
1370 return(cur);
1371}
1372
1373/**
1374 * xmlNewDocNode:
1375 * @doc: the document
1376 * @ns: namespace if any
1377 * @name: the node name
1378 * @content: the XML text content if any
1379 *
1380 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001381 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001382 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1383 * references, but XML special chars need to be escaped first by using
1384 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1385 * need entities support.
1386 *
1387 * Returns a pointer to the new node object.
1388 */
1389xmlNodePtr
1390xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1391 const xmlChar *name, const xmlChar *content) {
1392 xmlNodePtr cur;
1393
1394 cur = xmlNewNode(ns, name);
1395 if (cur != NULL) {
1396 cur->doc = doc;
1397 if (content != NULL) {
1398 cur->children = xmlStringGetNodeList(doc, content);
1399 UPDATE_LAST_CHILD_AND_PARENT(cur)
1400 }
1401 }
1402 return(cur);
1403}
1404
1405
1406/**
1407 * xmlNewDocRawNode:
1408 * @doc: the document
1409 * @ns: namespace if any
1410 * @name: the node name
1411 * @content: the text content if any
1412 *
1413 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001414 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001415 *
1416 * Returns a pointer to the new node object.
1417 */
1418xmlNodePtr
1419xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1420 const xmlChar *name, const xmlChar *content) {
1421 xmlNodePtr cur;
1422
1423 cur = xmlNewNode(ns, name);
1424 if (cur != NULL) {
1425 cur->doc = doc;
1426 if (content != NULL) {
1427 cur->children = xmlNewDocText(doc, content);
1428 UPDATE_LAST_CHILD_AND_PARENT(cur)
1429 }
1430 }
1431 return(cur);
1432}
1433
1434/**
1435 * xmlNewDocFragment:
1436 * @doc: the document owning the fragment
1437 *
1438 * Creation of a new Fragment node.
1439 * Returns a pointer to the new node object.
1440 */
1441xmlNodePtr
1442xmlNewDocFragment(xmlDocPtr doc) {
1443 xmlNodePtr cur;
1444
1445 /*
1446 * Allocate a new DocumentFragment node and fill the fields.
1447 */
1448 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1449 if (cur == NULL) {
1450 xmlGenericError(xmlGenericErrorContext,
1451 "xmlNewDocFragment : malloc failed\n");
1452 return(NULL);
1453 }
1454 memset(cur, 0, sizeof(xmlNode));
1455 cur->type = XML_DOCUMENT_FRAG_NODE;
1456
1457 cur->doc = doc;
1458 return(cur);
1459}
1460
1461/**
1462 * xmlNewText:
1463 * @content: the text content
1464 *
1465 * Creation of a new text node.
1466 * Returns a pointer to the new node object.
1467 */
1468xmlNodePtr
1469xmlNewText(const xmlChar *content) {
1470 xmlNodePtr cur;
1471
1472 /*
1473 * Allocate a new node and fill the fields.
1474 */
1475 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1476 if (cur == NULL) {
1477 xmlGenericError(xmlGenericErrorContext,
1478 "xmlNewText : malloc failed\n");
1479 return(NULL);
1480 }
1481 memset(cur, 0, sizeof(xmlNode));
1482 cur->type = XML_TEXT_NODE;
1483
1484 cur->name = xmlStringText;
1485 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001486 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001487 }
1488 return(cur);
1489}
1490
1491/**
1492 * xmlNewTextChild:
1493 * @parent: the parent node
1494 * @ns: a namespace if any
1495 * @name: the name of the child
1496 * @content: the text content of the child if any.
1497 *
1498 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001499 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001500 * a child TEXT node will be created containing the string content.
1501 *
1502 * Returns a pointer to the new node object.
1503 */
1504xmlNodePtr
1505xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1506 const xmlChar *name, const xmlChar *content) {
1507 xmlNodePtr cur, prev;
1508
1509 if (parent == NULL) {
1510#ifdef DEBUG_TREE
1511 xmlGenericError(xmlGenericErrorContext,
1512 "xmlNewTextChild : parent == NULL\n");
1513#endif
1514 return(NULL);
1515 }
1516
1517 if (name == NULL) {
1518#ifdef DEBUG_TREE
1519 xmlGenericError(xmlGenericErrorContext,
1520 "xmlNewTextChild : name == NULL\n");
1521#endif
1522 return(NULL);
1523 }
1524
1525 /*
1526 * Allocate a new node
1527 */
1528 if (ns == NULL)
1529 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1530 else
1531 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1532 if (cur == NULL) return(NULL);
1533
1534 /*
1535 * add the new element at the end of the children list.
1536 */
1537 cur->type = XML_ELEMENT_NODE;
1538 cur->parent = parent;
1539 cur->doc = parent->doc;
1540 if (parent->children == NULL) {
1541 parent->children = cur;
1542 parent->last = cur;
1543 } else {
1544 prev = parent->last;
1545 prev->next = cur;
1546 cur->prev = prev;
1547 parent->last = cur;
1548 }
1549
1550 return(cur);
1551}
1552
1553/**
1554 * xmlNewCharRef:
1555 * @doc: the document
1556 * @name: the char ref string, starting with # or "&# ... ;"
1557 *
1558 * Creation of a new character reference node.
1559 * Returns a pointer to the new node object.
1560 */
1561xmlNodePtr
1562xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1563 xmlNodePtr cur;
1564
1565 /*
1566 * Allocate a new node and fill the fields.
1567 */
1568 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1569 if (cur == NULL) {
1570 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001571 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001572 return(NULL);
1573 }
1574 memset(cur, 0, sizeof(xmlNode));
1575 cur->type = XML_ENTITY_REF_NODE;
1576
1577 cur->doc = doc;
1578 if (name[0] == '&') {
1579 int len;
1580 name++;
1581 len = xmlStrlen(name);
1582 if (name[len - 1] == ';')
1583 cur->name = xmlStrndup(name, len - 1);
1584 else
1585 cur->name = xmlStrndup(name, len);
1586 } else
1587 cur->name = xmlStrdup(name);
1588 return(cur);
1589}
1590
1591/**
1592 * xmlNewReference:
1593 * @doc: the document
1594 * @name: the reference name, or the reference string with & and ;
1595 *
1596 * Creation of a new reference node.
1597 * Returns a pointer to the new node object.
1598 */
1599xmlNodePtr
1600xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1601 xmlNodePtr cur;
1602 xmlEntityPtr ent;
1603
1604 /*
1605 * Allocate a new node and fill the fields.
1606 */
1607 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1608 if (cur == NULL) {
1609 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001610 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001611 return(NULL);
1612 }
1613 memset(cur, 0, sizeof(xmlNode));
1614 cur->type = XML_ENTITY_REF_NODE;
1615
1616 cur->doc = doc;
1617 if (name[0] == '&') {
1618 int len;
1619 name++;
1620 len = xmlStrlen(name);
1621 if (name[len - 1] == ';')
1622 cur->name = xmlStrndup(name, len - 1);
1623 else
1624 cur->name = xmlStrndup(name, len);
1625 } else
1626 cur->name = xmlStrdup(name);
1627
1628 ent = xmlGetDocEntity(doc, cur->name);
1629 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001630 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00001631 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001632 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00001633 * updated. Not sure if this is 100% correct.
1634 * -George
1635 */
1636 cur->children = (xmlNodePtr) ent;
1637 cur->last = (xmlNodePtr) ent;
1638 }
1639 return(cur);
1640}
1641
1642/**
1643 * xmlNewDocText:
1644 * @doc: the document
1645 * @content: the text content
1646 *
1647 * Creation of a new text node within a document.
1648 * Returns a pointer to the new node object.
1649 */
1650xmlNodePtr
1651xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1652 xmlNodePtr cur;
1653
1654 cur = xmlNewText(content);
1655 if (cur != NULL) cur->doc = doc;
1656 return(cur);
1657}
1658
1659/**
1660 * xmlNewTextLen:
1661 * @content: the text content
1662 * @len: the text len.
1663 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001664 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00001665 * Returns a pointer to the new node object.
1666 */
1667xmlNodePtr
1668xmlNewTextLen(const xmlChar *content, int len) {
1669 xmlNodePtr cur;
1670
1671 /*
1672 * Allocate a new node and fill the fields.
1673 */
1674 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1675 if (cur == NULL) {
1676 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001677 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001678 return(NULL);
1679 }
1680 memset(cur, 0, sizeof(xmlNode));
1681 cur->type = XML_TEXT_NODE;
1682
1683 cur->name = xmlStringText;
1684 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001685 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001686 }
1687 return(cur);
1688}
1689
1690/**
1691 * xmlNewDocTextLen:
1692 * @doc: the document
1693 * @content: the text content
1694 * @len: the text len.
1695 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001696 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00001697 * text node pertain to a given document.
1698 * Returns a pointer to the new node object.
1699 */
1700xmlNodePtr
1701xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1702 xmlNodePtr cur;
1703
1704 cur = xmlNewTextLen(content, len);
1705 if (cur != NULL) cur->doc = doc;
1706 return(cur);
1707}
1708
1709/**
1710 * xmlNewComment:
1711 * @content: the comment content
1712 *
1713 * Creation of a new node containing a comment.
1714 * Returns a pointer to the new node object.
1715 */
1716xmlNodePtr
1717xmlNewComment(const xmlChar *content) {
1718 xmlNodePtr cur;
1719
1720 /*
1721 * Allocate a new node and fill the fields.
1722 */
1723 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1724 if (cur == NULL) {
1725 xmlGenericError(xmlGenericErrorContext,
1726 "xmlNewComment : malloc failed\n");
1727 return(NULL);
1728 }
1729 memset(cur, 0, sizeof(xmlNode));
1730 cur->type = XML_COMMENT_NODE;
1731
1732 cur->name = xmlStringComment;
1733 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001734 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001735 }
1736 return(cur);
1737}
1738
1739/**
1740 * xmlNewCDataBlock:
1741 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00001742 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00001743 * @len: the length of the block
1744 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001745 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00001746 * Returns a pointer to the new node object.
1747 */
1748xmlNodePtr
1749xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1750 xmlNodePtr cur;
1751
1752 /*
1753 * Allocate a new node and fill the fields.
1754 */
1755 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1756 if (cur == NULL) {
1757 xmlGenericError(xmlGenericErrorContext,
1758 "xmlNewCDataBlock : malloc failed\n");
1759 return(NULL);
1760 }
1761 memset(cur, 0, sizeof(xmlNode));
1762 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001763 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001764
1765 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001766 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001767 }
1768 return(cur);
1769}
1770
1771/**
1772 * xmlNewDocComment:
1773 * @doc: the document
1774 * @content: the comment content
1775 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001776 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00001777 * Returns a pointer to the new node object.
1778 */
1779xmlNodePtr
1780xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1781 xmlNodePtr cur;
1782
1783 cur = xmlNewComment(content);
1784 if (cur != NULL) cur->doc = doc;
1785 return(cur);
1786}
1787
1788/**
1789 * xmlSetTreeDoc:
1790 * @tree: the top element
1791 * @doc: the document
1792 *
1793 * update all nodes under the tree to point to the right document
1794 */
1795void
1796xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00001797 xmlAttrPtr prop;
1798
Owen Taylor3473f882001-02-23 17:55:21 +00001799 if (tree == NULL)
1800 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001801 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00001802 if(tree->type == XML_ELEMENT_NODE) {
1803 prop = tree->properties;
1804 while (prop != NULL) {
1805 prop->doc = doc;
1806 xmlSetListDoc(prop->children, doc);
1807 prop = prop->next;
1808 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00001809 }
Owen Taylor3473f882001-02-23 17:55:21 +00001810 if (tree->children != NULL)
1811 xmlSetListDoc(tree->children, doc);
1812 tree->doc = doc;
1813 }
1814}
1815
1816/**
1817 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00001818 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00001819 * @doc: the document
1820 *
1821 * update all nodes in the list to point to the right document
1822 */
1823void
1824xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
1825 xmlNodePtr cur;
1826
1827 if (list == NULL)
1828 return;
1829 cur = list;
1830 while (cur != NULL) {
1831 if (cur->doc != doc)
1832 xmlSetTreeDoc(cur, doc);
1833 cur = cur->next;
1834 }
1835}
1836
1837
1838/**
1839 * xmlNewChild:
1840 * @parent: the parent node
1841 * @ns: a namespace if any
1842 * @name: the name of the child
1843 * @content: the XML content of the child if any.
1844 *
1845 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001846 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001847 * a child list containing the TEXTs and ENTITY_REFs node will be created.
1848 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1849 * references, but XML special chars need to be escaped first by using
1850 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
1851 * support is not needed.
1852 *
1853 * Returns a pointer to the new node object.
1854 */
1855xmlNodePtr
1856xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
1857 const xmlChar *name, const xmlChar *content) {
1858 xmlNodePtr cur, prev;
1859
1860 if (parent == NULL) {
1861#ifdef DEBUG_TREE
1862 xmlGenericError(xmlGenericErrorContext,
1863 "xmlNewChild : parent == NULL\n");
1864#endif
1865 return(NULL);
1866 }
1867
1868 if (name == NULL) {
1869#ifdef DEBUG_TREE
1870 xmlGenericError(xmlGenericErrorContext,
1871 "xmlNewChild : name == NULL\n");
1872#endif
1873 return(NULL);
1874 }
1875
1876 /*
1877 * Allocate a new node
1878 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00001879 if (parent->type == XML_ELEMENT_NODE) {
1880 if (ns == NULL)
1881 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
1882 else
1883 cur = xmlNewDocNode(parent->doc, ns, name, content);
1884 } else if ((parent->type == XML_DOCUMENT_NODE) ||
1885 (parent->type == XML_HTML_DOCUMENT_NODE)) {
1886 if (ns == NULL)
1887 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
1888 else
1889 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
1890 } else {
1891 return(NULL);
1892 }
Owen Taylor3473f882001-02-23 17:55:21 +00001893 if (cur == NULL) return(NULL);
1894
1895 /*
1896 * add the new element at the end of the children list.
1897 */
1898 cur->type = XML_ELEMENT_NODE;
1899 cur->parent = parent;
1900 cur->doc = parent->doc;
1901 if (parent->children == NULL) {
1902 parent->children = cur;
1903 parent->last = cur;
1904 } else {
1905 prev = parent->last;
1906 prev->next = cur;
1907 cur->prev = prev;
1908 parent->last = cur;
1909 }
1910
1911 return(cur);
1912}
1913
1914/**
1915 * xmlAddNextSibling:
1916 * @cur: the child node
1917 * @elem: the new node
1918 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001919 * Add a new node @elem as the next sibling of @cur
1920 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00001921 * first unlinked from its existing context.
1922 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001923 * If the new node is ATTRIBUTE, it is added into properties instead of children.
1924 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00001925 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001926 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001927 */
1928xmlNodePtr
1929xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
1930 if (cur == NULL) {
1931#ifdef DEBUG_TREE
1932 xmlGenericError(xmlGenericErrorContext,
1933 "xmlAddNextSibling : cur == NULL\n");
1934#endif
1935 return(NULL);
1936 }
1937 if (elem == NULL) {
1938#ifdef DEBUG_TREE
1939 xmlGenericError(xmlGenericErrorContext,
1940 "xmlAddNextSibling : elem == NULL\n");
1941#endif
1942 return(NULL);
1943 }
1944
1945 xmlUnlinkNode(elem);
1946
1947 if (elem->type == XML_TEXT_NODE) {
1948 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00001949 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001950 xmlFreeNode(elem);
1951 return(cur);
1952 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00001953 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
1954 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001955 xmlChar *tmp;
1956
1957 tmp = xmlStrdup(elem->content);
1958 tmp = xmlStrcat(tmp, cur->next->content);
1959 xmlNodeSetContent(cur->next, tmp);
1960 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00001961 xmlFreeNode(elem);
1962 return(cur->next);
1963 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001964 } else if (elem->type == XML_ATTRIBUTE_NODE) {
1965 /* check if an attribute with the same name exists */
1966 xmlAttrPtr attr;
1967
1968 if (elem->ns == NULL)
1969 attr = xmlHasProp(cur->parent, elem->name);
1970 else
1971 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
1972 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
1973 /* different instance, destroy it (attributes must be unique) */
1974 xmlFreeProp(attr);
1975 }
Owen Taylor3473f882001-02-23 17:55:21 +00001976 }
1977
1978 if (elem->doc != cur->doc) {
1979 xmlSetTreeDoc(elem, cur->doc);
1980 }
1981 elem->parent = cur->parent;
1982 elem->prev = cur;
1983 elem->next = cur->next;
1984 cur->next = elem;
1985 if (elem->next != NULL)
1986 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001987 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00001988 elem->parent->last = elem;
1989 return(elem);
1990}
1991
1992/**
1993 * xmlAddPrevSibling:
1994 * @cur: the child node
1995 * @elem: the new node
1996 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001997 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00001998 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001999 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002000 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002001 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2002 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002003 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002004 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002005 */
2006xmlNodePtr
2007xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2008 if (cur == NULL) {
2009#ifdef DEBUG_TREE
2010 xmlGenericError(xmlGenericErrorContext,
2011 "xmlAddPrevSibling : cur == NULL\n");
2012#endif
2013 return(NULL);
2014 }
2015 if (elem == NULL) {
2016#ifdef DEBUG_TREE
2017 xmlGenericError(xmlGenericErrorContext,
2018 "xmlAddPrevSibling : elem == NULL\n");
2019#endif
2020 return(NULL);
2021 }
2022
2023 xmlUnlinkNode(elem);
2024
2025 if (elem->type == XML_TEXT_NODE) {
2026 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002027 xmlChar *tmp;
2028
2029 tmp = xmlStrdup(elem->content);
2030 tmp = xmlStrcat(tmp, cur->content);
2031 xmlNodeSetContent(cur, tmp);
2032 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002033 xmlFreeNode(elem);
2034 return(cur);
2035 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002036 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2037 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002038 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002039 xmlFreeNode(elem);
2040 return(cur->prev);
2041 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002042 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2043 /* check if an attribute with the same name exists */
2044 xmlAttrPtr attr;
2045
2046 if (elem->ns == NULL)
2047 attr = xmlHasProp(cur->parent, elem->name);
2048 else
2049 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2050 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2051 /* different instance, destroy it (attributes must be unique) */
2052 xmlFreeProp(attr);
2053 }
Owen Taylor3473f882001-02-23 17:55:21 +00002054 }
2055
2056 if (elem->doc != cur->doc) {
2057 xmlSetTreeDoc(elem, cur->doc);
2058 }
2059 elem->parent = cur->parent;
2060 elem->next = cur;
2061 elem->prev = cur->prev;
2062 cur->prev = elem;
2063 if (elem->prev != NULL)
2064 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002065 if (elem->parent != NULL) {
2066 if (elem->type == XML_ATTRIBUTE_NODE) {
2067 if (elem->parent->properties == (xmlAttrPtr) cur) {
2068 elem->parent->properties = (xmlAttrPtr) elem;
2069 }
2070 } else {
2071 if (elem->parent->children == cur) {
2072 elem->parent->children = elem;
2073 }
2074 }
2075 }
Owen Taylor3473f882001-02-23 17:55:21 +00002076 return(elem);
2077}
2078
2079/**
2080 * xmlAddSibling:
2081 * @cur: the child node
2082 * @elem: the new node
2083 *
2084 * Add a new element @elem to the list of siblings of @cur
2085 * merging adjacent TEXT nodes (@elem may be freed)
2086 * If the new element was already inserted in a document it is
2087 * first unlinked from its existing context.
2088 *
2089 * Returns the new element or NULL in case of error.
2090 */
2091xmlNodePtr
2092xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2093 xmlNodePtr parent;
2094
2095 if (cur == NULL) {
2096#ifdef DEBUG_TREE
2097 xmlGenericError(xmlGenericErrorContext,
2098 "xmlAddSibling : cur == NULL\n");
2099#endif
2100 return(NULL);
2101 }
2102
2103 if (elem == NULL) {
2104#ifdef DEBUG_TREE
2105 xmlGenericError(xmlGenericErrorContext,
2106 "xmlAddSibling : elem == NULL\n");
2107#endif
2108 return(NULL);
2109 }
2110
2111 /*
2112 * Constant time is we can rely on the ->parent->last to find
2113 * the last sibling.
2114 */
2115 if ((cur->parent != NULL) &&
2116 (cur->parent->children != NULL) &&
2117 (cur->parent->last != NULL) &&
2118 (cur->parent->last->next == NULL)) {
2119 cur = cur->parent->last;
2120 } else {
2121 while (cur->next != NULL) cur = cur->next;
2122 }
2123
2124 xmlUnlinkNode(elem);
2125
2126 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002127 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002128 xmlFreeNode(elem);
2129 return(cur);
2130 }
2131
2132 if (elem->doc != cur->doc) {
2133 xmlSetTreeDoc(elem, cur->doc);
2134 }
2135 parent = cur->parent;
2136 elem->prev = cur;
2137 elem->next = NULL;
2138 elem->parent = parent;
2139 cur->next = elem;
2140 if (parent != NULL)
2141 parent->last = elem;
2142
2143 return(elem);
2144}
2145
2146/**
2147 * xmlAddChildList:
2148 * @parent: the parent node
2149 * @cur: the first node in the list
2150 *
2151 * Add a list of node at the end of the child list of the parent
2152 * merging adjacent TEXT nodes (@cur may be freed)
2153 *
2154 * Returns the last child or NULL in case of error.
2155 */
2156xmlNodePtr
2157xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2158 xmlNodePtr prev;
2159
2160 if (parent == NULL) {
2161#ifdef DEBUG_TREE
2162 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002163 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002164#endif
2165 return(NULL);
2166 }
2167
2168 if (cur == NULL) {
2169#ifdef DEBUG_TREE
2170 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002171 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002172#endif
2173 return(NULL);
2174 }
2175
2176 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2177 (cur->doc != parent->doc)) {
2178#ifdef DEBUG_TREE
2179 xmlGenericError(xmlGenericErrorContext,
2180 "Elements moved to a different document\n");
2181#endif
2182 }
2183
2184 /*
2185 * add the first element at the end of the children list.
2186 */
2187 if (parent->children == NULL) {
2188 parent->children = cur;
2189 } else {
2190 /*
2191 * If cur and parent->last both are TEXT nodes, then merge them.
2192 */
2193 if ((cur->type == XML_TEXT_NODE) &&
2194 (parent->last->type == XML_TEXT_NODE) &&
2195 (cur->name == parent->last->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002196 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002197 /*
2198 * if it's the only child, nothing more to be done.
2199 */
2200 if (cur->next == NULL) {
2201 xmlFreeNode(cur);
2202 return(parent->last);
2203 }
2204 prev = cur;
2205 cur = cur->next;
2206 xmlFreeNode(prev);
2207 }
2208 prev = parent->last;
2209 prev->next = cur;
2210 cur->prev = prev;
2211 }
2212 while (cur->next != NULL) {
2213 cur->parent = parent;
2214 if (cur->doc != parent->doc) {
2215 xmlSetTreeDoc(cur, parent->doc);
2216 }
2217 cur = cur->next;
2218 }
2219 cur->parent = parent;
2220 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2221 parent->last = cur;
2222
2223 return(cur);
2224}
2225
2226/**
2227 * xmlAddChild:
2228 * @parent: the parent node
2229 * @cur: the child node
2230 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002231 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002232 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002233 * If the new node was already inserted in a document it is
2234 * first unlinked from its existing context.
2235 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2236 * If there is an attribute with equal name, it is first destroyed.
2237 *
Owen Taylor3473f882001-02-23 17:55:21 +00002238 * Returns the child or NULL in case of error.
2239 */
2240xmlNodePtr
2241xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2242 xmlNodePtr prev;
2243
2244 if (parent == NULL) {
2245#ifdef DEBUG_TREE
2246 xmlGenericError(xmlGenericErrorContext,
2247 "xmlAddChild : parent == NULL\n");
2248#endif
2249 return(NULL);
2250 }
2251
2252 if (cur == NULL) {
2253#ifdef DEBUG_TREE
2254 xmlGenericError(xmlGenericErrorContext,
2255 "xmlAddChild : child == NULL\n");
2256#endif
2257 return(NULL);
2258 }
2259
Owen Taylor3473f882001-02-23 17:55:21 +00002260 /*
2261 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002262 * cur is then freed.
2263 */
2264 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002265 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002266 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002267 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002268 xmlFreeNode(cur);
2269 return(parent);
2270 }
2271 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2272 (parent->last->name == cur->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002273 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002274 xmlFreeNode(cur);
2275 return(parent->last);
2276 }
2277 }
2278
2279 /*
2280 * add the new element at the end of the children list.
2281 */
2282 cur->parent = parent;
2283 if (cur->doc != parent->doc) {
2284 xmlSetTreeDoc(cur, parent->doc);
2285 }
2286
2287 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002288 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002289 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002290 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002291 (parent->content != NULL)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002292 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002293 xmlFreeNode(cur);
2294 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002295 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002296 if (cur->type == XML_ATTRIBUTE_NODE) {
2297 if (parent->properties == NULL) {
2298 parent->properties = (xmlAttrPtr) cur;
2299 } else {
2300 /* check if an attribute with the same name exists */
2301 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002302
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002303 if (cur->ns == NULL)
2304 lastattr = xmlHasProp(parent, cur->name);
2305 else
2306 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2307 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2308 /* different instance, destroy it (attributes must be unique) */
2309 xmlFreeProp(lastattr);
2310 }
2311 /* find the end */
2312 lastattr = parent->properties;
2313 while (lastattr->next != NULL) {
2314 lastattr = lastattr->next;
2315 }
2316 lastattr->next = (xmlAttrPtr) cur;
2317 ((xmlAttrPtr) cur)->prev = lastattr;
2318 }
2319 } else {
2320 if (parent->children == NULL) {
2321 parent->children = cur;
2322 parent->last = cur;
2323 } else {
2324 prev = parent->last;
2325 prev->next = cur;
2326 cur->prev = prev;
2327 parent->last = cur;
2328 }
2329 }
Owen Taylor3473f882001-02-23 17:55:21 +00002330 return(cur);
2331}
2332
2333/**
2334 * xmlGetLastChild:
2335 * @parent: the parent node
2336 *
2337 * Search the last child of a node.
2338 * Returns the last child or NULL if none.
2339 */
2340xmlNodePtr
2341xmlGetLastChild(xmlNodePtr parent) {
2342 if (parent == NULL) {
2343#ifdef DEBUG_TREE
2344 xmlGenericError(xmlGenericErrorContext,
2345 "xmlGetLastChild : parent == NULL\n");
2346#endif
2347 return(NULL);
2348 }
2349 return(parent->last);
2350}
2351
2352/**
2353 * xmlFreeNodeList:
2354 * @cur: the first node in the list
2355 *
2356 * Free a node and all its siblings, this is a recursive behaviour, all
2357 * the children are freed too.
2358 */
2359void
2360xmlFreeNodeList(xmlNodePtr cur) {
2361 xmlNodePtr next;
2362 if (cur == NULL) {
2363#ifdef DEBUG_TREE
2364 xmlGenericError(xmlGenericErrorContext,
2365 "xmlFreeNodeList : node == NULL\n");
2366#endif
2367 return;
2368 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002369 if (cur->type == XML_NAMESPACE_DECL) {
2370 xmlFreeNsList((xmlNsPtr) cur);
2371 return;
2372 }
Owen Taylor3473f882001-02-23 17:55:21 +00002373 while (cur != NULL) {
2374 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002375 /* unroll to speed up freeing the document */
2376 if (cur->type != XML_DTD_NODE) {
2377 if ((cur->children != NULL) &&
2378 (cur->type != XML_ENTITY_REF_NODE))
2379 xmlFreeNodeList(cur->children);
2380 if (cur->properties != NULL)
2381 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002382 if ((cur->type != XML_ELEMENT_NODE) &&
2383 (cur->type != XML_XINCLUDE_START) &&
2384 (cur->type != XML_XINCLUDE_END) &&
2385 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002386 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002387 }
2388 if (((cur->type == XML_ELEMENT_NODE) ||
2389 (cur->type == XML_XINCLUDE_START) ||
2390 (cur->type == XML_XINCLUDE_END)) &&
2391 (cur->nsDef != NULL))
2392 xmlFreeNsList(cur->nsDef);
2393
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002394 /*
2395 * When a node is a text node or a comment, it uses a global static
2396 * variable for the name of the node.
2397 *
2398 * The xmlStrEqual comparisons need to be done when (happened with
2399 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002400 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002401 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002402 * the string addresses compare are not sufficient.
2403 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002404 if ((cur->name != NULL) &&
2405 (cur->name != xmlStringText) &&
2406 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002407 (cur->name != xmlStringComment)) {
2408 if (cur->type == XML_TEXT_NODE) {
2409 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2410 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2411 xmlFree((char *) cur->name);
2412 } else if (cur->type == XML_COMMENT_NODE) {
2413 if (!xmlStrEqual(cur->name, xmlStringComment))
2414 xmlFree((char *) cur->name);
2415 } else
2416 xmlFree((char *) cur->name);
2417 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002418 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002419 xmlFree(cur);
2420 }
Owen Taylor3473f882001-02-23 17:55:21 +00002421 cur = next;
2422 }
2423}
2424
2425/**
2426 * xmlFreeNode:
2427 * @cur: the node
2428 *
2429 * Free a node, this is a recursive behaviour, all the children are freed too.
2430 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2431 */
2432void
2433xmlFreeNode(xmlNodePtr cur) {
2434 if (cur == NULL) {
2435#ifdef DEBUG_TREE
2436 xmlGenericError(xmlGenericErrorContext,
2437 "xmlFreeNode : node == NULL\n");
2438#endif
2439 return;
2440 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002441 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002442 if (cur->type == XML_DTD_NODE) {
2443 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002444 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002445 }
2446 if (cur->type == XML_NAMESPACE_DECL) {
2447 xmlFreeNs((xmlNsPtr) cur);
2448 return;
2449 }
Owen Taylor3473f882001-02-23 17:55:21 +00002450 if ((cur->children != NULL) &&
2451 (cur->type != XML_ENTITY_REF_NODE))
2452 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002453 if (cur->properties != NULL)
2454 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002455 if ((cur->type != XML_ELEMENT_NODE) &&
2456 (cur->content != NULL) &&
2457 (cur->type != XML_ENTITY_REF_NODE) &&
2458 (cur->type != XML_XINCLUDE_END) &&
2459 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002460 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002461 }
2462
Daniel Veillardacd370f2001-06-09 17:17:51 +00002463 /*
2464 * When a node is a text node or a comment, it uses a global static
2465 * variable for the name of the node.
2466 *
2467 * The xmlStrEqual comparisons need to be done when (happened with
2468 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002469 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002470 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002471 * are not sufficient.
2472 */
Owen Taylor3473f882001-02-23 17:55:21 +00002473 if ((cur->name != NULL) &&
2474 (cur->name != xmlStringText) &&
2475 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002476 (cur->name != xmlStringComment)) {
2477 if (cur->type == XML_TEXT_NODE) {
2478 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2479 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2480 xmlFree((char *) cur->name);
2481 } else if (cur->type == XML_COMMENT_NODE) {
2482 if (!xmlStrEqual(cur->name, xmlStringComment))
2483 xmlFree((char *) cur->name);
2484 } else
2485 xmlFree((char *) cur->name);
2486 }
2487
Owen Taylor3473f882001-02-23 17:55:21 +00002488 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002489 xmlFree(cur);
2490}
2491
2492/**
2493 * xmlUnlinkNode:
2494 * @cur: the node
2495 *
2496 * Unlink a node from it's current context, the node is not freed
2497 */
2498void
2499xmlUnlinkNode(xmlNodePtr cur) {
2500 if (cur == NULL) {
2501#ifdef DEBUG_TREE
2502 xmlGenericError(xmlGenericErrorContext,
2503 "xmlUnlinkNode : node == NULL\n");
2504#endif
2505 return;
2506 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002507 if (cur->type == XML_DTD_NODE) {
2508 xmlDocPtr doc;
2509 doc = cur->doc;
2510 if (doc->intSubset == (xmlDtdPtr) cur)
2511 doc->intSubset = NULL;
2512 if (doc->extSubset == (xmlDtdPtr) cur)
2513 doc->extSubset = NULL;
2514 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002515 if (cur->parent != NULL) {
2516 xmlNodePtr parent;
2517 parent = cur->parent;
2518 if (cur->type == XML_ATTRIBUTE_NODE) {
2519 if (parent->properties == (xmlAttrPtr) cur)
2520 parent->properties = ((xmlAttrPtr) cur)->next;
2521 } else {
2522 if (parent->children == cur)
2523 parent->children = cur->next;
2524 if (parent->last == cur)
2525 parent->last = cur->prev;
2526 }
2527 cur->parent = NULL;
2528 }
Owen Taylor3473f882001-02-23 17:55:21 +00002529 if (cur->next != NULL)
2530 cur->next->prev = cur->prev;
2531 if (cur->prev != NULL)
2532 cur->prev->next = cur->next;
2533 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002534}
2535
2536/**
2537 * xmlReplaceNode:
2538 * @old: the old node
2539 * @cur: the node
2540 *
2541 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002542 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002543 * first unlinked from its existing context.
2544 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002545 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002546 */
2547xmlNodePtr
2548xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2549 if (old == NULL) {
2550#ifdef DEBUG_TREE
2551 xmlGenericError(xmlGenericErrorContext,
2552 "xmlReplaceNode : old == NULL\n");
2553#endif
2554 return(NULL);
2555 }
2556 if (cur == NULL) {
2557 xmlUnlinkNode(old);
2558 return(old);
2559 }
2560 if (cur == old) {
2561 return(old);
2562 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002563 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2564#ifdef DEBUG_TREE
2565 xmlGenericError(xmlGenericErrorContext,
2566 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2567#endif
2568 return(old);
2569 }
2570 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2571#ifdef DEBUG_TREE
2572 xmlGenericError(xmlGenericErrorContext,
2573 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2574#endif
2575 return(old);
2576 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002577 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2578#ifdef DEBUG_TREE
2579 xmlGenericError(xmlGenericErrorContext,
2580 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2581#endif
2582 return(old);
2583 }
2584 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2585#ifdef DEBUG_TREE
2586 xmlGenericError(xmlGenericErrorContext,
2587 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2588#endif
2589 return(old);
2590 }
Owen Taylor3473f882001-02-23 17:55:21 +00002591 xmlUnlinkNode(cur);
2592 cur->doc = old->doc;
2593 cur->parent = old->parent;
2594 cur->next = old->next;
2595 if (cur->next != NULL)
2596 cur->next->prev = cur;
2597 cur->prev = old->prev;
2598 if (cur->prev != NULL)
2599 cur->prev->next = cur;
2600 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002601 if (cur->type == XML_ATTRIBUTE_NODE) {
2602 if (cur->parent->properties == (xmlAttrPtr)old)
2603 cur->parent->properties = ((xmlAttrPtr) cur);
2604 } else {
2605 if (cur->parent->children == old)
2606 cur->parent->children = cur;
2607 if (cur->parent->last == old)
2608 cur->parent->last = cur;
2609 }
Owen Taylor3473f882001-02-23 17:55:21 +00002610 }
2611 old->next = old->prev = NULL;
2612 old->parent = NULL;
2613 return(old);
2614}
2615
2616/************************************************************************
2617 * *
2618 * Copy operations *
2619 * *
2620 ************************************************************************/
2621
2622/**
2623 * xmlCopyNamespace:
2624 * @cur: the namespace
2625 *
2626 * Do a copy of the namespace.
2627 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002628 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002629 */
2630xmlNsPtr
2631xmlCopyNamespace(xmlNsPtr cur) {
2632 xmlNsPtr ret;
2633
2634 if (cur == NULL) return(NULL);
2635 switch (cur->type) {
2636 case XML_LOCAL_NAMESPACE:
2637 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2638 break;
2639 default:
2640#ifdef DEBUG_TREE
2641 xmlGenericError(xmlGenericErrorContext,
2642 "xmlCopyNamespace: invalid type %d\n", cur->type);
2643#endif
2644 return(NULL);
2645 }
2646 return(ret);
2647}
2648
2649/**
2650 * xmlCopyNamespaceList:
2651 * @cur: the first namespace
2652 *
2653 * Do a copy of an namespace list.
2654 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002655 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002656 */
2657xmlNsPtr
2658xmlCopyNamespaceList(xmlNsPtr cur) {
2659 xmlNsPtr ret = NULL;
2660 xmlNsPtr p = NULL,q;
2661
2662 while (cur != NULL) {
2663 q = xmlCopyNamespace(cur);
2664 if (p == NULL) {
2665 ret = p = q;
2666 } else {
2667 p->next = q;
2668 p = q;
2669 }
2670 cur = cur->next;
2671 }
2672 return(ret);
2673}
2674
2675static xmlNodePtr
2676xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2677/**
2678 * xmlCopyProp:
2679 * @target: the element where the attribute will be grafted
2680 * @cur: the attribute
2681 *
2682 * Do a copy of the attribute.
2683 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002684 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002685 */
2686xmlAttrPtr
2687xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2688 xmlAttrPtr ret;
2689
2690 if (cur == NULL) return(NULL);
2691 if (target != NULL)
2692 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2693 else if (cur->parent != NULL)
2694 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2695 else if (cur->children != NULL)
2696 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2697 else
2698 ret = xmlNewDocProp(NULL, cur->name, NULL);
2699 if (ret == NULL) return(NULL);
2700 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002701
Owen Taylor3473f882001-02-23 17:55:21 +00002702 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00002703 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002704/*
2705 * if (target->doc)
2706 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2707 * else if (cur->doc) / * target may not yet have a doc : KPI * /
2708 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
2709 * else
2710 * ns = NULL;
2711 * ret->ns = ns;
2712 */
2713 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2714 if (ns == NULL) {
2715 /*
2716 * Humm, we are copying an element whose namespace is defined
2717 * out of the new tree scope. Search it in the original tree
2718 * and add it at the top of the new tree
2719 */
2720 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
2721 if (ns != NULL) {
2722 xmlNodePtr root = target;
2723 xmlNodePtr pred = NULL;
2724
2725 while (root->parent != NULL) {
2726 pred = root;
2727 root = root->parent;
2728 }
2729 if (root == (xmlNodePtr) target->doc) {
2730 /* correct possibly cycling above the document elt */
2731 root = pred;
2732 }
2733 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
2734 }
2735 } else {
2736 /*
2737 * we have to find something appropriate here since
2738 * we cant be sure, that the namespce we found is identified
2739 * by the prefix
2740 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002741 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002742 /* this is the nice case */
2743 ret->ns = ns;
2744 } else {
2745 /*
2746 * we are in trouble: we need a new reconcilied namespace.
2747 * This is expensive
2748 */
2749 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
2750 }
2751 }
2752
Owen Taylor3473f882001-02-23 17:55:21 +00002753 } else
2754 ret->ns = NULL;
2755
2756 if (cur->children != NULL) {
2757 xmlNodePtr tmp;
2758
2759 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2760 ret->last = NULL;
2761 tmp = ret->children;
2762 while (tmp != NULL) {
2763 /* tmp->parent = (xmlNodePtr)ret; */
2764 if (tmp->next == NULL)
2765 ret->last = tmp;
2766 tmp = tmp->next;
2767 }
2768 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002769 /*
2770 * Try to handle IDs
2771 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00002772 if ((target!= NULL) && (cur!= NULL) &&
2773 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002774 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
2775 if (xmlIsID(cur->doc, cur->parent, cur)) {
2776 xmlChar *id;
2777
2778 id = xmlNodeListGetString(cur->doc, cur->children, 1);
2779 if (id != NULL) {
2780 xmlAddID(NULL, target->doc, id, ret);
2781 xmlFree(id);
2782 }
2783 }
2784 }
Owen Taylor3473f882001-02-23 17:55:21 +00002785 return(ret);
2786}
2787
2788/**
2789 * xmlCopyPropList:
2790 * @target: the element where the attributes will be grafted
2791 * @cur: the first attribute
2792 *
2793 * Do a copy of an attribute list.
2794 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002795 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002796 */
2797xmlAttrPtr
2798xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
2799 xmlAttrPtr ret = NULL;
2800 xmlAttrPtr p = NULL,q;
2801
2802 while (cur != NULL) {
2803 q = xmlCopyProp(target, cur);
2804 if (p == NULL) {
2805 ret = p = q;
2806 } else {
2807 p->next = q;
2808 q->prev = p;
2809 p = q;
2810 }
2811 cur = cur->next;
2812 }
2813 return(ret);
2814}
2815
2816/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002817 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00002818 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002819 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00002820 * tricky reason: namespaces. Doing a direct copy of a node
2821 * say RPM:Copyright without changing the namespace pointer to
2822 * something else can produce stale links. One way to do it is
2823 * to keep a reference counter but this doesn't work as soon
2824 * as one move the element or the subtree out of the scope of
2825 * the existing namespace. The actual solution seems to add
2826 * a copy of the namespace at the top of the copied tree if
2827 * not available in the subtree.
2828 * Hence two functions, the public front-end call the inner ones
2829 */
2830
2831static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002832xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00002833 int recursive) {
2834 xmlNodePtr ret;
2835
2836 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00002837 switch (node->type) {
2838 case XML_TEXT_NODE:
2839 case XML_CDATA_SECTION_NODE:
2840 case XML_ELEMENT_NODE:
2841 case XML_ENTITY_REF_NODE:
2842 case XML_ENTITY_NODE:
2843 case XML_PI_NODE:
2844 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002845 case XML_XINCLUDE_START:
2846 case XML_XINCLUDE_END:
2847 break;
2848 case XML_ATTRIBUTE_NODE:
2849 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
2850 case XML_NAMESPACE_DECL:
2851 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
2852
Daniel Veillard39196eb2001-06-19 18:09:42 +00002853 case XML_DOCUMENT_NODE:
2854 case XML_HTML_DOCUMENT_NODE:
2855#ifdef LIBXML_DOCB_ENABLED
2856 case XML_DOCB_DOCUMENT_NODE:
2857#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002858 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00002859 case XML_DOCUMENT_TYPE_NODE:
2860 case XML_DOCUMENT_FRAG_NODE:
2861 case XML_NOTATION_NODE:
2862 case XML_DTD_NODE:
2863 case XML_ELEMENT_DECL:
2864 case XML_ATTRIBUTE_DECL:
2865 case XML_ENTITY_DECL:
2866 return(NULL);
2867 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002868
Owen Taylor3473f882001-02-23 17:55:21 +00002869 /*
2870 * Allocate a new node and fill the fields.
2871 */
2872 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2873 if (ret == NULL) {
2874 xmlGenericError(xmlGenericErrorContext,
2875 "xmlStaticCopyNode : malloc failed\n");
2876 return(NULL);
2877 }
2878 memset(ret, 0, sizeof(xmlNode));
2879 ret->type = node->type;
2880
2881 ret->doc = doc;
2882 ret->parent = parent;
2883 if (node->name == xmlStringText)
2884 ret->name = xmlStringText;
2885 else if (node->name == xmlStringTextNoenc)
2886 ret->name = xmlStringTextNoenc;
2887 else if (node->name == xmlStringComment)
2888 ret->name = xmlStringComment;
2889 else if (node->name != NULL)
2890 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00002891 if ((node->type != XML_ELEMENT_NODE) &&
2892 (node->content != NULL) &&
2893 (node->type != XML_ENTITY_REF_NODE) &&
2894 (node->type != XML_XINCLUDE_END) &&
2895 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002896 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00002897 }else{
2898 if (node->type == XML_ELEMENT_NODE)
2899 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002900 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00002901 if (parent != NULL) {
2902 xmlNodePtr tmp;
2903
2904 tmp = xmlAddChild(parent, ret);
2905 /* node could have coalesced */
2906 if (tmp != ret)
2907 return(tmp);
2908 }
Owen Taylor3473f882001-02-23 17:55:21 +00002909
2910 if (!recursive) return(ret);
2911 if (node->nsDef != NULL)
2912 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2913
2914 if (node->ns != NULL) {
2915 xmlNsPtr ns;
2916
2917 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2918 if (ns == NULL) {
2919 /*
2920 * Humm, we are copying an element whose namespace is defined
2921 * out of the new tree scope. Search it in the original tree
2922 * and add it at the top of the new tree
2923 */
2924 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2925 if (ns != NULL) {
2926 xmlNodePtr root = ret;
2927
2928 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00002929 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002930 }
2931 } else {
2932 /*
2933 * reference the existing namespace definition in our own tree.
2934 */
2935 ret->ns = ns;
2936 }
2937 }
2938 if (node->properties != NULL)
2939 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002940 if (node->type == XML_ENTITY_REF_NODE) {
2941 if ((doc == NULL) || (node->doc != doc)) {
2942 /*
2943 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00002944 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00002945 * we cannot keep the reference. Try to find it in the
2946 * target document.
2947 */
2948 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
2949 } else {
2950 ret->children = node->children;
2951 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00002952 ret->last = ret->children;
2953 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002954 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00002955 UPDATE_LAST_CHILD_AND_PARENT(ret)
2956 }
Owen Taylor3473f882001-02-23 17:55:21 +00002957 return(ret);
2958}
2959
2960static xmlNodePtr
2961xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2962 xmlNodePtr ret = NULL;
2963 xmlNodePtr p = NULL,q;
2964
2965 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002966 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00002967 if (doc == NULL) {
2968 node = node->next;
2969 continue;
2970 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002971 if (doc->intSubset == NULL) {
2972 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
2973 q->doc = doc;
2974 q->parent = parent;
2975 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00002976 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002977 } else {
2978 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00002979 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002980 }
2981 } else
2982 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002983 if (ret == NULL) {
2984 q->prev = NULL;
2985 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00002986 } else if (p != q) {
2987 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00002988 p->next = q;
2989 q->prev = p;
2990 p = q;
2991 }
2992 node = node->next;
2993 }
2994 return(ret);
2995}
2996
2997/**
2998 * xmlCopyNode:
2999 * @node: the node
3000 * @recursive: if 1 do a recursive copy.
3001 *
3002 * Do a copy of the node.
3003 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003004 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003005 */
3006xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003007xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003008 xmlNodePtr ret;
3009
3010 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3011 return(ret);
3012}
3013
3014/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003015 * xmlDocCopyNode:
3016 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003017 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003018 * @recursive: if 1 do a recursive copy.
3019 *
3020 * Do a copy of the node to a given document.
3021 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003022 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003023 */
3024xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003025xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003026 xmlNodePtr ret;
3027
3028 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3029 return(ret);
3030}
3031
3032/**
Owen Taylor3473f882001-02-23 17:55:21 +00003033 * xmlCopyNodeList:
3034 * @node: the first node in the list.
3035 *
3036 * Do a recursive copy of the node list.
3037 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003038 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003039 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003040xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003041 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3042 return(ret);
3043}
3044
3045/**
Owen Taylor3473f882001-02-23 17:55:21 +00003046 * xmlCopyDtd:
3047 * @dtd: the dtd
3048 *
3049 * Do a copy of the dtd.
3050 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003051 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003052 */
3053xmlDtdPtr
3054xmlCopyDtd(xmlDtdPtr dtd) {
3055 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003056 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003057
3058 if (dtd == NULL) return(NULL);
3059 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3060 if (ret == NULL) return(NULL);
3061 if (dtd->entities != NULL)
3062 ret->entities = (void *) xmlCopyEntitiesTable(
3063 (xmlEntitiesTablePtr) dtd->entities);
3064 if (dtd->notations != NULL)
3065 ret->notations = (void *) xmlCopyNotationTable(
3066 (xmlNotationTablePtr) dtd->notations);
3067 if (dtd->elements != NULL)
3068 ret->elements = (void *) xmlCopyElementTable(
3069 (xmlElementTablePtr) dtd->elements);
3070 if (dtd->attributes != NULL)
3071 ret->attributes = (void *) xmlCopyAttributeTable(
3072 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003073 if (dtd->pentities != NULL)
3074 ret->pentities = (void *) xmlCopyEntitiesTable(
3075 (xmlEntitiesTablePtr) dtd->pentities);
3076
3077 cur = dtd->children;
3078 while (cur != NULL) {
3079 q = NULL;
3080
3081 if (cur->type == XML_ENTITY_DECL) {
3082 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3083 switch (tmp->etype) {
3084 case XML_INTERNAL_GENERAL_ENTITY:
3085 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3086 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3087 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3088 break;
3089 case XML_INTERNAL_PARAMETER_ENTITY:
3090 case XML_EXTERNAL_PARAMETER_ENTITY:
3091 q = (xmlNodePtr)
3092 xmlGetParameterEntityFromDtd(ret, tmp->name);
3093 break;
3094 case XML_INTERNAL_PREDEFINED_ENTITY:
3095 break;
3096 }
3097 } else if (cur->type == XML_ELEMENT_DECL) {
3098 xmlElementPtr tmp = (xmlElementPtr) cur;
3099 q = (xmlNodePtr)
3100 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3101 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3102 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3103 q = (xmlNodePtr)
3104 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3105 } else if (cur->type == XML_COMMENT_NODE) {
3106 q = xmlCopyNode(cur, 0);
3107 }
3108
3109 if (q == NULL) {
3110 cur = cur->next;
3111 continue;
3112 }
3113
3114 if (p == NULL)
3115 ret->children = q;
3116 else
3117 p->next = q;
3118
3119 q->prev = p;
3120 q->parent = (xmlNodePtr) ret;
3121 q->next = NULL;
3122 ret->last = q;
3123 p = q;
3124 cur = cur->next;
3125 }
3126
Owen Taylor3473f882001-02-23 17:55:21 +00003127 return(ret);
3128}
3129
3130/**
3131 * xmlCopyDoc:
3132 * @doc: the document
3133 * @recursive: if 1 do a recursive copy.
3134 *
3135 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003136 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003137 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003138 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003139 */
3140xmlDocPtr
3141xmlCopyDoc(xmlDocPtr doc, int recursive) {
3142 xmlDocPtr ret;
3143
3144 if (doc == NULL) return(NULL);
3145 ret = xmlNewDoc(doc->version);
3146 if (ret == NULL) return(NULL);
3147 if (doc->name != NULL)
3148 ret->name = xmlMemStrdup(doc->name);
3149 if (doc->encoding != NULL)
3150 ret->encoding = xmlStrdup(doc->encoding);
3151 ret->charset = doc->charset;
3152 ret->compression = doc->compression;
3153 ret->standalone = doc->standalone;
3154 if (!recursive) return(ret);
3155
Daniel Veillardb33c2012001-04-25 12:59:04 +00003156 ret->last = NULL;
3157 ret->children = NULL;
3158 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003159 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003160 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003161 ret->intSubset->parent = ret;
3162 }
Owen Taylor3473f882001-02-23 17:55:21 +00003163 if (doc->oldNs != NULL)
3164 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3165 if (doc->children != NULL) {
3166 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003167
3168 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3169 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003170 ret->last = NULL;
3171 tmp = ret->children;
3172 while (tmp != NULL) {
3173 if (tmp->next == NULL)
3174 ret->last = tmp;
3175 tmp = tmp->next;
3176 }
3177 }
3178 return(ret);
3179}
3180
3181/************************************************************************
3182 * *
3183 * Content access functions *
3184 * *
3185 ************************************************************************/
3186
3187/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003188 * xmlGetLineNo:
3189 * @node : valid node
3190 *
3191 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003192 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003193 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003194 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003195 */
3196long
3197xmlGetLineNo(xmlNodePtr node)
3198{
3199 long result = -1;
3200
3201 if (!node)
3202 return result;
3203 if (node->type == XML_ELEMENT_NODE)
3204 result = (long) node->content;
3205 else if ((node->prev != NULL) &&
3206 ((node->prev->type == XML_ELEMENT_NODE) ||
3207 (node->prev->type == XML_TEXT_NODE)))
3208 result = xmlGetLineNo(node->prev);
3209 else if ((node->parent != NULL) &&
3210 ((node->parent->type == XML_ELEMENT_NODE) ||
3211 (node->parent->type == XML_TEXT_NODE)))
3212 result = xmlGetLineNo(node->parent);
3213
3214 return result;
3215}
3216
3217/**
3218 * xmlGetNodePath:
3219 * @node: a node
3220 *
3221 * Build a structure based Path for the given node
3222 *
3223 * Returns the new path or NULL in case of error. The caller must free
3224 * the returned string
3225 */
3226xmlChar *
3227xmlGetNodePath(xmlNodePtr node)
3228{
3229 xmlNodePtr cur, tmp, next;
3230 xmlChar *buffer = NULL, *temp;
3231 size_t buf_len;
3232 xmlChar *buf;
3233 char sep;
3234 const char *name;
3235 char nametemp[100];
3236 int occur = 0;
3237
3238 if (node == NULL)
3239 return (NULL);
3240
3241 buf_len = 500;
3242 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3243 if (buffer == NULL)
3244 return (NULL);
3245 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3246 if (buf == NULL) {
3247 xmlFree(buffer);
3248 return (NULL);
3249 }
3250
3251 buffer[0] = 0;
3252 cur = node;
3253 do {
3254 name = "";
3255 sep = '?';
3256 occur = 0;
3257 if ((cur->type == XML_DOCUMENT_NODE) ||
3258 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3259 if (buffer[0] == '/')
3260 break;
3261 sep = '/';
3262 next = NULL;
3263 } else if (cur->type == XML_ELEMENT_NODE) {
3264 sep = '/';
3265 name = (const char *) cur->name;
3266 if (cur->ns) {
3267 snprintf(nametemp, sizeof(nametemp) - 1,
3268 "%s:%s", cur->ns->prefix, cur->name);
3269 nametemp[sizeof(nametemp) - 1] = 0;
3270 name = nametemp;
3271 }
3272 next = cur->parent;
3273
3274 /*
3275 * Thumbler index computation
3276 */
3277 tmp = cur->prev;
3278 while (tmp != NULL) {
3279 if (xmlStrEqual(cur->name, tmp->name))
3280 occur++;
3281 tmp = tmp->prev;
3282 }
3283 if (occur == 0) {
3284 tmp = cur->next;
3285 while (tmp != NULL) {
3286 if (xmlStrEqual(cur->name, tmp->name))
3287 occur++;
3288 tmp = tmp->next;
3289 }
3290 if (occur != 0)
3291 occur = 1;
3292 } else
3293 occur++;
3294 } else if (cur->type == XML_ATTRIBUTE_NODE) {
3295 sep = '@';
3296 name = (const char *) (((xmlAttrPtr) cur)->name);
3297 next = ((xmlAttrPtr) cur)->parent;
3298 } else {
3299 next = cur->parent;
3300 }
3301
3302 /*
3303 * Make sure there is enough room
3304 */
3305 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3306 buf_len =
3307 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3308 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3309 if (temp == NULL) {
3310 xmlFree(buf);
3311 xmlFree(buffer);
3312 return (NULL);
3313 }
3314 buffer = temp;
3315 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3316 if (temp == NULL) {
3317 xmlFree(buf);
3318 xmlFree(buffer);
3319 return (NULL);
3320 }
3321 buf = temp;
3322 }
3323 if (occur == 0)
3324 snprintf((char *) buf, buf_len, "%c%s%s",
3325 sep, name, (char *) buffer);
3326 else
3327 snprintf((char *) buf, buf_len, "%c%s[%d]%s",
3328 sep, name, occur, (char *) buffer);
3329 snprintf((char *) buffer, buf_len, "%s", buf);
3330 cur = next;
3331 } while (cur != NULL);
3332 xmlFree(buf);
3333 return (buffer);
3334}
3335
3336/**
Owen Taylor3473f882001-02-23 17:55:21 +00003337 * xmlDocGetRootElement:
3338 * @doc: the document
3339 *
3340 * Get the root element of the document (doc->children is a list
3341 * containing possibly comments, PIs, etc ...).
3342 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003343 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003344 */
3345xmlNodePtr
3346xmlDocGetRootElement(xmlDocPtr doc) {
3347 xmlNodePtr ret;
3348
3349 if (doc == NULL) return(NULL);
3350 ret = doc->children;
3351 while (ret != NULL) {
3352 if (ret->type == XML_ELEMENT_NODE)
3353 return(ret);
3354 ret = ret->next;
3355 }
3356 return(ret);
3357}
3358
3359/**
3360 * xmlDocSetRootElement:
3361 * @doc: the document
3362 * @root: the new document root element
3363 *
3364 * Set the root element of the document (doc->children is a list
3365 * containing possibly comments, PIs, etc ...).
3366 *
3367 * Returns the old root element if any was found
3368 */
3369xmlNodePtr
3370xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3371 xmlNodePtr old = NULL;
3372
3373 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00003374 if (root == NULL)
3375 return(NULL);
3376 xmlUnlinkNode(root);
3377 root->doc = doc;
3378 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00003379 old = doc->children;
3380 while (old != NULL) {
3381 if (old->type == XML_ELEMENT_NODE)
3382 break;
3383 old = old->next;
3384 }
3385 if (old == NULL) {
3386 if (doc->children == NULL) {
3387 doc->children = root;
3388 doc->last = root;
3389 } else {
3390 xmlAddSibling(doc->children, root);
3391 }
3392 } else {
3393 xmlReplaceNode(old, root);
3394 }
3395 return(old);
3396}
3397
3398/**
3399 * xmlNodeSetLang:
3400 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003401 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003402 *
3403 * Set the language of a node, i.e. the values of the xml:lang
3404 * attribute.
3405 */
3406void
3407xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003408 xmlNsPtr ns;
3409
Owen Taylor3473f882001-02-23 17:55:21 +00003410 if (cur == NULL) return;
3411 switch(cur->type) {
3412 case XML_TEXT_NODE:
3413 case XML_CDATA_SECTION_NODE:
3414 case XML_COMMENT_NODE:
3415 case XML_DOCUMENT_NODE:
3416 case XML_DOCUMENT_TYPE_NODE:
3417 case XML_DOCUMENT_FRAG_NODE:
3418 case XML_NOTATION_NODE:
3419 case XML_HTML_DOCUMENT_NODE:
3420 case XML_DTD_NODE:
3421 case XML_ELEMENT_DECL:
3422 case XML_ATTRIBUTE_DECL:
3423 case XML_ENTITY_DECL:
3424 case XML_PI_NODE:
3425 case XML_ENTITY_REF_NODE:
3426 case XML_ENTITY_NODE:
3427 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003428#ifdef LIBXML_DOCB_ENABLED
3429 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003430#endif
3431 case XML_XINCLUDE_START:
3432 case XML_XINCLUDE_END:
3433 return;
3434 case XML_ELEMENT_NODE:
3435 case XML_ATTRIBUTE_NODE:
3436 break;
3437 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003438 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3439 if (ns == NULL)
3440 return;
3441 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003442}
3443
3444/**
3445 * xmlNodeGetLang:
3446 * @cur: the node being checked
3447 *
3448 * Searches the language of a node, i.e. the values of the xml:lang
3449 * attribute or the one carried by the nearest ancestor.
3450 *
3451 * Returns a pointer to the lang value, or NULL if not found
3452 * It's up to the caller to free the memory.
3453 */
3454xmlChar *
3455xmlNodeGetLang(xmlNodePtr cur) {
3456 xmlChar *lang;
3457
3458 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003459 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003460 if (lang != NULL)
3461 return(lang);
3462 cur = cur->parent;
3463 }
3464 return(NULL);
3465}
3466
3467
3468/**
3469 * xmlNodeSetSpacePreserve:
3470 * @cur: the node being changed
3471 * @val: the xml:space value ("0": default, 1: "preserve")
3472 *
3473 * Set (or reset) the space preserving behaviour of a node, i.e. the
3474 * value of the xml:space attribute.
3475 */
3476void
3477xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003478 xmlNsPtr ns;
3479
Owen Taylor3473f882001-02-23 17:55:21 +00003480 if (cur == NULL) return;
3481 switch(cur->type) {
3482 case XML_TEXT_NODE:
3483 case XML_CDATA_SECTION_NODE:
3484 case XML_COMMENT_NODE:
3485 case XML_DOCUMENT_NODE:
3486 case XML_DOCUMENT_TYPE_NODE:
3487 case XML_DOCUMENT_FRAG_NODE:
3488 case XML_NOTATION_NODE:
3489 case XML_HTML_DOCUMENT_NODE:
3490 case XML_DTD_NODE:
3491 case XML_ELEMENT_DECL:
3492 case XML_ATTRIBUTE_DECL:
3493 case XML_ENTITY_DECL:
3494 case XML_PI_NODE:
3495 case XML_ENTITY_REF_NODE:
3496 case XML_ENTITY_NODE:
3497 case XML_NAMESPACE_DECL:
3498 case XML_XINCLUDE_START:
3499 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003500#ifdef LIBXML_DOCB_ENABLED
3501 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003502#endif
3503 return;
3504 case XML_ELEMENT_NODE:
3505 case XML_ATTRIBUTE_NODE:
3506 break;
3507 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003508 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3509 if (ns == NULL)
3510 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003511 switch (val) {
3512 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003513 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003514 break;
3515 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003516 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003517 break;
3518 }
3519}
3520
3521/**
3522 * xmlNodeGetSpacePreserve:
3523 * @cur: the node being checked
3524 *
3525 * Searches the space preserving behaviour of a node, i.e. the values
3526 * of the xml:space attribute or the one carried by the nearest
3527 * ancestor.
3528 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003529 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003530 */
3531int
3532xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3533 xmlChar *space;
3534
3535 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003536 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003537 if (space != NULL) {
3538 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3539 xmlFree(space);
3540 return(1);
3541 }
3542 if (xmlStrEqual(space, BAD_CAST "default")) {
3543 xmlFree(space);
3544 return(0);
3545 }
3546 xmlFree(space);
3547 }
3548 cur = cur->parent;
3549 }
3550 return(-1);
3551}
3552
3553/**
3554 * xmlNodeSetName:
3555 * @cur: the node being changed
3556 * @name: the new tag name
3557 *
3558 * Set (or reset) the name of a node.
3559 */
3560void
3561xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3562 if (cur == NULL) return;
3563 if (name == NULL) return;
3564 switch(cur->type) {
3565 case XML_TEXT_NODE:
3566 case XML_CDATA_SECTION_NODE:
3567 case XML_COMMENT_NODE:
3568 case XML_DOCUMENT_TYPE_NODE:
3569 case XML_DOCUMENT_FRAG_NODE:
3570 case XML_NOTATION_NODE:
3571 case XML_HTML_DOCUMENT_NODE:
3572 case XML_NAMESPACE_DECL:
3573 case XML_XINCLUDE_START:
3574 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003575#ifdef LIBXML_DOCB_ENABLED
3576 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003577#endif
3578 return;
3579 case XML_ELEMENT_NODE:
3580 case XML_ATTRIBUTE_NODE:
3581 case XML_PI_NODE:
3582 case XML_ENTITY_REF_NODE:
3583 case XML_ENTITY_NODE:
3584 case XML_DTD_NODE:
3585 case XML_DOCUMENT_NODE:
3586 case XML_ELEMENT_DECL:
3587 case XML_ATTRIBUTE_DECL:
3588 case XML_ENTITY_DECL:
3589 break;
3590 }
3591 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3592 cur->name = xmlStrdup(name);
3593}
3594
3595/**
3596 * xmlNodeSetBase:
3597 * @cur: the node being changed
3598 * @uri: the new base URI
3599 *
3600 * Set (or reset) the base URI of a node, i.e. the value of the
3601 * xml:base attribute.
3602 */
3603void
3604xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003605 xmlNsPtr ns;
3606
Owen Taylor3473f882001-02-23 17:55:21 +00003607 if (cur == NULL) return;
3608 switch(cur->type) {
3609 case XML_TEXT_NODE:
3610 case XML_CDATA_SECTION_NODE:
3611 case XML_COMMENT_NODE:
3612 case XML_DOCUMENT_NODE:
3613 case XML_DOCUMENT_TYPE_NODE:
3614 case XML_DOCUMENT_FRAG_NODE:
3615 case XML_NOTATION_NODE:
3616 case XML_HTML_DOCUMENT_NODE:
3617 case XML_DTD_NODE:
3618 case XML_ELEMENT_DECL:
3619 case XML_ATTRIBUTE_DECL:
3620 case XML_ENTITY_DECL:
3621 case XML_PI_NODE:
3622 case XML_ENTITY_REF_NODE:
3623 case XML_ENTITY_NODE:
3624 case XML_NAMESPACE_DECL:
3625 case XML_XINCLUDE_START:
3626 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003627#ifdef LIBXML_DOCB_ENABLED
3628 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003629#endif
3630 return;
3631 case XML_ELEMENT_NODE:
3632 case XML_ATTRIBUTE_NODE:
3633 break;
3634 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003635
3636 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3637 if (ns == NULL)
3638 return;
3639 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00003640}
3641
3642/**
Owen Taylor3473f882001-02-23 17:55:21 +00003643 * xmlNodeGetBase:
3644 * @doc: the document the node pertains to
3645 * @cur: the node being checked
3646 *
3647 * Searches for the BASE URL. The code should work on both XML
3648 * and HTML document even if base mechanisms are completely different.
3649 * It returns the base as defined in RFC 2396 sections
3650 * 5.1.1. Base URI within Document Content
3651 * and
3652 * 5.1.2. Base URI from the Encapsulating Entity
3653 * However it does not return the document base (5.1.3), use
3654 * xmlDocumentGetBase() for this
3655 *
3656 * Returns a pointer to the base URL, or NULL if not found
3657 * It's up to the caller to free the memory.
3658 */
3659xmlChar *
3660xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003661 xmlChar *oldbase = NULL;
3662 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003663
3664 if ((cur == NULL) && (doc == NULL))
3665 return(NULL);
3666 if (doc == NULL) doc = cur->doc;
3667 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3668 cur = doc->children;
3669 while ((cur != NULL) && (cur->name != NULL)) {
3670 if (cur->type != XML_ELEMENT_NODE) {
3671 cur = cur->next;
3672 continue;
3673 }
3674 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3675 cur = cur->children;
3676 continue;
3677 }
3678 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3679 cur = cur->children;
3680 continue;
3681 }
3682 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3683 return(xmlGetProp(cur, BAD_CAST "href"));
3684 }
3685 cur = cur->next;
3686 }
3687 return(NULL);
3688 }
3689 while (cur != NULL) {
3690 if (cur->type == XML_ENTITY_DECL) {
3691 xmlEntityPtr ent = (xmlEntityPtr) cur;
3692 return(xmlStrdup(ent->URI));
3693 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003694 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003695 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003696 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003697 if (oldbase != NULL) {
3698 newbase = xmlBuildURI(oldbase, base);
3699 if (newbase != NULL) {
3700 xmlFree(oldbase);
3701 xmlFree(base);
3702 oldbase = newbase;
3703 } else {
3704 xmlFree(oldbase);
3705 xmlFree(base);
3706 return(NULL);
3707 }
3708 } else {
3709 oldbase = base;
3710 }
3711 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3712 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3713 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3714 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003715 }
3716 }
Owen Taylor3473f882001-02-23 17:55:21 +00003717 cur = cur->parent;
3718 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003719 if ((doc != NULL) && (doc->URL != NULL)) {
3720 if (oldbase == NULL)
3721 return(xmlStrdup(doc->URL));
3722 newbase = xmlBuildURI(oldbase, doc->URL);
3723 xmlFree(oldbase);
3724 return(newbase);
3725 }
3726 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003727}
3728
3729/**
3730 * xmlNodeGetContent:
3731 * @cur: the node being read
3732 *
3733 * Read the value of a node, this can be either the text carried
3734 * directly by this node if it's a TEXT node or the aggregate string
3735 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00003736 * Entity references are substituted.
3737 * Returns a new #xmlChar * or NULL if no content is available.
Owen Taylor3473f882001-02-23 17:55:21 +00003738 * It's up to the caller to free the memory.
3739 */
3740xmlChar *
3741xmlNodeGetContent(xmlNodePtr cur) {
3742 if (cur == NULL) return(NULL);
3743 switch (cur->type) {
3744 case XML_DOCUMENT_FRAG_NODE:
3745 case XML_ELEMENT_NODE: {
3746 xmlNodePtr tmp = cur;
3747 xmlBufferPtr buffer;
3748 xmlChar *ret;
3749
3750 buffer = xmlBufferCreate();
3751 if (buffer == NULL)
3752 return(NULL);
3753 while (tmp != NULL) {
3754 switch (tmp->type) {
Daniel Veillard2d703722001-05-30 18:32:34 +00003755 case XML_CDATA_SECTION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003756 case XML_TEXT_NODE:
3757 if (tmp->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00003758 xmlBufferCat(buffer, tmp->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003759 break;
3760 case XML_ENTITY_REF_NODE: {
3761 xmlEntityPtr ent;
3762
3763 ent = xmlGetDocEntity(cur->doc, tmp->name);
3764 if (ent != NULL)
3765 xmlBufferCat(buffer, ent->content);
3766 }
3767 default:
3768 break;
3769 }
3770 /*
3771 * Skip to next node
3772 */
3773 if (tmp->children != NULL) {
3774 if (tmp->children->type != XML_ENTITY_DECL) {
3775 tmp = tmp->children;
3776 continue;
3777 }
3778 }
Daniel Veillard6c831202001-03-07 15:57:53 +00003779 if (tmp == cur)
3780 break;
3781
Owen Taylor3473f882001-02-23 17:55:21 +00003782 if (tmp->next != NULL) {
3783 tmp = tmp->next;
3784 continue;
3785 }
3786
3787 do {
3788 tmp = tmp->parent;
3789 if (tmp == NULL)
3790 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00003791 if (tmp == cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003792 tmp = NULL;
3793 break;
3794 }
3795 if (tmp->next != NULL) {
3796 tmp = tmp->next;
3797 break;
3798 }
3799 } while (tmp != NULL);
3800 }
3801 ret = buffer->content;
3802 buffer->content = NULL;
3803 xmlBufferFree(buffer);
3804 return(ret);
3805 }
3806 case XML_ATTRIBUTE_NODE: {
3807 xmlAttrPtr attr = (xmlAttrPtr) cur;
3808 if (attr->parent != NULL)
3809 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
3810 else
3811 return(xmlNodeListGetString(NULL, attr->children, 1));
3812 break;
3813 }
3814 case XML_COMMENT_NODE:
3815 case XML_PI_NODE:
3816 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00003817 return(xmlStrdup(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00003818 return(NULL);
3819 case XML_ENTITY_REF_NODE:
3820 /*
3821 * Locate the entity, and get it's content
3822 * @@@
3823 */
3824 return(NULL);
3825 case XML_ENTITY_NODE:
3826 case XML_DOCUMENT_NODE:
3827 case XML_HTML_DOCUMENT_NODE:
3828 case XML_DOCUMENT_TYPE_NODE:
3829 case XML_NOTATION_NODE:
3830 case XML_DTD_NODE:
3831 case XML_XINCLUDE_START:
3832 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003833#ifdef LIBXML_DOCB_ENABLED
3834 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003835#endif
3836 return(NULL);
3837 case XML_NAMESPACE_DECL:
3838 return(xmlStrdup(((xmlNsPtr)cur)->href));
3839 case XML_ELEMENT_DECL:
3840 /* TODO !!! */
3841 return(NULL);
3842 case XML_ATTRIBUTE_DECL:
3843 /* TODO !!! */
3844 return(NULL);
3845 case XML_ENTITY_DECL:
3846 /* TODO !!! */
3847 return(NULL);
3848 case XML_CDATA_SECTION_NODE:
3849 case XML_TEXT_NODE:
3850 if (cur->content != NULL)
Daniel Veillard9ff88172002-03-11 09:15:32 +00003851 return(xmlStrdup(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00003852 return(NULL);
3853 }
3854 return(NULL);
3855}
3856
3857/**
3858 * xmlNodeSetContent:
3859 * @cur: the node being modified
3860 * @content: the new value of the content
3861 *
3862 * Replace the content of a node.
3863 */
3864void
3865xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
3866 if (cur == NULL) {
3867#ifdef DEBUG_TREE
3868 xmlGenericError(xmlGenericErrorContext,
3869 "xmlNodeSetContent : node == NULL\n");
3870#endif
3871 return;
3872 }
3873 switch (cur->type) {
3874 case XML_DOCUMENT_FRAG_NODE:
3875 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00003876 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003877 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3878 cur->children = xmlStringGetNodeList(cur->doc, content);
3879 UPDATE_LAST_CHILD_AND_PARENT(cur)
3880 break;
Owen Taylor3473f882001-02-23 17:55:21 +00003881 case XML_TEXT_NODE:
3882 case XML_CDATA_SECTION_NODE:
3883 case XML_ENTITY_REF_NODE:
3884 case XML_ENTITY_NODE:
3885 case XML_PI_NODE:
3886 case XML_COMMENT_NODE:
3887 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003888 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003889 }
3890 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3891 cur->last = cur->children = NULL;
3892 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003893 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00003894 } else
3895 cur->content = NULL;
3896 break;
3897 case XML_DOCUMENT_NODE:
3898 case XML_HTML_DOCUMENT_NODE:
3899 case XML_DOCUMENT_TYPE_NODE:
3900 case XML_XINCLUDE_START:
3901 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003902#ifdef LIBXML_DOCB_ENABLED
3903 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003904#endif
3905 break;
3906 case XML_NOTATION_NODE:
3907 break;
3908 case XML_DTD_NODE:
3909 break;
3910 case XML_NAMESPACE_DECL:
3911 break;
3912 case XML_ELEMENT_DECL:
3913 /* TODO !!! */
3914 break;
3915 case XML_ATTRIBUTE_DECL:
3916 /* TODO !!! */
3917 break;
3918 case XML_ENTITY_DECL:
3919 /* TODO !!! */
3920 break;
3921 }
3922}
3923
3924/**
3925 * xmlNodeSetContentLen:
3926 * @cur: the node being modified
3927 * @content: the new value of the content
3928 * @len: the size of @content
3929 *
3930 * Replace the content of a node.
3931 */
3932void
3933xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3934 if (cur == NULL) {
3935#ifdef DEBUG_TREE
3936 xmlGenericError(xmlGenericErrorContext,
3937 "xmlNodeSetContentLen : node == NULL\n");
3938#endif
3939 return;
3940 }
3941 switch (cur->type) {
3942 case XML_DOCUMENT_FRAG_NODE:
3943 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00003944 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003945 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3946 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
3947 UPDATE_LAST_CHILD_AND_PARENT(cur)
3948 break;
Owen Taylor3473f882001-02-23 17:55:21 +00003949 case XML_TEXT_NODE:
3950 case XML_CDATA_SECTION_NODE:
3951 case XML_ENTITY_REF_NODE:
3952 case XML_ENTITY_NODE:
3953 case XML_PI_NODE:
3954 case XML_COMMENT_NODE:
3955 case XML_NOTATION_NODE:
3956 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003957 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003958 }
3959 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3960 cur->children = cur->last = NULL;
3961 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003962 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00003963 } else
3964 cur->content = NULL;
3965 break;
3966 case XML_DOCUMENT_NODE:
3967 case XML_DTD_NODE:
3968 case XML_HTML_DOCUMENT_NODE:
3969 case XML_DOCUMENT_TYPE_NODE:
3970 case XML_NAMESPACE_DECL:
3971 case XML_XINCLUDE_START:
3972 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003973#ifdef LIBXML_DOCB_ENABLED
3974 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003975#endif
3976 break;
3977 case XML_ELEMENT_DECL:
3978 /* TODO !!! */
3979 break;
3980 case XML_ATTRIBUTE_DECL:
3981 /* TODO !!! */
3982 break;
3983 case XML_ENTITY_DECL:
3984 /* TODO !!! */
3985 break;
3986 }
3987}
3988
3989/**
3990 * xmlNodeAddContentLen:
3991 * @cur: the node being modified
3992 * @content: extra content
3993 * @len: the size of @content
3994 *
3995 * Append the extra substring to the node content.
3996 */
3997void
3998xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3999 if (cur == NULL) {
4000#ifdef DEBUG_TREE
4001 xmlGenericError(xmlGenericErrorContext,
4002 "xmlNodeAddContentLen : node == NULL\n");
4003#endif
4004 return;
4005 }
4006 if (len <= 0) return;
4007 switch (cur->type) {
4008 case XML_DOCUMENT_FRAG_NODE:
4009 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004010 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004011
Daniel Veillard7db37732001-07-12 01:20:08 +00004012 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004013 newNode = xmlNewTextLen(content, len);
4014 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004015 tmp = xmlAddChild(cur, newNode);
4016 if (tmp != newNode)
4017 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004018 if ((last != NULL) && (last->next == newNode)) {
4019 xmlTextMerge(last, newNode);
4020 }
4021 }
4022 break;
4023 }
4024 case XML_ATTRIBUTE_NODE:
4025 break;
4026 case XML_TEXT_NODE:
4027 case XML_CDATA_SECTION_NODE:
4028 case XML_ENTITY_REF_NODE:
4029 case XML_ENTITY_NODE:
4030 case XML_PI_NODE:
4031 case XML_COMMENT_NODE:
4032 case XML_NOTATION_NODE:
4033 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004034 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004035 }
4036 case XML_DOCUMENT_NODE:
4037 case XML_DTD_NODE:
4038 case XML_HTML_DOCUMENT_NODE:
4039 case XML_DOCUMENT_TYPE_NODE:
4040 case XML_NAMESPACE_DECL:
4041 case XML_XINCLUDE_START:
4042 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004043#ifdef LIBXML_DOCB_ENABLED
4044 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004045#endif
4046 break;
4047 case XML_ELEMENT_DECL:
4048 case XML_ATTRIBUTE_DECL:
4049 case XML_ENTITY_DECL:
4050 break;
4051 }
4052}
4053
4054/**
4055 * xmlNodeAddContent:
4056 * @cur: the node being modified
4057 * @content: extra content
4058 *
4059 * Append the extra substring to the node content.
4060 */
4061void
4062xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4063 int len;
4064
4065 if (cur == NULL) {
4066#ifdef DEBUG_TREE
4067 xmlGenericError(xmlGenericErrorContext,
4068 "xmlNodeAddContent : node == NULL\n");
4069#endif
4070 return;
4071 }
4072 if (content == NULL) return;
4073 len = xmlStrlen(content);
4074 xmlNodeAddContentLen(cur, content, len);
4075}
4076
4077/**
4078 * xmlTextMerge:
4079 * @first: the first text node
4080 * @second: the second text node being merged
4081 *
4082 * Merge two text nodes into one
4083 * Returns the first text node augmented
4084 */
4085xmlNodePtr
4086xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4087 if (first == NULL) return(second);
4088 if (second == NULL) return(first);
4089 if (first->type != XML_TEXT_NODE) return(first);
4090 if (second->type != XML_TEXT_NODE) return(first);
4091 if (second->name != first->name)
4092 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004093 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004094 xmlUnlinkNode(second);
4095 xmlFreeNode(second);
4096 return(first);
4097}
4098
4099/**
4100 * xmlGetNsList:
4101 * @doc: the document
4102 * @node: the current node
4103 *
4104 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004105 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004106 * that need to be freed by the caller or NULL if no
4107 * namespace if defined
4108 */
4109xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004110xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4111{
Owen Taylor3473f882001-02-23 17:55:21 +00004112 xmlNsPtr cur;
4113 xmlNsPtr *ret = NULL;
4114 int nbns = 0;
4115 int maxns = 10;
4116 int i;
4117
4118 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004119 if (node->type == XML_ELEMENT_NODE) {
4120 cur = node->nsDef;
4121 while (cur != NULL) {
4122 if (ret == NULL) {
4123 ret =
4124 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4125 sizeof(xmlNsPtr));
4126 if (ret == NULL) {
4127 xmlGenericError(xmlGenericErrorContext,
4128 "xmlGetNsList : out of memory!\n");
4129 return (NULL);
4130 }
4131 ret[nbns] = NULL;
4132 }
4133 for (i = 0; i < nbns; i++) {
4134 if ((cur->prefix == ret[i]->prefix) ||
4135 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4136 break;
4137 }
4138 if (i >= nbns) {
4139 if (nbns >= maxns) {
4140 maxns *= 2;
4141 ret = (xmlNsPtr *) xmlRealloc(ret,
4142 (maxns +
4143 1) *
4144 sizeof(xmlNsPtr));
4145 if (ret == NULL) {
4146 xmlGenericError(xmlGenericErrorContext,
4147 "xmlGetNsList : realloc failed!\n");
4148 return (NULL);
4149 }
4150 }
4151 ret[nbns++] = cur;
4152 ret[nbns] = NULL;
4153 }
Owen Taylor3473f882001-02-23 17:55:21 +00004154
Daniel Veillard77044732001-06-29 21:31:07 +00004155 cur = cur->next;
4156 }
4157 }
4158 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004159 }
Daniel Veillard77044732001-06-29 21:31:07 +00004160 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004161}
4162
4163/**
4164 * xmlSearchNs:
4165 * @doc: the document
4166 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004167 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004168 *
4169 * Search a Ns registered under a given name space for a document.
4170 * recurse on the parents until it finds the defined namespace
4171 * or return NULL otherwise.
4172 * @nameSpace can be NULL, this is a search for the default namespace.
4173 * We don't allow to cross entities boundaries. If you don't declare
4174 * the namespace within those you will be in troubles !!! A warning
4175 * is generated to cover this case.
4176 *
4177 * Returns the namespace pointer or NULL.
4178 */
4179xmlNsPtr
4180xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4181 xmlNsPtr cur;
4182
4183 if (node == NULL) return(NULL);
4184 if ((nameSpace != NULL) &&
4185 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillardd2f23002002-01-21 13:36:00 +00004186 if (doc == NULL)
4187 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004188 if (doc->oldNs == NULL) {
4189 /*
4190 * Allocate a new Namespace and fill the fields.
4191 */
4192 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4193 if (doc->oldNs == NULL) {
4194 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004195 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004196 return(NULL);
4197 }
4198 memset(doc->oldNs, 0, sizeof(xmlNs));
4199 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4200
4201 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4202 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4203 }
4204 return(doc->oldNs);
4205 }
4206 while (node != NULL) {
4207 if ((node->type == XML_ENTITY_REF_NODE) ||
4208 (node->type == XML_ENTITY_NODE) ||
4209 (node->type == XML_ENTITY_DECL))
4210 return(NULL);
4211 if (node->type == XML_ELEMENT_NODE) {
4212 cur = node->nsDef;
4213 while (cur != NULL) {
4214 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4215 (cur->href != NULL))
4216 return(cur);
4217 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4218 (cur->href != NULL) &&
4219 (xmlStrEqual(cur->prefix, nameSpace)))
4220 return(cur);
4221 cur = cur->next;
4222 }
4223 }
4224 node = node->parent;
4225 }
4226 return(NULL);
4227}
4228
4229/**
4230 * xmlSearchNsByHref:
4231 * @doc: the document
4232 * @node: the current node
4233 * @href: the namespace value
4234 *
4235 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4236 * the defined namespace or return NULL otherwise.
4237 * Returns the namespace pointer or NULL.
4238 */
4239xmlNsPtr
4240xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4241 xmlNsPtr cur;
4242 xmlNodePtr orig = node;
4243
4244 if ((node == NULL) || (href == NULL)) return(NULL);
4245 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004246 /*
4247 * Only the document can hold the XML spec namespace.
4248 */
4249 if (doc == NULL)
4250 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004251 if (doc->oldNs == NULL) {
4252 /*
4253 * Allocate a new Namespace and fill the fields.
4254 */
4255 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4256 if (doc->oldNs == NULL) {
4257 xmlGenericError(xmlGenericErrorContext,
4258 "xmlSearchNsByHref : malloc failed\n");
4259 return(NULL);
4260 }
4261 memset(doc->oldNs, 0, sizeof(xmlNs));
4262 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4263
4264 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4265 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4266 }
4267 return(doc->oldNs);
4268 }
4269 while (node != NULL) {
4270 cur = node->nsDef;
4271 while (cur != NULL) {
4272 if ((cur->href != NULL) && (href != NULL) &&
4273 (xmlStrEqual(cur->href, href))) {
4274 /*
4275 * Check that the prefix is not shadowed between orig and node
4276 */
4277 xmlNodePtr check = orig;
4278 xmlNsPtr tst;
4279
4280 while (check != node) {
4281 tst = check->nsDef;
4282 while (tst != NULL) {
4283 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4284 goto shadowed;
4285 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4286 (xmlStrEqual(tst->prefix, cur->prefix)))
4287 goto shadowed;
4288 tst = tst->next;
4289 }
4290 check = check->parent;
4291 }
4292 return(cur);
4293 }
4294shadowed:
4295 cur = cur->next;
4296 }
4297 node = node->parent;
4298 }
4299 return(NULL);
4300}
4301
4302/**
4303 * xmlNewReconciliedNs
4304 * @doc: the document
4305 * @tree: a node expected to hold the new namespace
4306 * @ns: the original namespace
4307 *
4308 * This function tries to locate a namespace definition in a tree
4309 * ancestors, or create a new namespace definition node similar to
4310 * @ns trying to reuse the same prefix. However if the given prefix is
4311 * null (default namespace) or reused within the subtree defined by
4312 * @tree or on one of its ancestors then a new prefix is generated.
4313 * Returns the (new) namespace definition or NULL in case of error
4314 */
4315xmlNsPtr
4316xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4317 xmlNsPtr def;
4318 xmlChar prefix[50];
4319 int counter = 1;
4320
4321 if (tree == NULL) {
4322#ifdef DEBUG_TREE
4323 xmlGenericError(xmlGenericErrorContext,
4324 "xmlNewReconciliedNs : tree == NULL\n");
4325#endif
4326 return(NULL);
4327 }
4328 if (ns == NULL) {
4329#ifdef DEBUG_TREE
4330 xmlGenericError(xmlGenericErrorContext,
4331 "xmlNewReconciliedNs : ns == NULL\n");
4332#endif
4333 return(NULL);
4334 }
4335 /*
4336 * Search an existing namespace definition inherited.
4337 */
4338 def = xmlSearchNsByHref(doc, tree, ns->href);
4339 if (def != NULL)
4340 return(def);
4341
4342 /*
4343 * Find a close prefix which is not already in use.
4344 * Let's strip namespace prefixes longer than 20 chars !
4345 */
Daniel Veillardf742d342002-03-07 00:05:35 +00004346 if (ns->prefix == NULL)
4347 sprintf((char *) prefix, "default");
4348 else
4349 sprintf((char *) prefix, "%.20s", ns->prefix);
4350
Owen Taylor3473f882001-02-23 17:55:21 +00004351 def = xmlSearchNs(doc, tree, prefix);
4352 while (def != NULL) {
4353 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00004354 if (ns->prefix == NULL)
4355 sprintf((char *) prefix, "default%d", counter++);
4356 else
4357 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00004358 def = xmlSearchNs(doc, tree, prefix);
4359 }
4360
4361 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004362 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004363 */
4364 def = xmlNewNs(tree, ns->href, prefix);
4365 return(def);
4366}
4367
4368/**
4369 * xmlReconciliateNs
4370 * @doc: the document
4371 * @tree: a node defining the subtree to reconciliate
4372 *
4373 * This function checks that all the namespaces declared within the given
4374 * tree are properly declared. This is needed for example after Copy or Cut
4375 * and then paste operations. The subtree may still hold pointers to
4376 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004377 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004378 * the new environment. If not possible the new namespaces are redeclared
4379 * on @tree at the top of the given subtree.
4380 * Returns the number of namespace declarations created or -1 in case of error.
4381 */
4382int
4383xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4384 xmlNsPtr *oldNs = NULL;
4385 xmlNsPtr *newNs = NULL;
4386 int sizeCache = 0;
4387 int nbCache = 0;
4388
4389 xmlNsPtr n;
4390 xmlNodePtr node = tree;
4391 xmlAttrPtr attr;
4392 int ret = 0, i;
4393
4394 while (node != NULL) {
4395 /*
4396 * Reconciliate the node namespace
4397 */
4398 if (node->ns != NULL) {
4399 /*
4400 * initialize the cache if needed
4401 */
4402 if (sizeCache == 0) {
4403 sizeCache = 10;
4404 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4405 sizeof(xmlNsPtr));
4406 if (oldNs == NULL) {
4407 xmlGenericError(xmlGenericErrorContext,
4408 "xmlReconciliateNs : memory pbm\n");
4409 return(-1);
4410 }
4411 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4412 sizeof(xmlNsPtr));
4413 if (newNs == NULL) {
4414 xmlGenericError(xmlGenericErrorContext,
4415 "xmlReconciliateNs : memory pbm\n");
4416 xmlFree(oldNs);
4417 return(-1);
4418 }
4419 }
4420 for (i = 0;i < nbCache;i++) {
4421 if (oldNs[i] == node->ns) {
4422 node->ns = newNs[i];
4423 break;
4424 }
4425 }
4426 if (i == nbCache) {
4427 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004428 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004429 */
4430 n = xmlNewReconciliedNs(doc, tree, node->ns);
4431 if (n != NULL) { /* :-( what if else ??? */
4432 /*
4433 * check if we need to grow the cache buffers.
4434 */
4435 if (sizeCache <= nbCache) {
4436 sizeCache *= 2;
4437 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4438 sizeof(xmlNsPtr));
4439 if (oldNs == NULL) {
4440 xmlGenericError(xmlGenericErrorContext,
4441 "xmlReconciliateNs : memory pbm\n");
4442 xmlFree(newNs);
4443 return(-1);
4444 }
4445 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4446 sizeof(xmlNsPtr));
4447 if (newNs == NULL) {
4448 xmlGenericError(xmlGenericErrorContext,
4449 "xmlReconciliateNs : memory pbm\n");
4450 xmlFree(oldNs);
4451 return(-1);
4452 }
4453 }
4454 newNs[nbCache] = n;
4455 oldNs[nbCache++] = node->ns;
4456 node->ns = n;
4457 }
4458 }
4459 }
4460 /*
4461 * now check for namespace hold by attributes on the node.
4462 */
4463 attr = node->properties;
4464 while (attr != NULL) {
4465 if (attr->ns != NULL) {
4466 /*
4467 * initialize the cache if needed
4468 */
4469 if (sizeCache == 0) {
4470 sizeCache = 10;
4471 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4472 sizeof(xmlNsPtr));
4473 if (oldNs == NULL) {
4474 xmlGenericError(xmlGenericErrorContext,
4475 "xmlReconciliateNs : memory pbm\n");
4476 return(-1);
4477 }
4478 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4479 sizeof(xmlNsPtr));
4480 if (newNs == NULL) {
4481 xmlGenericError(xmlGenericErrorContext,
4482 "xmlReconciliateNs : memory pbm\n");
4483 xmlFree(oldNs);
4484 return(-1);
4485 }
4486 }
4487 for (i = 0;i < nbCache;i++) {
4488 if (oldNs[i] == attr->ns) {
4489 node->ns = newNs[i];
4490 break;
4491 }
4492 }
4493 if (i == nbCache) {
4494 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004495 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004496 */
4497 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4498 if (n != NULL) { /* :-( what if else ??? */
4499 /*
4500 * check if we need to grow the cache buffers.
4501 */
4502 if (sizeCache <= nbCache) {
4503 sizeCache *= 2;
4504 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4505 sizeof(xmlNsPtr));
4506 if (oldNs == NULL) {
4507 xmlGenericError(xmlGenericErrorContext,
4508 "xmlReconciliateNs : memory pbm\n");
4509 xmlFree(newNs);
4510 return(-1);
4511 }
4512 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4513 sizeof(xmlNsPtr));
4514 if (newNs == NULL) {
4515 xmlGenericError(xmlGenericErrorContext,
4516 "xmlReconciliateNs : memory pbm\n");
4517 xmlFree(oldNs);
4518 return(-1);
4519 }
4520 }
4521 newNs[nbCache] = n;
4522 oldNs[nbCache++] = attr->ns;
4523 attr->ns = n;
4524 }
4525 }
4526 }
4527 attr = attr->next;
4528 }
4529
4530 /*
4531 * Browse the full subtree, deep first
4532 */
4533 if (node->children != NULL) {
4534 /* deep first */
4535 node = node->children;
4536 } else if ((node != tree) && (node->next != NULL)) {
4537 /* then siblings */
4538 node = node->next;
4539 } else if (node != tree) {
4540 /* go up to parents->next if needed */
4541 while (node != tree) {
4542 if (node->parent != NULL)
4543 node = node->parent;
4544 if ((node != tree) && (node->next != NULL)) {
4545 node = node->next;
4546 break;
4547 }
4548 if (node->parent == NULL) {
4549 node = NULL;
4550 break;
4551 }
4552 }
4553 /* exit condition */
4554 if (node == tree)
4555 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00004556 } else
4557 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004558 }
Daniel Veillardf742d342002-03-07 00:05:35 +00004559 if (oldNs != NULL)
4560 xmlFree(oldNs);
4561 if (newNs != NULL)
4562 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00004563 return(ret);
4564}
4565
4566/**
4567 * xmlHasProp:
4568 * @node: the node
4569 * @name: the attribute name
4570 *
4571 * Search an attribute associated to a node
4572 * This function also looks in DTD attribute declaration for #FIXED or
4573 * default declaration values unless DTD use has been turned off.
4574 *
4575 * Returns the attribute or the attribute declaration or NULL if
4576 * neither was found.
4577 */
4578xmlAttrPtr
4579xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4580 xmlAttrPtr prop;
4581 xmlDocPtr doc;
4582
4583 if ((node == NULL) || (name == NULL)) return(NULL);
4584 /*
4585 * Check on the properties attached to the node
4586 */
4587 prop = node->properties;
4588 while (prop != NULL) {
4589 if (xmlStrEqual(prop->name, name)) {
4590 return(prop);
4591 }
4592 prop = prop->next;
4593 }
4594 if (!xmlCheckDTD) return(NULL);
4595
4596 /*
4597 * Check if there is a default declaration in the internal
4598 * or external subsets
4599 */
4600 doc = node->doc;
4601 if (doc != NULL) {
4602 xmlAttributePtr attrDecl;
4603 if (doc->intSubset != NULL) {
4604 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4605 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4606 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4607 if (attrDecl != NULL)
4608 return((xmlAttrPtr) attrDecl);
4609 }
4610 }
4611 return(NULL);
4612}
4613
4614/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004615 * xmlHasNsProp:
4616 * @node: the node
4617 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004618 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004619 *
4620 * Search for an attribute associated to a node
4621 * This attribute has to be anchored in the namespace specified.
4622 * This does the entity substitution.
4623 * This function looks in DTD attribute declaration for #FIXED or
4624 * default declaration values unless DTD use has been turned off.
4625 *
4626 * Returns the attribute or the attribute declaration or NULL
4627 * if neither was found.
4628 */
4629xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004630xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004631 xmlAttrPtr prop;
4632 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004633
4634 if (node == NULL)
4635 return(NULL);
4636
4637 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004638 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004639 return(xmlHasProp(node, name));
4640 while (prop != NULL) {
4641 /*
4642 * One need to have
4643 * - same attribute names
4644 * - and the attribute carrying that namespace
4645 * or
4646 * no namespace on the attribute and the element carrying it
4647 */
4648 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004649 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4650 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004651 }
4652 prop = prop->next;
4653 }
4654 if (!xmlCheckDTD) return(NULL);
4655
4656 /*
4657 * Check if there is a default declaration in the internal
4658 * or external subsets
4659 */
4660 doc = node->doc;
4661 if (doc != NULL) {
4662 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004663 xmlAttributePtr attrDecl = NULL;
4664 xmlNsPtr *nsList, *cur;
4665 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004666
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004667 nsList = xmlGetNsList(node->doc, node);
4668 if (nsList == NULL)
4669 return(NULL);
4670 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
4671 ename = xmlStrdup(node->ns->prefix);
4672 ename = xmlStrcat(ename, BAD_CAST ":");
4673 ename = xmlStrcat(ename, node->name);
4674 } else {
4675 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004676 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004677 if (ename == NULL) {
4678 xmlFree(nsList);
4679 return(NULL);
4680 }
4681
4682 cur = nsList;
4683 while (*cur != NULL) {
4684 if (xmlStrEqual((*cur)->href, nameSpace)) {
4685 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
4686 name, (*cur)->prefix);
4687 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4688 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
4689 name, (*cur)->prefix);
4690 }
4691 cur++;
4692 }
4693 xmlFree(nsList);
4694 xmlFree(ename);
4695 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004696 }
4697 }
4698 return(NULL);
4699}
4700
4701/**
Owen Taylor3473f882001-02-23 17:55:21 +00004702 * xmlGetProp:
4703 * @node: the node
4704 * @name: the attribute name
4705 *
4706 * Search and get the value of an attribute associated to a node
4707 * This does the entity substitution.
4708 * This function looks in DTD attribute declaration for #FIXED or
4709 * default declaration values unless DTD use has been turned off.
4710 *
4711 * Returns the attribute value or NULL if not found.
4712 * It's up to the caller to free the memory.
4713 */
4714xmlChar *
4715xmlGetProp(xmlNodePtr node, const xmlChar *name) {
4716 xmlAttrPtr prop;
4717 xmlDocPtr doc;
4718
4719 if ((node == NULL) || (name == NULL)) return(NULL);
4720 /*
4721 * Check on the properties attached to the node
4722 */
4723 prop = node->properties;
4724 while (prop != NULL) {
4725 if (xmlStrEqual(prop->name, name)) {
4726 xmlChar *ret;
4727
4728 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4729 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4730 return(ret);
4731 }
4732 prop = prop->next;
4733 }
4734 if (!xmlCheckDTD) return(NULL);
4735
4736 /*
4737 * Check if there is a default declaration in the internal
4738 * or external subsets
4739 */
4740 doc = node->doc;
4741 if (doc != NULL) {
4742 xmlAttributePtr attrDecl;
4743 if (doc->intSubset != NULL) {
4744 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4745 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4746 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4747 if (attrDecl != NULL)
4748 return(xmlStrdup(attrDecl->defaultValue));
4749 }
4750 }
4751 return(NULL);
4752}
4753
4754/**
4755 * xmlGetNsProp:
4756 * @node: the node
4757 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004758 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004759 *
4760 * Search and get the value of an attribute associated to a node
4761 * This attribute has to be anchored in the namespace specified.
4762 * This does the entity substitution.
4763 * This function looks in DTD attribute declaration for #FIXED or
4764 * default declaration values unless DTD use has been turned off.
4765 *
4766 * Returns the attribute value or NULL if not found.
4767 * It's up to the caller to free the memory.
4768 */
4769xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00004770xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00004771 xmlAttrPtr prop;
4772 xmlDocPtr doc;
4773 xmlNsPtr ns;
4774
4775 if (node == NULL)
4776 return(NULL);
4777
4778 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004779 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00004780 return(xmlGetProp(node, name));
4781 while (prop != NULL) {
4782 /*
4783 * One need to have
4784 * - same attribute names
4785 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004786 */
4787 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00004788 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00004789 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00004790 xmlChar *ret;
4791
4792 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4793 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4794 return(ret);
4795 }
4796 prop = prop->next;
4797 }
4798 if (!xmlCheckDTD) return(NULL);
4799
4800 /*
4801 * Check if there is a default declaration in the internal
4802 * or external subsets
4803 */
4804 doc = node->doc;
4805 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004806 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00004807 xmlAttributePtr attrDecl;
4808
Owen Taylor3473f882001-02-23 17:55:21 +00004809 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4810 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4811 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4812
4813 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4814 /*
4815 * The DTD declaration only allows a prefix search
4816 */
4817 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004818 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00004819 return(xmlStrdup(attrDecl->defaultValue));
4820 }
4821 }
4822 }
4823 return(NULL);
4824}
4825
4826/**
4827 * xmlSetProp:
4828 * @node: the node
4829 * @name: the attribute name
4830 * @value: the attribute value
4831 *
4832 * Set (or reset) an attribute carried by a node.
4833 * Returns the attribute pointer.
4834 */
4835xmlAttrPtr
4836xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004837 xmlAttrPtr prop;
4838 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004839
4840 if ((node == NULL) || (name == NULL))
4841 return(NULL);
4842 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004843 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00004844 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00004845 if ((xmlStrEqual(prop->name, name)) &&
4846 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004847 xmlNodePtr oldprop = prop->children;
4848
Owen Taylor3473f882001-02-23 17:55:21 +00004849 prop->children = NULL;
4850 prop->last = NULL;
4851 if (value != NULL) {
4852 xmlChar *buffer;
4853 xmlNodePtr tmp;
4854
4855 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4856 prop->children = xmlStringGetNodeList(node->doc, buffer);
4857 prop->last = NULL;
4858 prop->doc = doc;
4859 tmp = prop->children;
4860 while (tmp != NULL) {
4861 tmp->parent = (xmlNodePtr) prop;
4862 tmp->doc = doc;
4863 if (tmp->next == NULL)
4864 prop->last = tmp;
4865 tmp = tmp->next;
4866 }
4867 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00004868 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004869 if (oldprop != NULL)
4870 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00004871 return(prop);
4872 }
4873 prop = prop->next;
4874 }
4875 prop = xmlNewProp(node, name, value);
4876 return(prop);
4877}
4878
4879/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004880 * xmlUnsetProp:
4881 * @node: the node
4882 * @name: the attribute name
4883 *
4884 * Remove an attribute carried by a node.
4885 * Returns 0 if successful, -1 if not found
4886 */
4887int
4888xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
4889 xmlAttrPtr prop = node->properties, prev = NULL;;
4890
4891 if ((node == NULL) || (name == NULL))
4892 return(-1);
4893 while (prop != NULL) {
4894 if ((xmlStrEqual(prop->name, name)) &&
4895 (prop->ns == NULL)) {
4896 if (prev == NULL)
4897 node->properties = prop->next;
4898 else
4899 prev->next = prop->next;
4900 xmlFreeProp(prop);
4901 return(0);
4902 }
4903 prev = prop;
4904 prop = prop->next;
4905 }
4906 return(-1);
4907}
4908
4909/**
Owen Taylor3473f882001-02-23 17:55:21 +00004910 * xmlSetNsProp:
4911 * @node: the node
4912 * @ns: the namespace definition
4913 * @name: the attribute name
4914 * @value: the attribute value
4915 *
4916 * Set (or reset) an attribute carried by a node.
4917 * The ns structure must be in scope, this is not checked.
4918 *
4919 * Returns the attribute pointer.
4920 */
4921xmlAttrPtr
4922xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
4923 const xmlChar *value) {
4924 xmlAttrPtr prop;
4925
4926 if ((node == NULL) || (name == NULL))
4927 return(NULL);
4928
4929 if (ns == NULL)
4930 return(xmlSetProp(node, name, value));
4931 if (ns->href == NULL)
4932 return(NULL);
4933 prop = node->properties;
4934
4935 while (prop != NULL) {
4936 /*
4937 * One need to have
4938 * - same attribute names
4939 * - and the attribute carrying that namespace
4940 * or
4941 * no namespace on the attribute and the element carrying it
4942 */
4943 if ((xmlStrEqual(prop->name, name)) &&
4944 (((prop->ns == NULL) && (node->ns != NULL) &&
4945 (xmlStrEqual(node->ns->href, ns->href))) ||
4946 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4947 if (prop->children != NULL)
4948 xmlFreeNodeList(prop->children);
4949 prop->children = NULL;
4950 prop->last = NULL;
4951 prop->ns = ns;
4952 if (value != NULL) {
4953 xmlChar *buffer;
4954 xmlNodePtr tmp;
4955
4956 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4957 prop->children = xmlStringGetNodeList(node->doc, buffer);
4958 prop->last = NULL;
4959 tmp = prop->children;
4960 while (tmp != NULL) {
4961 tmp->parent = (xmlNodePtr) prop;
4962 if (tmp->next == NULL)
4963 prop->last = tmp;
4964 tmp = tmp->next;
4965 }
4966 xmlFree(buffer);
4967 }
4968 return(prop);
4969 }
4970 prop = prop->next;
4971 }
4972 prop = xmlNewNsProp(node, ns, name, value);
4973 return(prop);
4974}
4975
4976/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004977 * xmlUnsetNsProp:
4978 * @node: the node
4979 * @ns: the namespace definition
4980 * @name: the attribute name
4981 *
4982 * Remove an attribute carried by a node.
4983 * Returns 0 if successful, -1 if not found
4984 */
4985int
4986xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
4987 xmlAttrPtr prop = node->properties, prev = NULL;;
4988
4989 if ((node == NULL) || (name == NULL))
4990 return(-1);
4991 if (ns == NULL)
4992 return(xmlUnsetProp(node, name));
4993 if (ns->href == NULL)
4994 return(-1);
4995 while (prop != NULL) {
4996 if ((xmlStrEqual(prop->name, name)) &&
4997 (((prop->ns == NULL) && (node->ns != NULL) &&
4998 (xmlStrEqual(node->ns->href, ns->href))) ||
4999 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
5000 if (prev == NULL)
5001 node->properties = prop->next;
5002 else
5003 prev->next = prop->next;
5004 xmlFreeProp(prop);
5005 return(0);
5006 }
5007 prev = prop;
5008 prop = prop->next;
5009 }
5010 return(-1);
5011}
5012
5013/**
Owen Taylor3473f882001-02-23 17:55:21 +00005014 * xmlNodeIsText:
5015 * @node: the node
5016 *
5017 * Is this node a Text node ?
5018 * Returns 1 yes, 0 no
5019 */
5020int
5021xmlNodeIsText(xmlNodePtr node) {
5022 if (node == NULL) return(0);
5023
5024 if (node->type == XML_TEXT_NODE) return(1);
5025 return(0);
5026}
5027
5028/**
5029 * xmlIsBlankNode:
5030 * @node: the node
5031 *
5032 * Checks whether this node is an empty or whitespace only
5033 * (and possibly ignorable) text-node.
5034 *
5035 * Returns 1 yes, 0 no
5036 */
5037int
5038xmlIsBlankNode(xmlNodePtr node) {
5039 const xmlChar *cur;
5040 if (node == NULL) return(0);
5041
Daniel Veillard7db37732001-07-12 01:20:08 +00005042 if ((node->type != XML_TEXT_NODE) &&
5043 (node->type != XML_CDATA_SECTION_NODE))
5044 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005045 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005046 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005047 while (*cur != 0) {
5048 if (!IS_BLANK(*cur)) return(0);
5049 cur++;
5050 }
5051
5052 return(1);
5053}
5054
5055/**
5056 * xmlTextConcat:
5057 * @node: the node
5058 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005059 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005060 *
5061 * Concat the given string at the end of the existing node content
5062 */
5063
5064void
5065xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5066 if (node == NULL) return;
5067
5068 if ((node->type != XML_TEXT_NODE) &&
5069 (node->type != XML_CDATA_SECTION_NODE)) {
5070#ifdef DEBUG_TREE
5071 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005072 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005073#endif
5074 return;
5075 }
Owen Taylor3473f882001-02-23 17:55:21 +00005076 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005077}
5078
5079/************************************************************************
5080 * *
5081 * Output : to a FILE or in memory *
5082 * *
5083 ************************************************************************/
5084
Owen Taylor3473f882001-02-23 17:55:21 +00005085/**
5086 * xmlBufferCreate:
5087 *
5088 * routine to create an XML buffer.
5089 * returns the new structure.
5090 */
5091xmlBufferPtr
5092xmlBufferCreate(void) {
5093 xmlBufferPtr ret;
5094
5095 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5096 if (ret == NULL) {
5097 xmlGenericError(xmlGenericErrorContext,
5098 "xmlBufferCreate : out of memory!\n");
5099 return(NULL);
5100 }
5101 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005102 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005103 ret->alloc = xmlBufferAllocScheme;
5104 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5105 if (ret->content == NULL) {
5106 xmlGenericError(xmlGenericErrorContext,
5107 "xmlBufferCreate : out of memory!\n");
5108 xmlFree(ret);
5109 return(NULL);
5110 }
5111 ret->content[0] = 0;
5112 return(ret);
5113}
5114
5115/**
5116 * xmlBufferCreateSize:
5117 * @size: initial size of buffer
5118 *
5119 * routine to create an XML buffer.
5120 * returns the new structure.
5121 */
5122xmlBufferPtr
5123xmlBufferCreateSize(size_t size) {
5124 xmlBufferPtr ret;
5125
5126 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5127 if (ret == NULL) {
5128 xmlGenericError(xmlGenericErrorContext,
5129 "xmlBufferCreate : out of memory!\n");
5130 return(NULL);
5131 }
5132 ret->use = 0;
5133 ret->alloc = xmlBufferAllocScheme;
5134 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5135 if (ret->size){
5136 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5137 if (ret->content == NULL) {
5138 xmlGenericError(xmlGenericErrorContext,
5139 "xmlBufferCreate : out of memory!\n");
5140 xmlFree(ret);
5141 return(NULL);
5142 }
5143 ret->content[0] = 0;
5144 } else
5145 ret->content = NULL;
5146 return(ret);
5147}
5148
5149/**
5150 * xmlBufferSetAllocationScheme:
5151 * @buf: the buffer to free
5152 * @scheme: allocation scheme to use
5153 *
5154 * Sets the allocation scheme for this buffer
5155 */
5156void
5157xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5158 xmlBufferAllocationScheme scheme) {
5159 if (buf == NULL) {
5160#ifdef DEBUG_BUFFER
5161 xmlGenericError(xmlGenericErrorContext,
5162 "xmlBufferSetAllocationScheme: buf == NULL\n");
5163#endif
5164 return;
5165 }
5166
5167 buf->alloc = scheme;
5168}
5169
5170/**
5171 * xmlBufferFree:
5172 * @buf: the buffer to free
5173 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005174 * Frees an XML buffer. It frees both the content and the structure which
5175 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005176 */
5177void
5178xmlBufferFree(xmlBufferPtr buf) {
5179 if (buf == NULL) {
5180#ifdef DEBUG_BUFFER
5181 xmlGenericError(xmlGenericErrorContext,
5182 "xmlBufferFree: buf == NULL\n");
5183#endif
5184 return;
5185 }
5186 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005187 xmlFree(buf->content);
5188 }
Owen Taylor3473f882001-02-23 17:55:21 +00005189 xmlFree(buf);
5190}
5191
5192/**
5193 * xmlBufferEmpty:
5194 * @buf: the buffer
5195 *
5196 * empty a buffer.
5197 */
5198void
5199xmlBufferEmpty(xmlBufferPtr buf) {
5200 if (buf->content == NULL) return;
5201 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005202 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005203}
5204
5205/**
5206 * xmlBufferShrink:
5207 * @buf: the buffer to dump
5208 * @len: the number of xmlChar to remove
5209 *
5210 * Remove the beginning of an XML buffer.
5211 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005212 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005213 */
5214int
5215xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5216 if (len == 0) return(0);
5217 if (len > buf->use) return(-1);
5218
5219 buf->use -= len;
5220 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5221
5222 buf->content[buf->use] = 0;
5223 return(len);
5224}
5225
5226/**
5227 * xmlBufferGrow:
5228 * @buf: the buffer
5229 * @len: the minimum free size to allocate
5230 *
5231 * Grow the available space of an XML buffer.
5232 *
5233 * Returns the new available space or -1 in case of error
5234 */
5235int
5236xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5237 int size;
5238 xmlChar *newbuf;
5239
5240 if (len + buf->use < buf->size) return(0);
5241
5242 size = buf->use + len + 100;
5243
5244 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5245 if (newbuf == NULL) return(-1);
5246 buf->content = newbuf;
5247 buf->size = size;
5248 return(buf->size - buf->use);
5249}
5250
5251/**
5252 * xmlBufferDump:
5253 * @file: the file output
5254 * @buf: the buffer to dump
5255 *
5256 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005257 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005258 */
5259int
5260xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5261 int ret;
5262
5263 if (buf == NULL) {
5264#ifdef DEBUG_BUFFER
5265 xmlGenericError(xmlGenericErrorContext,
5266 "xmlBufferDump: buf == NULL\n");
5267#endif
5268 return(0);
5269 }
5270 if (buf->content == NULL) {
5271#ifdef DEBUG_BUFFER
5272 xmlGenericError(xmlGenericErrorContext,
5273 "xmlBufferDump: buf->content == NULL\n");
5274#endif
5275 return(0);
5276 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005277 if (file == NULL)
5278 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005279 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5280 return(ret);
5281}
5282
5283/**
5284 * xmlBufferContent:
5285 * @buf: the buffer
5286 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005287 * Function to extract the content of a buffer
5288 *
Owen Taylor3473f882001-02-23 17:55:21 +00005289 * Returns the internal content
5290 */
5291
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005292const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005293xmlBufferContent(const xmlBufferPtr buf)
5294{
5295 if(!buf)
5296 return NULL;
5297
5298 return buf->content;
5299}
5300
5301/**
5302 * xmlBufferLength:
5303 * @buf: the buffer
5304 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005305 * Function to get the length of a buffer
5306 *
Owen Taylor3473f882001-02-23 17:55:21 +00005307 * Returns the length of data in the internal content
5308 */
5309
5310int
5311xmlBufferLength(const xmlBufferPtr buf)
5312{
5313 if(!buf)
5314 return 0;
5315
5316 return buf->use;
5317}
5318
5319/**
5320 * xmlBufferResize:
5321 * @buf: the buffer to resize
5322 * @size: the desired size
5323 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005324 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005325 *
5326 * Returns 0 in case of problems, 1 otherwise
5327 */
5328int
5329xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5330{
5331 unsigned int newSize;
5332 xmlChar* rebuf = NULL;
5333
5334 /*take care of empty case*/
5335 newSize = (buf->size ? buf->size*2 : size);
5336
5337 /* Don't resize if we don't have to */
5338 if (size < buf->size)
5339 return 1;
5340
5341 /* figure out new size */
5342 switch (buf->alloc){
5343 case XML_BUFFER_ALLOC_DOUBLEIT:
5344 while (size > newSize) newSize *= 2;
5345 break;
5346 case XML_BUFFER_ALLOC_EXACT:
5347 newSize = size+10;
5348 break;
5349 default:
5350 newSize = size+10;
5351 break;
5352 }
5353
5354 if (buf->content == NULL)
5355 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5356 else
5357 rebuf = (xmlChar *) xmlRealloc(buf->content,
5358 newSize * sizeof(xmlChar));
5359 if (rebuf == NULL) {
5360 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005361 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005362 return 0;
5363 }
5364 buf->content = rebuf;
5365 buf->size = newSize;
5366
5367 return 1;
5368}
5369
5370/**
5371 * xmlBufferAdd:
5372 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005373 * @str: the #xmlChar string
5374 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005375 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005376 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005377 * str is recomputed.
5378 */
5379void
5380xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5381 unsigned int needSize;
5382
5383 if (str == NULL) {
5384#ifdef DEBUG_BUFFER
5385 xmlGenericError(xmlGenericErrorContext,
5386 "xmlBufferAdd: str == NULL\n");
5387#endif
5388 return;
5389 }
5390 if (len < -1) {
5391#ifdef DEBUG_BUFFER
5392 xmlGenericError(xmlGenericErrorContext,
5393 "xmlBufferAdd: len < 0\n");
5394#endif
5395 return;
5396 }
5397 if (len == 0) return;
5398
5399 if (len < 0)
5400 len = xmlStrlen(str);
5401
5402 if (len <= 0) return;
5403
5404 needSize = buf->use + len + 2;
5405 if (needSize > buf->size){
5406 if (!xmlBufferResize(buf, needSize)){
5407 xmlGenericError(xmlGenericErrorContext,
5408 "xmlBufferAdd : out of memory!\n");
5409 return;
5410 }
5411 }
5412
5413 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5414 buf->use += len;
5415 buf->content[buf->use] = 0;
5416}
5417
5418/**
5419 * xmlBufferAddHead:
5420 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005421 * @str: the #xmlChar string
5422 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005423 *
5424 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005425 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005426 */
5427void
5428xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5429 unsigned int needSize;
5430
5431 if (str == NULL) {
5432#ifdef DEBUG_BUFFER
5433 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005434 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005435#endif
5436 return;
5437 }
5438 if (len < -1) {
5439#ifdef DEBUG_BUFFER
5440 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005441 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005442#endif
5443 return;
5444 }
5445 if (len == 0) return;
5446
5447 if (len < 0)
5448 len = xmlStrlen(str);
5449
5450 if (len <= 0) return;
5451
5452 needSize = buf->use + len + 2;
5453 if (needSize > buf->size){
5454 if (!xmlBufferResize(buf, needSize)){
5455 xmlGenericError(xmlGenericErrorContext,
5456 "xmlBufferAddHead : out of memory!\n");
5457 return;
5458 }
5459 }
5460
5461 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5462 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5463 buf->use += len;
5464 buf->content[buf->use] = 0;
5465}
5466
5467/**
5468 * xmlBufferCat:
5469 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005470 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005471 *
5472 * Append a zero terminated string to an XML buffer.
5473 */
5474void
5475xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5476 if (str != NULL)
5477 xmlBufferAdd(buf, str, -1);
5478}
5479
5480/**
5481 * xmlBufferCCat:
5482 * @buf: the buffer to dump
5483 * @str: the C char string
5484 *
5485 * Append a zero terminated C string to an XML buffer.
5486 */
5487void
5488xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5489 const char *cur;
5490
5491 if (str == NULL) {
5492#ifdef DEBUG_BUFFER
5493 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005494 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005495#endif
5496 return;
5497 }
5498 for (cur = str;*cur != 0;cur++) {
5499 if (buf->use + 10 >= buf->size) {
5500 if (!xmlBufferResize(buf, buf->use+10)){
5501 xmlGenericError(xmlGenericErrorContext,
5502 "xmlBufferCCat : out of memory!\n");
5503 return;
5504 }
5505 }
5506 buf->content[buf->use++] = *cur;
5507 }
5508 buf->content[buf->use] = 0;
5509}
5510
5511/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005512 * xmlBufferWriteXmlCHAR:
5513 * @buf: the XML buffer
5514 * @string: the string to add
5515 *
5516 * For VMS only.
5517 * routine which manages and grows an output buffer. This one adds
5518 * xmlChars at the end of the buffer.
5519 */
5520/**
Owen Taylor3473f882001-02-23 17:55:21 +00005521 * xmlBufferWriteCHAR:
5522 * @buf: the XML buffer
5523 * @string: the string to add
5524 *
5525 * routine which manages and grows an output buffer. This one adds
5526 * xmlChars at the end of the buffer.
5527 */
5528void
5529#ifdef VMS
5530xmlBufferWriteXmlCHAR
5531#else
5532xmlBufferWriteCHAR
5533#endif
5534(xmlBufferPtr buf, const xmlChar *string) {
5535 xmlBufferCat(buf, string);
5536}
5537
5538/**
5539 * xmlBufferWriteChar:
5540 * @buf: the XML buffer output
5541 * @string: the string to add
5542 *
5543 * routine which manage and grows an output buffer. This one add
5544 * C chars at the end of the array.
5545 */
5546void
5547xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5548 xmlBufferCCat(buf, string);
5549}
5550
5551
5552/**
5553 * xmlBufferWriteQuotedString:
5554 * @buf: the XML buffer output
5555 * @string: the string to add
5556 *
5557 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005558 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005559 * quote or double-quotes internally
5560 */
5561void
5562xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5563 if (xmlStrchr(string, '"')) {
5564 if (xmlStrchr(string, '\'')) {
5565#ifdef DEBUG_BUFFER
5566 xmlGenericError(xmlGenericErrorContext,
5567 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5568#endif
5569 }
5570 xmlBufferCCat(buf, "'");
5571 xmlBufferCat(buf, string);
5572 xmlBufferCCat(buf, "'");
5573 } else {
5574 xmlBufferCCat(buf, "\"");
5575 xmlBufferCat(buf, string);
5576 xmlBufferCCat(buf, "\"");
5577 }
5578}
5579
5580
5581/************************************************************************
5582 * *
5583 * Dumping XML tree content to a simple buffer *
5584 * *
5585 ************************************************************************/
5586
Owen Taylor3473f882001-02-23 17:55:21 +00005587static void
5588xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5589 int format);
5590void
5591htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5592
5593/**
5594 * xmlNsDump:
5595 * @buf: the XML buffer output
5596 * @cur: a namespace
5597 *
5598 * Dump a local Namespace definition.
5599 * Should be called in the context of attributes dumps.
5600 */
5601static void
5602xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5603 if (cur == NULL) {
5604#ifdef DEBUG_TREE
5605 xmlGenericError(xmlGenericErrorContext,
5606 "xmlNsDump : Ns == NULL\n");
5607#endif
5608 return;
5609 }
5610 if (cur->type == XML_LOCAL_NAMESPACE) {
5611 /* Within the context of an element attributes */
5612 if (cur->prefix != NULL) {
5613 xmlBufferWriteChar(buf, " xmlns:");
5614 xmlBufferWriteCHAR(buf, cur->prefix);
5615 } else
5616 xmlBufferWriteChar(buf, " xmlns");
5617 xmlBufferWriteChar(buf, "=");
5618 xmlBufferWriteQuotedString(buf, cur->href);
5619 }
5620}
5621
5622/**
5623 * xmlNsListDump:
5624 * @buf: the XML buffer output
5625 * @cur: the first namespace
5626 *
5627 * Dump a list of local Namespace definitions.
5628 * Should be called in the context of attributes dumps.
5629 */
5630static void
5631xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5632 while (cur != NULL) {
5633 xmlNsDump(buf, cur);
5634 cur = cur->next;
5635 }
5636}
5637
5638/**
5639 * xmlDtdDump:
5640 * @buf: the XML buffer output
Daniel Veillardd1640922001-12-17 15:30:10 +00005641 * @dtd: the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00005642 *
5643 * Dump the XML document DTD, if any.
5644 */
5645static void
5646xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5647 if (dtd == NULL) {
5648#ifdef DEBUG_TREE
5649 xmlGenericError(xmlGenericErrorContext,
5650 "xmlDtdDump : no internal subset\n");
5651#endif
5652 return;
5653 }
5654 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5655 xmlBufferWriteCHAR(buf, dtd->name);
5656 if (dtd->ExternalID != NULL) {
5657 xmlBufferWriteChar(buf, " PUBLIC ");
5658 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5659 xmlBufferWriteChar(buf, " ");
5660 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5661 } else if (dtd->SystemID != NULL) {
5662 xmlBufferWriteChar(buf, " SYSTEM ");
5663 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5664 }
5665 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5666 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5667 xmlBufferWriteChar(buf, ">");
5668 return;
5669 }
5670 xmlBufferWriteChar(buf, " [\n");
5671 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5672#if 0
5673 if (dtd->entities != NULL)
5674 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5675 if (dtd->notations != NULL)
5676 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5677 if (dtd->elements != NULL)
5678 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5679 if (dtd->attributes != NULL)
5680 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5681#endif
5682 xmlBufferWriteChar(buf, "]>");
5683}
5684
5685/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00005686 * xmlAttrSerializeContent:
5687 * @buf: the XML buffer output
5688 * @doc: the document
5689 * @attr: the attribute pointer
5690 *
5691 * Serialize the attribute in the buffer
5692 */
5693static void
5694xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr) {
5695 const xmlChar *cur, *base;
5696 xmlNodePtr children;
5697
5698 children = attr->children;
5699 while (children != NULL) {
5700 switch (children->type) {
5701 case XML_TEXT_NODE:
5702 base = cur = children->content;
5703 while (*cur != 0) {
5704 if (*cur == '\n') {
5705 if (base != cur)
5706 xmlBufferAdd(buf, base, cur - base);
5707 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
5708 cur++;
5709 base = cur;
5710#if 0
5711 } else if (*cur == '\'') {
5712 if (base != cur)
5713 xmlBufferAdd(buf, base, cur - base);
5714 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
5715 cur++;
5716 base = cur;
5717#endif
5718 } else if (*cur == '"') {
5719 if (base != cur)
5720 xmlBufferAdd(buf, base, cur - base);
5721 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
5722 cur++;
5723 base = cur;
5724 } else if (*cur == '<') {
5725 if (base != cur)
5726 xmlBufferAdd(buf, base, cur - base);
5727 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
5728 cur++;
5729 base = cur;
5730 } else if (*cur == '>') {
5731 if (base != cur)
5732 xmlBufferAdd(buf, base, cur - base);
5733 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
5734 cur++;
5735 base = cur;
5736 } else if (*cur == '&') {
5737 if (base != cur)
5738 xmlBufferAdd(buf, base, cur - base);
5739 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
5740 cur++;
5741 base = cur;
5742 } else if ((*cur >= 0x80) && ((doc == NULL) ||
5743 (doc->encoding == NULL))) {
5744 /*
5745 * We assume we have UTF-8 content.
5746 */
5747 char tmp[10];
5748 int val = 0, l = 1;
5749
5750 if (base != cur)
5751 xmlBufferAdd(buf, base, cur - base);
5752 if (*cur < 0xC0) {
5753 xmlGenericError(xmlGenericErrorContext,
5754 "xmlAttrSerializeContent : input not UTF-8\n");
5755 if (doc != NULL)
5756 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
5757 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
5758 tmp[sizeof(tmp) - 1] = 0;
5759 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
5760 cur++;
5761 base = cur;
5762 continue;
5763 } else if (*cur < 0xE0) {
5764 val = (cur[0]) & 0x1F;
5765 val <<= 6;
5766 val |= (cur[1]) & 0x3F;
5767 l = 2;
5768 } else if (*cur < 0xF0) {
5769 val = (cur[0]) & 0x0F;
5770 val <<= 6;
5771 val |= (cur[1]) & 0x3F;
5772 val <<= 6;
5773 val |= (cur[2]) & 0x3F;
5774 l = 3;
5775 } else if (*cur < 0xF8) {
5776 val = (cur[0]) & 0x07;
5777 val <<= 6;
5778 val |= (cur[1]) & 0x3F;
5779 val <<= 6;
5780 val |= (cur[2]) & 0x3F;
5781 val <<= 6;
5782 val |= (cur[3]) & 0x3F;
5783 l = 4;
5784 }
5785 if ((l == 1) || (!IS_CHAR(val))) {
5786 xmlGenericError(xmlGenericErrorContext,
5787 "xmlAttrSerializeContent : char out of range\n");
5788 if (doc != NULL)
5789 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
5790 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
5791 tmp[sizeof(tmp) - 1] = 0;
5792 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
5793 cur++;
5794 base = cur;
5795 continue;
5796 }
5797 /*
5798 * We could do multiple things here. Just save
5799 * as a char ref
5800 */
5801 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
5802 tmp[sizeof(tmp) - 1] = 0;
5803 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
5804 cur += l;
5805 base = cur;
5806 } else {
5807 cur++;
5808 }
5809 }
5810 if (base != cur)
5811 xmlBufferAdd(buf, base, cur - base);
5812 break;
5813 case XML_ENTITY_REF_NODE:
5814 xmlBufferAdd(buf, BAD_CAST "&", 1);
5815 xmlBufferAdd(buf, children->name, xmlStrlen(children->name));
5816 xmlBufferAdd(buf, BAD_CAST ";", 1);
5817 break;
5818 default:
5819 /* should not happen unless we have a badly built tree */
5820 break;
5821 }
5822 children = children->next;
5823 }
5824}
5825
5826/**
Owen Taylor3473f882001-02-23 17:55:21 +00005827 * xmlAttrDump:
5828 * @buf: the XML buffer output
5829 * @doc: the document
5830 * @cur: the attribute pointer
5831 *
5832 * Dump an XML attribute
5833 */
5834static void
5835xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00005836 if (cur == NULL) {
5837#ifdef DEBUG_TREE
5838 xmlGenericError(xmlGenericErrorContext,
5839 "xmlAttrDump : property == NULL\n");
5840#endif
5841 return;
5842 }
5843 xmlBufferWriteChar(buf, " ");
5844 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5845 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5846 xmlBufferWriteChar(buf, ":");
5847 }
5848 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00005849 xmlBufferWriteChar(buf, "=\"");
5850 xmlAttrSerializeContent(buf, doc, cur);
5851 xmlBufferWriteChar(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00005852}
5853
5854/**
5855 * xmlAttrListDump:
5856 * @buf: the XML buffer output
5857 * @doc: the document
5858 * @cur: the first attribute pointer
5859 *
5860 * Dump a list of XML attributes
5861 */
5862static void
5863xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5864 if (cur == NULL) {
5865#ifdef DEBUG_TREE
5866 xmlGenericError(xmlGenericErrorContext,
5867 "xmlAttrListDump : property == NULL\n");
5868#endif
5869 return;
5870 }
5871 while (cur != NULL) {
5872 xmlAttrDump(buf, doc, cur);
5873 cur = cur->next;
5874 }
5875}
5876
5877
5878
5879/**
5880 * xmlNodeListDump:
5881 * @buf: the XML buffer output
5882 * @doc: the document
5883 * @cur: the first node
5884 * @level: the imbrication level for indenting
5885 * @format: is formatting allowed
5886 *
5887 * Dump an XML node list, recursive behaviour,children are printed too.
5888 */
5889static void
5890xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5891 int format) {
5892 int i;
5893
5894 if (cur == NULL) {
5895#ifdef DEBUG_TREE
5896 xmlGenericError(xmlGenericErrorContext,
5897 "xmlNodeListDump : node == NULL\n");
5898#endif
5899 return;
5900 }
5901 while (cur != NULL) {
5902 if ((format) && (xmlIndentTreeOutput) &&
5903 (cur->type == XML_ELEMENT_NODE))
5904 for (i = 0;i < level;i++)
5905 xmlBufferWriteChar(buf, " ");
5906 xmlNodeDump(buf, doc, cur, level, format);
5907 if (format) {
5908 xmlBufferWriteChar(buf, "\n");
5909 }
5910 cur = cur->next;
5911 }
5912}
5913
5914/**
5915 * xmlNodeDump:
5916 * @buf: the XML buffer output
5917 * @doc: the document
5918 * @cur: the current node
5919 * @level: the imbrication level for indenting
5920 * @format: is formatting allowed
5921 *
5922 * Dump an XML node, recursive behaviour,children are printed too.
5923 */
5924void
5925xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5926 int format) {
5927 int i;
5928 xmlNodePtr tmp;
5929
5930 if (cur == NULL) {
5931#ifdef DEBUG_TREE
5932 xmlGenericError(xmlGenericErrorContext,
5933 "xmlNodeDump : node == NULL\n");
5934#endif
5935 return;
5936 }
5937 if (cur->type == XML_XINCLUDE_START)
5938 return;
5939 if (cur->type == XML_XINCLUDE_END)
5940 return;
5941 if (cur->type == XML_DTD_NODE) {
5942 xmlDtdDump(buf, (xmlDtdPtr) cur);
5943 return;
5944 }
5945 if (cur->type == XML_ELEMENT_DECL) {
5946 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
5947 return;
5948 }
Daniel Veillard78d12092001-10-11 09:12:24 +00005949 if (cur->type == XML_ATTRIBUTE_NODE){
5950 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
5951 return;
5952 }
Owen Taylor3473f882001-02-23 17:55:21 +00005953 if (cur->type == XML_ATTRIBUTE_DECL) {
5954 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
5955 return;
5956 }
5957 if (cur->type == XML_ENTITY_DECL) {
5958 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
5959 return;
5960 }
5961 if (cur->type == XML_TEXT_NODE) {
5962 if (cur->content != NULL) {
5963 if ((cur->name == xmlStringText) ||
5964 (cur->name != xmlStringTextNoenc)) {
5965 xmlChar *buffer;
5966
Owen Taylor3473f882001-02-23 17:55:21 +00005967 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005968 if (buffer != NULL) {
5969 xmlBufferWriteCHAR(buf, buffer);
5970 xmlFree(buffer);
5971 }
5972 } else {
5973 /*
5974 * Disable escaping, needed for XSLT
5975 */
Owen Taylor3473f882001-02-23 17:55:21 +00005976 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005977 }
5978 }
5979 return;
5980 }
5981 if (cur->type == XML_PI_NODE) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00005982 xmlBufferWriteChar(buf, "<?");
5983 xmlBufferWriteCHAR(buf, cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005984 if (cur->content != NULL) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00005985 xmlBufferWriteChar(buf, " ");
Daniel Veillard2c748c62002-01-16 15:37:50 +00005986 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005987 }
Daniel Veillard2c748c62002-01-16 15:37:50 +00005988 xmlBufferWriteChar(buf, "?>");
Owen Taylor3473f882001-02-23 17:55:21 +00005989 return;
5990 }
5991 if (cur->type == XML_COMMENT_NODE) {
5992 if (cur->content != NULL) {
5993 xmlBufferWriteChar(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00005994 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005995 xmlBufferWriteChar(buf, "-->");
5996 }
5997 return;
5998 }
5999 if (cur->type == XML_ENTITY_REF_NODE) {
6000 xmlBufferWriteChar(buf, "&");
6001 xmlBufferWriteCHAR(buf, cur->name);
6002 xmlBufferWriteChar(buf, ";");
6003 return;
6004 }
6005 if (cur->type == XML_CDATA_SECTION_NODE) {
6006 xmlBufferWriteChar(buf, "<![CDATA[");
6007 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006008 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006009 xmlBufferWriteChar(buf, "]]>");
6010 return;
6011 }
6012
6013 if (format == 1) {
6014 tmp = cur->children;
6015 while (tmp != NULL) {
6016 if ((tmp->type == XML_TEXT_NODE) ||
6017 (tmp->type == XML_ENTITY_REF_NODE)) {
6018 format = 0;
6019 break;
6020 }
6021 tmp = tmp->next;
6022 }
6023 }
6024 xmlBufferWriteChar(buf, "<");
6025 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6026 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6027 xmlBufferWriteChar(buf, ":");
6028 }
6029
6030 xmlBufferWriteCHAR(buf, cur->name);
6031 if (cur->nsDef)
6032 xmlNsListDump(buf, cur->nsDef);
6033 if (cur->properties != NULL)
6034 xmlAttrListDump(buf, doc, cur->properties);
6035
Daniel Veillard7db37732001-07-12 01:20:08 +00006036 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6037 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00006038 (!xmlSaveNoEmptyTags)) {
6039 xmlBufferWriteChar(buf, "/>");
6040 return;
6041 }
6042 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006043 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006044 xmlChar *buffer;
6045
Owen Taylor3473f882001-02-23 17:55:21 +00006046 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006047 if (buffer != NULL) {
6048 xmlBufferWriteCHAR(buf, buffer);
6049 xmlFree(buffer);
6050 }
6051 }
6052 if (cur->children != NULL) {
6053 if (format) xmlBufferWriteChar(buf, "\n");
6054 xmlNodeListDump(buf, doc, cur->children,
6055 (level >= 0?level+1:-1), format);
6056 if ((xmlIndentTreeOutput) && (format))
6057 for (i = 0;i < level;i++)
6058 xmlBufferWriteChar(buf, " ");
6059 }
6060 xmlBufferWriteChar(buf, "</");
6061 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6062 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6063 xmlBufferWriteChar(buf, ":");
6064 }
6065
6066 xmlBufferWriteCHAR(buf, cur->name);
6067 xmlBufferWriteChar(buf, ">");
6068}
6069
6070/**
6071 * xmlElemDump:
6072 * @f: the FILE * for the output
6073 * @doc: the document
6074 * @cur: the current node
6075 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006076 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006077 */
6078void
6079xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
6080 xmlBufferPtr buf;
6081
6082 if (cur == NULL) {
6083#ifdef DEBUG_TREE
6084 xmlGenericError(xmlGenericErrorContext,
6085 "xmlElemDump : cur == NULL\n");
6086#endif
6087 return;
6088 }
Owen Taylor3473f882001-02-23 17:55:21 +00006089#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006090 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006091 xmlGenericError(xmlGenericErrorContext,
6092 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006093 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006094#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00006095
Owen Taylor3473f882001-02-23 17:55:21 +00006096 buf = xmlBufferCreate();
6097 if (buf == NULL) return;
6098 if ((doc != NULL) &&
6099 (doc->type == XML_HTML_DOCUMENT_NODE)) {
6100#ifdef LIBXML_HTML_ENABLED
6101 htmlNodeDump(buf, doc, cur);
6102#else
6103 xmlGenericError(xmlGenericErrorContext,
6104 "HTML support not compiled in\n");
6105#endif /* LIBXML_HTML_ENABLED */
6106 } else
6107 xmlNodeDump(buf, doc, cur, 0, 1);
6108 xmlBufferDump(f, buf);
6109 xmlBufferFree(buf);
6110}
6111
6112/************************************************************************
6113 * *
6114 * Dumping XML tree content to an I/O output buffer *
6115 * *
6116 ************************************************************************/
6117
Owen Taylor3473f882001-02-23 17:55:21 +00006118static void
6119xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6120 int level, int format, const char *encoding);
6121/**
6122 * xmlNsDumpOutput:
6123 * @buf: the XML buffer output
6124 * @cur: a namespace
6125 *
6126 * Dump a local Namespace definition.
6127 * Should be called in the context of attributes dumps.
6128 */
6129static void
6130xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6131 if (cur == NULL) {
6132#ifdef DEBUG_TREE
6133 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006134 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006135#endif
6136 return;
6137 }
6138 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
6139 /* Within the context of an element attributes */
6140 if (cur->prefix != NULL) {
6141 xmlOutputBufferWriteString(buf, " xmlns:");
6142 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6143 } else
6144 xmlOutputBufferWriteString(buf, " xmlns");
6145 xmlOutputBufferWriteString(buf, "=");
6146 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6147 }
6148}
6149
6150/**
6151 * xmlNsListDumpOutput:
6152 * @buf: the XML buffer output
6153 * @cur: the first namespace
6154 *
6155 * Dump a list of local Namespace definitions.
6156 * Should be called in the context of attributes dumps.
6157 */
6158static void
6159xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6160 while (cur != NULL) {
6161 xmlNsDumpOutput(buf, cur);
6162 cur = cur->next;
6163 }
6164}
6165
6166/**
6167 * xmlDtdDumpOutput:
6168 * @buf: the XML buffer output
6169 * @doc: the document
6170 * @encoding: an optional encoding string
6171 *
6172 * Dump the XML document DTD, if any.
6173 */
6174static void
6175xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6176 if (dtd == NULL) {
6177#ifdef DEBUG_TREE
6178 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006179 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006180#endif
6181 return;
6182 }
6183 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6184 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6185 if (dtd->ExternalID != NULL) {
6186 xmlOutputBufferWriteString(buf, " PUBLIC ");
6187 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6188 xmlOutputBufferWriteString(buf, " ");
6189 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6190 } else if (dtd->SystemID != NULL) {
6191 xmlOutputBufferWriteString(buf, " SYSTEM ");
6192 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6193 }
6194 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6195 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6196 xmlOutputBufferWriteString(buf, ">");
6197 return;
6198 }
6199 xmlOutputBufferWriteString(buf, " [\n");
6200 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6201 xmlOutputBufferWriteString(buf, "]>");
6202}
6203
6204/**
6205 * xmlAttrDumpOutput:
6206 * @buf: the XML buffer output
6207 * @doc: the document
6208 * @cur: the attribute pointer
6209 * @encoding: an optional encoding string
6210 *
6211 * Dump an XML attribute
6212 */
6213static void
6214xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006215 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006216 if (cur == NULL) {
6217#ifdef DEBUG_TREE
6218 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006219 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006220#endif
6221 return;
6222 }
6223 xmlOutputBufferWriteString(buf, " ");
6224 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6225 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6226 xmlOutputBufferWriteString(buf, ":");
6227 }
6228 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006229 xmlOutputBufferWriteString(buf, "=\"");
6230 xmlAttrSerializeContent(buf->buffer, doc, cur);
6231 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006232}
6233
6234/**
6235 * xmlAttrListDumpOutput:
6236 * @buf: the XML buffer output
6237 * @doc: the document
6238 * @cur: the first attribute pointer
6239 * @encoding: an optional encoding string
6240 *
6241 * Dump a list of XML attributes
6242 */
6243static void
6244xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6245 xmlAttrPtr cur, const char *encoding) {
6246 if (cur == NULL) {
6247#ifdef DEBUG_TREE
6248 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006249 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006250#endif
6251 return;
6252 }
6253 while (cur != NULL) {
6254 xmlAttrDumpOutput(buf, doc, cur, encoding);
6255 cur = cur->next;
6256 }
6257}
6258
6259
6260
6261/**
6262 * xmlNodeListDumpOutput:
6263 * @buf: the XML buffer output
6264 * @doc: the document
6265 * @cur: the first node
6266 * @level: the imbrication level for indenting
6267 * @format: is formatting allowed
6268 * @encoding: an optional encoding string
6269 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006270 * Dump an XML node list, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006271 */
6272static void
6273xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6274 xmlNodePtr cur, int level, int format, const char *encoding) {
6275 int i;
6276
6277 if (cur == NULL) {
6278#ifdef DEBUG_TREE
6279 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006280 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006281#endif
6282 return;
6283 }
6284 while (cur != NULL) {
6285 if ((format) && (xmlIndentTreeOutput) &&
6286 (cur->type == XML_ELEMENT_NODE))
6287 for (i = 0;i < level;i++)
6288 xmlOutputBufferWriteString(buf, " ");
6289 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6290 if (format) {
6291 xmlOutputBufferWriteString(buf, "\n");
6292 }
6293 cur = cur->next;
6294 }
6295}
6296
6297/**
6298 * xmlNodeDumpOutput:
6299 * @buf: the XML buffer output
6300 * @doc: the document
6301 * @cur: the current node
6302 * @level: the imbrication level for indenting
6303 * @format: is formatting allowed
6304 * @encoding: an optional encoding string
6305 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006306 * Dump an XML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006307 */
6308void
6309xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6310 int level, int format, const char *encoding) {
6311 int i;
6312 xmlNodePtr tmp;
6313
6314 if (cur == NULL) {
6315#ifdef DEBUG_TREE
6316 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006317 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006318#endif
6319 return;
6320 }
6321 if (cur->type == XML_XINCLUDE_START)
6322 return;
6323 if (cur->type == XML_XINCLUDE_END)
6324 return;
6325 if (cur->type == XML_DTD_NODE) {
6326 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6327 return;
6328 }
6329 if (cur->type == XML_ELEMENT_DECL) {
6330 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6331 return;
6332 }
6333 if (cur->type == XML_ATTRIBUTE_DECL) {
6334 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6335 return;
6336 }
6337 if (cur->type == XML_ENTITY_DECL) {
6338 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6339 return;
6340 }
6341 if (cur->type == XML_TEXT_NODE) {
6342 if (cur->content != NULL) {
6343 if ((cur->name == xmlStringText) ||
6344 (cur->name != xmlStringTextNoenc)) {
6345 xmlChar *buffer;
6346
Owen Taylor3473f882001-02-23 17:55:21 +00006347 if (encoding == NULL)
6348 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6349 else
6350 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006351 if (buffer != NULL) {
6352 xmlOutputBufferWriteString(buf, (const char *)buffer);
6353 xmlFree(buffer);
6354 }
6355 } else {
6356 /*
6357 * Disable escaping, needed for XSLT
6358 */
Owen Taylor3473f882001-02-23 17:55:21 +00006359 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006360 }
6361 }
6362
6363 return;
6364 }
6365 if (cur->type == XML_PI_NODE) {
6366 if (cur->content != NULL) {
6367 xmlOutputBufferWriteString(buf, "<?");
6368 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6369 if (cur->content != NULL) {
6370 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006371 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006372 }
6373 xmlOutputBufferWriteString(buf, "?>");
6374 } else {
6375 xmlOutputBufferWriteString(buf, "<?");
6376 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6377 xmlOutputBufferWriteString(buf, "?>");
6378 }
6379 return;
6380 }
6381 if (cur->type == XML_COMMENT_NODE) {
6382 if (cur->content != NULL) {
6383 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006384 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006385 xmlOutputBufferWriteString(buf, "-->");
6386 }
6387 return;
6388 }
6389 if (cur->type == XML_ENTITY_REF_NODE) {
6390 xmlOutputBufferWriteString(buf, "&");
6391 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6392 xmlOutputBufferWriteString(buf, ";");
6393 return;
6394 }
6395 if (cur->type == XML_CDATA_SECTION_NODE) {
6396 xmlOutputBufferWriteString(buf, "<![CDATA[");
6397 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006398 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006399 xmlOutputBufferWriteString(buf, "]]>");
6400 return;
6401 }
6402
6403 if (format == 1) {
6404 tmp = cur->children;
6405 while (tmp != NULL) {
6406 if ((tmp->type == XML_TEXT_NODE) ||
6407 (tmp->type == XML_ENTITY_REF_NODE)) {
6408 format = 0;
6409 break;
6410 }
6411 tmp = tmp->next;
6412 }
6413 }
6414 xmlOutputBufferWriteString(buf, "<");
6415 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6416 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6417 xmlOutputBufferWriteString(buf, ":");
6418 }
6419
6420 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6421 if (cur->nsDef)
6422 xmlNsListDumpOutput(buf, cur->nsDef);
6423 if (cur->properties != NULL)
6424 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6425
Daniel Veillard7db37732001-07-12 01:20:08 +00006426 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6427 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006428 xmlOutputBufferWriteString(buf, "/>");
6429 return;
6430 }
6431 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006432 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006433 xmlChar *buffer;
6434
Owen Taylor3473f882001-02-23 17:55:21 +00006435 if (encoding == NULL)
6436 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6437 else
6438 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006439 if (buffer != NULL) {
6440 xmlOutputBufferWriteString(buf, (const char *)buffer);
6441 xmlFree(buffer);
6442 }
6443 }
6444 if (cur->children != NULL) {
6445 if (format) xmlOutputBufferWriteString(buf, "\n");
6446 xmlNodeListDumpOutput(buf, doc, cur->children,
6447 (level >= 0?level+1:-1), format, encoding);
6448 if ((xmlIndentTreeOutput) && (format))
6449 for (i = 0;i < level;i++)
6450 xmlOutputBufferWriteString(buf, " ");
6451 }
6452 xmlOutputBufferWriteString(buf, "</");
6453 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6454 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6455 xmlOutputBufferWriteString(buf, ":");
6456 }
6457
6458 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6459 xmlOutputBufferWriteString(buf, ">");
6460}
6461
6462/**
6463 * xmlDocContentDumpOutput:
6464 * @buf: the XML buffer output
6465 * @cur: the document
6466 * @encoding: an optional encoding string
6467 * @format: should formatting spaces been added
6468 *
6469 * Dump an XML document.
6470 */
6471static void
6472xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6473 const char *encoding, int format) {
6474 xmlOutputBufferWriteString(buf, "<?xml version=");
6475 if (cur->version != NULL)
6476 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6477 else
6478 xmlOutputBufferWriteString(buf, "\"1.0\"");
6479 if (encoding == NULL) {
6480 if (cur->encoding != NULL)
6481 encoding = (const char *) cur->encoding;
6482 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6483 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6484 }
6485 if (encoding != NULL) {
6486 xmlOutputBufferWriteString(buf, " encoding=");
6487 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6488 }
6489 switch (cur->standalone) {
6490 case 0:
6491 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6492 break;
6493 case 1:
6494 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6495 break;
6496 }
6497 xmlOutputBufferWriteString(buf, "?>\n");
6498 if (cur->children != NULL) {
6499 xmlNodePtr child = cur->children;
6500
6501 while (child != NULL) {
6502 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6503 xmlOutputBufferWriteString(buf, "\n");
6504 child = child->next;
6505 }
6506 }
6507}
6508
6509/************************************************************************
6510 * *
6511 * Saving functions front-ends *
6512 * *
6513 ************************************************************************/
6514
6515/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006516 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006517 * @out_doc: Document to generate XML text from
6518 * @doc_txt_ptr: Memory pointer for allocated XML text
6519 * @doc_txt_len: Length of the generated XML text
6520 * @txt_encoding: Character encoding to use when generating XML text
6521 * @format: should formatting spaces been added
6522 *
6523 * Dump the current DOM tree into memory using the character encoding specified
6524 * by the caller. Note it is up to the caller of this function to free the
6525 * allocated memory.
6526 */
6527
6528void
6529xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006530 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006531 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006532 int dummy = 0;
6533
6534 xmlCharEncoding doc_charset;
6535 xmlOutputBufferPtr out_buff = NULL;
6536 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6537
6538 if (doc_txt_len == NULL) {
6539 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6540 }
6541
6542 if (doc_txt_ptr == NULL) {
6543 *doc_txt_len = 0;
6544 xmlGenericError(xmlGenericErrorContext,
6545 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6546 return;
6547 }
6548
6549 *doc_txt_ptr = NULL;
6550 *doc_txt_len = 0;
6551
6552 if (out_doc == NULL) {
6553 /* No document, no output */
6554 xmlGenericError(xmlGenericErrorContext,
6555 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6556 return;
6557 }
6558
6559 /*
6560 * Validate the encoding value, if provided.
6561 * This logic is copied from xmlSaveFileEnc.
6562 */
6563
6564 if (txt_encoding == NULL)
6565 txt_encoding = (const char *) out_doc->encoding;
6566 if (txt_encoding != NULL) {
6567 doc_charset = xmlParseCharEncoding(txt_encoding);
6568
6569 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6570 xmlGenericError(xmlGenericErrorContext,
6571 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6572 return;
6573
6574 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6575 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6576 if ( conv_hdlr == NULL ) {
6577 xmlGenericError(xmlGenericErrorContext,
6578 "%s: %s %s '%s'\n",
6579 "xmlDocDumpFormatMemoryEnc",
6580 "Failed to identify encoding handler for",
6581 "character set",
6582 txt_encoding);
6583 return;
6584 }
6585 }
6586 }
6587
6588 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6589 xmlGenericError(xmlGenericErrorContext,
6590 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6591 return;
6592 }
6593
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006594 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006595 xmlOutputBufferFlush(out_buff);
6596 if (out_buff->conv != NULL) {
6597 *doc_txt_len = out_buff->conv->use;
6598 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6599 } else {
6600 *doc_txt_len = out_buff->buffer->use;
6601 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6602 }
6603 (void)xmlOutputBufferClose(out_buff);
6604
6605 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6606 *doc_txt_len = 0;
6607 xmlGenericError(xmlGenericErrorContext,
6608 "xmlDocDumpFormatMemoryEnc: %s\n",
6609 "Failed to allocate memory for document text representation.");
6610 }
6611
6612 return;
6613}
6614
6615/**
6616 * xmlDocDumpMemory:
6617 * @cur: the document
6618 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006619 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006620 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006621 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006622 * It's up to the caller to free the memory.
6623 */
6624void
6625xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6626 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6627}
6628
6629/**
6630 * xmlDocDumpFormatMemory:
6631 * @cur: the document
6632 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006633 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006634 * @format: should formatting spaces been added
6635 *
6636 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006637 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006638 * It's up to the caller to free the memory.
6639 */
6640void
6641xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6642 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6643}
6644
6645/**
6646 * xmlDocDumpMemoryEnc:
6647 * @out_doc: Document to generate XML text from
6648 * @doc_txt_ptr: Memory pointer for allocated XML text
6649 * @doc_txt_len: Length of the generated XML text
6650 * @txt_encoding: Character encoding to use when generating XML text
6651 *
6652 * Dump the current DOM tree into memory using the character encoding specified
6653 * by the caller. Note it is up to the caller of this function to free the
6654 * allocated memory.
6655 */
6656
6657void
6658xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6659 int * doc_txt_len, const char * txt_encoding) {
6660 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006661 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006662}
6663
6664/**
6665 * xmlGetDocCompressMode:
6666 * @doc: the document
6667 *
6668 * get the compression ratio for a document, ZLIB based
6669 * Returns 0 (uncompressed) to 9 (max compression)
6670 */
6671int
6672xmlGetDocCompressMode (xmlDocPtr doc) {
6673 if (doc == NULL) return(-1);
6674 return(doc->compression);
6675}
6676
6677/**
6678 * xmlSetDocCompressMode:
6679 * @doc: the document
6680 * @mode: the compression ratio
6681 *
6682 * set the compression ratio for a document, ZLIB based
6683 * Correct values: 0 (uncompressed) to 9 (max compression)
6684 */
6685void
6686xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6687 if (doc == NULL) return;
6688 if (mode < 0) doc->compression = 0;
6689 else if (mode > 9) doc->compression = 9;
6690 else doc->compression = mode;
6691}
6692
6693/**
6694 * xmlGetCompressMode:
6695 *
6696 * get the default compression mode used, ZLIB based.
6697 * Returns 0 (uncompressed) to 9 (max compression)
6698 */
6699int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00006700xmlGetCompressMode(void)
6701{
6702 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00006703}
6704
6705/**
6706 * xmlSetCompressMode:
6707 * @mode: the compression ratio
6708 *
6709 * set the default compression mode used, ZLIB based
6710 * Correct values: 0 (uncompressed) to 9 (max compression)
6711 */
6712void
6713xmlSetCompressMode(int mode) {
6714 if (mode < 0) xmlCompressMode = 0;
6715 else if (mode > 9) xmlCompressMode = 9;
6716 else xmlCompressMode = mode;
6717}
6718
6719/**
6720 * xmlDocDump:
6721 * @f: the FILE*
6722 * @cur: the document
6723 *
6724 * Dump an XML document to an open FILE.
6725 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006726 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006727 */
6728int
6729xmlDocDump(FILE *f, xmlDocPtr cur) {
6730 xmlOutputBufferPtr buf;
6731 const char * encoding;
6732 xmlCharEncodingHandlerPtr handler = NULL;
6733 int ret;
6734
6735 if (cur == NULL) {
6736#ifdef DEBUG_TREE
6737 xmlGenericError(xmlGenericErrorContext,
6738 "xmlDocDump : document == NULL\n");
6739#endif
6740 return(-1);
6741 }
6742 encoding = (const char *) cur->encoding;
6743
6744 if (encoding != NULL) {
6745 xmlCharEncoding enc;
6746
6747 enc = xmlParseCharEncoding(encoding);
6748
6749 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6750 xmlGenericError(xmlGenericErrorContext,
6751 "xmlDocDump: document not in UTF8\n");
6752 return(-1);
6753 }
6754 if (enc != XML_CHAR_ENCODING_UTF8) {
6755 handler = xmlFindCharEncodingHandler(encoding);
6756 if (handler == NULL) {
6757 xmlFree((char *) cur->encoding);
6758 cur->encoding = NULL;
6759 }
6760 }
6761 }
6762 buf = xmlOutputBufferCreateFile(f, handler);
6763 if (buf == NULL) return(-1);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006764 xmlDocContentDumpOutput(buf, cur, NULL, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006765
6766 ret = xmlOutputBufferClose(buf);
6767 return(ret);
6768}
6769
6770/**
6771 * xmlSaveFileTo:
6772 * @buf: an output I/O buffer
6773 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00006774 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00006775 *
6776 * Dump an XML document to an I/O buffer.
6777 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006778 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006779 */
6780int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006781xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006782 int ret;
6783
6784 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006785 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006786 ret = xmlOutputBufferClose(buf);
6787 return(ret);
6788}
6789
6790/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00006791 * xmlSaveFormatFileTo:
6792 * @buf: an output I/O buffer
6793 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00006794 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00006795 * @format: should formatting spaces been added
6796 *
6797 * Dump an XML document to an I/O buffer.
6798 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006799 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00006800 */
6801int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006802xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00006803 int ret;
6804
6805 if (buf == NULL) return(0);
6806 xmlDocContentDumpOutput(buf, cur, encoding, format);
6807 ret = xmlOutputBufferClose(buf);
6808 return(ret);
6809}
6810
6811/**
Daniel Veillardf012a642001-07-23 19:10:52 +00006812 * xmlSaveFormatFileEnc
6813 * @filename: the filename or URL to output
6814 * @cur: the document being saved
6815 * @encoding: the name of the encoding to use or NULL.
6816 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00006817 *
6818 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00006819 */
6820int
Daniel Veillardf012a642001-07-23 19:10:52 +00006821xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
6822 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00006823 xmlOutputBufferPtr buf;
6824 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00006825 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00006826 int ret;
6827
Daniel Veillardfb25a512002-01-13 20:32:08 +00006828 if (encoding == NULL)
6829 encoding = (const char *) cur->encoding;
6830
Owen Taylor3473f882001-02-23 17:55:21 +00006831 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006832
6833 enc = xmlParseCharEncoding(encoding);
6834 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6835 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006836 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006837 return(-1);
6838 }
6839 if (enc != XML_CHAR_ENCODING_UTF8) {
6840 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00006841 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006842 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006843 }
6844 }
6845
Daniel Veillardf012a642001-07-23 19:10:52 +00006846#ifdef HAVE_ZLIB_H
6847 if (cur->compression < 0) cur->compression = xmlCompressMode;
6848#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006849 /*
6850 * save the content to a temp buffer.
6851 */
Daniel Veillardf012a642001-07-23 19:10:52 +00006852 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00006853 if (buf == NULL) return(-1);
6854
Daniel Veillardf012a642001-07-23 19:10:52 +00006855 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006856
6857 ret = xmlOutputBufferClose(buf);
6858 return(ret);
6859}
6860
Daniel Veillardf012a642001-07-23 19:10:52 +00006861
6862/**
6863 * xmlSaveFileEnc:
6864 * @filename: the filename (or URL)
6865 * @cur: the document
6866 * @encoding: the name of an encoding (or NULL)
6867 *
6868 * Dump an XML document, converting it to the given encoding
6869 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006870 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00006871 */
6872int
6873xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
6874 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
6875}
6876
Owen Taylor3473f882001-02-23 17:55:21 +00006877/**
Daniel Veillard67fee942001-04-26 18:59:03 +00006878 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00006879 * @filename: the filename (or URL)
6880 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00006881 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00006882 *
6883 * Dump an XML document to a file. Will use compression if
6884 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00006885 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00006886 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006887 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006888 */
6889int
Daniel Veillard67fee942001-04-26 18:59:03 +00006890xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006891 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00006892}
6893
Daniel Veillard67fee942001-04-26 18:59:03 +00006894/**
6895 * xmlSaveFile:
6896 * @filename: the filename (or URL)
6897 * @cur: the document
6898 *
6899 * Dump an XML document to a file. Will use compression if
6900 * compiled in and enabled. If @filename is "-" the stdout file is
6901 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00006902 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00006903 */
6904int
6905xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006906 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00006907}
6908