blob: de9b04c1dc66e50445010448546180d902f5ba0e [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00006 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00007 *
8 * 14 Nov 2000 ht - Changed the name of function xmlBufferWriteChar under VMS
9 * as it was similar to xmlBufferWriteCHAR when compiling without case
10 * sensitivity.
11 *
12 */
13
Daniel Veillard34ce8be2002-03-18 19:37:11 +000014#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000015#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000016
Owen Taylor3473f882001-02-23 17:55:21 +000017#include <string.h> /* for memset() only ! */
18
19#ifdef HAVE_CTYPE_H
20#include <ctype.h>
21#endif
22#ifdef HAVE_STDLIB_H
23#include <stdlib.h>
24#endif
25#ifdef HAVE_ZLIB_H
26#include <zlib.h>
27#endif
28
29#include <libxml/xmlmemory.h>
30#include <libxml/tree.h>
31#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000032#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000033#include <libxml/entities.h>
34#include <libxml/valid.h>
35#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000036#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000037#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000038
Daniel Veillard56a4cb82001-03-24 17:00:36 +000039xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
40
41/************************************************************************
42 * *
43 * A few static variables and macros *
44 * *
45 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000046/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000047const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000048/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000049const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000050 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000051/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +000052const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
53
Owen Taylor3473f882001-02-23 17:55:21 +000054static int xmlCompressMode = 0;
55static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000056
Owen Taylor3473f882001-02-23 17:55:21 +000057#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
58 xmlNodePtr ulccur = (n)->children; \
59 if (ulccur == NULL) { \
60 (n)->last = NULL; \
61 } else { \
62 while (ulccur->next != NULL) { \
63 ulccur->parent = (n); \
64 ulccur = ulccur->next; \
65 } \
66 ulccur->parent = (n); \
67 (n)->last = ulccur; \
68}}
69
70/* #define DEBUG_BUFFER */
71/* #define DEBUG_TREE */
72
73/************************************************************************
74 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +000075 * Functions to move to entities.c once the *
76 * API freeze is smoothen and they can be made public. *
77 * *
78 ************************************************************************/
79#include <libxml/hash.h>
80
81/**
82 * xmlGetEntityFromDtd:
83 * @dtd: A pointer to the DTD to search
84 * @name: The entity name
85 *
86 * Do an entity lookup in the DTD entity hash table and
87 * return the corresponding entity, if found.
88 *
89 * Returns A pointer to the entity structure or NULL if not found.
90 */
91static xmlEntityPtr
92xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
93 xmlEntitiesTablePtr table;
94
95 if((dtd != NULL) && (dtd->entities != NULL)) {
96 table = (xmlEntitiesTablePtr) dtd->entities;
97 return((xmlEntityPtr) xmlHashLookup(table, name));
98 /* return(xmlGetEntityFromTable(table, name)); */
99 }
100 return(NULL);
101}
102/**
103 * xmlGetParameterEntityFromDtd:
104 * @dtd: A pointer to the DTD to search
105 * @name: The entity name
106 *
107 * Do an entity lookup in the DTD pararmeter entity hash table and
108 * return the corresponding entity, if found.
109 *
110 * Returns A pointer to the entity structure or NULL if not found.
111 */
112static xmlEntityPtr
113xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
114 xmlEntitiesTablePtr table;
115
116 if ((dtd != NULL) && (dtd->pentities != NULL)) {
117 table = (xmlEntitiesTablePtr) dtd->pentities;
118 return((xmlEntityPtr) xmlHashLookup(table, name));
119 /* return(xmlGetEntityFromTable(table, name)); */
120 }
121 return(NULL);
122}
123
124/************************************************************************
125 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000126 * Allocation and deallocation of basic structures *
127 * *
128 ************************************************************************/
129
130/**
131 * xmlSetBufferAllocationScheme:
132 * @scheme: allocation method to use
133 *
134 * Set the buffer allocation method. Types are
135 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
136 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
137 * improves performance
138 */
139void
140xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
141 xmlBufferAllocScheme = scheme;
142}
143
144/**
145 * xmlGetBufferAllocationScheme:
146 *
147 * Types are
148 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
149 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
150 * improves performance
151 *
152 * Returns the current allocation scheme
153 */
154xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000155xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000156 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000157}
158
159/**
160 * xmlNewNs:
161 * @node: the element carrying the namespace
162 * @href: the URI associated
163 * @prefix: the prefix for the namespace
164 *
165 * Creation of a new Namespace. This function will refuse to create
166 * a namespace with a similar prefix than an existing one present on this
167 * node.
168 * We use href==NULL in the case of an element creation where the namespace
169 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000170 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000171 */
172xmlNsPtr
173xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
174 xmlNsPtr cur;
175
176 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
177 return(NULL);
178
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000179 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
180 return(NULL);
181
Owen Taylor3473f882001-02-23 17:55:21 +0000182 /*
183 * Allocate a new Namespace and fill the fields.
184 */
185 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
186 if (cur == NULL) {
187 xmlGenericError(xmlGenericErrorContext,
188 "xmlNewNs : malloc failed\n");
189 return(NULL);
190 }
191 memset(cur, 0, sizeof(xmlNs));
192 cur->type = XML_LOCAL_NAMESPACE;
193
194 if (href != NULL)
195 cur->href = xmlStrdup(href);
196 if (prefix != NULL)
197 cur->prefix = xmlStrdup(prefix);
198
199 /*
200 * Add it at the end to preserve parsing order ...
201 * and checks for existing use of the prefix
202 */
203 if (node != NULL) {
204 if (node->nsDef == NULL) {
205 node->nsDef = cur;
206 } else {
207 xmlNsPtr prev = node->nsDef;
208
209 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
210 (xmlStrEqual(prev->prefix, cur->prefix))) {
211 xmlFreeNs(cur);
212 return(NULL);
213 }
214 while (prev->next != NULL) {
215 prev = prev->next;
216 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
217 (xmlStrEqual(prev->prefix, cur->prefix))) {
218 xmlFreeNs(cur);
219 return(NULL);
220 }
221 }
222 prev->next = cur;
223 }
224 }
225 return(cur);
226}
227
228/**
229 * xmlSetNs:
230 * @node: a node in the document
231 * @ns: a namespace pointer
232 *
233 * Associate a namespace to a node, a posteriori.
234 */
235void
236xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
237 if (node == NULL) {
238#ifdef DEBUG_TREE
239 xmlGenericError(xmlGenericErrorContext,
240 "xmlSetNs: node == NULL\n");
241#endif
242 return;
243 }
244 node->ns = ns;
245}
246
247/**
248 * xmlFreeNs:
249 * @cur: the namespace pointer
250 *
251 * Free up the structures associated to a namespace
252 */
253void
254xmlFreeNs(xmlNsPtr cur) {
255 if (cur == NULL) {
256#ifdef DEBUG_TREE
257 xmlGenericError(xmlGenericErrorContext,
258 "xmlFreeNs : ns == NULL\n");
259#endif
260 return;
261 }
262 if (cur->href != NULL) xmlFree((char *) cur->href);
263 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000264 xmlFree(cur);
265}
266
267/**
268 * xmlFreeNsList:
269 * @cur: the first namespace pointer
270 *
271 * Free up all the structures associated to the chained namespaces.
272 */
273void
274xmlFreeNsList(xmlNsPtr cur) {
275 xmlNsPtr next;
276 if (cur == NULL) {
277#ifdef DEBUG_TREE
278 xmlGenericError(xmlGenericErrorContext,
279 "xmlFreeNsList : ns == NULL\n");
280#endif
281 return;
282 }
283 while (cur != NULL) {
284 next = cur->next;
285 xmlFreeNs(cur);
286 cur = next;
287 }
288}
289
290/**
291 * xmlNewDtd:
292 * @doc: the document pointer
293 * @name: the DTD name
294 * @ExternalID: the external ID
295 * @SystemID: the system ID
296 *
297 * Creation of a new DTD for the external subset. To create an
298 * internal subset, use xmlCreateIntSubset().
299 *
300 * Returns a pointer to the new DTD structure
301 */
302xmlDtdPtr
303xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
304 const xmlChar *ExternalID, const xmlChar *SystemID) {
305 xmlDtdPtr cur;
306
307 if ((doc != NULL) && (doc->extSubset != NULL)) {
308#ifdef DEBUG_TREE
309 xmlGenericError(xmlGenericErrorContext,
310 "xmlNewDtd(%s): document %s already have a DTD %s\n",
311 /* !!! */ (char *) name, doc->name,
312 /* !!! */ (char *)doc->extSubset->name);
313#endif
314 return(NULL);
315 }
316
317 /*
318 * Allocate a new DTD and fill the fields.
319 */
320 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
321 if (cur == NULL) {
322 xmlGenericError(xmlGenericErrorContext,
323 "xmlNewDtd : malloc failed\n");
324 return(NULL);
325 }
326 memset(cur, 0 , sizeof(xmlDtd));
327 cur->type = XML_DTD_NODE;
328
329 if (name != NULL)
330 cur->name = xmlStrdup(name);
331 if (ExternalID != NULL)
332 cur->ExternalID = xmlStrdup(ExternalID);
333 if (SystemID != NULL)
334 cur->SystemID = xmlStrdup(SystemID);
335 if (doc != NULL)
336 doc->extSubset = cur;
337 cur->doc = doc;
338
339 return(cur);
340}
341
342/**
343 * xmlGetIntSubset:
344 * @doc: the document pointer
345 *
346 * Get the internal subset of a document
347 * Returns a pointer to the DTD structure or NULL if not found
348 */
349
350xmlDtdPtr
351xmlGetIntSubset(xmlDocPtr doc) {
352 xmlNodePtr cur;
353
354 if (doc == NULL)
355 return(NULL);
356 cur = doc->children;
357 while (cur != NULL) {
358 if (cur->type == XML_DTD_NODE)
359 return((xmlDtdPtr) cur);
360 cur = cur->next;
361 }
362 return((xmlDtdPtr) doc->intSubset);
363}
364
365/**
366 * xmlCreateIntSubset:
367 * @doc: the document pointer
368 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000369 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000370 * @SystemID: the system ID
371 *
372 * Create the internal subset of a document
373 * Returns a pointer to the new DTD structure
374 */
375xmlDtdPtr
376xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
377 const xmlChar *ExternalID, const xmlChar *SystemID) {
378 xmlDtdPtr cur;
379
380 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
381#ifdef DEBUG_TREE
382 xmlGenericError(xmlGenericErrorContext,
383
384 "xmlCreateIntSubset(): document %s already have an internal subset\n",
385 doc->name);
386#endif
387 return(NULL);
388 }
389
390 /*
391 * Allocate a new DTD and fill the fields.
392 */
393 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
394 if (cur == NULL) {
395 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000396 "xmlCreateIntSubset : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000397 return(NULL);
398 }
399 memset(cur, 0, sizeof(xmlDtd));
400 cur->type = XML_DTD_NODE;
401
402 if (name != NULL)
403 cur->name = xmlStrdup(name);
404 if (ExternalID != NULL)
405 cur->ExternalID = xmlStrdup(ExternalID);
406 if (SystemID != NULL)
407 cur->SystemID = xmlStrdup(SystemID);
408 if (doc != NULL) {
409 doc->intSubset = cur;
410 cur->parent = doc;
411 cur->doc = doc;
412 if (doc->children == NULL) {
413 doc->children = (xmlNodePtr) cur;
414 doc->last = (xmlNodePtr) cur;
415 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000416 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000417 xmlNodePtr prev;
418
Owen Taylor3473f882001-02-23 17:55:21 +0000419 prev = doc->children;
420 prev->prev = (xmlNodePtr) cur;
421 cur->next = prev;
422 doc->children = (xmlNodePtr) cur;
423 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000424 xmlNodePtr next;
425
426 next = doc->children;
427 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
428 next = next->next;
429 if (next == NULL) {
430 cur->prev = doc->last;
431 cur->prev->next = (xmlNodePtr) cur;
432 cur->next = NULL;
433 doc->last = (xmlNodePtr) cur;
434 } else {
435 cur->next = next;
436 cur->prev = next->prev;
437 if (cur->prev == NULL)
438 doc->children = (xmlNodePtr) cur;
439 else
440 cur->prev->next = (xmlNodePtr) cur;
441 next->prev = (xmlNodePtr) cur;
442 }
Owen Taylor3473f882001-02-23 17:55:21 +0000443 }
444 }
445 }
446 return(cur);
447}
448
449/**
450 * xmlFreeDtd:
451 * @cur: the DTD structure to free up
452 *
453 * Free a DTD structure.
454 */
455void
456xmlFreeDtd(xmlDtdPtr cur) {
457 if (cur == NULL) {
458#ifdef DEBUG_TREE
459 xmlGenericError(xmlGenericErrorContext,
460 "xmlFreeDtd : DTD == NULL\n");
461#endif
462 return;
463 }
464 if (cur->children != NULL) {
465 xmlNodePtr next, c = cur->children;
466
467 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000468 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000469 * indexes.
470 */
471 while (c != NULL) {
472 next = c->next;
473 if (c->type == XML_COMMENT_NODE) {
474 xmlUnlinkNode(c);
475 xmlFreeNode(c);
476 }
477 c = next;
478 }
479 }
480 if (cur->name != NULL) xmlFree((char *) cur->name);
481 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
482 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
483 /* TODO !!! */
484 if (cur->notations != NULL)
485 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
486
487 if (cur->elements != NULL)
488 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
489 if (cur->attributes != NULL)
490 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
491 if (cur->entities != NULL)
492 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
493 if (cur->pentities != NULL)
494 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
495
Owen Taylor3473f882001-02-23 17:55:21 +0000496 xmlFree(cur);
497}
498
499/**
500 * xmlNewDoc:
501 * @version: xmlChar string giving the version of XML "1.0"
502 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000503 * Creates a new XML document
504 *
Owen Taylor3473f882001-02-23 17:55:21 +0000505 * Returns a new document
506 */
507xmlDocPtr
508xmlNewDoc(const xmlChar *version) {
509 xmlDocPtr cur;
510
511 if (version == NULL)
512 version = (const xmlChar *) "1.0";
513
514 /*
515 * Allocate a new document and fill the fields.
516 */
517 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
518 if (cur == NULL) {
519 xmlGenericError(xmlGenericErrorContext,
520 "xmlNewDoc : malloc failed\n");
521 return(NULL);
522 }
523 memset(cur, 0, sizeof(xmlDoc));
524 cur->type = XML_DOCUMENT_NODE;
525
526 cur->version = xmlStrdup(version);
527 cur->standalone = -1;
528 cur->compression = -1; /* not initialized */
529 cur->doc = cur;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000530 cur->charset = XML_CHAR_ENCODING_UTF8;
Owen Taylor3473f882001-02-23 17:55:21 +0000531 return(cur);
532}
533
534/**
535 * xmlFreeDoc:
536 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +0000537 *
538 * Free up all the structures used by a document, tree included.
539 */
540void
541xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000542 xmlDtdPtr extSubset, intSubset;
543
Owen Taylor3473f882001-02-23 17:55:21 +0000544 if (cur == NULL) {
545#ifdef DEBUG_TREE
546 xmlGenericError(xmlGenericErrorContext,
547 "xmlFreeDoc : document == NULL\n");
548#endif
549 return;
550 }
Daniel Veillard76d66f42001-05-16 21:05:17 +0000551 /*
552 * Do this before freeing the children list to avoid ID lookups
553 */
554 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
555 cur->ids = NULL;
556 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
557 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000558 extSubset = cur->extSubset;
559 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +0000560 if (intSubset == extSubset)
561 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000562 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000563 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000564 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000565 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000566 }
Daniel Veillarda9142e72001-06-19 11:07:54 +0000567 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000568 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000569 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000570 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000571 }
572
573 if (cur->children != NULL) xmlFreeNodeList(cur->children);
574
Owen Taylor3473f882001-02-23 17:55:21 +0000575 if (cur->version != NULL) xmlFree((char *) cur->version);
576 if (cur->name != NULL) xmlFree((char *) cur->name);
577 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +0000578 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +0000579 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000580 xmlFree(cur);
581}
582
583/**
584 * xmlStringLenGetNodeList:
585 * @doc: the document
586 * @value: the value of the text
587 * @len: the length of the string value
588 *
589 * Parse the value string and build the node list associated. Should
590 * produce a flat tree with only TEXTs and ENTITY_REFs.
591 * Returns a pointer to the first child
592 */
593xmlNodePtr
594xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
595 xmlNodePtr ret = NULL, last = NULL;
596 xmlNodePtr node;
597 xmlChar *val;
598 const xmlChar *cur = value;
599 const xmlChar *q;
600 xmlEntityPtr ent;
601
602 if (value == NULL) return(NULL);
603
604 q = cur;
605 while ((*cur != 0) && (cur - value < len)) {
606 if (*cur == '&') {
607 /*
608 * Save the current text.
609 */
610 if (cur != q) {
611 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
612 xmlNodeAddContentLen(last, q, cur - q);
613 } else {
614 node = xmlNewDocTextLen(doc, q, cur - q);
615 if (node == NULL) return(ret);
616 if (last == NULL)
617 last = ret = node;
618 else {
619 last->next = node;
620 node->prev = last;
621 last = node;
622 }
623 }
624 }
625 /*
626 * Read the entity string
627 */
628 cur++;
629 q = cur;
630 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
631 if ((*cur == 0) || (cur - value >= len)) {
632#ifdef DEBUG_TREE
633 xmlGenericError(xmlGenericErrorContext,
634 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
635#endif
636 return(ret);
637 }
638 if (cur != q) {
639 /*
640 * Predefined entities don't generate nodes
641 */
642 val = xmlStrndup(q, cur - q);
643 ent = xmlGetDocEntity(doc, val);
644 if ((ent != NULL) &&
645 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
646 if (last == NULL) {
647 node = xmlNewDocText(doc, ent->content);
648 last = ret = node;
649 } else
650 xmlNodeAddContent(last, ent->content);
651
652 } else {
653 /*
654 * Create a new REFERENCE_REF node
655 */
656 node = xmlNewReference(doc, val);
657 if (node == NULL) {
658 if (val != NULL) xmlFree(val);
659 return(ret);
660 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000661 else if ((ent != NULL) && (ent->children == NULL)) {
662 xmlNodePtr tmp;
663
664 ent->children =
665 xmlStringGetNodeList(doc, (const xmlChar*)node->content);
666 tmp = ent->children;
667 while (tmp) {
668 tmp->parent = (xmlNodePtr)ent;
669 tmp = tmp->next;
670 }
671 }
Owen Taylor3473f882001-02-23 17:55:21 +0000672 if (last == NULL)
673 last = ret = node;
674 else {
675 last->next = node;
676 node->prev = last;
677 last = node;
678 }
679 }
680 xmlFree(val);
681 }
682 cur++;
683 q = cur;
684 } else
685 cur++;
686 }
687 if (cur != q) {
688 /*
689 * Handle the last piece of text.
690 */
691 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
692 xmlNodeAddContentLen(last, q, cur - q);
693 } else {
694 node = xmlNewDocTextLen(doc, q, cur - q);
695 if (node == NULL) return(ret);
696 if (last == NULL)
697 last = ret = node;
698 else {
699 last->next = node;
700 node->prev = last;
701 last = node;
702 }
703 }
704 }
705 return(ret);
706}
707
708/**
709 * xmlStringGetNodeList:
710 * @doc: the document
711 * @value: the value of the attribute
712 *
713 * Parse the value string and build the node list associated. Should
714 * produce a flat tree with only TEXTs and ENTITY_REFs.
715 * Returns a pointer to the first child
716 */
717xmlNodePtr
718xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
719 xmlNodePtr ret = NULL, last = NULL;
720 xmlNodePtr node;
721 xmlChar *val;
722 const xmlChar *cur = value;
723 const xmlChar *q;
724 xmlEntityPtr ent;
725
726 if (value == NULL) return(NULL);
727
728 q = cur;
729 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000730 if (cur[0] == '&') {
731 int charval = 0;
732 xmlChar tmp;
733
Owen Taylor3473f882001-02-23 17:55:21 +0000734 /*
735 * Save the current text.
736 */
737 if (cur != q) {
738 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
739 xmlNodeAddContentLen(last, q, cur - q);
740 } else {
741 node = xmlNewDocTextLen(doc, q, cur - q);
742 if (node == NULL) return(ret);
743 if (last == NULL)
744 last = ret = node;
745 else {
746 last->next = node;
747 node->prev = last;
748 last = node;
749 }
750 }
751 }
Owen Taylor3473f882001-02-23 17:55:21 +0000752 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000753 if ((cur[1] == '#') && (cur[2] == 'x')) {
754 cur += 3;
755 tmp = *cur;
756 while (tmp != ';') { /* Non input consuming loop */
757 if ((tmp >= '0') && (tmp <= '9'))
758 charval = charval * 16 + (tmp - '0');
759 else if ((tmp >= 'a') && (tmp <= 'f'))
760 charval = charval * 16 + (tmp - 'a') + 10;
761 else if ((tmp >= 'A') && (tmp <= 'F'))
762 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +0000763 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000764 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000765 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000766 charval = 0;
767 break;
768 }
769 cur++;
770 tmp = *cur;
771 }
772 if (tmp == ';')
773 cur++;
774 q = cur;
775 } else if (cur[1] == '#') {
776 cur += 2;
777 tmp = *cur;
778 while (tmp != ';') { /* Non input consuming loops */
779 if ((tmp >= '0') && (tmp <= '9'))
780 charval = charval * 10 + (tmp - '0');
781 else {
782 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000783 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000784 charval = 0;
785 break;
786 }
787 cur++;
788 tmp = *cur;
789 }
790 if (tmp == ';')
791 cur++;
792 q = cur;
793 } else {
794 /*
795 * Read the entity string
796 */
797 cur++;
798 q = cur;
799 while ((*cur != 0) && (*cur != ';')) cur++;
800 if (*cur == 0) {
801#ifdef DEBUG_TREE
802 xmlGenericError(xmlGenericErrorContext,
803 "xmlStringGetNodeList: unterminated entity %30s\n", q);
804#endif
805 return(ret);
806 }
807 if (cur != q) {
808 /*
809 * Predefined entities don't generate nodes
810 */
811 val = xmlStrndup(q, cur - q);
812 ent = xmlGetDocEntity(doc, val);
813 if ((ent != NULL) &&
814 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
815 if (last == NULL) {
816 node = xmlNewDocText(doc, ent->content);
817 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +0000818 } else if (last->type != XML_TEXT_NODE) {
819 node = xmlNewDocText(doc, ent->content);
820 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000821 } else
822 xmlNodeAddContent(last, ent->content);
823
824 } else {
825 /*
826 * Create a new REFERENCE_REF node
827 */
828 node = xmlNewReference(doc, val);
829 if (node == NULL) {
830 if (val != NULL) xmlFree(val);
831 return(ret);
832 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000833 else if ((ent != NULL) && (ent->children == NULL)) {
834 xmlNodePtr temp;
835
836 ent->children = xmlStringGetNodeList(doc,
837 (const xmlChar*)node->content);
838 temp = ent->children;
839 while (temp) {
840 temp->parent = (xmlNodePtr)ent;
841 temp = temp->next;
842 }
843 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000844 if (last == NULL) {
845 last = ret = node;
846 } else {
847 last = xmlAddNextSibling(last, node);
848 }
849 }
850 xmlFree(val);
851 }
852 cur++;
853 q = cur;
854 }
855 if (charval != 0) {
856 xmlChar buf[10];
857 int len;
858
859 len = xmlCopyCharMultiByte(buf, charval);
860 buf[len] = 0;
861 node = xmlNewDocText(doc, buf);
862 if (node != NULL) {
863 if (last == NULL) {
864 last = ret = node;
865 } else {
866 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000867 }
868 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000869
870 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000871 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000872 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000873 cur++;
874 }
Daniel Veillard75bea542001-05-11 17:41:21 +0000875 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000876 /*
877 * Handle the last piece of text.
878 */
879 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
880 xmlNodeAddContentLen(last, q, cur - q);
881 } else {
882 node = xmlNewDocTextLen(doc, q, cur - q);
883 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000884 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000885 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000886 } else {
887 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000888 }
889 }
890 }
891 return(ret);
892}
893
894/**
895 * xmlNodeListGetString:
896 * @doc: the document
897 * @list: a Node list
898 * @inLine: should we replace entity contents or show their external form
899 *
900 * Returns the string equivalent to the text contained in the Node list
901 * made of TEXTs and ENTITY_REFs
Daniel Veillardbd9afb52002-09-25 22:25:35 +0000902 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +0000903 */
904xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +0000905xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
906{
Owen Taylor3473f882001-02-23 17:55:21 +0000907 xmlNodePtr node = list;
908 xmlChar *ret = NULL;
909 xmlEntityPtr ent;
910
Daniel Veillard7646b182002-04-20 06:41:40 +0000911 if (list == NULL)
912 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000913
914 while (node != NULL) {
915 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +0000916 (node->type == XML_CDATA_SECTION_NODE)) {
917 if (inLine) {
918 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000919 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +0000920 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +0000921
Daniel Veillard7646b182002-04-20 06:41:40 +0000922 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
923 if (buffer != NULL) {
924 ret = xmlStrcat(ret, buffer);
925 xmlFree(buffer);
926 }
927 }
928 } else if (node->type == XML_ENTITY_REF_NODE) {
929 if (inLine) {
930 ent = xmlGetDocEntity(doc, node->name);
931 if (ent != NULL) {
932 xmlChar *buffer;
933
934 /* an entity content can be any "well balanced chunk",
935 * i.e. the result of the content [43] production:
936 * http://www.w3.org/TR/REC-xml#NT-content.
937 * So it can contain text, CDATA section or nested
938 * entity reference nodes (among others).
939 * -> we recursive call xmlNodeListGetString()
940 * which handles these types */
941 buffer = xmlNodeListGetString(doc, ent->children, 1);
942 if (buffer != NULL) {
943 ret = xmlStrcat(ret, buffer);
944 xmlFree(buffer);
945 }
946 } else {
947 ret = xmlStrcat(ret, node->content);
948 }
949 } else {
950 xmlChar buf[2];
951
952 buf[0] = '&';
953 buf[1] = 0;
954 ret = xmlStrncat(ret, buf, 1);
955 ret = xmlStrcat(ret, node->name);
956 buf[0] = ';';
957 buf[1] = 0;
958 ret = xmlStrncat(ret, buf, 1);
959 }
960 }
961#if 0
962 else {
963 xmlGenericError(xmlGenericErrorContext,
964 "xmlGetNodeListString : invalid node type %d\n",
965 node->type);
966 }
967#endif
968 node = node->next;
969 }
970 return (ret);
971}
Owen Taylor3473f882001-02-23 17:55:21 +0000972/**
973 * xmlNodeListGetRawString:
974 * @doc: the document
975 * @list: a Node list
976 * @inLine: should we replace entity contents or show their external form
977 *
978 * Returns the string equivalent to the text contained in the Node list
979 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
980 * this function doesn't do any character encoding handling.
981 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +0000982 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +0000983 */
984xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +0000985xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
986{
Owen Taylor3473f882001-02-23 17:55:21 +0000987 xmlNodePtr node = list;
988 xmlChar *ret = NULL;
989 xmlEntityPtr ent;
990
Daniel Veillard7646b182002-04-20 06:41:40 +0000991 if (list == NULL)
992 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000993
994 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +0000995 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +0000996 (node->type == XML_CDATA_SECTION_NODE)) {
997 if (inLine) {
998 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000999 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001000 xmlChar *buffer;
1001
1002 buffer = xmlEncodeSpecialChars(doc, node->content);
1003 if (buffer != NULL) {
1004 ret = xmlStrcat(ret, buffer);
1005 xmlFree(buffer);
1006 }
1007 }
1008 } else if (node->type == XML_ENTITY_REF_NODE) {
1009 if (inLine) {
1010 ent = xmlGetDocEntity(doc, node->name);
1011 if (ent != NULL) {
1012 xmlChar *buffer;
1013
1014 /* an entity content can be any "well balanced chunk",
1015 * i.e. the result of the content [43] production:
1016 * http://www.w3.org/TR/REC-xml#NT-content.
1017 * So it can contain text, CDATA section or nested
1018 * entity reference nodes (among others).
1019 * -> we recursive call xmlNodeListGetRawString()
1020 * which handles these types */
1021 buffer =
1022 xmlNodeListGetRawString(doc, ent->children, 1);
1023 if (buffer != NULL) {
1024 ret = xmlStrcat(ret, buffer);
1025 xmlFree(buffer);
1026 }
1027 } else {
1028 ret = xmlStrcat(ret, node->content);
1029 }
1030 } else {
1031 xmlChar buf[2];
1032
1033 buf[0] = '&';
1034 buf[1] = 0;
1035 ret = xmlStrncat(ret, buf, 1);
1036 ret = xmlStrcat(ret, node->name);
1037 buf[0] = ';';
1038 buf[1] = 0;
1039 ret = xmlStrncat(ret, buf, 1);
1040 }
1041 }
Owen Taylor3473f882001-02-23 17:55:21 +00001042#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001043 else {
1044 xmlGenericError(xmlGenericErrorContext,
1045 "xmlGetNodeListString : invalid node type %d\n",
1046 node->type);
1047 }
Owen Taylor3473f882001-02-23 17:55:21 +00001048#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001049 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001050 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001051 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001052}
1053
1054/**
1055 * xmlNewProp:
1056 * @node: the holding node
1057 * @name: the name of the attribute
1058 * @value: the value of the attribute
1059 *
1060 * Create a new property carried by a node.
1061 * Returns a pointer to the attribute
1062 */
1063xmlAttrPtr
1064xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1065 xmlAttrPtr cur;
1066 xmlDocPtr doc = NULL;
1067
1068 if (name == NULL) {
1069#ifdef DEBUG_TREE
1070 xmlGenericError(xmlGenericErrorContext,
1071 "xmlNewProp : name == NULL\n");
1072#endif
1073 return(NULL);
1074 }
1075
1076 /*
1077 * Allocate a new property and fill the fields.
1078 */
1079 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1080 if (cur == NULL) {
1081 xmlGenericError(xmlGenericErrorContext,
1082 "xmlNewProp : malloc failed\n");
1083 return(NULL);
1084 }
1085 memset(cur, 0, sizeof(xmlAttr));
1086 cur->type = XML_ATTRIBUTE_NODE;
1087
1088 cur->parent = node;
1089 if (node != NULL) {
1090 doc = node->doc;
1091 cur->doc = doc;
1092 }
1093 cur->name = xmlStrdup(name);
1094 if (value != NULL) {
1095 xmlChar *buffer;
1096 xmlNodePtr tmp;
1097
1098 buffer = xmlEncodeEntitiesReentrant(doc, value);
1099 cur->children = xmlStringGetNodeList(doc, buffer);
1100 cur->last = NULL;
1101 tmp = cur->children;
1102 while (tmp != NULL) {
1103 tmp->parent = (xmlNodePtr) cur;
1104 tmp->doc = doc;
1105 if (tmp->next == NULL)
1106 cur->last = tmp;
1107 tmp = tmp->next;
1108 }
1109 xmlFree(buffer);
1110 }
1111
1112 /*
1113 * Add it at the end to preserve parsing order ...
1114 */
1115 if (node != NULL) {
1116 if (node->properties == NULL) {
1117 node->properties = cur;
1118 } else {
1119 xmlAttrPtr prev = node->properties;
1120
1121 while (prev->next != NULL) prev = prev->next;
1122 prev->next = cur;
1123 cur->prev = prev;
1124 }
1125 }
1126 return(cur);
1127}
1128
1129/**
1130 * xmlNewNsProp:
1131 * @node: the holding node
1132 * @ns: the namespace
1133 * @name: the name of the attribute
1134 * @value: the value of the attribute
1135 *
1136 * Create a new property tagged with a namespace and carried by a node.
1137 * Returns a pointer to the attribute
1138 */
1139xmlAttrPtr
1140xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1141 const xmlChar *value) {
1142 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001143 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001144
1145 if (name == NULL) {
1146#ifdef DEBUG_TREE
1147 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001148 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001149#endif
1150 return(NULL);
1151 }
1152
1153 /*
1154 * Allocate a new property and fill the fields.
1155 */
1156 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1157 if (cur == NULL) {
1158 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001159 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001160 return(NULL);
1161 }
1162 memset(cur, 0, sizeof(xmlAttr));
1163 cur->type = XML_ATTRIBUTE_NODE;
1164
1165 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001166 if (node != NULL) {
1167 doc = node->doc;
1168 cur->doc = doc;
1169 }
Owen Taylor3473f882001-02-23 17:55:21 +00001170 cur->ns = ns;
1171 cur->name = xmlStrdup(name);
1172 if (value != NULL) {
1173 xmlChar *buffer;
1174 xmlNodePtr tmp;
1175
Daniel Veillarda682b212001-06-07 19:59:42 +00001176 buffer = xmlEncodeEntitiesReentrant(doc, value);
1177 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001178 cur->last = NULL;
1179 tmp = cur->children;
1180 while (tmp != NULL) {
1181 tmp->parent = (xmlNodePtr) cur;
1182 if (tmp->next == NULL)
1183 cur->last = tmp;
1184 tmp = tmp->next;
1185 }
1186 xmlFree(buffer);
1187 }
1188
1189 /*
1190 * Add it at the end to preserve parsing order ...
1191 */
1192 if (node != NULL) {
1193 if (node->properties == NULL) {
1194 node->properties = cur;
1195 } else {
1196 xmlAttrPtr prev = node->properties;
1197
1198 while (prev->next != NULL) prev = prev->next;
1199 prev->next = cur;
1200 cur->prev = prev;
1201 }
1202 }
1203 return(cur);
1204}
1205
1206/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001207 * xmlNewNsPropEatName:
1208 * @node: the holding node
1209 * @ns: the namespace
1210 * @name: the name of the attribute
1211 * @value: the value of the attribute
1212 *
1213 * Create a new property tagged with a namespace and carried by a node.
1214 * Returns a pointer to the attribute
1215 */
1216xmlAttrPtr
1217xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1218 const xmlChar *value) {
1219 xmlAttrPtr cur;
1220 xmlDocPtr doc = NULL;
1221
1222 if (name == NULL) {
1223#ifdef DEBUG_TREE
1224 xmlGenericError(xmlGenericErrorContext,
1225 "xmlNewNsPropEatName : name == NULL\n");
1226#endif
1227 return(NULL);
1228 }
1229
1230 /*
1231 * Allocate a new property and fill the fields.
1232 */
1233 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1234 if (cur == NULL) {
1235 xmlGenericError(xmlGenericErrorContext,
1236 "xmlNewNsPropEatName : malloc failed\n");
1237 return(NULL);
1238 }
1239 memset(cur, 0, sizeof(xmlAttr));
1240 cur->type = XML_ATTRIBUTE_NODE;
1241
1242 cur->parent = node;
1243 if (node != NULL) {
1244 doc = node->doc;
1245 cur->doc = doc;
1246 }
1247 cur->ns = ns;
1248 cur->name = name;
1249 if (value != NULL) {
1250 xmlChar *buffer;
1251 xmlNodePtr tmp;
1252
1253 buffer = xmlEncodeEntitiesReentrant(doc, value);
1254 cur->children = xmlStringGetNodeList(doc, buffer);
1255 cur->last = NULL;
1256 tmp = cur->children;
1257 while (tmp != NULL) {
1258 tmp->parent = (xmlNodePtr) cur;
1259 if (tmp->next == NULL)
1260 cur->last = tmp;
1261 tmp = tmp->next;
1262 }
1263 xmlFree(buffer);
1264 }
1265
1266 /*
1267 * Add it at the end to preserve parsing order ...
1268 */
1269 if (node != NULL) {
1270 if (node->properties == NULL) {
1271 node->properties = cur;
1272 } else {
1273 xmlAttrPtr prev = node->properties;
1274
1275 while (prev->next != NULL) prev = prev->next;
1276 prev->next = cur;
1277 cur->prev = prev;
1278 }
1279 }
1280 return(cur);
1281}
1282
1283/**
Owen Taylor3473f882001-02-23 17:55:21 +00001284 * xmlNewDocProp:
1285 * @doc: the document
1286 * @name: the name of the attribute
1287 * @value: the value of the attribute
1288 *
1289 * Create a new property carried by a document.
1290 * Returns a pointer to the attribute
1291 */
1292xmlAttrPtr
1293xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1294 xmlAttrPtr cur;
1295
1296 if (name == NULL) {
1297#ifdef DEBUG_TREE
1298 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001299 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001300#endif
1301 return(NULL);
1302 }
1303
1304 /*
1305 * Allocate a new property and fill the fields.
1306 */
1307 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1308 if (cur == NULL) {
1309 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001310 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001311 return(NULL);
1312 }
1313 memset(cur, 0, sizeof(xmlAttr));
1314 cur->type = XML_ATTRIBUTE_NODE;
1315
1316 cur->name = xmlStrdup(name);
1317 cur->doc = doc;
1318 if (value != NULL) {
1319 xmlNodePtr tmp;
1320
1321 cur->children = xmlStringGetNodeList(doc, value);
1322 cur->last = NULL;
1323
1324 tmp = cur->children;
1325 while (tmp != NULL) {
1326 tmp->parent = (xmlNodePtr) cur;
1327 if (tmp->next == NULL)
1328 cur->last = tmp;
1329 tmp = tmp->next;
1330 }
1331 }
1332 return(cur);
1333}
1334
1335/**
1336 * xmlFreePropList:
1337 * @cur: the first property in the list
1338 *
1339 * Free a property and all its siblings, all the children are freed too.
1340 */
1341void
1342xmlFreePropList(xmlAttrPtr cur) {
1343 xmlAttrPtr next;
1344 if (cur == NULL) {
1345#ifdef DEBUG_TREE
1346 xmlGenericError(xmlGenericErrorContext,
1347 "xmlFreePropList : property == NULL\n");
1348#endif
1349 return;
1350 }
1351 while (cur != NULL) {
1352 next = cur->next;
1353 xmlFreeProp(cur);
1354 cur = next;
1355 }
1356}
1357
1358/**
1359 * xmlFreeProp:
1360 * @cur: an attribute
1361 *
1362 * Free one attribute, all the content is freed too
1363 */
1364void
1365xmlFreeProp(xmlAttrPtr cur) {
1366 if (cur == NULL) {
1367#ifdef DEBUG_TREE
1368 xmlGenericError(xmlGenericErrorContext,
1369 "xmlFreeProp : property == NULL\n");
1370#endif
1371 return;
1372 }
1373 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001374 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1375 ((cur->parent->doc->intSubset != NULL) ||
1376 (cur->parent->doc->extSubset != NULL))) {
1377 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1378 xmlRemoveID(cur->parent->doc, cur);
1379 }
Owen Taylor3473f882001-02-23 17:55:21 +00001380 if (cur->name != NULL) xmlFree((char *) cur->name);
1381 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001382 xmlFree(cur);
1383}
1384
1385/**
1386 * xmlRemoveProp:
1387 * @cur: an attribute
1388 *
1389 * Unlink and free one attribute, all the content is freed too
1390 * Note this doesn't work for namespace definition attributes
1391 *
1392 * Returns 0 if success and -1 in case of error.
1393 */
1394int
1395xmlRemoveProp(xmlAttrPtr cur) {
1396 xmlAttrPtr tmp;
1397 if (cur == NULL) {
1398#ifdef DEBUG_TREE
1399 xmlGenericError(xmlGenericErrorContext,
1400 "xmlRemoveProp : cur == NULL\n");
1401#endif
1402 return(-1);
1403 }
1404 if (cur->parent == NULL) {
1405#ifdef DEBUG_TREE
1406 xmlGenericError(xmlGenericErrorContext,
1407 "xmlRemoveProp : cur->parent == NULL\n");
1408#endif
1409 return(-1);
1410 }
1411 tmp = cur->parent->properties;
1412 if (tmp == cur) {
1413 cur->parent->properties = cur->next;
1414 xmlFreeProp(cur);
1415 return(0);
1416 }
1417 while (tmp != NULL) {
1418 if (tmp->next == cur) {
1419 tmp->next = cur->next;
1420 if (tmp->next != NULL)
1421 tmp->next->prev = tmp;
1422 xmlFreeProp(cur);
1423 return(0);
1424 }
1425 tmp = tmp->next;
1426 }
1427#ifdef DEBUG_TREE
1428 xmlGenericError(xmlGenericErrorContext,
1429 "xmlRemoveProp : attribute not owned by its node\n");
1430#endif
1431 return(-1);
1432}
1433
1434/**
1435 * xmlNewPI:
1436 * @name: the processing instruction name
1437 * @content: the PI content
1438 *
1439 * Creation of a processing instruction element.
1440 * Returns a pointer to the new node object.
1441 */
1442xmlNodePtr
1443xmlNewPI(const xmlChar *name, const xmlChar *content) {
1444 xmlNodePtr cur;
1445
1446 if (name == NULL) {
1447#ifdef DEBUG_TREE
1448 xmlGenericError(xmlGenericErrorContext,
1449 "xmlNewPI : name == NULL\n");
1450#endif
1451 return(NULL);
1452 }
1453
1454 /*
1455 * Allocate a new node and fill the fields.
1456 */
1457 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1458 if (cur == NULL) {
1459 xmlGenericError(xmlGenericErrorContext,
1460 "xmlNewPI : malloc failed\n");
1461 return(NULL);
1462 }
1463 memset(cur, 0, sizeof(xmlNode));
1464 cur->type = XML_PI_NODE;
1465
1466 cur->name = xmlStrdup(name);
1467 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001468 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001469 }
1470 return(cur);
1471}
1472
1473/**
1474 * xmlNewNode:
1475 * @ns: namespace if any
1476 * @name: the node name
1477 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001478 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001479 *
1480 * Returns a pointer to the new node object.
1481 */
1482xmlNodePtr
1483xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1484 xmlNodePtr cur;
1485
1486 if (name == NULL) {
1487#ifdef DEBUG_TREE
1488 xmlGenericError(xmlGenericErrorContext,
1489 "xmlNewNode : name == NULL\n");
1490#endif
1491 return(NULL);
1492 }
1493
1494 /*
1495 * Allocate a new node and fill the fields.
1496 */
1497 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1498 if (cur == NULL) {
1499 xmlGenericError(xmlGenericErrorContext,
1500 "xmlNewNode : malloc failed\n");
1501 return(NULL);
1502 }
1503 memset(cur, 0, sizeof(xmlNode));
1504 cur->type = XML_ELEMENT_NODE;
1505
1506 cur->name = xmlStrdup(name);
1507 cur->ns = ns;
1508 return(cur);
1509}
1510
1511/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001512 * xmlNewNodeEatName:
1513 * @ns: namespace if any
1514 * @name: the node name
1515 *
1516 * Creation of a new node element. @ns is optional (NULL).
1517 *
1518 * Returns a pointer to the new node object.
1519 */
1520xmlNodePtr
1521xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
1522 xmlNodePtr cur;
1523
1524 if (name == NULL) {
1525#ifdef DEBUG_TREE
1526 xmlGenericError(xmlGenericErrorContext,
1527 "xmlNewNode : name == NULL\n");
1528#endif
1529 return(NULL);
1530 }
1531
1532 /*
1533 * Allocate a new node and fill the fields.
1534 */
1535 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1536 if (cur == NULL) {
1537 xmlGenericError(xmlGenericErrorContext,
1538 "xmlNewNode : malloc failed\n");
1539 return(NULL);
1540 }
1541 memset(cur, 0, sizeof(xmlNode));
1542 cur->type = XML_ELEMENT_NODE;
1543
1544 cur->name = name;
1545 cur->ns = ns;
1546 return(cur);
1547}
1548
1549/**
Owen Taylor3473f882001-02-23 17:55:21 +00001550 * xmlNewDocNode:
1551 * @doc: the document
1552 * @ns: namespace if any
1553 * @name: the node name
1554 * @content: the XML text content if any
1555 *
1556 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001557 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001558 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1559 * references, but XML special chars need to be escaped first by using
1560 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1561 * need entities support.
1562 *
1563 * Returns a pointer to the new node object.
1564 */
1565xmlNodePtr
1566xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1567 const xmlChar *name, const xmlChar *content) {
1568 xmlNodePtr cur;
1569
1570 cur = xmlNewNode(ns, name);
1571 if (cur != NULL) {
1572 cur->doc = doc;
1573 if (content != NULL) {
1574 cur->children = xmlStringGetNodeList(doc, content);
1575 UPDATE_LAST_CHILD_AND_PARENT(cur)
1576 }
1577 }
1578 return(cur);
1579}
1580
Daniel Veillard46de64e2002-05-29 08:21:33 +00001581/**
1582 * xmlNewDocNodeEatName:
1583 * @doc: the document
1584 * @ns: namespace if any
1585 * @name: the node name
1586 * @content: the XML text content if any
1587 *
1588 * Creation of a new node element within a document. @ns and @content
1589 * are optional (NULL).
1590 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1591 * references, but XML special chars need to be escaped first by using
1592 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1593 * need entities support.
1594 *
1595 * Returns a pointer to the new node object.
1596 */
1597xmlNodePtr
1598xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
1599 xmlChar *name, const xmlChar *content) {
1600 xmlNodePtr cur;
1601
1602 cur = xmlNewNodeEatName(ns, name);
1603 if (cur != NULL) {
1604 cur->doc = doc;
1605 if (content != NULL) {
1606 cur->children = xmlStringGetNodeList(doc, content);
1607 UPDATE_LAST_CHILD_AND_PARENT(cur)
1608 }
1609 }
1610 return(cur);
1611}
1612
Owen Taylor3473f882001-02-23 17:55:21 +00001613
1614/**
1615 * xmlNewDocRawNode:
1616 * @doc: the document
1617 * @ns: namespace if any
1618 * @name: the node name
1619 * @content: the text content if any
1620 *
1621 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001622 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001623 *
1624 * Returns a pointer to the new node object.
1625 */
1626xmlNodePtr
1627xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1628 const xmlChar *name, const xmlChar *content) {
1629 xmlNodePtr cur;
1630
1631 cur = xmlNewNode(ns, name);
1632 if (cur != NULL) {
1633 cur->doc = doc;
1634 if (content != NULL) {
1635 cur->children = xmlNewDocText(doc, content);
1636 UPDATE_LAST_CHILD_AND_PARENT(cur)
1637 }
1638 }
1639 return(cur);
1640}
1641
1642/**
1643 * xmlNewDocFragment:
1644 * @doc: the document owning the fragment
1645 *
1646 * Creation of a new Fragment node.
1647 * Returns a pointer to the new node object.
1648 */
1649xmlNodePtr
1650xmlNewDocFragment(xmlDocPtr doc) {
1651 xmlNodePtr cur;
1652
1653 /*
1654 * Allocate a new DocumentFragment node and fill the fields.
1655 */
1656 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1657 if (cur == NULL) {
1658 xmlGenericError(xmlGenericErrorContext,
1659 "xmlNewDocFragment : malloc failed\n");
1660 return(NULL);
1661 }
1662 memset(cur, 0, sizeof(xmlNode));
1663 cur->type = XML_DOCUMENT_FRAG_NODE;
1664
1665 cur->doc = doc;
1666 return(cur);
1667}
1668
1669/**
1670 * xmlNewText:
1671 * @content: the text content
1672 *
1673 * Creation of a new text node.
1674 * Returns a pointer to the new node object.
1675 */
1676xmlNodePtr
1677xmlNewText(const xmlChar *content) {
1678 xmlNodePtr cur;
1679
1680 /*
1681 * Allocate a new node and fill the fields.
1682 */
1683 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1684 if (cur == NULL) {
1685 xmlGenericError(xmlGenericErrorContext,
1686 "xmlNewText : malloc failed\n");
1687 return(NULL);
1688 }
1689 memset(cur, 0, sizeof(xmlNode));
1690 cur->type = XML_TEXT_NODE;
1691
1692 cur->name = xmlStringText;
1693 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001694 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001695 }
1696 return(cur);
1697}
1698
1699/**
1700 * xmlNewTextChild:
1701 * @parent: the parent node
1702 * @ns: a namespace if any
1703 * @name: the name of the child
1704 * @content: the text content of the child if any.
1705 *
1706 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001707 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001708 * a child TEXT node will be created containing the string content.
1709 *
1710 * Returns a pointer to the new node object.
1711 */
1712xmlNodePtr
1713xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1714 const xmlChar *name, const xmlChar *content) {
1715 xmlNodePtr cur, prev;
1716
1717 if (parent == NULL) {
1718#ifdef DEBUG_TREE
1719 xmlGenericError(xmlGenericErrorContext,
1720 "xmlNewTextChild : parent == NULL\n");
1721#endif
1722 return(NULL);
1723 }
1724
1725 if (name == NULL) {
1726#ifdef DEBUG_TREE
1727 xmlGenericError(xmlGenericErrorContext,
1728 "xmlNewTextChild : name == NULL\n");
1729#endif
1730 return(NULL);
1731 }
1732
1733 /*
1734 * Allocate a new node
1735 */
1736 if (ns == NULL)
1737 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1738 else
1739 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1740 if (cur == NULL) return(NULL);
1741
1742 /*
1743 * add the new element at the end of the children list.
1744 */
1745 cur->type = XML_ELEMENT_NODE;
1746 cur->parent = parent;
1747 cur->doc = parent->doc;
1748 if (parent->children == NULL) {
1749 parent->children = cur;
1750 parent->last = cur;
1751 } else {
1752 prev = parent->last;
1753 prev->next = cur;
1754 cur->prev = prev;
1755 parent->last = cur;
1756 }
1757
1758 return(cur);
1759}
1760
1761/**
1762 * xmlNewCharRef:
1763 * @doc: the document
1764 * @name: the char ref string, starting with # or "&# ... ;"
1765 *
1766 * Creation of a new character reference node.
1767 * Returns a pointer to the new node object.
1768 */
1769xmlNodePtr
1770xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1771 xmlNodePtr cur;
1772
1773 /*
1774 * Allocate a new node and fill the fields.
1775 */
1776 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1777 if (cur == NULL) {
1778 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001779 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001780 return(NULL);
1781 }
1782 memset(cur, 0, sizeof(xmlNode));
1783 cur->type = XML_ENTITY_REF_NODE;
1784
1785 cur->doc = doc;
1786 if (name[0] == '&') {
1787 int len;
1788 name++;
1789 len = xmlStrlen(name);
1790 if (name[len - 1] == ';')
1791 cur->name = xmlStrndup(name, len - 1);
1792 else
1793 cur->name = xmlStrndup(name, len);
1794 } else
1795 cur->name = xmlStrdup(name);
1796 return(cur);
1797}
1798
1799/**
1800 * xmlNewReference:
1801 * @doc: the document
1802 * @name: the reference name, or the reference string with & and ;
1803 *
1804 * Creation of a new reference node.
1805 * Returns a pointer to the new node object.
1806 */
1807xmlNodePtr
1808xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1809 xmlNodePtr cur;
1810 xmlEntityPtr ent;
1811
1812 /*
1813 * Allocate a new node and fill the fields.
1814 */
1815 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1816 if (cur == NULL) {
1817 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001818 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001819 return(NULL);
1820 }
1821 memset(cur, 0, sizeof(xmlNode));
1822 cur->type = XML_ENTITY_REF_NODE;
1823
1824 cur->doc = doc;
1825 if (name[0] == '&') {
1826 int len;
1827 name++;
1828 len = xmlStrlen(name);
1829 if (name[len - 1] == ';')
1830 cur->name = xmlStrndup(name, len - 1);
1831 else
1832 cur->name = xmlStrndup(name, len);
1833 } else
1834 cur->name = xmlStrdup(name);
1835
1836 ent = xmlGetDocEntity(doc, cur->name);
1837 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001838 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00001839 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001840 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00001841 * updated. Not sure if this is 100% correct.
1842 * -George
1843 */
1844 cur->children = (xmlNodePtr) ent;
1845 cur->last = (xmlNodePtr) ent;
1846 }
1847 return(cur);
1848}
1849
1850/**
1851 * xmlNewDocText:
1852 * @doc: the document
1853 * @content: the text content
1854 *
1855 * Creation of a new text node within a document.
1856 * Returns a pointer to the new node object.
1857 */
1858xmlNodePtr
1859xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1860 xmlNodePtr cur;
1861
1862 cur = xmlNewText(content);
1863 if (cur != NULL) cur->doc = doc;
1864 return(cur);
1865}
1866
1867/**
1868 * xmlNewTextLen:
1869 * @content: the text content
1870 * @len: the text len.
1871 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001872 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00001873 * Returns a pointer to the new node object.
1874 */
1875xmlNodePtr
1876xmlNewTextLen(const xmlChar *content, int len) {
1877 xmlNodePtr cur;
1878
1879 /*
1880 * Allocate a new node and fill the fields.
1881 */
1882 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1883 if (cur == NULL) {
1884 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001885 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001886 return(NULL);
1887 }
1888 memset(cur, 0, sizeof(xmlNode));
1889 cur->type = XML_TEXT_NODE;
1890
1891 cur->name = xmlStringText;
1892 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001893 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001894 }
1895 return(cur);
1896}
1897
1898/**
1899 * xmlNewDocTextLen:
1900 * @doc: the document
1901 * @content: the text content
1902 * @len: the text len.
1903 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001904 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00001905 * text node pertain to a given document.
1906 * Returns a pointer to the new node object.
1907 */
1908xmlNodePtr
1909xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1910 xmlNodePtr cur;
1911
1912 cur = xmlNewTextLen(content, len);
1913 if (cur != NULL) cur->doc = doc;
1914 return(cur);
1915}
1916
1917/**
1918 * xmlNewComment:
1919 * @content: the comment content
1920 *
1921 * Creation of a new node containing a comment.
1922 * Returns a pointer to the new node object.
1923 */
1924xmlNodePtr
1925xmlNewComment(const xmlChar *content) {
1926 xmlNodePtr cur;
1927
1928 /*
1929 * Allocate a new node and fill the fields.
1930 */
1931 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1932 if (cur == NULL) {
1933 xmlGenericError(xmlGenericErrorContext,
1934 "xmlNewComment : malloc failed\n");
1935 return(NULL);
1936 }
1937 memset(cur, 0, sizeof(xmlNode));
1938 cur->type = XML_COMMENT_NODE;
1939
1940 cur->name = xmlStringComment;
1941 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001942 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001943 }
1944 return(cur);
1945}
1946
1947/**
1948 * xmlNewCDataBlock:
1949 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00001950 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00001951 * @len: the length of the block
1952 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001953 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00001954 * Returns a pointer to the new node object.
1955 */
1956xmlNodePtr
1957xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1958 xmlNodePtr cur;
1959
1960 /*
1961 * Allocate a new node and fill the fields.
1962 */
1963 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1964 if (cur == NULL) {
1965 xmlGenericError(xmlGenericErrorContext,
1966 "xmlNewCDataBlock : malloc failed\n");
1967 return(NULL);
1968 }
1969 memset(cur, 0, sizeof(xmlNode));
1970 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001971 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001972
1973 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001974 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001975 }
1976 return(cur);
1977}
1978
1979/**
1980 * xmlNewDocComment:
1981 * @doc: the document
1982 * @content: the comment content
1983 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001984 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00001985 * Returns a pointer to the new node object.
1986 */
1987xmlNodePtr
1988xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1989 xmlNodePtr cur;
1990
1991 cur = xmlNewComment(content);
1992 if (cur != NULL) cur->doc = doc;
1993 return(cur);
1994}
1995
1996/**
1997 * xmlSetTreeDoc:
1998 * @tree: the top element
1999 * @doc: the document
2000 *
2001 * update all nodes under the tree to point to the right document
2002 */
2003void
2004xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002005 xmlAttrPtr prop;
2006
Owen Taylor3473f882001-02-23 17:55:21 +00002007 if (tree == NULL)
2008 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002009 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002010 if(tree->type == XML_ELEMENT_NODE) {
2011 prop = tree->properties;
2012 while (prop != NULL) {
2013 prop->doc = doc;
2014 xmlSetListDoc(prop->children, doc);
2015 prop = prop->next;
2016 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002017 }
Owen Taylor3473f882001-02-23 17:55:21 +00002018 if (tree->children != NULL)
2019 xmlSetListDoc(tree->children, doc);
2020 tree->doc = doc;
2021 }
2022}
2023
2024/**
2025 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002026 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002027 * @doc: the document
2028 *
2029 * update all nodes in the list to point to the right document
2030 */
2031void
2032xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2033 xmlNodePtr cur;
2034
2035 if (list == NULL)
2036 return;
2037 cur = list;
2038 while (cur != NULL) {
2039 if (cur->doc != doc)
2040 xmlSetTreeDoc(cur, doc);
2041 cur = cur->next;
2042 }
2043}
2044
2045
2046/**
2047 * xmlNewChild:
2048 * @parent: the parent node
2049 * @ns: a namespace if any
2050 * @name: the name of the child
2051 * @content: the XML content of the child if any.
2052 *
2053 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002054 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002055 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2056 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2057 * references, but XML special chars need to be escaped first by using
2058 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2059 * support is not needed.
2060 *
2061 * Returns a pointer to the new node object.
2062 */
2063xmlNodePtr
2064xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2065 const xmlChar *name, const xmlChar *content) {
2066 xmlNodePtr cur, prev;
2067
2068 if (parent == NULL) {
2069#ifdef DEBUG_TREE
2070 xmlGenericError(xmlGenericErrorContext,
2071 "xmlNewChild : parent == NULL\n");
2072#endif
2073 return(NULL);
2074 }
2075
2076 if (name == NULL) {
2077#ifdef DEBUG_TREE
2078 xmlGenericError(xmlGenericErrorContext,
2079 "xmlNewChild : name == NULL\n");
2080#endif
2081 return(NULL);
2082 }
2083
2084 /*
2085 * Allocate a new node
2086 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002087 if (parent->type == XML_ELEMENT_NODE) {
2088 if (ns == NULL)
2089 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2090 else
2091 cur = xmlNewDocNode(parent->doc, ns, name, content);
2092 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2093 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2094 if (ns == NULL)
2095 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2096 else
2097 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
2098 } else {
2099 return(NULL);
2100 }
Owen Taylor3473f882001-02-23 17:55:21 +00002101 if (cur == NULL) return(NULL);
2102
2103 /*
2104 * add the new element at the end of the children list.
2105 */
2106 cur->type = XML_ELEMENT_NODE;
2107 cur->parent = parent;
2108 cur->doc = parent->doc;
2109 if (parent->children == NULL) {
2110 parent->children = cur;
2111 parent->last = cur;
2112 } else {
2113 prev = parent->last;
2114 prev->next = cur;
2115 cur->prev = prev;
2116 parent->last = cur;
2117 }
2118
2119 return(cur);
2120}
2121
2122/**
2123 * xmlAddNextSibling:
2124 * @cur: the child node
2125 * @elem: the new node
2126 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002127 * Add a new node @elem as the next sibling of @cur
2128 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002129 * first unlinked from its existing context.
2130 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002131 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2132 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002133 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002134 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002135 */
2136xmlNodePtr
2137xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2138 if (cur == NULL) {
2139#ifdef DEBUG_TREE
2140 xmlGenericError(xmlGenericErrorContext,
2141 "xmlAddNextSibling : cur == NULL\n");
2142#endif
2143 return(NULL);
2144 }
2145 if (elem == NULL) {
2146#ifdef DEBUG_TREE
2147 xmlGenericError(xmlGenericErrorContext,
2148 "xmlAddNextSibling : elem == NULL\n");
2149#endif
2150 return(NULL);
2151 }
2152
2153 xmlUnlinkNode(elem);
2154
2155 if (elem->type == XML_TEXT_NODE) {
2156 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002157 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002158 xmlFreeNode(elem);
2159 return(cur);
2160 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002161 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2162 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002163 xmlChar *tmp;
2164
2165 tmp = xmlStrdup(elem->content);
2166 tmp = xmlStrcat(tmp, cur->next->content);
2167 xmlNodeSetContent(cur->next, tmp);
2168 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002169 xmlFreeNode(elem);
2170 return(cur->next);
2171 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002172 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2173 /* check if an attribute with the same name exists */
2174 xmlAttrPtr attr;
2175
2176 if (elem->ns == NULL)
2177 attr = xmlHasProp(cur->parent, elem->name);
2178 else
2179 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2180 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2181 /* different instance, destroy it (attributes must be unique) */
2182 xmlFreeProp(attr);
2183 }
Owen Taylor3473f882001-02-23 17:55:21 +00002184 }
2185
2186 if (elem->doc != cur->doc) {
2187 xmlSetTreeDoc(elem, cur->doc);
2188 }
2189 elem->parent = cur->parent;
2190 elem->prev = cur;
2191 elem->next = cur->next;
2192 cur->next = elem;
2193 if (elem->next != NULL)
2194 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002195 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002196 elem->parent->last = elem;
2197 return(elem);
2198}
2199
2200/**
2201 * xmlAddPrevSibling:
2202 * @cur: the child node
2203 * @elem: the new node
2204 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002205 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002206 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002207 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002208 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002209 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2210 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002211 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002212 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002213 */
2214xmlNodePtr
2215xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2216 if (cur == NULL) {
2217#ifdef DEBUG_TREE
2218 xmlGenericError(xmlGenericErrorContext,
2219 "xmlAddPrevSibling : cur == NULL\n");
2220#endif
2221 return(NULL);
2222 }
2223 if (elem == NULL) {
2224#ifdef DEBUG_TREE
2225 xmlGenericError(xmlGenericErrorContext,
2226 "xmlAddPrevSibling : elem == NULL\n");
2227#endif
2228 return(NULL);
2229 }
2230
2231 xmlUnlinkNode(elem);
2232
2233 if (elem->type == XML_TEXT_NODE) {
2234 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002235 xmlChar *tmp;
2236
2237 tmp = xmlStrdup(elem->content);
2238 tmp = xmlStrcat(tmp, cur->content);
2239 xmlNodeSetContent(cur, tmp);
2240 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002241 xmlFreeNode(elem);
2242 return(cur);
2243 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002244 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2245 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002246 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002247 xmlFreeNode(elem);
2248 return(cur->prev);
2249 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002250 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2251 /* check if an attribute with the same name exists */
2252 xmlAttrPtr attr;
2253
2254 if (elem->ns == NULL)
2255 attr = xmlHasProp(cur->parent, elem->name);
2256 else
2257 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2258 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2259 /* different instance, destroy it (attributes must be unique) */
2260 xmlFreeProp(attr);
2261 }
Owen Taylor3473f882001-02-23 17:55:21 +00002262 }
2263
2264 if (elem->doc != cur->doc) {
2265 xmlSetTreeDoc(elem, cur->doc);
2266 }
2267 elem->parent = cur->parent;
2268 elem->next = cur;
2269 elem->prev = cur->prev;
2270 cur->prev = elem;
2271 if (elem->prev != NULL)
2272 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002273 if (elem->parent != NULL) {
2274 if (elem->type == XML_ATTRIBUTE_NODE) {
2275 if (elem->parent->properties == (xmlAttrPtr) cur) {
2276 elem->parent->properties = (xmlAttrPtr) elem;
2277 }
2278 } else {
2279 if (elem->parent->children == cur) {
2280 elem->parent->children = elem;
2281 }
2282 }
2283 }
Owen Taylor3473f882001-02-23 17:55:21 +00002284 return(elem);
2285}
2286
2287/**
2288 * xmlAddSibling:
2289 * @cur: the child node
2290 * @elem: the new node
2291 *
2292 * Add a new element @elem to the list of siblings of @cur
2293 * merging adjacent TEXT nodes (@elem may be freed)
2294 * If the new element was already inserted in a document it is
2295 * first unlinked from its existing context.
2296 *
2297 * Returns the new element or NULL in case of error.
2298 */
2299xmlNodePtr
2300xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2301 xmlNodePtr parent;
2302
2303 if (cur == NULL) {
2304#ifdef DEBUG_TREE
2305 xmlGenericError(xmlGenericErrorContext,
2306 "xmlAddSibling : cur == NULL\n");
2307#endif
2308 return(NULL);
2309 }
2310
2311 if (elem == NULL) {
2312#ifdef DEBUG_TREE
2313 xmlGenericError(xmlGenericErrorContext,
2314 "xmlAddSibling : elem == NULL\n");
2315#endif
2316 return(NULL);
2317 }
2318
2319 /*
2320 * Constant time is we can rely on the ->parent->last to find
2321 * the last sibling.
2322 */
2323 if ((cur->parent != NULL) &&
2324 (cur->parent->children != NULL) &&
2325 (cur->parent->last != NULL) &&
2326 (cur->parent->last->next == NULL)) {
2327 cur = cur->parent->last;
2328 } else {
2329 while (cur->next != NULL) cur = cur->next;
2330 }
2331
2332 xmlUnlinkNode(elem);
2333
2334 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002335 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002336 xmlFreeNode(elem);
2337 return(cur);
2338 }
2339
2340 if (elem->doc != cur->doc) {
2341 xmlSetTreeDoc(elem, cur->doc);
2342 }
2343 parent = cur->parent;
2344 elem->prev = cur;
2345 elem->next = NULL;
2346 elem->parent = parent;
2347 cur->next = elem;
2348 if (parent != NULL)
2349 parent->last = elem;
2350
2351 return(elem);
2352}
2353
2354/**
2355 * xmlAddChildList:
2356 * @parent: the parent node
2357 * @cur: the first node in the list
2358 *
2359 * Add a list of node at the end of the child list of the parent
2360 * merging adjacent TEXT nodes (@cur may be freed)
2361 *
2362 * Returns the last child or NULL in case of error.
2363 */
2364xmlNodePtr
2365xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2366 xmlNodePtr prev;
2367
2368 if (parent == NULL) {
2369#ifdef DEBUG_TREE
2370 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002371 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002372#endif
2373 return(NULL);
2374 }
2375
2376 if (cur == NULL) {
2377#ifdef DEBUG_TREE
2378 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002379 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002380#endif
2381 return(NULL);
2382 }
2383
2384 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2385 (cur->doc != parent->doc)) {
2386#ifdef DEBUG_TREE
2387 xmlGenericError(xmlGenericErrorContext,
2388 "Elements moved to a different document\n");
2389#endif
2390 }
2391
2392 /*
2393 * add the first element at the end of the children list.
2394 */
2395 if (parent->children == NULL) {
2396 parent->children = cur;
2397 } else {
2398 /*
2399 * If cur and parent->last both are TEXT nodes, then merge them.
2400 */
2401 if ((cur->type == XML_TEXT_NODE) &&
2402 (parent->last->type == XML_TEXT_NODE) &&
2403 (cur->name == parent->last->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002404 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002405 /*
2406 * if it's the only child, nothing more to be done.
2407 */
2408 if (cur->next == NULL) {
2409 xmlFreeNode(cur);
2410 return(parent->last);
2411 }
2412 prev = cur;
2413 cur = cur->next;
2414 xmlFreeNode(prev);
2415 }
2416 prev = parent->last;
2417 prev->next = cur;
2418 cur->prev = prev;
2419 }
2420 while (cur->next != NULL) {
2421 cur->parent = parent;
2422 if (cur->doc != parent->doc) {
2423 xmlSetTreeDoc(cur, parent->doc);
2424 }
2425 cur = cur->next;
2426 }
2427 cur->parent = parent;
2428 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2429 parent->last = cur;
2430
2431 return(cur);
2432}
2433
2434/**
2435 * xmlAddChild:
2436 * @parent: the parent node
2437 * @cur: the child node
2438 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002439 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002440 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002441 * If the new node was already inserted in a document it is
2442 * first unlinked from its existing context.
2443 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2444 * If there is an attribute with equal name, it is first destroyed.
2445 *
Owen Taylor3473f882001-02-23 17:55:21 +00002446 * Returns the child or NULL in case of error.
2447 */
2448xmlNodePtr
2449xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2450 xmlNodePtr prev;
2451
2452 if (parent == NULL) {
2453#ifdef DEBUG_TREE
2454 xmlGenericError(xmlGenericErrorContext,
2455 "xmlAddChild : parent == NULL\n");
2456#endif
2457 return(NULL);
2458 }
2459
2460 if (cur == NULL) {
2461#ifdef DEBUG_TREE
2462 xmlGenericError(xmlGenericErrorContext,
2463 "xmlAddChild : child == NULL\n");
2464#endif
2465 return(NULL);
2466 }
2467
Owen Taylor3473f882001-02-23 17:55:21 +00002468 /*
2469 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002470 * cur is then freed.
2471 */
2472 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002473 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002474 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002475 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002476 xmlFreeNode(cur);
2477 return(parent);
2478 }
2479 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2480 (parent->last->name == cur->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002481 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002482 xmlFreeNode(cur);
2483 return(parent->last);
2484 }
2485 }
2486
2487 /*
2488 * add the new element at the end of the children list.
2489 */
2490 cur->parent = parent;
2491 if (cur->doc != parent->doc) {
2492 xmlSetTreeDoc(cur, parent->doc);
2493 }
2494
2495 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002496 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002497 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002498 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002499 (parent->content != NULL)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002500 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002501 xmlFreeNode(cur);
2502 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002503 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002504 if (cur->type == XML_ATTRIBUTE_NODE) {
2505 if (parent->properties == NULL) {
2506 parent->properties = (xmlAttrPtr) cur;
2507 } else {
2508 /* check if an attribute with the same name exists */
2509 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002510
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002511 if (cur->ns == NULL)
2512 lastattr = xmlHasProp(parent, cur->name);
2513 else
2514 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2515 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2516 /* different instance, destroy it (attributes must be unique) */
2517 xmlFreeProp(lastattr);
2518 }
2519 /* find the end */
2520 lastattr = parent->properties;
2521 while (lastattr->next != NULL) {
2522 lastattr = lastattr->next;
2523 }
2524 lastattr->next = (xmlAttrPtr) cur;
2525 ((xmlAttrPtr) cur)->prev = lastattr;
2526 }
2527 } else {
2528 if (parent->children == NULL) {
2529 parent->children = cur;
2530 parent->last = cur;
2531 } else {
2532 prev = parent->last;
2533 prev->next = cur;
2534 cur->prev = prev;
2535 parent->last = cur;
2536 }
2537 }
Owen Taylor3473f882001-02-23 17:55:21 +00002538 return(cur);
2539}
2540
2541/**
2542 * xmlGetLastChild:
2543 * @parent: the parent node
2544 *
2545 * Search the last child of a node.
2546 * Returns the last child or NULL if none.
2547 */
2548xmlNodePtr
2549xmlGetLastChild(xmlNodePtr parent) {
2550 if (parent == NULL) {
2551#ifdef DEBUG_TREE
2552 xmlGenericError(xmlGenericErrorContext,
2553 "xmlGetLastChild : parent == NULL\n");
2554#endif
2555 return(NULL);
2556 }
2557 return(parent->last);
2558}
2559
2560/**
2561 * xmlFreeNodeList:
2562 * @cur: the first node in the list
2563 *
2564 * Free a node and all its siblings, this is a recursive behaviour, all
2565 * the children are freed too.
2566 */
2567void
2568xmlFreeNodeList(xmlNodePtr cur) {
2569 xmlNodePtr next;
2570 if (cur == NULL) {
2571#ifdef DEBUG_TREE
2572 xmlGenericError(xmlGenericErrorContext,
2573 "xmlFreeNodeList : node == NULL\n");
2574#endif
2575 return;
2576 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002577 if (cur->type == XML_NAMESPACE_DECL) {
2578 xmlFreeNsList((xmlNsPtr) cur);
2579 return;
2580 }
Owen Taylor3473f882001-02-23 17:55:21 +00002581 while (cur != NULL) {
2582 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002583 /* unroll to speed up freeing the document */
2584 if (cur->type != XML_DTD_NODE) {
2585 if ((cur->children != NULL) &&
2586 (cur->type != XML_ENTITY_REF_NODE))
2587 xmlFreeNodeList(cur->children);
2588 if (cur->properties != NULL)
2589 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002590 if ((cur->type != XML_ELEMENT_NODE) &&
2591 (cur->type != XML_XINCLUDE_START) &&
2592 (cur->type != XML_XINCLUDE_END) &&
2593 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002594 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002595 }
2596 if (((cur->type == XML_ELEMENT_NODE) ||
2597 (cur->type == XML_XINCLUDE_START) ||
2598 (cur->type == XML_XINCLUDE_END)) &&
2599 (cur->nsDef != NULL))
2600 xmlFreeNsList(cur->nsDef);
2601
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002602 /*
2603 * When a node is a text node or a comment, it uses a global static
2604 * variable for the name of the node.
2605 *
2606 * The xmlStrEqual comparisons need to be done when (happened with
2607 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002608 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002609 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002610 * the string addresses compare are not sufficient.
2611 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002612 if ((cur->name != NULL) &&
2613 (cur->name != xmlStringText) &&
2614 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002615 (cur->name != xmlStringComment)) {
2616 if (cur->type == XML_TEXT_NODE) {
2617 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2618 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2619 xmlFree((char *) cur->name);
2620 } else if (cur->type == XML_COMMENT_NODE) {
2621 if (!xmlStrEqual(cur->name, xmlStringComment))
2622 xmlFree((char *) cur->name);
2623 } else
2624 xmlFree((char *) cur->name);
2625 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002626 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002627 xmlFree(cur);
2628 }
Owen Taylor3473f882001-02-23 17:55:21 +00002629 cur = next;
2630 }
2631}
2632
2633/**
2634 * xmlFreeNode:
2635 * @cur: the node
2636 *
2637 * Free a node, this is a recursive behaviour, all the children are freed too.
2638 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2639 */
2640void
2641xmlFreeNode(xmlNodePtr cur) {
2642 if (cur == NULL) {
2643#ifdef DEBUG_TREE
2644 xmlGenericError(xmlGenericErrorContext,
2645 "xmlFreeNode : node == NULL\n");
2646#endif
2647 return;
2648 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002649 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002650 if (cur->type == XML_DTD_NODE) {
2651 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002652 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002653 }
2654 if (cur->type == XML_NAMESPACE_DECL) {
2655 xmlFreeNs((xmlNsPtr) cur);
2656 return;
2657 }
Owen Taylor3473f882001-02-23 17:55:21 +00002658 if ((cur->children != NULL) &&
2659 (cur->type != XML_ENTITY_REF_NODE))
2660 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002661 if (cur->properties != NULL)
2662 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002663 if ((cur->type != XML_ELEMENT_NODE) &&
2664 (cur->content != NULL) &&
2665 (cur->type != XML_ENTITY_REF_NODE) &&
2666 (cur->type != XML_XINCLUDE_END) &&
2667 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002668 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002669 }
2670
Daniel Veillardacd370f2001-06-09 17:17:51 +00002671 /*
2672 * When a node is a text node or a comment, it uses a global static
2673 * variable for the name of the node.
2674 *
2675 * The xmlStrEqual comparisons need to be done when (happened with
2676 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002677 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002678 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002679 * are not sufficient.
2680 */
Owen Taylor3473f882001-02-23 17:55:21 +00002681 if ((cur->name != NULL) &&
2682 (cur->name != xmlStringText) &&
2683 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002684 (cur->name != xmlStringComment)) {
2685 if (cur->type == XML_TEXT_NODE) {
2686 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2687 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2688 xmlFree((char *) cur->name);
2689 } else if (cur->type == XML_COMMENT_NODE) {
2690 if (!xmlStrEqual(cur->name, xmlStringComment))
2691 xmlFree((char *) cur->name);
2692 } else
2693 xmlFree((char *) cur->name);
2694 }
2695
Owen Taylor3473f882001-02-23 17:55:21 +00002696 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002697 xmlFree(cur);
2698}
2699
2700/**
2701 * xmlUnlinkNode:
2702 * @cur: the node
2703 *
2704 * Unlink a node from it's current context, the node is not freed
2705 */
2706void
2707xmlUnlinkNode(xmlNodePtr cur) {
2708 if (cur == NULL) {
2709#ifdef DEBUG_TREE
2710 xmlGenericError(xmlGenericErrorContext,
2711 "xmlUnlinkNode : node == NULL\n");
2712#endif
2713 return;
2714 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002715 if (cur->type == XML_DTD_NODE) {
2716 xmlDocPtr doc;
2717 doc = cur->doc;
2718 if (doc->intSubset == (xmlDtdPtr) cur)
2719 doc->intSubset = NULL;
2720 if (doc->extSubset == (xmlDtdPtr) cur)
2721 doc->extSubset = NULL;
2722 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002723 if (cur->parent != NULL) {
2724 xmlNodePtr parent;
2725 parent = cur->parent;
2726 if (cur->type == XML_ATTRIBUTE_NODE) {
2727 if (parent->properties == (xmlAttrPtr) cur)
2728 parent->properties = ((xmlAttrPtr) cur)->next;
2729 } else {
2730 if (parent->children == cur)
2731 parent->children = cur->next;
2732 if (parent->last == cur)
2733 parent->last = cur->prev;
2734 }
2735 cur->parent = NULL;
2736 }
Owen Taylor3473f882001-02-23 17:55:21 +00002737 if (cur->next != NULL)
2738 cur->next->prev = cur->prev;
2739 if (cur->prev != NULL)
2740 cur->prev->next = cur->next;
2741 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002742}
2743
2744/**
2745 * xmlReplaceNode:
2746 * @old: the old node
2747 * @cur: the node
2748 *
2749 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002750 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002751 * first unlinked from its existing context.
2752 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002753 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002754 */
2755xmlNodePtr
2756xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2757 if (old == NULL) {
2758#ifdef DEBUG_TREE
2759 xmlGenericError(xmlGenericErrorContext,
2760 "xmlReplaceNode : old == NULL\n");
2761#endif
2762 return(NULL);
2763 }
2764 if (cur == NULL) {
2765 xmlUnlinkNode(old);
2766 return(old);
2767 }
2768 if (cur == old) {
2769 return(old);
2770 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002771 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2772#ifdef DEBUG_TREE
2773 xmlGenericError(xmlGenericErrorContext,
2774 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2775#endif
2776 return(old);
2777 }
2778 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2779#ifdef DEBUG_TREE
2780 xmlGenericError(xmlGenericErrorContext,
2781 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2782#endif
2783 return(old);
2784 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002785 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2786#ifdef DEBUG_TREE
2787 xmlGenericError(xmlGenericErrorContext,
2788 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2789#endif
2790 return(old);
2791 }
2792 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2793#ifdef DEBUG_TREE
2794 xmlGenericError(xmlGenericErrorContext,
2795 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2796#endif
2797 return(old);
2798 }
Owen Taylor3473f882001-02-23 17:55:21 +00002799 xmlUnlinkNode(cur);
2800 cur->doc = old->doc;
2801 cur->parent = old->parent;
2802 cur->next = old->next;
2803 if (cur->next != NULL)
2804 cur->next->prev = cur;
2805 cur->prev = old->prev;
2806 if (cur->prev != NULL)
2807 cur->prev->next = cur;
2808 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002809 if (cur->type == XML_ATTRIBUTE_NODE) {
2810 if (cur->parent->properties == (xmlAttrPtr)old)
2811 cur->parent->properties = ((xmlAttrPtr) cur);
2812 } else {
2813 if (cur->parent->children == old)
2814 cur->parent->children = cur;
2815 if (cur->parent->last == old)
2816 cur->parent->last = cur;
2817 }
Owen Taylor3473f882001-02-23 17:55:21 +00002818 }
2819 old->next = old->prev = NULL;
2820 old->parent = NULL;
2821 return(old);
2822}
2823
2824/************************************************************************
2825 * *
2826 * Copy operations *
2827 * *
2828 ************************************************************************/
2829
2830/**
2831 * xmlCopyNamespace:
2832 * @cur: the namespace
2833 *
2834 * Do a copy of the namespace.
2835 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002836 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002837 */
2838xmlNsPtr
2839xmlCopyNamespace(xmlNsPtr cur) {
2840 xmlNsPtr ret;
2841
2842 if (cur == NULL) return(NULL);
2843 switch (cur->type) {
2844 case XML_LOCAL_NAMESPACE:
2845 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2846 break;
2847 default:
2848#ifdef DEBUG_TREE
2849 xmlGenericError(xmlGenericErrorContext,
2850 "xmlCopyNamespace: invalid type %d\n", cur->type);
2851#endif
2852 return(NULL);
2853 }
2854 return(ret);
2855}
2856
2857/**
2858 * xmlCopyNamespaceList:
2859 * @cur: the first namespace
2860 *
2861 * Do a copy of an namespace list.
2862 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002863 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002864 */
2865xmlNsPtr
2866xmlCopyNamespaceList(xmlNsPtr cur) {
2867 xmlNsPtr ret = NULL;
2868 xmlNsPtr p = NULL,q;
2869
2870 while (cur != NULL) {
2871 q = xmlCopyNamespace(cur);
2872 if (p == NULL) {
2873 ret = p = q;
2874 } else {
2875 p->next = q;
2876 p = q;
2877 }
2878 cur = cur->next;
2879 }
2880 return(ret);
2881}
2882
2883static xmlNodePtr
2884xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2885/**
2886 * xmlCopyProp:
2887 * @target: the element where the attribute will be grafted
2888 * @cur: the attribute
2889 *
2890 * Do a copy of the attribute.
2891 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002892 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002893 */
2894xmlAttrPtr
2895xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2896 xmlAttrPtr ret;
2897
2898 if (cur == NULL) return(NULL);
2899 if (target != NULL)
2900 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2901 else if (cur->parent != NULL)
2902 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2903 else if (cur->children != NULL)
2904 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2905 else
2906 ret = xmlNewDocProp(NULL, cur->name, NULL);
2907 if (ret == NULL) return(NULL);
2908 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002909
Owen Taylor3473f882001-02-23 17:55:21 +00002910 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00002911 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002912/*
2913 * if (target->doc)
2914 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2915 * else if (cur->doc) / * target may not yet have a doc : KPI * /
2916 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
2917 * else
2918 * ns = NULL;
2919 * ret->ns = ns;
2920 */
2921 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2922 if (ns == NULL) {
2923 /*
2924 * Humm, we are copying an element whose namespace is defined
2925 * out of the new tree scope. Search it in the original tree
2926 * and add it at the top of the new tree
2927 */
2928 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
2929 if (ns != NULL) {
2930 xmlNodePtr root = target;
2931 xmlNodePtr pred = NULL;
2932
2933 while (root->parent != NULL) {
2934 pred = root;
2935 root = root->parent;
2936 }
2937 if (root == (xmlNodePtr) target->doc) {
2938 /* correct possibly cycling above the document elt */
2939 root = pred;
2940 }
2941 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
2942 }
2943 } else {
2944 /*
2945 * we have to find something appropriate here since
2946 * we cant be sure, that the namespce we found is identified
2947 * by the prefix
2948 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002949 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002950 /* this is the nice case */
2951 ret->ns = ns;
2952 } else {
2953 /*
2954 * we are in trouble: we need a new reconcilied namespace.
2955 * This is expensive
2956 */
2957 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
2958 }
2959 }
2960
Owen Taylor3473f882001-02-23 17:55:21 +00002961 } else
2962 ret->ns = NULL;
2963
2964 if (cur->children != NULL) {
2965 xmlNodePtr tmp;
2966
2967 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2968 ret->last = NULL;
2969 tmp = ret->children;
2970 while (tmp != NULL) {
2971 /* tmp->parent = (xmlNodePtr)ret; */
2972 if (tmp->next == NULL)
2973 ret->last = tmp;
2974 tmp = tmp->next;
2975 }
2976 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002977 /*
2978 * Try to handle IDs
2979 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00002980 if ((target!= NULL) && (cur!= NULL) &&
2981 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002982 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
2983 if (xmlIsID(cur->doc, cur->parent, cur)) {
2984 xmlChar *id;
2985
2986 id = xmlNodeListGetString(cur->doc, cur->children, 1);
2987 if (id != NULL) {
2988 xmlAddID(NULL, target->doc, id, ret);
2989 xmlFree(id);
2990 }
2991 }
2992 }
Owen Taylor3473f882001-02-23 17:55:21 +00002993 return(ret);
2994}
2995
2996/**
2997 * xmlCopyPropList:
2998 * @target: the element where the attributes will be grafted
2999 * @cur: the first attribute
3000 *
3001 * Do a copy of an attribute list.
3002 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003003 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003004 */
3005xmlAttrPtr
3006xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3007 xmlAttrPtr ret = NULL;
3008 xmlAttrPtr p = NULL,q;
3009
3010 while (cur != NULL) {
3011 q = xmlCopyProp(target, cur);
3012 if (p == NULL) {
3013 ret = p = q;
3014 } else {
3015 p->next = q;
3016 q->prev = p;
3017 p = q;
3018 }
3019 cur = cur->next;
3020 }
3021 return(ret);
3022}
3023
3024/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003025 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003026 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003027 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003028 * tricky reason: namespaces. Doing a direct copy of a node
3029 * say RPM:Copyright without changing the namespace pointer to
3030 * something else can produce stale links. One way to do it is
3031 * to keep a reference counter but this doesn't work as soon
3032 * as one move the element or the subtree out of the scope of
3033 * the existing namespace. The actual solution seems to add
3034 * a copy of the namespace at the top of the copied tree if
3035 * not available in the subtree.
3036 * Hence two functions, the public front-end call the inner ones
3037 */
3038
3039static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003040xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003041 int recursive) {
3042 xmlNodePtr ret;
3043
3044 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003045 switch (node->type) {
3046 case XML_TEXT_NODE:
3047 case XML_CDATA_SECTION_NODE:
3048 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003049 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003050 case XML_ENTITY_REF_NODE:
3051 case XML_ENTITY_NODE:
3052 case XML_PI_NODE:
3053 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003054 case XML_XINCLUDE_START:
3055 case XML_XINCLUDE_END:
3056 break;
3057 case XML_ATTRIBUTE_NODE:
3058 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3059 case XML_NAMESPACE_DECL:
3060 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3061
Daniel Veillard39196eb2001-06-19 18:09:42 +00003062 case XML_DOCUMENT_NODE:
3063 case XML_HTML_DOCUMENT_NODE:
3064#ifdef LIBXML_DOCB_ENABLED
3065 case XML_DOCB_DOCUMENT_NODE:
3066#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003067 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003068 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003069 case XML_NOTATION_NODE:
3070 case XML_DTD_NODE:
3071 case XML_ELEMENT_DECL:
3072 case XML_ATTRIBUTE_DECL:
3073 case XML_ENTITY_DECL:
3074 return(NULL);
3075 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003076
Owen Taylor3473f882001-02-23 17:55:21 +00003077 /*
3078 * Allocate a new node and fill the fields.
3079 */
3080 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3081 if (ret == NULL) {
3082 xmlGenericError(xmlGenericErrorContext,
3083 "xmlStaticCopyNode : malloc failed\n");
3084 return(NULL);
3085 }
3086 memset(ret, 0, sizeof(xmlNode));
3087 ret->type = node->type;
3088
3089 ret->doc = doc;
3090 ret->parent = parent;
3091 if (node->name == xmlStringText)
3092 ret->name = xmlStringText;
3093 else if (node->name == xmlStringTextNoenc)
3094 ret->name = xmlStringTextNoenc;
3095 else if (node->name == xmlStringComment)
3096 ret->name = xmlStringComment;
3097 else if (node->name != NULL)
3098 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003099 if ((node->type != XML_ELEMENT_NODE) &&
3100 (node->content != NULL) &&
3101 (node->type != XML_ENTITY_REF_NODE) &&
3102 (node->type != XML_XINCLUDE_END) &&
3103 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003104 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003105 }else{
3106 if (node->type == XML_ELEMENT_NODE)
3107 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003108 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003109 if (parent != NULL) {
3110 xmlNodePtr tmp;
3111
3112 tmp = xmlAddChild(parent, ret);
3113 /* node could have coalesced */
3114 if (tmp != ret)
3115 return(tmp);
3116 }
Owen Taylor3473f882001-02-23 17:55:21 +00003117
3118 if (!recursive) return(ret);
3119 if (node->nsDef != NULL)
3120 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3121
3122 if (node->ns != NULL) {
3123 xmlNsPtr ns;
3124
3125 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3126 if (ns == NULL) {
3127 /*
3128 * Humm, we are copying an element whose namespace is defined
3129 * out of the new tree scope. Search it in the original tree
3130 * and add it at the top of the new tree
3131 */
3132 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3133 if (ns != NULL) {
3134 xmlNodePtr root = ret;
3135
3136 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003137 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003138 }
3139 } else {
3140 /*
3141 * reference the existing namespace definition in our own tree.
3142 */
3143 ret->ns = ns;
3144 }
3145 }
3146 if (node->properties != NULL)
3147 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003148 if (node->type == XML_ENTITY_REF_NODE) {
3149 if ((doc == NULL) || (node->doc != doc)) {
3150 /*
3151 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003152 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003153 * we cannot keep the reference. Try to find it in the
3154 * target document.
3155 */
3156 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3157 } else {
3158 ret->children = node->children;
3159 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003160 ret->last = ret->children;
3161 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003162 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003163 UPDATE_LAST_CHILD_AND_PARENT(ret)
3164 }
Owen Taylor3473f882001-02-23 17:55:21 +00003165 return(ret);
3166}
3167
3168static xmlNodePtr
3169xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3170 xmlNodePtr ret = NULL;
3171 xmlNodePtr p = NULL,q;
3172
3173 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003174 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003175 if (doc == NULL) {
3176 node = node->next;
3177 continue;
3178 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003179 if (doc->intSubset == NULL) {
3180 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3181 q->doc = doc;
3182 q->parent = parent;
3183 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003184 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003185 } else {
3186 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003187 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003188 }
3189 } else
3190 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003191 if (ret == NULL) {
3192 q->prev = NULL;
3193 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003194 } else if (p != q) {
3195 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003196 p->next = q;
3197 q->prev = p;
3198 p = q;
3199 }
3200 node = node->next;
3201 }
3202 return(ret);
3203}
3204
3205/**
3206 * xmlCopyNode:
3207 * @node: the node
3208 * @recursive: if 1 do a recursive copy.
3209 *
3210 * Do a copy of the node.
3211 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003212 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003213 */
3214xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003215xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003216 xmlNodePtr ret;
3217
3218 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3219 return(ret);
3220}
3221
3222/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003223 * xmlDocCopyNode:
3224 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003225 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003226 * @recursive: if 1 do a recursive copy.
3227 *
3228 * Do a copy of the node to a given document.
3229 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003230 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003231 */
3232xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003233xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003234 xmlNodePtr ret;
3235
3236 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3237 return(ret);
3238}
3239
3240/**
Owen Taylor3473f882001-02-23 17:55:21 +00003241 * xmlCopyNodeList:
3242 * @node: the first node in the list.
3243 *
3244 * Do a recursive copy of the node list.
3245 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003246 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003247 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003248xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003249 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3250 return(ret);
3251}
3252
3253/**
Owen Taylor3473f882001-02-23 17:55:21 +00003254 * xmlCopyDtd:
3255 * @dtd: the dtd
3256 *
3257 * Do a copy of the dtd.
3258 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003259 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003260 */
3261xmlDtdPtr
3262xmlCopyDtd(xmlDtdPtr dtd) {
3263 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003264 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003265
3266 if (dtd == NULL) return(NULL);
3267 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3268 if (ret == NULL) return(NULL);
3269 if (dtd->entities != NULL)
3270 ret->entities = (void *) xmlCopyEntitiesTable(
3271 (xmlEntitiesTablePtr) dtd->entities);
3272 if (dtd->notations != NULL)
3273 ret->notations = (void *) xmlCopyNotationTable(
3274 (xmlNotationTablePtr) dtd->notations);
3275 if (dtd->elements != NULL)
3276 ret->elements = (void *) xmlCopyElementTable(
3277 (xmlElementTablePtr) dtd->elements);
3278 if (dtd->attributes != NULL)
3279 ret->attributes = (void *) xmlCopyAttributeTable(
3280 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003281 if (dtd->pentities != NULL)
3282 ret->pentities = (void *) xmlCopyEntitiesTable(
3283 (xmlEntitiesTablePtr) dtd->pentities);
3284
3285 cur = dtd->children;
3286 while (cur != NULL) {
3287 q = NULL;
3288
3289 if (cur->type == XML_ENTITY_DECL) {
3290 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3291 switch (tmp->etype) {
3292 case XML_INTERNAL_GENERAL_ENTITY:
3293 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3294 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3295 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3296 break;
3297 case XML_INTERNAL_PARAMETER_ENTITY:
3298 case XML_EXTERNAL_PARAMETER_ENTITY:
3299 q = (xmlNodePtr)
3300 xmlGetParameterEntityFromDtd(ret, tmp->name);
3301 break;
3302 case XML_INTERNAL_PREDEFINED_ENTITY:
3303 break;
3304 }
3305 } else if (cur->type == XML_ELEMENT_DECL) {
3306 xmlElementPtr tmp = (xmlElementPtr) cur;
3307 q = (xmlNodePtr)
3308 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3309 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3310 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3311 q = (xmlNodePtr)
3312 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3313 } else if (cur->type == XML_COMMENT_NODE) {
3314 q = xmlCopyNode(cur, 0);
3315 }
3316
3317 if (q == NULL) {
3318 cur = cur->next;
3319 continue;
3320 }
3321
3322 if (p == NULL)
3323 ret->children = q;
3324 else
3325 p->next = q;
3326
3327 q->prev = p;
3328 q->parent = (xmlNodePtr) ret;
3329 q->next = NULL;
3330 ret->last = q;
3331 p = q;
3332 cur = cur->next;
3333 }
3334
Owen Taylor3473f882001-02-23 17:55:21 +00003335 return(ret);
3336}
3337
3338/**
3339 * xmlCopyDoc:
3340 * @doc: the document
3341 * @recursive: if 1 do a recursive copy.
3342 *
3343 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003344 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003345 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003346 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003347 */
3348xmlDocPtr
3349xmlCopyDoc(xmlDocPtr doc, int recursive) {
3350 xmlDocPtr ret;
3351
3352 if (doc == NULL) return(NULL);
3353 ret = xmlNewDoc(doc->version);
3354 if (ret == NULL) return(NULL);
3355 if (doc->name != NULL)
3356 ret->name = xmlMemStrdup(doc->name);
3357 if (doc->encoding != NULL)
3358 ret->encoding = xmlStrdup(doc->encoding);
3359 ret->charset = doc->charset;
3360 ret->compression = doc->compression;
3361 ret->standalone = doc->standalone;
3362 if (!recursive) return(ret);
3363
Daniel Veillardb33c2012001-04-25 12:59:04 +00003364 ret->last = NULL;
3365 ret->children = NULL;
3366 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003367 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003368 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003369 ret->intSubset->parent = ret;
3370 }
Owen Taylor3473f882001-02-23 17:55:21 +00003371 if (doc->oldNs != NULL)
3372 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3373 if (doc->children != NULL) {
3374 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003375
3376 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3377 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003378 ret->last = NULL;
3379 tmp = ret->children;
3380 while (tmp != NULL) {
3381 if (tmp->next == NULL)
3382 ret->last = tmp;
3383 tmp = tmp->next;
3384 }
3385 }
3386 return(ret);
3387}
3388
3389/************************************************************************
3390 * *
3391 * Content access functions *
3392 * *
3393 ************************************************************************/
3394
3395/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003396 * xmlGetLineNo:
3397 * @node : valid node
3398 *
3399 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003400 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003401 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003402 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003403 */
3404long
3405xmlGetLineNo(xmlNodePtr node)
3406{
3407 long result = -1;
3408
3409 if (!node)
3410 return result;
3411 if (node->type == XML_ELEMENT_NODE)
3412 result = (long) node->content;
3413 else if ((node->prev != NULL) &&
3414 ((node->prev->type == XML_ELEMENT_NODE) ||
3415 (node->prev->type == XML_TEXT_NODE)))
3416 result = xmlGetLineNo(node->prev);
3417 else if ((node->parent != NULL) &&
3418 ((node->parent->type == XML_ELEMENT_NODE) ||
3419 (node->parent->type == XML_TEXT_NODE)))
3420 result = xmlGetLineNo(node->parent);
3421
3422 return result;
3423}
3424
3425/**
3426 * xmlGetNodePath:
3427 * @node: a node
3428 *
3429 * Build a structure based Path for the given node
3430 *
3431 * Returns the new path or NULL in case of error. The caller must free
3432 * the returned string
3433 */
3434xmlChar *
3435xmlGetNodePath(xmlNodePtr node)
3436{
3437 xmlNodePtr cur, tmp, next;
3438 xmlChar *buffer = NULL, *temp;
3439 size_t buf_len;
3440 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00003441 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00003442 const char *name;
3443 char nametemp[100];
3444 int occur = 0;
3445
3446 if (node == NULL)
3447 return (NULL);
3448
3449 buf_len = 500;
3450 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3451 if (buffer == NULL)
3452 return (NULL);
3453 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3454 if (buf == NULL) {
3455 xmlFree(buffer);
3456 return (NULL);
3457 }
3458
3459 buffer[0] = 0;
3460 cur = node;
3461 do {
3462 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003463 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003464 occur = 0;
3465 if ((cur->type == XML_DOCUMENT_NODE) ||
3466 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3467 if (buffer[0] == '/')
3468 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003469 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003470 next = NULL;
3471 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003472 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003473 name = (const char *) cur->name;
3474 if (cur->ns) {
3475 snprintf(nametemp, sizeof(nametemp) - 1,
3476 "%s:%s", cur->ns->prefix, cur->name);
3477 nametemp[sizeof(nametemp) - 1] = 0;
3478 name = nametemp;
3479 }
3480 next = cur->parent;
3481
3482 /*
3483 * Thumbler index computation
3484 */
3485 tmp = cur->prev;
3486 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00003487 if ((tmp->type == XML_ELEMENT_NODE) &&
3488 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003489 occur++;
3490 tmp = tmp->prev;
3491 }
3492 if (occur == 0) {
3493 tmp = cur->next;
3494 while (tmp != NULL) {
3495 if (xmlStrEqual(cur->name, tmp->name))
3496 occur++;
3497 tmp = tmp->next;
3498 }
3499 if (occur != 0)
3500 occur = 1;
3501 } else
3502 occur++;
3503 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003504 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003505 name = (const char *) (((xmlAttrPtr) cur)->name);
3506 next = ((xmlAttrPtr) cur)->parent;
3507 } else {
3508 next = cur->parent;
3509 }
3510
3511 /*
3512 * Make sure there is enough room
3513 */
3514 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3515 buf_len =
3516 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3517 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3518 if (temp == NULL) {
3519 xmlFree(buf);
3520 xmlFree(buffer);
3521 return (NULL);
3522 }
3523 buffer = temp;
3524 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3525 if (temp == NULL) {
3526 xmlFree(buf);
3527 xmlFree(buffer);
3528 return (NULL);
3529 }
3530 buf = temp;
3531 }
3532 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003533 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00003534 sep, name, (char *) buffer);
3535 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003536 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00003537 sep, name, occur, (char *) buffer);
3538 snprintf((char *) buffer, buf_len, "%s", buf);
3539 cur = next;
3540 } while (cur != NULL);
3541 xmlFree(buf);
3542 return (buffer);
3543}
3544
3545/**
Owen Taylor3473f882001-02-23 17:55:21 +00003546 * xmlDocGetRootElement:
3547 * @doc: the document
3548 *
3549 * Get the root element of the document (doc->children is a list
3550 * containing possibly comments, PIs, etc ...).
3551 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003552 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003553 */
3554xmlNodePtr
3555xmlDocGetRootElement(xmlDocPtr doc) {
3556 xmlNodePtr ret;
3557
3558 if (doc == NULL) return(NULL);
3559 ret = doc->children;
3560 while (ret != NULL) {
3561 if (ret->type == XML_ELEMENT_NODE)
3562 return(ret);
3563 ret = ret->next;
3564 }
3565 return(ret);
3566}
3567
3568/**
3569 * xmlDocSetRootElement:
3570 * @doc: the document
3571 * @root: the new document root element
3572 *
3573 * Set the root element of the document (doc->children is a list
3574 * containing possibly comments, PIs, etc ...).
3575 *
3576 * Returns the old root element if any was found
3577 */
3578xmlNodePtr
3579xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3580 xmlNodePtr old = NULL;
3581
3582 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00003583 if (root == NULL)
3584 return(NULL);
3585 xmlUnlinkNode(root);
3586 root->doc = doc;
3587 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00003588 old = doc->children;
3589 while (old != NULL) {
3590 if (old->type == XML_ELEMENT_NODE)
3591 break;
3592 old = old->next;
3593 }
3594 if (old == NULL) {
3595 if (doc->children == NULL) {
3596 doc->children = root;
3597 doc->last = root;
3598 } else {
3599 xmlAddSibling(doc->children, root);
3600 }
3601 } else {
3602 xmlReplaceNode(old, root);
3603 }
3604 return(old);
3605}
3606
3607/**
3608 * xmlNodeSetLang:
3609 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003610 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003611 *
3612 * Set the language of a node, i.e. the values of the xml:lang
3613 * attribute.
3614 */
3615void
3616xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003617 xmlNsPtr ns;
3618
Owen Taylor3473f882001-02-23 17:55:21 +00003619 if (cur == NULL) return;
3620 switch(cur->type) {
3621 case XML_TEXT_NODE:
3622 case XML_CDATA_SECTION_NODE:
3623 case XML_COMMENT_NODE:
3624 case XML_DOCUMENT_NODE:
3625 case XML_DOCUMENT_TYPE_NODE:
3626 case XML_DOCUMENT_FRAG_NODE:
3627 case XML_NOTATION_NODE:
3628 case XML_HTML_DOCUMENT_NODE:
3629 case XML_DTD_NODE:
3630 case XML_ELEMENT_DECL:
3631 case XML_ATTRIBUTE_DECL:
3632 case XML_ENTITY_DECL:
3633 case XML_PI_NODE:
3634 case XML_ENTITY_REF_NODE:
3635 case XML_ENTITY_NODE:
3636 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003637#ifdef LIBXML_DOCB_ENABLED
3638 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003639#endif
3640 case XML_XINCLUDE_START:
3641 case XML_XINCLUDE_END:
3642 return;
3643 case XML_ELEMENT_NODE:
3644 case XML_ATTRIBUTE_NODE:
3645 break;
3646 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003647 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3648 if (ns == NULL)
3649 return;
3650 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003651}
3652
3653/**
3654 * xmlNodeGetLang:
3655 * @cur: the node being checked
3656 *
3657 * Searches the language of a node, i.e. the values of the xml:lang
3658 * attribute or the one carried by the nearest ancestor.
3659 *
3660 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003661 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003662 */
3663xmlChar *
3664xmlNodeGetLang(xmlNodePtr cur) {
3665 xmlChar *lang;
3666
3667 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003668 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003669 if (lang != NULL)
3670 return(lang);
3671 cur = cur->parent;
3672 }
3673 return(NULL);
3674}
3675
3676
3677/**
3678 * xmlNodeSetSpacePreserve:
3679 * @cur: the node being changed
3680 * @val: the xml:space value ("0": default, 1: "preserve")
3681 *
3682 * Set (or reset) the space preserving behaviour of a node, i.e. the
3683 * value of the xml:space attribute.
3684 */
3685void
3686xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003687 xmlNsPtr ns;
3688
Owen Taylor3473f882001-02-23 17:55:21 +00003689 if (cur == NULL) return;
3690 switch(cur->type) {
3691 case XML_TEXT_NODE:
3692 case XML_CDATA_SECTION_NODE:
3693 case XML_COMMENT_NODE:
3694 case XML_DOCUMENT_NODE:
3695 case XML_DOCUMENT_TYPE_NODE:
3696 case XML_DOCUMENT_FRAG_NODE:
3697 case XML_NOTATION_NODE:
3698 case XML_HTML_DOCUMENT_NODE:
3699 case XML_DTD_NODE:
3700 case XML_ELEMENT_DECL:
3701 case XML_ATTRIBUTE_DECL:
3702 case XML_ENTITY_DECL:
3703 case XML_PI_NODE:
3704 case XML_ENTITY_REF_NODE:
3705 case XML_ENTITY_NODE:
3706 case XML_NAMESPACE_DECL:
3707 case XML_XINCLUDE_START:
3708 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003709#ifdef LIBXML_DOCB_ENABLED
3710 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003711#endif
3712 return;
3713 case XML_ELEMENT_NODE:
3714 case XML_ATTRIBUTE_NODE:
3715 break;
3716 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003717 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3718 if (ns == NULL)
3719 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003720 switch (val) {
3721 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003722 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003723 break;
3724 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003725 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003726 break;
3727 }
3728}
3729
3730/**
3731 * xmlNodeGetSpacePreserve:
3732 * @cur: the node being checked
3733 *
3734 * Searches the space preserving behaviour of a node, i.e. the values
3735 * of the xml:space attribute or the one carried by the nearest
3736 * ancestor.
3737 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003738 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003739 */
3740int
3741xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3742 xmlChar *space;
3743
3744 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003745 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003746 if (space != NULL) {
3747 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3748 xmlFree(space);
3749 return(1);
3750 }
3751 if (xmlStrEqual(space, BAD_CAST "default")) {
3752 xmlFree(space);
3753 return(0);
3754 }
3755 xmlFree(space);
3756 }
3757 cur = cur->parent;
3758 }
3759 return(-1);
3760}
3761
3762/**
3763 * xmlNodeSetName:
3764 * @cur: the node being changed
3765 * @name: the new tag name
3766 *
3767 * Set (or reset) the name of a node.
3768 */
3769void
3770xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3771 if (cur == NULL) return;
3772 if (name == NULL) return;
3773 switch(cur->type) {
3774 case XML_TEXT_NODE:
3775 case XML_CDATA_SECTION_NODE:
3776 case XML_COMMENT_NODE:
3777 case XML_DOCUMENT_TYPE_NODE:
3778 case XML_DOCUMENT_FRAG_NODE:
3779 case XML_NOTATION_NODE:
3780 case XML_HTML_DOCUMENT_NODE:
3781 case XML_NAMESPACE_DECL:
3782 case XML_XINCLUDE_START:
3783 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003784#ifdef LIBXML_DOCB_ENABLED
3785 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003786#endif
3787 return;
3788 case XML_ELEMENT_NODE:
3789 case XML_ATTRIBUTE_NODE:
3790 case XML_PI_NODE:
3791 case XML_ENTITY_REF_NODE:
3792 case XML_ENTITY_NODE:
3793 case XML_DTD_NODE:
3794 case XML_DOCUMENT_NODE:
3795 case XML_ELEMENT_DECL:
3796 case XML_ATTRIBUTE_DECL:
3797 case XML_ENTITY_DECL:
3798 break;
3799 }
3800 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3801 cur->name = xmlStrdup(name);
3802}
3803
3804/**
3805 * xmlNodeSetBase:
3806 * @cur: the node being changed
3807 * @uri: the new base URI
3808 *
3809 * Set (or reset) the base URI of a node, i.e. the value of the
3810 * xml:base attribute.
3811 */
3812void
3813xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003814 xmlNsPtr ns;
3815
Owen Taylor3473f882001-02-23 17:55:21 +00003816 if (cur == NULL) return;
3817 switch(cur->type) {
3818 case XML_TEXT_NODE:
3819 case XML_CDATA_SECTION_NODE:
3820 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003821 case XML_DOCUMENT_TYPE_NODE:
3822 case XML_DOCUMENT_FRAG_NODE:
3823 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003824 case XML_DTD_NODE:
3825 case XML_ELEMENT_DECL:
3826 case XML_ATTRIBUTE_DECL:
3827 case XML_ENTITY_DECL:
3828 case XML_PI_NODE:
3829 case XML_ENTITY_REF_NODE:
3830 case XML_ENTITY_NODE:
3831 case XML_NAMESPACE_DECL:
3832 case XML_XINCLUDE_START:
3833 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00003834 return;
3835 case XML_ELEMENT_NODE:
3836 case XML_ATTRIBUTE_NODE:
3837 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00003838 case XML_DOCUMENT_NODE:
3839#ifdef LIBXML_DOCB_ENABLED
3840 case XML_DOCB_DOCUMENT_NODE:
3841#endif
3842 case XML_HTML_DOCUMENT_NODE: {
3843 xmlDocPtr doc = (xmlDocPtr) cur;
3844
3845 if (doc->URL != NULL)
3846 xmlFree((xmlChar *) doc->URL);
3847 if (uri == NULL)
3848 doc->URL = NULL;
3849 else
3850 doc->URL = xmlStrdup(uri);
3851 return;
3852 }
Owen Taylor3473f882001-02-23 17:55:21 +00003853 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003854
3855 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3856 if (ns == NULL)
3857 return;
3858 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00003859}
3860
3861/**
Owen Taylor3473f882001-02-23 17:55:21 +00003862 * xmlNodeGetBase:
3863 * @doc: the document the node pertains to
3864 * @cur: the node being checked
3865 *
3866 * Searches for the BASE URL. The code should work on both XML
3867 * and HTML document even if base mechanisms are completely different.
3868 * It returns the base as defined in RFC 2396 sections
3869 * 5.1.1. Base URI within Document Content
3870 * and
3871 * 5.1.2. Base URI from the Encapsulating Entity
3872 * However it does not return the document base (5.1.3), use
3873 * xmlDocumentGetBase() for this
3874 *
3875 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003876 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003877 */
3878xmlChar *
3879xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003880 xmlChar *oldbase = NULL;
3881 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003882
3883 if ((cur == NULL) && (doc == NULL))
3884 return(NULL);
3885 if (doc == NULL) doc = cur->doc;
3886 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3887 cur = doc->children;
3888 while ((cur != NULL) && (cur->name != NULL)) {
3889 if (cur->type != XML_ELEMENT_NODE) {
3890 cur = cur->next;
3891 continue;
3892 }
3893 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3894 cur = cur->children;
3895 continue;
3896 }
3897 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3898 cur = cur->children;
3899 continue;
3900 }
3901 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3902 return(xmlGetProp(cur, BAD_CAST "href"));
3903 }
3904 cur = cur->next;
3905 }
3906 return(NULL);
3907 }
3908 while (cur != NULL) {
3909 if (cur->type == XML_ENTITY_DECL) {
3910 xmlEntityPtr ent = (xmlEntityPtr) cur;
3911 return(xmlStrdup(ent->URI));
3912 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003913 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003914 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003915 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003916 if (oldbase != NULL) {
3917 newbase = xmlBuildURI(oldbase, base);
3918 if (newbase != NULL) {
3919 xmlFree(oldbase);
3920 xmlFree(base);
3921 oldbase = newbase;
3922 } else {
3923 xmlFree(oldbase);
3924 xmlFree(base);
3925 return(NULL);
3926 }
3927 } else {
3928 oldbase = base;
3929 }
3930 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3931 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3932 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3933 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003934 }
3935 }
Owen Taylor3473f882001-02-23 17:55:21 +00003936 cur = cur->parent;
3937 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003938 if ((doc != NULL) && (doc->URL != NULL)) {
3939 if (oldbase == NULL)
3940 return(xmlStrdup(doc->URL));
3941 newbase = xmlBuildURI(oldbase, doc->URL);
3942 xmlFree(oldbase);
3943 return(newbase);
3944 }
3945 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003946}
3947
3948/**
3949 * xmlNodeGetContent:
3950 * @cur: the node being read
3951 *
3952 * Read the value of a node, this can be either the text carried
3953 * directly by this node if it's a TEXT node or the aggregate string
3954 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00003955 * Entity references are substituted.
3956 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003957 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003958 */
3959xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00003960xmlNodeGetContent(xmlNodePtr cur)
3961{
3962 if (cur == NULL)
3963 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003964 switch (cur->type) {
3965 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00003966 case XML_ELEMENT_NODE:{
3967 xmlNodePtr tmp = cur;
3968 xmlBufferPtr buffer;
3969 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00003970
Daniel Veillard7646b182002-04-20 06:41:40 +00003971 buffer = xmlBufferCreate();
3972 if (buffer == NULL)
3973 return (NULL);
3974 while (tmp != NULL) {
3975 switch (tmp->type) {
3976 case XML_CDATA_SECTION_NODE:
3977 case XML_TEXT_NODE:
3978 if (tmp->content != NULL)
3979 xmlBufferCat(buffer, tmp->content);
3980 break;
3981 case XML_ENTITY_REF_NODE:{
3982 /* recursive substitution of entity references */
3983 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00003984
Daniel Veillard7646b182002-04-20 06:41:40 +00003985 if (cont) {
3986 xmlBufferCat(buffer,
3987 (const xmlChar *) cont);
3988 xmlFree(cont);
3989 }
3990 break;
3991 }
3992 default:
3993 break;
3994 }
3995 /*
3996 * Skip to next node
3997 */
3998 if (tmp->children != NULL) {
3999 if (tmp->children->type != XML_ENTITY_DECL) {
4000 tmp = tmp->children;
4001 continue;
4002 }
4003 }
4004 if (tmp == cur)
4005 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004006
Daniel Veillard7646b182002-04-20 06:41:40 +00004007 if (tmp->next != NULL) {
4008 tmp = tmp->next;
4009 continue;
4010 }
4011
4012 do {
4013 tmp = tmp->parent;
4014 if (tmp == NULL)
4015 break;
4016 if (tmp == cur) {
4017 tmp = NULL;
4018 break;
4019 }
4020 if (tmp->next != NULL) {
4021 tmp = tmp->next;
4022 break;
4023 }
4024 } while (tmp != NULL);
4025 }
4026 ret = buffer->content;
4027 buffer->content = NULL;
4028 xmlBufferFree(buffer);
4029 return (ret);
4030 }
4031 case XML_ATTRIBUTE_NODE:{
4032 xmlAttrPtr attr = (xmlAttrPtr) cur;
4033
4034 if (attr->parent != NULL)
4035 return (xmlNodeListGetString
4036 (attr->parent->doc, attr->children, 1));
4037 else
4038 return (xmlNodeListGetString(NULL, attr->children, 1));
4039 break;
4040 }
Owen Taylor3473f882001-02-23 17:55:21 +00004041 case XML_COMMENT_NODE:
4042 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004043 if (cur->content != NULL)
4044 return (xmlStrdup(cur->content));
4045 return (NULL);
4046 case XML_ENTITY_REF_NODE:{
4047 xmlEntityPtr ent;
4048 xmlNodePtr tmp;
4049 xmlBufferPtr buffer;
4050 xmlChar *ret;
4051
4052 /* lookup entity declaration */
4053 ent = xmlGetDocEntity(cur->doc, cur->name);
4054 if (ent == NULL)
4055 return (NULL);
4056
4057 buffer = xmlBufferCreate();
4058 if (buffer == NULL)
4059 return (NULL);
4060
4061 /* an entity content can be any "well balanced chunk",
4062 * i.e. the result of the content [43] production:
4063 * http://www.w3.org/TR/REC-xml#NT-content
4064 * -> we iterate through child nodes and recursive call
4065 * xmlNodeGetContent() which handles all possible node types */
4066 tmp = ent->children;
4067 while (tmp) {
4068 xmlChar *cont = xmlNodeGetContent(tmp);
4069
4070 if (cont) {
4071 xmlBufferCat(buffer, (const xmlChar *) cont);
4072 xmlFree(cont);
4073 }
4074 tmp = tmp->next;
4075 }
4076
4077 ret = buffer->content;
4078 buffer->content = NULL;
4079 xmlBufferFree(buffer);
4080 return (ret);
4081 }
Owen Taylor3473f882001-02-23 17:55:21 +00004082 case XML_ENTITY_NODE:
4083 case XML_DOCUMENT_NODE:
4084 case XML_HTML_DOCUMENT_NODE:
4085 case XML_DOCUMENT_TYPE_NODE:
4086 case XML_NOTATION_NODE:
4087 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004088 case XML_XINCLUDE_START:
4089 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004090#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004091 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004092#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00004093 return (NULL);
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004094 case XML_NAMESPACE_DECL: {
4095 xmlChar *tmp;
4096
4097 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4098 return (tmp);
4099 }
Owen Taylor3473f882001-02-23 17:55:21 +00004100 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004101 /* TODO !!! */
4102 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004103 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004104 /* TODO !!! */
4105 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004106 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004107 /* TODO !!! */
4108 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004109 case XML_CDATA_SECTION_NODE:
4110 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004111 if (cur->content != NULL)
4112 return (xmlStrdup(cur->content));
4113 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004114 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004115 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004116}
Owen Taylor3473f882001-02-23 17:55:21 +00004117/**
4118 * xmlNodeSetContent:
4119 * @cur: the node being modified
4120 * @content: the new value of the content
4121 *
4122 * Replace the content of a node.
4123 */
4124void
4125xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4126 if (cur == NULL) {
4127#ifdef DEBUG_TREE
4128 xmlGenericError(xmlGenericErrorContext,
4129 "xmlNodeSetContent : node == NULL\n");
4130#endif
4131 return;
4132 }
4133 switch (cur->type) {
4134 case XML_DOCUMENT_FRAG_NODE:
4135 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004136 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004137 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4138 cur->children = xmlStringGetNodeList(cur->doc, content);
4139 UPDATE_LAST_CHILD_AND_PARENT(cur)
4140 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004141 case XML_TEXT_NODE:
4142 case XML_CDATA_SECTION_NODE:
4143 case XML_ENTITY_REF_NODE:
4144 case XML_ENTITY_NODE:
4145 case XML_PI_NODE:
4146 case XML_COMMENT_NODE:
4147 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004148 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004149 }
4150 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4151 cur->last = cur->children = NULL;
4152 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004153 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004154 } else
4155 cur->content = NULL;
4156 break;
4157 case XML_DOCUMENT_NODE:
4158 case XML_HTML_DOCUMENT_NODE:
4159 case XML_DOCUMENT_TYPE_NODE:
4160 case XML_XINCLUDE_START:
4161 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004162#ifdef LIBXML_DOCB_ENABLED
4163 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004164#endif
4165 break;
4166 case XML_NOTATION_NODE:
4167 break;
4168 case XML_DTD_NODE:
4169 break;
4170 case XML_NAMESPACE_DECL:
4171 break;
4172 case XML_ELEMENT_DECL:
4173 /* TODO !!! */
4174 break;
4175 case XML_ATTRIBUTE_DECL:
4176 /* TODO !!! */
4177 break;
4178 case XML_ENTITY_DECL:
4179 /* TODO !!! */
4180 break;
4181 }
4182}
4183
4184/**
4185 * xmlNodeSetContentLen:
4186 * @cur: the node being modified
4187 * @content: the new value of the content
4188 * @len: the size of @content
4189 *
4190 * Replace the content of a node.
4191 */
4192void
4193xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4194 if (cur == NULL) {
4195#ifdef DEBUG_TREE
4196 xmlGenericError(xmlGenericErrorContext,
4197 "xmlNodeSetContentLen : node == NULL\n");
4198#endif
4199 return;
4200 }
4201 switch (cur->type) {
4202 case XML_DOCUMENT_FRAG_NODE:
4203 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004204 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004205 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4206 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4207 UPDATE_LAST_CHILD_AND_PARENT(cur)
4208 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004209 case XML_TEXT_NODE:
4210 case XML_CDATA_SECTION_NODE:
4211 case XML_ENTITY_REF_NODE:
4212 case XML_ENTITY_NODE:
4213 case XML_PI_NODE:
4214 case XML_COMMENT_NODE:
4215 case XML_NOTATION_NODE:
4216 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004217 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004218 }
4219 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4220 cur->children = cur->last = NULL;
4221 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004222 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004223 } else
4224 cur->content = NULL;
4225 break;
4226 case XML_DOCUMENT_NODE:
4227 case XML_DTD_NODE:
4228 case XML_HTML_DOCUMENT_NODE:
4229 case XML_DOCUMENT_TYPE_NODE:
4230 case XML_NAMESPACE_DECL:
4231 case XML_XINCLUDE_START:
4232 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004233#ifdef LIBXML_DOCB_ENABLED
4234 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004235#endif
4236 break;
4237 case XML_ELEMENT_DECL:
4238 /* TODO !!! */
4239 break;
4240 case XML_ATTRIBUTE_DECL:
4241 /* TODO !!! */
4242 break;
4243 case XML_ENTITY_DECL:
4244 /* TODO !!! */
4245 break;
4246 }
4247}
4248
4249/**
4250 * xmlNodeAddContentLen:
4251 * @cur: the node being modified
4252 * @content: extra content
4253 * @len: the size of @content
4254 *
4255 * Append the extra substring to the node content.
4256 */
4257void
4258xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4259 if (cur == NULL) {
4260#ifdef DEBUG_TREE
4261 xmlGenericError(xmlGenericErrorContext,
4262 "xmlNodeAddContentLen : node == NULL\n");
4263#endif
4264 return;
4265 }
4266 if (len <= 0) return;
4267 switch (cur->type) {
4268 case XML_DOCUMENT_FRAG_NODE:
4269 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004270 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004271
Daniel Veillard7db37732001-07-12 01:20:08 +00004272 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004273 newNode = xmlNewTextLen(content, len);
4274 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004275 tmp = xmlAddChild(cur, newNode);
4276 if (tmp != newNode)
4277 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004278 if ((last != NULL) && (last->next == newNode)) {
4279 xmlTextMerge(last, newNode);
4280 }
4281 }
4282 break;
4283 }
4284 case XML_ATTRIBUTE_NODE:
4285 break;
4286 case XML_TEXT_NODE:
4287 case XML_CDATA_SECTION_NODE:
4288 case XML_ENTITY_REF_NODE:
4289 case XML_ENTITY_NODE:
4290 case XML_PI_NODE:
4291 case XML_COMMENT_NODE:
4292 case XML_NOTATION_NODE:
4293 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004294 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004295 }
4296 case XML_DOCUMENT_NODE:
4297 case XML_DTD_NODE:
4298 case XML_HTML_DOCUMENT_NODE:
4299 case XML_DOCUMENT_TYPE_NODE:
4300 case XML_NAMESPACE_DECL:
4301 case XML_XINCLUDE_START:
4302 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004303#ifdef LIBXML_DOCB_ENABLED
4304 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004305#endif
4306 break;
4307 case XML_ELEMENT_DECL:
4308 case XML_ATTRIBUTE_DECL:
4309 case XML_ENTITY_DECL:
4310 break;
4311 }
4312}
4313
4314/**
4315 * xmlNodeAddContent:
4316 * @cur: the node being modified
4317 * @content: extra content
4318 *
4319 * Append the extra substring to the node content.
4320 */
4321void
4322xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4323 int len;
4324
4325 if (cur == NULL) {
4326#ifdef DEBUG_TREE
4327 xmlGenericError(xmlGenericErrorContext,
4328 "xmlNodeAddContent : node == NULL\n");
4329#endif
4330 return;
4331 }
4332 if (content == NULL) return;
4333 len = xmlStrlen(content);
4334 xmlNodeAddContentLen(cur, content, len);
4335}
4336
4337/**
4338 * xmlTextMerge:
4339 * @first: the first text node
4340 * @second: the second text node being merged
4341 *
4342 * Merge two text nodes into one
4343 * Returns the first text node augmented
4344 */
4345xmlNodePtr
4346xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4347 if (first == NULL) return(second);
4348 if (second == NULL) return(first);
4349 if (first->type != XML_TEXT_NODE) return(first);
4350 if (second->type != XML_TEXT_NODE) return(first);
4351 if (second->name != first->name)
4352 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004353 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004354 xmlUnlinkNode(second);
4355 xmlFreeNode(second);
4356 return(first);
4357}
4358
4359/**
4360 * xmlGetNsList:
4361 * @doc: the document
4362 * @node: the current node
4363 *
4364 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004365 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004366 * that need to be freed by the caller or NULL if no
4367 * namespace if defined
4368 */
4369xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004370xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4371{
Owen Taylor3473f882001-02-23 17:55:21 +00004372 xmlNsPtr cur;
4373 xmlNsPtr *ret = NULL;
4374 int nbns = 0;
4375 int maxns = 10;
4376 int i;
4377
4378 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004379 if (node->type == XML_ELEMENT_NODE) {
4380 cur = node->nsDef;
4381 while (cur != NULL) {
4382 if (ret == NULL) {
4383 ret =
4384 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4385 sizeof(xmlNsPtr));
4386 if (ret == NULL) {
4387 xmlGenericError(xmlGenericErrorContext,
4388 "xmlGetNsList : out of memory!\n");
4389 return (NULL);
4390 }
4391 ret[nbns] = NULL;
4392 }
4393 for (i = 0; i < nbns; i++) {
4394 if ((cur->prefix == ret[i]->prefix) ||
4395 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4396 break;
4397 }
4398 if (i >= nbns) {
4399 if (nbns >= maxns) {
4400 maxns *= 2;
4401 ret = (xmlNsPtr *) xmlRealloc(ret,
4402 (maxns +
4403 1) *
4404 sizeof(xmlNsPtr));
4405 if (ret == NULL) {
4406 xmlGenericError(xmlGenericErrorContext,
4407 "xmlGetNsList : realloc failed!\n");
4408 return (NULL);
4409 }
4410 }
4411 ret[nbns++] = cur;
4412 ret[nbns] = NULL;
4413 }
Owen Taylor3473f882001-02-23 17:55:21 +00004414
Daniel Veillard77044732001-06-29 21:31:07 +00004415 cur = cur->next;
4416 }
4417 }
4418 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004419 }
Daniel Veillard77044732001-06-29 21:31:07 +00004420 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004421}
4422
4423/**
4424 * xmlSearchNs:
4425 * @doc: the document
4426 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004427 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004428 *
4429 * Search a Ns registered under a given name space for a document.
4430 * recurse on the parents until it finds the defined namespace
4431 * or return NULL otherwise.
4432 * @nameSpace can be NULL, this is a search for the default namespace.
4433 * We don't allow to cross entities boundaries. If you don't declare
4434 * the namespace within those you will be in troubles !!! A warning
4435 * is generated to cover this case.
4436 *
4437 * Returns the namespace pointer or NULL.
4438 */
4439xmlNsPtr
4440xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4441 xmlNsPtr cur;
4442
4443 if (node == NULL) return(NULL);
4444 if ((nameSpace != NULL) &&
4445 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00004446 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4447 /*
4448 * The XML-1.0 namespace is normally held on the root
4449 * element. In this case exceptionally create it on the
4450 * node element.
4451 */
4452 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4453 if (cur == NULL) {
4454 xmlGenericError(xmlGenericErrorContext,
4455 "xmlSearchNs : malloc failed\n");
4456 return(NULL);
4457 }
4458 memset(cur, 0, sizeof(xmlNs));
4459 cur->type = XML_LOCAL_NAMESPACE;
4460 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4461 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4462 cur->next = node->nsDef;
4463 node->nsDef = cur;
4464 return(cur);
4465 }
Owen Taylor3473f882001-02-23 17:55:21 +00004466 if (doc->oldNs == NULL) {
4467 /*
4468 * Allocate a new Namespace and fill the fields.
4469 */
4470 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4471 if (doc->oldNs == NULL) {
4472 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004473 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004474 return(NULL);
4475 }
4476 memset(doc->oldNs, 0, sizeof(xmlNs));
4477 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4478
4479 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4480 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4481 }
4482 return(doc->oldNs);
4483 }
4484 while (node != NULL) {
4485 if ((node->type == XML_ENTITY_REF_NODE) ||
4486 (node->type == XML_ENTITY_NODE) ||
4487 (node->type == XML_ENTITY_DECL))
4488 return(NULL);
4489 if (node->type == XML_ELEMENT_NODE) {
4490 cur = node->nsDef;
4491 while (cur != NULL) {
4492 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4493 (cur->href != NULL))
4494 return(cur);
4495 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4496 (cur->href != NULL) &&
4497 (xmlStrEqual(cur->prefix, nameSpace)))
4498 return(cur);
4499 cur = cur->next;
4500 }
4501 }
4502 node = node->parent;
4503 }
4504 return(NULL);
4505}
4506
4507/**
4508 * xmlSearchNsByHref:
4509 * @doc: the document
4510 * @node: the current node
4511 * @href: the namespace value
4512 *
4513 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4514 * the defined namespace or return NULL otherwise.
4515 * Returns the namespace pointer or NULL.
4516 */
4517xmlNsPtr
4518xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4519 xmlNsPtr cur;
4520 xmlNodePtr orig = node;
4521
4522 if ((node == NULL) || (href == NULL)) return(NULL);
4523 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004524 /*
4525 * Only the document can hold the XML spec namespace.
4526 */
Daniel Veillardc1a0da32002-08-14 08:32:18 +00004527 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4528 /*
4529 * The XML-1.0 namespace is normally held on the root
4530 * element. In this case exceptionally create it on the
4531 * node element.
4532 */
4533 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4534 if (cur == NULL) {
4535 xmlGenericError(xmlGenericErrorContext,
4536 "xmlSearchNs : malloc failed\n");
4537 return(NULL);
4538 }
4539 memset(cur, 0, sizeof(xmlNs));
4540 cur->type = XML_LOCAL_NAMESPACE;
4541 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4542 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4543 cur->next = node->nsDef;
4544 node->nsDef = cur;
4545 return(cur);
4546 }
Owen Taylor3473f882001-02-23 17:55:21 +00004547 if (doc->oldNs == NULL) {
4548 /*
4549 * Allocate a new Namespace and fill the fields.
4550 */
4551 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4552 if (doc->oldNs == NULL) {
4553 xmlGenericError(xmlGenericErrorContext,
4554 "xmlSearchNsByHref : malloc failed\n");
4555 return(NULL);
4556 }
4557 memset(doc->oldNs, 0, sizeof(xmlNs));
4558 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4559
4560 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4561 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4562 }
4563 return(doc->oldNs);
4564 }
4565 while (node != NULL) {
4566 cur = node->nsDef;
4567 while (cur != NULL) {
4568 if ((cur->href != NULL) && (href != NULL) &&
4569 (xmlStrEqual(cur->href, href))) {
4570 /*
4571 * Check that the prefix is not shadowed between orig and node
4572 */
4573 xmlNodePtr check = orig;
4574 xmlNsPtr tst;
4575
4576 while (check != node) {
4577 tst = check->nsDef;
4578 while (tst != NULL) {
4579 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4580 goto shadowed;
4581 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4582 (xmlStrEqual(tst->prefix, cur->prefix)))
4583 goto shadowed;
4584 tst = tst->next;
4585 }
4586 check = check->parent;
4587 }
4588 return(cur);
4589 }
4590shadowed:
4591 cur = cur->next;
4592 }
4593 node = node->parent;
4594 }
4595 return(NULL);
4596}
4597
4598/**
4599 * xmlNewReconciliedNs
4600 * @doc: the document
4601 * @tree: a node expected to hold the new namespace
4602 * @ns: the original namespace
4603 *
4604 * This function tries to locate a namespace definition in a tree
4605 * ancestors, or create a new namespace definition node similar to
4606 * @ns trying to reuse the same prefix. However if the given prefix is
4607 * null (default namespace) or reused within the subtree defined by
4608 * @tree or on one of its ancestors then a new prefix is generated.
4609 * Returns the (new) namespace definition or NULL in case of error
4610 */
4611xmlNsPtr
4612xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4613 xmlNsPtr def;
4614 xmlChar prefix[50];
4615 int counter = 1;
4616
4617 if (tree == NULL) {
4618#ifdef DEBUG_TREE
4619 xmlGenericError(xmlGenericErrorContext,
4620 "xmlNewReconciliedNs : tree == NULL\n");
4621#endif
4622 return(NULL);
4623 }
4624 if (ns == NULL) {
4625#ifdef DEBUG_TREE
4626 xmlGenericError(xmlGenericErrorContext,
4627 "xmlNewReconciliedNs : ns == NULL\n");
4628#endif
4629 return(NULL);
4630 }
4631 /*
4632 * Search an existing namespace definition inherited.
4633 */
4634 def = xmlSearchNsByHref(doc, tree, ns->href);
4635 if (def != NULL)
4636 return(def);
4637
4638 /*
4639 * Find a close prefix which is not already in use.
4640 * Let's strip namespace prefixes longer than 20 chars !
4641 */
Daniel Veillardf742d342002-03-07 00:05:35 +00004642 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004643 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00004644 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004645 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00004646
Owen Taylor3473f882001-02-23 17:55:21 +00004647 def = xmlSearchNs(doc, tree, prefix);
4648 while (def != NULL) {
4649 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00004650 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004651 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00004652 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004653 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00004654 def = xmlSearchNs(doc, tree, prefix);
4655 }
4656
4657 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004658 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004659 */
4660 def = xmlNewNs(tree, ns->href, prefix);
4661 return(def);
4662}
4663
4664/**
4665 * xmlReconciliateNs
4666 * @doc: the document
4667 * @tree: a node defining the subtree to reconciliate
4668 *
4669 * This function checks that all the namespaces declared within the given
4670 * tree are properly declared. This is needed for example after Copy or Cut
4671 * and then paste operations. The subtree may still hold pointers to
4672 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004673 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004674 * the new environment. If not possible the new namespaces are redeclared
4675 * on @tree at the top of the given subtree.
4676 * Returns the number of namespace declarations created or -1 in case of error.
4677 */
4678int
4679xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4680 xmlNsPtr *oldNs = NULL;
4681 xmlNsPtr *newNs = NULL;
4682 int sizeCache = 0;
4683 int nbCache = 0;
4684
4685 xmlNsPtr n;
4686 xmlNodePtr node = tree;
4687 xmlAttrPtr attr;
4688 int ret = 0, i;
4689
4690 while (node != NULL) {
4691 /*
4692 * Reconciliate the node namespace
4693 */
4694 if (node->ns != NULL) {
4695 /*
4696 * initialize the cache if needed
4697 */
4698 if (sizeCache == 0) {
4699 sizeCache = 10;
4700 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4701 sizeof(xmlNsPtr));
4702 if (oldNs == NULL) {
4703 xmlGenericError(xmlGenericErrorContext,
4704 "xmlReconciliateNs : memory pbm\n");
4705 return(-1);
4706 }
4707 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4708 sizeof(xmlNsPtr));
4709 if (newNs == NULL) {
4710 xmlGenericError(xmlGenericErrorContext,
4711 "xmlReconciliateNs : memory pbm\n");
4712 xmlFree(oldNs);
4713 return(-1);
4714 }
4715 }
4716 for (i = 0;i < nbCache;i++) {
4717 if (oldNs[i] == node->ns) {
4718 node->ns = newNs[i];
4719 break;
4720 }
4721 }
4722 if (i == nbCache) {
4723 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004724 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004725 */
4726 n = xmlNewReconciliedNs(doc, tree, node->ns);
4727 if (n != NULL) { /* :-( what if else ??? */
4728 /*
4729 * check if we need to grow the cache buffers.
4730 */
4731 if (sizeCache <= nbCache) {
4732 sizeCache *= 2;
4733 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4734 sizeof(xmlNsPtr));
4735 if (oldNs == NULL) {
4736 xmlGenericError(xmlGenericErrorContext,
4737 "xmlReconciliateNs : memory pbm\n");
4738 xmlFree(newNs);
4739 return(-1);
4740 }
4741 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4742 sizeof(xmlNsPtr));
4743 if (newNs == NULL) {
4744 xmlGenericError(xmlGenericErrorContext,
4745 "xmlReconciliateNs : memory pbm\n");
4746 xmlFree(oldNs);
4747 return(-1);
4748 }
4749 }
4750 newNs[nbCache] = n;
4751 oldNs[nbCache++] = node->ns;
4752 node->ns = n;
4753 }
4754 }
4755 }
4756 /*
4757 * now check for namespace hold by attributes on the node.
4758 */
4759 attr = node->properties;
4760 while (attr != NULL) {
4761 if (attr->ns != NULL) {
4762 /*
4763 * initialize the cache if needed
4764 */
4765 if (sizeCache == 0) {
4766 sizeCache = 10;
4767 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4768 sizeof(xmlNsPtr));
4769 if (oldNs == NULL) {
4770 xmlGenericError(xmlGenericErrorContext,
4771 "xmlReconciliateNs : memory pbm\n");
4772 return(-1);
4773 }
4774 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4775 sizeof(xmlNsPtr));
4776 if (newNs == NULL) {
4777 xmlGenericError(xmlGenericErrorContext,
4778 "xmlReconciliateNs : memory pbm\n");
4779 xmlFree(oldNs);
4780 return(-1);
4781 }
4782 }
4783 for (i = 0;i < nbCache;i++) {
4784 if (oldNs[i] == attr->ns) {
4785 node->ns = newNs[i];
4786 break;
4787 }
4788 }
4789 if (i == nbCache) {
4790 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004791 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004792 */
4793 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4794 if (n != NULL) { /* :-( what if else ??? */
4795 /*
4796 * check if we need to grow the cache buffers.
4797 */
4798 if (sizeCache <= nbCache) {
4799 sizeCache *= 2;
4800 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4801 sizeof(xmlNsPtr));
4802 if (oldNs == NULL) {
4803 xmlGenericError(xmlGenericErrorContext,
4804 "xmlReconciliateNs : memory pbm\n");
4805 xmlFree(newNs);
4806 return(-1);
4807 }
4808 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4809 sizeof(xmlNsPtr));
4810 if (newNs == NULL) {
4811 xmlGenericError(xmlGenericErrorContext,
4812 "xmlReconciliateNs : memory pbm\n");
4813 xmlFree(oldNs);
4814 return(-1);
4815 }
4816 }
4817 newNs[nbCache] = n;
4818 oldNs[nbCache++] = attr->ns;
4819 attr->ns = n;
4820 }
4821 }
4822 }
4823 attr = attr->next;
4824 }
4825
4826 /*
4827 * Browse the full subtree, deep first
4828 */
4829 if (node->children != NULL) {
4830 /* deep first */
4831 node = node->children;
4832 } else if ((node != tree) && (node->next != NULL)) {
4833 /* then siblings */
4834 node = node->next;
4835 } else if (node != tree) {
4836 /* go up to parents->next if needed */
4837 while (node != tree) {
4838 if (node->parent != NULL)
4839 node = node->parent;
4840 if ((node != tree) && (node->next != NULL)) {
4841 node = node->next;
4842 break;
4843 }
4844 if (node->parent == NULL) {
4845 node = NULL;
4846 break;
4847 }
4848 }
4849 /* exit condition */
4850 if (node == tree)
4851 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00004852 } else
4853 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004854 }
Daniel Veillardf742d342002-03-07 00:05:35 +00004855 if (oldNs != NULL)
4856 xmlFree(oldNs);
4857 if (newNs != NULL)
4858 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00004859 return(ret);
4860}
4861
4862/**
4863 * xmlHasProp:
4864 * @node: the node
4865 * @name: the attribute name
4866 *
4867 * Search an attribute associated to a node
4868 * This function also looks in DTD attribute declaration for #FIXED or
4869 * default declaration values unless DTD use has been turned off.
4870 *
4871 * Returns the attribute or the attribute declaration or NULL if
4872 * neither was found.
4873 */
4874xmlAttrPtr
4875xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4876 xmlAttrPtr prop;
4877 xmlDocPtr doc;
4878
4879 if ((node == NULL) || (name == NULL)) return(NULL);
4880 /*
4881 * Check on the properties attached to the node
4882 */
4883 prop = node->properties;
4884 while (prop != NULL) {
4885 if (xmlStrEqual(prop->name, name)) {
4886 return(prop);
4887 }
4888 prop = prop->next;
4889 }
4890 if (!xmlCheckDTD) return(NULL);
4891
4892 /*
4893 * Check if there is a default declaration in the internal
4894 * or external subsets
4895 */
4896 doc = node->doc;
4897 if (doc != NULL) {
4898 xmlAttributePtr attrDecl;
4899 if (doc->intSubset != NULL) {
4900 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4901 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4902 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4903 if (attrDecl != NULL)
4904 return((xmlAttrPtr) attrDecl);
4905 }
4906 }
4907 return(NULL);
4908}
4909
4910/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004911 * xmlHasNsProp:
4912 * @node: the node
4913 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004914 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004915 *
4916 * Search for an attribute associated to a node
4917 * This attribute has to be anchored in the namespace specified.
4918 * This does the entity substitution.
4919 * This function looks in DTD attribute declaration for #FIXED or
4920 * default declaration values unless DTD use has been turned off.
4921 *
4922 * Returns the attribute or the attribute declaration or NULL
4923 * if neither was found.
4924 */
4925xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004926xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004927 xmlAttrPtr prop;
4928 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004929
4930 if (node == NULL)
4931 return(NULL);
4932
4933 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004934 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004935 return(xmlHasProp(node, name));
4936 while (prop != NULL) {
4937 /*
4938 * One need to have
4939 * - same attribute names
4940 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004941 */
4942 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004943 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4944 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004945 }
4946 prop = prop->next;
4947 }
4948 if (!xmlCheckDTD) return(NULL);
4949
4950 /*
4951 * Check if there is a default declaration in the internal
4952 * or external subsets
4953 */
4954 doc = node->doc;
4955 if (doc != NULL) {
4956 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004957 xmlAttributePtr attrDecl = NULL;
4958 xmlNsPtr *nsList, *cur;
4959 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004960
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004961 nsList = xmlGetNsList(node->doc, node);
4962 if (nsList == NULL)
4963 return(NULL);
4964 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
4965 ename = xmlStrdup(node->ns->prefix);
4966 ename = xmlStrcat(ename, BAD_CAST ":");
4967 ename = xmlStrcat(ename, node->name);
4968 } else {
4969 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004970 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004971 if (ename == NULL) {
4972 xmlFree(nsList);
4973 return(NULL);
4974 }
4975
4976 cur = nsList;
4977 while (*cur != NULL) {
4978 if (xmlStrEqual((*cur)->href, nameSpace)) {
4979 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
4980 name, (*cur)->prefix);
4981 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4982 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
4983 name, (*cur)->prefix);
4984 }
4985 cur++;
4986 }
4987 xmlFree(nsList);
4988 xmlFree(ename);
4989 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004990 }
4991 }
4992 return(NULL);
4993}
4994
4995/**
Owen Taylor3473f882001-02-23 17:55:21 +00004996 * xmlGetProp:
4997 * @node: the node
4998 * @name: the attribute name
4999 *
5000 * Search and get the value of an attribute associated to a node
5001 * This does the entity substitution.
5002 * This function looks in DTD attribute declaration for #FIXED or
5003 * default declaration values unless DTD use has been turned off.
5004 *
5005 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005006 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005007 */
5008xmlChar *
5009xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5010 xmlAttrPtr prop;
5011 xmlDocPtr doc;
5012
5013 if ((node == NULL) || (name == NULL)) return(NULL);
5014 /*
5015 * Check on the properties attached to the node
5016 */
5017 prop = node->properties;
5018 while (prop != NULL) {
5019 if (xmlStrEqual(prop->name, name)) {
5020 xmlChar *ret;
5021
5022 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5023 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5024 return(ret);
5025 }
5026 prop = prop->next;
5027 }
5028 if (!xmlCheckDTD) return(NULL);
5029
5030 /*
5031 * Check if there is a default declaration in the internal
5032 * or external subsets
5033 */
5034 doc = node->doc;
5035 if (doc != NULL) {
5036 xmlAttributePtr attrDecl;
5037 if (doc->intSubset != NULL) {
5038 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5039 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5040 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5041 if (attrDecl != NULL)
5042 return(xmlStrdup(attrDecl->defaultValue));
5043 }
5044 }
5045 return(NULL);
5046}
5047
5048/**
5049 * xmlGetNsProp:
5050 * @node: the node
5051 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005052 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005053 *
5054 * Search and get the value of an attribute associated to a node
5055 * This attribute has to be anchored in the namespace specified.
5056 * This does the entity substitution.
5057 * This function looks in DTD attribute declaration for #FIXED or
5058 * default declaration values unless DTD use has been turned off.
5059 *
5060 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005061 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005062 */
5063xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005064xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005065 xmlAttrPtr prop;
5066 xmlDocPtr doc;
5067 xmlNsPtr ns;
5068
5069 if (node == NULL)
5070 return(NULL);
5071
5072 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005073 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005074 return(xmlGetProp(node, name));
5075 while (prop != NULL) {
5076 /*
5077 * One need to have
5078 * - same attribute names
5079 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005080 */
5081 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005082 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005083 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005084 xmlChar *ret;
5085
5086 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5087 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5088 return(ret);
5089 }
5090 prop = prop->next;
5091 }
5092 if (!xmlCheckDTD) return(NULL);
5093
5094 /*
5095 * Check if there is a default declaration in the internal
5096 * or external subsets
5097 */
5098 doc = node->doc;
5099 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005100 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005101 xmlAttributePtr attrDecl;
5102
Owen Taylor3473f882001-02-23 17:55:21 +00005103 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5104 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5105 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5106
5107 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5108 /*
5109 * The DTD declaration only allows a prefix search
5110 */
5111 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005112 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005113 return(xmlStrdup(attrDecl->defaultValue));
5114 }
5115 }
5116 }
5117 return(NULL);
5118}
5119
5120/**
5121 * xmlSetProp:
5122 * @node: the node
5123 * @name: the attribute name
5124 * @value: the attribute value
5125 *
5126 * Set (or reset) an attribute carried by a node.
5127 * Returns the attribute pointer.
5128 */
5129xmlAttrPtr
5130xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005131 xmlAttrPtr prop;
5132 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005133
5134 if ((node == NULL) || (name == NULL))
5135 return(NULL);
5136 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005137 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005138 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005139 if ((xmlStrEqual(prop->name, name)) &&
5140 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005141 xmlNodePtr oldprop = prop->children;
5142
Owen Taylor3473f882001-02-23 17:55:21 +00005143 prop->children = NULL;
5144 prop->last = NULL;
5145 if (value != NULL) {
5146 xmlChar *buffer;
5147 xmlNodePtr tmp;
5148
5149 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5150 prop->children = xmlStringGetNodeList(node->doc, buffer);
5151 prop->last = NULL;
5152 prop->doc = doc;
5153 tmp = prop->children;
5154 while (tmp != NULL) {
5155 tmp->parent = (xmlNodePtr) prop;
5156 tmp->doc = doc;
5157 if (tmp->next == NULL)
5158 prop->last = tmp;
5159 tmp = tmp->next;
5160 }
5161 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005162 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005163 if (oldprop != NULL)
5164 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005165 return(prop);
5166 }
5167 prop = prop->next;
5168 }
5169 prop = xmlNewProp(node, name, value);
5170 return(prop);
5171}
5172
5173/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005174 * xmlUnsetProp:
5175 * @node: the node
5176 * @name: the attribute name
5177 *
5178 * Remove an attribute carried by a node.
5179 * Returns 0 if successful, -1 if not found
5180 */
5181int
5182xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
5183 xmlAttrPtr prop = node->properties, prev = NULL;;
5184
5185 if ((node == NULL) || (name == NULL))
5186 return(-1);
5187 while (prop != NULL) {
5188 if ((xmlStrEqual(prop->name, name)) &&
5189 (prop->ns == NULL)) {
5190 if (prev == NULL)
5191 node->properties = prop->next;
5192 else
5193 prev->next = prop->next;
5194 xmlFreeProp(prop);
5195 return(0);
5196 }
5197 prev = prop;
5198 prop = prop->next;
5199 }
5200 return(-1);
5201}
5202
5203/**
Owen Taylor3473f882001-02-23 17:55:21 +00005204 * xmlSetNsProp:
5205 * @node: the node
5206 * @ns: the namespace definition
5207 * @name: the attribute name
5208 * @value: the attribute value
5209 *
5210 * Set (or reset) an attribute carried by a node.
5211 * The ns structure must be in scope, this is not checked.
5212 *
5213 * Returns the attribute pointer.
5214 */
5215xmlAttrPtr
5216xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5217 const xmlChar *value) {
5218 xmlAttrPtr prop;
5219
5220 if ((node == NULL) || (name == NULL))
5221 return(NULL);
5222
5223 if (ns == NULL)
5224 return(xmlSetProp(node, name, value));
5225 if (ns->href == NULL)
5226 return(NULL);
5227 prop = node->properties;
5228
5229 while (prop != NULL) {
5230 /*
5231 * One need to have
5232 * - same attribute names
5233 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005234 */
5235 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00005236 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005237 if (prop->children != NULL)
5238 xmlFreeNodeList(prop->children);
5239 prop->children = NULL;
5240 prop->last = NULL;
5241 prop->ns = ns;
5242 if (value != NULL) {
5243 xmlChar *buffer;
5244 xmlNodePtr tmp;
5245
5246 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5247 prop->children = xmlStringGetNodeList(node->doc, buffer);
5248 prop->last = NULL;
5249 tmp = prop->children;
5250 while (tmp != NULL) {
5251 tmp->parent = (xmlNodePtr) prop;
5252 if (tmp->next == NULL)
5253 prop->last = tmp;
5254 tmp = tmp->next;
5255 }
5256 xmlFree(buffer);
5257 }
5258 return(prop);
5259 }
5260 prop = prop->next;
5261 }
5262 prop = xmlNewNsProp(node, ns, name, value);
5263 return(prop);
5264}
5265
5266/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005267 * xmlUnsetNsProp:
5268 * @node: the node
5269 * @ns: the namespace definition
5270 * @name: the attribute name
5271 *
5272 * Remove an attribute carried by a node.
5273 * Returns 0 if successful, -1 if not found
5274 */
5275int
5276xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5277 xmlAttrPtr prop = node->properties, prev = NULL;;
5278
5279 if ((node == NULL) || (name == NULL))
5280 return(-1);
5281 if (ns == NULL)
5282 return(xmlUnsetProp(node, name));
5283 if (ns->href == NULL)
5284 return(-1);
5285 while (prop != NULL) {
5286 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00005287 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005288 if (prev == NULL)
5289 node->properties = prop->next;
5290 else
5291 prev->next = prop->next;
5292 xmlFreeProp(prop);
5293 return(0);
5294 }
5295 prev = prop;
5296 prop = prop->next;
5297 }
5298 return(-1);
5299}
5300
5301/**
Owen Taylor3473f882001-02-23 17:55:21 +00005302 * xmlNodeIsText:
5303 * @node: the node
5304 *
5305 * Is this node a Text node ?
5306 * Returns 1 yes, 0 no
5307 */
5308int
5309xmlNodeIsText(xmlNodePtr node) {
5310 if (node == NULL) return(0);
5311
5312 if (node->type == XML_TEXT_NODE) return(1);
5313 return(0);
5314}
5315
5316/**
5317 * xmlIsBlankNode:
5318 * @node: the node
5319 *
5320 * Checks whether this node is an empty or whitespace only
5321 * (and possibly ignorable) text-node.
5322 *
5323 * Returns 1 yes, 0 no
5324 */
5325int
5326xmlIsBlankNode(xmlNodePtr node) {
5327 const xmlChar *cur;
5328 if (node == NULL) return(0);
5329
Daniel Veillard7db37732001-07-12 01:20:08 +00005330 if ((node->type != XML_TEXT_NODE) &&
5331 (node->type != XML_CDATA_SECTION_NODE))
5332 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005333 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005334 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005335 while (*cur != 0) {
5336 if (!IS_BLANK(*cur)) return(0);
5337 cur++;
5338 }
5339
5340 return(1);
5341}
5342
5343/**
5344 * xmlTextConcat:
5345 * @node: the node
5346 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005347 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005348 *
5349 * Concat the given string at the end of the existing node content
5350 */
5351
5352void
5353xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5354 if (node == NULL) return;
5355
5356 if ((node->type != XML_TEXT_NODE) &&
5357 (node->type != XML_CDATA_SECTION_NODE)) {
5358#ifdef DEBUG_TREE
5359 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005360 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005361#endif
5362 return;
5363 }
Owen Taylor3473f882001-02-23 17:55:21 +00005364 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005365}
5366
5367/************************************************************************
5368 * *
5369 * Output : to a FILE or in memory *
5370 * *
5371 ************************************************************************/
5372
Owen Taylor3473f882001-02-23 17:55:21 +00005373/**
5374 * xmlBufferCreate:
5375 *
5376 * routine to create an XML buffer.
5377 * returns the new structure.
5378 */
5379xmlBufferPtr
5380xmlBufferCreate(void) {
5381 xmlBufferPtr ret;
5382
5383 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5384 if (ret == NULL) {
5385 xmlGenericError(xmlGenericErrorContext,
5386 "xmlBufferCreate : out of memory!\n");
5387 return(NULL);
5388 }
5389 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005390 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005391 ret->alloc = xmlBufferAllocScheme;
5392 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5393 if (ret->content == NULL) {
5394 xmlGenericError(xmlGenericErrorContext,
5395 "xmlBufferCreate : out of memory!\n");
5396 xmlFree(ret);
5397 return(NULL);
5398 }
5399 ret->content[0] = 0;
5400 return(ret);
5401}
5402
5403/**
5404 * xmlBufferCreateSize:
5405 * @size: initial size of buffer
5406 *
5407 * routine to create an XML buffer.
5408 * returns the new structure.
5409 */
5410xmlBufferPtr
5411xmlBufferCreateSize(size_t size) {
5412 xmlBufferPtr ret;
5413
5414 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5415 if (ret == NULL) {
5416 xmlGenericError(xmlGenericErrorContext,
5417 "xmlBufferCreate : out of memory!\n");
5418 return(NULL);
5419 }
5420 ret->use = 0;
5421 ret->alloc = xmlBufferAllocScheme;
5422 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5423 if (ret->size){
5424 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5425 if (ret->content == NULL) {
5426 xmlGenericError(xmlGenericErrorContext,
5427 "xmlBufferCreate : out of memory!\n");
5428 xmlFree(ret);
5429 return(NULL);
5430 }
5431 ret->content[0] = 0;
5432 } else
5433 ret->content = NULL;
5434 return(ret);
5435}
5436
5437/**
5438 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005439 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00005440 * @scheme: allocation scheme to use
5441 *
5442 * Sets the allocation scheme for this buffer
5443 */
5444void
5445xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5446 xmlBufferAllocationScheme scheme) {
5447 if (buf == NULL) {
5448#ifdef DEBUG_BUFFER
5449 xmlGenericError(xmlGenericErrorContext,
5450 "xmlBufferSetAllocationScheme: buf == NULL\n");
5451#endif
5452 return;
5453 }
5454
5455 buf->alloc = scheme;
5456}
5457
5458/**
5459 * xmlBufferFree:
5460 * @buf: the buffer to free
5461 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005462 * Frees an XML buffer. It frees both the content and the structure which
5463 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005464 */
5465void
5466xmlBufferFree(xmlBufferPtr buf) {
5467 if (buf == NULL) {
5468#ifdef DEBUG_BUFFER
5469 xmlGenericError(xmlGenericErrorContext,
5470 "xmlBufferFree: buf == NULL\n");
5471#endif
5472 return;
5473 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00005474 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005475 xmlFree(buf->content);
5476 }
Owen Taylor3473f882001-02-23 17:55:21 +00005477 xmlFree(buf);
5478}
5479
5480/**
5481 * xmlBufferEmpty:
5482 * @buf: the buffer
5483 *
5484 * empty a buffer.
5485 */
5486void
5487xmlBufferEmpty(xmlBufferPtr buf) {
5488 if (buf->content == NULL) return;
5489 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005490 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005491}
5492
5493/**
5494 * xmlBufferShrink:
5495 * @buf: the buffer to dump
5496 * @len: the number of xmlChar to remove
5497 *
5498 * Remove the beginning of an XML buffer.
5499 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005500 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005501 */
5502int
5503xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5504 if (len == 0) return(0);
5505 if (len > buf->use) return(-1);
5506
5507 buf->use -= len;
5508 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5509
5510 buf->content[buf->use] = 0;
5511 return(len);
5512}
5513
5514/**
5515 * xmlBufferGrow:
5516 * @buf: the buffer
5517 * @len: the minimum free size to allocate
5518 *
5519 * Grow the available space of an XML buffer.
5520 *
5521 * Returns the new available space or -1 in case of error
5522 */
5523int
5524xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5525 int size;
5526 xmlChar *newbuf;
5527
5528 if (len + buf->use < buf->size) return(0);
5529
5530 size = buf->use + len + 100;
5531
5532 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5533 if (newbuf == NULL) return(-1);
5534 buf->content = newbuf;
5535 buf->size = size;
5536 return(buf->size - buf->use);
5537}
5538
5539/**
5540 * xmlBufferDump:
5541 * @file: the file output
5542 * @buf: the buffer to dump
5543 *
5544 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005545 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005546 */
5547int
5548xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5549 int ret;
5550
5551 if (buf == NULL) {
5552#ifdef DEBUG_BUFFER
5553 xmlGenericError(xmlGenericErrorContext,
5554 "xmlBufferDump: buf == NULL\n");
5555#endif
5556 return(0);
5557 }
5558 if (buf->content == NULL) {
5559#ifdef DEBUG_BUFFER
5560 xmlGenericError(xmlGenericErrorContext,
5561 "xmlBufferDump: buf->content == NULL\n");
5562#endif
5563 return(0);
5564 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005565 if (file == NULL)
5566 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005567 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5568 return(ret);
5569}
5570
5571/**
5572 * xmlBufferContent:
5573 * @buf: the buffer
5574 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005575 * Function to extract the content of a buffer
5576 *
Owen Taylor3473f882001-02-23 17:55:21 +00005577 * Returns the internal content
5578 */
5579
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005580const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005581xmlBufferContent(const xmlBufferPtr buf)
5582{
5583 if(!buf)
5584 return NULL;
5585
5586 return buf->content;
5587}
5588
5589/**
5590 * xmlBufferLength:
5591 * @buf: the buffer
5592 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005593 * Function to get the length of a buffer
5594 *
Owen Taylor3473f882001-02-23 17:55:21 +00005595 * Returns the length of data in the internal content
5596 */
5597
5598int
5599xmlBufferLength(const xmlBufferPtr buf)
5600{
5601 if(!buf)
5602 return 0;
5603
5604 return buf->use;
5605}
5606
5607/**
5608 * xmlBufferResize:
5609 * @buf: the buffer to resize
5610 * @size: the desired size
5611 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005612 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005613 *
5614 * Returns 0 in case of problems, 1 otherwise
5615 */
5616int
5617xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5618{
5619 unsigned int newSize;
5620 xmlChar* rebuf = NULL;
5621
5622 /*take care of empty case*/
5623 newSize = (buf->size ? buf->size*2 : size);
5624
5625 /* Don't resize if we don't have to */
5626 if (size < buf->size)
5627 return 1;
5628
5629 /* figure out new size */
5630 switch (buf->alloc){
5631 case XML_BUFFER_ALLOC_DOUBLEIT:
5632 while (size > newSize) newSize *= 2;
5633 break;
5634 case XML_BUFFER_ALLOC_EXACT:
5635 newSize = size+10;
5636 break;
5637 default:
5638 newSize = size+10;
5639 break;
5640 }
5641
5642 if (buf->content == NULL)
5643 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5644 else
5645 rebuf = (xmlChar *) xmlRealloc(buf->content,
5646 newSize * sizeof(xmlChar));
5647 if (rebuf == NULL) {
5648 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005649 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005650 return 0;
5651 }
5652 buf->content = rebuf;
5653 buf->size = newSize;
5654
5655 return 1;
5656}
5657
5658/**
5659 * xmlBufferAdd:
5660 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005661 * @str: the #xmlChar string
5662 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005663 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005664 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005665 * str is recomputed.
5666 */
5667void
5668xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5669 unsigned int needSize;
5670
5671 if (str == NULL) {
5672#ifdef DEBUG_BUFFER
5673 xmlGenericError(xmlGenericErrorContext,
5674 "xmlBufferAdd: str == NULL\n");
5675#endif
5676 return;
5677 }
5678 if (len < -1) {
5679#ifdef DEBUG_BUFFER
5680 xmlGenericError(xmlGenericErrorContext,
5681 "xmlBufferAdd: len < 0\n");
5682#endif
5683 return;
5684 }
5685 if (len == 0) return;
5686
5687 if (len < 0)
5688 len = xmlStrlen(str);
5689
5690 if (len <= 0) return;
5691
5692 needSize = buf->use + len + 2;
5693 if (needSize > buf->size){
5694 if (!xmlBufferResize(buf, needSize)){
5695 xmlGenericError(xmlGenericErrorContext,
5696 "xmlBufferAdd : out of memory!\n");
5697 return;
5698 }
5699 }
5700
5701 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5702 buf->use += len;
5703 buf->content[buf->use] = 0;
5704}
5705
5706/**
5707 * xmlBufferAddHead:
5708 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005709 * @str: the #xmlChar string
5710 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005711 *
5712 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005713 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005714 */
5715void
5716xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5717 unsigned int needSize;
5718
5719 if (str == NULL) {
5720#ifdef DEBUG_BUFFER
5721 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005722 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005723#endif
5724 return;
5725 }
5726 if (len < -1) {
5727#ifdef DEBUG_BUFFER
5728 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005729 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005730#endif
5731 return;
5732 }
5733 if (len == 0) return;
5734
5735 if (len < 0)
5736 len = xmlStrlen(str);
5737
5738 if (len <= 0) return;
5739
5740 needSize = buf->use + len + 2;
5741 if (needSize > buf->size){
5742 if (!xmlBufferResize(buf, needSize)){
5743 xmlGenericError(xmlGenericErrorContext,
5744 "xmlBufferAddHead : out of memory!\n");
5745 return;
5746 }
5747 }
5748
5749 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5750 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5751 buf->use += len;
5752 buf->content[buf->use] = 0;
5753}
5754
5755/**
5756 * xmlBufferCat:
5757 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005758 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005759 *
5760 * Append a zero terminated string to an XML buffer.
5761 */
5762void
5763xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5764 if (str != NULL)
5765 xmlBufferAdd(buf, str, -1);
5766}
5767
5768/**
5769 * xmlBufferCCat:
5770 * @buf: the buffer to dump
5771 * @str: the C char string
5772 *
5773 * Append a zero terminated C string to an XML buffer.
5774 */
5775void
5776xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5777 const char *cur;
5778
5779 if (str == NULL) {
5780#ifdef DEBUG_BUFFER
5781 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005782 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005783#endif
5784 return;
5785 }
5786 for (cur = str;*cur != 0;cur++) {
5787 if (buf->use + 10 >= buf->size) {
5788 if (!xmlBufferResize(buf, buf->use+10)){
5789 xmlGenericError(xmlGenericErrorContext,
5790 "xmlBufferCCat : out of memory!\n");
5791 return;
5792 }
5793 }
5794 buf->content[buf->use++] = *cur;
5795 }
5796 buf->content[buf->use] = 0;
5797}
5798
5799/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005800 * xmlBufferWriteXmlCHAR:
5801 * @buf: the XML buffer
5802 * @string: the string to add
5803 *
5804 * For VMS only.
5805 * routine which manages and grows an output buffer. This one adds
5806 * xmlChars at the end of the buffer.
5807 */
5808/**
Owen Taylor3473f882001-02-23 17:55:21 +00005809 * xmlBufferWriteCHAR:
5810 * @buf: the XML buffer
5811 * @string: the string to add
5812 *
5813 * routine which manages and grows an output buffer. This one adds
5814 * xmlChars at the end of the buffer.
5815 */
5816void
5817#ifdef VMS
5818xmlBufferWriteXmlCHAR
5819#else
5820xmlBufferWriteCHAR
5821#endif
5822(xmlBufferPtr buf, const xmlChar *string) {
5823 xmlBufferCat(buf, string);
5824}
5825
5826/**
5827 * xmlBufferWriteChar:
5828 * @buf: the XML buffer output
5829 * @string: the string to add
5830 *
5831 * routine which manage and grows an output buffer. This one add
5832 * C chars at the end of the array.
5833 */
5834void
5835xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5836 xmlBufferCCat(buf, string);
5837}
5838
5839
5840/**
5841 * xmlBufferWriteQuotedString:
5842 * @buf: the XML buffer output
5843 * @string: the string to add
5844 *
5845 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005846 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005847 * quote or double-quotes internally
5848 */
5849void
5850xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5851 if (xmlStrchr(string, '"')) {
5852 if (xmlStrchr(string, '\'')) {
5853#ifdef DEBUG_BUFFER
5854 xmlGenericError(xmlGenericErrorContext,
5855 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5856#endif
5857 }
5858 xmlBufferCCat(buf, "'");
5859 xmlBufferCat(buf, string);
5860 xmlBufferCCat(buf, "'");
5861 } else {
5862 xmlBufferCCat(buf, "\"");
5863 xmlBufferCat(buf, string);
5864 xmlBufferCCat(buf, "\"");
5865 }
5866}
5867
5868
5869/************************************************************************
5870 * *
5871 * Dumping XML tree content to a simple buffer *
5872 * *
5873 ************************************************************************/
5874
Owen Taylor3473f882001-02-23 17:55:21 +00005875static void
5876xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5877 int format);
5878void
5879htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5880
5881/**
5882 * xmlNsDump:
5883 * @buf: the XML buffer output
5884 * @cur: a namespace
5885 *
5886 * Dump a local Namespace definition.
5887 * Should be called in the context of attributes dumps.
5888 */
5889static void
5890xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5891 if (cur == NULL) {
5892#ifdef DEBUG_TREE
5893 xmlGenericError(xmlGenericErrorContext,
5894 "xmlNsDump : Ns == NULL\n");
5895#endif
5896 return;
5897 }
5898 if (cur->type == XML_LOCAL_NAMESPACE) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005899 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
5900 return;
5901
Owen Taylor3473f882001-02-23 17:55:21 +00005902 /* Within the context of an element attributes */
5903 if (cur->prefix != NULL) {
5904 xmlBufferWriteChar(buf, " xmlns:");
5905 xmlBufferWriteCHAR(buf, cur->prefix);
5906 } else
5907 xmlBufferWriteChar(buf, " xmlns");
5908 xmlBufferWriteChar(buf, "=");
5909 xmlBufferWriteQuotedString(buf, cur->href);
5910 }
5911}
5912
5913/**
5914 * xmlNsListDump:
5915 * @buf: the XML buffer output
5916 * @cur: the first namespace
5917 *
5918 * Dump a list of local Namespace definitions.
5919 * Should be called in the context of attributes dumps.
5920 */
5921static void
5922xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5923 while (cur != NULL) {
5924 xmlNsDump(buf, cur);
5925 cur = cur->next;
5926 }
5927}
5928
5929/**
5930 * xmlDtdDump:
5931 * @buf: the XML buffer output
Daniel Veillardd1640922001-12-17 15:30:10 +00005932 * @dtd: the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00005933 *
5934 * Dump the XML document DTD, if any.
5935 */
5936static void
5937xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5938 if (dtd == NULL) {
5939#ifdef DEBUG_TREE
5940 xmlGenericError(xmlGenericErrorContext,
5941 "xmlDtdDump : no internal subset\n");
5942#endif
5943 return;
5944 }
5945 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5946 xmlBufferWriteCHAR(buf, dtd->name);
5947 if (dtd->ExternalID != NULL) {
5948 xmlBufferWriteChar(buf, " PUBLIC ");
5949 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5950 xmlBufferWriteChar(buf, " ");
5951 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5952 } else if (dtd->SystemID != NULL) {
5953 xmlBufferWriteChar(buf, " SYSTEM ");
5954 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5955 }
5956 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5957 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5958 xmlBufferWriteChar(buf, ">");
5959 return;
5960 }
5961 xmlBufferWriteChar(buf, " [\n");
5962 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5963#if 0
5964 if (dtd->entities != NULL)
5965 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5966 if (dtd->notations != NULL)
5967 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5968 if (dtd->elements != NULL)
5969 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5970 if (dtd->attributes != NULL)
5971 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5972#endif
5973 xmlBufferWriteChar(buf, "]>");
5974}
5975
5976/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00005977 * xmlAttrSerializeContent:
5978 * @buf: the XML buffer output
5979 * @doc: the document
5980 * @attr: the attribute pointer
5981 *
5982 * Serialize the attribute in the buffer
5983 */
5984static void
5985xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr) {
5986 const xmlChar *cur, *base;
5987 xmlNodePtr children;
5988
5989 children = attr->children;
5990 while (children != NULL) {
5991 switch (children->type) {
5992 case XML_TEXT_NODE:
5993 base = cur = children->content;
5994 while (*cur != 0) {
5995 if (*cur == '\n') {
5996 if (base != cur)
5997 xmlBufferAdd(buf, base, cur - base);
5998 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
5999 cur++;
6000 base = cur;
6001#if 0
6002 } else if (*cur == '\'') {
6003 if (base != cur)
6004 xmlBufferAdd(buf, base, cur - base);
6005 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
6006 cur++;
6007 base = cur;
6008#endif
6009 } else if (*cur == '"') {
6010 if (base != cur)
6011 xmlBufferAdd(buf, base, cur - base);
6012 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6013 cur++;
6014 base = cur;
6015 } else if (*cur == '<') {
6016 if (base != cur)
6017 xmlBufferAdd(buf, base, cur - base);
6018 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6019 cur++;
6020 base = cur;
6021 } else if (*cur == '>') {
6022 if (base != cur)
6023 xmlBufferAdd(buf, base, cur - base);
6024 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6025 cur++;
6026 base = cur;
6027 } else if (*cur == '&') {
6028 if (base != cur)
6029 xmlBufferAdd(buf, base, cur - base);
6030 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6031 cur++;
6032 base = cur;
6033 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6034 (doc->encoding == NULL))) {
6035 /*
6036 * We assume we have UTF-8 content.
6037 */
6038 char tmp[10];
6039 int val = 0, l = 1;
6040
6041 if (base != cur)
6042 xmlBufferAdd(buf, base, cur - base);
6043 if (*cur < 0xC0) {
6044 xmlGenericError(xmlGenericErrorContext,
6045 "xmlAttrSerializeContent : input not UTF-8\n");
6046 if (doc != NULL)
6047 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
6048 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6049 tmp[sizeof(tmp) - 1] = 0;
6050 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6051 cur++;
6052 base = cur;
6053 continue;
6054 } else if (*cur < 0xE0) {
6055 val = (cur[0]) & 0x1F;
6056 val <<= 6;
6057 val |= (cur[1]) & 0x3F;
6058 l = 2;
6059 } else if (*cur < 0xF0) {
6060 val = (cur[0]) & 0x0F;
6061 val <<= 6;
6062 val |= (cur[1]) & 0x3F;
6063 val <<= 6;
6064 val |= (cur[2]) & 0x3F;
6065 l = 3;
6066 } else if (*cur < 0xF8) {
6067 val = (cur[0]) & 0x07;
6068 val <<= 6;
6069 val |= (cur[1]) & 0x3F;
6070 val <<= 6;
6071 val |= (cur[2]) & 0x3F;
6072 val <<= 6;
6073 val |= (cur[3]) & 0x3F;
6074 l = 4;
6075 }
6076 if ((l == 1) || (!IS_CHAR(val))) {
6077 xmlGenericError(xmlGenericErrorContext,
6078 "xmlAttrSerializeContent : char out of range\n");
6079 if (doc != NULL)
6080 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
6081 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6082 tmp[sizeof(tmp) - 1] = 0;
6083 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6084 cur++;
6085 base = cur;
6086 continue;
6087 }
6088 /*
6089 * We could do multiple things here. Just save
6090 * as a char ref
6091 */
6092 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6093 tmp[sizeof(tmp) - 1] = 0;
6094 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6095 cur += l;
6096 base = cur;
6097 } else {
6098 cur++;
6099 }
6100 }
6101 if (base != cur)
6102 xmlBufferAdd(buf, base, cur - base);
6103 break;
6104 case XML_ENTITY_REF_NODE:
6105 xmlBufferAdd(buf, BAD_CAST "&", 1);
6106 xmlBufferAdd(buf, children->name, xmlStrlen(children->name));
6107 xmlBufferAdd(buf, BAD_CAST ";", 1);
6108 break;
6109 default:
6110 /* should not happen unless we have a badly built tree */
6111 break;
6112 }
6113 children = children->next;
6114 }
6115}
6116
6117/**
Owen Taylor3473f882001-02-23 17:55:21 +00006118 * xmlAttrDump:
6119 * @buf: the XML buffer output
6120 * @doc: the document
6121 * @cur: the attribute pointer
6122 *
6123 * Dump an XML attribute
6124 */
6125static void
6126xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00006127 if (cur == NULL) {
6128#ifdef DEBUG_TREE
6129 xmlGenericError(xmlGenericErrorContext,
6130 "xmlAttrDump : property == NULL\n");
6131#endif
6132 return;
6133 }
6134 xmlBufferWriteChar(buf, " ");
6135 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6136 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6137 xmlBufferWriteChar(buf, ":");
6138 }
6139 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006140 xmlBufferWriteChar(buf, "=\"");
6141 xmlAttrSerializeContent(buf, doc, cur);
6142 xmlBufferWriteChar(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006143}
6144
6145/**
6146 * xmlAttrListDump:
6147 * @buf: the XML buffer output
6148 * @doc: the document
6149 * @cur: the first attribute pointer
6150 *
6151 * Dump a list of XML attributes
6152 */
6153static void
6154xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
6155 if (cur == NULL) {
6156#ifdef DEBUG_TREE
6157 xmlGenericError(xmlGenericErrorContext,
6158 "xmlAttrListDump : property == NULL\n");
6159#endif
6160 return;
6161 }
6162 while (cur != NULL) {
6163 xmlAttrDump(buf, doc, cur);
6164 cur = cur->next;
6165 }
6166}
6167
6168
6169
6170/**
6171 * xmlNodeListDump:
6172 * @buf: the XML buffer output
6173 * @doc: the document
6174 * @cur: the first node
6175 * @level: the imbrication level for indenting
6176 * @format: is formatting allowed
6177 *
6178 * Dump an XML node list, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006179 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6180 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006181 */
6182static void
6183xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
6184 int format) {
6185 int i;
6186
6187 if (cur == NULL) {
6188#ifdef DEBUG_TREE
6189 xmlGenericError(xmlGenericErrorContext,
6190 "xmlNodeListDump : node == NULL\n");
6191#endif
6192 return;
6193 }
6194 while (cur != NULL) {
6195 if ((format) && (xmlIndentTreeOutput) &&
6196 (cur->type == XML_ELEMENT_NODE))
6197 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006198 xmlBufferWriteChar(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006199 xmlNodeDump(buf, doc, cur, level, format);
6200 if (format) {
6201 xmlBufferWriteChar(buf, "\n");
6202 }
6203 cur = cur->next;
6204 }
6205}
6206
6207/**
6208 * xmlNodeDump:
6209 * @buf: the XML buffer output
6210 * @doc: the document
6211 * @cur: the current node
6212 * @level: the imbrication level for indenting
6213 * @format: is formatting allowed
6214 *
6215 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006216 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6217 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006218 */
6219void
6220xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
6221 int format) {
6222 int i;
6223 xmlNodePtr tmp;
6224
6225 if (cur == NULL) {
6226#ifdef DEBUG_TREE
6227 xmlGenericError(xmlGenericErrorContext,
6228 "xmlNodeDump : node == NULL\n");
6229#endif
6230 return;
6231 }
6232 if (cur->type == XML_XINCLUDE_START)
6233 return;
6234 if (cur->type == XML_XINCLUDE_END)
6235 return;
6236 if (cur->type == XML_DTD_NODE) {
6237 xmlDtdDump(buf, (xmlDtdPtr) cur);
6238 return;
6239 }
6240 if (cur->type == XML_ELEMENT_DECL) {
6241 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
6242 return;
6243 }
Daniel Veillard78d12092001-10-11 09:12:24 +00006244 if (cur->type == XML_ATTRIBUTE_NODE){
6245 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
6246 return;
6247 }
Owen Taylor3473f882001-02-23 17:55:21 +00006248 if (cur->type == XML_ATTRIBUTE_DECL) {
6249 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
6250 return;
6251 }
6252 if (cur->type == XML_ENTITY_DECL) {
6253 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
6254 return;
6255 }
6256 if (cur->type == XML_TEXT_NODE) {
6257 if (cur->content != NULL) {
6258 if ((cur->name == xmlStringText) ||
6259 (cur->name != xmlStringTextNoenc)) {
6260 xmlChar *buffer;
6261
Owen Taylor3473f882001-02-23 17:55:21 +00006262 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006263 if (buffer != NULL) {
6264 xmlBufferWriteCHAR(buf, buffer);
6265 xmlFree(buffer);
6266 }
6267 } else {
6268 /*
6269 * Disable escaping, needed for XSLT
6270 */
Owen Taylor3473f882001-02-23 17:55:21 +00006271 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006272 }
6273 }
6274 return;
6275 }
6276 if (cur->type == XML_PI_NODE) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00006277 xmlBufferWriteChar(buf, "<?");
6278 xmlBufferWriteCHAR(buf, cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006279 if (cur->content != NULL) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00006280 xmlBufferWriteChar(buf, " ");
Daniel Veillard2c748c62002-01-16 15:37:50 +00006281 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006282 }
Daniel Veillard2c748c62002-01-16 15:37:50 +00006283 xmlBufferWriteChar(buf, "?>");
Owen Taylor3473f882001-02-23 17:55:21 +00006284 return;
6285 }
6286 if (cur->type == XML_COMMENT_NODE) {
6287 if (cur->content != NULL) {
6288 xmlBufferWriteChar(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006289 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006290 xmlBufferWriteChar(buf, "-->");
6291 }
6292 return;
6293 }
6294 if (cur->type == XML_ENTITY_REF_NODE) {
6295 xmlBufferWriteChar(buf, "&");
6296 xmlBufferWriteCHAR(buf, cur->name);
6297 xmlBufferWriteChar(buf, ";");
6298 return;
6299 }
6300 if (cur->type == XML_CDATA_SECTION_NODE) {
6301 xmlBufferWriteChar(buf, "<![CDATA[");
6302 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006303 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006304 xmlBufferWriteChar(buf, "]]>");
6305 return;
6306 }
6307
6308 if (format == 1) {
6309 tmp = cur->children;
6310 while (tmp != NULL) {
6311 if ((tmp->type == XML_TEXT_NODE) ||
6312 (tmp->type == XML_ENTITY_REF_NODE)) {
6313 format = 0;
6314 break;
6315 }
6316 tmp = tmp->next;
6317 }
6318 }
6319 xmlBufferWriteChar(buf, "<");
6320 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6321 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6322 xmlBufferWriteChar(buf, ":");
6323 }
6324
6325 xmlBufferWriteCHAR(buf, cur->name);
6326 if (cur->nsDef)
6327 xmlNsListDump(buf, cur->nsDef);
6328 if (cur->properties != NULL)
6329 xmlAttrListDump(buf, doc, cur->properties);
6330
Daniel Veillard7db37732001-07-12 01:20:08 +00006331 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6332 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00006333 (!xmlSaveNoEmptyTags)) {
6334 xmlBufferWriteChar(buf, "/>");
6335 return;
6336 }
6337 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006338 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006339 xmlChar *buffer;
6340
Owen Taylor3473f882001-02-23 17:55:21 +00006341 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006342 if (buffer != NULL) {
6343 xmlBufferWriteCHAR(buf, buffer);
6344 xmlFree(buffer);
6345 }
6346 }
6347 if (cur->children != NULL) {
6348 if (format) xmlBufferWriteChar(buf, "\n");
6349 xmlNodeListDump(buf, doc, cur->children,
6350 (level >= 0?level+1:-1), format);
6351 if ((xmlIndentTreeOutput) && (format))
6352 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006353 xmlBufferWriteChar(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006354 }
6355 xmlBufferWriteChar(buf, "</");
6356 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6357 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6358 xmlBufferWriteChar(buf, ":");
6359 }
6360
6361 xmlBufferWriteCHAR(buf, cur->name);
6362 xmlBufferWriteChar(buf, ">");
6363}
6364
6365/**
6366 * xmlElemDump:
6367 * @f: the FILE * for the output
6368 * @doc: the document
6369 * @cur: the current node
6370 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006371 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006372 */
6373void
6374xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
6375 xmlBufferPtr buf;
6376
6377 if (cur == NULL) {
6378#ifdef DEBUG_TREE
6379 xmlGenericError(xmlGenericErrorContext,
6380 "xmlElemDump : cur == NULL\n");
6381#endif
6382 return;
6383 }
Owen Taylor3473f882001-02-23 17:55:21 +00006384#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006385 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006386 xmlGenericError(xmlGenericErrorContext,
6387 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006388 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006389#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00006390
Owen Taylor3473f882001-02-23 17:55:21 +00006391 buf = xmlBufferCreate();
6392 if (buf == NULL) return;
6393 if ((doc != NULL) &&
6394 (doc->type == XML_HTML_DOCUMENT_NODE)) {
6395#ifdef LIBXML_HTML_ENABLED
6396 htmlNodeDump(buf, doc, cur);
6397#else
6398 xmlGenericError(xmlGenericErrorContext,
6399 "HTML support not compiled in\n");
6400#endif /* LIBXML_HTML_ENABLED */
6401 } else
6402 xmlNodeDump(buf, doc, cur, 0, 1);
6403 xmlBufferDump(f, buf);
6404 xmlBufferFree(buf);
6405}
6406
6407/************************************************************************
6408 * *
6409 * Dumping XML tree content to an I/O output buffer *
6410 * *
6411 ************************************************************************/
6412
Owen Taylor3473f882001-02-23 17:55:21 +00006413static void
6414xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6415 int level, int format, const char *encoding);
6416/**
6417 * xmlNsDumpOutput:
6418 * @buf: the XML buffer output
6419 * @cur: a namespace
6420 *
6421 * Dump a local Namespace definition.
6422 * Should be called in the context of attributes dumps.
6423 */
6424static void
6425xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6426 if (cur == NULL) {
6427#ifdef DEBUG_TREE
6428 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006429 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006430#endif
6431 return;
6432 }
6433 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006434 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6435 return;
6436
Owen Taylor3473f882001-02-23 17:55:21 +00006437 /* Within the context of an element attributes */
6438 if (cur->prefix != NULL) {
6439 xmlOutputBufferWriteString(buf, " xmlns:");
6440 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6441 } else
6442 xmlOutputBufferWriteString(buf, " xmlns");
6443 xmlOutputBufferWriteString(buf, "=");
6444 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6445 }
6446}
6447
6448/**
6449 * xmlNsListDumpOutput:
6450 * @buf: the XML buffer output
6451 * @cur: the first namespace
6452 *
6453 * Dump a list of local Namespace definitions.
6454 * Should be called in the context of attributes dumps.
6455 */
6456static void
6457xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6458 while (cur != NULL) {
6459 xmlNsDumpOutput(buf, cur);
6460 cur = cur->next;
6461 }
6462}
6463
6464/**
6465 * xmlDtdDumpOutput:
6466 * @buf: the XML buffer output
6467 * @doc: the document
6468 * @encoding: an optional encoding string
6469 *
6470 * Dump the XML document DTD, if any.
6471 */
6472static void
6473xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6474 if (dtd == NULL) {
6475#ifdef DEBUG_TREE
6476 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006477 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006478#endif
6479 return;
6480 }
6481 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6482 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6483 if (dtd->ExternalID != NULL) {
6484 xmlOutputBufferWriteString(buf, " PUBLIC ");
6485 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6486 xmlOutputBufferWriteString(buf, " ");
6487 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6488 } else if (dtd->SystemID != NULL) {
6489 xmlOutputBufferWriteString(buf, " SYSTEM ");
6490 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6491 }
6492 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6493 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6494 xmlOutputBufferWriteString(buf, ">");
6495 return;
6496 }
6497 xmlOutputBufferWriteString(buf, " [\n");
6498 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6499 xmlOutputBufferWriteString(buf, "]>");
6500}
6501
6502/**
6503 * xmlAttrDumpOutput:
6504 * @buf: the XML buffer output
6505 * @doc: the document
6506 * @cur: the attribute pointer
6507 * @encoding: an optional encoding string
6508 *
6509 * Dump an XML attribute
6510 */
6511static void
6512xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006513 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006514 if (cur == NULL) {
6515#ifdef DEBUG_TREE
6516 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006517 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006518#endif
6519 return;
6520 }
6521 xmlOutputBufferWriteString(buf, " ");
6522 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6523 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6524 xmlOutputBufferWriteString(buf, ":");
6525 }
6526 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006527 xmlOutputBufferWriteString(buf, "=\"");
6528 xmlAttrSerializeContent(buf->buffer, doc, cur);
6529 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006530}
6531
6532/**
6533 * xmlAttrListDumpOutput:
6534 * @buf: the XML buffer output
6535 * @doc: the document
6536 * @cur: the first attribute pointer
6537 * @encoding: an optional encoding string
6538 *
6539 * Dump a list of XML attributes
6540 */
6541static void
6542xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6543 xmlAttrPtr cur, const char *encoding) {
6544 if (cur == NULL) {
6545#ifdef DEBUG_TREE
6546 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006547 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006548#endif
6549 return;
6550 }
6551 while (cur != NULL) {
6552 xmlAttrDumpOutput(buf, doc, cur, encoding);
6553 cur = cur->next;
6554 }
6555}
6556
6557
6558
6559/**
6560 * xmlNodeListDumpOutput:
6561 * @buf: the XML buffer output
6562 * @doc: the document
6563 * @cur: the first node
6564 * @level: the imbrication level for indenting
6565 * @format: is formatting allowed
6566 * @encoding: an optional encoding string
6567 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006568 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006569 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6570 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006571 */
6572static void
6573xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6574 xmlNodePtr cur, int level, int format, const char *encoding) {
6575 int i;
6576
6577 if (cur == NULL) {
6578#ifdef DEBUG_TREE
6579 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006580 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006581#endif
6582 return;
6583 }
6584 while (cur != NULL) {
6585 if ((format) && (xmlIndentTreeOutput) &&
6586 (cur->type == XML_ELEMENT_NODE))
6587 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006588 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006589 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6590 if (format) {
6591 xmlOutputBufferWriteString(buf, "\n");
6592 }
6593 cur = cur->next;
6594 }
6595}
6596
6597/**
6598 * xmlNodeDumpOutput:
6599 * @buf: the XML buffer output
6600 * @doc: the document
6601 * @cur: the current node
6602 * @level: the imbrication level for indenting
6603 * @format: is formatting allowed
6604 * @encoding: an optional encoding string
6605 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006606 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006607 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6608 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006609 */
6610void
6611xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6612 int level, int format, const char *encoding) {
6613 int i;
6614 xmlNodePtr tmp;
6615
6616 if (cur == NULL) {
6617#ifdef DEBUG_TREE
6618 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006619 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006620#endif
6621 return;
6622 }
6623 if (cur->type == XML_XINCLUDE_START)
6624 return;
6625 if (cur->type == XML_XINCLUDE_END)
6626 return;
6627 if (cur->type == XML_DTD_NODE) {
6628 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6629 return;
6630 }
6631 if (cur->type == XML_ELEMENT_DECL) {
6632 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6633 return;
6634 }
6635 if (cur->type == XML_ATTRIBUTE_DECL) {
6636 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6637 return;
6638 }
6639 if (cur->type == XML_ENTITY_DECL) {
6640 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6641 return;
6642 }
6643 if (cur->type == XML_TEXT_NODE) {
6644 if (cur->content != NULL) {
6645 if ((cur->name == xmlStringText) ||
6646 (cur->name != xmlStringTextNoenc)) {
6647 xmlChar *buffer;
6648
Owen Taylor3473f882001-02-23 17:55:21 +00006649 if (encoding == NULL)
6650 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6651 else
6652 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006653 if (buffer != NULL) {
6654 xmlOutputBufferWriteString(buf, (const char *)buffer);
6655 xmlFree(buffer);
6656 }
6657 } else {
6658 /*
6659 * Disable escaping, needed for XSLT
6660 */
Owen Taylor3473f882001-02-23 17:55:21 +00006661 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006662 }
6663 }
6664
6665 return;
6666 }
6667 if (cur->type == XML_PI_NODE) {
6668 if (cur->content != NULL) {
6669 xmlOutputBufferWriteString(buf, "<?");
6670 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6671 if (cur->content != NULL) {
6672 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006673 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006674 }
6675 xmlOutputBufferWriteString(buf, "?>");
6676 } else {
6677 xmlOutputBufferWriteString(buf, "<?");
6678 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6679 xmlOutputBufferWriteString(buf, "?>");
6680 }
6681 return;
6682 }
6683 if (cur->type == XML_COMMENT_NODE) {
6684 if (cur->content != NULL) {
6685 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006686 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006687 xmlOutputBufferWriteString(buf, "-->");
6688 }
6689 return;
6690 }
6691 if (cur->type == XML_ENTITY_REF_NODE) {
6692 xmlOutputBufferWriteString(buf, "&");
6693 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6694 xmlOutputBufferWriteString(buf, ";");
6695 return;
6696 }
6697 if (cur->type == XML_CDATA_SECTION_NODE) {
6698 xmlOutputBufferWriteString(buf, "<![CDATA[");
6699 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006700 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006701 xmlOutputBufferWriteString(buf, "]]>");
6702 return;
6703 }
6704
6705 if (format == 1) {
6706 tmp = cur->children;
6707 while (tmp != NULL) {
6708 if ((tmp->type == XML_TEXT_NODE) ||
6709 (tmp->type == XML_ENTITY_REF_NODE)) {
6710 format = 0;
6711 break;
6712 }
6713 tmp = tmp->next;
6714 }
6715 }
6716 xmlOutputBufferWriteString(buf, "<");
6717 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6718 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6719 xmlOutputBufferWriteString(buf, ":");
6720 }
6721
6722 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6723 if (cur->nsDef)
6724 xmlNsListDumpOutput(buf, cur->nsDef);
6725 if (cur->properties != NULL)
6726 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6727
Daniel Veillard7db37732001-07-12 01:20:08 +00006728 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6729 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006730 xmlOutputBufferWriteString(buf, "/>");
6731 return;
6732 }
6733 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006734 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006735 xmlChar *buffer;
6736
Owen Taylor3473f882001-02-23 17:55:21 +00006737 if (encoding == NULL)
6738 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6739 else
6740 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006741 if (buffer != NULL) {
6742 xmlOutputBufferWriteString(buf, (const char *)buffer);
6743 xmlFree(buffer);
6744 }
6745 }
6746 if (cur->children != NULL) {
6747 if (format) xmlOutputBufferWriteString(buf, "\n");
6748 xmlNodeListDumpOutput(buf, doc, cur->children,
6749 (level >= 0?level+1:-1), format, encoding);
6750 if ((xmlIndentTreeOutput) && (format))
6751 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006752 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006753 }
6754 xmlOutputBufferWriteString(buf, "</");
6755 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6756 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6757 xmlOutputBufferWriteString(buf, ":");
6758 }
6759
6760 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6761 xmlOutputBufferWriteString(buf, ">");
6762}
6763
6764/**
6765 * xmlDocContentDumpOutput:
6766 * @buf: the XML buffer output
6767 * @cur: the document
6768 * @encoding: an optional encoding string
6769 * @format: should formatting spaces been added
6770 *
6771 * Dump an XML document.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006772 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6773 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006774 */
6775static void
6776xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6777 const char *encoding, int format) {
6778 xmlOutputBufferWriteString(buf, "<?xml version=");
6779 if (cur->version != NULL)
6780 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6781 else
6782 xmlOutputBufferWriteString(buf, "\"1.0\"");
6783 if (encoding == NULL) {
6784 if (cur->encoding != NULL)
6785 encoding = (const char *) cur->encoding;
6786 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6787 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6788 }
6789 if (encoding != NULL) {
6790 xmlOutputBufferWriteString(buf, " encoding=");
6791 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6792 }
6793 switch (cur->standalone) {
6794 case 0:
6795 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6796 break;
6797 case 1:
6798 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6799 break;
6800 }
6801 xmlOutputBufferWriteString(buf, "?>\n");
6802 if (cur->children != NULL) {
6803 xmlNodePtr child = cur->children;
6804
6805 while (child != NULL) {
6806 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6807 xmlOutputBufferWriteString(buf, "\n");
6808 child = child->next;
6809 }
6810 }
6811}
6812
6813/************************************************************************
6814 * *
6815 * Saving functions front-ends *
6816 * *
6817 ************************************************************************/
6818
6819/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006820 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006821 * @out_doc: Document to generate XML text from
6822 * @doc_txt_ptr: Memory pointer for allocated XML text
6823 * @doc_txt_len: Length of the generated XML text
6824 * @txt_encoding: Character encoding to use when generating XML text
6825 * @format: should formatting spaces been added
6826 *
6827 * Dump the current DOM tree into memory using the character encoding specified
6828 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006829 * allocated memory with xmlFree().
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006830 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6831 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006832 */
6833
6834void
6835xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006836 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006837 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006838 int dummy = 0;
6839
6840 xmlCharEncoding doc_charset;
6841 xmlOutputBufferPtr out_buff = NULL;
6842 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6843
6844 if (doc_txt_len == NULL) {
6845 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6846 }
6847
6848 if (doc_txt_ptr == NULL) {
6849 *doc_txt_len = 0;
6850 xmlGenericError(xmlGenericErrorContext,
6851 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6852 return;
6853 }
6854
6855 *doc_txt_ptr = NULL;
6856 *doc_txt_len = 0;
6857
6858 if (out_doc == NULL) {
6859 /* No document, no output */
6860 xmlGenericError(xmlGenericErrorContext,
6861 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6862 return;
6863 }
6864
6865 /*
6866 * Validate the encoding value, if provided.
6867 * This logic is copied from xmlSaveFileEnc.
6868 */
6869
6870 if (txt_encoding == NULL)
6871 txt_encoding = (const char *) out_doc->encoding;
6872 if (txt_encoding != NULL) {
6873 doc_charset = xmlParseCharEncoding(txt_encoding);
6874
6875 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6876 xmlGenericError(xmlGenericErrorContext,
6877 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6878 return;
6879
6880 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6881 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6882 if ( conv_hdlr == NULL ) {
6883 xmlGenericError(xmlGenericErrorContext,
6884 "%s: %s %s '%s'\n",
6885 "xmlDocDumpFormatMemoryEnc",
6886 "Failed to identify encoding handler for",
6887 "character set",
6888 txt_encoding);
6889 return;
6890 }
6891 }
6892 }
6893
6894 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6895 xmlGenericError(xmlGenericErrorContext,
6896 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6897 return;
6898 }
6899
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006900 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006901 xmlOutputBufferFlush(out_buff);
6902 if (out_buff->conv != NULL) {
6903 *doc_txt_len = out_buff->conv->use;
6904 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6905 } else {
6906 *doc_txt_len = out_buff->buffer->use;
6907 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6908 }
6909 (void)xmlOutputBufferClose(out_buff);
6910
6911 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6912 *doc_txt_len = 0;
6913 xmlGenericError(xmlGenericErrorContext,
6914 "xmlDocDumpFormatMemoryEnc: %s\n",
6915 "Failed to allocate memory for document text representation.");
6916 }
6917
6918 return;
6919}
6920
6921/**
6922 * xmlDocDumpMemory:
6923 * @cur: the document
6924 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006925 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006926 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006927 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006928 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006929 */
6930void
6931xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6932 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6933}
6934
6935/**
6936 * xmlDocDumpFormatMemory:
6937 * @cur: the document
6938 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006939 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006940 * @format: should formatting spaces been added
6941 *
6942 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006943 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006944 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006945 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6946 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006947 */
6948void
6949xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6950 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6951}
6952
6953/**
6954 * xmlDocDumpMemoryEnc:
6955 * @out_doc: Document to generate XML text from
6956 * @doc_txt_ptr: Memory pointer for allocated XML text
6957 * @doc_txt_len: Length of the generated XML text
6958 * @txt_encoding: Character encoding to use when generating XML text
6959 *
6960 * Dump the current DOM tree into memory using the character encoding specified
6961 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006962 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006963 */
6964
6965void
6966xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6967 int * doc_txt_len, const char * txt_encoding) {
6968 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006969 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006970}
6971
6972/**
6973 * xmlGetDocCompressMode:
6974 * @doc: the document
6975 *
6976 * get the compression ratio for a document, ZLIB based
6977 * Returns 0 (uncompressed) to 9 (max compression)
6978 */
6979int
6980xmlGetDocCompressMode (xmlDocPtr doc) {
6981 if (doc == NULL) return(-1);
6982 return(doc->compression);
6983}
6984
6985/**
6986 * xmlSetDocCompressMode:
6987 * @doc: the document
6988 * @mode: the compression ratio
6989 *
6990 * set the compression ratio for a document, ZLIB based
6991 * Correct values: 0 (uncompressed) to 9 (max compression)
6992 */
6993void
6994xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6995 if (doc == NULL) return;
6996 if (mode < 0) doc->compression = 0;
6997 else if (mode > 9) doc->compression = 9;
6998 else doc->compression = mode;
6999}
7000
7001/**
7002 * xmlGetCompressMode:
7003 *
7004 * get the default compression mode used, ZLIB based.
7005 * Returns 0 (uncompressed) to 9 (max compression)
7006 */
7007int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007008xmlGetCompressMode(void)
7009{
7010 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00007011}
7012
7013/**
7014 * xmlSetCompressMode:
7015 * @mode: the compression ratio
7016 *
7017 * set the default compression mode used, ZLIB based
7018 * Correct values: 0 (uncompressed) to 9 (max compression)
7019 */
7020void
7021xmlSetCompressMode(int mode) {
7022 if (mode < 0) xmlCompressMode = 0;
7023 else if (mode > 9) xmlCompressMode = 9;
7024 else xmlCompressMode = mode;
7025}
7026
7027/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007028 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00007029 * @f: the FILE*
7030 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00007031 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007032 *
7033 * Dump an XML document to an open FILE.
7034 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007035 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007036 */
7037int
Daniel Veillard9e412302002-06-10 15:59:44 +00007038xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007039 xmlOutputBufferPtr buf;
7040 const char * encoding;
7041 xmlCharEncodingHandlerPtr handler = NULL;
7042 int ret;
7043
7044 if (cur == NULL) {
7045#ifdef DEBUG_TREE
7046 xmlGenericError(xmlGenericErrorContext,
7047 "xmlDocDump : document == NULL\n");
7048#endif
7049 return(-1);
7050 }
7051 encoding = (const char *) cur->encoding;
7052
7053 if (encoding != NULL) {
7054 xmlCharEncoding enc;
7055
7056 enc = xmlParseCharEncoding(encoding);
7057
7058 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7059 xmlGenericError(xmlGenericErrorContext,
7060 "xmlDocDump: document not in UTF8\n");
7061 return(-1);
7062 }
7063 if (enc != XML_CHAR_ENCODING_UTF8) {
7064 handler = xmlFindCharEncodingHandler(encoding);
7065 if (handler == NULL) {
7066 xmlFree((char *) cur->encoding);
7067 cur->encoding = NULL;
7068 }
7069 }
7070 }
7071 buf = xmlOutputBufferCreateFile(f, handler);
7072 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00007073 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007074
7075 ret = xmlOutputBufferClose(buf);
7076 return(ret);
7077}
7078
7079/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007080 * xmlDocDump:
7081 * @f: the FILE*
7082 * @cur: the document
7083 *
7084 * Dump an XML document to an open FILE.
7085 *
7086 * returns: the number of bytes written or -1 in case of failure.
7087 */
7088int
7089xmlDocDump(FILE *f, xmlDocPtr cur) {
7090 return(xmlDocFormatDump (f, cur, 0));
7091}
7092
7093/**
Owen Taylor3473f882001-02-23 17:55:21 +00007094 * xmlSaveFileTo:
7095 * @buf: an output I/O buffer
7096 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007097 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00007098 *
7099 * Dump an XML document to an I/O buffer.
7100 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007101 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007102 */
7103int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007104xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007105 int ret;
7106
7107 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007108 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007109 ret = xmlOutputBufferClose(buf);
7110 return(ret);
7111}
7112
7113/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00007114 * xmlSaveFormatFileTo:
7115 * @buf: an output I/O buffer
7116 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007117 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00007118 * @format: should formatting spaces been added
7119 *
7120 * Dump an XML document to an I/O buffer.
7121 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007122 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00007123 */
7124int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007125xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00007126 int ret;
7127
7128 if (buf == NULL) return(0);
7129 xmlDocContentDumpOutput(buf, cur, encoding, format);
7130 ret = xmlOutputBufferClose(buf);
7131 return(ret);
7132}
7133
7134/**
Daniel Veillardf012a642001-07-23 19:10:52 +00007135 * xmlSaveFormatFileEnc
7136 * @filename: the filename or URL to output
7137 * @cur: the document being saved
7138 * @encoding: the name of the encoding to use or NULL.
7139 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00007140 *
7141 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00007142 */
7143int
Daniel Veillardf012a642001-07-23 19:10:52 +00007144xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
7145 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00007146 xmlOutputBufferPtr buf;
7147 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00007148 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00007149 int ret;
7150
Daniel Veillardfb25a512002-01-13 20:32:08 +00007151 if (encoding == NULL)
7152 encoding = (const char *) cur->encoding;
7153
Owen Taylor3473f882001-02-23 17:55:21 +00007154 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007155
7156 enc = xmlParseCharEncoding(encoding);
7157 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7158 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007159 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007160 return(-1);
7161 }
7162 if (enc != XML_CHAR_ENCODING_UTF8) {
7163 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00007164 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007165 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007166 }
7167 }
7168
Daniel Veillardf012a642001-07-23 19:10:52 +00007169#ifdef HAVE_ZLIB_H
7170 if (cur->compression < 0) cur->compression = xmlCompressMode;
7171#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007172 /*
7173 * save the content to a temp buffer.
7174 */
Daniel Veillardf012a642001-07-23 19:10:52 +00007175 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00007176 if (buf == NULL) return(-1);
7177
Daniel Veillardf012a642001-07-23 19:10:52 +00007178 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007179
7180 ret = xmlOutputBufferClose(buf);
7181 return(ret);
7182}
7183
Daniel Veillardf012a642001-07-23 19:10:52 +00007184
7185/**
7186 * xmlSaveFileEnc:
7187 * @filename: the filename (or URL)
7188 * @cur: the document
7189 * @encoding: the name of an encoding (or NULL)
7190 *
7191 * Dump an XML document, converting it to the given encoding
7192 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007193 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00007194 */
7195int
7196xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
7197 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
7198}
7199
Owen Taylor3473f882001-02-23 17:55:21 +00007200/**
Daniel Veillard67fee942001-04-26 18:59:03 +00007201 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00007202 * @filename: the filename (or URL)
7203 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00007204 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007205 *
7206 * Dump an XML document to a file. Will use compression if
7207 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00007208 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00007209 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007210 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007211 */
7212int
Daniel Veillard67fee942001-04-26 18:59:03 +00007213xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007214 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00007215}
7216
Daniel Veillard67fee942001-04-26 18:59:03 +00007217/**
7218 * xmlSaveFile:
7219 * @filename: the filename (or URL)
7220 * @cur: the document
7221 *
7222 * Dump an XML document to a file. Will use compression if
7223 * compiled in and enabled. If @filename is "-" the stdout file is
7224 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00007225 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00007226 */
7227int
7228xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007229 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00007230}
7231