blob: cf4a6b0f3456a1cd262b1f9574d64218da4b63da [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 *
Owen Taylor3473f882001-02-23 17:55:21 +00008 */
9
Daniel Veillard34ce8be2002-03-18 19:37:11 +000010#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000011#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000012
Owen Taylor3473f882001-02-23 17:55:21 +000013#include <string.h> /* for memset() only ! */
14
15#ifdef HAVE_CTYPE_H
16#include <ctype.h>
17#endif
18#ifdef HAVE_STDLIB_H
19#include <stdlib.h>
20#endif
21#ifdef HAVE_ZLIB_H
22#include <zlib.h>
23#endif
24
25#include <libxml/xmlmemory.h>
26#include <libxml/tree.h>
27#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000028#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000029#include <libxml/entities.h>
30#include <libxml/valid.h>
31#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000032#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000033#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000034
Daniel Veillard56a4cb82001-03-24 17:00:36 +000035xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
36
37/************************************************************************
38 * *
39 * A few static variables and macros *
40 * *
41 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000042/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000043const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000044/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000045const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000046 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000047/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +000048const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
49
Owen Taylor3473f882001-02-23 17:55:21 +000050static int xmlCompressMode = 0;
51static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000052
Owen Taylor3473f882001-02-23 17:55:21 +000053#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
54 xmlNodePtr ulccur = (n)->children; \
55 if (ulccur == NULL) { \
56 (n)->last = NULL; \
57 } else { \
58 while (ulccur->next != NULL) { \
59 ulccur->parent = (n); \
60 ulccur = ulccur->next; \
61 } \
62 ulccur->parent = (n); \
63 (n)->last = ulccur; \
64}}
65
66/* #define DEBUG_BUFFER */
67/* #define DEBUG_TREE */
68
69/************************************************************************
70 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +000071 * Functions to move to entities.c once the *
72 * API freeze is smoothen and they can be made public. *
73 * *
74 ************************************************************************/
75#include <libxml/hash.h>
76
77/**
78 * xmlGetEntityFromDtd:
79 * @dtd: A pointer to the DTD to search
80 * @name: The entity name
81 *
82 * Do an entity lookup in the DTD entity hash table and
83 * return the corresponding entity, if found.
84 *
85 * Returns A pointer to the entity structure or NULL if not found.
86 */
87static xmlEntityPtr
88xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
89 xmlEntitiesTablePtr table;
90
91 if((dtd != NULL) && (dtd->entities != NULL)) {
92 table = (xmlEntitiesTablePtr) dtd->entities;
93 return((xmlEntityPtr) xmlHashLookup(table, name));
94 /* return(xmlGetEntityFromTable(table, name)); */
95 }
96 return(NULL);
97}
98/**
99 * xmlGetParameterEntityFromDtd:
100 * @dtd: A pointer to the DTD to search
101 * @name: The entity name
102 *
103 * Do an entity lookup in the DTD pararmeter entity hash table and
104 * return the corresponding entity, if found.
105 *
106 * Returns A pointer to the entity structure or NULL if not found.
107 */
108static xmlEntityPtr
109xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
110 xmlEntitiesTablePtr table;
111
112 if ((dtd != NULL) && (dtd->pentities != NULL)) {
113 table = (xmlEntitiesTablePtr) dtd->pentities;
114 return((xmlEntityPtr) xmlHashLookup(table, name));
115 /* return(xmlGetEntityFromTable(table, name)); */
116 }
117 return(NULL);
118}
119
120/************************************************************************
121 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000122 * Allocation and deallocation of basic structures *
123 * *
124 ************************************************************************/
125
126/**
127 * xmlSetBufferAllocationScheme:
128 * @scheme: allocation method to use
129 *
130 * Set the buffer allocation method. Types are
131 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
132 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
133 * improves performance
134 */
135void
136xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
137 xmlBufferAllocScheme = scheme;
138}
139
140/**
141 * xmlGetBufferAllocationScheme:
142 *
143 * Types are
144 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
145 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
146 * improves performance
147 *
148 * Returns the current allocation scheme
149 */
150xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000151xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000152 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000153}
154
155/**
156 * xmlNewNs:
157 * @node: the element carrying the namespace
158 * @href: the URI associated
159 * @prefix: the prefix for the namespace
160 *
161 * Creation of a new Namespace. This function will refuse to create
162 * a namespace with a similar prefix than an existing one present on this
163 * node.
164 * We use href==NULL in the case of an element creation where the namespace
165 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000166 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000167 */
168xmlNsPtr
169xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
170 xmlNsPtr cur;
171
172 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
173 return(NULL);
174
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000175 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
176 return(NULL);
177
Owen Taylor3473f882001-02-23 17:55:21 +0000178 /*
179 * Allocate a new Namespace and fill the fields.
180 */
181 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
182 if (cur == NULL) {
183 xmlGenericError(xmlGenericErrorContext,
184 "xmlNewNs : malloc failed\n");
185 return(NULL);
186 }
187 memset(cur, 0, sizeof(xmlNs));
188 cur->type = XML_LOCAL_NAMESPACE;
189
190 if (href != NULL)
191 cur->href = xmlStrdup(href);
192 if (prefix != NULL)
193 cur->prefix = xmlStrdup(prefix);
194
195 /*
196 * Add it at the end to preserve parsing order ...
197 * and checks for existing use of the prefix
198 */
199 if (node != NULL) {
200 if (node->nsDef == NULL) {
201 node->nsDef = cur;
202 } else {
203 xmlNsPtr prev = node->nsDef;
204
205 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
206 (xmlStrEqual(prev->prefix, cur->prefix))) {
207 xmlFreeNs(cur);
208 return(NULL);
209 }
210 while (prev->next != NULL) {
211 prev = prev->next;
212 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
213 (xmlStrEqual(prev->prefix, cur->prefix))) {
214 xmlFreeNs(cur);
215 return(NULL);
216 }
217 }
218 prev->next = cur;
219 }
220 }
221 return(cur);
222}
223
224/**
225 * xmlSetNs:
226 * @node: a node in the document
227 * @ns: a namespace pointer
228 *
229 * Associate a namespace to a node, a posteriori.
230 */
231void
232xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
233 if (node == NULL) {
234#ifdef DEBUG_TREE
235 xmlGenericError(xmlGenericErrorContext,
236 "xmlSetNs: node == NULL\n");
237#endif
238 return;
239 }
240 node->ns = ns;
241}
242
243/**
244 * xmlFreeNs:
245 * @cur: the namespace pointer
246 *
247 * Free up the structures associated to a namespace
248 */
249void
250xmlFreeNs(xmlNsPtr cur) {
251 if (cur == NULL) {
252#ifdef DEBUG_TREE
253 xmlGenericError(xmlGenericErrorContext,
254 "xmlFreeNs : ns == NULL\n");
255#endif
256 return;
257 }
258 if (cur->href != NULL) xmlFree((char *) cur->href);
259 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000260 xmlFree(cur);
261}
262
263/**
264 * xmlFreeNsList:
265 * @cur: the first namespace pointer
266 *
267 * Free up all the structures associated to the chained namespaces.
268 */
269void
270xmlFreeNsList(xmlNsPtr cur) {
271 xmlNsPtr next;
272 if (cur == NULL) {
273#ifdef DEBUG_TREE
274 xmlGenericError(xmlGenericErrorContext,
275 "xmlFreeNsList : ns == NULL\n");
276#endif
277 return;
278 }
279 while (cur != NULL) {
280 next = cur->next;
281 xmlFreeNs(cur);
282 cur = next;
283 }
284}
285
286/**
287 * xmlNewDtd:
288 * @doc: the document pointer
289 * @name: the DTD name
290 * @ExternalID: the external ID
291 * @SystemID: the system ID
292 *
293 * Creation of a new DTD for the external subset. To create an
294 * internal subset, use xmlCreateIntSubset().
295 *
296 * Returns a pointer to the new DTD structure
297 */
298xmlDtdPtr
299xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
300 const xmlChar *ExternalID, const xmlChar *SystemID) {
301 xmlDtdPtr cur;
302
303 if ((doc != NULL) && (doc->extSubset != NULL)) {
304#ifdef DEBUG_TREE
305 xmlGenericError(xmlGenericErrorContext,
306 "xmlNewDtd(%s): document %s already have a DTD %s\n",
307 /* !!! */ (char *) name, doc->name,
308 /* !!! */ (char *)doc->extSubset->name);
309#endif
310 return(NULL);
311 }
312
313 /*
314 * Allocate a new DTD and fill the fields.
315 */
316 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
317 if (cur == NULL) {
318 xmlGenericError(xmlGenericErrorContext,
319 "xmlNewDtd : malloc failed\n");
320 return(NULL);
321 }
322 memset(cur, 0 , sizeof(xmlDtd));
323 cur->type = XML_DTD_NODE;
324
325 if (name != NULL)
326 cur->name = xmlStrdup(name);
327 if (ExternalID != NULL)
328 cur->ExternalID = xmlStrdup(ExternalID);
329 if (SystemID != NULL)
330 cur->SystemID = xmlStrdup(SystemID);
331 if (doc != NULL)
332 doc->extSubset = cur;
333 cur->doc = doc;
334
335 return(cur);
336}
337
338/**
339 * xmlGetIntSubset:
340 * @doc: the document pointer
341 *
342 * Get the internal subset of a document
343 * Returns a pointer to the DTD structure or NULL if not found
344 */
345
346xmlDtdPtr
347xmlGetIntSubset(xmlDocPtr doc) {
348 xmlNodePtr cur;
349
350 if (doc == NULL)
351 return(NULL);
352 cur = doc->children;
353 while (cur != NULL) {
354 if (cur->type == XML_DTD_NODE)
355 return((xmlDtdPtr) cur);
356 cur = cur->next;
357 }
358 return((xmlDtdPtr) doc->intSubset);
359}
360
361/**
362 * xmlCreateIntSubset:
363 * @doc: the document pointer
364 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000365 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000366 * @SystemID: the system ID
367 *
368 * Create the internal subset of a document
369 * Returns a pointer to the new DTD structure
370 */
371xmlDtdPtr
372xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
373 const xmlChar *ExternalID, const xmlChar *SystemID) {
374 xmlDtdPtr cur;
375
376 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
377#ifdef DEBUG_TREE
378 xmlGenericError(xmlGenericErrorContext,
379
380 "xmlCreateIntSubset(): document %s already have an internal subset\n",
381 doc->name);
382#endif
383 return(NULL);
384 }
385
386 /*
387 * Allocate a new DTD and fill the fields.
388 */
389 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
390 if (cur == NULL) {
391 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000392 "xmlCreateIntSubset : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000393 return(NULL);
394 }
395 memset(cur, 0, sizeof(xmlDtd));
396 cur->type = XML_DTD_NODE;
397
398 if (name != NULL)
399 cur->name = xmlStrdup(name);
400 if (ExternalID != NULL)
401 cur->ExternalID = xmlStrdup(ExternalID);
402 if (SystemID != NULL)
403 cur->SystemID = xmlStrdup(SystemID);
404 if (doc != NULL) {
405 doc->intSubset = cur;
406 cur->parent = doc;
407 cur->doc = doc;
408 if (doc->children == NULL) {
409 doc->children = (xmlNodePtr) cur;
410 doc->last = (xmlNodePtr) cur;
411 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000412 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000413 xmlNodePtr prev;
414
Owen Taylor3473f882001-02-23 17:55:21 +0000415 prev = doc->children;
416 prev->prev = (xmlNodePtr) cur;
417 cur->next = prev;
418 doc->children = (xmlNodePtr) cur;
419 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000420 xmlNodePtr next;
421
422 next = doc->children;
423 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
424 next = next->next;
425 if (next == NULL) {
426 cur->prev = doc->last;
427 cur->prev->next = (xmlNodePtr) cur;
428 cur->next = NULL;
429 doc->last = (xmlNodePtr) cur;
430 } else {
431 cur->next = next;
432 cur->prev = next->prev;
433 if (cur->prev == NULL)
434 doc->children = (xmlNodePtr) cur;
435 else
436 cur->prev->next = (xmlNodePtr) cur;
437 next->prev = (xmlNodePtr) cur;
438 }
Owen Taylor3473f882001-02-23 17:55:21 +0000439 }
440 }
441 }
442 return(cur);
443}
444
445/**
446 * xmlFreeDtd:
447 * @cur: the DTD structure to free up
448 *
449 * Free a DTD structure.
450 */
451void
452xmlFreeDtd(xmlDtdPtr cur) {
453 if (cur == NULL) {
454#ifdef DEBUG_TREE
455 xmlGenericError(xmlGenericErrorContext,
456 "xmlFreeDtd : DTD == NULL\n");
457#endif
458 return;
459 }
460 if (cur->children != NULL) {
461 xmlNodePtr next, c = cur->children;
462
463 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000464 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000465 * indexes.
466 */
467 while (c != NULL) {
468 next = c->next;
469 if (c->type == XML_COMMENT_NODE) {
470 xmlUnlinkNode(c);
471 xmlFreeNode(c);
472 }
473 c = next;
474 }
475 }
476 if (cur->name != NULL) xmlFree((char *) cur->name);
477 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
478 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
479 /* TODO !!! */
480 if (cur->notations != NULL)
481 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
482
483 if (cur->elements != NULL)
484 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
485 if (cur->attributes != NULL)
486 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
487 if (cur->entities != NULL)
488 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
489 if (cur->pentities != NULL)
490 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
491
Owen Taylor3473f882001-02-23 17:55:21 +0000492 xmlFree(cur);
493}
494
495/**
496 * xmlNewDoc:
497 * @version: xmlChar string giving the version of XML "1.0"
498 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000499 * Creates a new XML document
500 *
Owen Taylor3473f882001-02-23 17:55:21 +0000501 * Returns a new document
502 */
503xmlDocPtr
504xmlNewDoc(const xmlChar *version) {
505 xmlDocPtr cur;
506
507 if (version == NULL)
508 version = (const xmlChar *) "1.0";
509
510 /*
511 * Allocate a new document and fill the fields.
512 */
513 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
514 if (cur == NULL) {
515 xmlGenericError(xmlGenericErrorContext,
516 "xmlNewDoc : malloc failed\n");
517 return(NULL);
518 }
519 memset(cur, 0, sizeof(xmlDoc));
520 cur->type = XML_DOCUMENT_NODE;
521
522 cur->version = xmlStrdup(version);
523 cur->standalone = -1;
524 cur->compression = -1; /* not initialized */
525 cur->doc = cur;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000526 cur->charset = XML_CHAR_ENCODING_UTF8;
Owen Taylor3473f882001-02-23 17:55:21 +0000527 return(cur);
528}
529
530/**
531 * xmlFreeDoc:
532 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +0000533 *
534 * Free up all the structures used by a document, tree included.
535 */
536void
537xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000538 xmlDtdPtr extSubset, intSubset;
539
Owen Taylor3473f882001-02-23 17:55:21 +0000540 if (cur == NULL) {
541#ifdef DEBUG_TREE
542 xmlGenericError(xmlGenericErrorContext,
543 "xmlFreeDoc : document == NULL\n");
544#endif
545 return;
546 }
Daniel Veillard76d66f42001-05-16 21:05:17 +0000547 /*
548 * Do this before freeing the children list to avoid ID lookups
549 */
550 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
551 cur->ids = NULL;
552 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
553 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000554 extSubset = cur->extSubset;
555 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +0000556 if (intSubset == extSubset)
557 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000558 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000559 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000560 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000561 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000562 }
Daniel Veillarda9142e72001-06-19 11:07:54 +0000563 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000564 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000565 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000566 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000567 }
568
569 if (cur->children != NULL) xmlFreeNodeList(cur->children);
570
Owen Taylor3473f882001-02-23 17:55:21 +0000571 if (cur->version != NULL) xmlFree((char *) cur->version);
572 if (cur->name != NULL) xmlFree((char *) cur->name);
573 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +0000574 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +0000575 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000576 xmlFree(cur);
577}
578
579/**
580 * xmlStringLenGetNodeList:
581 * @doc: the document
582 * @value: the value of the text
583 * @len: the length of the string value
584 *
585 * Parse the value string and build the node list associated. Should
586 * produce a flat tree with only TEXTs and ENTITY_REFs.
587 * Returns a pointer to the first child
588 */
589xmlNodePtr
590xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
591 xmlNodePtr ret = NULL, last = NULL;
592 xmlNodePtr node;
593 xmlChar *val;
594 const xmlChar *cur = value;
595 const xmlChar *q;
596 xmlEntityPtr ent;
597
598 if (value == NULL) return(NULL);
599
600 q = cur;
601 while ((*cur != 0) && (cur - value < len)) {
602 if (*cur == '&') {
603 /*
604 * Save the current text.
605 */
606 if (cur != q) {
607 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
608 xmlNodeAddContentLen(last, q, cur - q);
609 } else {
610 node = xmlNewDocTextLen(doc, q, cur - q);
611 if (node == NULL) return(ret);
612 if (last == NULL)
613 last = ret = node;
614 else {
615 last->next = node;
616 node->prev = last;
617 last = node;
618 }
619 }
620 }
621 /*
622 * Read the entity string
623 */
624 cur++;
625 q = cur;
626 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
627 if ((*cur == 0) || (cur - value >= len)) {
628#ifdef DEBUG_TREE
629 xmlGenericError(xmlGenericErrorContext,
630 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
631#endif
632 return(ret);
633 }
634 if (cur != q) {
635 /*
636 * Predefined entities don't generate nodes
637 */
638 val = xmlStrndup(q, cur - q);
639 ent = xmlGetDocEntity(doc, val);
640 if ((ent != NULL) &&
641 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
642 if (last == NULL) {
643 node = xmlNewDocText(doc, ent->content);
644 last = ret = node;
645 } else
646 xmlNodeAddContent(last, ent->content);
647
648 } else {
649 /*
650 * Create a new REFERENCE_REF node
651 */
652 node = xmlNewReference(doc, val);
653 if (node == NULL) {
654 if (val != NULL) xmlFree(val);
655 return(ret);
656 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000657 else if ((ent != NULL) && (ent->children == NULL)) {
658 xmlNodePtr tmp;
659
660 ent->children =
661 xmlStringGetNodeList(doc, (const xmlChar*)node->content);
662 tmp = ent->children;
663 while (tmp) {
664 tmp->parent = (xmlNodePtr)ent;
665 tmp = tmp->next;
666 }
667 }
Owen Taylor3473f882001-02-23 17:55:21 +0000668 if (last == NULL)
669 last = ret = node;
670 else {
671 last->next = node;
672 node->prev = last;
673 last = node;
674 }
675 }
676 xmlFree(val);
677 }
678 cur++;
679 q = cur;
680 } else
681 cur++;
682 }
683 if (cur != q) {
684 /*
685 * Handle the last piece of text.
686 */
687 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
688 xmlNodeAddContentLen(last, q, cur - q);
689 } else {
690 node = xmlNewDocTextLen(doc, q, cur - q);
691 if (node == NULL) return(ret);
692 if (last == NULL)
693 last = ret = node;
694 else {
695 last->next = node;
696 node->prev = last;
697 last = node;
698 }
699 }
700 }
701 return(ret);
702}
703
704/**
705 * xmlStringGetNodeList:
706 * @doc: the document
707 * @value: the value of the attribute
708 *
709 * Parse the value string and build the node list associated. Should
710 * produce a flat tree with only TEXTs and ENTITY_REFs.
711 * Returns a pointer to the first child
712 */
713xmlNodePtr
714xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
715 xmlNodePtr ret = NULL, last = NULL;
716 xmlNodePtr node;
717 xmlChar *val;
718 const xmlChar *cur = value;
719 const xmlChar *q;
720 xmlEntityPtr ent;
721
722 if (value == NULL) return(NULL);
723
724 q = cur;
725 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000726 if (cur[0] == '&') {
727 int charval = 0;
728 xmlChar tmp;
729
Owen Taylor3473f882001-02-23 17:55:21 +0000730 /*
731 * Save the current text.
732 */
733 if (cur != q) {
734 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
735 xmlNodeAddContentLen(last, q, cur - q);
736 } else {
737 node = xmlNewDocTextLen(doc, q, cur - q);
738 if (node == NULL) return(ret);
739 if (last == NULL)
740 last = ret = node;
741 else {
742 last->next = node;
743 node->prev = last;
744 last = node;
745 }
746 }
747 }
Owen Taylor3473f882001-02-23 17:55:21 +0000748 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000749 if ((cur[1] == '#') && (cur[2] == 'x')) {
750 cur += 3;
751 tmp = *cur;
752 while (tmp != ';') { /* Non input consuming loop */
753 if ((tmp >= '0') && (tmp <= '9'))
754 charval = charval * 16 + (tmp - '0');
755 else if ((tmp >= 'a') && (tmp <= 'f'))
756 charval = charval * 16 + (tmp - 'a') + 10;
757 else if ((tmp >= 'A') && (tmp <= 'F'))
758 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +0000759 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000760 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000761 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000762 charval = 0;
763 break;
764 }
765 cur++;
766 tmp = *cur;
767 }
768 if (tmp == ';')
769 cur++;
770 q = cur;
771 } else if (cur[1] == '#') {
772 cur += 2;
773 tmp = *cur;
774 while (tmp != ';') { /* Non input consuming loops */
775 if ((tmp >= '0') && (tmp <= '9'))
776 charval = charval * 10 + (tmp - '0');
777 else {
778 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000779 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000780 charval = 0;
781 break;
782 }
783 cur++;
784 tmp = *cur;
785 }
786 if (tmp == ';')
787 cur++;
788 q = cur;
789 } else {
790 /*
791 * Read the entity string
792 */
793 cur++;
794 q = cur;
795 while ((*cur != 0) && (*cur != ';')) cur++;
796 if (*cur == 0) {
797#ifdef DEBUG_TREE
798 xmlGenericError(xmlGenericErrorContext,
799 "xmlStringGetNodeList: unterminated entity %30s\n", q);
800#endif
801 return(ret);
802 }
803 if (cur != q) {
804 /*
805 * Predefined entities don't generate nodes
806 */
807 val = xmlStrndup(q, cur - q);
808 ent = xmlGetDocEntity(doc, val);
809 if ((ent != NULL) &&
810 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
811 if (last == NULL) {
812 node = xmlNewDocText(doc, ent->content);
813 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +0000814 } else if (last->type != XML_TEXT_NODE) {
815 node = xmlNewDocText(doc, ent->content);
816 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000817 } else
818 xmlNodeAddContent(last, ent->content);
819
820 } else {
821 /*
822 * Create a new REFERENCE_REF node
823 */
824 node = xmlNewReference(doc, val);
825 if (node == NULL) {
826 if (val != NULL) xmlFree(val);
827 return(ret);
828 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000829 else if ((ent != NULL) && (ent->children == NULL)) {
830 xmlNodePtr temp;
831
832 ent->children = xmlStringGetNodeList(doc,
833 (const xmlChar*)node->content);
834 temp = ent->children;
835 while (temp) {
836 temp->parent = (xmlNodePtr)ent;
837 temp = temp->next;
838 }
839 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000840 if (last == NULL) {
841 last = ret = node;
842 } else {
843 last = xmlAddNextSibling(last, node);
844 }
845 }
846 xmlFree(val);
847 }
848 cur++;
849 q = cur;
850 }
851 if (charval != 0) {
852 xmlChar buf[10];
853 int len;
854
855 len = xmlCopyCharMultiByte(buf, charval);
856 buf[len] = 0;
857 node = xmlNewDocText(doc, buf);
858 if (node != NULL) {
859 if (last == NULL) {
860 last = ret = node;
861 } else {
862 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000863 }
864 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000865
866 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000867 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000868 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000869 cur++;
870 }
Daniel Veillard75bea542001-05-11 17:41:21 +0000871 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000872 /*
873 * Handle the last piece of text.
874 */
875 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
876 xmlNodeAddContentLen(last, q, cur - q);
877 } else {
878 node = xmlNewDocTextLen(doc, q, cur - q);
879 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000880 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000881 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000882 } else {
883 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000884 }
885 }
886 }
887 return(ret);
888}
889
890/**
891 * xmlNodeListGetString:
892 * @doc: the document
893 * @list: a Node list
894 * @inLine: should we replace entity contents or show their external form
895 *
896 * Returns the string equivalent to the text contained in the Node list
897 * made of TEXTs and ENTITY_REFs
Daniel Veillardbd9afb52002-09-25 22:25:35 +0000898 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +0000899 */
900xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +0000901xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
902{
Owen Taylor3473f882001-02-23 17:55:21 +0000903 xmlNodePtr node = list;
904 xmlChar *ret = NULL;
905 xmlEntityPtr ent;
906
Daniel Veillard7646b182002-04-20 06:41:40 +0000907 if (list == NULL)
908 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000909
910 while (node != NULL) {
911 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +0000912 (node->type == XML_CDATA_SECTION_NODE)) {
913 if (inLine) {
914 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000915 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +0000916 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +0000917
Daniel Veillard7646b182002-04-20 06:41:40 +0000918 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
919 if (buffer != NULL) {
920 ret = xmlStrcat(ret, buffer);
921 xmlFree(buffer);
922 }
923 }
924 } else if (node->type == XML_ENTITY_REF_NODE) {
925 if (inLine) {
926 ent = xmlGetDocEntity(doc, node->name);
927 if (ent != NULL) {
928 xmlChar *buffer;
929
930 /* an entity content can be any "well balanced chunk",
931 * i.e. the result of the content [43] production:
932 * http://www.w3.org/TR/REC-xml#NT-content.
933 * So it can contain text, CDATA section or nested
934 * entity reference nodes (among others).
935 * -> we recursive call xmlNodeListGetString()
936 * which handles these types */
937 buffer = xmlNodeListGetString(doc, ent->children, 1);
938 if (buffer != NULL) {
939 ret = xmlStrcat(ret, buffer);
940 xmlFree(buffer);
941 }
942 } else {
943 ret = xmlStrcat(ret, node->content);
944 }
945 } else {
946 xmlChar buf[2];
947
948 buf[0] = '&';
949 buf[1] = 0;
950 ret = xmlStrncat(ret, buf, 1);
951 ret = xmlStrcat(ret, node->name);
952 buf[0] = ';';
953 buf[1] = 0;
954 ret = xmlStrncat(ret, buf, 1);
955 }
956 }
957#if 0
958 else {
959 xmlGenericError(xmlGenericErrorContext,
960 "xmlGetNodeListString : invalid node type %d\n",
961 node->type);
962 }
963#endif
964 node = node->next;
965 }
966 return (ret);
967}
Owen Taylor3473f882001-02-23 17:55:21 +0000968/**
969 * xmlNodeListGetRawString:
970 * @doc: the document
971 * @list: a Node list
972 * @inLine: should we replace entity contents or show their external form
973 *
974 * Returns the string equivalent to the text contained in the Node list
975 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
976 * this function doesn't do any character encoding handling.
977 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +0000978 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +0000979 */
980xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +0000981xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
982{
Owen Taylor3473f882001-02-23 17:55:21 +0000983 xmlNodePtr node = list;
984 xmlChar *ret = NULL;
985 xmlEntityPtr ent;
986
Daniel Veillard7646b182002-04-20 06:41:40 +0000987 if (list == NULL)
988 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000989
990 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +0000991 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +0000992 (node->type == XML_CDATA_SECTION_NODE)) {
993 if (inLine) {
994 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000995 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +0000996 xmlChar *buffer;
997
998 buffer = xmlEncodeSpecialChars(doc, node->content);
999 if (buffer != NULL) {
1000 ret = xmlStrcat(ret, buffer);
1001 xmlFree(buffer);
1002 }
1003 }
1004 } else if (node->type == XML_ENTITY_REF_NODE) {
1005 if (inLine) {
1006 ent = xmlGetDocEntity(doc, node->name);
1007 if (ent != NULL) {
1008 xmlChar *buffer;
1009
1010 /* an entity content can be any "well balanced chunk",
1011 * i.e. the result of the content [43] production:
1012 * http://www.w3.org/TR/REC-xml#NT-content.
1013 * So it can contain text, CDATA section or nested
1014 * entity reference nodes (among others).
1015 * -> we recursive call xmlNodeListGetRawString()
1016 * which handles these types */
1017 buffer =
1018 xmlNodeListGetRawString(doc, ent->children, 1);
1019 if (buffer != NULL) {
1020 ret = xmlStrcat(ret, buffer);
1021 xmlFree(buffer);
1022 }
1023 } else {
1024 ret = xmlStrcat(ret, node->content);
1025 }
1026 } else {
1027 xmlChar buf[2];
1028
1029 buf[0] = '&';
1030 buf[1] = 0;
1031 ret = xmlStrncat(ret, buf, 1);
1032 ret = xmlStrcat(ret, node->name);
1033 buf[0] = ';';
1034 buf[1] = 0;
1035 ret = xmlStrncat(ret, buf, 1);
1036 }
1037 }
Owen Taylor3473f882001-02-23 17:55:21 +00001038#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001039 else {
1040 xmlGenericError(xmlGenericErrorContext,
1041 "xmlGetNodeListString : invalid node type %d\n",
1042 node->type);
1043 }
Owen Taylor3473f882001-02-23 17:55:21 +00001044#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001045 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001046 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001047 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001048}
1049
1050/**
1051 * xmlNewProp:
1052 * @node: the holding node
1053 * @name: the name of the attribute
1054 * @value: the value of the attribute
1055 *
1056 * Create a new property carried by a node.
1057 * Returns a pointer to the attribute
1058 */
1059xmlAttrPtr
1060xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1061 xmlAttrPtr cur;
1062 xmlDocPtr doc = NULL;
1063
1064 if (name == NULL) {
1065#ifdef DEBUG_TREE
1066 xmlGenericError(xmlGenericErrorContext,
1067 "xmlNewProp : name == NULL\n");
1068#endif
1069 return(NULL);
1070 }
1071
1072 /*
1073 * Allocate a new property and fill the fields.
1074 */
1075 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1076 if (cur == NULL) {
1077 xmlGenericError(xmlGenericErrorContext,
1078 "xmlNewProp : malloc failed\n");
1079 return(NULL);
1080 }
1081 memset(cur, 0, sizeof(xmlAttr));
1082 cur->type = XML_ATTRIBUTE_NODE;
1083
1084 cur->parent = node;
1085 if (node != NULL) {
1086 doc = node->doc;
1087 cur->doc = doc;
1088 }
1089 cur->name = xmlStrdup(name);
1090 if (value != NULL) {
1091 xmlChar *buffer;
1092 xmlNodePtr tmp;
1093
1094 buffer = xmlEncodeEntitiesReentrant(doc, value);
1095 cur->children = xmlStringGetNodeList(doc, buffer);
1096 cur->last = NULL;
1097 tmp = cur->children;
1098 while (tmp != NULL) {
1099 tmp->parent = (xmlNodePtr) cur;
1100 tmp->doc = doc;
1101 if (tmp->next == NULL)
1102 cur->last = tmp;
1103 tmp = tmp->next;
1104 }
1105 xmlFree(buffer);
1106 }
1107
1108 /*
1109 * Add it at the end to preserve parsing order ...
1110 */
1111 if (node != NULL) {
1112 if (node->properties == NULL) {
1113 node->properties = cur;
1114 } else {
1115 xmlAttrPtr prev = node->properties;
1116
1117 while (prev->next != NULL) prev = prev->next;
1118 prev->next = cur;
1119 cur->prev = prev;
1120 }
1121 }
1122 return(cur);
1123}
1124
1125/**
1126 * xmlNewNsProp:
1127 * @node: the holding node
1128 * @ns: the namespace
1129 * @name: the name of the attribute
1130 * @value: the value of the attribute
1131 *
1132 * Create a new property tagged with a namespace and carried by a node.
1133 * Returns a pointer to the attribute
1134 */
1135xmlAttrPtr
1136xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1137 const xmlChar *value) {
1138 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001139 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001140
1141 if (name == NULL) {
1142#ifdef DEBUG_TREE
1143 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001144 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001145#endif
1146 return(NULL);
1147 }
1148
1149 /*
1150 * Allocate a new property and fill the fields.
1151 */
1152 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1153 if (cur == NULL) {
1154 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001155 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001156 return(NULL);
1157 }
1158 memset(cur, 0, sizeof(xmlAttr));
1159 cur->type = XML_ATTRIBUTE_NODE;
1160
1161 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001162 if (node != NULL) {
1163 doc = node->doc;
1164 cur->doc = doc;
1165 }
Owen Taylor3473f882001-02-23 17:55:21 +00001166 cur->ns = ns;
1167 cur->name = xmlStrdup(name);
1168 if (value != NULL) {
1169 xmlChar *buffer;
1170 xmlNodePtr tmp;
1171
Daniel Veillarda682b212001-06-07 19:59:42 +00001172 buffer = xmlEncodeEntitiesReentrant(doc, value);
1173 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001174 cur->last = NULL;
1175 tmp = cur->children;
1176 while (tmp != NULL) {
1177 tmp->parent = (xmlNodePtr) cur;
1178 if (tmp->next == NULL)
1179 cur->last = tmp;
1180 tmp = tmp->next;
1181 }
1182 xmlFree(buffer);
1183 }
1184
1185 /*
1186 * Add it at the end to preserve parsing order ...
1187 */
1188 if (node != NULL) {
1189 if (node->properties == NULL) {
1190 node->properties = cur;
1191 } else {
1192 xmlAttrPtr prev = node->properties;
1193
1194 while (prev->next != NULL) prev = prev->next;
1195 prev->next = cur;
1196 cur->prev = prev;
1197 }
1198 }
1199 return(cur);
1200}
1201
1202/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001203 * xmlNewNsPropEatName:
1204 * @node: the holding node
1205 * @ns: the namespace
1206 * @name: the name of the attribute
1207 * @value: the value of the attribute
1208 *
1209 * Create a new property tagged with a namespace and carried by a node.
1210 * Returns a pointer to the attribute
1211 */
1212xmlAttrPtr
1213xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1214 const xmlChar *value) {
1215 xmlAttrPtr cur;
1216 xmlDocPtr doc = NULL;
1217
1218 if (name == NULL) {
1219#ifdef DEBUG_TREE
1220 xmlGenericError(xmlGenericErrorContext,
1221 "xmlNewNsPropEatName : name == NULL\n");
1222#endif
1223 return(NULL);
1224 }
1225
1226 /*
1227 * Allocate a new property and fill the fields.
1228 */
1229 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1230 if (cur == NULL) {
1231 xmlGenericError(xmlGenericErrorContext,
1232 "xmlNewNsPropEatName : malloc failed\n");
1233 return(NULL);
1234 }
1235 memset(cur, 0, sizeof(xmlAttr));
1236 cur->type = XML_ATTRIBUTE_NODE;
1237
1238 cur->parent = node;
1239 if (node != NULL) {
1240 doc = node->doc;
1241 cur->doc = doc;
1242 }
1243 cur->ns = ns;
1244 cur->name = name;
1245 if (value != NULL) {
1246 xmlChar *buffer;
1247 xmlNodePtr tmp;
1248
1249 buffer = xmlEncodeEntitiesReentrant(doc, value);
1250 cur->children = xmlStringGetNodeList(doc, buffer);
1251 cur->last = NULL;
1252 tmp = cur->children;
1253 while (tmp != NULL) {
1254 tmp->parent = (xmlNodePtr) cur;
1255 if (tmp->next == NULL)
1256 cur->last = tmp;
1257 tmp = tmp->next;
1258 }
1259 xmlFree(buffer);
1260 }
1261
1262 /*
1263 * Add it at the end to preserve parsing order ...
1264 */
1265 if (node != NULL) {
1266 if (node->properties == NULL) {
1267 node->properties = cur;
1268 } else {
1269 xmlAttrPtr prev = node->properties;
1270
1271 while (prev->next != NULL) prev = prev->next;
1272 prev->next = cur;
1273 cur->prev = prev;
1274 }
1275 }
1276 return(cur);
1277}
1278
1279/**
Owen Taylor3473f882001-02-23 17:55:21 +00001280 * xmlNewDocProp:
1281 * @doc: the document
1282 * @name: the name of the attribute
1283 * @value: the value of the attribute
1284 *
1285 * Create a new property carried by a document.
1286 * Returns a pointer to the attribute
1287 */
1288xmlAttrPtr
1289xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1290 xmlAttrPtr cur;
1291
1292 if (name == NULL) {
1293#ifdef DEBUG_TREE
1294 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001295 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001296#endif
1297 return(NULL);
1298 }
1299
1300 /*
1301 * Allocate a new property and fill the fields.
1302 */
1303 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1304 if (cur == NULL) {
1305 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001306 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001307 return(NULL);
1308 }
1309 memset(cur, 0, sizeof(xmlAttr));
1310 cur->type = XML_ATTRIBUTE_NODE;
1311
1312 cur->name = xmlStrdup(name);
1313 cur->doc = doc;
1314 if (value != NULL) {
1315 xmlNodePtr tmp;
1316
1317 cur->children = xmlStringGetNodeList(doc, value);
1318 cur->last = NULL;
1319
1320 tmp = cur->children;
1321 while (tmp != NULL) {
1322 tmp->parent = (xmlNodePtr) cur;
1323 if (tmp->next == NULL)
1324 cur->last = tmp;
1325 tmp = tmp->next;
1326 }
1327 }
1328 return(cur);
1329}
1330
1331/**
1332 * xmlFreePropList:
1333 * @cur: the first property in the list
1334 *
1335 * Free a property and all its siblings, all the children are freed too.
1336 */
1337void
1338xmlFreePropList(xmlAttrPtr cur) {
1339 xmlAttrPtr next;
1340 if (cur == NULL) {
1341#ifdef DEBUG_TREE
1342 xmlGenericError(xmlGenericErrorContext,
1343 "xmlFreePropList : property == NULL\n");
1344#endif
1345 return;
1346 }
1347 while (cur != NULL) {
1348 next = cur->next;
1349 xmlFreeProp(cur);
1350 cur = next;
1351 }
1352}
1353
1354/**
1355 * xmlFreeProp:
1356 * @cur: an attribute
1357 *
1358 * Free one attribute, all the content is freed too
1359 */
1360void
1361xmlFreeProp(xmlAttrPtr cur) {
1362 if (cur == NULL) {
1363#ifdef DEBUG_TREE
1364 xmlGenericError(xmlGenericErrorContext,
1365 "xmlFreeProp : property == NULL\n");
1366#endif
1367 return;
1368 }
1369 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001370 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1371 ((cur->parent->doc->intSubset != NULL) ||
1372 (cur->parent->doc->extSubset != NULL))) {
1373 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1374 xmlRemoveID(cur->parent->doc, cur);
1375 }
Owen Taylor3473f882001-02-23 17:55:21 +00001376 if (cur->name != NULL) xmlFree((char *) cur->name);
1377 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001378 xmlFree(cur);
1379}
1380
1381/**
1382 * xmlRemoveProp:
1383 * @cur: an attribute
1384 *
1385 * Unlink and free one attribute, all the content is freed too
1386 * Note this doesn't work for namespace definition attributes
1387 *
1388 * Returns 0 if success and -1 in case of error.
1389 */
1390int
1391xmlRemoveProp(xmlAttrPtr cur) {
1392 xmlAttrPtr tmp;
1393 if (cur == NULL) {
1394#ifdef DEBUG_TREE
1395 xmlGenericError(xmlGenericErrorContext,
1396 "xmlRemoveProp : cur == NULL\n");
1397#endif
1398 return(-1);
1399 }
1400 if (cur->parent == NULL) {
1401#ifdef DEBUG_TREE
1402 xmlGenericError(xmlGenericErrorContext,
1403 "xmlRemoveProp : cur->parent == NULL\n");
1404#endif
1405 return(-1);
1406 }
1407 tmp = cur->parent->properties;
1408 if (tmp == cur) {
1409 cur->parent->properties = cur->next;
1410 xmlFreeProp(cur);
1411 return(0);
1412 }
1413 while (tmp != NULL) {
1414 if (tmp->next == cur) {
1415 tmp->next = cur->next;
1416 if (tmp->next != NULL)
1417 tmp->next->prev = tmp;
1418 xmlFreeProp(cur);
1419 return(0);
1420 }
1421 tmp = tmp->next;
1422 }
1423#ifdef DEBUG_TREE
1424 xmlGenericError(xmlGenericErrorContext,
1425 "xmlRemoveProp : attribute not owned by its node\n");
1426#endif
1427 return(-1);
1428}
1429
1430/**
1431 * xmlNewPI:
1432 * @name: the processing instruction name
1433 * @content: the PI content
1434 *
1435 * Creation of a processing instruction element.
1436 * Returns a pointer to the new node object.
1437 */
1438xmlNodePtr
1439xmlNewPI(const xmlChar *name, const xmlChar *content) {
1440 xmlNodePtr cur;
1441
1442 if (name == NULL) {
1443#ifdef DEBUG_TREE
1444 xmlGenericError(xmlGenericErrorContext,
1445 "xmlNewPI : name == NULL\n");
1446#endif
1447 return(NULL);
1448 }
1449
1450 /*
1451 * Allocate a new node and fill the fields.
1452 */
1453 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1454 if (cur == NULL) {
1455 xmlGenericError(xmlGenericErrorContext,
1456 "xmlNewPI : malloc failed\n");
1457 return(NULL);
1458 }
1459 memset(cur, 0, sizeof(xmlNode));
1460 cur->type = XML_PI_NODE;
1461
1462 cur->name = xmlStrdup(name);
1463 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001464 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001465 }
1466 return(cur);
1467}
1468
1469/**
1470 * xmlNewNode:
1471 * @ns: namespace if any
1472 * @name: the node name
1473 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001474 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001475 *
1476 * Returns a pointer to the new node object.
1477 */
1478xmlNodePtr
1479xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1480 xmlNodePtr cur;
1481
1482 if (name == NULL) {
1483#ifdef DEBUG_TREE
1484 xmlGenericError(xmlGenericErrorContext,
1485 "xmlNewNode : name == NULL\n");
1486#endif
1487 return(NULL);
1488 }
1489
1490 /*
1491 * Allocate a new node and fill the fields.
1492 */
1493 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1494 if (cur == NULL) {
1495 xmlGenericError(xmlGenericErrorContext,
1496 "xmlNewNode : malloc failed\n");
1497 return(NULL);
1498 }
1499 memset(cur, 0, sizeof(xmlNode));
1500 cur->type = XML_ELEMENT_NODE;
1501
1502 cur->name = xmlStrdup(name);
1503 cur->ns = ns;
1504 return(cur);
1505}
1506
1507/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001508 * xmlNewNodeEatName:
1509 * @ns: namespace if any
1510 * @name: the node name
1511 *
1512 * Creation of a new node element. @ns is optional (NULL).
1513 *
1514 * Returns a pointer to the new node object.
1515 */
1516xmlNodePtr
1517xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
1518 xmlNodePtr cur;
1519
1520 if (name == NULL) {
1521#ifdef DEBUG_TREE
1522 xmlGenericError(xmlGenericErrorContext,
1523 "xmlNewNode : name == NULL\n");
1524#endif
1525 return(NULL);
1526 }
1527
1528 /*
1529 * Allocate a new node and fill the fields.
1530 */
1531 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1532 if (cur == NULL) {
1533 xmlGenericError(xmlGenericErrorContext,
1534 "xmlNewNode : malloc failed\n");
1535 return(NULL);
1536 }
1537 memset(cur, 0, sizeof(xmlNode));
1538 cur->type = XML_ELEMENT_NODE;
1539
1540 cur->name = name;
1541 cur->ns = ns;
1542 return(cur);
1543}
1544
1545/**
Owen Taylor3473f882001-02-23 17:55:21 +00001546 * xmlNewDocNode:
1547 * @doc: the document
1548 * @ns: namespace if any
1549 * @name: the node name
1550 * @content: the XML text content if any
1551 *
1552 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001553 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001554 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1555 * references, but XML special chars need to be escaped first by using
1556 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1557 * need entities support.
1558 *
1559 * Returns a pointer to the new node object.
1560 */
1561xmlNodePtr
1562xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1563 const xmlChar *name, const xmlChar *content) {
1564 xmlNodePtr cur;
1565
1566 cur = xmlNewNode(ns, name);
1567 if (cur != NULL) {
1568 cur->doc = doc;
1569 if (content != NULL) {
1570 cur->children = xmlStringGetNodeList(doc, content);
1571 UPDATE_LAST_CHILD_AND_PARENT(cur)
1572 }
1573 }
1574 return(cur);
1575}
1576
Daniel Veillard46de64e2002-05-29 08:21:33 +00001577/**
1578 * xmlNewDocNodeEatName:
1579 * @doc: the document
1580 * @ns: namespace if any
1581 * @name: the node name
1582 * @content: the XML text content if any
1583 *
1584 * Creation of a new node element within a document. @ns and @content
1585 * are optional (NULL).
1586 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1587 * references, but XML special chars need to be escaped first by using
1588 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1589 * need entities support.
1590 *
1591 * Returns a pointer to the new node object.
1592 */
1593xmlNodePtr
1594xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
1595 xmlChar *name, const xmlChar *content) {
1596 xmlNodePtr cur;
1597
1598 cur = xmlNewNodeEatName(ns, name);
1599 if (cur != NULL) {
1600 cur->doc = doc;
1601 if (content != NULL) {
1602 cur->children = xmlStringGetNodeList(doc, content);
1603 UPDATE_LAST_CHILD_AND_PARENT(cur)
1604 }
1605 }
1606 return(cur);
1607}
1608
Owen Taylor3473f882001-02-23 17:55:21 +00001609
1610/**
1611 * xmlNewDocRawNode:
1612 * @doc: the document
1613 * @ns: namespace if any
1614 * @name: the node name
1615 * @content: the text content if any
1616 *
1617 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001618 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001619 *
1620 * Returns a pointer to the new node object.
1621 */
1622xmlNodePtr
1623xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1624 const xmlChar *name, const xmlChar *content) {
1625 xmlNodePtr cur;
1626
1627 cur = xmlNewNode(ns, name);
1628 if (cur != NULL) {
1629 cur->doc = doc;
1630 if (content != NULL) {
1631 cur->children = xmlNewDocText(doc, content);
1632 UPDATE_LAST_CHILD_AND_PARENT(cur)
1633 }
1634 }
1635 return(cur);
1636}
1637
1638/**
1639 * xmlNewDocFragment:
1640 * @doc: the document owning the fragment
1641 *
1642 * Creation of a new Fragment node.
1643 * Returns a pointer to the new node object.
1644 */
1645xmlNodePtr
1646xmlNewDocFragment(xmlDocPtr doc) {
1647 xmlNodePtr cur;
1648
1649 /*
1650 * Allocate a new DocumentFragment node and fill the fields.
1651 */
1652 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1653 if (cur == NULL) {
1654 xmlGenericError(xmlGenericErrorContext,
1655 "xmlNewDocFragment : malloc failed\n");
1656 return(NULL);
1657 }
1658 memset(cur, 0, sizeof(xmlNode));
1659 cur->type = XML_DOCUMENT_FRAG_NODE;
1660
1661 cur->doc = doc;
1662 return(cur);
1663}
1664
1665/**
1666 * xmlNewText:
1667 * @content: the text content
1668 *
1669 * Creation of a new text node.
1670 * Returns a pointer to the new node object.
1671 */
1672xmlNodePtr
1673xmlNewText(const xmlChar *content) {
1674 xmlNodePtr cur;
1675
1676 /*
1677 * Allocate a new node and fill the fields.
1678 */
1679 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1680 if (cur == NULL) {
1681 xmlGenericError(xmlGenericErrorContext,
1682 "xmlNewText : malloc failed\n");
1683 return(NULL);
1684 }
1685 memset(cur, 0, sizeof(xmlNode));
1686 cur->type = XML_TEXT_NODE;
1687
1688 cur->name = xmlStringText;
1689 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001690 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001691 }
1692 return(cur);
1693}
1694
1695/**
1696 * xmlNewTextChild:
1697 * @parent: the parent node
1698 * @ns: a namespace if any
1699 * @name: the name of the child
1700 * @content: the text content of the child if any.
1701 *
1702 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001703 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001704 * a child TEXT node will be created containing the string content.
1705 *
1706 * Returns a pointer to the new node object.
1707 */
1708xmlNodePtr
1709xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1710 const xmlChar *name, const xmlChar *content) {
1711 xmlNodePtr cur, prev;
1712
1713 if (parent == NULL) {
1714#ifdef DEBUG_TREE
1715 xmlGenericError(xmlGenericErrorContext,
1716 "xmlNewTextChild : parent == NULL\n");
1717#endif
1718 return(NULL);
1719 }
1720
1721 if (name == NULL) {
1722#ifdef DEBUG_TREE
1723 xmlGenericError(xmlGenericErrorContext,
1724 "xmlNewTextChild : name == NULL\n");
1725#endif
1726 return(NULL);
1727 }
1728
1729 /*
1730 * Allocate a new node
1731 */
1732 if (ns == NULL)
1733 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1734 else
1735 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1736 if (cur == NULL) return(NULL);
1737
1738 /*
1739 * add the new element at the end of the children list.
1740 */
1741 cur->type = XML_ELEMENT_NODE;
1742 cur->parent = parent;
1743 cur->doc = parent->doc;
1744 if (parent->children == NULL) {
1745 parent->children = cur;
1746 parent->last = cur;
1747 } else {
1748 prev = parent->last;
1749 prev->next = cur;
1750 cur->prev = prev;
1751 parent->last = cur;
1752 }
1753
1754 return(cur);
1755}
1756
1757/**
1758 * xmlNewCharRef:
1759 * @doc: the document
1760 * @name: the char ref string, starting with # or "&# ... ;"
1761 *
1762 * Creation of a new character reference node.
1763 * Returns a pointer to the new node object.
1764 */
1765xmlNodePtr
1766xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1767 xmlNodePtr cur;
1768
1769 /*
1770 * Allocate a new node and fill the fields.
1771 */
1772 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1773 if (cur == NULL) {
1774 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001775 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001776 return(NULL);
1777 }
1778 memset(cur, 0, sizeof(xmlNode));
1779 cur->type = XML_ENTITY_REF_NODE;
1780
1781 cur->doc = doc;
1782 if (name[0] == '&') {
1783 int len;
1784 name++;
1785 len = xmlStrlen(name);
1786 if (name[len - 1] == ';')
1787 cur->name = xmlStrndup(name, len - 1);
1788 else
1789 cur->name = xmlStrndup(name, len);
1790 } else
1791 cur->name = xmlStrdup(name);
1792 return(cur);
1793}
1794
1795/**
1796 * xmlNewReference:
1797 * @doc: the document
1798 * @name: the reference name, or the reference string with & and ;
1799 *
1800 * Creation of a new reference node.
1801 * Returns a pointer to the new node object.
1802 */
1803xmlNodePtr
1804xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1805 xmlNodePtr cur;
1806 xmlEntityPtr ent;
1807
1808 /*
1809 * Allocate a new node and fill the fields.
1810 */
1811 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1812 if (cur == NULL) {
1813 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001814 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001815 return(NULL);
1816 }
1817 memset(cur, 0, sizeof(xmlNode));
1818 cur->type = XML_ENTITY_REF_NODE;
1819
1820 cur->doc = doc;
1821 if (name[0] == '&') {
1822 int len;
1823 name++;
1824 len = xmlStrlen(name);
1825 if (name[len - 1] == ';')
1826 cur->name = xmlStrndup(name, len - 1);
1827 else
1828 cur->name = xmlStrndup(name, len);
1829 } else
1830 cur->name = xmlStrdup(name);
1831
1832 ent = xmlGetDocEntity(doc, cur->name);
1833 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001834 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00001835 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001836 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00001837 * updated. Not sure if this is 100% correct.
1838 * -George
1839 */
1840 cur->children = (xmlNodePtr) ent;
1841 cur->last = (xmlNodePtr) ent;
1842 }
1843 return(cur);
1844}
1845
1846/**
1847 * xmlNewDocText:
1848 * @doc: the document
1849 * @content: the text content
1850 *
1851 * Creation of a new text node within a document.
1852 * Returns a pointer to the new node object.
1853 */
1854xmlNodePtr
1855xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1856 xmlNodePtr cur;
1857
1858 cur = xmlNewText(content);
1859 if (cur != NULL) cur->doc = doc;
1860 return(cur);
1861}
1862
1863/**
1864 * xmlNewTextLen:
1865 * @content: the text content
1866 * @len: the text len.
1867 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001868 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00001869 * Returns a pointer to the new node object.
1870 */
1871xmlNodePtr
1872xmlNewTextLen(const xmlChar *content, int len) {
1873 xmlNodePtr cur;
1874
1875 /*
1876 * Allocate a new node and fill the fields.
1877 */
1878 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1879 if (cur == NULL) {
1880 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001881 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001882 return(NULL);
1883 }
1884 memset(cur, 0, sizeof(xmlNode));
1885 cur->type = XML_TEXT_NODE;
1886
1887 cur->name = xmlStringText;
1888 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001889 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001890 }
1891 return(cur);
1892}
1893
1894/**
1895 * xmlNewDocTextLen:
1896 * @doc: the document
1897 * @content: the text content
1898 * @len: the text len.
1899 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001900 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00001901 * text node pertain to a given document.
1902 * Returns a pointer to the new node object.
1903 */
1904xmlNodePtr
1905xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1906 xmlNodePtr cur;
1907
1908 cur = xmlNewTextLen(content, len);
1909 if (cur != NULL) cur->doc = doc;
1910 return(cur);
1911}
1912
1913/**
1914 * xmlNewComment:
1915 * @content: the comment content
1916 *
1917 * Creation of a new node containing a comment.
1918 * Returns a pointer to the new node object.
1919 */
1920xmlNodePtr
1921xmlNewComment(const xmlChar *content) {
1922 xmlNodePtr cur;
1923
1924 /*
1925 * Allocate a new node and fill the fields.
1926 */
1927 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1928 if (cur == NULL) {
1929 xmlGenericError(xmlGenericErrorContext,
1930 "xmlNewComment : malloc failed\n");
1931 return(NULL);
1932 }
1933 memset(cur, 0, sizeof(xmlNode));
1934 cur->type = XML_COMMENT_NODE;
1935
1936 cur->name = xmlStringComment;
1937 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001938 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001939 }
1940 return(cur);
1941}
1942
1943/**
1944 * xmlNewCDataBlock:
1945 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00001946 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00001947 * @len: the length of the block
1948 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001949 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00001950 * Returns a pointer to the new node object.
1951 */
1952xmlNodePtr
1953xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1954 xmlNodePtr cur;
1955
1956 /*
1957 * Allocate a new node and fill the fields.
1958 */
1959 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1960 if (cur == NULL) {
1961 xmlGenericError(xmlGenericErrorContext,
1962 "xmlNewCDataBlock : malloc failed\n");
1963 return(NULL);
1964 }
1965 memset(cur, 0, sizeof(xmlNode));
1966 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001967 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001968
1969 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001970 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001971 }
1972 return(cur);
1973}
1974
1975/**
1976 * xmlNewDocComment:
1977 * @doc: the document
1978 * @content: the comment content
1979 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001980 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00001981 * Returns a pointer to the new node object.
1982 */
1983xmlNodePtr
1984xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1985 xmlNodePtr cur;
1986
1987 cur = xmlNewComment(content);
1988 if (cur != NULL) cur->doc = doc;
1989 return(cur);
1990}
1991
1992/**
1993 * xmlSetTreeDoc:
1994 * @tree: the top element
1995 * @doc: the document
1996 *
1997 * update all nodes under the tree to point to the right document
1998 */
1999void
2000xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002001 xmlAttrPtr prop;
2002
Owen Taylor3473f882001-02-23 17:55:21 +00002003 if (tree == NULL)
2004 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002005 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002006 if(tree->type == XML_ELEMENT_NODE) {
2007 prop = tree->properties;
2008 while (prop != NULL) {
2009 prop->doc = doc;
2010 xmlSetListDoc(prop->children, doc);
2011 prop = prop->next;
2012 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002013 }
Owen Taylor3473f882001-02-23 17:55:21 +00002014 if (tree->children != NULL)
2015 xmlSetListDoc(tree->children, doc);
2016 tree->doc = doc;
2017 }
2018}
2019
2020/**
2021 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002022 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002023 * @doc: the document
2024 *
2025 * update all nodes in the list to point to the right document
2026 */
2027void
2028xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2029 xmlNodePtr cur;
2030
2031 if (list == NULL)
2032 return;
2033 cur = list;
2034 while (cur != NULL) {
2035 if (cur->doc != doc)
2036 xmlSetTreeDoc(cur, doc);
2037 cur = cur->next;
2038 }
2039}
2040
2041
2042/**
2043 * xmlNewChild:
2044 * @parent: the parent node
2045 * @ns: a namespace if any
2046 * @name: the name of the child
2047 * @content: the XML content of the child if any.
2048 *
2049 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002050 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002051 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2052 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2053 * references, but XML special chars need to be escaped first by using
2054 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2055 * support is not needed.
2056 *
2057 * Returns a pointer to the new node object.
2058 */
2059xmlNodePtr
2060xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2061 const xmlChar *name, const xmlChar *content) {
2062 xmlNodePtr cur, prev;
2063
2064 if (parent == NULL) {
2065#ifdef DEBUG_TREE
2066 xmlGenericError(xmlGenericErrorContext,
2067 "xmlNewChild : parent == NULL\n");
2068#endif
2069 return(NULL);
2070 }
2071
2072 if (name == NULL) {
2073#ifdef DEBUG_TREE
2074 xmlGenericError(xmlGenericErrorContext,
2075 "xmlNewChild : name == NULL\n");
2076#endif
2077 return(NULL);
2078 }
2079
2080 /*
2081 * Allocate a new node
2082 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002083 if (parent->type == XML_ELEMENT_NODE) {
2084 if (ns == NULL)
2085 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2086 else
2087 cur = xmlNewDocNode(parent->doc, ns, name, content);
2088 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2089 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2090 if (ns == NULL)
2091 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2092 else
2093 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002094 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2095 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002096 } else {
2097 return(NULL);
2098 }
Owen Taylor3473f882001-02-23 17:55:21 +00002099 if (cur == NULL) return(NULL);
2100
2101 /*
2102 * add the new element at the end of the children list.
2103 */
2104 cur->type = XML_ELEMENT_NODE;
2105 cur->parent = parent;
2106 cur->doc = parent->doc;
2107 if (parent->children == NULL) {
2108 parent->children = cur;
2109 parent->last = cur;
2110 } else {
2111 prev = parent->last;
2112 prev->next = cur;
2113 cur->prev = prev;
2114 parent->last = cur;
2115 }
2116
2117 return(cur);
2118}
2119
2120/**
2121 * xmlAddNextSibling:
2122 * @cur: the child node
2123 * @elem: the new node
2124 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002125 * Add a new node @elem as the next sibling of @cur
2126 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002127 * first unlinked from its existing context.
2128 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002129 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2130 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002131 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002132 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002133 */
2134xmlNodePtr
2135xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2136 if (cur == NULL) {
2137#ifdef DEBUG_TREE
2138 xmlGenericError(xmlGenericErrorContext,
2139 "xmlAddNextSibling : cur == NULL\n");
2140#endif
2141 return(NULL);
2142 }
2143 if (elem == NULL) {
2144#ifdef DEBUG_TREE
2145 xmlGenericError(xmlGenericErrorContext,
2146 "xmlAddNextSibling : elem == NULL\n");
2147#endif
2148 return(NULL);
2149 }
2150
2151 xmlUnlinkNode(elem);
2152
2153 if (elem->type == XML_TEXT_NODE) {
2154 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002155 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002156 xmlFreeNode(elem);
2157 return(cur);
2158 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002159 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2160 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002161 xmlChar *tmp;
2162
2163 tmp = xmlStrdup(elem->content);
2164 tmp = xmlStrcat(tmp, cur->next->content);
2165 xmlNodeSetContent(cur->next, tmp);
2166 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002167 xmlFreeNode(elem);
2168 return(cur->next);
2169 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002170 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2171 /* check if an attribute with the same name exists */
2172 xmlAttrPtr attr;
2173
2174 if (elem->ns == NULL)
2175 attr = xmlHasProp(cur->parent, elem->name);
2176 else
2177 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2178 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2179 /* different instance, destroy it (attributes must be unique) */
2180 xmlFreeProp(attr);
2181 }
Owen Taylor3473f882001-02-23 17:55:21 +00002182 }
2183
2184 if (elem->doc != cur->doc) {
2185 xmlSetTreeDoc(elem, cur->doc);
2186 }
2187 elem->parent = cur->parent;
2188 elem->prev = cur;
2189 elem->next = cur->next;
2190 cur->next = elem;
2191 if (elem->next != NULL)
2192 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002193 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002194 elem->parent->last = elem;
2195 return(elem);
2196}
2197
2198/**
2199 * xmlAddPrevSibling:
2200 * @cur: the child node
2201 * @elem: the new node
2202 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002203 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002204 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002205 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002206 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002207 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2208 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002209 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002210 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002211 */
2212xmlNodePtr
2213xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2214 if (cur == NULL) {
2215#ifdef DEBUG_TREE
2216 xmlGenericError(xmlGenericErrorContext,
2217 "xmlAddPrevSibling : cur == NULL\n");
2218#endif
2219 return(NULL);
2220 }
2221 if (elem == NULL) {
2222#ifdef DEBUG_TREE
2223 xmlGenericError(xmlGenericErrorContext,
2224 "xmlAddPrevSibling : elem == NULL\n");
2225#endif
2226 return(NULL);
2227 }
2228
2229 xmlUnlinkNode(elem);
2230
2231 if (elem->type == XML_TEXT_NODE) {
2232 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002233 xmlChar *tmp;
2234
2235 tmp = xmlStrdup(elem->content);
2236 tmp = xmlStrcat(tmp, cur->content);
2237 xmlNodeSetContent(cur, tmp);
2238 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002239 xmlFreeNode(elem);
2240 return(cur);
2241 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002242 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2243 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002244 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002245 xmlFreeNode(elem);
2246 return(cur->prev);
2247 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002248 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2249 /* check if an attribute with the same name exists */
2250 xmlAttrPtr attr;
2251
2252 if (elem->ns == NULL)
2253 attr = xmlHasProp(cur->parent, elem->name);
2254 else
2255 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2256 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2257 /* different instance, destroy it (attributes must be unique) */
2258 xmlFreeProp(attr);
2259 }
Owen Taylor3473f882001-02-23 17:55:21 +00002260 }
2261
2262 if (elem->doc != cur->doc) {
2263 xmlSetTreeDoc(elem, cur->doc);
2264 }
2265 elem->parent = cur->parent;
2266 elem->next = cur;
2267 elem->prev = cur->prev;
2268 cur->prev = elem;
2269 if (elem->prev != NULL)
2270 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002271 if (elem->parent != NULL) {
2272 if (elem->type == XML_ATTRIBUTE_NODE) {
2273 if (elem->parent->properties == (xmlAttrPtr) cur) {
2274 elem->parent->properties = (xmlAttrPtr) elem;
2275 }
2276 } else {
2277 if (elem->parent->children == cur) {
2278 elem->parent->children = elem;
2279 }
2280 }
2281 }
Owen Taylor3473f882001-02-23 17:55:21 +00002282 return(elem);
2283}
2284
2285/**
2286 * xmlAddSibling:
2287 * @cur: the child node
2288 * @elem: the new node
2289 *
2290 * Add a new element @elem to the list of siblings of @cur
2291 * merging adjacent TEXT nodes (@elem may be freed)
2292 * If the new element was already inserted in a document it is
2293 * first unlinked from its existing context.
2294 *
2295 * Returns the new element or NULL in case of error.
2296 */
2297xmlNodePtr
2298xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2299 xmlNodePtr parent;
2300
2301 if (cur == NULL) {
2302#ifdef DEBUG_TREE
2303 xmlGenericError(xmlGenericErrorContext,
2304 "xmlAddSibling : cur == NULL\n");
2305#endif
2306 return(NULL);
2307 }
2308
2309 if (elem == NULL) {
2310#ifdef DEBUG_TREE
2311 xmlGenericError(xmlGenericErrorContext,
2312 "xmlAddSibling : elem == NULL\n");
2313#endif
2314 return(NULL);
2315 }
2316
2317 /*
2318 * Constant time is we can rely on the ->parent->last to find
2319 * the last sibling.
2320 */
2321 if ((cur->parent != NULL) &&
2322 (cur->parent->children != NULL) &&
2323 (cur->parent->last != NULL) &&
2324 (cur->parent->last->next == NULL)) {
2325 cur = cur->parent->last;
2326 } else {
2327 while (cur->next != NULL) cur = cur->next;
2328 }
2329
2330 xmlUnlinkNode(elem);
2331
2332 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002333 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002334 xmlFreeNode(elem);
2335 return(cur);
2336 }
2337
2338 if (elem->doc != cur->doc) {
2339 xmlSetTreeDoc(elem, cur->doc);
2340 }
2341 parent = cur->parent;
2342 elem->prev = cur;
2343 elem->next = NULL;
2344 elem->parent = parent;
2345 cur->next = elem;
2346 if (parent != NULL)
2347 parent->last = elem;
2348
2349 return(elem);
2350}
2351
2352/**
2353 * xmlAddChildList:
2354 * @parent: the parent node
2355 * @cur: the first node in the list
2356 *
2357 * Add a list of node at the end of the child list of the parent
2358 * merging adjacent TEXT nodes (@cur may be freed)
2359 *
2360 * Returns the last child or NULL in case of error.
2361 */
2362xmlNodePtr
2363xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2364 xmlNodePtr prev;
2365
2366 if (parent == NULL) {
2367#ifdef DEBUG_TREE
2368 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002369 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002370#endif
2371 return(NULL);
2372 }
2373
2374 if (cur == NULL) {
2375#ifdef DEBUG_TREE
2376 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002377 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002378#endif
2379 return(NULL);
2380 }
2381
2382 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2383 (cur->doc != parent->doc)) {
2384#ifdef DEBUG_TREE
2385 xmlGenericError(xmlGenericErrorContext,
2386 "Elements moved to a different document\n");
2387#endif
2388 }
2389
2390 /*
2391 * add the first element at the end of the children list.
2392 */
2393 if (parent->children == NULL) {
2394 parent->children = cur;
2395 } else {
2396 /*
2397 * If cur and parent->last both are TEXT nodes, then merge them.
2398 */
2399 if ((cur->type == XML_TEXT_NODE) &&
2400 (parent->last->type == XML_TEXT_NODE) &&
2401 (cur->name == parent->last->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002402 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002403 /*
2404 * if it's the only child, nothing more to be done.
2405 */
2406 if (cur->next == NULL) {
2407 xmlFreeNode(cur);
2408 return(parent->last);
2409 }
2410 prev = cur;
2411 cur = cur->next;
2412 xmlFreeNode(prev);
2413 }
2414 prev = parent->last;
2415 prev->next = cur;
2416 cur->prev = prev;
2417 }
2418 while (cur->next != NULL) {
2419 cur->parent = parent;
2420 if (cur->doc != parent->doc) {
2421 xmlSetTreeDoc(cur, parent->doc);
2422 }
2423 cur = cur->next;
2424 }
2425 cur->parent = parent;
2426 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2427 parent->last = cur;
2428
2429 return(cur);
2430}
2431
2432/**
2433 * xmlAddChild:
2434 * @parent: the parent node
2435 * @cur: the child node
2436 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002437 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002438 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002439 * If the new node was already inserted in a document it is
2440 * first unlinked from its existing context.
2441 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2442 * If there is an attribute with equal name, it is first destroyed.
2443 *
Owen Taylor3473f882001-02-23 17:55:21 +00002444 * Returns the child or NULL in case of error.
2445 */
2446xmlNodePtr
2447xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2448 xmlNodePtr prev;
2449
2450 if (parent == NULL) {
2451#ifdef DEBUG_TREE
2452 xmlGenericError(xmlGenericErrorContext,
2453 "xmlAddChild : parent == NULL\n");
2454#endif
2455 return(NULL);
2456 }
2457
2458 if (cur == NULL) {
2459#ifdef DEBUG_TREE
2460 xmlGenericError(xmlGenericErrorContext,
2461 "xmlAddChild : child == NULL\n");
2462#endif
2463 return(NULL);
2464 }
2465
Owen Taylor3473f882001-02-23 17:55:21 +00002466 /*
2467 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002468 * cur is then freed.
2469 */
2470 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002471 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002472 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002473 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002474 xmlFreeNode(cur);
2475 return(parent);
2476 }
2477 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2478 (parent->last->name == cur->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002479 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002480 xmlFreeNode(cur);
2481 return(parent->last);
2482 }
2483 }
2484
2485 /*
2486 * add the new element at the end of the children list.
2487 */
2488 cur->parent = parent;
2489 if (cur->doc != parent->doc) {
2490 xmlSetTreeDoc(cur, parent->doc);
2491 }
2492
2493 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002494 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002495 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002496 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002497 (parent->content != NULL)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002498 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002499 xmlFreeNode(cur);
2500 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002501 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002502 if (cur->type == XML_ATTRIBUTE_NODE) {
2503 if (parent->properties == NULL) {
2504 parent->properties = (xmlAttrPtr) cur;
2505 } else {
2506 /* check if an attribute with the same name exists */
2507 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002508
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002509 if (cur->ns == NULL)
2510 lastattr = xmlHasProp(parent, cur->name);
2511 else
2512 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2513 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2514 /* different instance, destroy it (attributes must be unique) */
2515 xmlFreeProp(lastattr);
2516 }
2517 /* find the end */
2518 lastattr = parent->properties;
2519 while (lastattr->next != NULL) {
2520 lastattr = lastattr->next;
2521 }
2522 lastattr->next = (xmlAttrPtr) cur;
2523 ((xmlAttrPtr) cur)->prev = lastattr;
2524 }
2525 } else {
2526 if (parent->children == NULL) {
2527 parent->children = cur;
2528 parent->last = cur;
2529 } else {
2530 prev = parent->last;
2531 prev->next = cur;
2532 cur->prev = prev;
2533 parent->last = cur;
2534 }
2535 }
Owen Taylor3473f882001-02-23 17:55:21 +00002536 return(cur);
2537}
2538
2539/**
2540 * xmlGetLastChild:
2541 * @parent: the parent node
2542 *
2543 * Search the last child of a node.
2544 * Returns the last child or NULL if none.
2545 */
2546xmlNodePtr
2547xmlGetLastChild(xmlNodePtr parent) {
2548 if (parent == NULL) {
2549#ifdef DEBUG_TREE
2550 xmlGenericError(xmlGenericErrorContext,
2551 "xmlGetLastChild : parent == NULL\n");
2552#endif
2553 return(NULL);
2554 }
2555 return(parent->last);
2556}
2557
2558/**
2559 * xmlFreeNodeList:
2560 * @cur: the first node in the list
2561 *
2562 * Free a node and all its siblings, this is a recursive behaviour, all
2563 * the children are freed too.
2564 */
2565void
2566xmlFreeNodeList(xmlNodePtr cur) {
2567 xmlNodePtr next;
2568 if (cur == NULL) {
2569#ifdef DEBUG_TREE
2570 xmlGenericError(xmlGenericErrorContext,
2571 "xmlFreeNodeList : node == NULL\n");
2572#endif
2573 return;
2574 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002575 if (cur->type == XML_NAMESPACE_DECL) {
2576 xmlFreeNsList((xmlNsPtr) cur);
2577 return;
2578 }
Owen Taylor3473f882001-02-23 17:55:21 +00002579 while (cur != NULL) {
2580 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002581 /* unroll to speed up freeing the document */
2582 if (cur->type != XML_DTD_NODE) {
2583 if ((cur->children != NULL) &&
2584 (cur->type != XML_ENTITY_REF_NODE))
2585 xmlFreeNodeList(cur->children);
2586 if (cur->properties != NULL)
2587 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002588 if ((cur->type != XML_ELEMENT_NODE) &&
2589 (cur->type != XML_XINCLUDE_START) &&
2590 (cur->type != XML_XINCLUDE_END) &&
2591 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002592 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002593 }
2594 if (((cur->type == XML_ELEMENT_NODE) ||
2595 (cur->type == XML_XINCLUDE_START) ||
2596 (cur->type == XML_XINCLUDE_END)) &&
2597 (cur->nsDef != NULL))
2598 xmlFreeNsList(cur->nsDef);
2599
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002600 /*
2601 * When a node is a text node or a comment, it uses a global static
2602 * variable for the name of the node.
2603 *
2604 * The xmlStrEqual comparisons need to be done when (happened with
2605 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002606 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002607 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002608 * the string addresses compare are not sufficient.
2609 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002610 if ((cur->name != NULL) &&
2611 (cur->name != xmlStringText) &&
2612 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002613 (cur->name != xmlStringComment)) {
2614 if (cur->type == XML_TEXT_NODE) {
2615 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2616 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2617 xmlFree((char *) cur->name);
2618 } else if (cur->type == XML_COMMENT_NODE) {
2619 if (!xmlStrEqual(cur->name, xmlStringComment))
2620 xmlFree((char *) cur->name);
2621 } else
2622 xmlFree((char *) cur->name);
2623 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002624 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002625 xmlFree(cur);
2626 }
Owen Taylor3473f882001-02-23 17:55:21 +00002627 cur = next;
2628 }
2629}
2630
2631/**
2632 * xmlFreeNode:
2633 * @cur: the node
2634 *
2635 * Free a node, this is a recursive behaviour, all the children are freed too.
2636 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2637 */
2638void
2639xmlFreeNode(xmlNodePtr cur) {
2640 if (cur == NULL) {
2641#ifdef DEBUG_TREE
2642 xmlGenericError(xmlGenericErrorContext,
2643 "xmlFreeNode : node == NULL\n");
2644#endif
2645 return;
2646 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002647 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002648 if (cur->type == XML_DTD_NODE) {
2649 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002650 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002651 }
2652 if (cur->type == XML_NAMESPACE_DECL) {
2653 xmlFreeNs((xmlNsPtr) cur);
2654 return;
2655 }
Owen Taylor3473f882001-02-23 17:55:21 +00002656 if ((cur->children != NULL) &&
2657 (cur->type != XML_ENTITY_REF_NODE))
2658 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002659 if (cur->properties != NULL)
2660 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002661 if ((cur->type != XML_ELEMENT_NODE) &&
2662 (cur->content != NULL) &&
2663 (cur->type != XML_ENTITY_REF_NODE) &&
2664 (cur->type != XML_XINCLUDE_END) &&
2665 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002666 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002667 }
2668
Daniel Veillardacd370f2001-06-09 17:17:51 +00002669 /*
2670 * When a node is a text node or a comment, it uses a global static
2671 * variable for the name of the node.
2672 *
2673 * The xmlStrEqual comparisons need to be done when (happened with
2674 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002675 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002676 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002677 * are not sufficient.
2678 */
Owen Taylor3473f882001-02-23 17:55:21 +00002679 if ((cur->name != NULL) &&
2680 (cur->name != xmlStringText) &&
2681 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002682 (cur->name != xmlStringComment)) {
2683 if (cur->type == XML_TEXT_NODE) {
2684 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2685 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2686 xmlFree((char *) cur->name);
2687 } else if (cur->type == XML_COMMENT_NODE) {
2688 if (!xmlStrEqual(cur->name, xmlStringComment))
2689 xmlFree((char *) cur->name);
2690 } else
2691 xmlFree((char *) cur->name);
2692 }
2693
Owen Taylor3473f882001-02-23 17:55:21 +00002694 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002695 xmlFree(cur);
2696}
2697
2698/**
2699 * xmlUnlinkNode:
2700 * @cur: the node
2701 *
2702 * Unlink a node from it's current context, the node is not freed
2703 */
2704void
2705xmlUnlinkNode(xmlNodePtr cur) {
2706 if (cur == NULL) {
2707#ifdef DEBUG_TREE
2708 xmlGenericError(xmlGenericErrorContext,
2709 "xmlUnlinkNode : node == NULL\n");
2710#endif
2711 return;
2712 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002713 if (cur->type == XML_DTD_NODE) {
2714 xmlDocPtr doc;
2715 doc = cur->doc;
2716 if (doc->intSubset == (xmlDtdPtr) cur)
2717 doc->intSubset = NULL;
2718 if (doc->extSubset == (xmlDtdPtr) cur)
2719 doc->extSubset = NULL;
2720 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002721 if (cur->parent != NULL) {
2722 xmlNodePtr parent;
2723 parent = cur->parent;
2724 if (cur->type == XML_ATTRIBUTE_NODE) {
2725 if (parent->properties == (xmlAttrPtr) cur)
2726 parent->properties = ((xmlAttrPtr) cur)->next;
2727 } else {
2728 if (parent->children == cur)
2729 parent->children = cur->next;
2730 if (parent->last == cur)
2731 parent->last = cur->prev;
2732 }
2733 cur->parent = NULL;
2734 }
Owen Taylor3473f882001-02-23 17:55:21 +00002735 if (cur->next != NULL)
2736 cur->next->prev = cur->prev;
2737 if (cur->prev != NULL)
2738 cur->prev->next = cur->next;
2739 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002740}
2741
2742/**
2743 * xmlReplaceNode:
2744 * @old: the old node
2745 * @cur: the node
2746 *
2747 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002748 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002749 * first unlinked from its existing context.
2750 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002751 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002752 */
2753xmlNodePtr
2754xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2755 if (old == NULL) {
2756#ifdef DEBUG_TREE
2757 xmlGenericError(xmlGenericErrorContext,
2758 "xmlReplaceNode : old == NULL\n");
2759#endif
2760 return(NULL);
2761 }
2762 if (cur == NULL) {
2763 xmlUnlinkNode(old);
2764 return(old);
2765 }
2766 if (cur == old) {
2767 return(old);
2768 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002769 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2770#ifdef DEBUG_TREE
2771 xmlGenericError(xmlGenericErrorContext,
2772 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2773#endif
2774 return(old);
2775 }
2776 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2777#ifdef DEBUG_TREE
2778 xmlGenericError(xmlGenericErrorContext,
2779 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2780#endif
2781 return(old);
2782 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002783 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2784#ifdef DEBUG_TREE
2785 xmlGenericError(xmlGenericErrorContext,
2786 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2787#endif
2788 return(old);
2789 }
2790 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2791#ifdef DEBUG_TREE
2792 xmlGenericError(xmlGenericErrorContext,
2793 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2794#endif
2795 return(old);
2796 }
Owen Taylor3473f882001-02-23 17:55:21 +00002797 xmlUnlinkNode(cur);
2798 cur->doc = old->doc;
2799 cur->parent = old->parent;
2800 cur->next = old->next;
2801 if (cur->next != NULL)
2802 cur->next->prev = cur;
2803 cur->prev = old->prev;
2804 if (cur->prev != NULL)
2805 cur->prev->next = cur;
2806 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002807 if (cur->type == XML_ATTRIBUTE_NODE) {
2808 if (cur->parent->properties == (xmlAttrPtr)old)
2809 cur->parent->properties = ((xmlAttrPtr) cur);
2810 } else {
2811 if (cur->parent->children == old)
2812 cur->parent->children = cur;
2813 if (cur->parent->last == old)
2814 cur->parent->last = cur;
2815 }
Owen Taylor3473f882001-02-23 17:55:21 +00002816 }
2817 old->next = old->prev = NULL;
2818 old->parent = NULL;
2819 return(old);
2820}
2821
2822/************************************************************************
2823 * *
2824 * Copy operations *
2825 * *
2826 ************************************************************************/
2827
2828/**
2829 * xmlCopyNamespace:
2830 * @cur: the namespace
2831 *
2832 * Do a copy of the namespace.
2833 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002834 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002835 */
2836xmlNsPtr
2837xmlCopyNamespace(xmlNsPtr cur) {
2838 xmlNsPtr ret;
2839
2840 if (cur == NULL) return(NULL);
2841 switch (cur->type) {
2842 case XML_LOCAL_NAMESPACE:
2843 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2844 break;
2845 default:
2846#ifdef DEBUG_TREE
2847 xmlGenericError(xmlGenericErrorContext,
2848 "xmlCopyNamespace: invalid type %d\n", cur->type);
2849#endif
2850 return(NULL);
2851 }
2852 return(ret);
2853}
2854
2855/**
2856 * xmlCopyNamespaceList:
2857 * @cur: the first namespace
2858 *
2859 * Do a copy of an namespace list.
2860 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002861 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002862 */
2863xmlNsPtr
2864xmlCopyNamespaceList(xmlNsPtr cur) {
2865 xmlNsPtr ret = NULL;
2866 xmlNsPtr p = NULL,q;
2867
2868 while (cur != NULL) {
2869 q = xmlCopyNamespace(cur);
2870 if (p == NULL) {
2871 ret = p = q;
2872 } else {
2873 p->next = q;
2874 p = q;
2875 }
2876 cur = cur->next;
2877 }
2878 return(ret);
2879}
2880
2881static xmlNodePtr
2882xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2883/**
2884 * xmlCopyProp:
2885 * @target: the element where the attribute will be grafted
2886 * @cur: the attribute
2887 *
2888 * Do a copy of the attribute.
2889 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002890 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002891 */
2892xmlAttrPtr
2893xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2894 xmlAttrPtr ret;
2895
2896 if (cur == NULL) return(NULL);
2897 if (target != NULL)
2898 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2899 else if (cur->parent != NULL)
2900 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2901 else if (cur->children != NULL)
2902 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2903 else
2904 ret = xmlNewDocProp(NULL, cur->name, NULL);
2905 if (ret == NULL) return(NULL);
2906 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002907
Owen Taylor3473f882001-02-23 17:55:21 +00002908 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00002909 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002910/*
2911 * if (target->doc)
2912 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2913 * else if (cur->doc) / * target may not yet have a doc : KPI * /
2914 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
2915 * else
2916 * ns = NULL;
2917 * ret->ns = ns;
2918 */
2919 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2920 if (ns == NULL) {
2921 /*
2922 * Humm, we are copying an element whose namespace is defined
2923 * out of the new tree scope. Search it in the original tree
2924 * and add it at the top of the new tree
2925 */
2926 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
2927 if (ns != NULL) {
2928 xmlNodePtr root = target;
2929 xmlNodePtr pred = NULL;
2930
2931 while (root->parent != NULL) {
2932 pred = root;
2933 root = root->parent;
2934 }
2935 if (root == (xmlNodePtr) target->doc) {
2936 /* correct possibly cycling above the document elt */
2937 root = pred;
2938 }
2939 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
2940 }
2941 } else {
2942 /*
2943 * we have to find something appropriate here since
2944 * we cant be sure, that the namespce we found is identified
2945 * by the prefix
2946 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002947 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002948 /* this is the nice case */
2949 ret->ns = ns;
2950 } else {
2951 /*
2952 * we are in trouble: we need a new reconcilied namespace.
2953 * This is expensive
2954 */
2955 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
2956 }
2957 }
2958
Owen Taylor3473f882001-02-23 17:55:21 +00002959 } else
2960 ret->ns = NULL;
2961
2962 if (cur->children != NULL) {
2963 xmlNodePtr tmp;
2964
2965 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2966 ret->last = NULL;
2967 tmp = ret->children;
2968 while (tmp != NULL) {
2969 /* tmp->parent = (xmlNodePtr)ret; */
2970 if (tmp->next == NULL)
2971 ret->last = tmp;
2972 tmp = tmp->next;
2973 }
2974 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002975 /*
2976 * Try to handle IDs
2977 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00002978 if ((target!= NULL) && (cur!= NULL) &&
2979 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002980 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
2981 if (xmlIsID(cur->doc, cur->parent, cur)) {
2982 xmlChar *id;
2983
2984 id = xmlNodeListGetString(cur->doc, cur->children, 1);
2985 if (id != NULL) {
2986 xmlAddID(NULL, target->doc, id, ret);
2987 xmlFree(id);
2988 }
2989 }
2990 }
Owen Taylor3473f882001-02-23 17:55:21 +00002991 return(ret);
2992}
2993
2994/**
2995 * xmlCopyPropList:
2996 * @target: the element where the attributes will be grafted
2997 * @cur: the first attribute
2998 *
2999 * Do a copy of an attribute list.
3000 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003001 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003002 */
3003xmlAttrPtr
3004xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3005 xmlAttrPtr ret = NULL;
3006 xmlAttrPtr p = NULL,q;
3007
3008 while (cur != NULL) {
3009 q = xmlCopyProp(target, cur);
3010 if (p == NULL) {
3011 ret = p = q;
3012 } else {
3013 p->next = q;
3014 q->prev = p;
3015 p = q;
3016 }
3017 cur = cur->next;
3018 }
3019 return(ret);
3020}
3021
3022/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003023 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003024 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003025 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003026 * tricky reason: namespaces. Doing a direct copy of a node
3027 * say RPM:Copyright without changing the namespace pointer to
3028 * something else can produce stale links. One way to do it is
3029 * to keep a reference counter but this doesn't work as soon
3030 * as one move the element or the subtree out of the scope of
3031 * the existing namespace. The actual solution seems to add
3032 * a copy of the namespace at the top of the copied tree if
3033 * not available in the subtree.
3034 * Hence two functions, the public front-end call the inner ones
3035 */
3036
3037static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003038xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003039 int recursive) {
3040 xmlNodePtr ret;
3041
3042 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003043 switch (node->type) {
3044 case XML_TEXT_NODE:
3045 case XML_CDATA_SECTION_NODE:
3046 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003047 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003048 case XML_ENTITY_REF_NODE:
3049 case XML_ENTITY_NODE:
3050 case XML_PI_NODE:
3051 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003052 case XML_XINCLUDE_START:
3053 case XML_XINCLUDE_END:
3054 break;
3055 case XML_ATTRIBUTE_NODE:
3056 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3057 case XML_NAMESPACE_DECL:
3058 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3059
Daniel Veillard39196eb2001-06-19 18:09:42 +00003060 case XML_DOCUMENT_NODE:
3061 case XML_HTML_DOCUMENT_NODE:
3062#ifdef LIBXML_DOCB_ENABLED
3063 case XML_DOCB_DOCUMENT_NODE:
3064#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003065 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003066 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003067 case XML_NOTATION_NODE:
3068 case XML_DTD_NODE:
3069 case XML_ELEMENT_DECL:
3070 case XML_ATTRIBUTE_DECL:
3071 case XML_ENTITY_DECL:
3072 return(NULL);
3073 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003074
Owen Taylor3473f882001-02-23 17:55:21 +00003075 /*
3076 * Allocate a new node and fill the fields.
3077 */
3078 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3079 if (ret == NULL) {
3080 xmlGenericError(xmlGenericErrorContext,
3081 "xmlStaticCopyNode : malloc failed\n");
3082 return(NULL);
3083 }
3084 memset(ret, 0, sizeof(xmlNode));
3085 ret->type = node->type;
3086
3087 ret->doc = doc;
3088 ret->parent = parent;
3089 if (node->name == xmlStringText)
3090 ret->name = xmlStringText;
3091 else if (node->name == xmlStringTextNoenc)
3092 ret->name = xmlStringTextNoenc;
3093 else if (node->name == xmlStringComment)
3094 ret->name = xmlStringComment;
3095 else if (node->name != NULL)
3096 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003097 if ((node->type != XML_ELEMENT_NODE) &&
3098 (node->content != NULL) &&
3099 (node->type != XML_ENTITY_REF_NODE) &&
3100 (node->type != XML_XINCLUDE_END) &&
3101 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003102 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003103 }else{
3104 if (node->type == XML_ELEMENT_NODE)
3105 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003106 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003107 if (parent != NULL) {
3108 xmlNodePtr tmp;
3109
3110 tmp = xmlAddChild(parent, ret);
3111 /* node could have coalesced */
3112 if (tmp != ret)
3113 return(tmp);
3114 }
Owen Taylor3473f882001-02-23 17:55:21 +00003115
3116 if (!recursive) return(ret);
3117 if (node->nsDef != NULL)
3118 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3119
3120 if (node->ns != NULL) {
3121 xmlNsPtr ns;
3122
3123 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3124 if (ns == NULL) {
3125 /*
3126 * Humm, we are copying an element whose namespace is defined
3127 * out of the new tree scope. Search it in the original tree
3128 * and add it at the top of the new tree
3129 */
3130 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3131 if (ns != NULL) {
3132 xmlNodePtr root = ret;
3133
3134 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003135 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003136 }
3137 } else {
3138 /*
3139 * reference the existing namespace definition in our own tree.
3140 */
3141 ret->ns = ns;
3142 }
3143 }
3144 if (node->properties != NULL)
3145 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003146 if (node->type == XML_ENTITY_REF_NODE) {
3147 if ((doc == NULL) || (node->doc != doc)) {
3148 /*
3149 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003150 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003151 * we cannot keep the reference. Try to find it in the
3152 * target document.
3153 */
3154 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3155 } else {
3156 ret->children = node->children;
3157 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003158 ret->last = ret->children;
3159 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003160 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003161 UPDATE_LAST_CHILD_AND_PARENT(ret)
3162 }
Owen Taylor3473f882001-02-23 17:55:21 +00003163 return(ret);
3164}
3165
3166static xmlNodePtr
3167xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3168 xmlNodePtr ret = NULL;
3169 xmlNodePtr p = NULL,q;
3170
3171 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003172 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003173 if (doc == NULL) {
3174 node = node->next;
3175 continue;
3176 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003177 if (doc->intSubset == NULL) {
3178 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3179 q->doc = doc;
3180 q->parent = parent;
3181 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003182 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003183 } else {
3184 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003185 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003186 }
3187 } else
3188 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003189 if (ret == NULL) {
3190 q->prev = NULL;
3191 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003192 } else if (p != q) {
3193 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003194 p->next = q;
3195 q->prev = p;
3196 p = q;
3197 }
3198 node = node->next;
3199 }
3200 return(ret);
3201}
3202
3203/**
3204 * xmlCopyNode:
3205 * @node: the node
3206 * @recursive: if 1 do a recursive copy.
3207 *
3208 * Do a copy of the node.
3209 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003210 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003211 */
3212xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003213xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003214 xmlNodePtr ret;
3215
3216 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3217 return(ret);
3218}
3219
3220/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003221 * xmlDocCopyNode:
3222 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003223 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003224 * @recursive: if 1 do a recursive copy.
3225 *
3226 * Do a copy of the node to a given document.
3227 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003228 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003229 */
3230xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003231xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003232 xmlNodePtr ret;
3233
3234 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3235 return(ret);
3236}
3237
3238/**
Owen Taylor3473f882001-02-23 17:55:21 +00003239 * xmlCopyNodeList:
3240 * @node: the first node in the list.
3241 *
3242 * Do a recursive copy of the node list.
3243 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003244 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003245 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003246xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003247 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3248 return(ret);
3249}
3250
3251/**
Owen Taylor3473f882001-02-23 17:55:21 +00003252 * xmlCopyDtd:
3253 * @dtd: the dtd
3254 *
3255 * Do a copy of the dtd.
3256 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003257 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003258 */
3259xmlDtdPtr
3260xmlCopyDtd(xmlDtdPtr dtd) {
3261 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003262 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003263
3264 if (dtd == NULL) return(NULL);
3265 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3266 if (ret == NULL) return(NULL);
3267 if (dtd->entities != NULL)
3268 ret->entities = (void *) xmlCopyEntitiesTable(
3269 (xmlEntitiesTablePtr) dtd->entities);
3270 if (dtd->notations != NULL)
3271 ret->notations = (void *) xmlCopyNotationTable(
3272 (xmlNotationTablePtr) dtd->notations);
3273 if (dtd->elements != NULL)
3274 ret->elements = (void *) xmlCopyElementTable(
3275 (xmlElementTablePtr) dtd->elements);
3276 if (dtd->attributes != NULL)
3277 ret->attributes = (void *) xmlCopyAttributeTable(
3278 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003279 if (dtd->pentities != NULL)
3280 ret->pentities = (void *) xmlCopyEntitiesTable(
3281 (xmlEntitiesTablePtr) dtd->pentities);
3282
3283 cur = dtd->children;
3284 while (cur != NULL) {
3285 q = NULL;
3286
3287 if (cur->type == XML_ENTITY_DECL) {
3288 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3289 switch (tmp->etype) {
3290 case XML_INTERNAL_GENERAL_ENTITY:
3291 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3292 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3293 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3294 break;
3295 case XML_INTERNAL_PARAMETER_ENTITY:
3296 case XML_EXTERNAL_PARAMETER_ENTITY:
3297 q = (xmlNodePtr)
3298 xmlGetParameterEntityFromDtd(ret, tmp->name);
3299 break;
3300 case XML_INTERNAL_PREDEFINED_ENTITY:
3301 break;
3302 }
3303 } else if (cur->type == XML_ELEMENT_DECL) {
3304 xmlElementPtr tmp = (xmlElementPtr) cur;
3305 q = (xmlNodePtr)
3306 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3307 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3308 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3309 q = (xmlNodePtr)
3310 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3311 } else if (cur->type == XML_COMMENT_NODE) {
3312 q = xmlCopyNode(cur, 0);
3313 }
3314
3315 if (q == NULL) {
3316 cur = cur->next;
3317 continue;
3318 }
3319
3320 if (p == NULL)
3321 ret->children = q;
3322 else
3323 p->next = q;
3324
3325 q->prev = p;
3326 q->parent = (xmlNodePtr) ret;
3327 q->next = NULL;
3328 ret->last = q;
3329 p = q;
3330 cur = cur->next;
3331 }
3332
Owen Taylor3473f882001-02-23 17:55:21 +00003333 return(ret);
3334}
3335
3336/**
3337 * xmlCopyDoc:
3338 * @doc: the document
3339 * @recursive: if 1 do a recursive copy.
3340 *
3341 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003342 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003343 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003344 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003345 */
3346xmlDocPtr
3347xmlCopyDoc(xmlDocPtr doc, int recursive) {
3348 xmlDocPtr ret;
3349
3350 if (doc == NULL) return(NULL);
3351 ret = xmlNewDoc(doc->version);
3352 if (ret == NULL) return(NULL);
3353 if (doc->name != NULL)
3354 ret->name = xmlMemStrdup(doc->name);
3355 if (doc->encoding != NULL)
3356 ret->encoding = xmlStrdup(doc->encoding);
3357 ret->charset = doc->charset;
3358 ret->compression = doc->compression;
3359 ret->standalone = doc->standalone;
3360 if (!recursive) return(ret);
3361
Daniel Veillardb33c2012001-04-25 12:59:04 +00003362 ret->last = NULL;
3363 ret->children = NULL;
3364 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003365 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003366 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003367 ret->intSubset->parent = ret;
3368 }
Owen Taylor3473f882001-02-23 17:55:21 +00003369 if (doc->oldNs != NULL)
3370 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3371 if (doc->children != NULL) {
3372 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003373
3374 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3375 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003376 ret->last = NULL;
3377 tmp = ret->children;
3378 while (tmp != NULL) {
3379 if (tmp->next == NULL)
3380 ret->last = tmp;
3381 tmp = tmp->next;
3382 }
3383 }
3384 return(ret);
3385}
3386
3387/************************************************************************
3388 * *
3389 * Content access functions *
3390 * *
3391 ************************************************************************/
3392
3393/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003394 * xmlGetLineNo:
3395 * @node : valid node
3396 *
3397 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003398 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003399 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003400 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003401 */
3402long
3403xmlGetLineNo(xmlNodePtr node)
3404{
3405 long result = -1;
3406
3407 if (!node)
3408 return result;
3409 if (node->type == XML_ELEMENT_NODE)
3410 result = (long) node->content;
3411 else if ((node->prev != NULL) &&
3412 ((node->prev->type == XML_ELEMENT_NODE) ||
3413 (node->prev->type == XML_TEXT_NODE)))
3414 result = xmlGetLineNo(node->prev);
3415 else if ((node->parent != NULL) &&
3416 ((node->parent->type == XML_ELEMENT_NODE) ||
3417 (node->parent->type == XML_TEXT_NODE)))
3418 result = xmlGetLineNo(node->parent);
3419
3420 return result;
3421}
3422
3423/**
3424 * xmlGetNodePath:
3425 * @node: a node
3426 *
3427 * Build a structure based Path for the given node
3428 *
3429 * Returns the new path or NULL in case of error. The caller must free
3430 * the returned string
3431 */
3432xmlChar *
3433xmlGetNodePath(xmlNodePtr node)
3434{
3435 xmlNodePtr cur, tmp, next;
3436 xmlChar *buffer = NULL, *temp;
3437 size_t buf_len;
3438 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00003439 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00003440 const char *name;
3441 char nametemp[100];
3442 int occur = 0;
3443
3444 if (node == NULL)
3445 return (NULL);
3446
3447 buf_len = 500;
3448 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3449 if (buffer == NULL)
3450 return (NULL);
3451 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3452 if (buf == NULL) {
3453 xmlFree(buffer);
3454 return (NULL);
3455 }
3456
3457 buffer[0] = 0;
3458 cur = node;
3459 do {
3460 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003461 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003462 occur = 0;
3463 if ((cur->type == XML_DOCUMENT_NODE) ||
3464 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3465 if (buffer[0] == '/')
3466 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003467 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003468 next = NULL;
3469 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003470 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003471 name = (const char *) cur->name;
3472 if (cur->ns) {
3473 snprintf(nametemp, sizeof(nametemp) - 1,
3474 "%s:%s", cur->ns->prefix, cur->name);
3475 nametemp[sizeof(nametemp) - 1] = 0;
3476 name = nametemp;
3477 }
3478 next = cur->parent;
3479
3480 /*
3481 * Thumbler index computation
3482 */
3483 tmp = cur->prev;
3484 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00003485 if ((tmp->type == XML_ELEMENT_NODE) &&
3486 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003487 occur++;
3488 tmp = tmp->prev;
3489 }
3490 if (occur == 0) {
3491 tmp = cur->next;
3492 while (tmp != NULL) {
3493 if (xmlStrEqual(cur->name, tmp->name))
3494 occur++;
3495 tmp = tmp->next;
3496 }
3497 if (occur != 0)
3498 occur = 1;
3499 } else
3500 occur++;
3501 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003502 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003503 name = (const char *) (((xmlAttrPtr) cur)->name);
3504 next = ((xmlAttrPtr) cur)->parent;
3505 } else {
3506 next = cur->parent;
3507 }
3508
3509 /*
3510 * Make sure there is enough room
3511 */
3512 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3513 buf_len =
3514 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3515 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3516 if (temp == NULL) {
3517 xmlFree(buf);
3518 xmlFree(buffer);
3519 return (NULL);
3520 }
3521 buffer = temp;
3522 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3523 if (temp == NULL) {
3524 xmlFree(buf);
3525 xmlFree(buffer);
3526 return (NULL);
3527 }
3528 buf = temp;
3529 }
3530 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003531 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00003532 sep, name, (char *) buffer);
3533 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003534 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00003535 sep, name, occur, (char *) buffer);
3536 snprintf((char *) buffer, buf_len, "%s", buf);
3537 cur = next;
3538 } while (cur != NULL);
3539 xmlFree(buf);
3540 return (buffer);
3541}
3542
3543/**
Owen Taylor3473f882001-02-23 17:55:21 +00003544 * xmlDocGetRootElement:
3545 * @doc: the document
3546 *
3547 * Get the root element of the document (doc->children is a list
3548 * containing possibly comments, PIs, etc ...).
3549 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003550 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003551 */
3552xmlNodePtr
3553xmlDocGetRootElement(xmlDocPtr doc) {
3554 xmlNodePtr ret;
3555
3556 if (doc == NULL) return(NULL);
3557 ret = doc->children;
3558 while (ret != NULL) {
3559 if (ret->type == XML_ELEMENT_NODE)
3560 return(ret);
3561 ret = ret->next;
3562 }
3563 return(ret);
3564}
3565
3566/**
3567 * xmlDocSetRootElement:
3568 * @doc: the document
3569 * @root: the new document root element
3570 *
3571 * Set the root element of the document (doc->children is a list
3572 * containing possibly comments, PIs, etc ...).
3573 *
3574 * Returns the old root element if any was found
3575 */
3576xmlNodePtr
3577xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3578 xmlNodePtr old = NULL;
3579
3580 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00003581 if (root == NULL)
3582 return(NULL);
3583 xmlUnlinkNode(root);
3584 root->doc = doc;
3585 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00003586 old = doc->children;
3587 while (old != NULL) {
3588 if (old->type == XML_ELEMENT_NODE)
3589 break;
3590 old = old->next;
3591 }
3592 if (old == NULL) {
3593 if (doc->children == NULL) {
3594 doc->children = root;
3595 doc->last = root;
3596 } else {
3597 xmlAddSibling(doc->children, root);
3598 }
3599 } else {
3600 xmlReplaceNode(old, root);
3601 }
3602 return(old);
3603}
3604
3605/**
3606 * xmlNodeSetLang:
3607 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003608 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003609 *
3610 * Set the language of a node, i.e. the values of the xml:lang
3611 * attribute.
3612 */
3613void
3614xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003615 xmlNsPtr ns;
3616
Owen Taylor3473f882001-02-23 17:55:21 +00003617 if (cur == NULL) return;
3618 switch(cur->type) {
3619 case XML_TEXT_NODE:
3620 case XML_CDATA_SECTION_NODE:
3621 case XML_COMMENT_NODE:
3622 case XML_DOCUMENT_NODE:
3623 case XML_DOCUMENT_TYPE_NODE:
3624 case XML_DOCUMENT_FRAG_NODE:
3625 case XML_NOTATION_NODE:
3626 case XML_HTML_DOCUMENT_NODE:
3627 case XML_DTD_NODE:
3628 case XML_ELEMENT_DECL:
3629 case XML_ATTRIBUTE_DECL:
3630 case XML_ENTITY_DECL:
3631 case XML_PI_NODE:
3632 case XML_ENTITY_REF_NODE:
3633 case XML_ENTITY_NODE:
3634 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003635#ifdef LIBXML_DOCB_ENABLED
3636 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003637#endif
3638 case XML_XINCLUDE_START:
3639 case XML_XINCLUDE_END:
3640 return;
3641 case XML_ELEMENT_NODE:
3642 case XML_ATTRIBUTE_NODE:
3643 break;
3644 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003645 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3646 if (ns == NULL)
3647 return;
3648 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003649}
3650
3651/**
3652 * xmlNodeGetLang:
3653 * @cur: the node being checked
3654 *
3655 * Searches the language of a node, i.e. the values of the xml:lang
3656 * attribute or the one carried by the nearest ancestor.
3657 *
3658 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003659 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003660 */
3661xmlChar *
3662xmlNodeGetLang(xmlNodePtr cur) {
3663 xmlChar *lang;
3664
3665 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003666 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003667 if (lang != NULL)
3668 return(lang);
3669 cur = cur->parent;
3670 }
3671 return(NULL);
3672}
3673
3674
3675/**
3676 * xmlNodeSetSpacePreserve:
3677 * @cur: the node being changed
3678 * @val: the xml:space value ("0": default, 1: "preserve")
3679 *
3680 * Set (or reset) the space preserving behaviour of a node, i.e. the
3681 * value of the xml:space attribute.
3682 */
3683void
3684xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003685 xmlNsPtr ns;
3686
Owen Taylor3473f882001-02-23 17:55:21 +00003687 if (cur == NULL) return;
3688 switch(cur->type) {
3689 case XML_TEXT_NODE:
3690 case XML_CDATA_SECTION_NODE:
3691 case XML_COMMENT_NODE:
3692 case XML_DOCUMENT_NODE:
3693 case XML_DOCUMENT_TYPE_NODE:
3694 case XML_DOCUMENT_FRAG_NODE:
3695 case XML_NOTATION_NODE:
3696 case XML_HTML_DOCUMENT_NODE:
3697 case XML_DTD_NODE:
3698 case XML_ELEMENT_DECL:
3699 case XML_ATTRIBUTE_DECL:
3700 case XML_ENTITY_DECL:
3701 case XML_PI_NODE:
3702 case XML_ENTITY_REF_NODE:
3703 case XML_ENTITY_NODE:
3704 case XML_NAMESPACE_DECL:
3705 case XML_XINCLUDE_START:
3706 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003707#ifdef LIBXML_DOCB_ENABLED
3708 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003709#endif
3710 return;
3711 case XML_ELEMENT_NODE:
3712 case XML_ATTRIBUTE_NODE:
3713 break;
3714 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003715 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3716 if (ns == NULL)
3717 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003718 switch (val) {
3719 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003720 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003721 break;
3722 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003723 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003724 break;
3725 }
3726}
3727
3728/**
3729 * xmlNodeGetSpacePreserve:
3730 * @cur: the node being checked
3731 *
3732 * Searches the space preserving behaviour of a node, i.e. the values
3733 * of the xml:space attribute or the one carried by the nearest
3734 * ancestor.
3735 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003736 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003737 */
3738int
3739xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3740 xmlChar *space;
3741
3742 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003743 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003744 if (space != NULL) {
3745 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3746 xmlFree(space);
3747 return(1);
3748 }
3749 if (xmlStrEqual(space, BAD_CAST "default")) {
3750 xmlFree(space);
3751 return(0);
3752 }
3753 xmlFree(space);
3754 }
3755 cur = cur->parent;
3756 }
3757 return(-1);
3758}
3759
3760/**
3761 * xmlNodeSetName:
3762 * @cur: the node being changed
3763 * @name: the new tag name
3764 *
3765 * Set (or reset) the name of a node.
3766 */
3767void
3768xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3769 if (cur == NULL) return;
3770 if (name == NULL) return;
3771 switch(cur->type) {
3772 case XML_TEXT_NODE:
3773 case XML_CDATA_SECTION_NODE:
3774 case XML_COMMENT_NODE:
3775 case XML_DOCUMENT_TYPE_NODE:
3776 case XML_DOCUMENT_FRAG_NODE:
3777 case XML_NOTATION_NODE:
3778 case XML_HTML_DOCUMENT_NODE:
3779 case XML_NAMESPACE_DECL:
3780 case XML_XINCLUDE_START:
3781 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003782#ifdef LIBXML_DOCB_ENABLED
3783 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003784#endif
3785 return;
3786 case XML_ELEMENT_NODE:
3787 case XML_ATTRIBUTE_NODE:
3788 case XML_PI_NODE:
3789 case XML_ENTITY_REF_NODE:
3790 case XML_ENTITY_NODE:
3791 case XML_DTD_NODE:
3792 case XML_DOCUMENT_NODE:
3793 case XML_ELEMENT_DECL:
3794 case XML_ATTRIBUTE_DECL:
3795 case XML_ENTITY_DECL:
3796 break;
3797 }
3798 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3799 cur->name = xmlStrdup(name);
3800}
3801
3802/**
3803 * xmlNodeSetBase:
3804 * @cur: the node being changed
3805 * @uri: the new base URI
3806 *
3807 * Set (or reset) the base URI of a node, i.e. the value of the
3808 * xml:base attribute.
3809 */
3810void
3811xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003812 xmlNsPtr ns;
3813
Owen Taylor3473f882001-02-23 17:55:21 +00003814 if (cur == NULL) return;
3815 switch(cur->type) {
3816 case XML_TEXT_NODE:
3817 case XML_CDATA_SECTION_NODE:
3818 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003819 case XML_DOCUMENT_TYPE_NODE:
3820 case XML_DOCUMENT_FRAG_NODE:
3821 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003822 case XML_DTD_NODE:
3823 case XML_ELEMENT_DECL:
3824 case XML_ATTRIBUTE_DECL:
3825 case XML_ENTITY_DECL:
3826 case XML_PI_NODE:
3827 case XML_ENTITY_REF_NODE:
3828 case XML_ENTITY_NODE:
3829 case XML_NAMESPACE_DECL:
3830 case XML_XINCLUDE_START:
3831 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00003832 return;
3833 case XML_ELEMENT_NODE:
3834 case XML_ATTRIBUTE_NODE:
3835 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00003836 case XML_DOCUMENT_NODE:
3837#ifdef LIBXML_DOCB_ENABLED
3838 case XML_DOCB_DOCUMENT_NODE:
3839#endif
3840 case XML_HTML_DOCUMENT_NODE: {
3841 xmlDocPtr doc = (xmlDocPtr) cur;
3842
3843 if (doc->URL != NULL)
3844 xmlFree((xmlChar *) doc->URL);
3845 if (uri == NULL)
3846 doc->URL = NULL;
3847 else
3848 doc->URL = xmlStrdup(uri);
3849 return;
3850 }
Owen Taylor3473f882001-02-23 17:55:21 +00003851 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003852
3853 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3854 if (ns == NULL)
3855 return;
3856 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00003857}
3858
3859/**
Owen Taylor3473f882001-02-23 17:55:21 +00003860 * xmlNodeGetBase:
3861 * @doc: the document the node pertains to
3862 * @cur: the node being checked
3863 *
3864 * Searches for the BASE URL. The code should work on both XML
3865 * and HTML document even if base mechanisms are completely different.
3866 * It returns the base as defined in RFC 2396 sections
3867 * 5.1.1. Base URI within Document Content
3868 * and
3869 * 5.1.2. Base URI from the Encapsulating Entity
3870 * However it does not return the document base (5.1.3), use
3871 * xmlDocumentGetBase() for this
3872 *
3873 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003874 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003875 */
3876xmlChar *
3877xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003878 xmlChar *oldbase = NULL;
3879 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003880
3881 if ((cur == NULL) && (doc == NULL))
3882 return(NULL);
3883 if (doc == NULL) doc = cur->doc;
3884 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3885 cur = doc->children;
3886 while ((cur != NULL) && (cur->name != NULL)) {
3887 if (cur->type != XML_ELEMENT_NODE) {
3888 cur = cur->next;
3889 continue;
3890 }
3891 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3892 cur = cur->children;
3893 continue;
3894 }
3895 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3896 cur = cur->children;
3897 continue;
3898 }
3899 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3900 return(xmlGetProp(cur, BAD_CAST "href"));
3901 }
3902 cur = cur->next;
3903 }
3904 return(NULL);
3905 }
3906 while (cur != NULL) {
3907 if (cur->type == XML_ENTITY_DECL) {
3908 xmlEntityPtr ent = (xmlEntityPtr) cur;
3909 return(xmlStrdup(ent->URI));
3910 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003911 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003912 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003913 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003914 if (oldbase != NULL) {
3915 newbase = xmlBuildURI(oldbase, base);
3916 if (newbase != NULL) {
3917 xmlFree(oldbase);
3918 xmlFree(base);
3919 oldbase = newbase;
3920 } else {
3921 xmlFree(oldbase);
3922 xmlFree(base);
3923 return(NULL);
3924 }
3925 } else {
3926 oldbase = base;
3927 }
3928 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3929 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3930 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3931 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003932 }
3933 }
Owen Taylor3473f882001-02-23 17:55:21 +00003934 cur = cur->parent;
3935 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003936 if ((doc != NULL) && (doc->URL != NULL)) {
3937 if (oldbase == NULL)
3938 return(xmlStrdup(doc->URL));
3939 newbase = xmlBuildURI(oldbase, doc->URL);
3940 xmlFree(oldbase);
3941 return(newbase);
3942 }
3943 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003944}
3945
3946/**
3947 * xmlNodeGetContent:
3948 * @cur: the node being read
3949 *
3950 * Read the value of a node, this can be either the text carried
3951 * directly by this node if it's a TEXT node or the aggregate string
3952 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00003953 * Entity references are substituted.
3954 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003955 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003956 */
3957xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00003958xmlNodeGetContent(xmlNodePtr cur)
3959{
3960 if (cur == NULL)
3961 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003962 switch (cur->type) {
3963 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00003964 case XML_ELEMENT_NODE:{
3965 xmlNodePtr tmp = cur;
3966 xmlBufferPtr buffer;
3967 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00003968
Daniel Veillard7646b182002-04-20 06:41:40 +00003969 buffer = xmlBufferCreate();
3970 if (buffer == NULL)
3971 return (NULL);
3972 while (tmp != NULL) {
3973 switch (tmp->type) {
3974 case XML_CDATA_SECTION_NODE:
3975 case XML_TEXT_NODE:
3976 if (tmp->content != NULL)
3977 xmlBufferCat(buffer, tmp->content);
3978 break;
3979 case XML_ENTITY_REF_NODE:{
3980 /* recursive substitution of entity references */
3981 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00003982
Daniel Veillard7646b182002-04-20 06:41:40 +00003983 if (cont) {
3984 xmlBufferCat(buffer,
3985 (const xmlChar *) cont);
3986 xmlFree(cont);
3987 }
3988 break;
3989 }
3990 default:
3991 break;
3992 }
3993 /*
3994 * Skip to next node
3995 */
3996 if (tmp->children != NULL) {
3997 if (tmp->children->type != XML_ENTITY_DECL) {
3998 tmp = tmp->children;
3999 continue;
4000 }
4001 }
4002 if (tmp == cur)
4003 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004004
Daniel Veillard7646b182002-04-20 06:41:40 +00004005 if (tmp->next != NULL) {
4006 tmp = tmp->next;
4007 continue;
4008 }
4009
4010 do {
4011 tmp = tmp->parent;
4012 if (tmp == NULL)
4013 break;
4014 if (tmp == cur) {
4015 tmp = NULL;
4016 break;
4017 }
4018 if (tmp->next != NULL) {
4019 tmp = tmp->next;
4020 break;
4021 }
4022 } while (tmp != NULL);
4023 }
4024 ret = buffer->content;
4025 buffer->content = NULL;
4026 xmlBufferFree(buffer);
4027 return (ret);
4028 }
4029 case XML_ATTRIBUTE_NODE:{
4030 xmlAttrPtr attr = (xmlAttrPtr) cur;
4031
4032 if (attr->parent != NULL)
4033 return (xmlNodeListGetString
4034 (attr->parent->doc, attr->children, 1));
4035 else
4036 return (xmlNodeListGetString(NULL, attr->children, 1));
4037 break;
4038 }
Owen Taylor3473f882001-02-23 17:55:21 +00004039 case XML_COMMENT_NODE:
4040 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004041 if (cur->content != NULL)
4042 return (xmlStrdup(cur->content));
4043 return (NULL);
4044 case XML_ENTITY_REF_NODE:{
4045 xmlEntityPtr ent;
4046 xmlNodePtr tmp;
4047 xmlBufferPtr buffer;
4048 xmlChar *ret;
4049
4050 /* lookup entity declaration */
4051 ent = xmlGetDocEntity(cur->doc, cur->name);
4052 if (ent == NULL)
4053 return (NULL);
4054
4055 buffer = xmlBufferCreate();
4056 if (buffer == NULL)
4057 return (NULL);
4058
4059 /* an entity content can be any "well balanced chunk",
4060 * i.e. the result of the content [43] production:
4061 * http://www.w3.org/TR/REC-xml#NT-content
4062 * -> we iterate through child nodes and recursive call
4063 * xmlNodeGetContent() which handles all possible node types */
4064 tmp = ent->children;
4065 while (tmp) {
4066 xmlChar *cont = xmlNodeGetContent(tmp);
4067
4068 if (cont) {
4069 xmlBufferCat(buffer, (const xmlChar *) cont);
4070 xmlFree(cont);
4071 }
4072 tmp = tmp->next;
4073 }
4074
4075 ret = buffer->content;
4076 buffer->content = NULL;
4077 xmlBufferFree(buffer);
4078 return (ret);
4079 }
Owen Taylor3473f882001-02-23 17:55:21 +00004080 case XML_ENTITY_NODE:
4081 case XML_DOCUMENT_NODE:
4082 case XML_HTML_DOCUMENT_NODE:
4083 case XML_DOCUMENT_TYPE_NODE:
4084 case XML_NOTATION_NODE:
4085 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004086 case XML_XINCLUDE_START:
4087 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004088#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004089 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004090#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00004091 return (NULL);
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004092 case XML_NAMESPACE_DECL: {
4093 xmlChar *tmp;
4094
4095 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4096 return (tmp);
4097 }
Owen Taylor3473f882001-02-23 17:55:21 +00004098 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004099 /* TODO !!! */
4100 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004101 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004102 /* TODO !!! */
4103 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004104 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004105 /* TODO !!! */
4106 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004107 case XML_CDATA_SECTION_NODE:
4108 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004109 if (cur->content != NULL)
4110 return (xmlStrdup(cur->content));
4111 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004112 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004113 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004114}
Owen Taylor3473f882001-02-23 17:55:21 +00004115/**
4116 * xmlNodeSetContent:
4117 * @cur: the node being modified
4118 * @content: the new value of the content
4119 *
4120 * Replace the content of a node.
4121 */
4122void
4123xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4124 if (cur == NULL) {
4125#ifdef DEBUG_TREE
4126 xmlGenericError(xmlGenericErrorContext,
4127 "xmlNodeSetContent : node == NULL\n");
4128#endif
4129 return;
4130 }
4131 switch (cur->type) {
4132 case XML_DOCUMENT_FRAG_NODE:
4133 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004134 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004135 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4136 cur->children = xmlStringGetNodeList(cur->doc, content);
4137 UPDATE_LAST_CHILD_AND_PARENT(cur)
4138 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004139 case XML_TEXT_NODE:
4140 case XML_CDATA_SECTION_NODE:
4141 case XML_ENTITY_REF_NODE:
4142 case XML_ENTITY_NODE:
4143 case XML_PI_NODE:
4144 case XML_COMMENT_NODE:
4145 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004146 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004147 }
4148 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4149 cur->last = cur->children = NULL;
4150 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004151 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004152 } else
4153 cur->content = NULL;
4154 break;
4155 case XML_DOCUMENT_NODE:
4156 case XML_HTML_DOCUMENT_NODE:
4157 case XML_DOCUMENT_TYPE_NODE:
4158 case XML_XINCLUDE_START:
4159 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004160#ifdef LIBXML_DOCB_ENABLED
4161 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004162#endif
4163 break;
4164 case XML_NOTATION_NODE:
4165 break;
4166 case XML_DTD_NODE:
4167 break;
4168 case XML_NAMESPACE_DECL:
4169 break;
4170 case XML_ELEMENT_DECL:
4171 /* TODO !!! */
4172 break;
4173 case XML_ATTRIBUTE_DECL:
4174 /* TODO !!! */
4175 break;
4176 case XML_ENTITY_DECL:
4177 /* TODO !!! */
4178 break;
4179 }
4180}
4181
4182/**
4183 * xmlNodeSetContentLen:
4184 * @cur: the node being modified
4185 * @content: the new value of the content
4186 * @len: the size of @content
4187 *
4188 * Replace the content of a node.
4189 */
4190void
4191xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4192 if (cur == NULL) {
4193#ifdef DEBUG_TREE
4194 xmlGenericError(xmlGenericErrorContext,
4195 "xmlNodeSetContentLen : node == NULL\n");
4196#endif
4197 return;
4198 }
4199 switch (cur->type) {
4200 case XML_DOCUMENT_FRAG_NODE:
4201 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004202 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004203 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4204 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4205 UPDATE_LAST_CHILD_AND_PARENT(cur)
4206 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004207 case XML_TEXT_NODE:
4208 case XML_CDATA_SECTION_NODE:
4209 case XML_ENTITY_REF_NODE:
4210 case XML_ENTITY_NODE:
4211 case XML_PI_NODE:
4212 case XML_COMMENT_NODE:
4213 case XML_NOTATION_NODE:
4214 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004215 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004216 }
4217 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4218 cur->children = cur->last = NULL;
4219 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004220 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004221 } else
4222 cur->content = NULL;
4223 break;
4224 case XML_DOCUMENT_NODE:
4225 case XML_DTD_NODE:
4226 case XML_HTML_DOCUMENT_NODE:
4227 case XML_DOCUMENT_TYPE_NODE:
4228 case XML_NAMESPACE_DECL:
4229 case XML_XINCLUDE_START:
4230 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004231#ifdef LIBXML_DOCB_ENABLED
4232 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004233#endif
4234 break;
4235 case XML_ELEMENT_DECL:
4236 /* TODO !!! */
4237 break;
4238 case XML_ATTRIBUTE_DECL:
4239 /* TODO !!! */
4240 break;
4241 case XML_ENTITY_DECL:
4242 /* TODO !!! */
4243 break;
4244 }
4245}
4246
4247/**
4248 * xmlNodeAddContentLen:
4249 * @cur: the node being modified
4250 * @content: extra content
4251 * @len: the size of @content
4252 *
4253 * Append the extra substring to the node content.
4254 */
4255void
4256xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4257 if (cur == NULL) {
4258#ifdef DEBUG_TREE
4259 xmlGenericError(xmlGenericErrorContext,
4260 "xmlNodeAddContentLen : node == NULL\n");
4261#endif
4262 return;
4263 }
4264 if (len <= 0) return;
4265 switch (cur->type) {
4266 case XML_DOCUMENT_FRAG_NODE:
4267 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004268 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004269
Daniel Veillard7db37732001-07-12 01:20:08 +00004270 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004271 newNode = xmlNewTextLen(content, len);
4272 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004273 tmp = xmlAddChild(cur, newNode);
4274 if (tmp != newNode)
4275 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004276 if ((last != NULL) && (last->next == newNode)) {
4277 xmlTextMerge(last, newNode);
4278 }
4279 }
4280 break;
4281 }
4282 case XML_ATTRIBUTE_NODE:
4283 break;
4284 case XML_TEXT_NODE:
4285 case XML_CDATA_SECTION_NODE:
4286 case XML_ENTITY_REF_NODE:
4287 case XML_ENTITY_NODE:
4288 case XML_PI_NODE:
4289 case XML_COMMENT_NODE:
4290 case XML_NOTATION_NODE:
4291 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004292 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004293 }
4294 case XML_DOCUMENT_NODE:
4295 case XML_DTD_NODE:
4296 case XML_HTML_DOCUMENT_NODE:
4297 case XML_DOCUMENT_TYPE_NODE:
4298 case XML_NAMESPACE_DECL:
4299 case XML_XINCLUDE_START:
4300 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004301#ifdef LIBXML_DOCB_ENABLED
4302 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004303#endif
4304 break;
4305 case XML_ELEMENT_DECL:
4306 case XML_ATTRIBUTE_DECL:
4307 case XML_ENTITY_DECL:
4308 break;
4309 }
4310}
4311
4312/**
4313 * xmlNodeAddContent:
4314 * @cur: the node being modified
4315 * @content: extra content
4316 *
4317 * Append the extra substring to the node content.
4318 */
4319void
4320xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4321 int len;
4322
4323 if (cur == NULL) {
4324#ifdef DEBUG_TREE
4325 xmlGenericError(xmlGenericErrorContext,
4326 "xmlNodeAddContent : node == NULL\n");
4327#endif
4328 return;
4329 }
4330 if (content == NULL) return;
4331 len = xmlStrlen(content);
4332 xmlNodeAddContentLen(cur, content, len);
4333}
4334
4335/**
4336 * xmlTextMerge:
4337 * @first: the first text node
4338 * @second: the second text node being merged
4339 *
4340 * Merge two text nodes into one
4341 * Returns the first text node augmented
4342 */
4343xmlNodePtr
4344xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4345 if (first == NULL) return(second);
4346 if (second == NULL) return(first);
4347 if (first->type != XML_TEXT_NODE) return(first);
4348 if (second->type != XML_TEXT_NODE) return(first);
4349 if (second->name != first->name)
4350 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004351 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004352 xmlUnlinkNode(second);
4353 xmlFreeNode(second);
4354 return(first);
4355}
4356
4357/**
4358 * xmlGetNsList:
4359 * @doc: the document
4360 * @node: the current node
4361 *
4362 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004363 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004364 * that need to be freed by the caller or NULL if no
4365 * namespace if defined
4366 */
4367xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004368xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4369{
Owen Taylor3473f882001-02-23 17:55:21 +00004370 xmlNsPtr cur;
4371 xmlNsPtr *ret = NULL;
4372 int nbns = 0;
4373 int maxns = 10;
4374 int i;
4375
4376 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004377 if (node->type == XML_ELEMENT_NODE) {
4378 cur = node->nsDef;
4379 while (cur != NULL) {
4380 if (ret == NULL) {
4381 ret =
4382 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4383 sizeof(xmlNsPtr));
4384 if (ret == NULL) {
4385 xmlGenericError(xmlGenericErrorContext,
4386 "xmlGetNsList : out of memory!\n");
4387 return (NULL);
4388 }
4389 ret[nbns] = NULL;
4390 }
4391 for (i = 0; i < nbns; i++) {
4392 if ((cur->prefix == ret[i]->prefix) ||
4393 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4394 break;
4395 }
4396 if (i >= nbns) {
4397 if (nbns >= maxns) {
4398 maxns *= 2;
4399 ret = (xmlNsPtr *) xmlRealloc(ret,
4400 (maxns +
4401 1) *
4402 sizeof(xmlNsPtr));
4403 if (ret == NULL) {
4404 xmlGenericError(xmlGenericErrorContext,
4405 "xmlGetNsList : realloc failed!\n");
4406 return (NULL);
4407 }
4408 }
4409 ret[nbns++] = cur;
4410 ret[nbns] = NULL;
4411 }
Owen Taylor3473f882001-02-23 17:55:21 +00004412
Daniel Veillard77044732001-06-29 21:31:07 +00004413 cur = cur->next;
4414 }
4415 }
4416 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004417 }
Daniel Veillard77044732001-06-29 21:31:07 +00004418 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004419}
4420
4421/**
4422 * xmlSearchNs:
4423 * @doc: the document
4424 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004425 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004426 *
4427 * Search a Ns registered under a given name space for a document.
4428 * recurse on the parents until it finds the defined namespace
4429 * or return NULL otherwise.
4430 * @nameSpace can be NULL, this is a search for the default namespace.
4431 * We don't allow to cross entities boundaries. If you don't declare
4432 * the namespace within those you will be in troubles !!! A warning
4433 * is generated to cover this case.
4434 *
4435 * Returns the namespace pointer or NULL.
4436 */
4437xmlNsPtr
4438xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4439 xmlNsPtr cur;
4440
4441 if (node == NULL) return(NULL);
4442 if ((nameSpace != NULL) &&
4443 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00004444 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4445 /*
4446 * The XML-1.0 namespace is normally held on the root
4447 * element. In this case exceptionally create it on the
4448 * node element.
4449 */
4450 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4451 if (cur == NULL) {
4452 xmlGenericError(xmlGenericErrorContext,
4453 "xmlSearchNs : malloc failed\n");
4454 return(NULL);
4455 }
4456 memset(cur, 0, sizeof(xmlNs));
4457 cur->type = XML_LOCAL_NAMESPACE;
4458 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4459 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4460 cur->next = node->nsDef;
4461 node->nsDef = cur;
4462 return(cur);
4463 }
Owen Taylor3473f882001-02-23 17:55:21 +00004464 if (doc->oldNs == NULL) {
4465 /*
4466 * Allocate a new Namespace and fill the fields.
4467 */
4468 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4469 if (doc->oldNs == NULL) {
4470 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004471 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004472 return(NULL);
4473 }
4474 memset(doc->oldNs, 0, sizeof(xmlNs));
4475 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4476
4477 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4478 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4479 }
4480 return(doc->oldNs);
4481 }
4482 while (node != NULL) {
4483 if ((node->type == XML_ENTITY_REF_NODE) ||
4484 (node->type == XML_ENTITY_NODE) ||
4485 (node->type == XML_ENTITY_DECL))
4486 return(NULL);
4487 if (node->type == XML_ELEMENT_NODE) {
4488 cur = node->nsDef;
4489 while (cur != NULL) {
4490 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4491 (cur->href != NULL))
4492 return(cur);
4493 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4494 (cur->href != NULL) &&
4495 (xmlStrEqual(cur->prefix, nameSpace)))
4496 return(cur);
4497 cur = cur->next;
4498 }
4499 }
4500 node = node->parent;
4501 }
4502 return(NULL);
4503}
4504
4505/**
4506 * xmlSearchNsByHref:
4507 * @doc: the document
4508 * @node: the current node
4509 * @href: the namespace value
4510 *
4511 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4512 * the defined namespace or return NULL otherwise.
4513 * Returns the namespace pointer or NULL.
4514 */
4515xmlNsPtr
4516xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4517 xmlNsPtr cur;
4518 xmlNodePtr orig = node;
4519
4520 if ((node == NULL) || (href == NULL)) return(NULL);
4521 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004522 /*
4523 * Only the document can hold the XML spec namespace.
4524 */
Daniel Veillardc1a0da32002-08-14 08:32:18 +00004525 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4526 /*
4527 * The XML-1.0 namespace is normally held on the root
4528 * element. In this case exceptionally create it on the
4529 * node element.
4530 */
4531 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4532 if (cur == NULL) {
4533 xmlGenericError(xmlGenericErrorContext,
4534 "xmlSearchNs : malloc failed\n");
4535 return(NULL);
4536 }
4537 memset(cur, 0, sizeof(xmlNs));
4538 cur->type = XML_LOCAL_NAMESPACE;
4539 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4540 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4541 cur->next = node->nsDef;
4542 node->nsDef = cur;
4543 return(cur);
4544 }
Owen Taylor3473f882001-02-23 17:55:21 +00004545 if (doc->oldNs == NULL) {
4546 /*
4547 * Allocate a new Namespace and fill the fields.
4548 */
4549 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4550 if (doc->oldNs == NULL) {
4551 xmlGenericError(xmlGenericErrorContext,
4552 "xmlSearchNsByHref : malloc failed\n");
4553 return(NULL);
4554 }
4555 memset(doc->oldNs, 0, sizeof(xmlNs));
4556 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4557
4558 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4559 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4560 }
4561 return(doc->oldNs);
4562 }
4563 while (node != NULL) {
4564 cur = node->nsDef;
4565 while (cur != NULL) {
4566 if ((cur->href != NULL) && (href != NULL) &&
4567 (xmlStrEqual(cur->href, href))) {
4568 /*
4569 * Check that the prefix is not shadowed between orig and node
4570 */
4571 xmlNodePtr check = orig;
4572 xmlNsPtr tst;
4573
4574 while (check != node) {
4575 tst = check->nsDef;
4576 while (tst != NULL) {
4577 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4578 goto shadowed;
4579 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4580 (xmlStrEqual(tst->prefix, cur->prefix)))
4581 goto shadowed;
4582 tst = tst->next;
4583 }
4584 check = check->parent;
4585 }
4586 return(cur);
4587 }
4588shadowed:
4589 cur = cur->next;
4590 }
4591 node = node->parent;
4592 }
4593 return(NULL);
4594}
4595
4596/**
4597 * xmlNewReconciliedNs
4598 * @doc: the document
4599 * @tree: a node expected to hold the new namespace
4600 * @ns: the original namespace
4601 *
4602 * This function tries to locate a namespace definition in a tree
4603 * ancestors, or create a new namespace definition node similar to
4604 * @ns trying to reuse the same prefix. However if the given prefix is
4605 * null (default namespace) or reused within the subtree defined by
4606 * @tree or on one of its ancestors then a new prefix is generated.
4607 * Returns the (new) namespace definition or NULL in case of error
4608 */
4609xmlNsPtr
4610xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4611 xmlNsPtr def;
4612 xmlChar prefix[50];
4613 int counter = 1;
4614
4615 if (tree == NULL) {
4616#ifdef DEBUG_TREE
4617 xmlGenericError(xmlGenericErrorContext,
4618 "xmlNewReconciliedNs : tree == NULL\n");
4619#endif
4620 return(NULL);
4621 }
4622 if (ns == NULL) {
4623#ifdef DEBUG_TREE
4624 xmlGenericError(xmlGenericErrorContext,
4625 "xmlNewReconciliedNs : ns == NULL\n");
4626#endif
4627 return(NULL);
4628 }
4629 /*
4630 * Search an existing namespace definition inherited.
4631 */
4632 def = xmlSearchNsByHref(doc, tree, ns->href);
4633 if (def != NULL)
4634 return(def);
4635
4636 /*
4637 * Find a close prefix which is not already in use.
4638 * Let's strip namespace prefixes longer than 20 chars !
4639 */
Daniel Veillardf742d342002-03-07 00:05:35 +00004640 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004641 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00004642 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004643 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00004644
Owen Taylor3473f882001-02-23 17:55:21 +00004645 def = xmlSearchNs(doc, tree, prefix);
4646 while (def != NULL) {
4647 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00004648 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004649 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00004650 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004651 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00004652 def = xmlSearchNs(doc, tree, prefix);
4653 }
4654
4655 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004656 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004657 */
4658 def = xmlNewNs(tree, ns->href, prefix);
4659 return(def);
4660}
4661
4662/**
4663 * xmlReconciliateNs
4664 * @doc: the document
4665 * @tree: a node defining the subtree to reconciliate
4666 *
4667 * This function checks that all the namespaces declared within the given
4668 * tree are properly declared. This is needed for example after Copy or Cut
4669 * and then paste operations. The subtree may still hold pointers to
4670 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004671 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004672 * the new environment. If not possible the new namespaces are redeclared
4673 * on @tree at the top of the given subtree.
4674 * Returns the number of namespace declarations created or -1 in case of error.
4675 */
4676int
4677xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4678 xmlNsPtr *oldNs = NULL;
4679 xmlNsPtr *newNs = NULL;
4680 int sizeCache = 0;
4681 int nbCache = 0;
4682
4683 xmlNsPtr n;
4684 xmlNodePtr node = tree;
4685 xmlAttrPtr attr;
4686 int ret = 0, i;
4687
4688 while (node != NULL) {
4689 /*
4690 * Reconciliate the node namespace
4691 */
4692 if (node->ns != NULL) {
4693 /*
4694 * initialize the cache if needed
4695 */
4696 if (sizeCache == 0) {
4697 sizeCache = 10;
4698 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4699 sizeof(xmlNsPtr));
4700 if (oldNs == NULL) {
4701 xmlGenericError(xmlGenericErrorContext,
4702 "xmlReconciliateNs : memory pbm\n");
4703 return(-1);
4704 }
4705 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4706 sizeof(xmlNsPtr));
4707 if (newNs == NULL) {
4708 xmlGenericError(xmlGenericErrorContext,
4709 "xmlReconciliateNs : memory pbm\n");
4710 xmlFree(oldNs);
4711 return(-1);
4712 }
4713 }
4714 for (i = 0;i < nbCache;i++) {
4715 if (oldNs[i] == node->ns) {
4716 node->ns = newNs[i];
4717 break;
4718 }
4719 }
4720 if (i == nbCache) {
4721 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004722 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004723 */
4724 n = xmlNewReconciliedNs(doc, tree, node->ns);
4725 if (n != NULL) { /* :-( what if else ??? */
4726 /*
4727 * check if we need to grow the cache buffers.
4728 */
4729 if (sizeCache <= nbCache) {
4730 sizeCache *= 2;
4731 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4732 sizeof(xmlNsPtr));
4733 if (oldNs == NULL) {
4734 xmlGenericError(xmlGenericErrorContext,
4735 "xmlReconciliateNs : memory pbm\n");
4736 xmlFree(newNs);
4737 return(-1);
4738 }
4739 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4740 sizeof(xmlNsPtr));
4741 if (newNs == NULL) {
4742 xmlGenericError(xmlGenericErrorContext,
4743 "xmlReconciliateNs : memory pbm\n");
4744 xmlFree(oldNs);
4745 return(-1);
4746 }
4747 }
4748 newNs[nbCache] = n;
4749 oldNs[nbCache++] = node->ns;
4750 node->ns = n;
4751 }
4752 }
4753 }
4754 /*
4755 * now check for namespace hold by attributes on the node.
4756 */
4757 attr = node->properties;
4758 while (attr != NULL) {
4759 if (attr->ns != NULL) {
4760 /*
4761 * initialize the cache if needed
4762 */
4763 if (sizeCache == 0) {
4764 sizeCache = 10;
4765 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4766 sizeof(xmlNsPtr));
4767 if (oldNs == NULL) {
4768 xmlGenericError(xmlGenericErrorContext,
4769 "xmlReconciliateNs : memory pbm\n");
4770 return(-1);
4771 }
4772 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4773 sizeof(xmlNsPtr));
4774 if (newNs == NULL) {
4775 xmlGenericError(xmlGenericErrorContext,
4776 "xmlReconciliateNs : memory pbm\n");
4777 xmlFree(oldNs);
4778 return(-1);
4779 }
4780 }
4781 for (i = 0;i < nbCache;i++) {
4782 if (oldNs[i] == attr->ns) {
4783 node->ns = newNs[i];
4784 break;
4785 }
4786 }
4787 if (i == nbCache) {
4788 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004789 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004790 */
4791 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4792 if (n != NULL) { /* :-( what if else ??? */
4793 /*
4794 * check if we need to grow the cache buffers.
4795 */
4796 if (sizeCache <= nbCache) {
4797 sizeCache *= 2;
4798 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4799 sizeof(xmlNsPtr));
4800 if (oldNs == NULL) {
4801 xmlGenericError(xmlGenericErrorContext,
4802 "xmlReconciliateNs : memory pbm\n");
4803 xmlFree(newNs);
4804 return(-1);
4805 }
4806 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4807 sizeof(xmlNsPtr));
4808 if (newNs == NULL) {
4809 xmlGenericError(xmlGenericErrorContext,
4810 "xmlReconciliateNs : memory pbm\n");
4811 xmlFree(oldNs);
4812 return(-1);
4813 }
4814 }
4815 newNs[nbCache] = n;
4816 oldNs[nbCache++] = attr->ns;
4817 attr->ns = n;
4818 }
4819 }
4820 }
4821 attr = attr->next;
4822 }
4823
4824 /*
4825 * Browse the full subtree, deep first
4826 */
4827 if (node->children != NULL) {
4828 /* deep first */
4829 node = node->children;
4830 } else if ((node != tree) && (node->next != NULL)) {
4831 /* then siblings */
4832 node = node->next;
4833 } else if (node != tree) {
4834 /* go up to parents->next if needed */
4835 while (node != tree) {
4836 if (node->parent != NULL)
4837 node = node->parent;
4838 if ((node != tree) && (node->next != NULL)) {
4839 node = node->next;
4840 break;
4841 }
4842 if (node->parent == NULL) {
4843 node = NULL;
4844 break;
4845 }
4846 }
4847 /* exit condition */
4848 if (node == tree)
4849 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00004850 } else
4851 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004852 }
Daniel Veillardf742d342002-03-07 00:05:35 +00004853 if (oldNs != NULL)
4854 xmlFree(oldNs);
4855 if (newNs != NULL)
4856 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00004857 return(ret);
4858}
4859
4860/**
4861 * xmlHasProp:
4862 * @node: the node
4863 * @name: the attribute name
4864 *
4865 * Search an attribute associated to a node
4866 * This function also looks in DTD attribute declaration for #FIXED or
4867 * default declaration values unless DTD use has been turned off.
4868 *
4869 * Returns the attribute or the attribute declaration or NULL if
4870 * neither was found.
4871 */
4872xmlAttrPtr
4873xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4874 xmlAttrPtr prop;
4875 xmlDocPtr doc;
4876
4877 if ((node == NULL) || (name == NULL)) return(NULL);
4878 /*
4879 * Check on the properties attached to the node
4880 */
4881 prop = node->properties;
4882 while (prop != NULL) {
4883 if (xmlStrEqual(prop->name, name)) {
4884 return(prop);
4885 }
4886 prop = prop->next;
4887 }
4888 if (!xmlCheckDTD) return(NULL);
4889
4890 /*
4891 * Check if there is a default declaration in the internal
4892 * or external subsets
4893 */
4894 doc = node->doc;
4895 if (doc != NULL) {
4896 xmlAttributePtr attrDecl;
4897 if (doc->intSubset != NULL) {
4898 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4899 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4900 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4901 if (attrDecl != NULL)
4902 return((xmlAttrPtr) attrDecl);
4903 }
4904 }
4905 return(NULL);
4906}
4907
4908/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004909 * xmlHasNsProp:
4910 * @node: the node
4911 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004912 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004913 *
4914 * Search for an attribute associated to a node
4915 * This attribute has to be anchored in the namespace specified.
4916 * This does the entity substitution.
4917 * This function looks in DTD attribute declaration for #FIXED or
4918 * default declaration values unless DTD use has been turned off.
4919 *
4920 * Returns the attribute or the attribute declaration or NULL
4921 * if neither was found.
4922 */
4923xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004924xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004925 xmlAttrPtr prop;
4926 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004927
4928 if (node == NULL)
4929 return(NULL);
4930
4931 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004932 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004933 return(xmlHasProp(node, name));
4934 while (prop != NULL) {
4935 /*
4936 * One need to have
4937 * - same attribute names
4938 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004939 */
4940 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004941 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4942 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004943 }
4944 prop = prop->next;
4945 }
4946 if (!xmlCheckDTD) return(NULL);
4947
4948 /*
4949 * Check if there is a default declaration in the internal
4950 * or external subsets
4951 */
4952 doc = node->doc;
4953 if (doc != NULL) {
4954 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004955 xmlAttributePtr attrDecl = NULL;
4956 xmlNsPtr *nsList, *cur;
4957 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004958
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004959 nsList = xmlGetNsList(node->doc, node);
4960 if (nsList == NULL)
4961 return(NULL);
4962 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
4963 ename = xmlStrdup(node->ns->prefix);
4964 ename = xmlStrcat(ename, BAD_CAST ":");
4965 ename = xmlStrcat(ename, node->name);
4966 } else {
4967 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004968 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004969 if (ename == NULL) {
4970 xmlFree(nsList);
4971 return(NULL);
4972 }
4973
4974 cur = nsList;
4975 while (*cur != NULL) {
4976 if (xmlStrEqual((*cur)->href, nameSpace)) {
4977 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
4978 name, (*cur)->prefix);
4979 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4980 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
4981 name, (*cur)->prefix);
4982 }
4983 cur++;
4984 }
4985 xmlFree(nsList);
4986 xmlFree(ename);
4987 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004988 }
4989 }
4990 return(NULL);
4991}
4992
4993/**
Owen Taylor3473f882001-02-23 17:55:21 +00004994 * xmlGetProp:
4995 * @node: the node
4996 * @name: the attribute name
4997 *
4998 * Search and get the value of an attribute associated to a node
4999 * This does the entity substitution.
5000 * This function looks in DTD attribute declaration for #FIXED or
5001 * default declaration values unless DTD use has been turned off.
5002 *
5003 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005004 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005005 */
5006xmlChar *
5007xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5008 xmlAttrPtr prop;
5009 xmlDocPtr doc;
5010
5011 if ((node == NULL) || (name == NULL)) return(NULL);
5012 /*
5013 * Check on the properties attached to the node
5014 */
5015 prop = node->properties;
5016 while (prop != NULL) {
5017 if (xmlStrEqual(prop->name, name)) {
5018 xmlChar *ret;
5019
5020 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5021 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5022 return(ret);
5023 }
5024 prop = prop->next;
5025 }
5026 if (!xmlCheckDTD) return(NULL);
5027
5028 /*
5029 * Check if there is a default declaration in the internal
5030 * or external subsets
5031 */
5032 doc = node->doc;
5033 if (doc != NULL) {
5034 xmlAttributePtr attrDecl;
5035 if (doc->intSubset != NULL) {
5036 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5037 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5038 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5039 if (attrDecl != NULL)
5040 return(xmlStrdup(attrDecl->defaultValue));
5041 }
5042 }
5043 return(NULL);
5044}
5045
5046/**
5047 * xmlGetNsProp:
5048 * @node: the node
5049 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005050 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005051 *
5052 * Search and get the value of an attribute associated to a node
5053 * This attribute has to be anchored in the namespace specified.
5054 * This does the entity substitution.
5055 * This function looks in DTD attribute declaration for #FIXED or
5056 * default declaration values unless DTD use has been turned off.
5057 *
5058 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005059 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005060 */
5061xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005062xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005063 xmlAttrPtr prop;
5064 xmlDocPtr doc;
5065 xmlNsPtr ns;
5066
5067 if (node == NULL)
5068 return(NULL);
5069
5070 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005071 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005072 return(xmlGetProp(node, name));
5073 while (prop != NULL) {
5074 /*
5075 * One need to have
5076 * - same attribute names
5077 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005078 */
5079 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005080 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005081 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005082 xmlChar *ret;
5083
5084 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5085 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5086 return(ret);
5087 }
5088 prop = prop->next;
5089 }
5090 if (!xmlCheckDTD) return(NULL);
5091
5092 /*
5093 * Check if there is a default declaration in the internal
5094 * or external subsets
5095 */
5096 doc = node->doc;
5097 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005098 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005099 xmlAttributePtr attrDecl;
5100
Owen Taylor3473f882001-02-23 17:55:21 +00005101 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5102 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5103 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5104
5105 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5106 /*
5107 * The DTD declaration only allows a prefix search
5108 */
5109 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005110 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005111 return(xmlStrdup(attrDecl->defaultValue));
5112 }
5113 }
5114 }
5115 return(NULL);
5116}
5117
5118/**
5119 * xmlSetProp:
5120 * @node: the node
5121 * @name: the attribute name
5122 * @value: the attribute value
5123 *
5124 * Set (or reset) an attribute carried by a node.
5125 * Returns the attribute pointer.
5126 */
5127xmlAttrPtr
5128xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005129 xmlAttrPtr prop;
5130 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005131
5132 if ((node == NULL) || (name == NULL))
5133 return(NULL);
5134 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005135 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005136 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005137 if ((xmlStrEqual(prop->name, name)) &&
5138 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005139 xmlNodePtr oldprop = prop->children;
5140
Owen Taylor3473f882001-02-23 17:55:21 +00005141 prop->children = NULL;
5142 prop->last = NULL;
5143 if (value != NULL) {
5144 xmlChar *buffer;
5145 xmlNodePtr tmp;
5146
5147 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5148 prop->children = xmlStringGetNodeList(node->doc, buffer);
5149 prop->last = NULL;
5150 prop->doc = doc;
5151 tmp = prop->children;
5152 while (tmp != NULL) {
5153 tmp->parent = (xmlNodePtr) prop;
5154 tmp->doc = doc;
5155 if (tmp->next == NULL)
5156 prop->last = tmp;
5157 tmp = tmp->next;
5158 }
5159 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005160 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005161 if (oldprop != NULL)
5162 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005163 return(prop);
5164 }
5165 prop = prop->next;
5166 }
5167 prop = xmlNewProp(node, name, value);
5168 return(prop);
5169}
5170
5171/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005172 * xmlUnsetProp:
5173 * @node: the node
5174 * @name: the attribute name
5175 *
5176 * Remove an attribute carried by a node.
5177 * Returns 0 if successful, -1 if not found
5178 */
5179int
5180xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
5181 xmlAttrPtr prop = node->properties, prev = NULL;;
5182
5183 if ((node == NULL) || (name == NULL))
5184 return(-1);
5185 while (prop != NULL) {
5186 if ((xmlStrEqual(prop->name, name)) &&
5187 (prop->ns == NULL)) {
5188 if (prev == NULL)
5189 node->properties = prop->next;
5190 else
5191 prev->next = prop->next;
5192 xmlFreeProp(prop);
5193 return(0);
5194 }
5195 prev = prop;
5196 prop = prop->next;
5197 }
5198 return(-1);
5199}
5200
5201/**
Owen Taylor3473f882001-02-23 17:55:21 +00005202 * xmlSetNsProp:
5203 * @node: the node
5204 * @ns: the namespace definition
5205 * @name: the attribute name
5206 * @value: the attribute value
5207 *
5208 * Set (or reset) an attribute carried by a node.
5209 * The ns structure must be in scope, this is not checked.
5210 *
5211 * Returns the attribute pointer.
5212 */
5213xmlAttrPtr
5214xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5215 const xmlChar *value) {
5216 xmlAttrPtr prop;
5217
5218 if ((node == NULL) || (name == NULL))
5219 return(NULL);
5220
5221 if (ns == NULL)
5222 return(xmlSetProp(node, name, value));
5223 if (ns->href == NULL)
5224 return(NULL);
5225 prop = node->properties;
5226
5227 while (prop != NULL) {
5228 /*
5229 * One need to have
5230 * - same attribute names
5231 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005232 */
5233 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00005234 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005235 if (prop->children != NULL)
5236 xmlFreeNodeList(prop->children);
5237 prop->children = NULL;
5238 prop->last = NULL;
5239 prop->ns = ns;
5240 if (value != NULL) {
5241 xmlChar *buffer;
5242 xmlNodePtr tmp;
5243
5244 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5245 prop->children = xmlStringGetNodeList(node->doc, buffer);
5246 prop->last = NULL;
5247 tmp = prop->children;
5248 while (tmp != NULL) {
5249 tmp->parent = (xmlNodePtr) prop;
5250 if (tmp->next == NULL)
5251 prop->last = tmp;
5252 tmp = tmp->next;
5253 }
5254 xmlFree(buffer);
5255 }
5256 return(prop);
5257 }
5258 prop = prop->next;
5259 }
5260 prop = xmlNewNsProp(node, ns, name, value);
5261 return(prop);
5262}
5263
5264/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005265 * xmlUnsetNsProp:
5266 * @node: the node
5267 * @ns: the namespace definition
5268 * @name: the attribute name
5269 *
5270 * Remove an attribute carried by a node.
5271 * Returns 0 if successful, -1 if not found
5272 */
5273int
5274xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5275 xmlAttrPtr prop = node->properties, prev = NULL;;
5276
5277 if ((node == NULL) || (name == NULL))
5278 return(-1);
5279 if (ns == NULL)
5280 return(xmlUnsetProp(node, name));
5281 if (ns->href == NULL)
5282 return(-1);
5283 while (prop != NULL) {
5284 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00005285 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005286 if (prev == NULL)
5287 node->properties = prop->next;
5288 else
5289 prev->next = prop->next;
5290 xmlFreeProp(prop);
5291 return(0);
5292 }
5293 prev = prop;
5294 prop = prop->next;
5295 }
5296 return(-1);
5297}
5298
5299/**
Owen Taylor3473f882001-02-23 17:55:21 +00005300 * xmlNodeIsText:
5301 * @node: the node
5302 *
5303 * Is this node a Text node ?
5304 * Returns 1 yes, 0 no
5305 */
5306int
5307xmlNodeIsText(xmlNodePtr node) {
5308 if (node == NULL) return(0);
5309
5310 if (node->type == XML_TEXT_NODE) return(1);
5311 return(0);
5312}
5313
5314/**
5315 * xmlIsBlankNode:
5316 * @node: the node
5317 *
5318 * Checks whether this node is an empty or whitespace only
5319 * (and possibly ignorable) text-node.
5320 *
5321 * Returns 1 yes, 0 no
5322 */
5323int
5324xmlIsBlankNode(xmlNodePtr node) {
5325 const xmlChar *cur;
5326 if (node == NULL) return(0);
5327
Daniel Veillard7db37732001-07-12 01:20:08 +00005328 if ((node->type != XML_TEXT_NODE) &&
5329 (node->type != XML_CDATA_SECTION_NODE))
5330 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005331 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005332 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005333 while (*cur != 0) {
5334 if (!IS_BLANK(*cur)) return(0);
5335 cur++;
5336 }
5337
5338 return(1);
5339}
5340
5341/**
5342 * xmlTextConcat:
5343 * @node: the node
5344 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005345 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005346 *
5347 * Concat the given string at the end of the existing node content
5348 */
5349
5350void
5351xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5352 if (node == NULL) return;
5353
5354 if ((node->type != XML_TEXT_NODE) &&
5355 (node->type != XML_CDATA_SECTION_NODE)) {
5356#ifdef DEBUG_TREE
5357 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005358 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005359#endif
5360 return;
5361 }
Owen Taylor3473f882001-02-23 17:55:21 +00005362 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005363}
5364
5365/************************************************************************
5366 * *
5367 * Output : to a FILE or in memory *
5368 * *
5369 ************************************************************************/
5370
Owen Taylor3473f882001-02-23 17:55:21 +00005371/**
5372 * xmlBufferCreate:
5373 *
5374 * routine to create an XML buffer.
5375 * returns the new structure.
5376 */
5377xmlBufferPtr
5378xmlBufferCreate(void) {
5379 xmlBufferPtr ret;
5380
5381 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5382 if (ret == NULL) {
5383 xmlGenericError(xmlGenericErrorContext,
5384 "xmlBufferCreate : out of memory!\n");
5385 return(NULL);
5386 }
5387 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005388 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005389 ret->alloc = xmlBufferAllocScheme;
5390 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5391 if (ret->content == NULL) {
5392 xmlGenericError(xmlGenericErrorContext,
5393 "xmlBufferCreate : out of memory!\n");
5394 xmlFree(ret);
5395 return(NULL);
5396 }
5397 ret->content[0] = 0;
5398 return(ret);
5399}
5400
5401/**
5402 * xmlBufferCreateSize:
5403 * @size: initial size of buffer
5404 *
5405 * routine to create an XML buffer.
5406 * returns the new structure.
5407 */
5408xmlBufferPtr
5409xmlBufferCreateSize(size_t size) {
5410 xmlBufferPtr ret;
5411
5412 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5413 if (ret == NULL) {
5414 xmlGenericError(xmlGenericErrorContext,
5415 "xmlBufferCreate : out of memory!\n");
5416 return(NULL);
5417 }
5418 ret->use = 0;
5419 ret->alloc = xmlBufferAllocScheme;
5420 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5421 if (ret->size){
5422 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5423 if (ret->content == NULL) {
5424 xmlGenericError(xmlGenericErrorContext,
5425 "xmlBufferCreate : out of memory!\n");
5426 xmlFree(ret);
5427 return(NULL);
5428 }
5429 ret->content[0] = 0;
5430 } else
5431 ret->content = NULL;
5432 return(ret);
5433}
5434
5435/**
5436 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005437 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00005438 * @scheme: allocation scheme to use
5439 *
5440 * Sets the allocation scheme for this buffer
5441 */
5442void
5443xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5444 xmlBufferAllocationScheme scheme) {
5445 if (buf == NULL) {
5446#ifdef DEBUG_BUFFER
5447 xmlGenericError(xmlGenericErrorContext,
5448 "xmlBufferSetAllocationScheme: buf == NULL\n");
5449#endif
5450 return;
5451 }
5452
5453 buf->alloc = scheme;
5454}
5455
5456/**
5457 * xmlBufferFree:
5458 * @buf: the buffer to free
5459 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005460 * Frees an XML buffer. It frees both the content and the structure which
5461 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005462 */
5463void
5464xmlBufferFree(xmlBufferPtr buf) {
5465 if (buf == NULL) {
5466#ifdef DEBUG_BUFFER
5467 xmlGenericError(xmlGenericErrorContext,
5468 "xmlBufferFree: buf == NULL\n");
5469#endif
5470 return;
5471 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00005472 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005473 xmlFree(buf->content);
5474 }
Owen Taylor3473f882001-02-23 17:55:21 +00005475 xmlFree(buf);
5476}
5477
5478/**
5479 * xmlBufferEmpty:
5480 * @buf: the buffer
5481 *
5482 * empty a buffer.
5483 */
5484void
5485xmlBufferEmpty(xmlBufferPtr buf) {
5486 if (buf->content == NULL) return;
5487 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005488 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005489}
5490
5491/**
5492 * xmlBufferShrink:
5493 * @buf: the buffer to dump
5494 * @len: the number of xmlChar to remove
5495 *
5496 * Remove the beginning of an XML buffer.
5497 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005498 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005499 */
5500int
5501xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5502 if (len == 0) return(0);
5503 if (len > buf->use) return(-1);
5504
5505 buf->use -= len;
5506 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5507
5508 buf->content[buf->use] = 0;
5509 return(len);
5510}
5511
5512/**
5513 * xmlBufferGrow:
5514 * @buf: the buffer
5515 * @len: the minimum free size to allocate
5516 *
5517 * Grow the available space of an XML buffer.
5518 *
5519 * Returns the new available space or -1 in case of error
5520 */
5521int
5522xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5523 int size;
5524 xmlChar *newbuf;
5525
5526 if (len + buf->use < buf->size) return(0);
5527
5528 size = buf->use + len + 100;
5529
5530 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5531 if (newbuf == NULL) return(-1);
5532 buf->content = newbuf;
5533 buf->size = size;
5534 return(buf->size - buf->use);
5535}
5536
5537/**
5538 * xmlBufferDump:
5539 * @file: the file output
5540 * @buf: the buffer to dump
5541 *
5542 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005543 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005544 */
5545int
5546xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5547 int ret;
5548
5549 if (buf == NULL) {
5550#ifdef DEBUG_BUFFER
5551 xmlGenericError(xmlGenericErrorContext,
5552 "xmlBufferDump: buf == NULL\n");
5553#endif
5554 return(0);
5555 }
5556 if (buf->content == NULL) {
5557#ifdef DEBUG_BUFFER
5558 xmlGenericError(xmlGenericErrorContext,
5559 "xmlBufferDump: buf->content == NULL\n");
5560#endif
5561 return(0);
5562 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005563 if (file == NULL)
5564 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005565 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5566 return(ret);
5567}
5568
5569/**
5570 * xmlBufferContent:
5571 * @buf: the buffer
5572 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005573 * Function to extract the content of a buffer
5574 *
Owen Taylor3473f882001-02-23 17:55:21 +00005575 * Returns the internal content
5576 */
5577
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005578const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005579xmlBufferContent(const xmlBufferPtr buf)
5580{
5581 if(!buf)
5582 return NULL;
5583
5584 return buf->content;
5585}
5586
5587/**
5588 * xmlBufferLength:
5589 * @buf: the buffer
5590 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005591 * Function to get the length of a buffer
5592 *
Owen Taylor3473f882001-02-23 17:55:21 +00005593 * Returns the length of data in the internal content
5594 */
5595
5596int
5597xmlBufferLength(const xmlBufferPtr buf)
5598{
5599 if(!buf)
5600 return 0;
5601
5602 return buf->use;
5603}
5604
5605/**
5606 * xmlBufferResize:
5607 * @buf: the buffer to resize
5608 * @size: the desired size
5609 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005610 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005611 *
5612 * Returns 0 in case of problems, 1 otherwise
5613 */
5614int
5615xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5616{
5617 unsigned int newSize;
5618 xmlChar* rebuf = NULL;
5619
5620 /*take care of empty case*/
5621 newSize = (buf->size ? buf->size*2 : size);
5622
5623 /* Don't resize if we don't have to */
5624 if (size < buf->size)
5625 return 1;
5626
5627 /* figure out new size */
5628 switch (buf->alloc){
5629 case XML_BUFFER_ALLOC_DOUBLEIT:
5630 while (size > newSize) newSize *= 2;
5631 break;
5632 case XML_BUFFER_ALLOC_EXACT:
5633 newSize = size+10;
5634 break;
5635 default:
5636 newSize = size+10;
5637 break;
5638 }
5639
5640 if (buf->content == NULL)
5641 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5642 else
5643 rebuf = (xmlChar *) xmlRealloc(buf->content,
5644 newSize * sizeof(xmlChar));
5645 if (rebuf == NULL) {
5646 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005647 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005648 return 0;
5649 }
5650 buf->content = rebuf;
5651 buf->size = newSize;
5652
5653 return 1;
5654}
5655
5656/**
5657 * xmlBufferAdd:
5658 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005659 * @str: the #xmlChar string
5660 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005661 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005662 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005663 * str is recomputed.
5664 */
5665void
5666xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5667 unsigned int needSize;
5668
5669 if (str == NULL) {
5670#ifdef DEBUG_BUFFER
5671 xmlGenericError(xmlGenericErrorContext,
5672 "xmlBufferAdd: str == NULL\n");
5673#endif
5674 return;
5675 }
5676 if (len < -1) {
5677#ifdef DEBUG_BUFFER
5678 xmlGenericError(xmlGenericErrorContext,
5679 "xmlBufferAdd: len < 0\n");
5680#endif
5681 return;
5682 }
5683 if (len == 0) return;
5684
5685 if (len < 0)
5686 len = xmlStrlen(str);
5687
5688 if (len <= 0) return;
5689
5690 needSize = buf->use + len + 2;
5691 if (needSize > buf->size){
5692 if (!xmlBufferResize(buf, needSize)){
5693 xmlGenericError(xmlGenericErrorContext,
5694 "xmlBufferAdd : out of memory!\n");
5695 return;
5696 }
5697 }
5698
5699 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5700 buf->use += len;
5701 buf->content[buf->use] = 0;
5702}
5703
5704/**
5705 * xmlBufferAddHead:
5706 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005707 * @str: the #xmlChar string
5708 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005709 *
5710 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005711 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005712 */
5713void
5714xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5715 unsigned int needSize;
5716
5717 if (str == NULL) {
5718#ifdef DEBUG_BUFFER
5719 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005720 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005721#endif
5722 return;
5723 }
5724 if (len < -1) {
5725#ifdef DEBUG_BUFFER
5726 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005727 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005728#endif
5729 return;
5730 }
5731 if (len == 0) return;
5732
5733 if (len < 0)
5734 len = xmlStrlen(str);
5735
5736 if (len <= 0) return;
5737
5738 needSize = buf->use + len + 2;
5739 if (needSize > buf->size){
5740 if (!xmlBufferResize(buf, needSize)){
5741 xmlGenericError(xmlGenericErrorContext,
5742 "xmlBufferAddHead : out of memory!\n");
5743 return;
5744 }
5745 }
5746
5747 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5748 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5749 buf->use += len;
5750 buf->content[buf->use] = 0;
5751}
5752
5753/**
5754 * xmlBufferCat:
5755 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005756 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005757 *
5758 * Append a zero terminated string to an XML buffer.
5759 */
5760void
5761xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5762 if (str != NULL)
5763 xmlBufferAdd(buf, str, -1);
5764}
5765
5766/**
5767 * xmlBufferCCat:
5768 * @buf: the buffer to dump
5769 * @str: the C char string
5770 *
5771 * Append a zero terminated C string to an XML buffer.
5772 */
5773void
5774xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5775 const char *cur;
5776
5777 if (str == NULL) {
5778#ifdef DEBUG_BUFFER
5779 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005780 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005781#endif
5782 return;
5783 }
5784 for (cur = str;*cur != 0;cur++) {
5785 if (buf->use + 10 >= buf->size) {
5786 if (!xmlBufferResize(buf, buf->use+10)){
5787 xmlGenericError(xmlGenericErrorContext,
5788 "xmlBufferCCat : out of memory!\n");
5789 return;
5790 }
5791 }
5792 buf->content[buf->use++] = *cur;
5793 }
5794 buf->content[buf->use] = 0;
5795}
5796
5797/**
5798 * xmlBufferWriteCHAR:
5799 * @buf: the XML buffer
5800 * @string: the string to add
5801 *
5802 * routine which manages and grows an output buffer. This one adds
5803 * xmlChars at the end of the buffer.
5804 */
5805void
Owen Taylor3473f882001-02-23 17:55:21 +00005806xmlBufferWriteCHAR
Owen Taylor3473f882001-02-23 17:55:21 +00005807(xmlBufferPtr buf, const xmlChar *string) {
5808 xmlBufferCat(buf, string);
5809}
5810
5811/**
5812 * xmlBufferWriteChar:
5813 * @buf: the XML buffer output
5814 * @string: the string to add
5815 *
5816 * routine which manage and grows an output buffer. This one add
5817 * C chars at the end of the array.
5818 */
5819void
5820xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5821 xmlBufferCCat(buf, string);
5822}
5823
5824
5825/**
5826 * xmlBufferWriteQuotedString:
5827 * @buf: the XML buffer output
5828 * @string: the string to add
5829 *
5830 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005831 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005832 * quote or double-quotes internally
5833 */
5834void
5835xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5836 if (xmlStrchr(string, '"')) {
5837 if (xmlStrchr(string, '\'')) {
5838#ifdef DEBUG_BUFFER
5839 xmlGenericError(xmlGenericErrorContext,
5840 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5841#endif
5842 }
5843 xmlBufferCCat(buf, "'");
5844 xmlBufferCat(buf, string);
5845 xmlBufferCCat(buf, "'");
5846 } else {
5847 xmlBufferCCat(buf, "\"");
5848 xmlBufferCat(buf, string);
5849 xmlBufferCCat(buf, "\"");
5850 }
5851}
5852
5853
5854/************************************************************************
5855 * *
5856 * Dumping XML tree content to a simple buffer *
5857 * *
5858 ************************************************************************/
5859
Owen Taylor3473f882001-02-23 17:55:21 +00005860static void
5861xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5862 int format);
5863void
5864htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5865
5866/**
5867 * xmlNsDump:
5868 * @buf: the XML buffer output
5869 * @cur: a namespace
5870 *
5871 * Dump a local Namespace definition.
5872 * Should be called in the context of attributes dumps.
5873 */
5874static void
5875xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5876 if (cur == NULL) {
5877#ifdef DEBUG_TREE
5878 xmlGenericError(xmlGenericErrorContext,
5879 "xmlNsDump : Ns == NULL\n");
5880#endif
5881 return;
5882 }
5883 if (cur->type == XML_LOCAL_NAMESPACE) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005884 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
5885 return;
5886
Owen Taylor3473f882001-02-23 17:55:21 +00005887 /* Within the context of an element attributes */
5888 if (cur->prefix != NULL) {
5889 xmlBufferWriteChar(buf, " xmlns:");
5890 xmlBufferWriteCHAR(buf, cur->prefix);
5891 } else
5892 xmlBufferWriteChar(buf, " xmlns");
5893 xmlBufferWriteChar(buf, "=");
5894 xmlBufferWriteQuotedString(buf, cur->href);
5895 }
5896}
5897
5898/**
5899 * xmlNsListDump:
5900 * @buf: the XML buffer output
5901 * @cur: the first namespace
5902 *
5903 * Dump a list of local Namespace definitions.
5904 * Should be called in the context of attributes dumps.
5905 */
5906static void
5907xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5908 while (cur != NULL) {
5909 xmlNsDump(buf, cur);
5910 cur = cur->next;
5911 }
5912}
5913
5914/**
5915 * xmlDtdDump:
5916 * @buf: the XML buffer output
Daniel Veillardd1640922001-12-17 15:30:10 +00005917 * @dtd: the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00005918 *
5919 * Dump the XML document DTD, if any.
5920 */
5921static void
5922xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5923 if (dtd == NULL) {
5924#ifdef DEBUG_TREE
5925 xmlGenericError(xmlGenericErrorContext,
5926 "xmlDtdDump : no internal subset\n");
5927#endif
5928 return;
5929 }
5930 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5931 xmlBufferWriteCHAR(buf, dtd->name);
5932 if (dtd->ExternalID != NULL) {
5933 xmlBufferWriteChar(buf, " PUBLIC ");
5934 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5935 xmlBufferWriteChar(buf, " ");
5936 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5937 } else if (dtd->SystemID != NULL) {
5938 xmlBufferWriteChar(buf, " SYSTEM ");
5939 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5940 }
5941 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5942 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5943 xmlBufferWriteChar(buf, ">");
5944 return;
5945 }
5946 xmlBufferWriteChar(buf, " [\n");
5947 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5948#if 0
5949 if (dtd->entities != NULL)
5950 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5951 if (dtd->notations != NULL)
5952 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5953 if (dtd->elements != NULL)
5954 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5955 if (dtd->attributes != NULL)
5956 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5957#endif
5958 xmlBufferWriteChar(buf, "]>");
5959}
5960
5961/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00005962 * xmlAttrSerializeContent:
5963 * @buf: the XML buffer output
5964 * @doc: the document
5965 * @attr: the attribute pointer
5966 *
5967 * Serialize the attribute in the buffer
5968 */
5969static void
5970xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr) {
5971 const xmlChar *cur, *base;
5972 xmlNodePtr children;
5973
5974 children = attr->children;
5975 while (children != NULL) {
5976 switch (children->type) {
5977 case XML_TEXT_NODE:
5978 base = cur = children->content;
5979 while (*cur != 0) {
5980 if (*cur == '\n') {
5981 if (base != cur)
5982 xmlBufferAdd(buf, base, cur - base);
5983 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
5984 cur++;
5985 base = cur;
5986#if 0
5987 } else if (*cur == '\'') {
5988 if (base != cur)
5989 xmlBufferAdd(buf, base, cur - base);
5990 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
5991 cur++;
5992 base = cur;
5993#endif
5994 } else if (*cur == '"') {
5995 if (base != cur)
5996 xmlBufferAdd(buf, base, cur - base);
5997 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
5998 cur++;
5999 base = cur;
6000 } else if (*cur == '<') {
6001 if (base != cur)
6002 xmlBufferAdd(buf, base, cur - base);
6003 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6004 cur++;
6005 base = cur;
6006 } else if (*cur == '>') {
6007 if (base != cur)
6008 xmlBufferAdd(buf, base, cur - base);
6009 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6010 cur++;
6011 base = cur;
6012 } else if (*cur == '&') {
6013 if (base != cur)
6014 xmlBufferAdd(buf, base, cur - base);
6015 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6016 cur++;
6017 base = cur;
6018 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6019 (doc->encoding == NULL))) {
6020 /*
6021 * We assume we have UTF-8 content.
6022 */
6023 char tmp[10];
6024 int val = 0, l = 1;
6025
6026 if (base != cur)
6027 xmlBufferAdd(buf, base, cur - base);
6028 if (*cur < 0xC0) {
6029 xmlGenericError(xmlGenericErrorContext,
6030 "xmlAttrSerializeContent : input not UTF-8\n");
6031 if (doc != NULL)
6032 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
6033 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6034 tmp[sizeof(tmp) - 1] = 0;
6035 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6036 cur++;
6037 base = cur;
6038 continue;
6039 } else if (*cur < 0xE0) {
6040 val = (cur[0]) & 0x1F;
6041 val <<= 6;
6042 val |= (cur[1]) & 0x3F;
6043 l = 2;
6044 } else if (*cur < 0xF0) {
6045 val = (cur[0]) & 0x0F;
6046 val <<= 6;
6047 val |= (cur[1]) & 0x3F;
6048 val <<= 6;
6049 val |= (cur[2]) & 0x3F;
6050 l = 3;
6051 } else if (*cur < 0xF8) {
6052 val = (cur[0]) & 0x07;
6053 val <<= 6;
6054 val |= (cur[1]) & 0x3F;
6055 val <<= 6;
6056 val |= (cur[2]) & 0x3F;
6057 val <<= 6;
6058 val |= (cur[3]) & 0x3F;
6059 l = 4;
6060 }
6061 if ((l == 1) || (!IS_CHAR(val))) {
6062 xmlGenericError(xmlGenericErrorContext,
6063 "xmlAttrSerializeContent : char out of range\n");
6064 if (doc != NULL)
6065 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
6066 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6067 tmp[sizeof(tmp) - 1] = 0;
6068 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6069 cur++;
6070 base = cur;
6071 continue;
6072 }
6073 /*
6074 * We could do multiple things here. Just save
6075 * as a char ref
6076 */
6077 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6078 tmp[sizeof(tmp) - 1] = 0;
6079 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6080 cur += l;
6081 base = cur;
6082 } else {
6083 cur++;
6084 }
6085 }
6086 if (base != cur)
6087 xmlBufferAdd(buf, base, cur - base);
6088 break;
6089 case XML_ENTITY_REF_NODE:
6090 xmlBufferAdd(buf, BAD_CAST "&", 1);
6091 xmlBufferAdd(buf, children->name, xmlStrlen(children->name));
6092 xmlBufferAdd(buf, BAD_CAST ";", 1);
6093 break;
6094 default:
6095 /* should not happen unless we have a badly built tree */
6096 break;
6097 }
6098 children = children->next;
6099 }
6100}
6101
6102/**
Owen Taylor3473f882001-02-23 17:55:21 +00006103 * xmlAttrDump:
6104 * @buf: the XML buffer output
6105 * @doc: the document
6106 * @cur: the attribute pointer
6107 *
6108 * Dump an XML attribute
6109 */
6110static void
6111xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00006112 if (cur == NULL) {
6113#ifdef DEBUG_TREE
6114 xmlGenericError(xmlGenericErrorContext,
6115 "xmlAttrDump : property == NULL\n");
6116#endif
6117 return;
6118 }
6119 xmlBufferWriteChar(buf, " ");
6120 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6121 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6122 xmlBufferWriteChar(buf, ":");
6123 }
6124 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006125 xmlBufferWriteChar(buf, "=\"");
6126 xmlAttrSerializeContent(buf, doc, cur);
6127 xmlBufferWriteChar(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006128}
6129
6130/**
6131 * xmlAttrListDump:
6132 * @buf: the XML buffer output
6133 * @doc: the document
6134 * @cur: the first attribute pointer
6135 *
6136 * Dump a list of XML attributes
6137 */
6138static void
6139xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
6140 if (cur == NULL) {
6141#ifdef DEBUG_TREE
6142 xmlGenericError(xmlGenericErrorContext,
6143 "xmlAttrListDump : property == NULL\n");
6144#endif
6145 return;
6146 }
6147 while (cur != NULL) {
6148 xmlAttrDump(buf, doc, cur);
6149 cur = cur->next;
6150 }
6151}
6152
6153
6154
6155/**
6156 * xmlNodeListDump:
6157 * @buf: the XML buffer output
6158 * @doc: the document
6159 * @cur: the first node
6160 * @level: the imbrication level for indenting
6161 * @format: is formatting allowed
6162 *
6163 * Dump an XML node list, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006164 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6165 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006166 */
6167static void
6168xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
6169 int format) {
6170 int i;
6171
6172 if (cur == NULL) {
6173#ifdef DEBUG_TREE
6174 xmlGenericError(xmlGenericErrorContext,
6175 "xmlNodeListDump : node == NULL\n");
6176#endif
6177 return;
6178 }
6179 while (cur != NULL) {
6180 if ((format) && (xmlIndentTreeOutput) &&
6181 (cur->type == XML_ELEMENT_NODE))
6182 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006183 xmlBufferWriteChar(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006184 xmlNodeDump(buf, doc, cur, level, format);
6185 if (format) {
6186 xmlBufferWriteChar(buf, "\n");
6187 }
6188 cur = cur->next;
6189 }
6190}
6191
6192/**
6193 * xmlNodeDump:
6194 * @buf: the XML buffer output
6195 * @doc: the document
6196 * @cur: the current node
6197 * @level: the imbrication level for indenting
6198 * @format: is formatting allowed
6199 *
6200 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006201 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6202 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006203 */
6204void
6205xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
6206 int format) {
6207 int i;
6208 xmlNodePtr tmp;
6209
6210 if (cur == NULL) {
6211#ifdef DEBUG_TREE
6212 xmlGenericError(xmlGenericErrorContext,
6213 "xmlNodeDump : node == NULL\n");
6214#endif
6215 return;
6216 }
6217 if (cur->type == XML_XINCLUDE_START)
6218 return;
6219 if (cur->type == XML_XINCLUDE_END)
6220 return;
6221 if (cur->type == XML_DTD_NODE) {
6222 xmlDtdDump(buf, (xmlDtdPtr) cur);
6223 return;
6224 }
6225 if (cur->type == XML_ELEMENT_DECL) {
6226 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
6227 return;
6228 }
Daniel Veillard78d12092001-10-11 09:12:24 +00006229 if (cur->type == XML_ATTRIBUTE_NODE){
6230 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
6231 return;
6232 }
Owen Taylor3473f882001-02-23 17:55:21 +00006233 if (cur->type == XML_ATTRIBUTE_DECL) {
6234 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
6235 return;
6236 }
6237 if (cur->type == XML_ENTITY_DECL) {
6238 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
6239 return;
6240 }
6241 if (cur->type == XML_TEXT_NODE) {
6242 if (cur->content != NULL) {
6243 if ((cur->name == xmlStringText) ||
6244 (cur->name != xmlStringTextNoenc)) {
6245 xmlChar *buffer;
6246
Owen Taylor3473f882001-02-23 17:55:21 +00006247 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006248 if (buffer != NULL) {
6249 xmlBufferWriteCHAR(buf, buffer);
6250 xmlFree(buffer);
6251 }
6252 } else {
6253 /*
6254 * Disable escaping, needed for XSLT
6255 */
Owen Taylor3473f882001-02-23 17:55:21 +00006256 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006257 }
6258 }
6259 return;
6260 }
6261 if (cur->type == XML_PI_NODE) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00006262 xmlBufferWriteChar(buf, "<?");
6263 xmlBufferWriteCHAR(buf, cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006264 if (cur->content != NULL) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00006265 xmlBufferWriteChar(buf, " ");
Daniel Veillard2c748c62002-01-16 15:37:50 +00006266 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006267 }
Daniel Veillard2c748c62002-01-16 15:37:50 +00006268 xmlBufferWriteChar(buf, "?>");
Owen Taylor3473f882001-02-23 17:55:21 +00006269 return;
6270 }
6271 if (cur->type == XML_COMMENT_NODE) {
6272 if (cur->content != NULL) {
6273 xmlBufferWriteChar(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006274 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006275 xmlBufferWriteChar(buf, "-->");
6276 }
6277 return;
6278 }
6279 if (cur->type == XML_ENTITY_REF_NODE) {
6280 xmlBufferWriteChar(buf, "&");
6281 xmlBufferWriteCHAR(buf, cur->name);
6282 xmlBufferWriteChar(buf, ";");
6283 return;
6284 }
6285 if (cur->type == XML_CDATA_SECTION_NODE) {
6286 xmlBufferWriteChar(buf, "<![CDATA[");
6287 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006288 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006289 xmlBufferWriteChar(buf, "]]>");
6290 return;
6291 }
6292
6293 if (format == 1) {
6294 tmp = cur->children;
6295 while (tmp != NULL) {
6296 if ((tmp->type == XML_TEXT_NODE) ||
6297 (tmp->type == XML_ENTITY_REF_NODE)) {
6298 format = 0;
6299 break;
6300 }
6301 tmp = tmp->next;
6302 }
6303 }
6304 xmlBufferWriteChar(buf, "<");
6305 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6306 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6307 xmlBufferWriteChar(buf, ":");
6308 }
6309
6310 xmlBufferWriteCHAR(buf, cur->name);
6311 if (cur->nsDef)
6312 xmlNsListDump(buf, cur->nsDef);
6313 if (cur->properties != NULL)
6314 xmlAttrListDump(buf, doc, cur->properties);
6315
Daniel Veillard7db37732001-07-12 01:20:08 +00006316 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6317 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00006318 (!xmlSaveNoEmptyTags)) {
6319 xmlBufferWriteChar(buf, "/>");
6320 return;
6321 }
6322 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006323 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006324 xmlChar *buffer;
6325
Owen Taylor3473f882001-02-23 17:55:21 +00006326 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006327 if (buffer != NULL) {
6328 xmlBufferWriteCHAR(buf, buffer);
6329 xmlFree(buffer);
6330 }
6331 }
6332 if (cur->children != NULL) {
6333 if (format) xmlBufferWriteChar(buf, "\n");
6334 xmlNodeListDump(buf, doc, cur->children,
6335 (level >= 0?level+1:-1), format);
6336 if ((xmlIndentTreeOutput) && (format))
6337 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006338 xmlBufferWriteChar(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006339 }
6340 xmlBufferWriteChar(buf, "</");
6341 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6342 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6343 xmlBufferWriteChar(buf, ":");
6344 }
6345
6346 xmlBufferWriteCHAR(buf, cur->name);
6347 xmlBufferWriteChar(buf, ">");
6348}
6349
6350/**
6351 * xmlElemDump:
6352 * @f: the FILE * for the output
6353 * @doc: the document
6354 * @cur: the current node
6355 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006356 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006357 */
6358void
6359xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
6360 xmlBufferPtr buf;
6361
6362 if (cur == NULL) {
6363#ifdef DEBUG_TREE
6364 xmlGenericError(xmlGenericErrorContext,
6365 "xmlElemDump : cur == NULL\n");
6366#endif
6367 return;
6368 }
Owen Taylor3473f882001-02-23 17:55:21 +00006369#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006370 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006371 xmlGenericError(xmlGenericErrorContext,
6372 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006373 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006374#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00006375
Owen Taylor3473f882001-02-23 17:55:21 +00006376 buf = xmlBufferCreate();
6377 if (buf == NULL) return;
6378 if ((doc != NULL) &&
6379 (doc->type == XML_HTML_DOCUMENT_NODE)) {
6380#ifdef LIBXML_HTML_ENABLED
6381 htmlNodeDump(buf, doc, cur);
6382#else
6383 xmlGenericError(xmlGenericErrorContext,
6384 "HTML support not compiled in\n");
6385#endif /* LIBXML_HTML_ENABLED */
6386 } else
6387 xmlNodeDump(buf, doc, cur, 0, 1);
6388 xmlBufferDump(f, buf);
6389 xmlBufferFree(buf);
6390}
6391
6392/************************************************************************
6393 * *
6394 * Dumping XML tree content to an I/O output buffer *
6395 * *
6396 ************************************************************************/
6397
Owen Taylor3473f882001-02-23 17:55:21 +00006398static void
6399xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6400 int level, int format, const char *encoding);
6401/**
6402 * xmlNsDumpOutput:
6403 * @buf: the XML buffer output
6404 * @cur: a namespace
6405 *
6406 * Dump a local Namespace definition.
6407 * Should be called in the context of attributes dumps.
6408 */
6409static void
6410xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6411 if (cur == NULL) {
6412#ifdef DEBUG_TREE
6413 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006414 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006415#endif
6416 return;
6417 }
6418 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006419 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6420 return;
6421
Owen Taylor3473f882001-02-23 17:55:21 +00006422 /* Within the context of an element attributes */
6423 if (cur->prefix != NULL) {
6424 xmlOutputBufferWriteString(buf, " xmlns:");
6425 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6426 } else
6427 xmlOutputBufferWriteString(buf, " xmlns");
6428 xmlOutputBufferWriteString(buf, "=");
6429 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6430 }
6431}
6432
6433/**
6434 * xmlNsListDumpOutput:
6435 * @buf: the XML buffer output
6436 * @cur: the first namespace
6437 *
6438 * Dump a list of local Namespace definitions.
6439 * Should be called in the context of attributes dumps.
6440 */
6441static void
6442xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6443 while (cur != NULL) {
6444 xmlNsDumpOutput(buf, cur);
6445 cur = cur->next;
6446 }
6447}
6448
6449/**
6450 * xmlDtdDumpOutput:
6451 * @buf: the XML buffer output
6452 * @doc: the document
6453 * @encoding: an optional encoding string
6454 *
6455 * Dump the XML document DTD, if any.
6456 */
6457static void
6458xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6459 if (dtd == NULL) {
6460#ifdef DEBUG_TREE
6461 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006462 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006463#endif
6464 return;
6465 }
6466 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6467 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6468 if (dtd->ExternalID != NULL) {
6469 xmlOutputBufferWriteString(buf, " PUBLIC ");
6470 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6471 xmlOutputBufferWriteString(buf, " ");
6472 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6473 } else if (dtd->SystemID != NULL) {
6474 xmlOutputBufferWriteString(buf, " SYSTEM ");
6475 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6476 }
6477 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6478 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6479 xmlOutputBufferWriteString(buf, ">");
6480 return;
6481 }
6482 xmlOutputBufferWriteString(buf, " [\n");
6483 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6484 xmlOutputBufferWriteString(buf, "]>");
6485}
6486
6487/**
6488 * xmlAttrDumpOutput:
6489 * @buf: the XML buffer output
6490 * @doc: the document
6491 * @cur: the attribute pointer
6492 * @encoding: an optional encoding string
6493 *
6494 * Dump an XML attribute
6495 */
6496static void
6497xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006498 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006499 if (cur == NULL) {
6500#ifdef DEBUG_TREE
6501 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006502 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006503#endif
6504 return;
6505 }
6506 xmlOutputBufferWriteString(buf, " ");
6507 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6508 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6509 xmlOutputBufferWriteString(buf, ":");
6510 }
6511 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006512 xmlOutputBufferWriteString(buf, "=\"");
6513 xmlAttrSerializeContent(buf->buffer, doc, cur);
6514 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006515}
6516
6517/**
6518 * xmlAttrListDumpOutput:
6519 * @buf: the XML buffer output
6520 * @doc: the document
6521 * @cur: the first attribute pointer
6522 * @encoding: an optional encoding string
6523 *
6524 * Dump a list of XML attributes
6525 */
6526static void
6527xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6528 xmlAttrPtr cur, const char *encoding) {
6529 if (cur == NULL) {
6530#ifdef DEBUG_TREE
6531 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006532 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006533#endif
6534 return;
6535 }
6536 while (cur != NULL) {
6537 xmlAttrDumpOutput(buf, doc, cur, encoding);
6538 cur = cur->next;
6539 }
6540}
6541
6542
6543
6544/**
6545 * xmlNodeListDumpOutput:
6546 * @buf: the XML buffer output
6547 * @doc: the document
6548 * @cur: the first node
6549 * @level: the imbrication level for indenting
6550 * @format: is formatting allowed
6551 * @encoding: an optional encoding string
6552 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006553 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006554 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6555 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006556 */
6557static void
6558xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6559 xmlNodePtr cur, int level, int format, const char *encoding) {
6560 int i;
6561
6562 if (cur == NULL) {
6563#ifdef DEBUG_TREE
6564 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006565 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006566#endif
6567 return;
6568 }
6569 while (cur != NULL) {
6570 if ((format) && (xmlIndentTreeOutput) &&
6571 (cur->type == XML_ELEMENT_NODE))
6572 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006573 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006574 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6575 if (format) {
6576 xmlOutputBufferWriteString(buf, "\n");
6577 }
6578 cur = cur->next;
6579 }
6580}
6581
6582/**
6583 * xmlNodeDumpOutput:
6584 * @buf: the XML buffer output
6585 * @doc: the document
6586 * @cur: the current node
6587 * @level: the imbrication level for indenting
6588 * @format: is formatting allowed
6589 * @encoding: an optional encoding string
6590 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006591 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006592 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6593 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006594 */
6595void
6596xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6597 int level, int format, const char *encoding) {
6598 int i;
6599 xmlNodePtr tmp;
6600
6601 if (cur == NULL) {
6602#ifdef DEBUG_TREE
6603 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006604 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006605#endif
6606 return;
6607 }
6608 if (cur->type == XML_XINCLUDE_START)
6609 return;
6610 if (cur->type == XML_XINCLUDE_END)
6611 return;
6612 if (cur->type == XML_DTD_NODE) {
6613 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6614 return;
6615 }
6616 if (cur->type == XML_ELEMENT_DECL) {
6617 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6618 return;
6619 }
6620 if (cur->type == XML_ATTRIBUTE_DECL) {
6621 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6622 return;
6623 }
6624 if (cur->type == XML_ENTITY_DECL) {
6625 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6626 return;
6627 }
6628 if (cur->type == XML_TEXT_NODE) {
6629 if (cur->content != NULL) {
6630 if ((cur->name == xmlStringText) ||
6631 (cur->name != xmlStringTextNoenc)) {
6632 xmlChar *buffer;
6633
Owen Taylor3473f882001-02-23 17:55:21 +00006634 if (encoding == NULL)
6635 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6636 else
6637 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006638 if (buffer != NULL) {
6639 xmlOutputBufferWriteString(buf, (const char *)buffer);
6640 xmlFree(buffer);
6641 }
6642 } else {
6643 /*
6644 * Disable escaping, needed for XSLT
6645 */
Owen Taylor3473f882001-02-23 17:55:21 +00006646 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006647 }
6648 }
6649
6650 return;
6651 }
6652 if (cur->type == XML_PI_NODE) {
6653 if (cur->content != NULL) {
6654 xmlOutputBufferWriteString(buf, "<?");
6655 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6656 if (cur->content != NULL) {
6657 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006658 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006659 }
6660 xmlOutputBufferWriteString(buf, "?>");
6661 } else {
6662 xmlOutputBufferWriteString(buf, "<?");
6663 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6664 xmlOutputBufferWriteString(buf, "?>");
6665 }
6666 return;
6667 }
6668 if (cur->type == XML_COMMENT_NODE) {
6669 if (cur->content != NULL) {
6670 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006671 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006672 xmlOutputBufferWriteString(buf, "-->");
6673 }
6674 return;
6675 }
6676 if (cur->type == XML_ENTITY_REF_NODE) {
6677 xmlOutputBufferWriteString(buf, "&");
6678 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6679 xmlOutputBufferWriteString(buf, ";");
6680 return;
6681 }
6682 if (cur->type == XML_CDATA_SECTION_NODE) {
6683 xmlOutputBufferWriteString(buf, "<![CDATA[");
6684 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006685 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006686 xmlOutputBufferWriteString(buf, "]]>");
6687 return;
6688 }
6689
6690 if (format == 1) {
6691 tmp = cur->children;
6692 while (tmp != NULL) {
6693 if ((tmp->type == XML_TEXT_NODE) ||
6694 (tmp->type == XML_ENTITY_REF_NODE)) {
6695 format = 0;
6696 break;
6697 }
6698 tmp = tmp->next;
6699 }
6700 }
6701 xmlOutputBufferWriteString(buf, "<");
6702 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6703 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6704 xmlOutputBufferWriteString(buf, ":");
6705 }
6706
6707 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6708 if (cur->nsDef)
6709 xmlNsListDumpOutput(buf, cur->nsDef);
6710 if (cur->properties != NULL)
6711 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6712
Daniel Veillard7db37732001-07-12 01:20:08 +00006713 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6714 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006715 xmlOutputBufferWriteString(buf, "/>");
6716 return;
6717 }
6718 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006719 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006720 xmlChar *buffer;
6721
Owen Taylor3473f882001-02-23 17:55:21 +00006722 if (encoding == NULL)
6723 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6724 else
6725 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006726 if (buffer != NULL) {
6727 xmlOutputBufferWriteString(buf, (const char *)buffer);
6728 xmlFree(buffer);
6729 }
6730 }
6731 if (cur->children != NULL) {
6732 if (format) xmlOutputBufferWriteString(buf, "\n");
6733 xmlNodeListDumpOutput(buf, doc, cur->children,
6734 (level >= 0?level+1:-1), format, encoding);
6735 if ((xmlIndentTreeOutput) && (format))
6736 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006737 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006738 }
6739 xmlOutputBufferWriteString(buf, "</");
6740 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6741 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6742 xmlOutputBufferWriteString(buf, ":");
6743 }
6744
6745 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6746 xmlOutputBufferWriteString(buf, ">");
6747}
6748
6749/**
6750 * xmlDocContentDumpOutput:
6751 * @buf: the XML buffer output
6752 * @cur: the document
6753 * @encoding: an optional encoding string
6754 * @format: should formatting spaces been added
6755 *
6756 * Dump an XML document.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006757 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6758 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006759 */
6760static void
6761xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6762 const char *encoding, int format) {
6763 xmlOutputBufferWriteString(buf, "<?xml version=");
6764 if (cur->version != NULL)
6765 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6766 else
6767 xmlOutputBufferWriteString(buf, "\"1.0\"");
6768 if (encoding == NULL) {
6769 if (cur->encoding != NULL)
6770 encoding = (const char *) cur->encoding;
6771 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6772 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6773 }
6774 if (encoding != NULL) {
6775 xmlOutputBufferWriteString(buf, " encoding=");
6776 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6777 }
6778 switch (cur->standalone) {
6779 case 0:
6780 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6781 break;
6782 case 1:
6783 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6784 break;
6785 }
6786 xmlOutputBufferWriteString(buf, "?>\n");
6787 if (cur->children != NULL) {
6788 xmlNodePtr child = cur->children;
6789
6790 while (child != NULL) {
6791 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6792 xmlOutputBufferWriteString(buf, "\n");
6793 child = child->next;
6794 }
6795 }
6796}
6797
6798/************************************************************************
6799 * *
6800 * Saving functions front-ends *
6801 * *
6802 ************************************************************************/
6803
6804/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006805 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006806 * @out_doc: Document to generate XML text from
6807 * @doc_txt_ptr: Memory pointer for allocated XML text
6808 * @doc_txt_len: Length of the generated XML text
6809 * @txt_encoding: Character encoding to use when generating XML text
6810 * @format: should formatting spaces been added
6811 *
6812 * Dump the current DOM tree into memory using the character encoding specified
6813 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006814 * allocated memory with xmlFree().
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006815 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6816 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006817 */
6818
6819void
6820xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006821 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006822 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006823 int dummy = 0;
6824
6825 xmlCharEncoding doc_charset;
6826 xmlOutputBufferPtr out_buff = NULL;
6827 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6828
6829 if (doc_txt_len == NULL) {
6830 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6831 }
6832
6833 if (doc_txt_ptr == NULL) {
6834 *doc_txt_len = 0;
6835 xmlGenericError(xmlGenericErrorContext,
6836 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6837 return;
6838 }
6839
6840 *doc_txt_ptr = NULL;
6841 *doc_txt_len = 0;
6842
6843 if (out_doc == NULL) {
6844 /* No document, no output */
6845 xmlGenericError(xmlGenericErrorContext,
6846 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6847 return;
6848 }
6849
6850 /*
6851 * Validate the encoding value, if provided.
6852 * This logic is copied from xmlSaveFileEnc.
6853 */
6854
6855 if (txt_encoding == NULL)
6856 txt_encoding = (const char *) out_doc->encoding;
6857 if (txt_encoding != NULL) {
6858 doc_charset = xmlParseCharEncoding(txt_encoding);
6859
6860 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6861 xmlGenericError(xmlGenericErrorContext,
6862 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6863 return;
6864
6865 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6866 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6867 if ( conv_hdlr == NULL ) {
6868 xmlGenericError(xmlGenericErrorContext,
6869 "%s: %s %s '%s'\n",
6870 "xmlDocDumpFormatMemoryEnc",
6871 "Failed to identify encoding handler for",
6872 "character set",
6873 txt_encoding);
6874 return;
6875 }
6876 }
6877 }
6878
6879 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6880 xmlGenericError(xmlGenericErrorContext,
6881 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6882 return;
6883 }
6884
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006885 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006886 xmlOutputBufferFlush(out_buff);
6887 if (out_buff->conv != NULL) {
6888 *doc_txt_len = out_buff->conv->use;
6889 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6890 } else {
6891 *doc_txt_len = out_buff->buffer->use;
6892 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6893 }
6894 (void)xmlOutputBufferClose(out_buff);
6895
6896 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6897 *doc_txt_len = 0;
6898 xmlGenericError(xmlGenericErrorContext,
6899 "xmlDocDumpFormatMemoryEnc: %s\n",
6900 "Failed to allocate memory for document text representation.");
6901 }
6902
6903 return;
6904}
6905
6906/**
6907 * xmlDocDumpMemory:
6908 * @cur: the document
6909 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006910 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006911 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006912 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006913 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006914 */
6915void
6916xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6917 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6918}
6919
6920/**
6921 * xmlDocDumpFormatMemory:
6922 * @cur: the document
6923 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006924 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006925 * @format: should formatting spaces been added
6926 *
6927 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006928 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006929 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006930 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6931 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006932 */
6933void
6934xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6935 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6936}
6937
6938/**
6939 * xmlDocDumpMemoryEnc:
6940 * @out_doc: Document to generate XML text from
6941 * @doc_txt_ptr: Memory pointer for allocated XML text
6942 * @doc_txt_len: Length of the generated XML text
6943 * @txt_encoding: Character encoding to use when generating XML text
6944 *
6945 * Dump the current DOM tree into memory using the character encoding specified
6946 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006947 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006948 */
6949
6950void
6951xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6952 int * doc_txt_len, const char * txt_encoding) {
6953 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006954 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006955}
6956
6957/**
6958 * xmlGetDocCompressMode:
6959 * @doc: the document
6960 *
6961 * get the compression ratio for a document, ZLIB based
6962 * Returns 0 (uncompressed) to 9 (max compression)
6963 */
6964int
6965xmlGetDocCompressMode (xmlDocPtr doc) {
6966 if (doc == NULL) return(-1);
6967 return(doc->compression);
6968}
6969
6970/**
6971 * xmlSetDocCompressMode:
6972 * @doc: the document
6973 * @mode: the compression ratio
6974 *
6975 * set the compression ratio for a document, ZLIB based
6976 * Correct values: 0 (uncompressed) to 9 (max compression)
6977 */
6978void
6979xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6980 if (doc == NULL) return;
6981 if (mode < 0) doc->compression = 0;
6982 else if (mode > 9) doc->compression = 9;
6983 else doc->compression = mode;
6984}
6985
6986/**
6987 * xmlGetCompressMode:
6988 *
6989 * get the default compression mode used, ZLIB based.
6990 * Returns 0 (uncompressed) to 9 (max compression)
6991 */
6992int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00006993xmlGetCompressMode(void)
6994{
6995 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00006996}
6997
6998/**
6999 * xmlSetCompressMode:
7000 * @mode: the compression ratio
7001 *
7002 * set the default compression mode used, ZLIB based
7003 * Correct values: 0 (uncompressed) to 9 (max compression)
7004 */
7005void
7006xmlSetCompressMode(int mode) {
7007 if (mode < 0) xmlCompressMode = 0;
7008 else if (mode > 9) xmlCompressMode = 9;
7009 else xmlCompressMode = mode;
7010}
7011
7012/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007013 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00007014 * @f: the FILE*
7015 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00007016 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007017 *
7018 * Dump an XML document to an open FILE.
7019 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007020 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007021 */
7022int
Daniel Veillard9e412302002-06-10 15:59:44 +00007023xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007024 xmlOutputBufferPtr buf;
7025 const char * encoding;
7026 xmlCharEncodingHandlerPtr handler = NULL;
7027 int ret;
7028
7029 if (cur == NULL) {
7030#ifdef DEBUG_TREE
7031 xmlGenericError(xmlGenericErrorContext,
7032 "xmlDocDump : document == NULL\n");
7033#endif
7034 return(-1);
7035 }
7036 encoding = (const char *) cur->encoding;
7037
7038 if (encoding != NULL) {
7039 xmlCharEncoding enc;
7040
7041 enc = xmlParseCharEncoding(encoding);
7042
7043 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7044 xmlGenericError(xmlGenericErrorContext,
7045 "xmlDocDump: document not in UTF8\n");
7046 return(-1);
7047 }
7048 if (enc != XML_CHAR_ENCODING_UTF8) {
7049 handler = xmlFindCharEncodingHandler(encoding);
7050 if (handler == NULL) {
7051 xmlFree((char *) cur->encoding);
7052 cur->encoding = NULL;
7053 }
7054 }
7055 }
7056 buf = xmlOutputBufferCreateFile(f, handler);
7057 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00007058 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007059
7060 ret = xmlOutputBufferClose(buf);
7061 return(ret);
7062}
7063
7064/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007065 * xmlDocDump:
7066 * @f: the FILE*
7067 * @cur: the document
7068 *
7069 * Dump an XML document to an open FILE.
7070 *
7071 * returns: the number of bytes written or -1 in case of failure.
7072 */
7073int
7074xmlDocDump(FILE *f, xmlDocPtr cur) {
7075 return(xmlDocFormatDump (f, cur, 0));
7076}
7077
7078/**
Owen Taylor3473f882001-02-23 17:55:21 +00007079 * xmlSaveFileTo:
7080 * @buf: an output I/O buffer
7081 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007082 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00007083 *
7084 * Dump an XML document to an I/O buffer.
7085 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007086 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007087 */
7088int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007089xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007090 int ret;
7091
7092 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007093 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007094 ret = xmlOutputBufferClose(buf);
7095 return(ret);
7096}
7097
7098/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00007099 * xmlSaveFormatFileTo:
7100 * @buf: an output I/O buffer
7101 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007102 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00007103 * @format: should formatting spaces been added
7104 *
7105 * Dump an XML document to an I/O buffer.
7106 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007107 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00007108 */
7109int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007110xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00007111 int ret;
7112
7113 if (buf == NULL) return(0);
7114 xmlDocContentDumpOutput(buf, cur, encoding, format);
7115 ret = xmlOutputBufferClose(buf);
7116 return(ret);
7117}
7118
7119/**
Daniel Veillardf012a642001-07-23 19:10:52 +00007120 * xmlSaveFormatFileEnc
7121 * @filename: the filename or URL to output
7122 * @cur: the document being saved
7123 * @encoding: the name of the encoding to use or NULL.
7124 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00007125 *
7126 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00007127 */
7128int
Daniel Veillardf012a642001-07-23 19:10:52 +00007129xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
7130 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00007131 xmlOutputBufferPtr buf;
7132 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00007133 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00007134 int ret;
7135
Daniel Veillardfb25a512002-01-13 20:32:08 +00007136 if (encoding == NULL)
7137 encoding = (const char *) cur->encoding;
7138
Owen Taylor3473f882001-02-23 17:55:21 +00007139 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007140
7141 enc = xmlParseCharEncoding(encoding);
7142 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7143 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007144 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007145 return(-1);
7146 }
7147 if (enc != XML_CHAR_ENCODING_UTF8) {
7148 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00007149 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007150 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007151 }
7152 }
7153
Daniel Veillardf012a642001-07-23 19:10:52 +00007154#ifdef HAVE_ZLIB_H
7155 if (cur->compression < 0) cur->compression = xmlCompressMode;
7156#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007157 /*
7158 * save the content to a temp buffer.
7159 */
Daniel Veillardf012a642001-07-23 19:10:52 +00007160 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00007161 if (buf == NULL) return(-1);
7162
Daniel Veillardf012a642001-07-23 19:10:52 +00007163 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007164
7165 ret = xmlOutputBufferClose(buf);
7166 return(ret);
7167}
7168
Daniel Veillardf012a642001-07-23 19:10:52 +00007169
7170/**
7171 * xmlSaveFileEnc:
7172 * @filename: the filename (or URL)
7173 * @cur: the document
7174 * @encoding: the name of an encoding (or NULL)
7175 *
7176 * Dump an XML document, converting it to the given encoding
7177 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007178 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00007179 */
7180int
7181xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
7182 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
7183}
7184
Owen Taylor3473f882001-02-23 17:55:21 +00007185/**
Daniel Veillard67fee942001-04-26 18:59:03 +00007186 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00007187 * @filename: the filename (or URL)
7188 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00007189 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007190 *
7191 * Dump an XML document to a file. Will use compression if
7192 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00007193 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00007194 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007195 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007196 */
7197int
Daniel Veillard67fee942001-04-26 18:59:03 +00007198xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007199 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00007200}
7201
Daniel Veillard67fee942001-04-26 18:59:03 +00007202/**
7203 * xmlSaveFile:
7204 * @filename: the filename (or URL)
7205 * @cur: the document
7206 *
7207 * Dump an XML document to a file. Will use compression if
7208 * compiled in and enabled. If @filename is "-" the stdout file is
7209 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00007210 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00007211 */
7212int
7213xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007214 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00007215}
7216