blob: 44ea7a5532abbba031ebb62b3cfd0d6256b32f4d [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 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00002656 if (cur->type == XML_ATTRIBUTE_NODE) {
2657 xmlFreeProp((xmlAttrPtr) cur);
2658 return;
2659 }
Owen Taylor3473f882001-02-23 17:55:21 +00002660 if ((cur->children != NULL) &&
2661 (cur->type != XML_ENTITY_REF_NODE))
2662 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002663 if (cur->properties != NULL)
2664 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002665 if ((cur->type != XML_ELEMENT_NODE) &&
2666 (cur->content != NULL) &&
2667 (cur->type != XML_ENTITY_REF_NODE) &&
2668 (cur->type != XML_XINCLUDE_END) &&
2669 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002670 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002671 }
2672
Daniel Veillardacd370f2001-06-09 17:17:51 +00002673 /*
2674 * When a node is a text node or a comment, it uses a global static
2675 * variable for the name of the node.
2676 *
2677 * The xmlStrEqual comparisons need to be done when (happened with
2678 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002679 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002680 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002681 * are not sufficient.
2682 */
Owen Taylor3473f882001-02-23 17:55:21 +00002683 if ((cur->name != NULL) &&
2684 (cur->name != xmlStringText) &&
2685 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002686 (cur->name != xmlStringComment)) {
2687 if (cur->type == XML_TEXT_NODE) {
2688 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2689 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2690 xmlFree((char *) cur->name);
2691 } else if (cur->type == XML_COMMENT_NODE) {
2692 if (!xmlStrEqual(cur->name, xmlStringComment))
2693 xmlFree((char *) cur->name);
2694 } else
2695 xmlFree((char *) cur->name);
2696 }
2697
Owen Taylor3473f882001-02-23 17:55:21 +00002698 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002699 xmlFree(cur);
2700}
2701
2702/**
2703 * xmlUnlinkNode:
2704 * @cur: the node
2705 *
2706 * Unlink a node from it's current context, the node is not freed
2707 */
2708void
2709xmlUnlinkNode(xmlNodePtr cur) {
2710 if (cur == NULL) {
2711#ifdef DEBUG_TREE
2712 xmlGenericError(xmlGenericErrorContext,
2713 "xmlUnlinkNode : node == NULL\n");
2714#endif
2715 return;
2716 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002717 if (cur->type == XML_DTD_NODE) {
2718 xmlDocPtr doc;
2719 doc = cur->doc;
2720 if (doc->intSubset == (xmlDtdPtr) cur)
2721 doc->intSubset = NULL;
2722 if (doc->extSubset == (xmlDtdPtr) cur)
2723 doc->extSubset = NULL;
2724 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002725 if (cur->parent != NULL) {
2726 xmlNodePtr parent;
2727 parent = cur->parent;
2728 if (cur->type == XML_ATTRIBUTE_NODE) {
2729 if (parent->properties == (xmlAttrPtr) cur)
2730 parent->properties = ((xmlAttrPtr) cur)->next;
2731 } else {
2732 if (parent->children == cur)
2733 parent->children = cur->next;
2734 if (parent->last == cur)
2735 parent->last = cur->prev;
2736 }
2737 cur->parent = NULL;
2738 }
Owen Taylor3473f882001-02-23 17:55:21 +00002739 if (cur->next != NULL)
2740 cur->next->prev = cur->prev;
2741 if (cur->prev != NULL)
2742 cur->prev->next = cur->next;
2743 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002744}
2745
2746/**
2747 * xmlReplaceNode:
2748 * @old: the old node
2749 * @cur: the node
2750 *
2751 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002752 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002753 * first unlinked from its existing context.
2754 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002755 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002756 */
2757xmlNodePtr
2758xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2759 if (old == NULL) {
2760#ifdef DEBUG_TREE
2761 xmlGenericError(xmlGenericErrorContext,
2762 "xmlReplaceNode : old == NULL\n");
2763#endif
2764 return(NULL);
2765 }
2766 if (cur == NULL) {
2767 xmlUnlinkNode(old);
2768 return(old);
2769 }
2770 if (cur == old) {
2771 return(old);
2772 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002773 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2774#ifdef DEBUG_TREE
2775 xmlGenericError(xmlGenericErrorContext,
2776 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2777#endif
2778 return(old);
2779 }
2780 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2781#ifdef DEBUG_TREE
2782 xmlGenericError(xmlGenericErrorContext,
2783 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2784#endif
2785 return(old);
2786 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002787 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2788#ifdef DEBUG_TREE
2789 xmlGenericError(xmlGenericErrorContext,
2790 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2791#endif
2792 return(old);
2793 }
2794 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2795#ifdef DEBUG_TREE
2796 xmlGenericError(xmlGenericErrorContext,
2797 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2798#endif
2799 return(old);
2800 }
Owen Taylor3473f882001-02-23 17:55:21 +00002801 xmlUnlinkNode(cur);
2802 cur->doc = old->doc;
2803 cur->parent = old->parent;
2804 cur->next = old->next;
2805 if (cur->next != NULL)
2806 cur->next->prev = cur;
2807 cur->prev = old->prev;
2808 if (cur->prev != NULL)
2809 cur->prev->next = cur;
2810 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002811 if (cur->type == XML_ATTRIBUTE_NODE) {
2812 if (cur->parent->properties == (xmlAttrPtr)old)
2813 cur->parent->properties = ((xmlAttrPtr) cur);
2814 } else {
2815 if (cur->parent->children == old)
2816 cur->parent->children = cur;
2817 if (cur->parent->last == old)
2818 cur->parent->last = cur;
2819 }
Owen Taylor3473f882001-02-23 17:55:21 +00002820 }
2821 old->next = old->prev = NULL;
2822 old->parent = NULL;
2823 return(old);
2824}
2825
2826/************************************************************************
2827 * *
2828 * Copy operations *
2829 * *
2830 ************************************************************************/
2831
2832/**
2833 * xmlCopyNamespace:
2834 * @cur: the namespace
2835 *
2836 * Do a copy of the namespace.
2837 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002838 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002839 */
2840xmlNsPtr
2841xmlCopyNamespace(xmlNsPtr cur) {
2842 xmlNsPtr ret;
2843
2844 if (cur == NULL) return(NULL);
2845 switch (cur->type) {
2846 case XML_LOCAL_NAMESPACE:
2847 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2848 break;
2849 default:
2850#ifdef DEBUG_TREE
2851 xmlGenericError(xmlGenericErrorContext,
2852 "xmlCopyNamespace: invalid type %d\n", cur->type);
2853#endif
2854 return(NULL);
2855 }
2856 return(ret);
2857}
2858
2859/**
2860 * xmlCopyNamespaceList:
2861 * @cur: the first namespace
2862 *
2863 * Do a copy of an namespace list.
2864 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002865 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002866 */
2867xmlNsPtr
2868xmlCopyNamespaceList(xmlNsPtr cur) {
2869 xmlNsPtr ret = NULL;
2870 xmlNsPtr p = NULL,q;
2871
2872 while (cur != NULL) {
2873 q = xmlCopyNamespace(cur);
2874 if (p == NULL) {
2875 ret = p = q;
2876 } else {
2877 p->next = q;
2878 p = q;
2879 }
2880 cur = cur->next;
2881 }
2882 return(ret);
2883}
2884
2885static xmlNodePtr
2886xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2887/**
2888 * xmlCopyProp:
2889 * @target: the element where the attribute will be grafted
2890 * @cur: the attribute
2891 *
2892 * Do a copy of the attribute.
2893 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002894 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002895 */
2896xmlAttrPtr
2897xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2898 xmlAttrPtr ret;
2899
2900 if (cur == NULL) return(NULL);
2901 if (target != NULL)
2902 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2903 else if (cur->parent != NULL)
2904 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2905 else if (cur->children != NULL)
2906 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2907 else
2908 ret = xmlNewDocProp(NULL, cur->name, NULL);
2909 if (ret == NULL) return(NULL);
2910 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002911
Owen Taylor3473f882001-02-23 17:55:21 +00002912 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00002913 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002914/*
2915 * if (target->doc)
2916 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2917 * else if (cur->doc) / * target may not yet have a doc : KPI * /
2918 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
2919 * else
2920 * ns = NULL;
2921 * ret->ns = ns;
2922 */
2923 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2924 if (ns == NULL) {
2925 /*
2926 * Humm, we are copying an element whose namespace is defined
2927 * out of the new tree scope. Search it in the original tree
2928 * and add it at the top of the new tree
2929 */
2930 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
2931 if (ns != NULL) {
2932 xmlNodePtr root = target;
2933 xmlNodePtr pred = NULL;
2934
2935 while (root->parent != NULL) {
2936 pred = root;
2937 root = root->parent;
2938 }
2939 if (root == (xmlNodePtr) target->doc) {
2940 /* correct possibly cycling above the document elt */
2941 root = pred;
2942 }
2943 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
2944 }
2945 } else {
2946 /*
2947 * we have to find something appropriate here since
2948 * we cant be sure, that the namespce we found is identified
2949 * by the prefix
2950 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002951 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002952 /* this is the nice case */
2953 ret->ns = ns;
2954 } else {
2955 /*
2956 * we are in trouble: we need a new reconcilied namespace.
2957 * This is expensive
2958 */
2959 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
2960 }
2961 }
2962
Owen Taylor3473f882001-02-23 17:55:21 +00002963 } else
2964 ret->ns = NULL;
2965
2966 if (cur->children != NULL) {
2967 xmlNodePtr tmp;
2968
2969 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2970 ret->last = NULL;
2971 tmp = ret->children;
2972 while (tmp != NULL) {
2973 /* tmp->parent = (xmlNodePtr)ret; */
2974 if (tmp->next == NULL)
2975 ret->last = tmp;
2976 tmp = tmp->next;
2977 }
2978 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002979 /*
2980 * Try to handle IDs
2981 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00002982 if ((target!= NULL) && (cur!= NULL) &&
2983 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002984 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
2985 if (xmlIsID(cur->doc, cur->parent, cur)) {
2986 xmlChar *id;
2987
2988 id = xmlNodeListGetString(cur->doc, cur->children, 1);
2989 if (id != NULL) {
2990 xmlAddID(NULL, target->doc, id, ret);
2991 xmlFree(id);
2992 }
2993 }
2994 }
Owen Taylor3473f882001-02-23 17:55:21 +00002995 return(ret);
2996}
2997
2998/**
2999 * xmlCopyPropList:
3000 * @target: the element where the attributes will be grafted
3001 * @cur: the first attribute
3002 *
3003 * Do a copy of an attribute list.
3004 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003005 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003006 */
3007xmlAttrPtr
3008xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3009 xmlAttrPtr ret = NULL;
3010 xmlAttrPtr p = NULL,q;
3011
3012 while (cur != NULL) {
3013 q = xmlCopyProp(target, cur);
3014 if (p == NULL) {
3015 ret = p = q;
3016 } else {
3017 p->next = q;
3018 q->prev = p;
3019 p = q;
3020 }
3021 cur = cur->next;
3022 }
3023 return(ret);
3024}
3025
3026/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003027 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003028 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003029 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003030 * tricky reason: namespaces. Doing a direct copy of a node
3031 * say RPM:Copyright without changing the namespace pointer to
3032 * something else can produce stale links. One way to do it is
3033 * to keep a reference counter but this doesn't work as soon
3034 * as one move the element or the subtree out of the scope of
3035 * the existing namespace. The actual solution seems to add
3036 * a copy of the namespace at the top of the copied tree if
3037 * not available in the subtree.
3038 * Hence two functions, the public front-end call the inner ones
3039 */
3040
3041static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003042xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003043 int recursive) {
3044 xmlNodePtr ret;
3045
3046 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003047 switch (node->type) {
3048 case XML_TEXT_NODE:
3049 case XML_CDATA_SECTION_NODE:
3050 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003051 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003052 case XML_ENTITY_REF_NODE:
3053 case XML_ENTITY_NODE:
3054 case XML_PI_NODE:
3055 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003056 case XML_XINCLUDE_START:
3057 case XML_XINCLUDE_END:
3058 break;
3059 case XML_ATTRIBUTE_NODE:
3060 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3061 case XML_NAMESPACE_DECL:
3062 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3063
Daniel Veillard39196eb2001-06-19 18:09:42 +00003064 case XML_DOCUMENT_NODE:
3065 case XML_HTML_DOCUMENT_NODE:
3066#ifdef LIBXML_DOCB_ENABLED
3067 case XML_DOCB_DOCUMENT_NODE:
3068#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003069 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003070 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003071 case XML_NOTATION_NODE:
3072 case XML_DTD_NODE:
3073 case XML_ELEMENT_DECL:
3074 case XML_ATTRIBUTE_DECL:
3075 case XML_ENTITY_DECL:
3076 return(NULL);
3077 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003078
Owen Taylor3473f882001-02-23 17:55:21 +00003079 /*
3080 * Allocate a new node and fill the fields.
3081 */
3082 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3083 if (ret == NULL) {
3084 xmlGenericError(xmlGenericErrorContext,
3085 "xmlStaticCopyNode : malloc failed\n");
3086 return(NULL);
3087 }
3088 memset(ret, 0, sizeof(xmlNode));
3089 ret->type = node->type;
3090
3091 ret->doc = doc;
3092 ret->parent = parent;
3093 if (node->name == xmlStringText)
3094 ret->name = xmlStringText;
3095 else if (node->name == xmlStringTextNoenc)
3096 ret->name = xmlStringTextNoenc;
3097 else if (node->name == xmlStringComment)
3098 ret->name = xmlStringComment;
3099 else if (node->name != NULL)
3100 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003101 if ((node->type != XML_ELEMENT_NODE) &&
3102 (node->content != NULL) &&
3103 (node->type != XML_ENTITY_REF_NODE) &&
3104 (node->type != XML_XINCLUDE_END) &&
3105 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003106 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003107 }else{
3108 if (node->type == XML_ELEMENT_NODE)
3109 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003110 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003111 if (parent != NULL) {
3112 xmlNodePtr tmp;
3113
3114 tmp = xmlAddChild(parent, ret);
3115 /* node could have coalesced */
3116 if (tmp != ret)
3117 return(tmp);
3118 }
Owen Taylor3473f882001-02-23 17:55:21 +00003119
3120 if (!recursive) return(ret);
3121 if (node->nsDef != NULL)
3122 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3123
3124 if (node->ns != NULL) {
3125 xmlNsPtr ns;
3126
3127 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3128 if (ns == NULL) {
3129 /*
3130 * Humm, we are copying an element whose namespace is defined
3131 * out of the new tree scope. Search it in the original tree
3132 * and add it at the top of the new tree
3133 */
3134 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3135 if (ns != NULL) {
3136 xmlNodePtr root = ret;
3137
3138 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003139 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003140 }
3141 } else {
3142 /*
3143 * reference the existing namespace definition in our own tree.
3144 */
3145 ret->ns = ns;
3146 }
3147 }
3148 if (node->properties != NULL)
3149 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003150 if (node->type == XML_ENTITY_REF_NODE) {
3151 if ((doc == NULL) || (node->doc != doc)) {
3152 /*
3153 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003154 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003155 * we cannot keep the reference. Try to find it in the
3156 * target document.
3157 */
3158 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3159 } else {
3160 ret->children = node->children;
3161 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003162 ret->last = ret->children;
3163 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003164 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003165 UPDATE_LAST_CHILD_AND_PARENT(ret)
3166 }
Owen Taylor3473f882001-02-23 17:55:21 +00003167 return(ret);
3168}
3169
3170static xmlNodePtr
3171xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3172 xmlNodePtr ret = NULL;
3173 xmlNodePtr p = NULL,q;
3174
3175 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003176 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003177 if (doc == NULL) {
3178 node = node->next;
3179 continue;
3180 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003181 if (doc->intSubset == NULL) {
3182 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3183 q->doc = doc;
3184 q->parent = parent;
3185 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003186 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003187 } else {
3188 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003189 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003190 }
3191 } else
3192 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003193 if (ret == NULL) {
3194 q->prev = NULL;
3195 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003196 } else if (p != q) {
3197 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003198 p->next = q;
3199 q->prev = p;
3200 p = q;
3201 }
3202 node = node->next;
3203 }
3204 return(ret);
3205}
3206
3207/**
3208 * xmlCopyNode:
3209 * @node: the node
3210 * @recursive: if 1 do a recursive copy.
3211 *
3212 * Do a copy of the node.
3213 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003214 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003215 */
3216xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003217xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003218 xmlNodePtr ret;
3219
3220 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3221 return(ret);
3222}
3223
3224/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003225 * xmlDocCopyNode:
3226 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003227 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003228 * @recursive: if 1 do a recursive copy.
3229 *
3230 * Do a copy of the node to a given document.
3231 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003232 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003233 */
3234xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003235xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003236 xmlNodePtr ret;
3237
3238 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3239 return(ret);
3240}
3241
3242/**
Owen Taylor3473f882001-02-23 17:55:21 +00003243 * xmlCopyNodeList:
3244 * @node: the first node in the list.
3245 *
3246 * Do a recursive copy of the node list.
3247 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003248 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003249 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003250xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003251 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3252 return(ret);
3253}
3254
3255/**
Owen Taylor3473f882001-02-23 17:55:21 +00003256 * xmlCopyDtd:
3257 * @dtd: the dtd
3258 *
3259 * Do a copy of the dtd.
3260 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003261 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003262 */
3263xmlDtdPtr
3264xmlCopyDtd(xmlDtdPtr dtd) {
3265 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003266 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003267
3268 if (dtd == NULL) return(NULL);
3269 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3270 if (ret == NULL) return(NULL);
3271 if (dtd->entities != NULL)
3272 ret->entities = (void *) xmlCopyEntitiesTable(
3273 (xmlEntitiesTablePtr) dtd->entities);
3274 if (dtd->notations != NULL)
3275 ret->notations = (void *) xmlCopyNotationTable(
3276 (xmlNotationTablePtr) dtd->notations);
3277 if (dtd->elements != NULL)
3278 ret->elements = (void *) xmlCopyElementTable(
3279 (xmlElementTablePtr) dtd->elements);
3280 if (dtd->attributes != NULL)
3281 ret->attributes = (void *) xmlCopyAttributeTable(
3282 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003283 if (dtd->pentities != NULL)
3284 ret->pentities = (void *) xmlCopyEntitiesTable(
3285 (xmlEntitiesTablePtr) dtd->pentities);
3286
3287 cur = dtd->children;
3288 while (cur != NULL) {
3289 q = NULL;
3290
3291 if (cur->type == XML_ENTITY_DECL) {
3292 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3293 switch (tmp->etype) {
3294 case XML_INTERNAL_GENERAL_ENTITY:
3295 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3296 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3297 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3298 break;
3299 case XML_INTERNAL_PARAMETER_ENTITY:
3300 case XML_EXTERNAL_PARAMETER_ENTITY:
3301 q = (xmlNodePtr)
3302 xmlGetParameterEntityFromDtd(ret, tmp->name);
3303 break;
3304 case XML_INTERNAL_PREDEFINED_ENTITY:
3305 break;
3306 }
3307 } else if (cur->type == XML_ELEMENT_DECL) {
3308 xmlElementPtr tmp = (xmlElementPtr) cur;
3309 q = (xmlNodePtr)
3310 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3311 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3312 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3313 q = (xmlNodePtr)
3314 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3315 } else if (cur->type == XML_COMMENT_NODE) {
3316 q = xmlCopyNode(cur, 0);
3317 }
3318
3319 if (q == NULL) {
3320 cur = cur->next;
3321 continue;
3322 }
3323
3324 if (p == NULL)
3325 ret->children = q;
3326 else
3327 p->next = q;
3328
3329 q->prev = p;
3330 q->parent = (xmlNodePtr) ret;
3331 q->next = NULL;
3332 ret->last = q;
3333 p = q;
3334 cur = cur->next;
3335 }
3336
Owen Taylor3473f882001-02-23 17:55:21 +00003337 return(ret);
3338}
3339
3340/**
3341 * xmlCopyDoc:
3342 * @doc: the document
3343 * @recursive: if 1 do a recursive copy.
3344 *
3345 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003346 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003347 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003348 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003349 */
3350xmlDocPtr
3351xmlCopyDoc(xmlDocPtr doc, int recursive) {
3352 xmlDocPtr ret;
3353
3354 if (doc == NULL) return(NULL);
3355 ret = xmlNewDoc(doc->version);
3356 if (ret == NULL) return(NULL);
3357 if (doc->name != NULL)
3358 ret->name = xmlMemStrdup(doc->name);
3359 if (doc->encoding != NULL)
3360 ret->encoding = xmlStrdup(doc->encoding);
3361 ret->charset = doc->charset;
3362 ret->compression = doc->compression;
3363 ret->standalone = doc->standalone;
3364 if (!recursive) return(ret);
3365
Daniel Veillardb33c2012001-04-25 12:59:04 +00003366 ret->last = NULL;
3367 ret->children = NULL;
3368 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003369 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003370 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003371 ret->intSubset->parent = ret;
3372 }
Owen Taylor3473f882001-02-23 17:55:21 +00003373 if (doc->oldNs != NULL)
3374 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3375 if (doc->children != NULL) {
3376 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003377
3378 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3379 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003380 ret->last = NULL;
3381 tmp = ret->children;
3382 while (tmp != NULL) {
3383 if (tmp->next == NULL)
3384 ret->last = tmp;
3385 tmp = tmp->next;
3386 }
3387 }
3388 return(ret);
3389}
3390
3391/************************************************************************
3392 * *
3393 * Content access functions *
3394 * *
3395 ************************************************************************/
3396
3397/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003398 * xmlGetLineNo:
3399 * @node : valid node
3400 *
3401 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003402 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003403 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003404 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003405 */
3406long
3407xmlGetLineNo(xmlNodePtr node)
3408{
3409 long result = -1;
3410
3411 if (!node)
3412 return result;
3413 if (node->type == XML_ELEMENT_NODE)
3414 result = (long) node->content;
3415 else if ((node->prev != NULL) &&
3416 ((node->prev->type == XML_ELEMENT_NODE) ||
3417 (node->prev->type == XML_TEXT_NODE)))
3418 result = xmlGetLineNo(node->prev);
3419 else if ((node->parent != NULL) &&
3420 ((node->parent->type == XML_ELEMENT_NODE) ||
3421 (node->parent->type == XML_TEXT_NODE)))
3422 result = xmlGetLineNo(node->parent);
3423
3424 return result;
3425}
3426
3427/**
3428 * xmlGetNodePath:
3429 * @node: a node
3430 *
3431 * Build a structure based Path for the given node
3432 *
3433 * Returns the new path or NULL in case of error. The caller must free
3434 * the returned string
3435 */
3436xmlChar *
3437xmlGetNodePath(xmlNodePtr node)
3438{
3439 xmlNodePtr cur, tmp, next;
3440 xmlChar *buffer = NULL, *temp;
3441 size_t buf_len;
3442 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00003443 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00003444 const char *name;
3445 char nametemp[100];
3446 int occur = 0;
3447
3448 if (node == NULL)
3449 return (NULL);
3450
3451 buf_len = 500;
3452 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3453 if (buffer == NULL)
3454 return (NULL);
3455 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3456 if (buf == NULL) {
3457 xmlFree(buffer);
3458 return (NULL);
3459 }
3460
3461 buffer[0] = 0;
3462 cur = node;
3463 do {
3464 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003465 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003466 occur = 0;
3467 if ((cur->type == XML_DOCUMENT_NODE) ||
3468 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3469 if (buffer[0] == '/')
3470 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003471 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003472 next = NULL;
3473 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003474 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003475 name = (const char *) cur->name;
3476 if (cur->ns) {
3477 snprintf(nametemp, sizeof(nametemp) - 1,
3478 "%s:%s", cur->ns->prefix, cur->name);
3479 nametemp[sizeof(nametemp) - 1] = 0;
3480 name = nametemp;
3481 }
3482 next = cur->parent;
3483
3484 /*
3485 * Thumbler index computation
3486 */
3487 tmp = cur->prev;
3488 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00003489 if ((tmp->type == XML_ELEMENT_NODE) &&
3490 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003491 occur++;
3492 tmp = tmp->prev;
3493 }
3494 if (occur == 0) {
3495 tmp = cur->next;
3496 while (tmp != NULL) {
3497 if (xmlStrEqual(cur->name, tmp->name))
3498 occur++;
3499 tmp = tmp->next;
3500 }
3501 if (occur != 0)
3502 occur = 1;
3503 } else
3504 occur++;
3505 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003506 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003507 name = (const char *) (((xmlAttrPtr) cur)->name);
3508 next = ((xmlAttrPtr) cur)->parent;
3509 } else {
3510 next = cur->parent;
3511 }
3512
3513 /*
3514 * Make sure there is enough room
3515 */
3516 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3517 buf_len =
3518 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3519 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3520 if (temp == NULL) {
3521 xmlFree(buf);
3522 xmlFree(buffer);
3523 return (NULL);
3524 }
3525 buffer = temp;
3526 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3527 if (temp == NULL) {
3528 xmlFree(buf);
3529 xmlFree(buffer);
3530 return (NULL);
3531 }
3532 buf = temp;
3533 }
3534 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003535 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00003536 sep, name, (char *) buffer);
3537 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003538 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00003539 sep, name, occur, (char *) buffer);
3540 snprintf((char *) buffer, buf_len, "%s", buf);
3541 cur = next;
3542 } while (cur != NULL);
3543 xmlFree(buf);
3544 return (buffer);
3545}
3546
3547/**
Owen Taylor3473f882001-02-23 17:55:21 +00003548 * xmlDocGetRootElement:
3549 * @doc: the document
3550 *
3551 * Get the root element of the document (doc->children is a list
3552 * containing possibly comments, PIs, etc ...).
3553 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003554 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003555 */
3556xmlNodePtr
3557xmlDocGetRootElement(xmlDocPtr doc) {
3558 xmlNodePtr ret;
3559
3560 if (doc == NULL) return(NULL);
3561 ret = doc->children;
3562 while (ret != NULL) {
3563 if (ret->type == XML_ELEMENT_NODE)
3564 return(ret);
3565 ret = ret->next;
3566 }
3567 return(ret);
3568}
3569
3570/**
3571 * xmlDocSetRootElement:
3572 * @doc: the document
3573 * @root: the new document root element
3574 *
3575 * Set the root element of the document (doc->children is a list
3576 * containing possibly comments, PIs, etc ...).
3577 *
3578 * Returns the old root element if any was found
3579 */
3580xmlNodePtr
3581xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3582 xmlNodePtr old = NULL;
3583
3584 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00003585 if (root == NULL)
3586 return(NULL);
3587 xmlUnlinkNode(root);
3588 root->doc = doc;
3589 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00003590 old = doc->children;
3591 while (old != NULL) {
3592 if (old->type == XML_ELEMENT_NODE)
3593 break;
3594 old = old->next;
3595 }
3596 if (old == NULL) {
3597 if (doc->children == NULL) {
3598 doc->children = root;
3599 doc->last = root;
3600 } else {
3601 xmlAddSibling(doc->children, root);
3602 }
3603 } else {
3604 xmlReplaceNode(old, root);
3605 }
3606 return(old);
3607}
3608
3609/**
3610 * xmlNodeSetLang:
3611 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003612 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003613 *
3614 * Set the language of a node, i.e. the values of the xml:lang
3615 * attribute.
3616 */
3617void
3618xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003619 xmlNsPtr ns;
3620
Owen Taylor3473f882001-02-23 17:55:21 +00003621 if (cur == NULL) return;
3622 switch(cur->type) {
3623 case XML_TEXT_NODE:
3624 case XML_CDATA_SECTION_NODE:
3625 case XML_COMMENT_NODE:
3626 case XML_DOCUMENT_NODE:
3627 case XML_DOCUMENT_TYPE_NODE:
3628 case XML_DOCUMENT_FRAG_NODE:
3629 case XML_NOTATION_NODE:
3630 case XML_HTML_DOCUMENT_NODE:
3631 case XML_DTD_NODE:
3632 case XML_ELEMENT_DECL:
3633 case XML_ATTRIBUTE_DECL:
3634 case XML_ENTITY_DECL:
3635 case XML_PI_NODE:
3636 case XML_ENTITY_REF_NODE:
3637 case XML_ENTITY_NODE:
3638 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003639#ifdef LIBXML_DOCB_ENABLED
3640 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003641#endif
3642 case XML_XINCLUDE_START:
3643 case XML_XINCLUDE_END:
3644 return;
3645 case XML_ELEMENT_NODE:
3646 case XML_ATTRIBUTE_NODE:
3647 break;
3648 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003649 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3650 if (ns == NULL)
3651 return;
3652 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003653}
3654
3655/**
3656 * xmlNodeGetLang:
3657 * @cur: the node being checked
3658 *
3659 * Searches the language of a node, i.e. the values of the xml:lang
3660 * attribute or the one carried by the nearest ancestor.
3661 *
3662 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003663 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003664 */
3665xmlChar *
3666xmlNodeGetLang(xmlNodePtr cur) {
3667 xmlChar *lang;
3668
3669 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003670 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003671 if (lang != NULL)
3672 return(lang);
3673 cur = cur->parent;
3674 }
3675 return(NULL);
3676}
3677
3678
3679/**
3680 * xmlNodeSetSpacePreserve:
3681 * @cur: the node being changed
3682 * @val: the xml:space value ("0": default, 1: "preserve")
3683 *
3684 * Set (or reset) the space preserving behaviour of a node, i.e. the
3685 * value of the xml:space attribute.
3686 */
3687void
3688xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003689 xmlNsPtr ns;
3690
Owen Taylor3473f882001-02-23 17:55:21 +00003691 if (cur == NULL) return;
3692 switch(cur->type) {
3693 case XML_TEXT_NODE:
3694 case XML_CDATA_SECTION_NODE:
3695 case XML_COMMENT_NODE:
3696 case XML_DOCUMENT_NODE:
3697 case XML_DOCUMENT_TYPE_NODE:
3698 case XML_DOCUMENT_FRAG_NODE:
3699 case XML_NOTATION_NODE:
3700 case XML_HTML_DOCUMENT_NODE:
3701 case XML_DTD_NODE:
3702 case XML_ELEMENT_DECL:
3703 case XML_ATTRIBUTE_DECL:
3704 case XML_ENTITY_DECL:
3705 case XML_PI_NODE:
3706 case XML_ENTITY_REF_NODE:
3707 case XML_ENTITY_NODE:
3708 case XML_NAMESPACE_DECL:
3709 case XML_XINCLUDE_START:
3710 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003711#ifdef LIBXML_DOCB_ENABLED
3712 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003713#endif
3714 return;
3715 case XML_ELEMENT_NODE:
3716 case XML_ATTRIBUTE_NODE:
3717 break;
3718 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003719 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3720 if (ns == NULL)
3721 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003722 switch (val) {
3723 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003724 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003725 break;
3726 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003727 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003728 break;
3729 }
3730}
3731
3732/**
3733 * xmlNodeGetSpacePreserve:
3734 * @cur: the node being checked
3735 *
3736 * Searches the space preserving behaviour of a node, i.e. the values
3737 * of the xml:space attribute or the one carried by the nearest
3738 * ancestor.
3739 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003740 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003741 */
3742int
3743xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3744 xmlChar *space;
3745
3746 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003747 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003748 if (space != NULL) {
3749 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3750 xmlFree(space);
3751 return(1);
3752 }
3753 if (xmlStrEqual(space, BAD_CAST "default")) {
3754 xmlFree(space);
3755 return(0);
3756 }
3757 xmlFree(space);
3758 }
3759 cur = cur->parent;
3760 }
3761 return(-1);
3762}
3763
3764/**
3765 * xmlNodeSetName:
3766 * @cur: the node being changed
3767 * @name: the new tag name
3768 *
3769 * Set (or reset) the name of a node.
3770 */
3771void
3772xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3773 if (cur == NULL) return;
3774 if (name == NULL) return;
3775 switch(cur->type) {
3776 case XML_TEXT_NODE:
3777 case XML_CDATA_SECTION_NODE:
3778 case XML_COMMENT_NODE:
3779 case XML_DOCUMENT_TYPE_NODE:
3780 case XML_DOCUMENT_FRAG_NODE:
3781 case XML_NOTATION_NODE:
3782 case XML_HTML_DOCUMENT_NODE:
3783 case XML_NAMESPACE_DECL:
3784 case XML_XINCLUDE_START:
3785 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003786#ifdef LIBXML_DOCB_ENABLED
3787 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003788#endif
3789 return;
3790 case XML_ELEMENT_NODE:
3791 case XML_ATTRIBUTE_NODE:
3792 case XML_PI_NODE:
3793 case XML_ENTITY_REF_NODE:
3794 case XML_ENTITY_NODE:
3795 case XML_DTD_NODE:
3796 case XML_DOCUMENT_NODE:
3797 case XML_ELEMENT_DECL:
3798 case XML_ATTRIBUTE_DECL:
3799 case XML_ENTITY_DECL:
3800 break;
3801 }
3802 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3803 cur->name = xmlStrdup(name);
3804}
3805
3806/**
3807 * xmlNodeSetBase:
3808 * @cur: the node being changed
3809 * @uri: the new base URI
3810 *
3811 * Set (or reset) the base URI of a node, i.e. the value of the
3812 * xml:base attribute.
3813 */
3814void
3815xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003816 xmlNsPtr ns;
3817
Owen Taylor3473f882001-02-23 17:55:21 +00003818 if (cur == NULL) return;
3819 switch(cur->type) {
3820 case XML_TEXT_NODE:
3821 case XML_CDATA_SECTION_NODE:
3822 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003823 case XML_DOCUMENT_TYPE_NODE:
3824 case XML_DOCUMENT_FRAG_NODE:
3825 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003826 case XML_DTD_NODE:
3827 case XML_ELEMENT_DECL:
3828 case XML_ATTRIBUTE_DECL:
3829 case XML_ENTITY_DECL:
3830 case XML_PI_NODE:
3831 case XML_ENTITY_REF_NODE:
3832 case XML_ENTITY_NODE:
3833 case XML_NAMESPACE_DECL:
3834 case XML_XINCLUDE_START:
3835 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00003836 return;
3837 case XML_ELEMENT_NODE:
3838 case XML_ATTRIBUTE_NODE:
3839 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00003840 case XML_DOCUMENT_NODE:
3841#ifdef LIBXML_DOCB_ENABLED
3842 case XML_DOCB_DOCUMENT_NODE:
3843#endif
3844 case XML_HTML_DOCUMENT_NODE: {
3845 xmlDocPtr doc = (xmlDocPtr) cur;
3846
3847 if (doc->URL != NULL)
3848 xmlFree((xmlChar *) doc->URL);
3849 if (uri == NULL)
3850 doc->URL = NULL;
3851 else
3852 doc->URL = xmlStrdup(uri);
3853 return;
3854 }
Owen Taylor3473f882001-02-23 17:55:21 +00003855 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003856
3857 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3858 if (ns == NULL)
3859 return;
3860 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00003861}
3862
3863/**
Owen Taylor3473f882001-02-23 17:55:21 +00003864 * xmlNodeGetBase:
3865 * @doc: the document the node pertains to
3866 * @cur: the node being checked
3867 *
3868 * Searches for the BASE URL. The code should work on both XML
3869 * and HTML document even if base mechanisms are completely different.
3870 * It returns the base as defined in RFC 2396 sections
3871 * 5.1.1. Base URI within Document Content
3872 * and
3873 * 5.1.2. Base URI from the Encapsulating Entity
3874 * However it does not return the document base (5.1.3), use
3875 * xmlDocumentGetBase() for this
3876 *
3877 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003878 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003879 */
3880xmlChar *
3881xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003882 xmlChar *oldbase = NULL;
3883 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003884
3885 if ((cur == NULL) && (doc == NULL))
3886 return(NULL);
3887 if (doc == NULL) doc = cur->doc;
3888 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3889 cur = doc->children;
3890 while ((cur != NULL) && (cur->name != NULL)) {
3891 if (cur->type != XML_ELEMENT_NODE) {
3892 cur = cur->next;
3893 continue;
3894 }
3895 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3896 cur = cur->children;
3897 continue;
3898 }
3899 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3900 cur = cur->children;
3901 continue;
3902 }
3903 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3904 return(xmlGetProp(cur, BAD_CAST "href"));
3905 }
3906 cur = cur->next;
3907 }
3908 return(NULL);
3909 }
3910 while (cur != NULL) {
3911 if (cur->type == XML_ENTITY_DECL) {
3912 xmlEntityPtr ent = (xmlEntityPtr) cur;
3913 return(xmlStrdup(ent->URI));
3914 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003915 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003916 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003917 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003918 if (oldbase != NULL) {
3919 newbase = xmlBuildURI(oldbase, base);
3920 if (newbase != NULL) {
3921 xmlFree(oldbase);
3922 xmlFree(base);
3923 oldbase = newbase;
3924 } else {
3925 xmlFree(oldbase);
3926 xmlFree(base);
3927 return(NULL);
3928 }
3929 } else {
3930 oldbase = base;
3931 }
3932 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3933 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3934 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3935 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003936 }
3937 }
Owen Taylor3473f882001-02-23 17:55:21 +00003938 cur = cur->parent;
3939 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003940 if ((doc != NULL) && (doc->URL != NULL)) {
3941 if (oldbase == NULL)
3942 return(xmlStrdup(doc->URL));
3943 newbase = xmlBuildURI(oldbase, doc->URL);
3944 xmlFree(oldbase);
3945 return(newbase);
3946 }
3947 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003948}
3949
3950/**
3951 * xmlNodeGetContent:
3952 * @cur: the node being read
3953 *
3954 * Read the value of a node, this can be either the text carried
3955 * directly by this node if it's a TEXT node or the aggregate string
3956 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00003957 * Entity references are substituted.
3958 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003959 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003960 */
3961xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00003962xmlNodeGetContent(xmlNodePtr cur)
3963{
3964 if (cur == NULL)
3965 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003966 switch (cur->type) {
3967 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00003968 case XML_ELEMENT_NODE:{
3969 xmlNodePtr tmp = cur;
3970 xmlBufferPtr buffer;
3971 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00003972
Daniel Veillard7646b182002-04-20 06:41:40 +00003973 buffer = xmlBufferCreate();
3974 if (buffer == NULL)
3975 return (NULL);
3976 while (tmp != NULL) {
3977 switch (tmp->type) {
3978 case XML_CDATA_SECTION_NODE:
3979 case XML_TEXT_NODE:
3980 if (tmp->content != NULL)
3981 xmlBufferCat(buffer, tmp->content);
3982 break;
3983 case XML_ENTITY_REF_NODE:{
3984 /* recursive substitution of entity references */
3985 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00003986
Daniel Veillard7646b182002-04-20 06:41:40 +00003987 if (cont) {
3988 xmlBufferCat(buffer,
3989 (const xmlChar *) cont);
3990 xmlFree(cont);
3991 }
3992 break;
3993 }
3994 default:
3995 break;
3996 }
3997 /*
3998 * Skip to next node
3999 */
4000 if (tmp->children != NULL) {
4001 if (tmp->children->type != XML_ENTITY_DECL) {
4002 tmp = tmp->children;
4003 continue;
4004 }
4005 }
4006 if (tmp == cur)
4007 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004008
Daniel Veillard7646b182002-04-20 06:41:40 +00004009 if (tmp->next != NULL) {
4010 tmp = tmp->next;
4011 continue;
4012 }
4013
4014 do {
4015 tmp = tmp->parent;
4016 if (tmp == NULL)
4017 break;
4018 if (tmp == cur) {
4019 tmp = NULL;
4020 break;
4021 }
4022 if (tmp->next != NULL) {
4023 tmp = tmp->next;
4024 break;
4025 }
4026 } while (tmp != NULL);
4027 }
4028 ret = buffer->content;
4029 buffer->content = NULL;
4030 xmlBufferFree(buffer);
4031 return (ret);
4032 }
4033 case XML_ATTRIBUTE_NODE:{
4034 xmlAttrPtr attr = (xmlAttrPtr) cur;
4035
4036 if (attr->parent != NULL)
4037 return (xmlNodeListGetString
4038 (attr->parent->doc, attr->children, 1));
4039 else
4040 return (xmlNodeListGetString(NULL, attr->children, 1));
4041 break;
4042 }
Owen Taylor3473f882001-02-23 17:55:21 +00004043 case XML_COMMENT_NODE:
4044 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004045 if (cur->content != NULL)
4046 return (xmlStrdup(cur->content));
4047 return (NULL);
4048 case XML_ENTITY_REF_NODE:{
4049 xmlEntityPtr ent;
4050 xmlNodePtr tmp;
4051 xmlBufferPtr buffer;
4052 xmlChar *ret;
4053
4054 /* lookup entity declaration */
4055 ent = xmlGetDocEntity(cur->doc, cur->name);
4056 if (ent == NULL)
4057 return (NULL);
4058
4059 buffer = xmlBufferCreate();
4060 if (buffer == NULL)
4061 return (NULL);
4062
4063 /* an entity content can be any "well balanced chunk",
4064 * i.e. the result of the content [43] production:
4065 * http://www.w3.org/TR/REC-xml#NT-content
4066 * -> we iterate through child nodes and recursive call
4067 * xmlNodeGetContent() which handles all possible node types */
4068 tmp = ent->children;
4069 while (tmp) {
4070 xmlChar *cont = xmlNodeGetContent(tmp);
4071
4072 if (cont) {
4073 xmlBufferCat(buffer, (const xmlChar *) cont);
4074 xmlFree(cont);
4075 }
4076 tmp = tmp->next;
4077 }
4078
4079 ret = buffer->content;
4080 buffer->content = NULL;
4081 xmlBufferFree(buffer);
4082 return (ret);
4083 }
Owen Taylor3473f882001-02-23 17:55:21 +00004084 case XML_ENTITY_NODE:
4085 case XML_DOCUMENT_NODE:
4086 case XML_HTML_DOCUMENT_NODE:
4087 case XML_DOCUMENT_TYPE_NODE:
4088 case XML_NOTATION_NODE:
4089 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004090 case XML_XINCLUDE_START:
4091 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004092#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004093 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004094#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00004095 return (NULL);
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004096 case XML_NAMESPACE_DECL: {
4097 xmlChar *tmp;
4098
4099 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4100 return (tmp);
4101 }
Owen Taylor3473f882001-02-23 17:55:21 +00004102 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004103 /* TODO !!! */
4104 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004105 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004106 /* TODO !!! */
4107 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004108 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004109 /* TODO !!! */
4110 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004111 case XML_CDATA_SECTION_NODE:
4112 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004113 if (cur->content != NULL)
4114 return (xmlStrdup(cur->content));
4115 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004116 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004117 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004118}
Owen Taylor3473f882001-02-23 17:55:21 +00004119/**
4120 * xmlNodeSetContent:
4121 * @cur: the node being modified
4122 * @content: the new value of the content
4123 *
4124 * Replace the content of a node.
4125 */
4126void
4127xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4128 if (cur == NULL) {
4129#ifdef DEBUG_TREE
4130 xmlGenericError(xmlGenericErrorContext,
4131 "xmlNodeSetContent : node == NULL\n");
4132#endif
4133 return;
4134 }
4135 switch (cur->type) {
4136 case XML_DOCUMENT_FRAG_NODE:
4137 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004138 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004139 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4140 cur->children = xmlStringGetNodeList(cur->doc, content);
4141 UPDATE_LAST_CHILD_AND_PARENT(cur)
4142 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004143 case XML_TEXT_NODE:
4144 case XML_CDATA_SECTION_NODE:
4145 case XML_ENTITY_REF_NODE:
4146 case XML_ENTITY_NODE:
4147 case XML_PI_NODE:
4148 case XML_COMMENT_NODE:
4149 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004150 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004151 }
4152 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4153 cur->last = cur->children = NULL;
4154 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004155 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004156 } else
4157 cur->content = NULL;
4158 break;
4159 case XML_DOCUMENT_NODE:
4160 case XML_HTML_DOCUMENT_NODE:
4161 case XML_DOCUMENT_TYPE_NODE:
4162 case XML_XINCLUDE_START:
4163 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004164#ifdef LIBXML_DOCB_ENABLED
4165 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004166#endif
4167 break;
4168 case XML_NOTATION_NODE:
4169 break;
4170 case XML_DTD_NODE:
4171 break;
4172 case XML_NAMESPACE_DECL:
4173 break;
4174 case XML_ELEMENT_DECL:
4175 /* TODO !!! */
4176 break;
4177 case XML_ATTRIBUTE_DECL:
4178 /* TODO !!! */
4179 break;
4180 case XML_ENTITY_DECL:
4181 /* TODO !!! */
4182 break;
4183 }
4184}
4185
4186/**
4187 * xmlNodeSetContentLen:
4188 * @cur: the node being modified
4189 * @content: the new value of the content
4190 * @len: the size of @content
4191 *
4192 * Replace the content of a node.
4193 */
4194void
4195xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4196 if (cur == NULL) {
4197#ifdef DEBUG_TREE
4198 xmlGenericError(xmlGenericErrorContext,
4199 "xmlNodeSetContentLen : node == NULL\n");
4200#endif
4201 return;
4202 }
4203 switch (cur->type) {
4204 case XML_DOCUMENT_FRAG_NODE:
4205 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004206 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004207 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4208 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4209 UPDATE_LAST_CHILD_AND_PARENT(cur)
4210 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004211 case XML_TEXT_NODE:
4212 case XML_CDATA_SECTION_NODE:
4213 case XML_ENTITY_REF_NODE:
4214 case XML_ENTITY_NODE:
4215 case XML_PI_NODE:
4216 case XML_COMMENT_NODE:
4217 case XML_NOTATION_NODE:
4218 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004219 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004220 }
4221 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4222 cur->children = cur->last = NULL;
4223 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004224 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004225 } else
4226 cur->content = NULL;
4227 break;
4228 case XML_DOCUMENT_NODE:
4229 case XML_DTD_NODE:
4230 case XML_HTML_DOCUMENT_NODE:
4231 case XML_DOCUMENT_TYPE_NODE:
4232 case XML_NAMESPACE_DECL:
4233 case XML_XINCLUDE_START:
4234 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004235#ifdef LIBXML_DOCB_ENABLED
4236 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004237#endif
4238 break;
4239 case XML_ELEMENT_DECL:
4240 /* TODO !!! */
4241 break;
4242 case XML_ATTRIBUTE_DECL:
4243 /* TODO !!! */
4244 break;
4245 case XML_ENTITY_DECL:
4246 /* TODO !!! */
4247 break;
4248 }
4249}
4250
4251/**
4252 * xmlNodeAddContentLen:
4253 * @cur: the node being modified
4254 * @content: extra content
4255 * @len: the size of @content
4256 *
4257 * Append the extra substring to the node content.
4258 */
4259void
4260xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4261 if (cur == NULL) {
4262#ifdef DEBUG_TREE
4263 xmlGenericError(xmlGenericErrorContext,
4264 "xmlNodeAddContentLen : node == NULL\n");
4265#endif
4266 return;
4267 }
4268 if (len <= 0) return;
4269 switch (cur->type) {
4270 case XML_DOCUMENT_FRAG_NODE:
4271 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004272 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004273
Daniel Veillard7db37732001-07-12 01:20:08 +00004274 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004275 newNode = xmlNewTextLen(content, len);
4276 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004277 tmp = xmlAddChild(cur, newNode);
4278 if (tmp != newNode)
4279 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004280 if ((last != NULL) && (last->next == newNode)) {
4281 xmlTextMerge(last, newNode);
4282 }
4283 }
4284 break;
4285 }
4286 case XML_ATTRIBUTE_NODE:
4287 break;
4288 case XML_TEXT_NODE:
4289 case XML_CDATA_SECTION_NODE:
4290 case XML_ENTITY_REF_NODE:
4291 case XML_ENTITY_NODE:
4292 case XML_PI_NODE:
4293 case XML_COMMENT_NODE:
4294 case XML_NOTATION_NODE:
4295 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004296 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004297 }
4298 case XML_DOCUMENT_NODE:
4299 case XML_DTD_NODE:
4300 case XML_HTML_DOCUMENT_NODE:
4301 case XML_DOCUMENT_TYPE_NODE:
4302 case XML_NAMESPACE_DECL:
4303 case XML_XINCLUDE_START:
4304 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004305#ifdef LIBXML_DOCB_ENABLED
4306 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004307#endif
4308 break;
4309 case XML_ELEMENT_DECL:
4310 case XML_ATTRIBUTE_DECL:
4311 case XML_ENTITY_DECL:
4312 break;
4313 }
4314}
4315
4316/**
4317 * xmlNodeAddContent:
4318 * @cur: the node being modified
4319 * @content: extra content
4320 *
4321 * Append the extra substring to the node content.
4322 */
4323void
4324xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4325 int len;
4326
4327 if (cur == NULL) {
4328#ifdef DEBUG_TREE
4329 xmlGenericError(xmlGenericErrorContext,
4330 "xmlNodeAddContent : node == NULL\n");
4331#endif
4332 return;
4333 }
4334 if (content == NULL) return;
4335 len = xmlStrlen(content);
4336 xmlNodeAddContentLen(cur, content, len);
4337}
4338
4339/**
4340 * xmlTextMerge:
4341 * @first: the first text node
4342 * @second: the second text node being merged
4343 *
4344 * Merge two text nodes into one
4345 * Returns the first text node augmented
4346 */
4347xmlNodePtr
4348xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4349 if (first == NULL) return(second);
4350 if (second == NULL) return(first);
4351 if (first->type != XML_TEXT_NODE) return(first);
4352 if (second->type != XML_TEXT_NODE) return(first);
4353 if (second->name != first->name)
4354 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004355 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004356 xmlUnlinkNode(second);
4357 xmlFreeNode(second);
4358 return(first);
4359}
4360
4361/**
4362 * xmlGetNsList:
4363 * @doc: the document
4364 * @node: the current node
4365 *
4366 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004367 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004368 * that need to be freed by the caller or NULL if no
4369 * namespace if defined
4370 */
4371xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004372xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4373{
Owen Taylor3473f882001-02-23 17:55:21 +00004374 xmlNsPtr cur;
4375 xmlNsPtr *ret = NULL;
4376 int nbns = 0;
4377 int maxns = 10;
4378 int i;
4379
4380 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004381 if (node->type == XML_ELEMENT_NODE) {
4382 cur = node->nsDef;
4383 while (cur != NULL) {
4384 if (ret == NULL) {
4385 ret =
4386 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4387 sizeof(xmlNsPtr));
4388 if (ret == NULL) {
4389 xmlGenericError(xmlGenericErrorContext,
4390 "xmlGetNsList : out of memory!\n");
4391 return (NULL);
4392 }
4393 ret[nbns] = NULL;
4394 }
4395 for (i = 0; i < nbns; i++) {
4396 if ((cur->prefix == ret[i]->prefix) ||
4397 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4398 break;
4399 }
4400 if (i >= nbns) {
4401 if (nbns >= maxns) {
4402 maxns *= 2;
4403 ret = (xmlNsPtr *) xmlRealloc(ret,
4404 (maxns +
4405 1) *
4406 sizeof(xmlNsPtr));
4407 if (ret == NULL) {
4408 xmlGenericError(xmlGenericErrorContext,
4409 "xmlGetNsList : realloc failed!\n");
4410 return (NULL);
4411 }
4412 }
4413 ret[nbns++] = cur;
4414 ret[nbns] = NULL;
4415 }
Owen Taylor3473f882001-02-23 17:55:21 +00004416
Daniel Veillard77044732001-06-29 21:31:07 +00004417 cur = cur->next;
4418 }
4419 }
4420 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004421 }
Daniel Veillard77044732001-06-29 21:31:07 +00004422 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004423}
4424
4425/**
4426 * xmlSearchNs:
4427 * @doc: the document
4428 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004429 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004430 *
4431 * Search a Ns registered under a given name space for a document.
4432 * recurse on the parents until it finds the defined namespace
4433 * or return NULL otherwise.
4434 * @nameSpace can be NULL, this is a search for the default namespace.
4435 * We don't allow to cross entities boundaries. If you don't declare
4436 * the namespace within those you will be in troubles !!! A warning
4437 * is generated to cover this case.
4438 *
4439 * Returns the namespace pointer or NULL.
4440 */
4441xmlNsPtr
4442xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4443 xmlNsPtr cur;
4444
4445 if (node == NULL) return(NULL);
4446 if ((nameSpace != NULL) &&
4447 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00004448 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4449 /*
4450 * The XML-1.0 namespace is normally held on the root
4451 * element. In this case exceptionally create it on the
4452 * node element.
4453 */
4454 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4455 if (cur == NULL) {
4456 xmlGenericError(xmlGenericErrorContext,
4457 "xmlSearchNs : malloc failed\n");
4458 return(NULL);
4459 }
4460 memset(cur, 0, sizeof(xmlNs));
4461 cur->type = XML_LOCAL_NAMESPACE;
4462 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4463 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4464 cur->next = node->nsDef;
4465 node->nsDef = cur;
4466 return(cur);
4467 }
Owen Taylor3473f882001-02-23 17:55:21 +00004468 if (doc->oldNs == NULL) {
4469 /*
4470 * Allocate a new Namespace and fill the fields.
4471 */
4472 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4473 if (doc->oldNs == NULL) {
4474 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004475 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004476 return(NULL);
4477 }
4478 memset(doc->oldNs, 0, sizeof(xmlNs));
4479 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4480
4481 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4482 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4483 }
4484 return(doc->oldNs);
4485 }
4486 while (node != NULL) {
4487 if ((node->type == XML_ENTITY_REF_NODE) ||
4488 (node->type == XML_ENTITY_NODE) ||
4489 (node->type == XML_ENTITY_DECL))
4490 return(NULL);
4491 if (node->type == XML_ELEMENT_NODE) {
4492 cur = node->nsDef;
4493 while (cur != NULL) {
4494 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4495 (cur->href != NULL))
4496 return(cur);
4497 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4498 (cur->href != NULL) &&
4499 (xmlStrEqual(cur->prefix, nameSpace)))
4500 return(cur);
4501 cur = cur->next;
4502 }
4503 }
4504 node = node->parent;
4505 }
4506 return(NULL);
4507}
4508
4509/**
4510 * xmlSearchNsByHref:
4511 * @doc: the document
4512 * @node: the current node
4513 * @href: the namespace value
4514 *
4515 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4516 * the defined namespace or return NULL otherwise.
4517 * Returns the namespace pointer or NULL.
4518 */
4519xmlNsPtr
4520xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4521 xmlNsPtr cur;
4522 xmlNodePtr orig = node;
4523
4524 if ((node == NULL) || (href == NULL)) return(NULL);
4525 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004526 /*
4527 * Only the document can hold the XML spec namespace.
4528 */
Daniel Veillardc1a0da32002-08-14 08:32:18 +00004529 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4530 /*
4531 * The XML-1.0 namespace is normally held on the root
4532 * element. In this case exceptionally create it on the
4533 * node element.
4534 */
4535 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4536 if (cur == NULL) {
4537 xmlGenericError(xmlGenericErrorContext,
4538 "xmlSearchNs : malloc failed\n");
4539 return(NULL);
4540 }
4541 memset(cur, 0, sizeof(xmlNs));
4542 cur->type = XML_LOCAL_NAMESPACE;
4543 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4544 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4545 cur->next = node->nsDef;
4546 node->nsDef = cur;
4547 return(cur);
4548 }
Owen Taylor3473f882001-02-23 17:55:21 +00004549 if (doc->oldNs == NULL) {
4550 /*
4551 * Allocate a new Namespace and fill the fields.
4552 */
4553 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4554 if (doc->oldNs == NULL) {
4555 xmlGenericError(xmlGenericErrorContext,
4556 "xmlSearchNsByHref : malloc failed\n");
4557 return(NULL);
4558 }
4559 memset(doc->oldNs, 0, sizeof(xmlNs));
4560 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4561
4562 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4563 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4564 }
4565 return(doc->oldNs);
4566 }
4567 while (node != NULL) {
4568 cur = node->nsDef;
4569 while (cur != NULL) {
4570 if ((cur->href != NULL) && (href != NULL) &&
4571 (xmlStrEqual(cur->href, href))) {
4572 /*
4573 * Check that the prefix is not shadowed between orig and node
4574 */
4575 xmlNodePtr check = orig;
4576 xmlNsPtr tst;
4577
4578 while (check != node) {
4579 tst = check->nsDef;
4580 while (tst != NULL) {
4581 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4582 goto shadowed;
4583 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4584 (xmlStrEqual(tst->prefix, cur->prefix)))
4585 goto shadowed;
4586 tst = tst->next;
4587 }
4588 check = check->parent;
4589 }
4590 return(cur);
4591 }
4592shadowed:
4593 cur = cur->next;
4594 }
4595 node = node->parent;
4596 }
4597 return(NULL);
4598}
4599
4600/**
4601 * xmlNewReconciliedNs
4602 * @doc: the document
4603 * @tree: a node expected to hold the new namespace
4604 * @ns: the original namespace
4605 *
4606 * This function tries to locate a namespace definition in a tree
4607 * ancestors, or create a new namespace definition node similar to
4608 * @ns trying to reuse the same prefix. However if the given prefix is
4609 * null (default namespace) or reused within the subtree defined by
4610 * @tree or on one of its ancestors then a new prefix is generated.
4611 * Returns the (new) namespace definition or NULL in case of error
4612 */
4613xmlNsPtr
4614xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4615 xmlNsPtr def;
4616 xmlChar prefix[50];
4617 int counter = 1;
4618
4619 if (tree == NULL) {
4620#ifdef DEBUG_TREE
4621 xmlGenericError(xmlGenericErrorContext,
4622 "xmlNewReconciliedNs : tree == NULL\n");
4623#endif
4624 return(NULL);
4625 }
4626 if (ns == NULL) {
4627#ifdef DEBUG_TREE
4628 xmlGenericError(xmlGenericErrorContext,
4629 "xmlNewReconciliedNs : ns == NULL\n");
4630#endif
4631 return(NULL);
4632 }
4633 /*
4634 * Search an existing namespace definition inherited.
4635 */
4636 def = xmlSearchNsByHref(doc, tree, ns->href);
4637 if (def != NULL)
4638 return(def);
4639
4640 /*
4641 * Find a close prefix which is not already in use.
4642 * Let's strip namespace prefixes longer than 20 chars !
4643 */
Daniel Veillardf742d342002-03-07 00:05:35 +00004644 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004645 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00004646 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004647 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00004648
Owen Taylor3473f882001-02-23 17:55:21 +00004649 def = xmlSearchNs(doc, tree, prefix);
4650 while (def != NULL) {
4651 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00004652 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004653 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00004654 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004655 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00004656 def = xmlSearchNs(doc, tree, prefix);
4657 }
4658
4659 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004660 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004661 */
4662 def = xmlNewNs(tree, ns->href, prefix);
4663 return(def);
4664}
4665
4666/**
4667 * xmlReconciliateNs
4668 * @doc: the document
4669 * @tree: a node defining the subtree to reconciliate
4670 *
4671 * This function checks that all the namespaces declared within the given
4672 * tree are properly declared. This is needed for example after Copy or Cut
4673 * and then paste operations. The subtree may still hold pointers to
4674 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004675 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004676 * the new environment. If not possible the new namespaces are redeclared
4677 * on @tree at the top of the given subtree.
4678 * Returns the number of namespace declarations created or -1 in case of error.
4679 */
4680int
4681xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4682 xmlNsPtr *oldNs = NULL;
4683 xmlNsPtr *newNs = NULL;
4684 int sizeCache = 0;
4685 int nbCache = 0;
4686
4687 xmlNsPtr n;
4688 xmlNodePtr node = tree;
4689 xmlAttrPtr attr;
4690 int ret = 0, i;
4691
4692 while (node != NULL) {
4693 /*
4694 * Reconciliate the node namespace
4695 */
4696 if (node->ns != NULL) {
4697 /*
4698 * initialize the cache if needed
4699 */
4700 if (sizeCache == 0) {
4701 sizeCache = 10;
4702 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4703 sizeof(xmlNsPtr));
4704 if (oldNs == NULL) {
4705 xmlGenericError(xmlGenericErrorContext,
4706 "xmlReconciliateNs : memory pbm\n");
4707 return(-1);
4708 }
4709 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4710 sizeof(xmlNsPtr));
4711 if (newNs == NULL) {
4712 xmlGenericError(xmlGenericErrorContext,
4713 "xmlReconciliateNs : memory pbm\n");
4714 xmlFree(oldNs);
4715 return(-1);
4716 }
4717 }
4718 for (i = 0;i < nbCache;i++) {
4719 if (oldNs[i] == node->ns) {
4720 node->ns = newNs[i];
4721 break;
4722 }
4723 }
4724 if (i == nbCache) {
4725 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004726 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004727 */
4728 n = xmlNewReconciliedNs(doc, tree, node->ns);
4729 if (n != NULL) { /* :-( what if else ??? */
4730 /*
4731 * check if we need to grow the cache buffers.
4732 */
4733 if (sizeCache <= nbCache) {
4734 sizeCache *= 2;
4735 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4736 sizeof(xmlNsPtr));
4737 if (oldNs == NULL) {
4738 xmlGenericError(xmlGenericErrorContext,
4739 "xmlReconciliateNs : memory pbm\n");
4740 xmlFree(newNs);
4741 return(-1);
4742 }
4743 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4744 sizeof(xmlNsPtr));
4745 if (newNs == NULL) {
4746 xmlGenericError(xmlGenericErrorContext,
4747 "xmlReconciliateNs : memory pbm\n");
4748 xmlFree(oldNs);
4749 return(-1);
4750 }
4751 }
4752 newNs[nbCache] = n;
4753 oldNs[nbCache++] = node->ns;
4754 node->ns = n;
4755 }
4756 }
4757 }
4758 /*
4759 * now check for namespace hold by attributes on the node.
4760 */
4761 attr = node->properties;
4762 while (attr != NULL) {
4763 if (attr->ns != NULL) {
4764 /*
4765 * initialize the cache if needed
4766 */
4767 if (sizeCache == 0) {
4768 sizeCache = 10;
4769 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4770 sizeof(xmlNsPtr));
4771 if (oldNs == NULL) {
4772 xmlGenericError(xmlGenericErrorContext,
4773 "xmlReconciliateNs : memory pbm\n");
4774 return(-1);
4775 }
4776 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4777 sizeof(xmlNsPtr));
4778 if (newNs == NULL) {
4779 xmlGenericError(xmlGenericErrorContext,
4780 "xmlReconciliateNs : memory pbm\n");
4781 xmlFree(oldNs);
4782 return(-1);
4783 }
4784 }
4785 for (i = 0;i < nbCache;i++) {
4786 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00004787 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00004788 break;
4789 }
4790 }
4791 if (i == nbCache) {
4792 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004793 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004794 */
4795 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4796 if (n != NULL) { /* :-( what if else ??? */
4797 /*
4798 * check if we need to grow the cache buffers.
4799 */
4800 if (sizeCache <= nbCache) {
4801 sizeCache *= 2;
4802 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4803 sizeof(xmlNsPtr));
4804 if (oldNs == NULL) {
4805 xmlGenericError(xmlGenericErrorContext,
4806 "xmlReconciliateNs : memory pbm\n");
4807 xmlFree(newNs);
4808 return(-1);
4809 }
4810 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4811 sizeof(xmlNsPtr));
4812 if (newNs == NULL) {
4813 xmlGenericError(xmlGenericErrorContext,
4814 "xmlReconciliateNs : memory pbm\n");
4815 xmlFree(oldNs);
4816 return(-1);
4817 }
4818 }
4819 newNs[nbCache] = n;
4820 oldNs[nbCache++] = attr->ns;
4821 attr->ns = n;
4822 }
4823 }
4824 }
4825 attr = attr->next;
4826 }
4827
4828 /*
4829 * Browse the full subtree, deep first
4830 */
4831 if (node->children != NULL) {
4832 /* deep first */
4833 node = node->children;
4834 } else if ((node != tree) && (node->next != NULL)) {
4835 /* then siblings */
4836 node = node->next;
4837 } else if (node != tree) {
4838 /* go up to parents->next if needed */
4839 while (node != tree) {
4840 if (node->parent != NULL)
4841 node = node->parent;
4842 if ((node != tree) && (node->next != NULL)) {
4843 node = node->next;
4844 break;
4845 }
4846 if (node->parent == NULL) {
4847 node = NULL;
4848 break;
4849 }
4850 }
4851 /* exit condition */
4852 if (node == tree)
4853 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00004854 } else
4855 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004856 }
Daniel Veillardf742d342002-03-07 00:05:35 +00004857 if (oldNs != NULL)
4858 xmlFree(oldNs);
4859 if (newNs != NULL)
4860 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00004861 return(ret);
4862}
4863
4864/**
4865 * xmlHasProp:
4866 * @node: the node
4867 * @name: the attribute name
4868 *
4869 * Search an attribute associated to a node
4870 * This function also looks in DTD attribute declaration for #FIXED or
4871 * default declaration values unless DTD use has been turned off.
4872 *
4873 * Returns the attribute or the attribute declaration or NULL if
4874 * neither was found.
4875 */
4876xmlAttrPtr
4877xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4878 xmlAttrPtr prop;
4879 xmlDocPtr doc;
4880
4881 if ((node == NULL) || (name == NULL)) return(NULL);
4882 /*
4883 * Check on the properties attached to the node
4884 */
4885 prop = node->properties;
4886 while (prop != NULL) {
4887 if (xmlStrEqual(prop->name, name)) {
4888 return(prop);
4889 }
4890 prop = prop->next;
4891 }
4892 if (!xmlCheckDTD) return(NULL);
4893
4894 /*
4895 * Check if there is a default declaration in the internal
4896 * or external subsets
4897 */
4898 doc = node->doc;
4899 if (doc != NULL) {
4900 xmlAttributePtr attrDecl;
4901 if (doc->intSubset != NULL) {
4902 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4903 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4904 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4905 if (attrDecl != NULL)
4906 return((xmlAttrPtr) attrDecl);
4907 }
4908 }
4909 return(NULL);
4910}
4911
4912/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004913 * xmlHasNsProp:
4914 * @node: the node
4915 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004916 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004917 *
4918 * Search for an attribute associated to a node
4919 * This attribute has to be anchored in the namespace specified.
4920 * This does the entity substitution.
4921 * This function looks in DTD attribute declaration for #FIXED or
4922 * default declaration values unless DTD use has been turned off.
4923 *
4924 * Returns the attribute or the attribute declaration or NULL
4925 * if neither was found.
4926 */
4927xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004928xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004929 xmlAttrPtr prop;
4930 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004931
4932 if (node == NULL)
4933 return(NULL);
4934
4935 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004936 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004937 return(xmlHasProp(node, name));
4938 while (prop != NULL) {
4939 /*
4940 * One need to have
4941 * - same attribute names
4942 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004943 */
4944 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004945 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4946 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004947 }
4948 prop = prop->next;
4949 }
4950 if (!xmlCheckDTD) return(NULL);
4951
4952 /*
4953 * Check if there is a default declaration in the internal
4954 * or external subsets
4955 */
4956 doc = node->doc;
4957 if (doc != NULL) {
4958 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004959 xmlAttributePtr attrDecl = NULL;
4960 xmlNsPtr *nsList, *cur;
4961 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004962
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004963 nsList = xmlGetNsList(node->doc, node);
4964 if (nsList == NULL)
4965 return(NULL);
4966 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
4967 ename = xmlStrdup(node->ns->prefix);
4968 ename = xmlStrcat(ename, BAD_CAST ":");
4969 ename = xmlStrcat(ename, node->name);
4970 } else {
4971 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004972 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004973 if (ename == NULL) {
4974 xmlFree(nsList);
4975 return(NULL);
4976 }
4977
4978 cur = nsList;
4979 while (*cur != NULL) {
4980 if (xmlStrEqual((*cur)->href, nameSpace)) {
4981 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
4982 name, (*cur)->prefix);
4983 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4984 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
4985 name, (*cur)->prefix);
4986 }
4987 cur++;
4988 }
4989 xmlFree(nsList);
4990 xmlFree(ename);
4991 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004992 }
4993 }
4994 return(NULL);
4995}
4996
4997/**
Owen Taylor3473f882001-02-23 17:55:21 +00004998 * xmlGetProp:
4999 * @node: the node
5000 * @name: the attribute name
5001 *
5002 * Search and get the value of an attribute associated to a node
5003 * This does the entity substitution.
5004 * This function looks in DTD attribute declaration for #FIXED or
5005 * default declaration values unless DTD use has been turned off.
5006 *
5007 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005008 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005009 */
5010xmlChar *
5011xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5012 xmlAttrPtr prop;
5013 xmlDocPtr doc;
5014
5015 if ((node == NULL) || (name == NULL)) return(NULL);
5016 /*
5017 * Check on the properties attached to the node
5018 */
5019 prop = node->properties;
5020 while (prop != NULL) {
5021 if (xmlStrEqual(prop->name, name)) {
5022 xmlChar *ret;
5023
5024 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5025 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5026 return(ret);
5027 }
5028 prop = prop->next;
5029 }
5030 if (!xmlCheckDTD) return(NULL);
5031
5032 /*
5033 * Check if there is a default declaration in the internal
5034 * or external subsets
5035 */
5036 doc = node->doc;
5037 if (doc != NULL) {
5038 xmlAttributePtr attrDecl;
5039 if (doc->intSubset != NULL) {
5040 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5041 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5042 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5043 if (attrDecl != NULL)
5044 return(xmlStrdup(attrDecl->defaultValue));
5045 }
5046 }
5047 return(NULL);
5048}
5049
5050/**
5051 * xmlGetNsProp:
5052 * @node: the node
5053 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005054 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005055 *
5056 * Search and get the value of an attribute associated to a node
5057 * This attribute has to be anchored in the namespace specified.
5058 * This does the entity substitution.
5059 * This function looks in DTD attribute declaration for #FIXED or
5060 * default declaration values unless DTD use has been turned off.
5061 *
5062 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005063 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005064 */
5065xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005066xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005067 xmlAttrPtr prop;
5068 xmlDocPtr doc;
5069 xmlNsPtr ns;
5070
5071 if (node == NULL)
5072 return(NULL);
5073
5074 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005075 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005076 return(xmlGetProp(node, name));
5077 while (prop != NULL) {
5078 /*
5079 * One need to have
5080 * - same attribute names
5081 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005082 */
5083 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005084 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005085 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005086 xmlChar *ret;
5087
5088 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5089 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5090 return(ret);
5091 }
5092 prop = prop->next;
5093 }
5094 if (!xmlCheckDTD) return(NULL);
5095
5096 /*
5097 * Check if there is a default declaration in the internal
5098 * or external subsets
5099 */
5100 doc = node->doc;
5101 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005102 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005103 xmlAttributePtr attrDecl;
5104
Owen Taylor3473f882001-02-23 17:55:21 +00005105 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5106 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5107 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5108
5109 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5110 /*
5111 * The DTD declaration only allows a prefix search
5112 */
5113 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005114 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005115 return(xmlStrdup(attrDecl->defaultValue));
5116 }
5117 }
5118 }
5119 return(NULL);
5120}
5121
5122/**
5123 * xmlSetProp:
5124 * @node: the node
5125 * @name: the attribute name
5126 * @value: the attribute value
5127 *
5128 * Set (or reset) an attribute carried by a node.
5129 * Returns the attribute pointer.
5130 */
5131xmlAttrPtr
5132xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005133 xmlAttrPtr prop;
5134 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005135
5136 if ((node == NULL) || (name == NULL))
5137 return(NULL);
5138 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005139 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005140 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005141 if ((xmlStrEqual(prop->name, name)) &&
5142 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005143 xmlNodePtr oldprop = prop->children;
5144
Owen Taylor3473f882001-02-23 17:55:21 +00005145 prop->children = NULL;
5146 prop->last = NULL;
5147 if (value != NULL) {
5148 xmlChar *buffer;
5149 xmlNodePtr tmp;
5150
5151 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5152 prop->children = xmlStringGetNodeList(node->doc, buffer);
5153 prop->last = NULL;
5154 prop->doc = doc;
5155 tmp = prop->children;
5156 while (tmp != NULL) {
5157 tmp->parent = (xmlNodePtr) prop;
5158 tmp->doc = doc;
5159 if (tmp->next == NULL)
5160 prop->last = tmp;
5161 tmp = tmp->next;
5162 }
5163 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005164 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005165 if (oldprop != NULL)
5166 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005167 return(prop);
5168 }
5169 prop = prop->next;
5170 }
5171 prop = xmlNewProp(node, name, value);
5172 return(prop);
5173}
5174
5175/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005176 * xmlUnsetProp:
5177 * @node: the node
5178 * @name: the attribute name
5179 *
5180 * Remove an attribute carried by a node.
5181 * Returns 0 if successful, -1 if not found
5182 */
5183int
5184xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
5185 xmlAttrPtr prop = node->properties, prev = NULL;;
5186
5187 if ((node == NULL) || (name == NULL))
5188 return(-1);
5189 while (prop != NULL) {
5190 if ((xmlStrEqual(prop->name, name)) &&
5191 (prop->ns == NULL)) {
5192 if (prev == NULL)
5193 node->properties = prop->next;
5194 else
5195 prev->next = prop->next;
5196 xmlFreeProp(prop);
5197 return(0);
5198 }
5199 prev = prop;
5200 prop = prop->next;
5201 }
5202 return(-1);
5203}
5204
5205/**
Owen Taylor3473f882001-02-23 17:55:21 +00005206 * xmlSetNsProp:
5207 * @node: the node
5208 * @ns: the namespace definition
5209 * @name: the attribute name
5210 * @value: the attribute value
5211 *
5212 * Set (or reset) an attribute carried by a node.
5213 * The ns structure must be in scope, this is not checked.
5214 *
5215 * Returns the attribute pointer.
5216 */
5217xmlAttrPtr
5218xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5219 const xmlChar *value) {
5220 xmlAttrPtr prop;
5221
5222 if ((node == NULL) || (name == NULL))
5223 return(NULL);
5224
5225 if (ns == NULL)
5226 return(xmlSetProp(node, name, value));
5227 if (ns->href == NULL)
5228 return(NULL);
5229 prop = node->properties;
5230
5231 while (prop != NULL) {
5232 /*
5233 * One need to have
5234 * - same attribute names
5235 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005236 */
5237 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00005238 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005239 if (prop->children != NULL)
5240 xmlFreeNodeList(prop->children);
5241 prop->children = NULL;
5242 prop->last = NULL;
5243 prop->ns = ns;
5244 if (value != NULL) {
5245 xmlChar *buffer;
5246 xmlNodePtr tmp;
5247
5248 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5249 prop->children = xmlStringGetNodeList(node->doc, buffer);
5250 prop->last = NULL;
5251 tmp = prop->children;
5252 while (tmp != NULL) {
5253 tmp->parent = (xmlNodePtr) prop;
5254 if (tmp->next == NULL)
5255 prop->last = tmp;
5256 tmp = tmp->next;
5257 }
5258 xmlFree(buffer);
5259 }
5260 return(prop);
5261 }
5262 prop = prop->next;
5263 }
5264 prop = xmlNewNsProp(node, ns, name, value);
5265 return(prop);
5266}
5267
5268/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005269 * xmlUnsetNsProp:
5270 * @node: the node
5271 * @ns: the namespace definition
5272 * @name: the attribute name
5273 *
5274 * Remove an attribute carried by a node.
5275 * Returns 0 if successful, -1 if not found
5276 */
5277int
5278xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5279 xmlAttrPtr prop = node->properties, prev = NULL;;
5280
5281 if ((node == NULL) || (name == NULL))
5282 return(-1);
5283 if (ns == NULL)
5284 return(xmlUnsetProp(node, name));
5285 if (ns->href == NULL)
5286 return(-1);
5287 while (prop != NULL) {
5288 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00005289 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005290 if (prev == NULL)
5291 node->properties = prop->next;
5292 else
5293 prev->next = prop->next;
5294 xmlFreeProp(prop);
5295 return(0);
5296 }
5297 prev = prop;
5298 prop = prop->next;
5299 }
5300 return(-1);
5301}
5302
5303/**
Owen Taylor3473f882001-02-23 17:55:21 +00005304 * xmlNodeIsText:
5305 * @node: the node
5306 *
5307 * Is this node a Text node ?
5308 * Returns 1 yes, 0 no
5309 */
5310int
5311xmlNodeIsText(xmlNodePtr node) {
5312 if (node == NULL) return(0);
5313
5314 if (node->type == XML_TEXT_NODE) return(1);
5315 return(0);
5316}
5317
5318/**
5319 * xmlIsBlankNode:
5320 * @node: the node
5321 *
5322 * Checks whether this node is an empty or whitespace only
5323 * (and possibly ignorable) text-node.
5324 *
5325 * Returns 1 yes, 0 no
5326 */
5327int
5328xmlIsBlankNode(xmlNodePtr node) {
5329 const xmlChar *cur;
5330 if (node == NULL) return(0);
5331
Daniel Veillard7db37732001-07-12 01:20:08 +00005332 if ((node->type != XML_TEXT_NODE) &&
5333 (node->type != XML_CDATA_SECTION_NODE))
5334 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005335 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005336 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005337 while (*cur != 0) {
5338 if (!IS_BLANK(*cur)) return(0);
5339 cur++;
5340 }
5341
5342 return(1);
5343}
5344
5345/**
5346 * xmlTextConcat:
5347 * @node: the node
5348 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005349 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005350 *
5351 * Concat the given string at the end of the existing node content
5352 */
5353
5354void
5355xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5356 if (node == NULL) return;
5357
5358 if ((node->type != XML_TEXT_NODE) &&
5359 (node->type != XML_CDATA_SECTION_NODE)) {
5360#ifdef DEBUG_TREE
5361 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005362 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005363#endif
5364 return;
5365 }
Owen Taylor3473f882001-02-23 17:55:21 +00005366 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005367}
5368
5369/************************************************************************
5370 * *
5371 * Output : to a FILE or in memory *
5372 * *
5373 ************************************************************************/
5374
Owen Taylor3473f882001-02-23 17:55:21 +00005375/**
5376 * xmlBufferCreate:
5377 *
5378 * routine to create an XML buffer.
5379 * returns the new structure.
5380 */
5381xmlBufferPtr
5382xmlBufferCreate(void) {
5383 xmlBufferPtr ret;
5384
5385 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5386 if (ret == NULL) {
5387 xmlGenericError(xmlGenericErrorContext,
5388 "xmlBufferCreate : out of memory!\n");
5389 return(NULL);
5390 }
5391 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005392 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005393 ret->alloc = xmlBufferAllocScheme;
5394 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5395 if (ret->content == NULL) {
5396 xmlGenericError(xmlGenericErrorContext,
5397 "xmlBufferCreate : out of memory!\n");
5398 xmlFree(ret);
5399 return(NULL);
5400 }
5401 ret->content[0] = 0;
5402 return(ret);
5403}
5404
5405/**
5406 * xmlBufferCreateSize:
5407 * @size: initial size of buffer
5408 *
5409 * routine to create an XML buffer.
5410 * returns the new structure.
5411 */
5412xmlBufferPtr
5413xmlBufferCreateSize(size_t size) {
5414 xmlBufferPtr ret;
5415
5416 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5417 if (ret == NULL) {
5418 xmlGenericError(xmlGenericErrorContext,
5419 "xmlBufferCreate : out of memory!\n");
5420 return(NULL);
5421 }
5422 ret->use = 0;
5423 ret->alloc = xmlBufferAllocScheme;
5424 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5425 if (ret->size){
5426 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5427 if (ret->content == NULL) {
5428 xmlGenericError(xmlGenericErrorContext,
5429 "xmlBufferCreate : out of memory!\n");
5430 xmlFree(ret);
5431 return(NULL);
5432 }
5433 ret->content[0] = 0;
5434 } else
5435 ret->content = NULL;
5436 return(ret);
5437}
5438
5439/**
5440 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005441 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00005442 * @scheme: allocation scheme to use
5443 *
5444 * Sets the allocation scheme for this buffer
5445 */
5446void
5447xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5448 xmlBufferAllocationScheme scheme) {
5449 if (buf == NULL) {
5450#ifdef DEBUG_BUFFER
5451 xmlGenericError(xmlGenericErrorContext,
5452 "xmlBufferSetAllocationScheme: buf == NULL\n");
5453#endif
5454 return;
5455 }
5456
5457 buf->alloc = scheme;
5458}
5459
5460/**
5461 * xmlBufferFree:
5462 * @buf: the buffer to free
5463 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005464 * Frees an XML buffer. It frees both the content and the structure which
5465 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005466 */
5467void
5468xmlBufferFree(xmlBufferPtr buf) {
5469 if (buf == NULL) {
5470#ifdef DEBUG_BUFFER
5471 xmlGenericError(xmlGenericErrorContext,
5472 "xmlBufferFree: buf == NULL\n");
5473#endif
5474 return;
5475 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00005476 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005477 xmlFree(buf->content);
5478 }
Owen Taylor3473f882001-02-23 17:55:21 +00005479 xmlFree(buf);
5480}
5481
5482/**
5483 * xmlBufferEmpty:
5484 * @buf: the buffer
5485 *
5486 * empty a buffer.
5487 */
5488void
5489xmlBufferEmpty(xmlBufferPtr buf) {
5490 if (buf->content == NULL) return;
5491 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005492 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005493}
5494
5495/**
5496 * xmlBufferShrink:
5497 * @buf: the buffer to dump
5498 * @len: the number of xmlChar to remove
5499 *
5500 * Remove the beginning of an XML buffer.
5501 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005502 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005503 */
5504int
5505xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5506 if (len == 0) return(0);
5507 if (len > buf->use) return(-1);
5508
5509 buf->use -= len;
5510 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5511
5512 buf->content[buf->use] = 0;
5513 return(len);
5514}
5515
5516/**
5517 * xmlBufferGrow:
5518 * @buf: the buffer
5519 * @len: the minimum free size to allocate
5520 *
5521 * Grow the available space of an XML buffer.
5522 *
5523 * Returns the new available space or -1 in case of error
5524 */
5525int
5526xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5527 int size;
5528 xmlChar *newbuf;
5529
5530 if (len + buf->use < buf->size) return(0);
5531
5532 size = buf->use + len + 100;
5533
5534 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5535 if (newbuf == NULL) return(-1);
5536 buf->content = newbuf;
5537 buf->size = size;
5538 return(buf->size - buf->use);
5539}
5540
5541/**
5542 * xmlBufferDump:
5543 * @file: the file output
5544 * @buf: the buffer to dump
5545 *
5546 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005547 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005548 */
5549int
5550xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5551 int ret;
5552
5553 if (buf == NULL) {
5554#ifdef DEBUG_BUFFER
5555 xmlGenericError(xmlGenericErrorContext,
5556 "xmlBufferDump: buf == NULL\n");
5557#endif
5558 return(0);
5559 }
5560 if (buf->content == NULL) {
5561#ifdef DEBUG_BUFFER
5562 xmlGenericError(xmlGenericErrorContext,
5563 "xmlBufferDump: buf->content == NULL\n");
5564#endif
5565 return(0);
5566 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005567 if (file == NULL)
5568 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005569 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5570 return(ret);
5571}
5572
5573/**
5574 * xmlBufferContent:
5575 * @buf: the buffer
5576 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005577 * Function to extract the content of a buffer
5578 *
Owen Taylor3473f882001-02-23 17:55:21 +00005579 * Returns the internal content
5580 */
5581
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005582const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005583xmlBufferContent(const xmlBufferPtr buf)
5584{
5585 if(!buf)
5586 return NULL;
5587
5588 return buf->content;
5589}
5590
5591/**
5592 * xmlBufferLength:
5593 * @buf: the buffer
5594 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005595 * Function to get the length of a buffer
5596 *
Owen Taylor3473f882001-02-23 17:55:21 +00005597 * Returns the length of data in the internal content
5598 */
5599
5600int
5601xmlBufferLength(const xmlBufferPtr buf)
5602{
5603 if(!buf)
5604 return 0;
5605
5606 return buf->use;
5607}
5608
5609/**
5610 * xmlBufferResize:
5611 * @buf: the buffer to resize
5612 * @size: the desired size
5613 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005614 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005615 *
5616 * Returns 0 in case of problems, 1 otherwise
5617 */
5618int
5619xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5620{
5621 unsigned int newSize;
5622 xmlChar* rebuf = NULL;
5623
5624 /*take care of empty case*/
5625 newSize = (buf->size ? buf->size*2 : size);
5626
5627 /* Don't resize if we don't have to */
5628 if (size < buf->size)
5629 return 1;
5630
5631 /* figure out new size */
5632 switch (buf->alloc){
5633 case XML_BUFFER_ALLOC_DOUBLEIT:
5634 while (size > newSize) newSize *= 2;
5635 break;
5636 case XML_BUFFER_ALLOC_EXACT:
5637 newSize = size+10;
5638 break;
5639 default:
5640 newSize = size+10;
5641 break;
5642 }
5643
5644 if (buf->content == NULL)
5645 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5646 else
5647 rebuf = (xmlChar *) xmlRealloc(buf->content,
5648 newSize * sizeof(xmlChar));
5649 if (rebuf == NULL) {
5650 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005651 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005652 return 0;
5653 }
5654 buf->content = rebuf;
5655 buf->size = newSize;
5656
5657 return 1;
5658}
5659
5660/**
5661 * xmlBufferAdd:
5662 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005663 * @str: the #xmlChar string
5664 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005665 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005666 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005667 * str is recomputed.
5668 */
5669void
5670xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5671 unsigned int needSize;
5672
5673 if (str == NULL) {
5674#ifdef DEBUG_BUFFER
5675 xmlGenericError(xmlGenericErrorContext,
5676 "xmlBufferAdd: str == NULL\n");
5677#endif
5678 return;
5679 }
5680 if (len < -1) {
5681#ifdef DEBUG_BUFFER
5682 xmlGenericError(xmlGenericErrorContext,
5683 "xmlBufferAdd: len < 0\n");
5684#endif
5685 return;
5686 }
5687 if (len == 0) return;
5688
5689 if (len < 0)
5690 len = xmlStrlen(str);
5691
5692 if (len <= 0) return;
5693
5694 needSize = buf->use + len + 2;
5695 if (needSize > buf->size){
5696 if (!xmlBufferResize(buf, needSize)){
5697 xmlGenericError(xmlGenericErrorContext,
5698 "xmlBufferAdd : out of memory!\n");
5699 return;
5700 }
5701 }
5702
5703 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5704 buf->use += len;
5705 buf->content[buf->use] = 0;
5706}
5707
5708/**
5709 * xmlBufferAddHead:
5710 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005711 * @str: the #xmlChar string
5712 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005713 *
5714 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005715 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005716 */
5717void
5718xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5719 unsigned int needSize;
5720
5721 if (str == NULL) {
5722#ifdef DEBUG_BUFFER
5723 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005724 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005725#endif
5726 return;
5727 }
5728 if (len < -1) {
5729#ifdef DEBUG_BUFFER
5730 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005731 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005732#endif
5733 return;
5734 }
5735 if (len == 0) return;
5736
5737 if (len < 0)
5738 len = xmlStrlen(str);
5739
5740 if (len <= 0) return;
5741
5742 needSize = buf->use + len + 2;
5743 if (needSize > buf->size){
5744 if (!xmlBufferResize(buf, needSize)){
5745 xmlGenericError(xmlGenericErrorContext,
5746 "xmlBufferAddHead : out of memory!\n");
5747 return;
5748 }
5749 }
5750
5751 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5752 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5753 buf->use += len;
5754 buf->content[buf->use] = 0;
5755}
5756
5757/**
5758 * xmlBufferCat:
5759 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005760 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005761 *
5762 * Append a zero terminated string to an XML buffer.
5763 */
5764void
5765xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5766 if (str != NULL)
5767 xmlBufferAdd(buf, str, -1);
5768}
5769
5770/**
5771 * xmlBufferCCat:
5772 * @buf: the buffer to dump
5773 * @str: the C char string
5774 *
5775 * Append a zero terminated C string to an XML buffer.
5776 */
5777void
5778xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5779 const char *cur;
5780
5781 if (str == NULL) {
5782#ifdef DEBUG_BUFFER
5783 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005784 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005785#endif
5786 return;
5787 }
5788 for (cur = str;*cur != 0;cur++) {
5789 if (buf->use + 10 >= buf->size) {
5790 if (!xmlBufferResize(buf, buf->use+10)){
5791 xmlGenericError(xmlGenericErrorContext,
5792 "xmlBufferCCat : out of memory!\n");
5793 return;
5794 }
5795 }
5796 buf->content[buf->use++] = *cur;
5797 }
5798 buf->content[buf->use] = 0;
5799}
5800
5801/**
5802 * xmlBufferWriteCHAR:
5803 * @buf: the XML buffer
5804 * @string: the string to add
5805 *
5806 * routine which manages and grows an output buffer. This one adds
5807 * xmlChars at the end of the buffer.
5808 */
5809void
Owen Taylor3473f882001-02-23 17:55:21 +00005810xmlBufferWriteCHAR
Owen Taylor3473f882001-02-23 17:55:21 +00005811(xmlBufferPtr buf, const xmlChar *string) {
5812 xmlBufferCat(buf, string);
5813}
5814
5815/**
5816 * xmlBufferWriteChar:
5817 * @buf: the XML buffer output
5818 * @string: the string to add
5819 *
5820 * routine which manage and grows an output buffer. This one add
5821 * C chars at the end of the array.
5822 */
5823void
5824xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5825 xmlBufferCCat(buf, string);
5826}
5827
5828
5829/**
5830 * xmlBufferWriteQuotedString:
5831 * @buf: the XML buffer output
5832 * @string: the string to add
5833 *
5834 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005835 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005836 * quote or double-quotes internally
5837 */
5838void
5839xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5840 if (xmlStrchr(string, '"')) {
5841 if (xmlStrchr(string, '\'')) {
5842#ifdef DEBUG_BUFFER
5843 xmlGenericError(xmlGenericErrorContext,
5844 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5845#endif
5846 }
5847 xmlBufferCCat(buf, "'");
5848 xmlBufferCat(buf, string);
5849 xmlBufferCCat(buf, "'");
5850 } else {
5851 xmlBufferCCat(buf, "\"");
5852 xmlBufferCat(buf, string);
5853 xmlBufferCCat(buf, "\"");
5854 }
5855}
5856
5857
5858/************************************************************************
5859 * *
5860 * Dumping XML tree content to a simple buffer *
5861 * *
5862 ************************************************************************/
5863
Owen Taylor3473f882001-02-23 17:55:21 +00005864static void
5865xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5866 int format);
5867void
5868htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5869
5870/**
5871 * xmlNsDump:
5872 * @buf: the XML buffer output
5873 * @cur: a namespace
5874 *
5875 * Dump a local Namespace definition.
5876 * Should be called in the context of attributes dumps.
5877 */
5878static void
5879xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5880 if (cur == NULL) {
5881#ifdef DEBUG_TREE
5882 xmlGenericError(xmlGenericErrorContext,
5883 "xmlNsDump : Ns == NULL\n");
5884#endif
5885 return;
5886 }
5887 if (cur->type == XML_LOCAL_NAMESPACE) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005888 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
5889 return;
5890
Owen Taylor3473f882001-02-23 17:55:21 +00005891 /* Within the context of an element attributes */
5892 if (cur->prefix != NULL) {
5893 xmlBufferWriteChar(buf, " xmlns:");
5894 xmlBufferWriteCHAR(buf, cur->prefix);
5895 } else
5896 xmlBufferWriteChar(buf, " xmlns");
5897 xmlBufferWriteChar(buf, "=");
5898 xmlBufferWriteQuotedString(buf, cur->href);
5899 }
5900}
5901
5902/**
5903 * xmlNsListDump:
5904 * @buf: the XML buffer output
5905 * @cur: the first namespace
5906 *
5907 * Dump a list of local Namespace definitions.
5908 * Should be called in the context of attributes dumps.
5909 */
5910static void
5911xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5912 while (cur != NULL) {
5913 xmlNsDump(buf, cur);
5914 cur = cur->next;
5915 }
5916}
5917
5918/**
5919 * xmlDtdDump:
5920 * @buf: the XML buffer output
Daniel Veillardd1640922001-12-17 15:30:10 +00005921 * @dtd: the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00005922 *
5923 * Dump the XML document DTD, if any.
5924 */
5925static void
5926xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5927 if (dtd == NULL) {
5928#ifdef DEBUG_TREE
5929 xmlGenericError(xmlGenericErrorContext,
5930 "xmlDtdDump : no internal subset\n");
5931#endif
5932 return;
5933 }
5934 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5935 xmlBufferWriteCHAR(buf, dtd->name);
5936 if (dtd->ExternalID != NULL) {
5937 xmlBufferWriteChar(buf, " PUBLIC ");
5938 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5939 xmlBufferWriteChar(buf, " ");
5940 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5941 } else if (dtd->SystemID != NULL) {
5942 xmlBufferWriteChar(buf, " SYSTEM ");
5943 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5944 }
5945 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5946 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5947 xmlBufferWriteChar(buf, ">");
5948 return;
5949 }
5950 xmlBufferWriteChar(buf, " [\n");
5951 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5952#if 0
5953 if (dtd->entities != NULL)
5954 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5955 if (dtd->notations != NULL)
5956 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5957 if (dtd->elements != NULL)
5958 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5959 if (dtd->attributes != NULL)
5960 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5961#endif
5962 xmlBufferWriteChar(buf, "]>");
5963}
5964
5965/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00005966 * xmlAttrSerializeContent:
5967 * @buf: the XML buffer output
5968 * @doc: the document
5969 * @attr: the attribute pointer
5970 *
5971 * Serialize the attribute in the buffer
5972 */
5973static void
5974xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr) {
5975 const xmlChar *cur, *base;
5976 xmlNodePtr children;
5977
5978 children = attr->children;
5979 while (children != NULL) {
5980 switch (children->type) {
5981 case XML_TEXT_NODE:
5982 base = cur = children->content;
5983 while (*cur != 0) {
5984 if (*cur == '\n') {
5985 if (base != cur)
5986 xmlBufferAdd(buf, base, cur - base);
5987 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
5988 cur++;
5989 base = cur;
5990#if 0
5991 } else if (*cur == '\'') {
5992 if (base != cur)
5993 xmlBufferAdd(buf, base, cur - base);
5994 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
5995 cur++;
5996 base = cur;
5997#endif
5998 } else if (*cur == '"') {
5999 if (base != cur)
6000 xmlBufferAdd(buf, base, cur - base);
6001 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6002 cur++;
6003 base = cur;
6004 } else if (*cur == '<') {
6005 if (base != cur)
6006 xmlBufferAdd(buf, base, cur - base);
6007 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6008 cur++;
6009 base = cur;
6010 } else if (*cur == '>') {
6011 if (base != cur)
6012 xmlBufferAdd(buf, base, cur - base);
6013 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6014 cur++;
6015 base = cur;
6016 } else if (*cur == '&') {
6017 if (base != cur)
6018 xmlBufferAdd(buf, base, cur - base);
6019 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6020 cur++;
6021 base = cur;
6022 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6023 (doc->encoding == NULL))) {
6024 /*
6025 * We assume we have UTF-8 content.
6026 */
6027 char tmp[10];
6028 int val = 0, l = 1;
6029
6030 if (base != cur)
6031 xmlBufferAdd(buf, base, cur - base);
6032 if (*cur < 0xC0) {
6033 xmlGenericError(xmlGenericErrorContext,
6034 "xmlAttrSerializeContent : input not UTF-8\n");
6035 if (doc != NULL)
6036 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
6037 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6038 tmp[sizeof(tmp) - 1] = 0;
6039 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6040 cur++;
6041 base = cur;
6042 continue;
6043 } else if (*cur < 0xE0) {
6044 val = (cur[0]) & 0x1F;
6045 val <<= 6;
6046 val |= (cur[1]) & 0x3F;
6047 l = 2;
6048 } else if (*cur < 0xF0) {
6049 val = (cur[0]) & 0x0F;
6050 val <<= 6;
6051 val |= (cur[1]) & 0x3F;
6052 val <<= 6;
6053 val |= (cur[2]) & 0x3F;
6054 l = 3;
6055 } else if (*cur < 0xF8) {
6056 val = (cur[0]) & 0x07;
6057 val <<= 6;
6058 val |= (cur[1]) & 0x3F;
6059 val <<= 6;
6060 val |= (cur[2]) & 0x3F;
6061 val <<= 6;
6062 val |= (cur[3]) & 0x3F;
6063 l = 4;
6064 }
6065 if ((l == 1) || (!IS_CHAR(val))) {
6066 xmlGenericError(xmlGenericErrorContext,
6067 "xmlAttrSerializeContent : char out of range\n");
6068 if (doc != NULL)
6069 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
6070 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6071 tmp[sizeof(tmp) - 1] = 0;
6072 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6073 cur++;
6074 base = cur;
6075 continue;
6076 }
6077 /*
6078 * We could do multiple things here. Just save
6079 * as a char ref
6080 */
6081 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6082 tmp[sizeof(tmp) - 1] = 0;
6083 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6084 cur += l;
6085 base = cur;
6086 } else {
6087 cur++;
6088 }
6089 }
6090 if (base != cur)
6091 xmlBufferAdd(buf, base, cur - base);
6092 break;
6093 case XML_ENTITY_REF_NODE:
6094 xmlBufferAdd(buf, BAD_CAST "&", 1);
6095 xmlBufferAdd(buf, children->name, xmlStrlen(children->name));
6096 xmlBufferAdd(buf, BAD_CAST ";", 1);
6097 break;
6098 default:
6099 /* should not happen unless we have a badly built tree */
6100 break;
6101 }
6102 children = children->next;
6103 }
6104}
6105
6106/**
Owen Taylor3473f882001-02-23 17:55:21 +00006107 * xmlAttrDump:
6108 * @buf: the XML buffer output
6109 * @doc: the document
6110 * @cur: the attribute pointer
6111 *
6112 * Dump an XML attribute
6113 */
6114static void
6115xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00006116 if (cur == NULL) {
6117#ifdef DEBUG_TREE
6118 xmlGenericError(xmlGenericErrorContext,
6119 "xmlAttrDump : property == NULL\n");
6120#endif
6121 return;
6122 }
6123 xmlBufferWriteChar(buf, " ");
6124 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6125 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6126 xmlBufferWriteChar(buf, ":");
6127 }
6128 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006129 xmlBufferWriteChar(buf, "=\"");
6130 xmlAttrSerializeContent(buf, doc, cur);
6131 xmlBufferWriteChar(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006132}
6133
6134/**
6135 * xmlAttrListDump:
6136 * @buf: the XML buffer output
6137 * @doc: the document
6138 * @cur: the first attribute pointer
6139 *
6140 * Dump a list of XML attributes
6141 */
6142static void
6143xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
6144 if (cur == NULL) {
6145#ifdef DEBUG_TREE
6146 xmlGenericError(xmlGenericErrorContext,
6147 "xmlAttrListDump : property == NULL\n");
6148#endif
6149 return;
6150 }
6151 while (cur != NULL) {
6152 xmlAttrDump(buf, doc, cur);
6153 cur = cur->next;
6154 }
6155}
6156
6157
6158
6159/**
6160 * xmlNodeListDump:
6161 * @buf: the XML buffer output
6162 * @doc: the document
6163 * @cur: the first node
6164 * @level: the imbrication level for indenting
6165 * @format: is formatting allowed
6166 *
6167 * Dump an XML node list, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006168 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6169 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006170 */
6171static void
6172xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
6173 int format) {
6174 int i;
6175
6176 if (cur == NULL) {
6177#ifdef DEBUG_TREE
6178 xmlGenericError(xmlGenericErrorContext,
6179 "xmlNodeListDump : node == NULL\n");
6180#endif
6181 return;
6182 }
6183 while (cur != NULL) {
6184 if ((format) && (xmlIndentTreeOutput) &&
6185 (cur->type == XML_ELEMENT_NODE))
6186 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006187 xmlBufferWriteChar(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006188 xmlNodeDump(buf, doc, cur, level, format);
6189 if (format) {
6190 xmlBufferWriteChar(buf, "\n");
6191 }
6192 cur = cur->next;
6193 }
6194}
6195
6196/**
6197 * xmlNodeDump:
6198 * @buf: the XML buffer output
6199 * @doc: the document
6200 * @cur: the current node
6201 * @level: the imbrication level for indenting
6202 * @format: is formatting allowed
6203 *
6204 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006205 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6206 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006207 */
6208void
6209xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
6210 int format) {
6211 int i;
6212 xmlNodePtr tmp;
6213
6214 if (cur == NULL) {
6215#ifdef DEBUG_TREE
6216 xmlGenericError(xmlGenericErrorContext,
6217 "xmlNodeDump : node == NULL\n");
6218#endif
6219 return;
6220 }
6221 if (cur->type == XML_XINCLUDE_START)
6222 return;
6223 if (cur->type == XML_XINCLUDE_END)
6224 return;
6225 if (cur->type == XML_DTD_NODE) {
6226 xmlDtdDump(buf, (xmlDtdPtr) cur);
6227 return;
6228 }
6229 if (cur->type == XML_ELEMENT_DECL) {
6230 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
6231 return;
6232 }
Daniel Veillard78d12092001-10-11 09:12:24 +00006233 if (cur->type == XML_ATTRIBUTE_NODE){
6234 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
6235 return;
6236 }
Owen Taylor3473f882001-02-23 17:55:21 +00006237 if (cur->type == XML_ATTRIBUTE_DECL) {
6238 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
6239 return;
6240 }
6241 if (cur->type == XML_ENTITY_DECL) {
6242 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
6243 return;
6244 }
6245 if (cur->type == XML_TEXT_NODE) {
6246 if (cur->content != NULL) {
6247 if ((cur->name == xmlStringText) ||
6248 (cur->name != xmlStringTextNoenc)) {
6249 xmlChar *buffer;
6250
Owen Taylor3473f882001-02-23 17:55:21 +00006251 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006252 if (buffer != NULL) {
6253 xmlBufferWriteCHAR(buf, buffer);
6254 xmlFree(buffer);
6255 }
6256 } else {
6257 /*
6258 * Disable escaping, needed for XSLT
6259 */
Owen Taylor3473f882001-02-23 17:55:21 +00006260 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006261 }
6262 }
6263 return;
6264 }
6265 if (cur->type == XML_PI_NODE) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00006266 xmlBufferWriteChar(buf, "<?");
6267 xmlBufferWriteCHAR(buf, cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006268 if (cur->content != NULL) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00006269 xmlBufferWriteChar(buf, " ");
Daniel Veillard2c748c62002-01-16 15:37:50 +00006270 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006271 }
Daniel Veillard2c748c62002-01-16 15:37:50 +00006272 xmlBufferWriteChar(buf, "?>");
Owen Taylor3473f882001-02-23 17:55:21 +00006273 return;
6274 }
6275 if (cur->type == XML_COMMENT_NODE) {
6276 if (cur->content != NULL) {
6277 xmlBufferWriteChar(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006278 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006279 xmlBufferWriteChar(buf, "-->");
6280 }
6281 return;
6282 }
6283 if (cur->type == XML_ENTITY_REF_NODE) {
6284 xmlBufferWriteChar(buf, "&");
6285 xmlBufferWriteCHAR(buf, cur->name);
6286 xmlBufferWriteChar(buf, ";");
6287 return;
6288 }
6289 if (cur->type == XML_CDATA_SECTION_NODE) {
6290 xmlBufferWriteChar(buf, "<![CDATA[");
6291 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006292 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006293 xmlBufferWriteChar(buf, "]]>");
6294 return;
6295 }
6296
6297 if (format == 1) {
6298 tmp = cur->children;
6299 while (tmp != NULL) {
6300 if ((tmp->type == XML_TEXT_NODE) ||
6301 (tmp->type == XML_ENTITY_REF_NODE)) {
6302 format = 0;
6303 break;
6304 }
6305 tmp = tmp->next;
6306 }
6307 }
6308 xmlBufferWriteChar(buf, "<");
6309 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6310 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6311 xmlBufferWriteChar(buf, ":");
6312 }
6313
6314 xmlBufferWriteCHAR(buf, cur->name);
6315 if (cur->nsDef)
6316 xmlNsListDump(buf, cur->nsDef);
6317 if (cur->properties != NULL)
6318 xmlAttrListDump(buf, doc, cur->properties);
6319
Daniel Veillard7db37732001-07-12 01:20:08 +00006320 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6321 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00006322 (!xmlSaveNoEmptyTags)) {
6323 xmlBufferWriteChar(buf, "/>");
6324 return;
6325 }
6326 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006327 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006328 xmlChar *buffer;
6329
Owen Taylor3473f882001-02-23 17:55:21 +00006330 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006331 if (buffer != NULL) {
6332 xmlBufferWriteCHAR(buf, buffer);
6333 xmlFree(buffer);
6334 }
6335 }
6336 if (cur->children != NULL) {
6337 if (format) xmlBufferWriteChar(buf, "\n");
6338 xmlNodeListDump(buf, doc, cur->children,
6339 (level >= 0?level+1:-1), format);
6340 if ((xmlIndentTreeOutput) && (format))
6341 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006342 xmlBufferWriteChar(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006343 }
6344 xmlBufferWriteChar(buf, "</");
6345 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6346 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6347 xmlBufferWriteChar(buf, ":");
6348 }
6349
6350 xmlBufferWriteCHAR(buf, cur->name);
6351 xmlBufferWriteChar(buf, ">");
6352}
6353
6354/**
6355 * xmlElemDump:
6356 * @f: the FILE * for the output
6357 * @doc: the document
6358 * @cur: the current node
6359 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006360 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006361 */
6362void
6363xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
6364 xmlBufferPtr buf;
6365
6366 if (cur == NULL) {
6367#ifdef DEBUG_TREE
6368 xmlGenericError(xmlGenericErrorContext,
6369 "xmlElemDump : cur == NULL\n");
6370#endif
6371 return;
6372 }
Owen Taylor3473f882001-02-23 17:55:21 +00006373#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006374 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006375 xmlGenericError(xmlGenericErrorContext,
6376 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006377 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006378#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00006379
Owen Taylor3473f882001-02-23 17:55:21 +00006380 buf = xmlBufferCreate();
6381 if (buf == NULL) return;
6382 if ((doc != NULL) &&
6383 (doc->type == XML_HTML_DOCUMENT_NODE)) {
6384#ifdef LIBXML_HTML_ENABLED
6385 htmlNodeDump(buf, doc, cur);
6386#else
6387 xmlGenericError(xmlGenericErrorContext,
6388 "HTML support not compiled in\n");
6389#endif /* LIBXML_HTML_ENABLED */
6390 } else
6391 xmlNodeDump(buf, doc, cur, 0, 1);
6392 xmlBufferDump(f, buf);
6393 xmlBufferFree(buf);
6394}
6395
6396/************************************************************************
6397 * *
6398 * Dumping XML tree content to an I/O output buffer *
6399 * *
6400 ************************************************************************/
6401
Owen Taylor3473f882001-02-23 17:55:21 +00006402static void
6403xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6404 int level, int format, const char *encoding);
6405/**
6406 * xmlNsDumpOutput:
6407 * @buf: the XML buffer output
6408 * @cur: a namespace
6409 *
6410 * Dump a local Namespace definition.
6411 * Should be called in the context of attributes dumps.
6412 */
6413static void
6414xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6415 if (cur == NULL) {
6416#ifdef DEBUG_TREE
6417 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006418 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006419#endif
6420 return;
6421 }
6422 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006423 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6424 return;
6425
Owen Taylor3473f882001-02-23 17:55:21 +00006426 /* Within the context of an element attributes */
6427 if (cur->prefix != NULL) {
6428 xmlOutputBufferWriteString(buf, " xmlns:");
6429 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6430 } else
6431 xmlOutputBufferWriteString(buf, " xmlns");
6432 xmlOutputBufferWriteString(buf, "=");
6433 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6434 }
6435}
6436
6437/**
6438 * xmlNsListDumpOutput:
6439 * @buf: the XML buffer output
6440 * @cur: the first namespace
6441 *
6442 * Dump a list of local Namespace definitions.
6443 * Should be called in the context of attributes dumps.
6444 */
6445static void
6446xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6447 while (cur != NULL) {
6448 xmlNsDumpOutput(buf, cur);
6449 cur = cur->next;
6450 }
6451}
6452
6453/**
6454 * xmlDtdDumpOutput:
6455 * @buf: the XML buffer output
6456 * @doc: the document
6457 * @encoding: an optional encoding string
6458 *
6459 * Dump the XML document DTD, if any.
6460 */
6461static void
6462xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6463 if (dtd == NULL) {
6464#ifdef DEBUG_TREE
6465 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006466 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006467#endif
6468 return;
6469 }
6470 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6471 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6472 if (dtd->ExternalID != NULL) {
6473 xmlOutputBufferWriteString(buf, " PUBLIC ");
6474 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6475 xmlOutputBufferWriteString(buf, " ");
6476 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6477 } else if (dtd->SystemID != NULL) {
6478 xmlOutputBufferWriteString(buf, " SYSTEM ");
6479 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6480 }
6481 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6482 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6483 xmlOutputBufferWriteString(buf, ">");
6484 return;
6485 }
6486 xmlOutputBufferWriteString(buf, " [\n");
6487 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6488 xmlOutputBufferWriteString(buf, "]>");
6489}
6490
6491/**
6492 * xmlAttrDumpOutput:
6493 * @buf: the XML buffer output
6494 * @doc: the document
6495 * @cur: the attribute pointer
6496 * @encoding: an optional encoding string
6497 *
6498 * Dump an XML attribute
6499 */
6500static void
6501xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006502 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006503 if (cur == NULL) {
6504#ifdef DEBUG_TREE
6505 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006506 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006507#endif
6508 return;
6509 }
6510 xmlOutputBufferWriteString(buf, " ");
6511 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6512 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6513 xmlOutputBufferWriteString(buf, ":");
6514 }
6515 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006516 xmlOutputBufferWriteString(buf, "=\"");
6517 xmlAttrSerializeContent(buf->buffer, doc, cur);
6518 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006519}
6520
6521/**
6522 * xmlAttrListDumpOutput:
6523 * @buf: the XML buffer output
6524 * @doc: the document
6525 * @cur: the first attribute pointer
6526 * @encoding: an optional encoding string
6527 *
6528 * Dump a list of XML attributes
6529 */
6530static void
6531xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6532 xmlAttrPtr cur, const char *encoding) {
6533 if (cur == NULL) {
6534#ifdef DEBUG_TREE
6535 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006536 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006537#endif
6538 return;
6539 }
6540 while (cur != NULL) {
6541 xmlAttrDumpOutput(buf, doc, cur, encoding);
6542 cur = cur->next;
6543 }
6544}
6545
6546
6547
6548/**
6549 * xmlNodeListDumpOutput:
6550 * @buf: the XML buffer output
6551 * @doc: the document
6552 * @cur: the first node
6553 * @level: the imbrication level for indenting
6554 * @format: is formatting allowed
6555 * @encoding: an optional encoding string
6556 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006557 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006558 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6559 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006560 */
6561static void
6562xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6563 xmlNodePtr cur, int level, int format, const char *encoding) {
6564 int i;
6565
6566 if (cur == NULL) {
6567#ifdef DEBUG_TREE
6568 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006569 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006570#endif
6571 return;
6572 }
6573 while (cur != NULL) {
6574 if ((format) && (xmlIndentTreeOutput) &&
6575 (cur->type == XML_ELEMENT_NODE))
6576 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006577 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006578 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6579 if (format) {
6580 xmlOutputBufferWriteString(buf, "\n");
6581 }
6582 cur = cur->next;
6583 }
6584}
6585
6586/**
6587 * xmlNodeDumpOutput:
6588 * @buf: the XML buffer output
6589 * @doc: the document
6590 * @cur: the current node
6591 * @level: the imbrication level for indenting
6592 * @format: is formatting allowed
6593 * @encoding: an optional encoding string
6594 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006595 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006596 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6597 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006598 */
6599void
6600xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6601 int level, int format, const char *encoding) {
6602 int i;
6603 xmlNodePtr tmp;
6604
6605 if (cur == NULL) {
6606#ifdef DEBUG_TREE
6607 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006608 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006609#endif
6610 return;
6611 }
6612 if (cur->type == XML_XINCLUDE_START)
6613 return;
6614 if (cur->type == XML_XINCLUDE_END)
6615 return;
6616 if (cur->type == XML_DTD_NODE) {
6617 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6618 return;
6619 }
6620 if (cur->type == XML_ELEMENT_DECL) {
6621 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6622 return;
6623 }
6624 if (cur->type == XML_ATTRIBUTE_DECL) {
6625 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6626 return;
6627 }
6628 if (cur->type == XML_ENTITY_DECL) {
6629 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6630 return;
6631 }
6632 if (cur->type == XML_TEXT_NODE) {
6633 if (cur->content != NULL) {
6634 if ((cur->name == xmlStringText) ||
6635 (cur->name != xmlStringTextNoenc)) {
6636 xmlChar *buffer;
6637
Owen Taylor3473f882001-02-23 17:55:21 +00006638 if (encoding == NULL)
6639 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6640 else
6641 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006642 if (buffer != NULL) {
6643 xmlOutputBufferWriteString(buf, (const char *)buffer);
6644 xmlFree(buffer);
6645 }
6646 } else {
6647 /*
6648 * Disable escaping, needed for XSLT
6649 */
Owen Taylor3473f882001-02-23 17:55:21 +00006650 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006651 }
6652 }
6653
6654 return;
6655 }
6656 if (cur->type == XML_PI_NODE) {
6657 if (cur->content != NULL) {
6658 xmlOutputBufferWriteString(buf, "<?");
6659 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6660 if (cur->content != NULL) {
6661 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006662 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006663 }
6664 xmlOutputBufferWriteString(buf, "?>");
6665 } else {
6666 xmlOutputBufferWriteString(buf, "<?");
6667 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6668 xmlOutputBufferWriteString(buf, "?>");
6669 }
6670 return;
6671 }
6672 if (cur->type == XML_COMMENT_NODE) {
6673 if (cur->content != NULL) {
6674 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006675 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006676 xmlOutputBufferWriteString(buf, "-->");
6677 }
6678 return;
6679 }
6680 if (cur->type == XML_ENTITY_REF_NODE) {
6681 xmlOutputBufferWriteString(buf, "&");
6682 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6683 xmlOutputBufferWriteString(buf, ";");
6684 return;
6685 }
6686 if (cur->type == XML_CDATA_SECTION_NODE) {
6687 xmlOutputBufferWriteString(buf, "<![CDATA[");
6688 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006689 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006690 xmlOutputBufferWriteString(buf, "]]>");
6691 return;
6692 }
6693
6694 if (format == 1) {
6695 tmp = cur->children;
6696 while (tmp != NULL) {
6697 if ((tmp->type == XML_TEXT_NODE) ||
6698 (tmp->type == XML_ENTITY_REF_NODE)) {
6699 format = 0;
6700 break;
6701 }
6702 tmp = tmp->next;
6703 }
6704 }
6705 xmlOutputBufferWriteString(buf, "<");
6706 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6707 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6708 xmlOutputBufferWriteString(buf, ":");
6709 }
6710
6711 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6712 if (cur->nsDef)
6713 xmlNsListDumpOutput(buf, cur->nsDef);
6714 if (cur->properties != NULL)
6715 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6716
Daniel Veillard7db37732001-07-12 01:20:08 +00006717 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6718 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006719 xmlOutputBufferWriteString(buf, "/>");
6720 return;
6721 }
6722 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006723 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006724 xmlChar *buffer;
6725
Owen Taylor3473f882001-02-23 17:55:21 +00006726 if (encoding == NULL)
6727 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6728 else
6729 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006730 if (buffer != NULL) {
6731 xmlOutputBufferWriteString(buf, (const char *)buffer);
6732 xmlFree(buffer);
6733 }
6734 }
6735 if (cur->children != NULL) {
6736 if (format) xmlOutputBufferWriteString(buf, "\n");
6737 xmlNodeListDumpOutput(buf, doc, cur->children,
6738 (level >= 0?level+1:-1), format, encoding);
6739 if ((xmlIndentTreeOutput) && (format))
6740 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006741 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006742 }
6743 xmlOutputBufferWriteString(buf, "</");
6744 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6745 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6746 xmlOutputBufferWriteString(buf, ":");
6747 }
6748
6749 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6750 xmlOutputBufferWriteString(buf, ">");
6751}
6752
6753/**
6754 * xmlDocContentDumpOutput:
6755 * @buf: the XML buffer output
6756 * @cur: the document
6757 * @encoding: an optional encoding string
6758 * @format: should formatting spaces been added
6759 *
6760 * Dump an XML document.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006761 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6762 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006763 */
6764static void
6765xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6766 const char *encoding, int format) {
6767 xmlOutputBufferWriteString(buf, "<?xml version=");
6768 if (cur->version != NULL)
6769 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6770 else
6771 xmlOutputBufferWriteString(buf, "\"1.0\"");
6772 if (encoding == NULL) {
6773 if (cur->encoding != NULL)
6774 encoding = (const char *) cur->encoding;
6775 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6776 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6777 }
6778 if (encoding != NULL) {
6779 xmlOutputBufferWriteString(buf, " encoding=");
6780 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6781 }
6782 switch (cur->standalone) {
6783 case 0:
6784 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6785 break;
6786 case 1:
6787 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6788 break;
6789 }
6790 xmlOutputBufferWriteString(buf, "?>\n");
6791 if (cur->children != NULL) {
6792 xmlNodePtr child = cur->children;
6793
6794 while (child != NULL) {
6795 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6796 xmlOutputBufferWriteString(buf, "\n");
6797 child = child->next;
6798 }
6799 }
6800}
6801
6802/************************************************************************
6803 * *
6804 * Saving functions front-ends *
6805 * *
6806 ************************************************************************/
6807
6808/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006809 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006810 * @out_doc: Document to generate XML text from
6811 * @doc_txt_ptr: Memory pointer for allocated XML text
6812 * @doc_txt_len: Length of the generated XML text
6813 * @txt_encoding: Character encoding to use when generating XML text
6814 * @format: should formatting spaces been added
6815 *
6816 * Dump the current DOM tree into memory using the character encoding specified
6817 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006818 * allocated memory with xmlFree().
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006819 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6820 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006821 */
6822
6823void
6824xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006825 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006826 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006827 int dummy = 0;
6828
6829 xmlCharEncoding doc_charset;
6830 xmlOutputBufferPtr out_buff = NULL;
6831 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6832
6833 if (doc_txt_len == NULL) {
6834 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6835 }
6836
6837 if (doc_txt_ptr == NULL) {
6838 *doc_txt_len = 0;
6839 xmlGenericError(xmlGenericErrorContext,
6840 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6841 return;
6842 }
6843
6844 *doc_txt_ptr = NULL;
6845 *doc_txt_len = 0;
6846
6847 if (out_doc == NULL) {
6848 /* No document, no output */
6849 xmlGenericError(xmlGenericErrorContext,
6850 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6851 return;
6852 }
6853
6854 /*
6855 * Validate the encoding value, if provided.
6856 * This logic is copied from xmlSaveFileEnc.
6857 */
6858
6859 if (txt_encoding == NULL)
6860 txt_encoding = (const char *) out_doc->encoding;
6861 if (txt_encoding != NULL) {
6862 doc_charset = xmlParseCharEncoding(txt_encoding);
6863
6864 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6865 xmlGenericError(xmlGenericErrorContext,
6866 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6867 return;
6868
6869 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6870 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6871 if ( conv_hdlr == NULL ) {
6872 xmlGenericError(xmlGenericErrorContext,
6873 "%s: %s %s '%s'\n",
6874 "xmlDocDumpFormatMemoryEnc",
6875 "Failed to identify encoding handler for",
6876 "character set",
6877 txt_encoding);
6878 return;
6879 }
6880 }
6881 }
6882
6883 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6884 xmlGenericError(xmlGenericErrorContext,
6885 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6886 return;
6887 }
6888
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006889 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006890 xmlOutputBufferFlush(out_buff);
6891 if (out_buff->conv != NULL) {
6892 *doc_txt_len = out_buff->conv->use;
6893 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6894 } else {
6895 *doc_txt_len = out_buff->buffer->use;
6896 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6897 }
6898 (void)xmlOutputBufferClose(out_buff);
6899
6900 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6901 *doc_txt_len = 0;
6902 xmlGenericError(xmlGenericErrorContext,
6903 "xmlDocDumpFormatMemoryEnc: %s\n",
6904 "Failed to allocate memory for document text representation.");
6905 }
6906
6907 return;
6908}
6909
6910/**
6911 * xmlDocDumpMemory:
6912 * @cur: the document
6913 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006914 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006915 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006916 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006917 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006918 */
6919void
6920xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6921 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6922}
6923
6924/**
6925 * xmlDocDumpFormatMemory:
6926 * @cur: the document
6927 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006928 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006929 * @format: should formatting spaces been added
6930 *
6931 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006932 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006933 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006934 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6935 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006936 */
6937void
6938xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6939 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6940}
6941
6942/**
6943 * xmlDocDumpMemoryEnc:
6944 * @out_doc: Document to generate XML text from
6945 * @doc_txt_ptr: Memory pointer for allocated XML text
6946 * @doc_txt_len: Length of the generated XML text
6947 * @txt_encoding: Character encoding to use when generating XML text
6948 *
6949 * Dump the current DOM tree into memory using the character encoding specified
6950 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006951 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006952 */
6953
6954void
6955xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6956 int * doc_txt_len, const char * txt_encoding) {
6957 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006958 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006959}
6960
6961/**
6962 * xmlGetDocCompressMode:
6963 * @doc: the document
6964 *
6965 * get the compression ratio for a document, ZLIB based
6966 * Returns 0 (uncompressed) to 9 (max compression)
6967 */
6968int
6969xmlGetDocCompressMode (xmlDocPtr doc) {
6970 if (doc == NULL) return(-1);
6971 return(doc->compression);
6972}
6973
6974/**
6975 * xmlSetDocCompressMode:
6976 * @doc: the document
6977 * @mode: the compression ratio
6978 *
6979 * set the compression ratio for a document, ZLIB based
6980 * Correct values: 0 (uncompressed) to 9 (max compression)
6981 */
6982void
6983xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6984 if (doc == NULL) return;
6985 if (mode < 0) doc->compression = 0;
6986 else if (mode > 9) doc->compression = 9;
6987 else doc->compression = mode;
6988}
6989
6990/**
6991 * xmlGetCompressMode:
6992 *
6993 * get the default compression mode used, ZLIB based.
6994 * Returns 0 (uncompressed) to 9 (max compression)
6995 */
6996int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00006997xmlGetCompressMode(void)
6998{
6999 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00007000}
7001
7002/**
7003 * xmlSetCompressMode:
7004 * @mode: the compression ratio
7005 *
7006 * set the default compression mode used, ZLIB based
7007 * Correct values: 0 (uncompressed) to 9 (max compression)
7008 */
7009void
7010xmlSetCompressMode(int mode) {
7011 if (mode < 0) xmlCompressMode = 0;
7012 else if (mode > 9) xmlCompressMode = 9;
7013 else xmlCompressMode = mode;
7014}
7015
7016/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007017 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00007018 * @f: the FILE*
7019 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00007020 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007021 *
7022 * Dump an XML document to an open FILE.
7023 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007024 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007025 */
7026int
Daniel Veillard9e412302002-06-10 15:59:44 +00007027xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007028 xmlOutputBufferPtr buf;
7029 const char * encoding;
7030 xmlCharEncodingHandlerPtr handler = NULL;
7031 int ret;
7032
7033 if (cur == NULL) {
7034#ifdef DEBUG_TREE
7035 xmlGenericError(xmlGenericErrorContext,
7036 "xmlDocDump : document == NULL\n");
7037#endif
7038 return(-1);
7039 }
7040 encoding = (const char *) cur->encoding;
7041
7042 if (encoding != NULL) {
7043 xmlCharEncoding enc;
7044
7045 enc = xmlParseCharEncoding(encoding);
7046
7047 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7048 xmlGenericError(xmlGenericErrorContext,
7049 "xmlDocDump: document not in UTF8\n");
7050 return(-1);
7051 }
7052 if (enc != XML_CHAR_ENCODING_UTF8) {
7053 handler = xmlFindCharEncodingHandler(encoding);
7054 if (handler == NULL) {
7055 xmlFree((char *) cur->encoding);
7056 cur->encoding = NULL;
7057 }
7058 }
7059 }
7060 buf = xmlOutputBufferCreateFile(f, handler);
7061 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00007062 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007063
7064 ret = xmlOutputBufferClose(buf);
7065 return(ret);
7066}
7067
7068/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007069 * xmlDocDump:
7070 * @f: the FILE*
7071 * @cur: the document
7072 *
7073 * Dump an XML document to an open FILE.
7074 *
7075 * returns: the number of bytes written or -1 in case of failure.
7076 */
7077int
7078xmlDocDump(FILE *f, xmlDocPtr cur) {
7079 return(xmlDocFormatDump (f, cur, 0));
7080}
7081
7082/**
Owen Taylor3473f882001-02-23 17:55:21 +00007083 * xmlSaveFileTo:
7084 * @buf: an output I/O buffer
7085 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007086 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00007087 *
7088 * Dump an XML document to an I/O buffer.
7089 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007090 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007091 */
7092int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007093xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007094 int ret;
7095
7096 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007097 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007098 ret = xmlOutputBufferClose(buf);
7099 return(ret);
7100}
7101
7102/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00007103 * xmlSaveFormatFileTo:
7104 * @buf: an output I/O buffer
7105 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007106 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00007107 * @format: should formatting spaces been added
7108 *
7109 * Dump an XML document to an I/O buffer.
7110 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007111 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00007112 */
7113int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007114xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00007115 int ret;
7116
7117 if (buf == NULL) return(0);
7118 xmlDocContentDumpOutput(buf, cur, encoding, format);
7119 ret = xmlOutputBufferClose(buf);
7120 return(ret);
7121}
7122
7123/**
Daniel Veillardf012a642001-07-23 19:10:52 +00007124 * xmlSaveFormatFileEnc
7125 * @filename: the filename or URL to output
7126 * @cur: the document being saved
7127 * @encoding: the name of the encoding to use or NULL.
7128 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00007129 *
7130 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00007131 */
7132int
Daniel Veillardf012a642001-07-23 19:10:52 +00007133xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
7134 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00007135 xmlOutputBufferPtr buf;
7136 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00007137 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00007138 int ret;
7139
Daniel Veillardfb25a512002-01-13 20:32:08 +00007140 if (encoding == NULL)
7141 encoding = (const char *) cur->encoding;
7142
Owen Taylor3473f882001-02-23 17:55:21 +00007143 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007144
7145 enc = xmlParseCharEncoding(encoding);
7146 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7147 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007148 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007149 return(-1);
7150 }
7151 if (enc != XML_CHAR_ENCODING_UTF8) {
7152 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00007153 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007154 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007155 }
7156 }
7157
Daniel Veillardf012a642001-07-23 19:10:52 +00007158#ifdef HAVE_ZLIB_H
7159 if (cur->compression < 0) cur->compression = xmlCompressMode;
7160#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007161 /*
7162 * save the content to a temp buffer.
7163 */
Daniel Veillardf012a642001-07-23 19:10:52 +00007164 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00007165 if (buf == NULL) return(-1);
7166
Daniel Veillardf012a642001-07-23 19:10:52 +00007167 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007168
7169 ret = xmlOutputBufferClose(buf);
7170 return(ret);
7171}
7172
Daniel Veillardf012a642001-07-23 19:10:52 +00007173
7174/**
7175 * xmlSaveFileEnc:
7176 * @filename: the filename (or URL)
7177 * @cur: the document
7178 * @encoding: the name of an encoding (or NULL)
7179 *
7180 * Dump an XML document, converting it to the given encoding
7181 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007182 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00007183 */
7184int
7185xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
7186 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
7187}
7188
Owen Taylor3473f882001-02-23 17:55:21 +00007189/**
Daniel Veillard67fee942001-04-26 18:59:03 +00007190 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00007191 * @filename: the filename (or URL)
7192 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00007193 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007194 *
7195 * Dump an XML document to a file. Will use compression if
7196 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00007197 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00007198 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007199 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007200 */
7201int
Daniel Veillard67fee942001-04-26 18:59:03 +00007202xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007203 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00007204}
7205
Daniel Veillard67fee942001-04-26 18:59:03 +00007206/**
7207 * xmlSaveFile:
7208 * @filename: the filename (or URL)
7209 * @cur: the document
7210 *
7211 * Dump an XML document to a file. Will use compression if
7212 * compiled in and enabled. If @filename is "-" the stdout file is
7213 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00007214 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00007215 */
7216int
7217xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007218 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00007219}
7220