blob: 26276ca1e457e752ca59a00a1a6c809420fac7cf [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00006 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00007 *
Owen Taylor3473f882001-02-23 17:55:21 +00008 */
9
Daniel Veillard34ce8be2002-03-18 19:37:11 +000010#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000011#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000012
Owen Taylor3473f882001-02-23 17:55:21 +000013#include <string.h> /* for memset() only ! */
14
15#ifdef HAVE_CTYPE_H
16#include <ctype.h>
17#endif
18#ifdef HAVE_STDLIB_H
19#include <stdlib.h>
20#endif
21#ifdef HAVE_ZLIB_H
22#include <zlib.h>
23#endif
24
25#include <libxml/xmlmemory.h>
26#include <libxml/tree.h>
27#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000028#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000029#include <libxml/entities.h>
30#include <libxml/valid.h>
31#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000032#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000033#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000034
Daniel Veillard56a4cb82001-03-24 17:00:36 +000035xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
36
37/************************************************************************
38 * *
39 * A few static variables and macros *
40 * *
41 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000042/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000043const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000044/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000045const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000046 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000047/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +000048const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
49
Owen Taylor3473f882001-02-23 17:55:21 +000050static int xmlCompressMode = 0;
51static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000052
Owen Taylor3473f882001-02-23 17:55:21 +000053#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
54 xmlNodePtr ulccur = (n)->children; \
55 if (ulccur == NULL) { \
56 (n)->last = NULL; \
57 } else { \
58 while (ulccur->next != NULL) { \
59 ulccur->parent = (n); \
60 ulccur = ulccur->next; \
61 } \
62 ulccur->parent = (n); \
63 (n)->last = ulccur; \
64}}
65
66/* #define DEBUG_BUFFER */
67/* #define DEBUG_TREE */
68
69/************************************************************************
70 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +000071 * Functions to move to entities.c once the *
72 * API freeze is smoothen and they can be made public. *
73 * *
74 ************************************************************************/
75#include <libxml/hash.h>
76
77/**
78 * xmlGetEntityFromDtd:
79 * @dtd: A pointer to the DTD to search
80 * @name: The entity name
81 *
82 * Do an entity lookup in the DTD entity hash table and
83 * return the corresponding entity, if found.
84 *
85 * Returns A pointer to the entity structure or NULL if not found.
86 */
87static xmlEntityPtr
88xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
89 xmlEntitiesTablePtr table;
90
91 if((dtd != NULL) && (dtd->entities != NULL)) {
92 table = (xmlEntitiesTablePtr) dtd->entities;
93 return((xmlEntityPtr) xmlHashLookup(table, name));
94 /* return(xmlGetEntityFromTable(table, name)); */
95 }
96 return(NULL);
97}
98/**
99 * xmlGetParameterEntityFromDtd:
100 * @dtd: A pointer to the DTD to search
101 * @name: The entity name
102 *
103 * Do an entity lookup in the DTD pararmeter entity hash table and
104 * return the corresponding entity, if found.
105 *
106 * Returns A pointer to the entity structure or NULL if not found.
107 */
108static xmlEntityPtr
109xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
110 xmlEntitiesTablePtr table;
111
112 if ((dtd != NULL) && (dtd->pentities != NULL)) {
113 table = (xmlEntitiesTablePtr) dtd->pentities;
114 return((xmlEntityPtr) xmlHashLookup(table, name));
115 /* return(xmlGetEntityFromTable(table, name)); */
116 }
117 return(NULL);
118}
119
120/************************************************************************
121 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000122 * Allocation and deallocation of basic structures *
123 * *
124 ************************************************************************/
125
126/**
127 * xmlSetBufferAllocationScheme:
128 * @scheme: allocation method to use
129 *
130 * Set the buffer allocation method. Types are
131 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
132 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
133 * improves performance
134 */
135void
136xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
137 xmlBufferAllocScheme = scheme;
138}
139
140/**
141 * xmlGetBufferAllocationScheme:
142 *
143 * Types are
144 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
145 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
146 * improves performance
147 *
148 * Returns the current allocation scheme
149 */
150xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000151xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000152 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000153}
154
155/**
156 * xmlNewNs:
157 * @node: the element carrying the namespace
158 * @href: the URI associated
159 * @prefix: the prefix for the namespace
160 *
161 * Creation of a new Namespace. This function will refuse to create
162 * a namespace with a similar prefix than an existing one present on this
163 * node.
164 * We use href==NULL in the case of an element creation where the namespace
165 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000166 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000167 */
168xmlNsPtr
169xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
170 xmlNsPtr cur;
171
172 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
173 return(NULL);
174
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000175 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
176 return(NULL);
177
Owen Taylor3473f882001-02-23 17:55:21 +0000178 /*
179 * Allocate a new Namespace and fill the fields.
180 */
181 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
182 if (cur == NULL) {
183 xmlGenericError(xmlGenericErrorContext,
184 "xmlNewNs : malloc failed\n");
185 return(NULL);
186 }
187 memset(cur, 0, sizeof(xmlNs));
188 cur->type = XML_LOCAL_NAMESPACE;
189
190 if (href != NULL)
191 cur->href = xmlStrdup(href);
192 if (prefix != NULL)
193 cur->prefix = xmlStrdup(prefix);
194
195 /*
196 * Add it at the end to preserve parsing order ...
197 * and checks for existing use of the prefix
198 */
199 if (node != NULL) {
200 if (node->nsDef == NULL) {
201 node->nsDef = cur;
202 } else {
203 xmlNsPtr prev = node->nsDef;
204
205 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
206 (xmlStrEqual(prev->prefix, cur->prefix))) {
207 xmlFreeNs(cur);
208 return(NULL);
209 }
210 while (prev->next != NULL) {
211 prev = prev->next;
212 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
213 (xmlStrEqual(prev->prefix, cur->prefix))) {
214 xmlFreeNs(cur);
215 return(NULL);
216 }
217 }
218 prev->next = cur;
219 }
220 }
221 return(cur);
222}
223
224/**
225 * xmlSetNs:
226 * @node: a node in the document
227 * @ns: a namespace pointer
228 *
229 * Associate a namespace to a node, a posteriori.
230 */
231void
232xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
233 if (node == NULL) {
234#ifdef DEBUG_TREE
235 xmlGenericError(xmlGenericErrorContext,
236 "xmlSetNs: node == NULL\n");
237#endif
238 return;
239 }
240 node->ns = ns;
241}
242
243/**
244 * xmlFreeNs:
245 * @cur: the namespace pointer
246 *
247 * Free up the structures associated to a namespace
248 */
249void
250xmlFreeNs(xmlNsPtr cur) {
251 if (cur == NULL) {
252#ifdef DEBUG_TREE
253 xmlGenericError(xmlGenericErrorContext,
254 "xmlFreeNs : ns == NULL\n");
255#endif
256 return;
257 }
258 if (cur->href != NULL) xmlFree((char *) cur->href);
259 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000260 xmlFree(cur);
261}
262
263/**
264 * xmlFreeNsList:
265 * @cur: the first namespace pointer
266 *
267 * Free up all the structures associated to the chained namespaces.
268 */
269void
270xmlFreeNsList(xmlNsPtr cur) {
271 xmlNsPtr next;
272 if (cur == NULL) {
273#ifdef DEBUG_TREE
274 xmlGenericError(xmlGenericErrorContext,
275 "xmlFreeNsList : ns == NULL\n");
276#endif
277 return;
278 }
279 while (cur != NULL) {
280 next = cur->next;
281 xmlFreeNs(cur);
282 cur = next;
283 }
284}
285
286/**
287 * xmlNewDtd:
288 * @doc: the document pointer
289 * @name: the DTD name
290 * @ExternalID: the external ID
291 * @SystemID: the system ID
292 *
293 * Creation of a new DTD for the external subset. To create an
294 * internal subset, use xmlCreateIntSubset().
295 *
296 * Returns a pointer to the new DTD structure
297 */
298xmlDtdPtr
299xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
300 const xmlChar *ExternalID, const xmlChar *SystemID) {
301 xmlDtdPtr cur;
302
303 if ((doc != NULL) && (doc->extSubset != NULL)) {
304#ifdef DEBUG_TREE
305 xmlGenericError(xmlGenericErrorContext,
306 "xmlNewDtd(%s): document %s already have a DTD %s\n",
307 /* !!! */ (char *) name, doc->name,
308 /* !!! */ (char *)doc->extSubset->name);
309#endif
310 return(NULL);
311 }
312
313 /*
314 * Allocate a new DTD and fill the fields.
315 */
316 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
317 if (cur == NULL) {
318 xmlGenericError(xmlGenericErrorContext,
319 "xmlNewDtd : malloc failed\n");
320 return(NULL);
321 }
322 memset(cur, 0 , sizeof(xmlDtd));
323 cur->type = XML_DTD_NODE;
324
325 if (name != NULL)
326 cur->name = xmlStrdup(name);
327 if (ExternalID != NULL)
328 cur->ExternalID = xmlStrdup(ExternalID);
329 if (SystemID != NULL)
330 cur->SystemID = xmlStrdup(SystemID);
331 if (doc != NULL)
332 doc->extSubset = cur;
333 cur->doc = doc;
334
335 return(cur);
336}
337
338/**
339 * xmlGetIntSubset:
340 * @doc: the document pointer
341 *
342 * Get the internal subset of a document
343 * Returns a pointer to the DTD structure or NULL if not found
344 */
345
346xmlDtdPtr
347xmlGetIntSubset(xmlDocPtr doc) {
348 xmlNodePtr cur;
349
350 if (doc == NULL)
351 return(NULL);
352 cur = doc->children;
353 while (cur != NULL) {
354 if (cur->type == XML_DTD_NODE)
355 return((xmlDtdPtr) cur);
356 cur = cur->next;
357 }
358 return((xmlDtdPtr) doc->intSubset);
359}
360
361/**
362 * xmlCreateIntSubset:
363 * @doc: the document pointer
364 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000365 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000366 * @SystemID: the system ID
367 *
368 * Create the internal subset of a document
369 * Returns a pointer to the new DTD structure
370 */
371xmlDtdPtr
372xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
373 const xmlChar *ExternalID, const xmlChar *SystemID) {
374 xmlDtdPtr cur;
375
376 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
377#ifdef DEBUG_TREE
378 xmlGenericError(xmlGenericErrorContext,
379
380 "xmlCreateIntSubset(): document %s already have an internal subset\n",
381 doc->name);
382#endif
383 return(NULL);
384 }
385
386 /*
387 * Allocate a new DTD and fill the fields.
388 */
389 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
390 if (cur == NULL) {
391 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000392 "xmlCreateIntSubset : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000393 return(NULL);
394 }
395 memset(cur, 0, sizeof(xmlDtd));
396 cur->type = XML_DTD_NODE;
397
398 if (name != NULL)
399 cur->name = xmlStrdup(name);
400 if (ExternalID != NULL)
401 cur->ExternalID = xmlStrdup(ExternalID);
402 if (SystemID != NULL)
403 cur->SystemID = xmlStrdup(SystemID);
404 if (doc != NULL) {
405 doc->intSubset = cur;
406 cur->parent = doc;
407 cur->doc = doc;
408 if (doc->children == NULL) {
409 doc->children = (xmlNodePtr) cur;
410 doc->last = (xmlNodePtr) cur;
411 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000412 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000413 xmlNodePtr prev;
414
Owen Taylor3473f882001-02-23 17:55:21 +0000415 prev = doc->children;
416 prev->prev = (xmlNodePtr) cur;
417 cur->next = prev;
418 doc->children = (xmlNodePtr) cur;
419 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000420 xmlNodePtr next;
421
422 next = doc->children;
423 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
424 next = next->next;
425 if (next == NULL) {
426 cur->prev = doc->last;
427 cur->prev->next = (xmlNodePtr) cur;
428 cur->next = NULL;
429 doc->last = (xmlNodePtr) cur;
430 } else {
431 cur->next = next;
432 cur->prev = next->prev;
433 if (cur->prev == NULL)
434 doc->children = (xmlNodePtr) cur;
435 else
436 cur->prev->next = (xmlNodePtr) cur;
437 next->prev = (xmlNodePtr) cur;
438 }
Owen Taylor3473f882001-02-23 17:55:21 +0000439 }
440 }
441 }
442 return(cur);
443}
444
445/**
446 * xmlFreeDtd:
447 * @cur: the DTD structure to free up
448 *
449 * Free a DTD structure.
450 */
451void
452xmlFreeDtd(xmlDtdPtr cur) {
453 if (cur == NULL) {
454#ifdef DEBUG_TREE
455 xmlGenericError(xmlGenericErrorContext,
456 "xmlFreeDtd : DTD == NULL\n");
457#endif
458 return;
459 }
460 if (cur->children != NULL) {
461 xmlNodePtr next, c = cur->children;
462
463 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000464 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000465 * indexes.
466 */
467 while (c != NULL) {
468 next = c->next;
469 if (c->type == XML_COMMENT_NODE) {
470 xmlUnlinkNode(c);
471 xmlFreeNode(c);
472 }
473 c = next;
474 }
475 }
476 if (cur->name != NULL) xmlFree((char *) cur->name);
477 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
478 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
479 /* TODO !!! */
480 if (cur->notations != NULL)
481 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
482
483 if (cur->elements != NULL)
484 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
485 if (cur->attributes != NULL)
486 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
487 if (cur->entities != NULL)
488 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
489 if (cur->pentities != NULL)
490 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
491
Owen Taylor3473f882001-02-23 17:55:21 +0000492 xmlFree(cur);
493}
494
495/**
496 * xmlNewDoc:
497 * @version: xmlChar string giving the version of XML "1.0"
498 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000499 * Creates a new XML document
500 *
Owen Taylor3473f882001-02-23 17:55:21 +0000501 * Returns a new document
502 */
503xmlDocPtr
504xmlNewDoc(const xmlChar *version) {
505 xmlDocPtr cur;
506
507 if (version == NULL)
508 version = (const xmlChar *) "1.0";
509
510 /*
511 * Allocate a new document and fill the fields.
512 */
513 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
514 if (cur == NULL) {
515 xmlGenericError(xmlGenericErrorContext,
516 "xmlNewDoc : malloc failed\n");
517 return(NULL);
518 }
519 memset(cur, 0, sizeof(xmlDoc));
520 cur->type = XML_DOCUMENT_NODE;
521
522 cur->version = xmlStrdup(version);
523 cur->standalone = -1;
524 cur->compression = -1; /* not initialized */
525 cur->doc = cur;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000526 cur->charset = XML_CHAR_ENCODING_UTF8;
Owen Taylor3473f882001-02-23 17:55:21 +0000527 return(cur);
528}
529
530/**
531 * xmlFreeDoc:
532 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +0000533 *
534 * Free up all the structures used by a document, tree included.
535 */
536void
537xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000538 xmlDtdPtr extSubset, intSubset;
539
Owen Taylor3473f882001-02-23 17:55:21 +0000540 if (cur == NULL) {
541#ifdef DEBUG_TREE
542 xmlGenericError(xmlGenericErrorContext,
543 "xmlFreeDoc : document == NULL\n");
544#endif
545 return;
546 }
Daniel Veillard76d66f42001-05-16 21:05:17 +0000547 /*
548 * Do this before freeing the children list to avoid ID lookups
549 */
550 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
551 cur->ids = NULL;
552 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
553 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000554 extSubset = cur->extSubset;
555 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +0000556 if (intSubset == extSubset)
557 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000558 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000559 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000560 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000561 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000562 }
Daniel Veillarda9142e72001-06-19 11:07:54 +0000563 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000564 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000565 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000566 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000567 }
568
569 if (cur->children != NULL) xmlFreeNodeList(cur->children);
570
Owen Taylor3473f882001-02-23 17:55:21 +0000571 if (cur->version != NULL) xmlFree((char *) cur->version);
572 if (cur->name != NULL) xmlFree((char *) cur->name);
573 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +0000574 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +0000575 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000576 xmlFree(cur);
577}
578
579/**
580 * xmlStringLenGetNodeList:
581 * @doc: the document
582 * @value: the value of the text
583 * @len: the length of the string value
584 *
585 * Parse the value string and build the node list associated. Should
586 * produce a flat tree with only TEXTs and ENTITY_REFs.
587 * Returns a pointer to the first child
588 */
589xmlNodePtr
590xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
591 xmlNodePtr ret = NULL, last = NULL;
592 xmlNodePtr node;
593 xmlChar *val;
594 const xmlChar *cur = value;
595 const xmlChar *q;
596 xmlEntityPtr ent;
597
598 if (value == NULL) return(NULL);
599
600 q = cur;
601 while ((*cur != 0) && (cur - value < len)) {
602 if (*cur == '&') {
603 /*
604 * Save the current text.
605 */
606 if (cur != q) {
607 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
608 xmlNodeAddContentLen(last, q, cur - q);
609 } else {
610 node = xmlNewDocTextLen(doc, q, cur - q);
611 if (node == NULL) return(ret);
612 if (last == NULL)
613 last = ret = node;
614 else {
615 last->next = node;
616 node->prev = last;
617 last = node;
618 }
619 }
620 }
621 /*
622 * Read the entity string
623 */
624 cur++;
625 q = cur;
626 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
627 if ((*cur == 0) || (cur - value >= len)) {
628#ifdef DEBUG_TREE
629 xmlGenericError(xmlGenericErrorContext,
630 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
631#endif
632 return(ret);
633 }
634 if (cur != q) {
635 /*
636 * Predefined entities don't generate nodes
637 */
638 val = xmlStrndup(q, cur - q);
639 ent = xmlGetDocEntity(doc, val);
640 if ((ent != NULL) &&
641 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
642 if (last == NULL) {
643 node = xmlNewDocText(doc, ent->content);
644 last = ret = node;
645 } else
646 xmlNodeAddContent(last, ent->content);
647
648 } else {
649 /*
650 * Create a new REFERENCE_REF node
651 */
652 node = xmlNewReference(doc, val);
653 if (node == NULL) {
654 if (val != NULL) xmlFree(val);
655 return(ret);
656 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000657 else if ((ent != NULL) && (ent->children == NULL)) {
658 xmlNodePtr tmp;
659
660 ent->children =
661 xmlStringGetNodeList(doc, (const xmlChar*)node->content);
662 tmp = ent->children;
663 while (tmp) {
664 tmp->parent = (xmlNodePtr)ent;
665 tmp = tmp->next;
666 }
667 }
Owen Taylor3473f882001-02-23 17:55:21 +0000668 if (last == NULL)
669 last = ret = node;
670 else {
671 last->next = node;
672 node->prev = last;
673 last = node;
674 }
675 }
676 xmlFree(val);
677 }
678 cur++;
679 q = cur;
680 } else
681 cur++;
682 }
683 if (cur != q) {
684 /*
685 * Handle the last piece of text.
686 */
687 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
688 xmlNodeAddContentLen(last, q, cur - q);
689 } else {
690 node = xmlNewDocTextLen(doc, q, cur - q);
691 if (node == NULL) return(ret);
692 if (last == NULL)
693 last = ret = node;
694 else {
695 last->next = node;
696 node->prev = last;
697 last = node;
698 }
699 }
700 }
701 return(ret);
702}
703
704/**
705 * xmlStringGetNodeList:
706 * @doc: the document
707 * @value: the value of the attribute
708 *
709 * Parse the value string and build the node list associated. Should
710 * produce a flat tree with only TEXTs and ENTITY_REFs.
711 * Returns a pointer to the first child
712 */
713xmlNodePtr
714xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
715 xmlNodePtr ret = NULL, last = NULL;
716 xmlNodePtr node;
717 xmlChar *val;
718 const xmlChar *cur = value;
719 const xmlChar *q;
720 xmlEntityPtr ent;
721
722 if (value == NULL) return(NULL);
723
724 q = cur;
725 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000726 if (cur[0] == '&') {
727 int charval = 0;
728 xmlChar tmp;
729
Owen Taylor3473f882001-02-23 17:55:21 +0000730 /*
731 * Save the current text.
732 */
733 if (cur != q) {
734 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
735 xmlNodeAddContentLen(last, q, cur - q);
736 } else {
737 node = xmlNewDocTextLen(doc, q, cur - q);
738 if (node == NULL) return(ret);
739 if (last == NULL)
740 last = ret = node;
741 else {
742 last->next = node;
743 node->prev = last;
744 last = node;
745 }
746 }
747 }
Owen Taylor3473f882001-02-23 17:55:21 +0000748 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000749 if ((cur[1] == '#') && (cur[2] == 'x')) {
750 cur += 3;
751 tmp = *cur;
752 while (tmp != ';') { /* Non input consuming loop */
753 if ((tmp >= '0') && (tmp <= '9'))
754 charval = charval * 16 + (tmp - '0');
755 else if ((tmp >= 'a') && (tmp <= 'f'))
756 charval = charval * 16 + (tmp - 'a') + 10;
757 else if ((tmp >= 'A') && (tmp <= 'F'))
758 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +0000759 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000760 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000761 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000762 charval = 0;
763 break;
764 }
765 cur++;
766 tmp = *cur;
767 }
768 if (tmp == ';')
769 cur++;
770 q = cur;
771 } else if (cur[1] == '#') {
772 cur += 2;
773 tmp = *cur;
774 while (tmp != ';') { /* Non input consuming loops */
775 if ((tmp >= '0') && (tmp <= '9'))
776 charval = charval * 10 + (tmp - '0');
777 else {
778 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000779 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000780 charval = 0;
781 break;
782 }
783 cur++;
784 tmp = *cur;
785 }
786 if (tmp == ';')
787 cur++;
788 q = cur;
789 } else {
790 /*
791 * Read the entity string
792 */
793 cur++;
794 q = cur;
795 while ((*cur != 0) && (*cur != ';')) cur++;
796 if (*cur == 0) {
797#ifdef DEBUG_TREE
798 xmlGenericError(xmlGenericErrorContext,
799 "xmlStringGetNodeList: unterminated entity %30s\n", q);
800#endif
801 return(ret);
802 }
803 if (cur != q) {
804 /*
805 * Predefined entities don't generate nodes
806 */
807 val = xmlStrndup(q, cur - q);
808 ent = xmlGetDocEntity(doc, val);
809 if ((ent != NULL) &&
810 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
811 if (last == NULL) {
812 node = xmlNewDocText(doc, ent->content);
813 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +0000814 } else if (last->type != XML_TEXT_NODE) {
815 node = xmlNewDocText(doc, ent->content);
816 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000817 } else
818 xmlNodeAddContent(last, ent->content);
819
820 } else {
821 /*
822 * Create a new REFERENCE_REF node
823 */
824 node = xmlNewReference(doc, val);
825 if (node == NULL) {
826 if (val != NULL) xmlFree(val);
827 return(ret);
828 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000829 else if ((ent != NULL) && (ent->children == NULL)) {
830 xmlNodePtr temp;
831
832 ent->children = xmlStringGetNodeList(doc,
833 (const xmlChar*)node->content);
834 temp = ent->children;
835 while (temp) {
836 temp->parent = (xmlNodePtr)ent;
837 temp = temp->next;
838 }
839 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000840 if (last == NULL) {
841 last = ret = node;
842 } else {
843 last = xmlAddNextSibling(last, node);
844 }
845 }
846 xmlFree(val);
847 }
848 cur++;
849 q = cur;
850 }
851 if (charval != 0) {
852 xmlChar buf[10];
853 int len;
854
855 len = xmlCopyCharMultiByte(buf, charval);
856 buf[len] = 0;
857 node = xmlNewDocText(doc, buf);
858 if (node != NULL) {
859 if (last == NULL) {
860 last = ret = node;
861 } else {
862 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000863 }
864 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000865
866 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000867 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000868 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000869 cur++;
870 }
Daniel Veillard75bea542001-05-11 17:41:21 +0000871 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000872 /*
873 * Handle the last piece of text.
874 */
875 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
876 xmlNodeAddContentLen(last, q, cur - q);
877 } else {
878 node = xmlNewDocTextLen(doc, q, cur - q);
879 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000880 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000881 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000882 } else {
883 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000884 }
885 }
886 }
887 return(ret);
888}
889
890/**
891 * xmlNodeListGetString:
892 * @doc: the document
893 * @list: a Node list
894 * @inLine: should we replace entity contents or show their external form
895 *
896 * Returns the string equivalent to the text contained in the Node list
897 * made of TEXTs and ENTITY_REFs
Daniel Veillardbd9afb52002-09-25 22:25:35 +0000898 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +0000899 */
900xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +0000901xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
902{
Owen Taylor3473f882001-02-23 17:55:21 +0000903 xmlNodePtr node = list;
904 xmlChar *ret = NULL;
905 xmlEntityPtr ent;
906
Daniel Veillard7646b182002-04-20 06:41:40 +0000907 if (list == NULL)
908 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000909
910 while (node != NULL) {
911 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +0000912 (node->type == XML_CDATA_SECTION_NODE)) {
913 if (inLine) {
914 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000915 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +0000916 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +0000917
Daniel Veillard7646b182002-04-20 06:41:40 +0000918 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
919 if (buffer != NULL) {
920 ret = xmlStrcat(ret, buffer);
921 xmlFree(buffer);
922 }
923 }
924 } else if (node->type == XML_ENTITY_REF_NODE) {
925 if (inLine) {
926 ent = xmlGetDocEntity(doc, node->name);
927 if (ent != NULL) {
928 xmlChar *buffer;
929
930 /* an entity content can be any "well balanced chunk",
931 * i.e. the result of the content [43] production:
932 * http://www.w3.org/TR/REC-xml#NT-content.
933 * So it can contain text, CDATA section or nested
934 * entity reference nodes (among others).
935 * -> we recursive call xmlNodeListGetString()
936 * which handles these types */
937 buffer = xmlNodeListGetString(doc, ent->children, 1);
938 if (buffer != NULL) {
939 ret = xmlStrcat(ret, buffer);
940 xmlFree(buffer);
941 }
942 } else {
943 ret = xmlStrcat(ret, node->content);
944 }
945 } else {
946 xmlChar buf[2];
947
948 buf[0] = '&';
949 buf[1] = 0;
950 ret = xmlStrncat(ret, buf, 1);
951 ret = xmlStrcat(ret, node->name);
952 buf[0] = ';';
953 buf[1] = 0;
954 ret = xmlStrncat(ret, buf, 1);
955 }
956 }
957#if 0
958 else {
959 xmlGenericError(xmlGenericErrorContext,
960 "xmlGetNodeListString : invalid node type %d\n",
961 node->type);
962 }
963#endif
964 node = node->next;
965 }
966 return (ret);
967}
Owen Taylor3473f882001-02-23 17:55:21 +0000968/**
969 * xmlNodeListGetRawString:
970 * @doc: the document
971 * @list: a Node list
972 * @inLine: should we replace entity contents or show their external form
973 *
974 * Returns the string equivalent to the text contained in the Node list
975 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
976 * this function doesn't do any character encoding handling.
977 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +0000978 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +0000979 */
980xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +0000981xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
982{
Owen Taylor3473f882001-02-23 17:55:21 +0000983 xmlNodePtr node = list;
984 xmlChar *ret = NULL;
985 xmlEntityPtr ent;
986
Daniel Veillard7646b182002-04-20 06:41:40 +0000987 if (list == NULL)
988 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000989
990 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +0000991 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +0000992 (node->type == XML_CDATA_SECTION_NODE)) {
993 if (inLine) {
994 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000995 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +0000996 xmlChar *buffer;
997
998 buffer = xmlEncodeSpecialChars(doc, node->content);
999 if (buffer != NULL) {
1000 ret = xmlStrcat(ret, buffer);
1001 xmlFree(buffer);
1002 }
1003 }
1004 } else if (node->type == XML_ENTITY_REF_NODE) {
1005 if (inLine) {
1006 ent = xmlGetDocEntity(doc, node->name);
1007 if (ent != NULL) {
1008 xmlChar *buffer;
1009
1010 /* an entity content can be any "well balanced chunk",
1011 * i.e. the result of the content [43] production:
1012 * http://www.w3.org/TR/REC-xml#NT-content.
1013 * So it can contain text, CDATA section or nested
1014 * entity reference nodes (among others).
1015 * -> we recursive call xmlNodeListGetRawString()
1016 * which handles these types */
1017 buffer =
1018 xmlNodeListGetRawString(doc, ent->children, 1);
1019 if (buffer != NULL) {
1020 ret = xmlStrcat(ret, buffer);
1021 xmlFree(buffer);
1022 }
1023 } else {
1024 ret = xmlStrcat(ret, node->content);
1025 }
1026 } else {
1027 xmlChar buf[2];
1028
1029 buf[0] = '&';
1030 buf[1] = 0;
1031 ret = xmlStrncat(ret, buf, 1);
1032 ret = xmlStrcat(ret, node->name);
1033 buf[0] = ';';
1034 buf[1] = 0;
1035 ret = xmlStrncat(ret, buf, 1);
1036 }
1037 }
Owen Taylor3473f882001-02-23 17:55:21 +00001038#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001039 else {
1040 xmlGenericError(xmlGenericErrorContext,
1041 "xmlGetNodeListString : invalid node type %d\n",
1042 node->type);
1043 }
Owen Taylor3473f882001-02-23 17:55:21 +00001044#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001045 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001046 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001047 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001048}
1049
1050/**
1051 * xmlNewProp:
1052 * @node: the holding node
1053 * @name: the name of the attribute
1054 * @value: the value of the attribute
1055 *
1056 * Create a new property carried by a node.
1057 * Returns a pointer to the attribute
1058 */
1059xmlAttrPtr
1060xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1061 xmlAttrPtr cur;
1062 xmlDocPtr doc = NULL;
1063
1064 if (name == NULL) {
1065#ifdef DEBUG_TREE
1066 xmlGenericError(xmlGenericErrorContext,
1067 "xmlNewProp : name == NULL\n");
1068#endif
1069 return(NULL);
1070 }
1071
1072 /*
1073 * Allocate a new property and fill the fields.
1074 */
1075 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1076 if (cur == NULL) {
1077 xmlGenericError(xmlGenericErrorContext,
1078 "xmlNewProp : malloc failed\n");
1079 return(NULL);
1080 }
1081 memset(cur, 0, sizeof(xmlAttr));
1082 cur->type = XML_ATTRIBUTE_NODE;
1083
1084 cur->parent = node;
1085 if (node != NULL) {
1086 doc = node->doc;
1087 cur->doc = doc;
1088 }
1089 cur->name = xmlStrdup(name);
1090 if (value != NULL) {
1091 xmlChar *buffer;
1092 xmlNodePtr tmp;
1093
1094 buffer = xmlEncodeEntitiesReentrant(doc, value);
1095 cur->children = xmlStringGetNodeList(doc, buffer);
1096 cur->last = NULL;
1097 tmp = cur->children;
1098 while (tmp != NULL) {
1099 tmp->parent = (xmlNodePtr) cur;
1100 tmp->doc = doc;
1101 if (tmp->next == NULL)
1102 cur->last = tmp;
1103 tmp = tmp->next;
1104 }
1105 xmlFree(buffer);
1106 }
1107
1108 /*
1109 * Add it at the end to preserve parsing order ...
1110 */
1111 if (node != NULL) {
1112 if (node->properties == NULL) {
1113 node->properties = cur;
1114 } else {
1115 xmlAttrPtr prev = node->properties;
1116
1117 while (prev->next != NULL) prev = prev->next;
1118 prev->next = cur;
1119 cur->prev = prev;
1120 }
1121 }
1122 return(cur);
1123}
1124
1125/**
1126 * xmlNewNsProp:
1127 * @node: the holding node
1128 * @ns: the namespace
1129 * @name: the name of the attribute
1130 * @value: the value of the attribute
1131 *
1132 * Create a new property tagged with a namespace and carried by a node.
1133 * Returns a pointer to the attribute
1134 */
1135xmlAttrPtr
1136xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1137 const xmlChar *value) {
1138 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001139 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001140
1141 if (name == NULL) {
1142#ifdef DEBUG_TREE
1143 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001144 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001145#endif
1146 return(NULL);
1147 }
1148
1149 /*
1150 * Allocate a new property and fill the fields.
1151 */
1152 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1153 if (cur == NULL) {
1154 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001155 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001156 return(NULL);
1157 }
1158 memset(cur, 0, sizeof(xmlAttr));
1159 cur->type = XML_ATTRIBUTE_NODE;
1160
1161 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001162 if (node != NULL) {
1163 doc = node->doc;
1164 cur->doc = doc;
1165 }
Owen Taylor3473f882001-02-23 17:55:21 +00001166 cur->ns = ns;
1167 cur->name = xmlStrdup(name);
1168 if (value != NULL) {
1169 xmlChar *buffer;
1170 xmlNodePtr tmp;
1171
Daniel Veillarda682b212001-06-07 19:59:42 +00001172 buffer = xmlEncodeEntitiesReentrant(doc, value);
1173 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001174 cur->last = NULL;
1175 tmp = cur->children;
1176 while (tmp != NULL) {
1177 tmp->parent = (xmlNodePtr) cur;
1178 if (tmp->next == NULL)
1179 cur->last = tmp;
1180 tmp = tmp->next;
1181 }
1182 xmlFree(buffer);
1183 }
1184
1185 /*
1186 * Add it at the end to preserve parsing order ...
1187 */
1188 if (node != NULL) {
1189 if (node->properties == NULL) {
1190 node->properties = cur;
1191 } else {
1192 xmlAttrPtr prev = node->properties;
1193
1194 while (prev->next != NULL) prev = prev->next;
1195 prev->next = cur;
1196 cur->prev = prev;
1197 }
1198 }
1199 return(cur);
1200}
1201
1202/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001203 * xmlNewNsPropEatName:
1204 * @node: the holding node
1205 * @ns: the namespace
1206 * @name: the name of the attribute
1207 * @value: the value of the attribute
1208 *
1209 * Create a new property tagged with a namespace and carried by a node.
1210 * Returns a pointer to the attribute
1211 */
1212xmlAttrPtr
1213xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1214 const xmlChar *value) {
1215 xmlAttrPtr cur;
1216 xmlDocPtr doc = NULL;
1217
1218 if (name == NULL) {
1219#ifdef DEBUG_TREE
1220 xmlGenericError(xmlGenericErrorContext,
1221 "xmlNewNsPropEatName : name == NULL\n");
1222#endif
1223 return(NULL);
1224 }
1225
1226 /*
1227 * Allocate a new property and fill the fields.
1228 */
1229 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1230 if (cur == NULL) {
1231 xmlGenericError(xmlGenericErrorContext,
1232 "xmlNewNsPropEatName : malloc failed\n");
1233 return(NULL);
1234 }
1235 memset(cur, 0, sizeof(xmlAttr));
1236 cur->type = XML_ATTRIBUTE_NODE;
1237
1238 cur->parent = node;
1239 if (node != NULL) {
1240 doc = node->doc;
1241 cur->doc = doc;
1242 }
1243 cur->ns = ns;
1244 cur->name = name;
1245 if (value != NULL) {
1246 xmlChar *buffer;
1247 xmlNodePtr tmp;
1248
1249 buffer = xmlEncodeEntitiesReentrant(doc, value);
1250 cur->children = xmlStringGetNodeList(doc, buffer);
1251 cur->last = NULL;
1252 tmp = cur->children;
1253 while (tmp != NULL) {
1254 tmp->parent = (xmlNodePtr) cur;
1255 if (tmp->next == NULL)
1256 cur->last = tmp;
1257 tmp = tmp->next;
1258 }
1259 xmlFree(buffer);
1260 }
1261
1262 /*
1263 * Add it at the end to preserve parsing order ...
1264 */
1265 if (node != NULL) {
1266 if (node->properties == NULL) {
1267 node->properties = cur;
1268 } else {
1269 xmlAttrPtr prev = node->properties;
1270
1271 while (prev->next != NULL) prev = prev->next;
1272 prev->next = cur;
1273 cur->prev = prev;
1274 }
1275 }
1276 return(cur);
1277}
1278
1279/**
Owen Taylor3473f882001-02-23 17:55:21 +00001280 * xmlNewDocProp:
1281 * @doc: the document
1282 * @name: the name of the attribute
1283 * @value: the value of the attribute
1284 *
1285 * Create a new property carried by a document.
1286 * Returns a pointer to the attribute
1287 */
1288xmlAttrPtr
1289xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1290 xmlAttrPtr cur;
1291
1292 if (name == NULL) {
1293#ifdef DEBUG_TREE
1294 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001295 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001296#endif
1297 return(NULL);
1298 }
1299
1300 /*
1301 * Allocate a new property and fill the fields.
1302 */
1303 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1304 if (cur == NULL) {
1305 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001306 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001307 return(NULL);
1308 }
1309 memset(cur, 0, sizeof(xmlAttr));
1310 cur->type = XML_ATTRIBUTE_NODE;
1311
1312 cur->name = xmlStrdup(name);
1313 cur->doc = doc;
1314 if (value != NULL) {
1315 xmlNodePtr tmp;
1316
1317 cur->children = xmlStringGetNodeList(doc, value);
1318 cur->last = NULL;
1319
1320 tmp = cur->children;
1321 while (tmp != NULL) {
1322 tmp->parent = (xmlNodePtr) cur;
1323 if (tmp->next == NULL)
1324 cur->last = tmp;
1325 tmp = tmp->next;
1326 }
1327 }
1328 return(cur);
1329}
1330
1331/**
1332 * xmlFreePropList:
1333 * @cur: the first property in the list
1334 *
1335 * Free a property and all its siblings, all the children are freed too.
1336 */
1337void
1338xmlFreePropList(xmlAttrPtr cur) {
1339 xmlAttrPtr next;
1340 if (cur == NULL) {
1341#ifdef DEBUG_TREE
1342 xmlGenericError(xmlGenericErrorContext,
1343 "xmlFreePropList : property == NULL\n");
1344#endif
1345 return;
1346 }
1347 while (cur != NULL) {
1348 next = cur->next;
1349 xmlFreeProp(cur);
1350 cur = next;
1351 }
1352}
1353
1354/**
1355 * xmlFreeProp:
1356 * @cur: an attribute
1357 *
1358 * Free one attribute, all the content is freed too
1359 */
1360void
1361xmlFreeProp(xmlAttrPtr cur) {
1362 if (cur == NULL) {
1363#ifdef DEBUG_TREE
1364 xmlGenericError(xmlGenericErrorContext,
1365 "xmlFreeProp : property == NULL\n");
1366#endif
1367 return;
1368 }
1369 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001370 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1371 ((cur->parent->doc->intSubset != NULL) ||
1372 (cur->parent->doc->extSubset != NULL))) {
1373 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1374 xmlRemoveID(cur->parent->doc, cur);
1375 }
Owen Taylor3473f882001-02-23 17:55:21 +00001376 if (cur->name != NULL) xmlFree((char *) cur->name);
1377 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001378 xmlFree(cur);
1379}
1380
1381/**
1382 * xmlRemoveProp:
1383 * @cur: an attribute
1384 *
1385 * Unlink and free one attribute, all the content is freed too
1386 * Note this doesn't work for namespace definition attributes
1387 *
1388 * Returns 0 if success and -1 in case of error.
1389 */
1390int
1391xmlRemoveProp(xmlAttrPtr cur) {
1392 xmlAttrPtr tmp;
1393 if (cur == NULL) {
1394#ifdef DEBUG_TREE
1395 xmlGenericError(xmlGenericErrorContext,
1396 "xmlRemoveProp : cur == NULL\n");
1397#endif
1398 return(-1);
1399 }
1400 if (cur->parent == NULL) {
1401#ifdef DEBUG_TREE
1402 xmlGenericError(xmlGenericErrorContext,
1403 "xmlRemoveProp : cur->parent == NULL\n");
1404#endif
1405 return(-1);
1406 }
1407 tmp = cur->parent->properties;
1408 if (tmp == cur) {
1409 cur->parent->properties = cur->next;
1410 xmlFreeProp(cur);
1411 return(0);
1412 }
1413 while (tmp != NULL) {
1414 if (tmp->next == cur) {
1415 tmp->next = cur->next;
1416 if (tmp->next != NULL)
1417 tmp->next->prev = tmp;
1418 xmlFreeProp(cur);
1419 return(0);
1420 }
1421 tmp = tmp->next;
1422 }
1423#ifdef DEBUG_TREE
1424 xmlGenericError(xmlGenericErrorContext,
1425 "xmlRemoveProp : attribute not owned by its node\n");
1426#endif
1427 return(-1);
1428}
1429
1430/**
1431 * xmlNewPI:
1432 * @name: the processing instruction name
1433 * @content: the PI content
1434 *
1435 * Creation of a processing instruction element.
1436 * Returns a pointer to the new node object.
1437 */
1438xmlNodePtr
1439xmlNewPI(const xmlChar *name, const xmlChar *content) {
1440 xmlNodePtr cur;
1441
1442 if (name == NULL) {
1443#ifdef DEBUG_TREE
1444 xmlGenericError(xmlGenericErrorContext,
1445 "xmlNewPI : name == NULL\n");
1446#endif
1447 return(NULL);
1448 }
1449
1450 /*
1451 * Allocate a new node and fill the fields.
1452 */
1453 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1454 if (cur == NULL) {
1455 xmlGenericError(xmlGenericErrorContext,
1456 "xmlNewPI : malloc failed\n");
1457 return(NULL);
1458 }
1459 memset(cur, 0, sizeof(xmlNode));
1460 cur->type = XML_PI_NODE;
1461
1462 cur->name = xmlStrdup(name);
1463 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001464 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001465 }
1466 return(cur);
1467}
1468
1469/**
1470 * xmlNewNode:
1471 * @ns: namespace if any
1472 * @name: the node name
1473 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001474 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001475 *
1476 * Returns a pointer to the new node object.
1477 */
1478xmlNodePtr
1479xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1480 xmlNodePtr cur;
1481
1482 if (name == NULL) {
1483#ifdef DEBUG_TREE
1484 xmlGenericError(xmlGenericErrorContext,
1485 "xmlNewNode : name == NULL\n");
1486#endif
1487 return(NULL);
1488 }
1489
1490 /*
1491 * Allocate a new node and fill the fields.
1492 */
1493 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1494 if (cur == NULL) {
1495 xmlGenericError(xmlGenericErrorContext,
1496 "xmlNewNode : malloc failed\n");
1497 return(NULL);
1498 }
1499 memset(cur, 0, sizeof(xmlNode));
1500 cur->type = XML_ELEMENT_NODE;
1501
1502 cur->name = xmlStrdup(name);
1503 cur->ns = ns;
1504 return(cur);
1505}
1506
1507/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001508 * xmlNewNodeEatName:
1509 * @ns: namespace if any
1510 * @name: the node name
1511 *
1512 * Creation of a new node element. @ns is optional (NULL).
1513 *
1514 * Returns a pointer to the new node object.
1515 */
1516xmlNodePtr
1517xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
1518 xmlNodePtr cur;
1519
1520 if (name == NULL) {
1521#ifdef DEBUG_TREE
1522 xmlGenericError(xmlGenericErrorContext,
1523 "xmlNewNode : name == NULL\n");
1524#endif
1525 return(NULL);
1526 }
1527
1528 /*
1529 * Allocate a new node and fill the fields.
1530 */
1531 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1532 if (cur == NULL) {
1533 xmlGenericError(xmlGenericErrorContext,
1534 "xmlNewNode : malloc failed\n");
1535 return(NULL);
1536 }
1537 memset(cur, 0, sizeof(xmlNode));
1538 cur->type = XML_ELEMENT_NODE;
1539
1540 cur->name = name;
1541 cur->ns = ns;
1542 return(cur);
1543}
1544
1545/**
Owen Taylor3473f882001-02-23 17:55:21 +00001546 * xmlNewDocNode:
1547 * @doc: the document
1548 * @ns: namespace if any
1549 * @name: the node name
1550 * @content: the XML text content if any
1551 *
1552 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001553 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001554 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1555 * references, but XML special chars need to be escaped first by using
1556 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1557 * need entities support.
1558 *
1559 * Returns a pointer to the new node object.
1560 */
1561xmlNodePtr
1562xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1563 const xmlChar *name, const xmlChar *content) {
1564 xmlNodePtr cur;
1565
1566 cur = xmlNewNode(ns, name);
1567 if (cur != NULL) {
1568 cur->doc = doc;
1569 if (content != NULL) {
1570 cur->children = xmlStringGetNodeList(doc, content);
1571 UPDATE_LAST_CHILD_AND_PARENT(cur)
1572 }
1573 }
1574 return(cur);
1575}
1576
Daniel Veillard46de64e2002-05-29 08:21:33 +00001577/**
1578 * xmlNewDocNodeEatName:
1579 * @doc: the document
1580 * @ns: namespace if any
1581 * @name: the node name
1582 * @content: the XML text content if any
1583 *
1584 * Creation of a new node element within a document. @ns and @content
1585 * are optional (NULL).
1586 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1587 * references, but XML special chars need to be escaped first by using
1588 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1589 * need entities support.
1590 *
1591 * Returns a pointer to the new node object.
1592 */
1593xmlNodePtr
1594xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
1595 xmlChar *name, const xmlChar *content) {
1596 xmlNodePtr cur;
1597
1598 cur = xmlNewNodeEatName(ns, name);
1599 if (cur != NULL) {
1600 cur->doc = doc;
1601 if (content != NULL) {
1602 cur->children = xmlStringGetNodeList(doc, content);
1603 UPDATE_LAST_CHILD_AND_PARENT(cur)
1604 }
1605 }
1606 return(cur);
1607}
1608
Owen Taylor3473f882001-02-23 17:55:21 +00001609
1610/**
1611 * xmlNewDocRawNode:
1612 * @doc: the document
1613 * @ns: namespace if any
1614 * @name: the node name
1615 * @content: the text content if any
1616 *
1617 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001618 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001619 *
1620 * Returns a pointer to the new node object.
1621 */
1622xmlNodePtr
1623xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1624 const xmlChar *name, const xmlChar *content) {
1625 xmlNodePtr cur;
1626
1627 cur = xmlNewNode(ns, name);
1628 if (cur != NULL) {
1629 cur->doc = doc;
1630 if (content != NULL) {
1631 cur->children = xmlNewDocText(doc, content);
1632 UPDATE_LAST_CHILD_AND_PARENT(cur)
1633 }
1634 }
1635 return(cur);
1636}
1637
1638/**
1639 * xmlNewDocFragment:
1640 * @doc: the document owning the fragment
1641 *
1642 * Creation of a new Fragment node.
1643 * Returns a pointer to the new node object.
1644 */
1645xmlNodePtr
1646xmlNewDocFragment(xmlDocPtr doc) {
1647 xmlNodePtr cur;
1648
1649 /*
1650 * Allocate a new DocumentFragment node and fill the fields.
1651 */
1652 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1653 if (cur == NULL) {
1654 xmlGenericError(xmlGenericErrorContext,
1655 "xmlNewDocFragment : malloc failed\n");
1656 return(NULL);
1657 }
1658 memset(cur, 0, sizeof(xmlNode));
1659 cur->type = XML_DOCUMENT_FRAG_NODE;
1660
1661 cur->doc = doc;
1662 return(cur);
1663}
1664
1665/**
1666 * xmlNewText:
1667 * @content: the text content
1668 *
1669 * Creation of a new text node.
1670 * Returns a pointer to the new node object.
1671 */
1672xmlNodePtr
1673xmlNewText(const xmlChar *content) {
1674 xmlNodePtr cur;
1675
1676 /*
1677 * Allocate a new node and fill the fields.
1678 */
1679 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1680 if (cur == NULL) {
1681 xmlGenericError(xmlGenericErrorContext,
1682 "xmlNewText : malloc failed\n");
1683 return(NULL);
1684 }
1685 memset(cur, 0, sizeof(xmlNode));
1686 cur->type = XML_TEXT_NODE;
1687
1688 cur->name = xmlStringText;
1689 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001690 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001691 }
1692 return(cur);
1693}
1694
1695/**
1696 * xmlNewTextChild:
1697 * @parent: the parent node
1698 * @ns: a namespace if any
1699 * @name: the name of the child
1700 * @content: the text content of the child if any.
1701 *
1702 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001703 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001704 * a child TEXT node will be created containing the string content.
1705 *
1706 * Returns a pointer to the new node object.
1707 */
1708xmlNodePtr
1709xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1710 const xmlChar *name, const xmlChar *content) {
1711 xmlNodePtr cur, prev;
1712
1713 if (parent == NULL) {
1714#ifdef DEBUG_TREE
1715 xmlGenericError(xmlGenericErrorContext,
1716 "xmlNewTextChild : parent == NULL\n");
1717#endif
1718 return(NULL);
1719 }
1720
1721 if (name == NULL) {
1722#ifdef DEBUG_TREE
1723 xmlGenericError(xmlGenericErrorContext,
1724 "xmlNewTextChild : name == NULL\n");
1725#endif
1726 return(NULL);
1727 }
1728
1729 /*
1730 * Allocate a new node
1731 */
1732 if (ns == NULL)
1733 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1734 else
1735 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1736 if (cur == NULL) return(NULL);
1737
1738 /*
1739 * add the new element at the end of the children list.
1740 */
1741 cur->type = XML_ELEMENT_NODE;
1742 cur->parent = parent;
1743 cur->doc = parent->doc;
1744 if (parent->children == NULL) {
1745 parent->children = cur;
1746 parent->last = cur;
1747 } else {
1748 prev = parent->last;
1749 prev->next = cur;
1750 cur->prev = prev;
1751 parent->last = cur;
1752 }
1753
1754 return(cur);
1755}
1756
1757/**
1758 * xmlNewCharRef:
1759 * @doc: the document
1760 * @name: the char ref string, starting with # or "&# ... ;"
1761 *
1762 * Creation of a new character reference node.
1763 * Returns a pointer to the new node object.
1764 */
1765xmlNodePtr
1766xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1767 xmlNodePtr cur;
1768
1769 /*
1770 * Allocate a new node and fill the fields.
1771 */
1772 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1773 if (cur == NULL) {
1774 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001775 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001776 return(NULL);
1777 }
1778 memset(cur, 0, sizeof(xmlNode));
1779 cur->type = XML_ENTITY_REF_NODE;
1780
1781 cur->doc = doc;
1782 if (name[0] == '&') {
1783 int len;
1784 name++;
1785 len = xmlStrlen(name);
1786 if (name[len - 1] == ';')
1787 cur->name = xmlStrndup(name, len - 1);
1788 else
1789 cur->name = xmlStrndup(name, len);
1790 } else
1791 cur->name = xmlStrdup(name);
1792 return(cur);
1793}
1794
1795/**
1796 * xmlNewReference:
1797 * @doc: the document
1798 * @name: the reference name, or the reference string with & and ;
1799 *
1800 * Creation of a new reference node.
1801 * Returns a pointer to the new node object.
1802 */
1803xmlNodePtr
1804xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1805 xmlNodePtr cur;
1806 xmlEntityPtr ent;
1807
1808 /*
1809 * Allocate a new node and fill the fields.
1810 */
1811 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1812 if (cur == NULL) {
1813 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001814 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001815 return(NULL);
1816 }
1817 memset(cur, 0, sizeof(xmlNode));
1818 cur->type = XML_ENTITY_REF_NODE;
1819
1820 cur->doc = doc;
1821 if (name[0] == '&') {
1822 int len;
1823 name++;
1824 len = xmlStrlen(name);
1825 if (name[len - 1] == ';')
1826 cur->name = xmlStrndup(name, len - 1);
1827 else
1828 cur->name = xmlStrndup(name, len);
1829 } else
1830 cur->name = xmlStrdup(name);
1831
1832 ent = xmlGetDocEntity(doc, cur->name);
1833 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001834 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00001835 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001836 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00001837 * updated. Not sure if this is 100% correct.
1838 * -George
1839 */
1840 cur->children = (xmlNodePtr) ent;
1841 cur->last = (xmlNodePtr) ent;
1842 }
1843 return(cur);
1844}
1845
1846/**
1847 * xmlNewDocText:
1848 * @doc: the document
1849 * @content: the text content
1850 *
1851 * Creation of a new text node within a document.
1852 * Returns a pointer to the new node object.
1853 */
1854xmlNodePtr
1855xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1856 xmlNodePtr cur;
1857
1858 cur = xmlNewText(content);
1859 if (cur != NULL) cur->doc = doc;
1860 return(cur);
1861}
1862
1863/**
1864 * xmlNewTextLen:
1865 * @content: the text content
1866 * @len: the text len.
1867 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001868 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00001869 * Returns a pointer to the new node object.
1870 */
1871xmlNodePtr
1872xmlNewTextLen(const xmlChar *content, int len) {
1873 xmlNodePtr cur;
1874
1875 /*
1876 * Allocate a new node and fill the fields.
1877 */
1878 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1879 if (cur == NULL) {
1880 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001881 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001882 return(NULL);
1883 }
1884 memset(cur, 0, sizeof(xmlNode));
1885 cur->type = XML_TEXT_NODE;
1886
1887 cur->name = xmlStringText;
1888 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001889 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001890 }
1891 return(cur);
1892}
1893
1894/**
1895 * xmlNewDocTextLen:
1896 * @doc: the document
1897 * @content: the text content
1898 * @len: the text len.
1899 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001900 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00001901 * text node pertain to a given document.
1902 * Returns a pointer to the new node object.
1903 */
1904xmlNodePtr
1905xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1906 xmlNodePtr cur;
1907
1908 cur = xmlNewTextLen(content, len);
1909 if (cur != NULL) cur->doc = doc;
1910 return(cur);
1911}
1912
1913/**
1914 * xmlNewComment:
1915 * @content: the comment content
1916 *
1917 * Creation of a new node containing a comment.
1918 * Returns a pointer to the new node object.
1919 */
1920xmlNodePtr
1921xmlNewComment(const xmlChar *content) {
1922 xmlNodePtr cur;
1923
1924 /*
1925 * Allocate a new node and fill the fields.
1926 */
1927 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1928 if (cur == NULL) {
1929 xmlGenericError(xmlGenericErrorContext,
1930 "xmlNewComment : malloc failed\n");
1931 return(NULL);
1932 }
1933 memset(cur, 0, sizeof(xmlNode));
1934 cur->type = XML_COMMENT_NODE;
1935
1936 cur->name = xmlStringComment;
1937 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001938 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001939 }
1940 return(cur);
1941}
1942
1943/**
1944 * xmlNewCDataBlock:
1945 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00001946 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00001947 * @len: the length of the block
1948 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001949 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00001950 * Returns a pointer to the new node object.
1951 */
1952xmlNodePtr
1953xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1954 xmlNodePtr cur;
1955
1956 /*
1957 * Allocate a new node and fill the fields.
1958 */
1959 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1960 if (cur == NULL) {
1961 xmlGenericError(xmlGenericErrorContext,
1962 "xmlNewCDataBlock : malloc failed\n");
1963 return(NULL);
1964 }
1965 memset(cur, 0, sizeof(xmlNode));
1966 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001967 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001968
1969 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001970 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001971 }
1972 return(cur);
1973}
1974
1975/**
1976 * xmlNewDocComment:
1977 * @doc: the document
1978 * @content: the comment content
1979 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001980 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00001981 * Returns a pointer to the new node object.
1982 */
1983xmlNodePtr
1984xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1985 xmlNodePtr cur;
1986
1987 cur = xmlNewComment(content);
1988 if (cur != NULL) cur->doc = doc;
1989 return(cur);
1990}
1991
1992/**
1993 * xmlSetTreeDoc:
1994 * @tree: the top element
1995 * @doc: the document
1996 *
1997 * update all nodes under the tree to point to the right document
1998 */
1999void
2000xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002001 xmlAttrPtr prop;
2002
Owen Taylor3473f882001-02-23 17:55:21 +00002003 if (tree == NULL)
2004 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002005 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002006 if(tree->type == XML_ELEMENT_NODE) {
2007 prop = tree->properties;
2008 while (prop != NULL) {
2009 prop->doc = doc;
2010 xmlSetListDoc(prop->children, doc);
2011 prop = prop->next;
2012 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002013 }
Owen Taylor3473f882001-02-23 17:55:21 +00002014 if (tree->children != NULL)
2015 xmlSetListDoc(tree->children, doc);
2016 tree->doc = doc;
2017 }
2018}
2019
2020/**
2021 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002022 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002023 * @doc: the document
2024 *
2025 * update all nodes in the list to point to the right document
2026 */
2027void
2028xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2029 xmlNodePtr cur;
2030
2031 if (list == NULL)
2032 return;
2033 cur = list;
2034 while (cur != NULL) {
2035 if (cur->doc != doc)
2036 xmlSetTreeDoc(cur, doc);
2037 cur = cur->next;
2038 }
2039}
2040
2041
2042/**
2043 * xmlNewChild:
2044 * @parent: the parent node
2045 * @ns: a namespace if any
2046 * @name: the name of the child
2047 * @content: the XML content of the child if any.
2048 *
2049 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002050 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002051 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2052 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2053 * references, but XML special chars need to be escaped first by using
2054 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2055 * support is not needed.
2056 *
2057 * Returns a pointer to the new node object.
2058 */
2059xmlNodePtr
2060xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2061 const xmlChar *name, const xmlChar *content) {
2062 xmlNodePtr cur, prev;
2063
2064 if (parent == NULL) {
2065#ifdef DEBUG_TREE
2066 xmlGenericError(xmlGenericErrorContext,
2067 "xmlNewChild : parent == NULL\n");
2068#endif
2069 return(NULL);
2070 }
2071
2072 if (name == NULL) {
2073#ifdef DEBUG_TREE
2074 xmlGenericError(xmlGenericErrorContext,
2075 "xmlNewChild : name == NULL\n");
2076#endif
2077 return(NULL);
2078 }
2079
2080 /*
2081 * Allocate a new node
2082 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002083 if (parent->type == XML_ELEMENT_NODE) {
2084 if (ns == NULL)
2085 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2086 else
2087 cur = xmlNewDocNode(parent->doc, ns, name, content);
2088 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2089 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2090 if (ns == NULL)
2091 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2092 else
2093 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002094 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2095 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002096 } else {
2097 return(NULL);
2098 }
Owen Taylor3473f882001-02-23 17:55:21 +00002099 if (cur == NULL) return(NULL);
2100
2101 /*
2102 * add the new element at the end of the children list.
2103 */
2104 cur->type = XML_ELEMENT_NODE;
2105 cur->parent = parent;
2106 cur->doc = parent->doc;
2107 if (parent->children == NULL) {
2108 parent->children = cur;
2109 parent->last = cur;
2110 } else {
2111 prev = parent->last;
2112 prev->next = cur;
2113 cur->prev = prev;
2114 parent->last = cur;
2115 }
2116
2117 return(cur);
2118}
2119
2120/**
2121 * xmlAddNextSibling:
2122 * @cur: the child node
2123 * @elem: the new node
2124 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002125 * Add a new node @elem as the next sibling of @cur
2126 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002127 * first unlinked from its existing context.
2128 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002129 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2130 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002131 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002132 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002133 */
2134xmlNodePtr
2135xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2136 if (cur == NULL) {
2137#ifdef DEBUG_TREE
2138 xmlGenericError(xmlGenericErrorContext,
2139 "xmlAddNextSibling : cur == NULL\n");
2140#endif
2141 return(NULL);
2142 }
2143 if (elem == NULL) {
2144#ifdef DEBUG_TREE
2145 xmlGenericError(xmlGenericErrorContext,
2146 "xmlAddNextSibling : elem == NULL\n");
2147#endif
2148 return(NULL);
2149 }
2150
2151 xmlUnlinkNode(elem);
2152
2153 if (elem->type == XML_TEXT_NODE) {
2154 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002155 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002156 xmlFreeNode(elem);
2157 return(cur);
2158 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002159 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2160 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002161 xmlChar *tmp;
2162
2163 tmp = xmlStrdup(elem->content);
2164 tmp = xmlStrcat(tmp, cur->next->content);
2165 xmlNodeSetContent(cur->next, tmp);
2166 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002167 xmlFreeNode(elem);
2168 return(cur->next);
2169 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002170 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2171 /* check if an attribute with the same name exists */
2172 xmlAttrPtr attr;
2173
2174 if (elem->ns == NULL)
2175 attr = xmlHasProp(cur->parent, elem->name);
2176 else
2177 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2178 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2179 /* different instance, destroy it (attributes must be unique) */
2180 xmlFreeProp(attr);
2181 }
Owen Taylor3473f882001-02-23 17:55:21 +00002182 }
2183
2184 if (elem->doc != cur->doc) {
2185 xmlSetTreeDoc(elem, cur->doc);
2186 }
2187 elem->parent = cur->parent;
2188 elem->prev = cur;
2189 elem->next = cur->next;
2190 cur->next = elem;
2191 if (elem->next != NULL)
2192 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002193 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002194 elem->parent->last = elem;
2195 return(elem);
2196}
2197
2198/**
2199 * xmlAddPrevSibling:
2200 * @cur: the child node
2201 * @elem: the new node
2202 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002203 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002204 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002205 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002206 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002207 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2208 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002209 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002210 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002211 */
2212xmlNodePtr
2213xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2214 if (cur == NULL) {
2215#ifdef DEBUG_TREE
2216 xmlGenericError(xmlGenericErrorContext,
2217 "xmlAddPrevSibling : cur == NULL\n");
2218#endif
2219 return(NULL);
2220 }
2221 if (elem == NULL) {
2222#ifdef DEBUG_TREE
2223 xmlGenericError(xmlGenericErrorContext,
2224 "xmlAddPrevSibling : elem == NULL\n");
2225#endif
2226 return(NULL);
2227 }
2228
2229 xmlUnlinkNode(elem);
2230
2231 if (elem->type == XML_TEXT_NODE) {
2232 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002233 xmlChar *tmp;
2234
2235 tmp = xmlStrdup(elem->content);
2236 tmp = xmlStrcat(tmp, cur->content);
2237 xmlNodeSetContent(cur, tmp);
2238 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002239 xmlFreeNode(elem);
2240 return(cur);
2241 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002242 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2243 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002244 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002245 xmlFreeNode(elem);
2246 return(cur->prev);
2247 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002248 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2249 /* check if an attribute with the same name exists */
2250 xmlAttrPtr attr;
2251
2252 if (elem->ns == NULL)
2253 attr = xmlHasProp(cur->parent, elem->name);
2254 else
2255 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2256 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2257 /* different instance, destroy it (attributes must be unique) */
2258 xmlFreeProp(attr);
2259 }
Owen Taylor3473f882001-02-23 17:55:21 +00002260 }
2261
2262 if (elem->doc != cur->doc) {
2263 xmlSetTreeDoc(elem, cur->doc);
2264 }
2265 elem->parent = cur->parent;
2266 elem->next = cur;
2267 elem->prev = cur->prev;
2268 cur->prev = elem;
2269 if (elem->prev != NULL)
2270 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002271 if (elem->parent != NULL) {
2272 if (elem->type == XML_ATTRIBUTE_NODE) {
2273 if (elem->parent->properties == (xmlAttrPtr) cur) {
2274 elem->parent->properties = (xmlAttrPtr) elem;
2275 }
2276 } else {
2277 if (elem->parent->children == cur) {
2278 elem->parent->children = elem;
2279 }
2280 }
2281 }
Owen Taylor3473f882001-02-23 17:55:21 +00002282 return(elem);
2283}
2284
2285/**
2286 * xmlAddSibling:
2287 * @cur: the child node
2288 * @elem: the new node
2289 *
2290 * Add a new element @elem to the list of siblings of @cur
2291 * merging adjacent TEXT nodes (@elem may be freed)
2292 * If the new element was already inserted in a document it is
2293 * first unlinked from its existing context.
2294 *
2295 * Returns the new element or NULL in case of error.
2296 */
2297xmlNodePtr
2298xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2299 xmlNodePtr parent;
2300
2301 if (cur == NULL) {
2302#ifdef DEBUG_TREE
2303 xmlGenericError(xmlGenericErrorContext,
2304 "xmlAddSibling : cur == NULL\n");
2305#endif
2306 return(NULL);
2307 }
2308
2309 if (elem == NULL) {
2310#ifdef DEBUG_TREE
2311 xmlGenericError(xmlGenericErrorContext,
2312 "xmlAddSibling : elem == NULL\n");
2313#endif
2314 return(NULL);
2315 }
2316
2317 /*
2318 * Constant time is we can rely on the ->parent->last to find
2319 * the last sibling.
2320 */
2321 if ((cur->parent != NULL) &&
2322 (cur->parent->children != NULL) &&
2323 (cur->parent->last != NULL) &&
2324 (cur->parent->last->next == NULL)) {
2325 cur = cur->parent->last;
2326 } else {
2327 while (cur->next != NULL) cur = cur->next;
2328 }
2329
2330 xmlUnlinkNode(elem);
2331
2332 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002333 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002334 xmlFreeNode(elem);
2335 return(cur);
2336 }
2337
2338 if (elem->doc != cur->doc) {
2339 xmlSetTreeDoc(elem, cur->doc);
2340 }
2341 parent = cur->parent;
2342 elem->prev = cur;
2343 elem->next = NULL;
2344 elem->parent = parent;
2345 cur->next = elem;
2346 if (parent != NULL)
2347 parent->last = elem;
2348
2349 return(elem);
2350}
2351
2352/**
2353 * xmlAddChildList:
2354 * @parent: the parent node
2355 * @cur: the first node in the list
2356 *
2357 * Add a list of node at the end of the child list of the parent
2358 * merging adjacent TEXT nodes (@cur may be freed)
2359 *
2360 * Returns the last child or NULL in case of error.
2361 */
2362xmlNodePtr
2363xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2364 xmlNodePtr prev;
2365
2366 if (parent == NULL) {
2367#ifdef DEBUG_TREE
2368 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002369 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002370#endif
2371 return(NULL);
2372 }
2373
2374 if (cur == NULL) {
2375#ifdef DEBUG_TREE
2376 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002377 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002378#endif
2379 return(NULL);
2380 }
2381
2382 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2383 (cur->doc != parent->doc)) {
2384#ifdef DEBUG_TREE
2385 xmlGenericError(xmlGenericErrorContext,
2386 "Elements moved to a different document\n");
2387#endif
2388 }
2389
2390 /*
2391 * add the first element at the end of the children list.
2392 */
2393 if (parent->children == NULL) {
2394 parent->children = cur;
2395 } else {
2396 /*
2397 * If cur and parent->last both are TEXT nodes, then merge them.
2398 */
2399 if ((cur->type == XML_TEXT_NODE) &&
2400 (parent->last->type == XML_TEXT_NODE) &&
2401 (cur->name == parent->last->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002402 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002403 /*
2404 * if it's the only child, nothing more to be done.
2405 */
2406 if (cur->next == NULL) {
2407 xmlFreeNode(cur);
2408 return(parent->last);
2409 }
2410 prev = cur;
2411 cur = cur->next;
2412 xmlFreeNode(prev);
2413 }
2414 prev = parent->last;
2415 prev->next = cur;
2416 cur->prev = prev;
2417 }
2418 while (cur->next != NULL) {
2419 cur->parent = parent;
2420 if (cur->doc != parent->doc) {
2421 xmlSetTreeDoc(cur, parent->doc);
2422 }
2423 cur = cur->next;
2424 }
2425 cur->parent = parent;
2426 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2427 parent->last = cur;
2428
2429 return(cur);
2430}
2431
2432/**
2433 * xmlAddChild:
2434 * @parent: the parent node
2435 * @cur: the child node
2436 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002437 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002438 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002439 * If the new node was already inserted in a document it is
2440 * first unlinked from its existing context.
2441 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2442 * If there is an attribute with equal name, it is first destroyed.
2443 *
Owen Taylor3473f882001-02-23 17:55:21 +00002444 * Returns the child or NULL in case of error.
2445 */
2446xmlNodePtr
2447xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2448 xmlNodePtr prev;
2449
2450 if (parent == NULL) {
2451#ifdef DEBUG_TREE
2452 xmlGenericError(xmlGenericErrorContext,
2453 "xmlAddChild : parent == NULL\n");
2454#endif
2455 return(NULL);
2456 }
2457
2458 if (cur == NULL) {
2459#ifdef DEBUG_TREE
2460 xmlGenericError(xmlGenericErrorContext,
2461 "xmlAddChild : child == NULL\n");
2462#endif
2463 return(NULL);
2464 }
2465
Owen Taylor3473f882001-02-23 17:55:21 +00002466 /*
2467 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002468 * cur is then freed.
2469 */
2470 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002471 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002472 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002473 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002474 xmlFreeNode(cur);
2475 return(parent);
2476 }
2477 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2478 (parent->last->name == cur->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002479 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002480 xmlFreeNode(cur);
2481 return(parent->last);
2482 }
2483 }
2484
2485 /*
2486 * add the new element at the end of the children list.
2487 */
2488 cur->parent = parent;
2489 if (cur->doc != parent->doc) {
2490 xmlSetTreeDoc(cur, parent->doc);
2491 }
2492
2493 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002494 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002495 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002496 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002497 (parent->content != NULL)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002498 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002499 xmlFreeNode(cur);
2500 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002501 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002502 if (cur->type == XML_ATTRIBUTE_NODE) {
2503 if (parent->properties == NULL) {
2504 parent->properties = (xmlAttrPtr) cur;
2505 } else {
2506 /* check if an attribute with the same name exists */
2507 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002508
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002509 if (cur->ns == NULL)
2510 lastattr = xmlHasProp(parent, cur->name);
2511 else
2512 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2513 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2514 /* different instance, destroy it (attributes must be unique) */
2515 xmlFreeProp(lastattr);
2516 }
2517 /* find the end */
2518 lastattr = parent->properties;
2519 while (lastattr->next != NULL) {
2520 lastattr = lastattr->next;
2521 }
2522 lastattr->next = (xmlAttrPtr) cur;
2523 ((xmlAttrPtr) cur)->prev = lastattr;
2524 }
2525 } else {
2526 if (parent->children == NULL) {
2527 parent->children = cur;
2528 parent->last = cur;
2529 } else {
2530 prev = parent->last;
2531 prev->next = cur;
2532 cur->prev = prev;
2533 parent->last = cur;
2534 }
2535 }
Owen Taylor3473f882001-02-23 17:55:21 +00002536 return(cur);
2537}
2538
2539/**
2540 * xmlGetLastChild:
2541 * @parent: the parent node
2542 *
2543 * Search the last child of a node.
2544 * Returns the last child or NULL if none.
2545 */
2546xmlNodePtr
2547xmlGetLastChild(xmlNodePtr parent) {
2548 if (parent == NULL) {
2549#ifdef DEBUG_TREE
2550 xmlGenericError(xmlGenericErrorContext,
2551 "xmlGetLastChild : parent == NULL\n");
2552#endif
2553 return(NULL);
2554 }
2555 return(parent->last);
2556}
2557
2558/**
2559 * xmlFreeNodeList:
2560 * @cur: the first node in the list
2561 *
2562 * Free a node and all its siblings, this is a recursive behaviour, all
2563 * the children are freed too.
2564 */
2565void
2566xmlFreeNodeList(xmlNodePtr cur) {
2567 xmlNodePtr next;
2568 if (cur == NULL) {
2569#ifdef DEBUG_TREE
2570 xmlGenericError(xmlGenericErrorContext,
2571 "xmlFreeNodeList : node == NULL\n");
2572#endif
2573 return;
2574 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002575 if (cur->type == XML_NAMESPACE_DECL) {
2576 xmlFreeNsList((xmlNsPtr) cur);
2577 return;
2578 }
Owen Taylor3473f882001-02-23 17:55:21 +00002579 while (cur != NULL) {
2580 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002581 /* unroll to speed up freeing the document */
2582 if (cur->type != XML_DTD_NODE) {
2583 if ((cur->children != NULL) &&
2584 (cur->type != XML_ENTITY_REF_NODE))
2585 xmlFreeNodeList(cur->children);
2586 if (cur->properties != NULL)
2587 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002588 if ((cur->type != XML_ELEMENT_NODE) &&
2589 (cur->type != XML_XINCLUDE_START) &&
2590 (cur->type != XML_XINCLUDE_END) &&
2591 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002592 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002593 }
2594 if (((cur->type == XML_ELEMENT_NODE) ||
2595 (cur->type == XML_XINCLUDE_START) ||
2596 (cur->type == XML_XINCLUDE_END)) &&
2597 (cur->nsDef != NULL))
2598 xmlFreeNsList(cur->nsDef);
2599
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002600 /*
2601 * When a node is a text node or a comment, it uses a global static
2602 * variable for the name of the node.
2603 *
2604 * The xmlStrEqual comparisons need to be done when (happened with
2605 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002606 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002607 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002608 * the string addresses compare are not sufficient.
2609 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002610 if ((cur->name != NULL) &&
2611 (cur->name != xmlStringText) &&
2612 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002613 (cur->name != xmlStringComment)) {
2614 if (cur->type == XML_TEXT_NODE) {
2615 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2616 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2617 xmlFree((char *) cur->name);
2618 } else if (cur->type == XML_COMMENT_NODE) {
2619 if (!xmlStrEqual(cur->name, xmlStringComment))
2620 xmlFree((char *) cur->name);
2621 } else
2622 xmlFree((char *) cur->name);
2623 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002624 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002625 xmlFree(cur);
2626 }
Owen Taylor3473f882001-02-23 17:55:21 +00002627 cur = next;
2628 }
2629}
2630
2631/**
2632 * xmlFreeNode:
2633 * @cur: the node
2634 *
2635 * Free a node, this is a recursive behaviour, all the children are freed too.
2636 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2637 */
2638void
2639xmlFreeNode(xmlNodePtr cur) {
2640 if (cur == NULL) {
2641#ifdef DEBUG_TREE
2642 xmlGenericError(xmlGenericErrorContext,
2643 "xmlFreeNode : node == NULL\n");
2644#endif
2645 return;
2646 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002647 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002648 if (cur->type == XML_DTD_NODE) {
2649 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002650 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002651 }
2652 if (cur->type == XML_NAMESPACE_DECL) {
2653 xmlFreeNs((xmlNsPtr) cur);
2654 return;
2655 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00002656 if (cur->type == XML_ATTRIBUTE_NODE) {
2657 xmlFreeProp((xmlAttrPtr) cur);
2658 return;
2659 }
Owen Taylor3473f882001-02-23 17:55:21 +00002660 if ((cur->children != NULL) &&
2661 (cur->type != XML_ENTITY_REF_NODE))
2662 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002663 if (cur->properties != NULL)
2664 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002665 if ((cur->type != XML_ELEMENT_NODE) &&
2666 (cur->content != NULL) &&
2667 (cur->type != XML_ENTITY_REF_NODE) &&
2668 (cur->type != XML_XINCLUDE_END) &&
2669 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002670 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002671 }
2672
Daniel Veillardacd370f2001-06-09 17:17:51 +00002673 /*
2674 * When a node is a text node or a comment, it uses a global static
2675 * variable for the name of the node.
2676 *
2677 * The xmlStrEqual comparisons need to be done when (happened with
2678 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002679 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002680 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002681 * are not sufficient.
2682 */
Owen Taylor3473f882001-02-23 17:55:21 +00002683 if ((cur->name != NULL) &&
2684 (cur->name != xmlStringText) &&
2685 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002686 (cur->name != xmlStringComment)) {
2687 if (cur->type == XML_TEXT_NODE) {
2688 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2689 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2690 xmlFree((char *) cur->name);
2691 } else if (cur->type == XML_COMMENT_NODE) {
2692 if (!xmlStrEqual(cur->name, xmlStringComment))
2693 xmlFree((char *) cur->name);
2694 } else
2695 xmlFree((char *) cur->name);
2696 }
2697
Owen Taylor3473f882001-02-23 17:55:21 +00002698 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002699 xmlFree(cur);
2700}
2701
2702/**
2703 * xmlUnlinkNode:
2704 * @cur: the node
2705 *
2706 * Unlink a node from it's current context, the node is not freed
2707 */
2708void
2709xmlUnlinkNode(xmlNodePtr cur) {
2710 if (cur == NULL) {
2711#ifdef DEBUG_TREE
2712 xmlGenericError(xmlGenericErrorContext,
2713 "xmlUnlinkNode : node == NULL\n");
2714#endif
2715 return;
2716 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002717 if (cur->type == XML_DTD_NODE) {
2718 xmlDocPtr doc;
2719 doc = cur->doc;
2720 if (doc->intSubset == (xmlDtdPtr) cur)
2721 doc->intSubset = NULL;
2722 if (doc->extSubset == (xmlDtdPtr) cur)
2723 doc->extSubset = NULL;
2724 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002725 if (cur->parent != NULL) {
2726 xmlNodePtr parent;
2727 parent = cur->parent;
2728 if (cur->type == XML_ATTRIBUTE_NODE) {
2729 if (parent->properties == (xmlAttrPtr) cur)
2730 parent->properties = ((xmlAttrPtr) cur)->next;
2731 } else {
2732 if (parent->children == cur)
2733 parent->children = cur->next;
2734 if (parent->last == cur)
2735 parent->last = cur->prev;
2736 }
2737 cur->parent = NULL;
2738 }
Owen Taylor3473f882001-02-23 17:55:21 +00002739 if (cur->next != NULL)
2740 cur->next->prev = cur->prev;
2741 if (cur->prev != NULL)
2742 cur->prev->next = cur->next;
2743 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002744}
2745
2746/**
2747 * xmlReplaceNode:
2748 * @old: the old node
2749 * @cur: the node
2750 *
2751 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002752 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002753 * first unlinked from its existing context.
2754 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002755 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002756 */
2757xmlNodePtr
2758xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2759 if (old == NULL) {
2760#ifdef DEBUG_TREE
2761 xmlGenericError(xmlGenericErrorContext,
2762 "xmlReplaceNode : old == NULL\n");
2763#endif
2764 return(NULL);
2765 }
2766 if (cur == NULL) {
2767 xmlUnlinkNode(old);
2768 return(old);
2769 }
2770 if (cur == old) {
2771 return(old);
2772 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002773 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2774#ifdef DEBUG_TREE
2775 xmlGenericError(xmlGenericErrorContext,
2776 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2777#endif
2778 return(old);
2779 }
2780 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2781#ifdef DEBUG_TREE
2782 xmlGenericError(xmlGenericErrorContext,
2783 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2784#endif
2785 return(old);
2786 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002787 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2788#ifdef DEBUG_TREE
2789 xmlGenericError(xmlGenericErrorContext,
2790 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2791#endif
2792 return(old);
2793 }
2794 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2795#ifdef DEBUG_TREE
2796 xmlGenericError(xmlGenericErrorContext,
2797 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2798#endif
2799 return(old);
2800 }
Owen Taylor3473f882001-02-23 17:55:21 +00002801 xmlUnlinkNode(cur);
2802 cur->doc = old->doc;
2803 cur->parent = old->parent;
2804 cur->next = old->next;
2805 if (cur->next != NULL)
2806 cur->next->prev = cur;
2807 cur->prev = old->prev;
2808 if (cur->prev != NULL)
2809 cur->prev->next = cur;
2810 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002811 if (cur->type == XML_ATTRIBUTE_NODE) {
2812 if (cur->parent->properties == (xmlAttrPtr)old)
2813 cur->parent->properties = ((xmlAttrPtr) cur);
2814 } else {
2815 if (cur->parent->children == old)
2816 cur->parent->children = cur;
2817 if (cur->parent->last == old)
2818 cur->parent->last = cur;
2819 }
Owen Taylor3473f882001-02-23 17:55:21 +00002820 }
2821 old->next = old->prev = NULL;
2822 old->parent = NULL;
2823 return(old);
2824}
2825
2826/************************************************************************
2827 * *
2828 * Copy operations *
2829 * *
2830 ************************************************************************/
2831
2832/**
2833 * xmlCopyNamespace:
2834 * @cur: the namespace
2835 *
2836 * Do a copy of the namespace.
2837 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002838 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002839 */
2840xmlNsPtr
2841xmlCopyNamespace(xmlNsPtr cur) {
2842 xmlNsPtr ret;
2843
2844 if (cur == NULL) return(NULL);
2845 switch (cur->type) {
2846 case XML_LOCAL_NAMESPACE:
2847 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2848 break;
2849 default:
2850#ifdef DEBUG_TREE
2851 xmlGenericError(xmlGenericErrorContext,
2852 "xmlCopyNamespace: invalid type %d\n", cur->type);
2853#endif
2854 return(NULL);
2855 }
2856 return(ret);
2857}
2858
2859/**
2860 * xmlCopyNamespaceList:
2861 * @cur: the first namespace
2862 *
2863 * Do a copy of an namespace list.
2864 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002865 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002866 */
2867xmlNsPtr
2868xmlCopyNamespaceList(xmlNsPtr cur) {
2869 xmlNsPtr ret = NULL;
2870 xmlNsPtr p = NULL,q;
2871
2872 while (cur != NULL) {
2873 q = xmlCopyNamespace(cur);
2874 if (p == NULL) {
2875 ret = p = q;
2876 } else {
2877 p->next = q;
2878 p = q;
2879 }
2880 cur = cur->next;
2881 }
2882 return(ret);
2883}
2884
2885static xmlNodePtr
2886xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2887/**
2888 * xmlCopyProp:
2889 * @target: the element where the attribute will be grafted
2890 * @cur: the attribute
2891 *
2892 * Do a copy of the attribute.
2893 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002894 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002895 */
2896xmlAttrPtr
2897xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2898 xmlAttrPtr ret;
2899
2900 if (cur == NULL) return(NULL);
2901 if (target != NULL)
2902 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2903 else if (cur->parent != NULL)
2904 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2905 else if (cur->children != NULL)
2906 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2907 else
2908 ret = xmlNewDocProp(NULL, cur->name, NULL);
2909 if (ret == NULL) return(NULL);
2910 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002911
Owen Taylor3473f882001-02-23 17:55:21 +00002912 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00002913 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002914/*
2915 * if (target->doc)
2916 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2917 * else if (cur->doc) / * target may not yet have a doc : KPI * /
2918 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
2919 * else
2920 * ns = NULL;
2921 * ret->ns = ns;
2922 */
2923 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2924 if (ns == NULL) {
2925 /*
2926 * Humm, we are copying an element whose namespace is defined
2927 * out of the new tree scope. Search it in the original tree
2928 * and add it at the top of the new tree
2929 */
2930 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
2931 if (ns != NULL) {
2932 xmlNodePtr root = target;
2933 xmlNodePtr pred = NULL;
2934
2935 while (root->parent != NULL) {
2936 pred = root;
2937 root = root->parent;
2938 }
2939 if (root == (xmlNodePtr) target->doc) {
2940 /* correct possibly cycling above the document elt */
2941 root = pred;
2942 }
2943 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
2944 }
2945 } else {
2946 /*
2947 * we have to find something appropriate here since
2948 * we cant be sure, that the namespce we found is identified
2949 * by the prefix
2950 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002951 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002952 /* this is the nice case */
2953 ret->ns = ns;
2954 } else {
2955 /*
2956 * we are in trouble: we need a new reconcilied namespace.
2957 * This is expensive
2958 */
2959 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
2960 }
2961 }
2962
Owen Taylor3473f882001-02-23 17:55:21 +00002963 } else
2964 ret->ns = NULL;
2965
2966 if (cur->children != NULL) {
2967 xmlNodePtr tmp;
2968
2969 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2970 ret->last = NULL;
2971 tmp = ret->children;
2972 while (tmp != NULL) {
2973 /* tmp->parent = (xmlNodePtr)ret; */
2974 if (tmp->next == NULL)
2975 ret->last = tmp;
2976 tmp = tmp->next;
2977 }
2978 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002979 /*
2980 * Try to handle IDs
2981 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00002982 if ((target!= NULL) && (cur!= NULL) &&
2983 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002984 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
2985 if (xmlIsID(cur->doc, cur->parent, cur)) {
2986 xmlChar *id;
2987
2988 id = xmlNodeListGetString(cur->doc, cur->children, 1);
2989 if (id != NULL) {
2990 xmlAddID(NULL, target->doc, id, ret);
2991 xmlFree(id);
2992 }
2993 }
2994 }
Owen Taylor3473f882001-02-23 17:55:21 +00002995 return(ret);
2996}
2997
2998/**
2999 * xmlCopyPropList:
3000 * @target: the element where the attributes will be grafted
3001 * @cur: the first attribute
3002 *
3003 * Do a copy of an attribute list.
3004 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003005 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003006 */
3007xmlAttrPtr
3008xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3009 xmlAttrPtr ret = NULL;
3010 xmlAttrPtr p = NULL,q;
3011
3012 while (cur != NULL) {
3013 q = xmlCopyProp(target, cur);
3014 if (p == NULL) {
3015 ret = p = q;
3016 } else {
3017 p->next = q;
3018 q->prev = p;
3019 p = q;
3020 }
3021 cur = cur->next;
3022 }
3023 return(ret);
3024}
3025
3026/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003027 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003028 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003029 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003030 * tricky reason: namespaces. Doing a direct copy of a node
3031 * say RPM:Copyright without changing the namespace pointer to
3032 * something else can produce stale links. One way to do it is
3033 * to keep a reference counter but this doesn't work as soon
3034 * as one move the element or the subtree out of the scope of
3035 * the existing namespace. The actual solution seems to add
3036 * a copy of the namespace at the top of the copied tree if
3037 * not available in the subtree.
3038 * Hence two functions, the public front-end call the inner ones
3039 */
3040
3041static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003042xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003043 int recursive) {
3044 xmlNodePtr ret;
3045
3046 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003047 switch (node->type) {
3048 case XML_TEXT_NODE:
3049 case XML_CDATA_SECTION_NODE:
3050 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003051 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003052 case XML_ENTITY_REF_NODE:
3053 case XML_ENTITY_NODE:
3054 case XML_PI_NODE:
3055 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003056 case XML_XINCLUDE_START:
3057 case XML_XINCLUDE_END:
3058 break;
3059 case XML_ATTRIBUTE_NODE:
3060 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3061 case XML_NAMESPACE_DECL:
3062 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3063
Daniel Veillard39196eb2001-06-19 18:09:42 +00003064 case XML_DOCUMENT_NODE:
3065 case XML_HTML_DOCUMENT_NODE:
3066#ifdef LIBXML_DOCB_ENABLED
3067 case XML_DOCB_DOCUMENT_NODE:
3068#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003069 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003070 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003071 case XML_NOTATION_NODE:
3072 case XML_DTD_NODE:
3073 case XML_ELEMENT_DECL:
3074 case XML_ATTRIBUTE_DECL:
3075 case XML_ENTITY_DECL:
3076 return(NULL);
3077 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003078
Owen Taylor3473f882001-02-23 17:55:21 +00003079 /*
3080 * Allocate a new node and fill the fields.
3081 */
3082 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3083 if (ret == NULL) {
3084 xmlGenericError(xmlGenericErrorContext,
3085 "xmlStaticCopyNode : malloc failed\n");
3086 return(NULL);
3087 }
3088 memset(ret, 0, sizeof(xmlNode));
3089 ret->type = node->type;
3090
3091 ret->doc = doc;
3092 ret->parent = parent;
3093 if (node->name == xmlStringText)
3094 ret->name = xmlStringText;
3095 else if (node->name == xmlStringTextNoenc)
3096 ret->name = xmlStringTextNoenc;
3097 else if (node->name == xmlStringComment)
3098 ret->name = xmlStringComment;
3099 else if (node->name != NULL)
3100 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003101 if ((node->type != XML_ELEMENT_NODE) &&
3102 (node->content != NULL) &&
3103 (node->type != XML_ENTITY_REF_NODE) &&
3104 (node->type != XML_XINCLUDE_END) &&
3105 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003106 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003107 }else{
3108 if (node->type == XML_ELEMENT_NODE)
3109 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003110 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003111 if (parent != NULL) {
3112 xmlNodePtr tmp;
3113
3114 tmp = xmlAddChild(parent, ret);
3115 /* node could have coalesced */
3116 if (tmp != ret)
3117 return(tmp);
3118 }
Owen Taylor3473f882001-02-23 17:55:21 +00003119
3120 if (!recursive) return(ret);
3121 if (node->nsDef != NULL)
3122 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3123
3124 if (node->ns != NULL) {
3125 xmlNsPtr ns;
3126
3127 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3128 if (ns == NULL) {
3129 /*
3130 * Humm, we are copying an element whose namespace is defined
3131 * out of the new tree scope. Search it in the original tree
3132 * and add it at the top of the new tree
3133 */
3134 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3135 if (ns != NULL) {
3136 xmlNodePtr root = ret;
3137
3138 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003139 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003140 }
3141 } else {
3142 /*
3143 * reference the existing namespace definition in our own tree.
3144 */
3145 ret->ns = ns;
3146 }
3147 }
3148 if (node->properties != NULL)
3149 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003150 if (node->type == XML_ENTITY_REF_NODE) {
3151 if ((doc == NULL) || (node->doc != doc)) {
3152 /*
3153 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003154 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003155 * we cannot keep the reference. Try to find it in the
3156 * target document.
3157 */
3158 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3159 } else {
3160 ret->children = node->children;
3161 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003162 ret->last = ret->children;
3163 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003164 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003165 UPDATE_LAST_CHILD_AND_PARENT(ret)
3166 }
Owen Taylor3473f882001-02-23 17:55:21 +00003167 return(ret);
3168}
3169
3170static xmlNodePtr
3171xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3172 xmlNodePtr ret = NULL;
3173 xmlNodePtr p = NULL,q;
3174
3175 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003176 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003177 if (doc == NULL) {
3178 node = node->next;
3179 continue;
3180 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003181 if (doc->intSubset == NULL) {
3182 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3183 q->doc = doc;
3184 q->parent = parent;
3185 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003186 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003187 } else {
3188 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003189 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003190 }
3191 } else
3192 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003193 if (ret == NULL) {
3194 q->prev = NULL;
3195 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003196 } else if (p != q) {
3197 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003198 p->next = q;
3199 q->prev = p;
3200 p = q;
3201 }
3202 node = node->next;
3203 }
3204 return(ret);
3205}
3206
3207/**
3208 * xmlCopyNode:
3209 * @node: the node
3210 * @recursive: if 1 do a recursive copy.
3211 *
3212 * Do a copy of the node.
3213 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003214 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003215 */
3216xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003217xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003218 xmlNodePtr ret;
3219
3220 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3221 return(ret);
3222}
3223
3224/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003225 * xmlDocCopyNode:
3226 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003227 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003228 * @recursive: if 1 do a recursive copy.
3229 *
3230 * Do a copy of the node to a given document.
3231 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003232 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003233 */
3234xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003235xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003236 xmlNodePtr ret;
3237
3238 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3239 return(ret);
3240}
3241
3242/**
Owen Taylor3473f882001-02-23 17:55:21 +00003243 * xmlCopyNodeList:
3244 * @node: the first node in the list.
3245 *
3246 * Do a recursive copy of the node list.
3247 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003248 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003249 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003250xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003251 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3252 return(ret);
3253}
3254
3255/**
Owen Taylor3473f882001-02-23 17:55:21 +00003256 * xmlCopyDtd:
3257 * @dtd: the dtd
3258 *
3259 * Do a copy of the dtd.
3260 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003261 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003262 */
3263xmlDtdPtr
3264xmlCopyDtd(xmlDtdPtr dtd) {
3265 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003266 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003267
3268 if (dtd == NULL) return(NULL);
3269 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3270 if (ret == NULL) return(NULL);
3271 if (dtd->entities != NULL)
3272 ret->entities = (void *) xmlCopyEntitiesTable(
3273 (xmlEntitiesTablePtr) dtd->entities);
3274 if (dtd->notations != NULL)
3275 ret->notations = (void *) xmlCopyNotationTable(
3276 (xmlNotationTablePtr) dtd->notations);
3277 if (dtd->elements != NULL)
3278 ret->elements = (void *) xmlCopyElementTable(
3279 (xmlElementTablePtr) dtd->elements);
3280 if (dtd->attributes != NULL)
3281 ret->attributes = (void *) xmlCopyAttributeTable(
3282 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003283 if (dtd->pentities != NULL)
3284 ret->pentities = (void *) xmlCopyEntitiesTable(
3285 (xmlEntitiesTablePtr) dtd->pentities);
3286
3287 cur = dtd->children;
3288 while (cur != NULL) {
3289 q = NULL;
3290
3291 if (cur->type == XML_ENTITY_DECL) {
3292 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3293 switch (tmp->etype) {
3294 case XML_INTERNAL_GENERAL_ENTITY:
3295 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3296 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3297 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3298 break;
3299 case XML_INTERNAL_PARAMETER_ENTITY:
3300 case XML_EXTERNAL_PARAMETER_ENTITY:
3301 q = (xmlNodePtr)
3302 xmlGetParameterEntityFromDtd(ret, tmp->name);
3303 break;
3304 case XML_INTERNAL_PREDEFINED_ENTITY:
3305 break;
3306 }
3307 } else if (cur->type == XML_ELEMENT_DECL) {
3308 xmlElementPtr tmp = (xmlElementPtr) cur;
3309 q = (xmlNodePtr)
3310 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3311 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3312 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3313 q = (xmlNodePtr)
3314 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3315 } else if (cur->type == XML_COMMENT_NODE) {
3316 q = xmlCopyNode(cur, 0);
3317 }
3318
3319 if (q == NULL) {
3320 cur = cur->next;
3321 continue;
3322 }
3323
3324 if (p == NULL)
3325 ret->children = q;
3326 else
3327 p->next = q;
3328
3329 q->prev = p;
3330 q->parent = (xmlNodePtr) ret;
3331 q->next = NULL;
3332 ret->last = q;
3333 p = q;
3334 cur = cur->next;
3335 }
3336
Owen Taylor3473f882001-02-23 17:55:21 +00003337 return(ret);
3338}
3339
3340/**
3341 * xmlCopyDoc:
3342 * @doc: the document
3343 * @recursive: if 1 do a recursive copy.
3344 *
3345 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003346 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003347 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003348 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003349 */
3350xmlDocPtr
3351xmlCopyDoc(xmlDocPtr doc, int recursive) {
3352 xmlDocPtr ret;
3353
3354 if (doc == NULL) return(NULL);
3355 ret = xmlNewDoc(doc->version);
3356 if (ret == NULL) return(NULL);
3357 if (doc->name != NULL)
3358 ret->name = xmlMemStrdup(doc->name);
3359 if (doc->encoding != NULL)
3360 ret->encoding = xmlStrdup(doc->encoding);
3361 ret->charset = doc->charset;
3362 ret->compression = doc->compression;
3363 ret->standalone = doc->standalone;
3364 if (!recursive) return(ret);
3365
Daniel Veillardb33c2012001-04-25 12:59:04 +00003366 ret->last = NULL;
3367 ret->children = NULL;
3368 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003369 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003370 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003371 ret->intSubset->parent = ret;
3372 }
Owen Taylor3473f882001-02-23 17:55:21 +00003373 if (doc->oldNs != NULL)
3374 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3375 if (doc->children != NULL) {
3376 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003377
3378 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3379 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003380 ret->last = NULL;
3381 tmp = ret->children;
3382 while (tmp != NULL) {
3383 if (tmp->next == NULL)
3384 ret->last = tmp;
3385 tmp = tmp->next;
3386 }
3387 }
3388 return(ret);
3389}
3390
3391/************************************************************************
3392 * *
3393 * Content access functions *
3394 * *
3395 ************************************************************************/
3396
3397/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003398 * xmlGetLineNo:
3399 * @node : valid node
3400 *
3401 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003402 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003403 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003404 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003405 */
3406long
3407xmlGetLineNo(xmlNodePtr node)
3408{
3409 long result = -1;
3410
3411 if (!node)
3412 return result;
3413 if (node->type == XML_ELEMENT_NODE)
3414 result = (long) node->content;
3415 else if ((node->prev != NULL) &&
3416 ((node->prev->type == XML_ELEMENT_NODE) ||
3417 (node->prev->type == XML_TEXT_NODE)))
3418 result = xmlGetLineNo(node->prev);
3419 else if ((node->parent != NULL) &&
3420 ((node->parent->type == XML_ELEMENT_NODE) ||
3421 (node->parent->type == XML_TEXT_NODE)))
3422 result = xmlGetLineNo(node->parent);
3423
3424 return result;
3425}
3426
3427/**
3428 * xmlGetNodePath:
3429 * @node: a node
3430 *
3431 * Build a structure based Path for the given node
3432 *
3433 * Returns the new path or NULL in case of error. The caller must free
3434 * the returned string
3435 */
3436xmlChar *
3437xmlGetNodePath(xmlNodePtr node)
3438{
3439 xmlNodePtr cur, tmp, next;
3440 xmlChar *buffer = NULL, *temp;
3441 size_t buf_len;
3442 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00003443 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00003444 const char *name;
3445 char nametemp[100];
3446 int occur = 0;
3447
3448 if (node == NULL)
3449 return (NULL);
3450
3451 buf_len = 500;
3452 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3453 if (buffer == NULL)
3454 return (NULL);
3455 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3456 if (buf == NULL) {
3457 xmlFree(buffer);
3458 return (NULL);
3459 }
3460
3461 buffer[0] = 0;
3462 cur = node;
3463 do {
3464 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003465 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003466 occur = 0;
3467 if ((cur->type == XML_DOCUMENT_NODE) ||
3468 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3469 if (buffer[0] == '/')
3470 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003471 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003472 next = NULL;
3473 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003474 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003475 name = (const char *) cur->name;
3476 if (cur->ns) {
3477 snprintf(nametemp, sizeof(nametemp) - 1,
3478 "%s:%s", cur->ns->prefix, cur->name);
3479 nametemp[sizeof(nametemp) - 1] = 0;
3480 name = nametemp;
3481 }
3482 next = cur->parent;
3483
3484 /*
3485 * Thumbler index computation
3486 */
3487 tmp = cur->prev;
3488 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00003489 if ((tmp->type == XML_ELEMENT_NODE) &&
3490 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003491 occur++;
3492 tmp = tmp->prev;
3493 }
3494 if (occur == 0) {
3495 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003496 while (tmp != NULL && occur == 0) {
3497 if ((tmp->type == XML_ELEMENT_NODE) &&
3498 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003499 occur++;
3500 tmp = tmp->next;
3501 }
3502 if (occur != 0)
3503 occur = 1;
3504 } else
3505 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003506 } else if (cur->type == XML_COMMENT_NODE) {
3507 sep = "/";
3508 name = "comment()";
3509 next = cur->parent;
3510
3511 /*
3512 * Thumbler index computation
3513 */
3514 tmp = cur->prev;
3515 while (tmp != NULL) {
3516 if (tmp->type == XML_COMMENT_NODE)
3517 occur++;
3518 tmp = tmp->prev;
3519 }
3520 if (occur == 0) {
3521 tmp = cur->next;
3522 while (tmp != NULL && occur == 0) {
3523 if (tmp->type == XML_COMMENT_NODE)
3524 occur++;
3525 tmp = tmp->next;
3526 }
3527 if (occur != 0)
3528 occur = 1;
3529 } else
3530 occur++;
3531 } else if ((cur->type == XML_TEXT_NODE) ||
3532 (cur->type == XML_CDATA_SECTION_NODE)) {
3533 sep = "/";
3534 name = "text()";
3535 next = cur->parent;
3536
3537 /*
3538 * Thumbler index computation
3539 */
3540 tmp = cur->prev;
3541 while (tmp != NULL) {
3542 if ((cur->type == XML_TEXT_NODE) ||
3543 (cur->type == XML_CDATA_SECTION_NODE))
3544 occur++;
3545 tmp = tmp->prev;
3546 }
3547 if (occur == 0) {
3548 tmp = cur->next;
3549 while (tmp != NULL && occur == 0) {
3550 if ((cur->type == XML_TEXT_NODE) ||
3551 (cur->type == XML_CDATA_SECTION_NODE))
3552 occur++;
3553 tmp = tmp->next;
3554 }
3555 if (occur != 0)
3556 occur = 1;
3557 } else
3558 occur++;
3559 } else if (cur->type == XML_PI_NODE) {
3560 sep = "/";
3561 snprintf(nametemp, sizeof(nametemp) - 1,
3562 "processing-instruction('%s')", cur->name);
3563 nametemp[sizeof(nametemp) - 1] = 0;
3564 name = nametemp;
3565
3566 next = cur->parent;
3567
3568 /*
3569 * Thumbler index computation
3570 */
3571 tmp = cur->prev;
3572 while (tmp != NULL) {
3573 if ((tmp->type == XML_PI_NODE) &&
3574 (xmlStrEqual(cur->name, tmp->name)))
3575 occur++;
3576 tmp = tmp->prev;
3577 }
3578 if (occur == 0) {
3579 tmp = cur->next;
3580 while (tmp != NULL && occur == 0) {
3581 if ((tmp->type == XML_PI_NODE) &&
3582 (xmlStrEqual(cur->name, tmp->name)))
3583 occur++;
3584 tmp = tmp->next;
3585 }
3586 if (occur != 0)
3587 occur = 1;
3588 } else
3589 occur++;
3590
Daniel Veillard8faa7832001-11-26 15:58:08 +00003591 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003592 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003593 name = (const char *) (((xmlAttrPtr) cur)->name);
3594 next = ((xmlAttrPtr) cur)->parent;
3595 } else {
3596 next = cur->parent;
3597 }
3598
3599 /*
3600 * Make sure there is enough room
3601 */
3602 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3603 buf_len =
3604 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3605 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3606 if (temp == NULL) {
3607 xmlFree(buf);
3608 xmlFree(buffer);
3609 return (NULL);
3610 }
3611 buffer = temp;
3612 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3613 if (temp == NULL) {
3614 xmlFree(buf);
3615 xmlFree(buffer);
3616 return (NULL);
3617 }
3618 buf = temp;
3619 }
3620 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003621 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00003622 sep, name, (char *) buffer);
3623 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003624 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00003625 sep, name, occur, (char *) buffer);
3626 snprintf((char *) buffer, buf_len, "%s", buf);
3627 cur = next;
3628 } while (cur != NULL);
3629 xmlFree(buf);
3630 return (buffer);
3631}
3632
3633/**
Owen Taylor3473f882001-02-23 17:55:21 +00003634 * xmlDocGetRootElement:
3635 * @doc: the document
3636 *
3637 * Get the root element of the document (doc->children is a list
3638 * containing possibly comments, PIs, etc ...).
3639 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003640 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003641 */
3642xmlNodePtr
3643xmlDocGetRootElement(xmlDocPtr doc) {
3644 xmlNodePtr ret;
3645
3646 if (doc == NULL) return(NULL);
3647 ret = doc->children;
3648 while (ret != NULL) {
3649 if (ret->type == XML_ELEMENT_NODE)
3650 return(ret);
3651 ret = ret->next;
3652 }
3653 return(ret);
3654}
3655
3656/**
3657 * xmlDocSetRootElement:
3658 * @doc: the document
3659 * @root: the new document root element
3660 *
3661 * Set the root element of the document (doc->children is a list
3662 * containing possibly comments, PIs, etc ...).
3663 *
3664 * Returns the old root element if any was found
3665 */
3666xmlNodePtr
3667xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3668 xmlNodePtr old = NULL;
3669
3670 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00003671 if (root == NULL)
3672 return(NULL);
3673 xmlUnlinkNode(root);
3674 root->doc = doc;
3675 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00003676 old = doc->children;
3677 while (old != NULL) {
3678 if (old->type == XML_ELEMENT_NODE)
3679 break;
3680 old = old->next;
3681 }
3682 if (old == NULL) {
3683 if (doc->children == NULL) {
3684 doc->children = root;
3685 doc->last = root;
3686 } else {
3687 xmlAddSibling(doc->children, root);
3688 }
3689 } else {
3690 xmlReplaceNode(old, root);
3691 }
3692 return(old);
3693}
3694
3695/**
3696 * xmlNodeSetLang:
3697 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003698 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003699 *
3700 * Set the language of a node, i.e. the values of the xml:lang
3701 * attribute.
3702 */
3703void
3704xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003705 xmlNsPtr ns;
3706
Owen Taylor3473f882001-02-23 17:55:21 +00003707 if (cur == NULL) return;
3708 switch(cur->type) {
3709 case XML_TEXT_NODE:
3710 case XML_CDATA_SECTION_NODE:
3711 case XML_COMMENT_NODE:
3712 case XML_DOCUMENT_NODE:
3713 case XML_DOCUMENT_TYPE_NODE:
3714 case XML_DOCUMENT_FRAG_NODE:
3715 case XML_NOTATION_NODE:
3716 case XML_HTML_DOCUMENT_NODE:
3717 case XML_DTD_NODE:
3718 case XML_ELEMENT_DECL:
3719 case XML_ATTRIBUTE_DECL:
3720 case XML_ENTITY_DECL:
3721 case XML_PI_NODE:
3722 case XML_ENTITY_REF_NODE:
3723 case XML_ENTITY_NODE:
3724 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003725#ifdef LIBXML_DOCB_ENABLED
3726 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003727#endif
3728 case XML_XINCLUDE_START:
3729 case XML_XINCLUDE_END:
3730 return;
3731 case XML_ELEMENT_NODE:
3732 case XML_ATTRIBUTE_NODE:
3733 break;
3734 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003735 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3736 if (ns == NULL)
3737 return;
3738 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003739}
3740
3741/**
3742 * xmlNodeGetLang:
3743 * @cur: the node being checked
3744 *
3745 * Searches the language of a node, i.e. the values of the xml:lang
3746 * attribute or the one carried by the nearest ancestor.
3747 *
3748 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003749 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003750 */
3751xmlChar *
3752xmlNodeGetLang(xmlNodePtr cur) {
3753 xmlChar *lang;
3754
3755 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003756 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003757 if (lang != NULL)
3758 return(lang);
3759 cur = cur->parent;
3760 }
3761 return(NULL);
3762}
3763
3764
3765/**
3766 * xmlNodeSetSpacePreserve:
3767 * @cur: the node being changed
3768 * @val: the xml:space value ("0": default, 1: "preserve")
3769 *
3770 * Set (or reset) the space preserving behaviour of a node, i.e. the
3771 * value of the xml:space attribute.
3772 */
3773void
3774xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003775 xmlNsPtr ns;
3776
Owen Taylor3473f882001-02-23 17:55:21 +00003777 if (cur == NULL) return;
3778 switch(cur->type) {
3779 case XML_TEXT_NODE:
3780 case XML_CDATA_SECTION_NODE:
3781 case XML_COMMENT_NODE:
3782 case XML_DOCUMENT_NODE:
3783 case XML_DOCUMENT_TYPE_NODE:
3784 case XML_DOCUMENT_FRAG_NODE:
3785 case XML_NOTATION_NODE:
3786 case XML_HTML_DOCUMENT_NODE:
3787 case XML_DTD_NODE:
3788 case XML_ELEMENT_DECL:
3789 case XML_ATTRIBUTE_DECL:
3790 case XML_ENTITY_DECL:
3791 case XML_PI_NODE:
3792 case XML_ENTITY_REF_NODE:
3793 case XML_ENTITY_NODE:
3794 case XML_NAMESPACE_DECL:
3795 case XML_XINCLUDE_START:
3796 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003797#ifdef LIBXML_DOCB_ENABLED
3798 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003799#endif
3800 return;
3801 case XML_ELEMENT_NODE:
3802 case XML_ATTRIBUTE_NODE:
3803 break;
3804 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003805 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3806 if (ns == NULL)
3807 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003808 switch (val) {
3809 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003810 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003811 break;
3812 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003813 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003814 break;
3815 }
3816}
3817
3818/**
3819 * xmlNodeGetSpacePreserve:
3820 * @cur: the node being checked
3821 *
3822 * Searches the space preserving behaviour of a node, i.e. the values
3823 * of the xml:space attribute or the one carried by the nearest
3824 * ancestor.
3825 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003826 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003827 */
3828int
3829xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3830 xmlChar *space;
3831
3832 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003833 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003834 if (space != NULL) {
3835 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3836 xmlFree(space);
3837 return(1);
3838 }
3839 if (xmlStrEqual(space, BAD_CAST "default")) {
3840 xmlFree(space);
3841 return(0);
3842 }
3843 xmlFree(space);
3844 }
3845 cur = cur->parent;
3846 }
3847 return(-1);
3848}
3849
3850/**
3851 * xmlNodeSetName:
3852 * @cur: the node being changed
3853 * @name: the new tag name
3854 *
3855 * Set (or reset) the name of a node.
3856 */
3857void
3858xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3859 if (cur == NULL) return;
3860 if (name == NULL) return;
3861 switch(cur->type) {
3862 case XML_TEXT_NODE:
3863 case XML_CDATA_SECTION_NODE:
3864 case XML_COMMENT_NODE:
3865 case XML_DOCUMENT_TYPE_NODE:
3866 case XML_DOCUMENT_FRAG_NODE:
3867 case XML_NOTATION_NODE:
3868 case XML_HTML_DOCUMENT_NODE:
3869 case XML_NAMESPACE_DECL:
3870 case XML_XINCLUDE_START:
3871 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003872#ifdef LIBXML_DOCB_ENABLED
3873 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003874#endif
3875 return;
3876 case XML_ELEMENT_NODE:
3877 case XML_ATTRIBUTE_NODE:
3878 case XML_PI_NODE:
3879 case XML_ENTITY_REF_NODE:
3880 case XML_ENTITY_NODE:
3881 case XML_DTD_NODE:
3882 case XML_DOCUMENT_NODE:
3883 case XML_ELEMENT_DECL:
3884 case XML_ATTRIBUTE_DECL:
3885 case XML_ENTITY_DECL:
3886 break;
3887 }
3888 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3889 cur->name = xmlStrdup(name);
3890}
3891
3892/**
3893 * xmlNodeSetBase:
3894 * @cur: the node being changed
3895 * @uri: the new base URI
3896 *
3897 * Set (or reset) the base URI of a node, i.e. the value of the
3898 * xml:base attribute.
3899 */
3900void
3901xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003902 xmlNsPtr ns;
3903
Owen Taylor3473f882001-02-23 17:55:21 +00003904 if (cur == NULL) return;
3905 switch(cur->type) {
3906 case XML_TEXT_NODE:
3907 case XML_CDATA_SECTION_NODE:
3908 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003909 case XML_DOCUMENT_TYPE_NODE:
3910 case XML_DOCUMENT_FRAG_NODE:
3911 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003912 case XML_DTD_NODE:
3913 case XML_ELEMENT_DECL:
3914 case XML_ATTRIBUTE_DECL:
3915 case XML_ENTITY_DECL:
3916 case XML_PI_NODE:
3917 case XML_ENTITY_REF_NODE:
3918 case XML_ENTITY_NODE:
3919 case XML_NAMESPACE_DECL:
3920 case XML_XINCLUDE_START:
3921 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00003922 return;
3923 case XML_ELEMENT_NODE:
3924 case XML_ATTRIBUTE_NODE:
3925 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00003926 case XML_DOCUMENT_NODE:
3927#ifdef LIBXML_DOCB_ENABLED
3928 case XML_DOCB_DOCUMENT_NODE:
3929#endif
3930 case XML_HTML_DOCUMENT_NODE: {
3931 xmlDocPtr doc = (xmlDocPtr) cur;
3932
3933 if (doc->URL != NULL)
3934 xmlFree((xmlChar *) doc->URL);
3935 if (uri == NULL)
3936 doc->URL = NULL;
3937 else
3938 doc->URL = xmlStrdup(uri);
3939 return;
3940 }
Owen Taylor3473f882001-02-23 17:55:21 +00003941 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003942
3943 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3944 if (ns == NULL)
3945 return;
3946 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00003947}
3948
3949/**
Owen Taylor3473f882001-02-23 17:55:21 +00003950 * xmlNodeGetBase:
3951 * @doc: the document the node pertains to
3952 * @cur: the node being checked
3953 *
3954 * Searches for the BASE URL. The code should work on both XML
3955 * and HTML document even if base mechanisms are completely different.
3956 * It returns the base as defined in RFC 2396 sections
3957 * 5.1.1. Base URI within Document Content
3958 * and
3959 * 5.1.2. Base URI from the Encapsulating Entity
3960 * However it does not return the document base (5.1.3), use
3961 * xmlDocumentGetBase() for this
3962 *
3963 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003964 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003965 */
3966xmlChar *
3967xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003968 xmlChar *oldbase = NULL;
3969 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003970
3971 if ((cur == NULL) && (doc == NULL))
3972 return(NULL);
3973 if (doc == NULL) doc = cur->doc;
3974 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3975 cur = doc->children;
3976 while ((cur != NULL) && (cur->name != NULL)) {
3977 if (cur->type != XML_ELEMENT_NODE) {
3978 cur = cur->next;
3979 continue;
3980 }
3981 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3982 cur = cur->children;
3983 continue;
3984 }
3985 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3986 cur = cur->children;
3987 continue;
3988 }
3989 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3990 return(xmlGetProp(cur, BAD_CAST "href"));
3991 }
3992 cur = cur->next;
3993 }
3994 return(NULL);
3995 }
3996 while (cur != NULL) {
3997 if (cur->type == XML_ENTITY_DECL) {
3998 xmlEntityPtr ent = (xmlEntityPtr) cur;
3999 return(xmlStrdup(ent->URI));
4000 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004001 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004002 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004003 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004004 if (oldbase != NULL) {
4005 newbase = xmlBuildURI(oldbase, base);
4006 if (newbase != NULL) {
4007 xmlFree(oldbase);
4008 xmlFree(base);
4009 oldbase = newbase;
4010 } else {
4011 xmlFree(oldbase);
4012 xmlFree(base);
4013 return(NULL);
4014 }
4015 } else {
4016 oldbase = base;
4017 }
4018 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4019 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4020 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4021 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004022 }
4023 }
Owen Taylor3473f882001-02-23 17:55:21 +00004024 cur = cur->parent;
4025 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004026 if ((doc != NULL) && (doc->URL != NULL)) {
4027 if (oldbase == NULL)
4028 return(xmlStrdup(doc->URL));
4029 newbase = xmlBuildURI(oldbase, doc->URL);
4030 xmlFree(oldbase);
4031 return(newbase);
4032 }
4033 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004034}
4035
4036/**
4037 * xmlNodeGetContent:
4038 * @cur: the node being read
4039 *
4040 * Read the value of a node, this can be either the text carried
4041 * directly by this node if it's a TEXT node or the aggregate string
4042 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004043 * Entity references are substituted.
4044 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004045 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004046 */
4047xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004048xmlNodeGetContent(xmlNodePtr cur)
4049{
4050 if (cur == NULL)
4051 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004052 switch (cur->type) {
4053 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004054 case XML_ELEMENT_NODE:{
4055 xmlNodePtr tmp = cur;
4056 xmlBufferPtr buffer;
4057 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004058
Daniel Veillard7646b182002-04-20 06:41:40 +00004059 buffer = xmlBufferCreate();
4060 if (buffer == NULL)
4061 return (NULL);
4062 while (tmp != NULL) {
4063 switch (tmp->type) {
4064 case XML_CDATA_SECTION_NODE:
4065 case XML_TEXT_NODE:
4066 if (tmp->content != NULL)
4067 xmlBufferCat(buffer, tmp->content);
4068 break;
4069 case XML_ENTITY_REF_NODE:{
4070 /* recursive substitution of entity references */
4071 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00004072
Daniel Veillard7646b182002-04-20 06:41:40 +00004073 if (cont) {
4074 xmlBufferCat(buffer,
4075 (const xmlChar *) cont);
4076 xmlFree(cont);
4077 }
4078 break;
4079 }
4080 default:
4081 break;
4082 }
4083 /*
4084 * Skip to next node
4085 */
4086 if (tmp->children != NULL) {
4087 if (tmp->children->type != XML_ENTITY_DECL) {
4088 tmp = tmp->children;
4089 continue;
4090 }
4091 }
4092 if (tmp == cur)
4093 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004094
Daniel Veillard7646b182002-04-20 06:41:40 +00004095 if (tmp->next != NULL) {
4096 tmp = tmp->next;
4097 continue;
4098 }
4099
4100 do {
4101 tmp = tmp->parent;
4102 if (tmp == NULL)
4103 break;
4104 if (tmp == cur) {
4105 tmp = NULL;
4106 break;
4107 }
4108 if (tmp->next != NULL) {
4109 tmp = tmp->next;
4110 break;
4111 }
4112 } while (tmp != NULL);
4113 }
4114 ret = buffer->content;
4115 buffer->content = NULL;
4116 xmlBufferFree(buffer);
4117 return (ret);
4118 }
4119 case XML_ATTRIBUTE_NODE:{
4120 xmlAttrPtr attr = (xmlAttrPtr) cur;
4121
4122 if (attr->parent != NULL)
4123 return (xmlNodeListGetString
4124 (attr->parent->doc, attr->children, 1));
4125 else
4126 return (xmlNodeListGetString(NULL, attr->children, 1));
4127 break;
4128 }
Owen Taylor3473f882001-02-23 17:55:21 +00004129 case XML_COMMENT_NODE:
4130 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004131 if (cur->content != NULL)
4132 return (xmlStrdup(cur->content));
4133 return (NULL);
4134 case XML_ENTITY_REF_NODE:{
4135 xmlEntityPtr ent;
4136 xmlNodePtr tmp;
4137 xmlBufferPtr buffer;
4138 xmlChar *ret;
4139
4140 /* lookup entity declaration */
4141 ent = xmlGetDocEntity(cur->doc, cur->name);
4142 if (ent == NULL)
4143 return (NULL);
4144
4145 buffer = xmlBufferCreate();
4146 if (buffer == NULL)
4147 return (NULL);
4148
4149 /* an entity content can be any "well balanced chunk",
4150 * i.e. the result of the content [43] production:
4151 * http://www.w3.org/TR/REC-xml#NT-content
4152 * -> we iterate through child nodes and recursive call
4153 * xmlNodeGetContent() which handles all possible node types */
4154 tmp = ent->children;
4155 while (tmp) {
4156 xmlChar *cont = xmlNodeGetContent(tmp);
4157
4158 if (cont) {
4159 xmlBufferCat(buffer, (const xmlChar *) cont);
4160 xmlFree(cont);
4161 }
4162 tmp = tmp->next;
4163 }
4164
4165 ret = buffer->content;
4166 buffer->content = NULL;
4167 xmlBufferFree(buffer);
4168 return (ret);
4169 }
Owen Taylor3473f882001-02-23 17:55:21 +00004170 case XML_ENTITY_NODE:
4171 case XML_DOCUMENT_NODE:
4172 case XML_HTML_DOCUMENT_NODE:
4173 case XML_DOCUMENT_TYPE_NODE:
4174 case XML_NOTATION_NODE:
4175 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004176 case XML_XINCLUDE_START:
4177 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004178#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004179 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004180#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00004181 return (NULL);
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004182 case XML_NAMESPACE_DECL: {
4183 xmlChar *tmp;
4184
4185 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4186 return (tmp);
4187 }
Owen Taylor3473f882001-02-23 17:55:21 +00004188 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004189 /* TODO !!! */
4190 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004191 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004192 /* TODO !!! */
4193 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004194 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004195 /* TODO !!! */
4196 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004197 case XML_CDATA_SECTION_NODE:
4198 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004199 if (cur->content != NULL)
4200 return (xmlStrdup(cur->content));
4201 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004202 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004203 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004204}
Owen Taylor3473f882001-02-23 17:55:21 +00004205/**
4206 * xmlNodeSetContent:
4207 * @cur: the node being modified
4208 * @content: the new value of the content
4209 *
4210 * Replace the content of a node.
4211 */
4212void
4213xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4214 if (cur == NULL) {
4215#ifdef DEBUG_TREE
4216 xmlGenericError(xmlGenericErrorContext,
4217 "xmlNodeSetContent : node == NULL\n");
4218#endif
4219 return;
4220 }
4221 switch (cur->type) {
4222 case XML_DOCUMENT_FRAG_NODE:
4223 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004224 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004225 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4226 cur->children = xmlStringGetNodeList(cur->doc, content);
4227 UPDATE_LAST_CHILD_AND_PARENT(cur)
4228 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004229 case XML_TEXT_NODE:
4230 case XML_CDATA_SECTION_NODE:
4231 case XML_ENTITY_REF_NODE:
4232 case XML_ENTITY_NODE:
4233 case XML_PI_NODE:
4234 case XML_COMMENT_NODE:
4235 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004236 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004237 }
4238 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4239 cur->last = cur->children = NULL;
4240 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004241 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004242 } else
4243 cur->content = NULL;
4244 break;
4245 case XML_DOCUMENT_NODE:
4246 case XML_HTML_DOCUMENT_NODE:
4247 case XML_DOCUMENT_TYPE_NODE:
4248 case XML_XINCLUDE_START:
4249 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004250#ifdef LIBXML_DOCB_ENABLED
4251 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004252#endif
4253 break;
4254 case XML_NOTATION_NODE:
4255 break;
4256 case XML_DTD_NODE:
4257 break;
4258 case XML_NAMESPACE_DECL:
4259 break;
4260 case XML_ELEMENT_DECL:
4261 /* TODO !!! */
4262 break;
4263 case XML_ATTRIBUTE_DECL:
4264 /* TODO !!! */
4265 break;
4266 case XML_ENTITY_DECL:
4267 /* TODO !!! */
4268 break;
4269 }
4270}
4271
4272/**
4273 * xmlNodeSetContentLen:
4274 * @cur: the node being modified
4275 * @content: the new value of the content
4276 * @len: the size of @content
4277 *
4278 * Replace the content of a node.
4279 */
4280void
4281xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4282 if (cur == NULL) {
4283#ifdef DEBUG_TREE
4284 xmlGenericError(xmlGenericErrorContext,
4285 "xmlNodeSetContentLen : node == NULL\n");
4286#endif
4287 return;
4288 }
4289 switch (cur->type) {
4290 case XML_DOCUMENT_FRAG_NODE:
4291 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004292 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004293 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4294 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4295 UPDATE_LAST_CHILD_AND_PARENT(cur)
4296 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004297 case XML_TEXT_NODE:
4298 case XML_CDATA_SECTION_NODE:
4299 case XML_ENTITY_REF_NODE:
4300 case XML_ENTITY_NODE:
4301 case XML_PI_NODE:
4302 case XML_COMMENT_NODE:
4303 case XML_NOTATION_NODE:
4304 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004305 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004306 }
4307 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4308 cur->children = cur->last = NULL;
4309 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004310 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004311 } else
4312 cur->content = NULL;
4313 break;
4314 case XML_DOCUMENT_NODE:
4315 case XML_DTD_NODE:
4316 case XML_HTML_DOCUMENT_NODE:
4317 case XML_DOCUMENT_TYPE_NODE:
4318 case XML_NAMESPACE_DECL:
4319 case XML_XINCLUDE_START:
4320 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004321#ifdef LIBXML_DOCB_ENABLED
4322 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004323#endif
4324 break;
4325 case XML_ELEMENT_DECL:
4326 /* TODO !!! */
4327 break;
4328 case XML_ATTRIBUTE_DECL:
4329 /* TODO !!! */
4330 break;
4331 case XML_ENTITY_DECL:
4332 /* TODO !!! */
4333 break;
4334 }
4335}
4336
4337/**
4338 * xmlNodeAddContentLen:
4339 * @cur: the node being modified
4340 * @content: extra content
4341 * @len: the size of @content
4342 *
4343 * Append the extra substring to the node content.
4344 */
4345void
4346xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4347 if (cur == NULL) {
4348#ifdef DEBUG_TREE
4349 xmlGenericError(xmlGenericErrorContext,
4350 "xmlNodeAddContentLen : node == NULL\n");
4351#endif
4352 return;
4353 }
4354 if (len <= 0) return;
4355 switch (cur->type) {
4356 case XML_DOCUMENT_FRAG_NODE:
4357 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004358 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004359
Daniel Veillard7db37732001-07-12 01:20:08 +00004360 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004361 newNode = xmlNewTextLen(content, len);
4362 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004363 tmp = xmlAddChild(cur, newNode);
4364 if (tmp != newNode)
4365 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004366 if ((last != NULL) && (last->next == newNode)) {
4367 xmlTextMerge(last, newNode);
4368 }
4369 }
4370 break;
4371 }
4372 case XML_ATTRIBUTE_NODE:
4373 break;
4374 case XML_TEXT_NODE:
4375 case XML_CDATA_SECTION_NODE:
4376 case XML_ENTITY_REF_NODE:
4377 case XML_ENTITY_NODE:
4378 case XML_PI_NODE:
4379 case XML_COMMENT_NODE:
4380 case XML_NOTATION_NODE:
4381 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004382 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004383 }
4384 case XML_DOCUMENT_NODE:
4385 case XML_DTD_NODE:
4386 case XML_HTML_DOCUMENT_NODE:
4387 case XML_DOCUMENT_TYPE_NODE:
4388 case XML_NAMESPACE_DECL:
4389 case XML_XINCLUDE_START:
4390 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004391#ifdef LIBXML_DOCB_ENABLED
4392 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004393#endif
4394 break;
4395 case XML_ELEMENT_DECL:
4396 case XML_ATTRIBUTE_DECL:
4397 case XML_ENTITY_DECL:
4398 break;
4399 }
4400}
4401
4402/**
4403 * xmlNodeAddContent:
4404 * @cur: the node being modified
4405 * @content: extra content
4406 *
4407 * Append the extra substring to the node content.
4408 */
4409void
4410xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4411 int len;
4412
4413 if (cur == NULL) {
4414#ifdef DEBUG_TREE
4415 xmlGenericError(xmlGenericErrorContext,
4416 "xmlNodeAddContent : node == NULL\n");
4417#endif
4418 return;
4419 }
4420 if (content == NULL) return;
4421 len = xmlStrlen(content);
4422 xmlNodeAddContentLen(cur, content, len);
4423}
4424
4425/**
4426 * xmlTextMerge:
4427 * @first: the first text node
4428 * @second: the second text node being merged
4429 *
4430 * Merge two text nodes into one
4431 * Returns the first text node augmented
4432 */
4433xmlNodePtr
4434xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4435 if (first == NULL) return(second);
4436 if (second == NULL) return(first);
4437 if (first->type != XML_TEXT_NODE) return(first);
4438 if (second->type != XML_TEXT_NODE) return(first);
4439 if (second->name != first->name)
4440 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004441 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004442 xmlUnlinkNode(second);
4443 xmlFreeNode(second);
4444 return(first);
4445}
4446
4447/**
4448 * xmlGetNsList:
4449 * @doc: the document
4450 * @node: the current node
4451 *
4452 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004453 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004454 * that need to be freed by the caller or NULL if no
4455 * namespace if defined
4456 */
4457xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004458xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4459{
Owen Taylor3473f882001-02-23 17:55:21 +00004460 xmlNsPtr cur;
4461 xmlNsPtr *ret = NULL;
4462 int nbns = 0;
4463 int maxns = 10;
4464 int i;
4465
4466 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004467 if (node->type == XML_ELEMENT_NODE) {
4468 cur = node->nsDef;
4469 while (cur != NULL) {
4470 if (ret == NULL) {
4471 ret =
4472 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4473 sizeof(xmlNsPtr));
4474 if (ret == NULL) {
4475 xmlGenericError(xmlGenericErrorContext,
4476 "xmlGetNsList : out of memory!\n");
4477 return (NULL);
4478 }
4479 ret[nbns] = NULL;
4480 }
4481 for (i = 0; i < nbns; i++) {
4482 if ((cur->prefix == ret[i]->prefix) ||
4483 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4484 break;
4485 }
4486 if (i >= nbns) {
4487 if (nbns >= maxns) {
4488 maxns *= 2;
4489 ret = (xmlNsPtr *) xmlRealloc(ret,
4490 (maxns +
4491 1) *
4492 sizeof(xmlNsPtr));
4493 if (ret == NULL) {
4494 xmlGenericError(xmlGenericErrorContext,
4495 "xmlGetNsList : realloc failed!\n");
4496 return (NULL);
4497 }
4498 }
4499 ret[nbns++] = cur;
4500 ret[nbns] = NULL;
4501 }
Owen Taylor3473f882001-02-23 17:55:21 +00004502
Daniel Veillard77044732001-06-29 21:31:07 +00004503 cur = cur->next;
4504 }
4505 }
4506 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004507 }
Daniel Veillard77044732001-06-29 21:31:07 +00004508 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004509}
4510
4511/**
4512 * xmlSearchNs:
4513 * @doc: the document
4514 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004515 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004516 *
4517 * Search a Ns registered under a given name space for a document.
4518 * recurse on the parents until it finds the defined namespace
4519 * or return NULL otherwise.
4520 * @nameSpace can be NULL, this is a search for the default namespace.
4521 * We don't allow to cross entities boundaries. If you don't declare
4522 * the namespace within those you will be in troubles !!! A warning
4523 * is generated to cover this case.
4524 *
4525 * Returns the namespace pointer or NULL.
4526 */
4527xmlNsPtr
4528xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4529 xmlNsPtr cur;
4530
4531 if (node == NULL) return(NULL);
4532 if ((nameSpace != NULL) &&
4533 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00004534 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4535 /*
4536 * The XML-1.0 namespace is normally held on the root
4537 * element. In this case exceptionally create it on the
4538 * node element.
4539 */
4540 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4541 if (cur == NULL) {
4542 xmlGenericError(xmlGenericErrorContext,
4543 "xmlSearchNs : malloc failed\n");
4544 return(NULL);
4545 }
4546 memset(cur, 0, sizeof(xmlNs));
4547 cur->type = XML_LOCAL_NAMESPACE;
4548 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4549 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4550 cur->next = node->nsDef;
4551 node->nsDef = cur;
4552 return(cur);
4553 }
Owen Taylor3473f882001-02-23 17:55:21 +00004554 if (doc->oldNs == NULL) {
4555 /*
4556 * Allocate a new Namespace and fill the fields.
4557 */
4558 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4559 if (doc->oldNs == NULL) {
4560 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004561 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004562 return(NULL);
4563 }
4564 memset(doc->oldNs, 0, sizeof(xmlNs));
4565 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4566
4567 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4568 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4569 }
4570 return(doc->oldNs);
4571 }
4572 while (node != NULL) {
4573 if ((node->type == XML_ENTITY_REF_NODE) ||
4574 (node->type == XML_ENTITY_NODE) ||
4575 (node->type == XML_ENTITY_DECL))
4576 return(NULL);
4577 if (node->type == XML_ELEMENT_NODE) {
4578 cur = node->nsDef;
4579 while (cur != NULL) {
4580 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4581 (cur->href != NULL))
4582 return(cur);
4583 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4584 (cur->href != NULL) &&
4585 (xmlStrEqual(cur->prefix, nameSpace)))
4586 return(cur);
4587 cur = cur->next;
4588 }
4589 }
4590 node = node->parent;
4591 }
4592 return(NULL);
4593}
4594
4595/**
4596 * xmlSearchNsByHref:
4597 * @doc: the document
4598 * @node: the current node
4599 * @href: the namespace value
4600 *
4601 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4602 * the defined namespace or return NULL otherwise.
4603 * Returns the namespace pointer or NULL.
4604 */
4605xmlNsPtr
4606xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4607 xmlNsPtr cur;
4608 xmlNodePtr orig = node;
4609
4610 if ((node == NULL) || (href == NULL)) return(NULL);
4611 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004612 /*
4613 * Only the document can hold the XML spec namespace.
4614 */
Daniel Veillardc1a0da32002-08-14 08:32:18 +00004615 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4616 /*
4617 * The XML-1.0 namespace is normally held on the root
4618 * element. In this case exceptionally create it on the
4619 * node element.
4620 */
4621 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4622 if (cur == NULL) {
4623 xmlGenericError(xmlGenericErrorContext,
4624 "xmlSearchNs : malloc failed\n");
4625 return(NULL);
4626 }
4627 memset(cur, 0, sizeof(xmlNs));
4628 cur->type = XML_LOCAL_NAMESPACE;
4629 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4630 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4631 cur->next = node->nsDef;
4632 node->nsDef = cur;
4633 return(cur);
4634 }
Owen Taylor3473f882001-02-23 17:55:21 +00004635 if (doc->oldNs == NULL) {
4636 /*
4637 * Allocate a new Namespace and fill the fields.
4638 */
4639 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4640 if (doc->oldNs == NULL) {
4641 xmlGenericError(xmlGenericErrorContext,
4642 "xmlSearchNsByHref : malloc failed\n");
4643 return(NULL);
4644 }
4645 memset(doc->oldNs, 0, sizeof(xmlNs));
4646 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4647
4648 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4649 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4650 }
4651 return(doc->oldNs);
4652 }
4653 while (node != NULL) {
4654 cur = node->nsDef;
4655 while (cur != NULL) {
4656 if ((cur->href != NULL) && (href != NULL) &&
4657 (xmlStrEqual(cur->href, href))) {
4658 /*
4659 * Check that the prefix is not shadowed between orig and node
4660 */
4661 xmlNodePtr check = orig;
4662 xmlNsPtr tst;
4663
4664 while (check != node) {
4665 tst = check->nsDef;
4666 while (tst != NULL) {
4667 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4668 goto shadowed;
4669 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4670 (xmlStrEqual(tst->prefix, cur->prefix)))
4671 goto shadowed;
4672 tst = tst->next;
4673 }
4674 check = check->parent;
4675 }
4676 return(cur);
4677 }
4678shadowed:
4679 cur = cur->next;
4680 }
4681 node = node->parent;
4682 }
4683 return(NULL);
4684}
4685
4686/**
4687 * xmlNewReconciliedNs
4688 * @doc: the document
4689 * @tree: a node expected to hold the new namespace
4690 * @ns: the original namespace
4691 *
4692 * This function tries to locate a namespace definition in a tree
4693 * ancestors, or create a new namespace definition node similar to
4694 * @ns trying to reuse the same prefix. However if the given prefix is
4695 * null (default namespace) or reused within the subtree defined by
4696 * @tree or on one of its ancestors then a new prefix is generated.
4697 * Returns the (new) namespace definition or NULL in case of error
4698 */
4699xmlNsPtr
4700xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4701 xmlNsPtr def;
4702 xmlChar prefix[50];
4703 int counter = 1;
4704
4705 if (tree == NULL) {
4706#ifdef DEBUG_TREE
4707 xmlGenericError(xmlGenericErrorContext,
4708 "xmlNewReconciliedNs : tree == NULL\n");
4709#endif
4710 return(NULL);
4711 }
4712 if (ns == NULL) {
4713#ifdef DEBUG_TREE
4714 xmlGenericError(xmlGenericErrorContext,
4715 "xmlNewReconciliedNs : ns == NULL\n");
4716#endif
4717 return(NULL);
4718 }
4719 /*
4720 * Search an existing namespace definition inherited.
4721 */
4722 def = xmlSearchNsByHref(doc, tree, ns->href);
4723 if (def != NULL)
4724 return(def);
4725
4726 /*
4727 * Find a close prefix which is not already in use.
4728 * Let's strip namespace prefixes longer than 20 chars !
4729 */
Daniel Veillardf742d342002-03-07 00:05:35 +00004730 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004731 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00004732 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004733 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00004734
Owen Taylor3473f882001-02-23 17:55:21 +00004735 def = xmlSearchNs(doc, tree, prefix);
4736 while (def != NULL) {
4737 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00004738 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004739 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00004740 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004741 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00004742 def = xmlSearchNs(doc, tree, prefix);
4743 }
4744
4745 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004746 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004747 */
4748 def = xmlNewNs(tree, ns->href, prefix);
4749 return(def);
4750}
4751
4752/**
4753 * xmlReconciliateNs
4754 * @doc: the document
4755 * @tree: a node defining the subtree to reconciliate
4756 *
4757 * This function checks that all the namespaces declared within the given
4758 * tree are properly declared. This is needed for example after Copy or Cut
4759 * and then paste operations. The subtree may still hold pointers to
4760 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004761 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004762 * the new environment. If not possible the new namespaces are redeclared
4763 * on @tree at the top of the given subtree.
4764 * Returns the number of namespace declarations created or -1 in case of error.
4765 */
4766int
4767xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4768 xmlNsPtr *oldNs = NULL;
4769 xmlNsPtr *newNs = NULL;
4770 int sizeCache = 0;
4771 int nbCache = 0;
4772
4773 xmlNsPtr n;
4774 xmlNodePtr node = tree;
4775 xmlAttrPtr attr;
4776 int ret = 0, i;
4777
4778 while (node != NULL) {
4779 /*
4780 * Reconciliate the node namespace
4781 */
4782 if (node->ns != NULL) {
4783 /*
4784 * initialize the cache if needed
4785 */
4786 if (sizeCache == 0) {
4787 sizeCache = 10;
4788 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4789 sizeof(xmlNsPtr));
4790 if (oldNs == NULL) {
4791 xmlGenericError(xmlGenericErrorContext,
4792 "xmlReconciliateNs : memory pbm\n");
4793 return(-1);
4794 }
4795 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4796 sizeof(xmlNsPtr));
4797 if (newNs == NULL) {
4798 xmlGenericError(xmlGenericErrorContext,
4799 "xmlReconciliateNs : memory pbm\n");
4800 xmlFree(oldNs);
4801 return(-1);
4802 }
4803 }
4804 for (i = 0;i < nbCache;i++) {
4805 if (oldNs[i] == node->ns) {
4806 node->ns = newNs[i];
4807 break;
4808 }
4809 }
4810 if (i == nbCache) {
4811 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004812 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004813 */
4814 n = xmlNewReconciliedNs(doc, tree, node->ns);
4815 if (n != NULL) { /* :-( what if else ??? */
4816 /*
4817 * check if we need to grow the cache buffers.
4818 */
4819 if (sizeCache <= nbCache) {
4820 sizeCache *= 2;
4821 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4822 sizeof(xmlNsPtr));
4823 if (oldNs == NULL) {
4824 xmlGenericError(xmlGenericErrorContext,
4825 "xmlReconciliateNs : memory pbm\n");
4826 xmlFree(newNs);
4827 return(-1);
4828 }
4829 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4830 sizeof(xmlNsPtr));
4831 if (newNs == NULL) {
4832 xmlGenericError(xmlGenericErrorContext,
4833 "xmlReconciliateNs : memory pbm\n");
4834 xmlFree(oldNs);
4835 return(-1);
4836 }
4837 }
4838 newNs[nbCache] = n;
4839 oldNs[nbCache++] = node->ns;
4840 node->ns = n;
4841 }
4842 }
4843 }
4844 /*
4845 * now check for namespace hold by attributes on the node.
4846 */
4847 attr = node->properties;
4848 while (attr != NULL) {
4849 if (attr->ns != NULL) {
4850 /*
4851 * initialize the cache if needed
4852 */
4853 if (sizeCache == 0) {
4854 sizeCache = 10;
4855 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4856 sizeof(xmlNsPtr));
4857 if (oldNs == NULL) {
4858 xmlGenericError(xmlGenericErrorContext,
4859 "xmlReconciliateNs : memory pbm\n");
4860 return(-1);
4861 }
4862 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4863 sizeof(xmlNsPtr));
4864 if (newNs == NULL) {
4865 xmlGenericError(xmlGenericErrorContext,
4866 "xmlReconciliateNs : memory pbm\n");
4867 xmlFree(oldNs);
4868 return(-1);
4869 }
4870 }
4871 for (i = 0;i < nbCache;i++) {
4872 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00004873 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00004874 break;
4875 }
4876 }
4877 if (i == nbCache) {
4878 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004879 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004880 */
4881 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4882 if (n != NULL) { /* :-( what if else ??? */
4883 /*
4884 * check if we need to grow the cache buffers.
4885 */
4886 if (sizeCache <= nbCache) {
4887 sizeCache *= 2;
4888 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4889 sizeof(xmlNsPtr));
4890 if (oldNs == NULL) {
4891 xmlGenericError(xmlGenericErrorContext,
4892 "xmlReconciliateNs : memory pbm\n");
4893 xmlFree(newNs);
4894 return(-1);
4895 }
4896 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4897 sizeof(xmlNsPtr));
4898 if (newNs == NULL) {
4899 xmlGenericError(xmlGenericErrorContext,
4900 "xmlReconciliateNs : memory pbm\n");
4901 xmlFree(oldNs);
4902 return(-1);
4903 }
4904 }
4905 newNs[nbCache] = n;
4906 oldNs[nbCache++] = attr->ns;
4907 attr->ns = n;
4908 }
4909 }
4910 }
4911 attr = attr->next;
4912 }
4913
4914 /*
4915 * Browse the full subtree, deep first
4916 */
4917 if (node->children != NULL) {
4918 /* deep first */
4919 node = node->children;
4920 } else if ((node != tree) && (node->next != NULL)) {
4921 /* then siblings */
4922 node = node->next;
4923 } else if (node != tree) {
4924 /* go up to parents->next if needed */
4925 while (node != tree) {
4926 if (node->parent != NULL)
4927 node = node->parent;
4928 if ((node != tree) && (node->next != NULL)) {
4929 node = node->next;
4930 break;
4931 }
4932 if (node->parent == NULL) {
4933 node = NULL;
4934 break;
4935 }
4936 }
4937 /* exit condition */
4938 if (node == tree)
4939 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00004940 } else
4941 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004942 }
Daniel Veillardf742d342002-03-07 00:05:35 +00004943 if (oldNs != NULL)
4944 xmlFree(oldNs);
4945 if (newNs != NULL)
4946 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00004947 return(ret);
4948}
4949
4950/**
4951 * xmlHasProp:
4952 * @node: the node
4953 * @name: the attribute name
4954 *
4955 * Search an attribute associated to a node
4956 * This function also looks in DTD attribute declaration for #FIXED or
4957 * default declaration values unless DTD use has been turned off.
4958 *
4959 * Returns the attribute or the attribute declaration or NULL if
4960 * neither was found.
4961 */
4962xmlAttrPtr
4963xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4964 xmlAttrPtr prop;
4965 xmlDocPtr doc;
4966
4967 if ((node == NULL) || (name == NULL)) return(NULL);
4968 /*
4969 * Check on the properties attached to the node
4970 */
4971 prop = node->properties;
4972 while (prop != NULL) {
4973 if (xmlStrEqual(prop->name, name)) {
4974 return(prop);
4975 }
4976 prop = prop->next;
4977 }
4978 if (!xmlCheckDTD) return(NULL);
4979
4980 /*
4981 * Check if there is a default declaration in the internal
4982 * or external subsets
4983 */
4984 doc = node->doc;
4985 if (doc != NULL) {
4986 xmlAttributePtr attrDecl;
4987 if (doc->intSubset != NULL) {
4988 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4989 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4990 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4991 if (attrDecl != NULL)
4992 return((xmlAttrPtr) attrDecl);
4993 }
4994 }
4995 return(NULL);
4996}
4997
4998/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004999 * xmlHasNsProp:
5000 * @node: the node
5001 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005002 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005003 *
5004 * Search for an attribute associated to a node
5005 * This attribute has to be anchored in the namespace specified.
5006 * This does the entity substitution.
5007 * This function looks in DTD attribute declaration for #FIXED or
5008 * default declaration values unless DTD use has been turned off.
5009 *
5010 * Returns the attribute or the attribute declaration or NULL
5011 * if neither was found.
5012 */
5013xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005014xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005015 xmlAttrPtr prop;
5016 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005017
5018 if (node == NULL)
5019 return(NULL);
5020
5021 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005022 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005023 return(xmlHasProp(node, name));
5024 while (prop != NULL) {
5025 /*
5026 * One need to have
5027 * - same attribute names
5028 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005029 */
5030 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005031 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5032 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005033 }
5034 prop = prop->next;
5035 }
5036 if (!xmlCheckDTD) return(NULL);
5037
5038 /*
5039 * Check if there is a default declaration in the internal
5040 * or external subsets
5041 */
5042 doc = node->doc;
5043 if (doc != NULL) {
5044 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005045 xmlAttributePtr attrDecl = NULL;
5046 xmlNsPtr *nsList, *cur;
5047 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005048
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005049 nsList = xmlGetNsList(node->doc, node);
5050 if (nsList == NULL)
5051 return(NULL);
5052 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5053 ename = xmlStrdup(node->ns->prefix);
5054 ename = xmlStrcat(ename, BAD_CAST ":");
5055 ename = xmlStrcat(ename, node->name);
5056 } else {
5057 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005058 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005059 if (ename == NULL) {
5060 xmlFree(nsList);
5061 return(NULL);
5062 }
5063
5064 cur = nsList;
5065 while (*cur != NULL) {
5066 if (xmlStrEqual((*cur)->href, nameSpace)) {
5067 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5068 name, (*cur)->prefix);
5069 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5070 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5071 name, (*cur)->prefix);
5072 }
5073 cur++;
5074 }
5075 xmlFree(nsList);
5076 xmlFree(ename);
5077 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005078 }
5079 }
5080 return(NULL);
5081}
5082
5083/**
Owen Taylor3473f882001-02-23 17:55:21 +00005084 * xmlGetProp:
5085 * @node: the node
5086 * @name: the attribute name
5087 *
5088 * Search and get the value of an attribute associated to a node
5089 * This does the entity substitution.
5090 * This function looks in DTD attribute declaration for #FIXED or
5091 * default declaration values unless DTD use has been turned off.
5092 *
5093 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005094 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005095 */
5096xmlChar *
5097xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5098 xmlAttrPtr prop;
5099 xmlDocPtr doc;
5100
5101 if ((node == NULL) || (name == NULL)) return(NULL);
5102 /*
5103 * Check on the properties attached to the node
5104 */
5105 prop = node->properties;
5106 while (prop != NULL) {
5107 if (xmlStrEqual(prop->name, name)) {
5108 xmlChar *ret;
5109
5110 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5111 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5112 return(ret);
5113 }
5114 prop = prop->next;
5115 }
5116 if (!xmlCheckDTD) return(NULL);
5117
5118 /*
5119 * Check if there is a default declaration in the internal
5120 * or external subsets
5121 */
5122 doc = node->doc;
5123 if (doc != NULL) {
5124 xmlAttributePtr attrDecl;
5125 if (doc->intSubset != NULL) {
5126 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5127 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5128 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5129 if (attrDecl != NULL)
5130 return(xmlStrdup(attrDecl->defaultValue));
5131 }
5132 }
5133 return(NULL);
5134}
5135
5136/**
5137 * xmlGetNsProp:
5138 * @node: the node
5139 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005140 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005141 *
5142 * Search and get the value of an attribute associated to a node
5143 * This attribute has to be anchored in the namespace specified.
5144 * This does the entity substitution.
5145 * This function looks in DTD attribute declaration for #FIXED or
5146 * default declaration values unless DTD use has been turned off.
5147 *
5148 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005149 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005150 */
5151xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005152xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005153 xmlAttrPtr prop;
5154 xmlDocPtr doc;
5155 xmlNsPtr ns;
5156
5157 if (node == NULL)
5158 return(NULL);
5159
5160 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005161 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005162 return(xmlGetProp(node, name));
5163 while (prop != NULL) {
5164 /*
5165 * One need to have
5166 * - same attribute names
5167 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005168 */
5169 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005170 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005171 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005172 xmlChar *ret;
5173
5174 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5175 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5176 return(ret);
5177 }
5178 prop = prop->next;
5179 }
5180 if (!xmlCheckDTD) return(NULL);
5181
5182 /*
5183 * Check if there is a default declaration in the internal
5184 * or external subsets
5185 */
5186 doc = node->doc;
5187 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005188 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005189 xmlAttributePtr attrDecl;
5190
Owen Taylor3473f882001-02-23 17:55:21 +00005191 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5192 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5193 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5194
5195 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5196 /*
5197 * The DTD declaration only allows a prefix search
5198 */
5199 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005200 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005201 return(xmlStrdup(attrDecl->defaultValue));
5202 }
5203 }
5204 }
5205 return(NULL);
5206}
5207
5208/**
5209 * xmlSetProp:
5210 * @node: the node
5211 * @name: the attribute name
5212 * @value: the attribute value
5213 *
5214 * Set (or reset) an attribute carried by a node.
5215 * Returns the attribute pointer.
5216 */
5217xmlAttrPtr
5218xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005219 xmlAttrPtr prop;
5220 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005221
5222 if ((node == NULL) || (name == NULL))
5223 return(NULL);
5224 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005225 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005226 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005227 if ((xmlStrEqual(prop->name, name)) &&
5228 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005229 xmlNodePtr oldprop = prop->children;
5230
Owen Taylor3473f882001-02-23 17:55:21 +00005231 prop->children = NULL;
5232 prop->last = NULL;
5233 if (value != NULL) {
5234 xmlChar *buffer;
5235 xmlNodePtr tmp;
5236
5237 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5238 prop->children = xmlStringGetNodeList(node->doc, buffer);
5239 prop->last = NULL;
5240 prop->doc = doc;
5241 tmp = prop->children;
5242 while (tmp != NULL) {
5243 tmp->parent = (xmlNodePtr) prop;
5244 tmp->doc = doc;
5245 if (tmp->next == NULL)
5246 prop->last = tmp;
5247 tmp = tmp->next;
5248 }
5249 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005250 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005251 if (oldprop != NULL)
5252 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005253 return(prop);
5254 }
5255 prop = prop->next;
5256 }
5257 prop = xmlNewProp(node, name, value);
5258 return(prop);
5259}
5260
5261/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005262 * xmlUnsetProp:
5263 * @node: the node
5264 * @name: the attribute name
5265 *
5266 * Remove an attribute carried by a node.
5267 * Returns 0 if successful, -1 if not found
5268 */
5269int
5270xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
5271 xmlAttrPtr prop = node->properties, prev = NULL;;
5272
5273 if ((node == NULL) || (name == NULL))
5274 return(-1);
5275 while (prop != NULL) {
5276 if ((xmlStrEqual(prop->name, name)) &&
5277 (prop->ns == NULL)) {
5278 if (prev == NULL)
5279 node->properties = prop->next;
5280 else
5281 prev->next = prop->next;
5282 xmlFreeProp(prop);
5283 return(0);
5284 }
5285 prev = prop;
5286 prop = prop->next;
5287 }
5288 return(-1);
5289}
5290
5291/**
Owen Taylor3473f882001-02-23 17:55:21 +00005292 * xmlSetNsProp:
5293 * @node: the node
5294 * @ns: the namespace definition
5295 * @name: the attribute name
5296 * @value: the attribute value
5297 *
5298 * Set (or reset) an attribute carried by a node.
5299 * The ns structure must be in scope, this is not checked.
5300 *
5301 * Returns the attribute pointer.
5302 */
5303xmlAttrPtr
5304xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5305 const xmlChar *value) {
5306 xmlAttrPtr prop;
5307
5308 if ((node == NULL) || (name == NULL))
5309 return(NULL);
5310
5311 if (ns == NULL)
5312 return(xmlSetProp(node, name, value));
5313 if (ns->href == NULL)
5314 return(NULL);
5315 prop = node->properties;
5316
5317 while (prop != NULL) {
5318 /*
5319 * One need to have
5320 * - same attribute names
5321 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005322 */
5323 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00005324 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005325 if (prop->children != NULL)
5326 xmlFreeNodeList(prop->children);
5327 prop->children = NULL;
5328 prop->last = NULL;
5329 prop->ns = ns;
5330 if (value != NULL) {
5331 xmlChar *buffer;
5332 xmlNodePtr tmp;
5333
5334 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5335 prop->children = xmlStringGetNodeList(node->doc, buffer);
5336 prop->last = NULL;
5337 tmp = prop->children;
5338 while (tmp != NULL) {
5339 tmp->parent = (xmlNodePtr) prop;
5340 if (tmp->next == NULL)
5341 prop->last = tmp;
5342 tmp = tmp->next;
5343 }
5344 xmlFree(buffer);
5345 }
5346 return(prop);
5347 }
5348 prop = prop->next;
5349 }
5350 prop = xmlNewNsProp(node, ns, name, value);
5351 return(prop);
5352}
5353
5354/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005355 * xmlUnsetNsProp:
5356 * @node: the node
5357 * @ns: the namespace definition
5358 * @name: the attribute name
5359 *
5360 * Remove an attribute carried by a node.
5361 * Returns 0 if successful, -1 if not found
5362 */
5363int
5364xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5365 xmlAttrPtr prop = node->properties, prev = NULL;;
5366
5367 if ((node == NULL) || (name == NULL))
5368 return(-1);
5369 if (ns == NULL)
5370 return(xmlUnsetProp(node, name));
5371 if (ns->href == NULL)
5372 return(-1);
5373 while (prop != NULL) {
5374 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00005375 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005376 if (prev == NULL)
5377 node->properties = prop->next;
5378 else
5379 prev->next = prop->next;
5380 xmlFreeProp(prop);
5381 return(0);
5382 }
5383 prev = prop;
5384 prop = prop->next;
5385 }
5386 return(-1);
5387}
5388
5389/**
Owen Taylor3473f882001-02-23 17:55:21 +00005390 * xmlNodeIsText:
5391 * @node: the node
5392 *
5393 * Is this node a Text node ?
5394 * Returns 1 yes, 0 no
5395 */
5396int
5397xmlNodeIsText(xmlNodePtr node) {
5398 if (node == NULL) return(0);
5399
5400 if (node->type == XML_TEXT_NODE) return(1);
5401 return(0);
5402}
5403
5404/**
5405 * xmlIsBlankNode:
5406 * @node: the node
5407 *
5408 * Checks whether this node is an empty or whitespace only
5409 * (and possibly ignorable) text-node.
5410 *
5411 * Returns 1 yes, 0 no
5412 */
5413int
5414xmlIsBlankNode(xmlNodePtr node) {
5415 const xmlChar *cur;
5416 if (node == NULL) return(0);
5417
Daniel Veillard7db37732001-07-12 01:20:08 +00005418 if ((node->type != XML_TEXT_NODE) &&
5419 (node->type != XML_CDATA_SECTION_NODE))
5420 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005421 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005422 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005423 while (*cur != 0) {
5424 if (!IS_BLANK(*cur)) return(0);
5425 cur++;
5426 }
5427
5428 return(1);
5429}
5430
5431/**
5432 * xmlTextConcat:
5433 * @node: the node
5434 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005435 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005436 *
5437 * Concat the given string at the end of the existing node content
5438 */
5439
5440void
5441xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5442 if (node == NULL) return;
5443
5444 if ((node->type != XML_TEXT_NODE) &&
5445 (node->type != XML_CDATA_SECTION_NODE)) {
5446#ifdef DEBUG_TREE
5447 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005448 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005449#endif
5450 return;
5451 }
Owen Taylor3473f882001-02-23 17:55:21 +00005452 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005453}
5454
5455/************************************************************************
5456 * *
5457 * Output : to a FILE or in memory *
5458 * *
5459 ************************************************************************/
5460
Owen Taylor3473f882001-02-23 17:55:21 +00005461/**
5462 * xmlBufferCreate:
5463 *
5464 * routine to create an XML buffer.
5465 * returns the new structure.
5466 */
5467xmlBufferPtr
5468xmlBufferCreate(void) {
5469 xmlBufferPtr ret;
5470
5471 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5472 if (ret == NULL) {
5473 xmlGenericError(xmlGenericErrorContext,
5474 "xmlBufferCreate : out of memory!\n");
5475 return(NULL);
5476 }
5477 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005478 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005479 ret->alloc = xmlBufferAllocScheme;
5480 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5481 if (ret->content == NULL) {
5482 xmlGenericError(xmlGenericErrorContext,
5483 "xmlBufferCreate : out of memory!\n");
5484 xmlFree(ret);
5485 return(NULL);
5486 }
5487 ret->content[0] = 0;
5488 return(ret);
5489}
5490
5491/**
5492 * xmlBufferCreateSize:
5493 * @size: initial size of buffer
5494 *
5495 * routine to create an XML buffer.
5496 * returns the new structure.
5497 */
5498xmlBufferPtr
5499xmlBufferCreateSize(size_t size) {
5500 xmlBufferPtr ret;
5501
5502 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5503 if (ret == NULL) {
5504 xmlGenericError(xmlGenericErrorContext,
5505 "xmlBufferCreate : out of memory!\n");
5506 return(NULL);
5507 }
5508 ret->use = 0;
5509 ret->alloc = xmlBufferAllocScheme;
5510 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5511 if (ret->size){
5512 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5513 if (ret->content == NULL) {
5514 xmlGenericError(xmlGenericErrorContext,
5515 "xmlBufferCreate : out of memory!\n");
5516 xmlFree(ret);
5517 return(NULL);
5518 }
5519 ret->content[0] = 0;
5520 } else
5521 ret->content = NULL;
5522 return(ret);
5523}
5524
5525/**
5526 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005527 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00005528 * @scheme: allocation scheme to use
5529 *
5530 * Sets the allocation scheme for this buffer
5531 */
5532void
5533xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5534 xmlBufferAllocationScheme scheme) {
5535 if (buf == NULL) {
5536#ifdef DEBUG_BUFFER
5537 xmlGenericError(xmlGenericErrorContext,
5538 "xmlBufferSetAllocationScheme: buf == NULL\n");
5539#endif
5540 return;
5541 }
5542
5543 buf->alloc = scheme;
5544}
5545
5546/**
5547 * xmlBufferFree:
5548 * @buf: the buffer to free
5549 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005550 * Frees an XML buffer. It frees both the content and the structure which
5551 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005552 */
5553void
5554xmlBufferFree(xmlBufferPtr buf) {
5555 if (buf == NULL) {
5556#ifdef DEBUG_BUFFER
5557 xmlGenericError(xmlGenericErrorContext,
5558 "xmlBufferFree: buf == NULL\n");
5559#endif
5560 return;
5561 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00005562 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005563 xmlFree(buf->content);
5564 }
Owen Taylor3473f882001-02-23 17:55:21 +00005565 xmlFree(buf);
5566}
5567
5568/**
5569 * xmlBufferEmpty:
5570 * @buf: the buffer
5571 *
5572 * empty a buffer.
5573 */
5574void
5575xmlBufferEmpty(xmlBufferPtr buf) {
5576 if (buf->content == NULL) return;
5577 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005578 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005579}
5580
5581/**
5582 * xmlBufferShrink:
5583 * @buf: the buffer to dump
5584 * @len: the number of xmlChar to remove
5585 *
5586 * Remove the beginning of an XML buffer.
5587 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005588 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005589 */
5590int
5591xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5592 if (len == 0) return(0);
5593 if (len > buf->use) return(-1);
5594
5595 buf->use -= len;
5596 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5597
5598 buf->content[buf->use] = 0;
5599 return(len);
5600}
5601
5602/**
5603 * xmlBufferGrow:
5604 * @buf: the buffer
5605 * @len: the minimum free size to allocate
5606 *
5607 * Grow the available space of an XML buffer.
5608 *
5609 * Returns the new available space or -1 in case of error
5610 */
5611int
5612xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5613 int size;
5614 xmlChar *newbuf;
5615
5616 if (len + buf->use < buf->size) return(0);
5617
5618 size = buf->use + len + 100;
5619
5620 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5621 if (newbuf == NULL) return(-1);
5622 buf->content = newbuf;
5623 buf->size = size;
5624 return(buf->size - buf->use);
5625}
5626
5627/**
5628 * xmlBufferDump:
5629 * @file: the file output
5630 * @buf: the buffer to dump
5631 *
5632 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005633 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005634 */
5635int
5636xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5637 int ret;
5638
5639 if (buf == NULL) {
5640#ifdef DEBUG_BUFFER
5641 xmlGenericError(xmlGenericErrorContext,
5642 "xmlBufferDump: buf == NULL\n");
5643#endif
5644 return(0);
5645 }
5646 if (buf->content == NULL) {
5647#ifdef DEBUG_BUFFER
5648 xmlGenericError(xmlGenericErrorContext,
5649 "xmlBufferDump: buf->content == NULL\n");
5650#endif
5651 return(0);
5652 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005653 if (file == NULL)
5654 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005655 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5656 return(ret);
5657}
5658
5659/**
5660 * xmlBufferContent:
5661 * @buf: the buffer
5662 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005663 * Function to extract the content of a buffer
5664 *
Owen Taylor3473f882001-02-23 17:55:21 +00005665 * Returns the internal content
5666 */
5667
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005668const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005669xmlBufferContent(const xmlBufferPtr buf)
5670{
5671 if(!buf)
5672 return NULL;
5673
5674 return buf->content;
5675}
5676
5677/**
5678 * xmlBufferLength:
5679 * @buf: the buffer
5680 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005681 * Function to get the length of a buffer
5682 *
Owen Taylor3473f882001-02-23 17:55:21 +00005683 * Returns the length of data in the internal content
5684 */
5685
5686int
5687xmlBufferLength(const xmlBufferPtr buf)
5688{
5689 if(!buf)
5690 return 0;
5691
5692 return buf->use;
5693}
5694
5695/**
5696 * xmlBufferResize:
5697 * @buf: the buffer to resize
5698 * @size: the desired size
5699 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005700 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005701 *
5702 * Returns 0 in case of problems, 1 otherwise
5703 */
5704int
5705xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5706{
5707 unsigned int newSize;
5708 xmlChar* rebuf = NULL;
5709
5710 /*take care of empty case*/
5711 newSize = (buf->size ? buf->size*2 : size);
5712
5713 /* Don't resize if we don't have to */
5714 if (size < buf->size)
5715 return 1;
5716
5717 /* figure out new size */
5718 switch (buf->alloc){
5719 case XML_BUFFER_ALLOC_DOUBLEIT:
5720 while (size > newSize) newSize *= 2;
5721 break;
5722 case XML_BUFFER_ALLOC_EXACT:
5723 newSize = size+10;
5724 break;
5725 default:
5726 newSize = size+10;
5727 break;
5728 }
5729
5730 if (buf->content == NULL)
5731 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5732 else
5733 rebuf = (xmlChar *) xmlRealloc(buf->content,
5734 newSize * sizeof(xmlChar));
5735 if (rebuf == NULL) {
5736 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005737 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005738 return 0;
5739 }
5740 buf->content = rebuf;
5741 buf->size = newSize;
5742
5743 return 1;
5744}
5745
5746/**
5747 * xmlBufferAdd:
5748 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005749 * @str: the #xmlChar string
5750 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005751 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005752 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005753 * str is recomputed.
5754 */
5755void
5756xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5757 unsigned int needSize;
5758
5759 if (str == NULL) {
5760#ifdef DEBUG_BUFFER
5761 xmlGenericError(xmlGenericErrorContext,
5762 "xmlBufferAdd: str == NULL\n");
5763#endif
5764 return;
5765 }
5766 if (len < -1) {
5767#ifdef DEBUG_BUFFER
5768 xmlGenericError(xmlGenericErrorContext,
5769 "xmlBufferAdd: len < 0\n");
5770#endif
5771 return;
5772 }
5773 if (len == 0) return;
5774
5775 if (len < 0)
5776 len = xmlStrlen(str);
5777
5778 if (len <= 0) return;
5779
5780 needSize = buf->use + len + 2;
5781 if (needSize > buf->size){
5782 if (!xmlBufferResize(buf, needSize)){
5783 xmlGenericError(xmlGenericErrorContext,
5784 "xmlBufferAdd : out of memory!\n");
5785 return;
5786 }
5787 }
5788
5789 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5790 buf->use += len;
5791 buf->content[buf->use] = 0;
5792}
5793
5794/**
5795 * xmlBufferAddHead:
5796 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005797 * @str: the #xmlChar string
5798 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005799 *
5800 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005801 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005802 */
5803void
5804xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5805 unsigned int needSize;
5806
5807 if (str == NULL) {
5808#ifdef DEBUG_BUFFER
5809 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005810 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005811#endif
5812 return;
5813 }
5814 if (len < -1) {
5815#ifdef DEBUG_BUFFER
5816 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005817 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005818#endif
5819 return;
5820 }
5821 if (len == 0) return;
5822
5823 if (len < 0)
5824 len = xmlStrlen(str);
5825
5826 if (len <= 0) return;
5827
5828 needSize = buf->use + len + 2;
5829 if (needSize > buf->size){
5830 if (!xmlBufferResize(buf, needSize)){
5831 xmlGenericError(xmlGenericErrorContext,
5832 "xmlBufferAddHead : out of memory!\n");
5833 return;
5834 }
5835 }
5836
5837 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5838 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5839 buf->use += len;
5840 buf->content[buf->use] = 0;
5841}
5842
5843/**
5844 * xmlBufferCat:
5845 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005846 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005847 *
5848 * Append a zero terminated string to an XML buffer.
5849 */
5850void
5851xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5852 if (str != NULL)
5853 xmlBufferAdd(buf, str, -1);
5854}
5855
5856/**
5857 * xmlBufferCCat:
5858 * @buf: the buffer to dump
5859 * @str: the C char string
5860 *
5861 * Append a zero terminated C string to an XML buffer.
5862 */
5863void
5864xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5865 const char *cur;
5866
5867 if (str == NULL) {
5868#ifdef DEBUG_BUFFER
5869 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005870 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005871#endif
5872 return;
5873 }
5874 for (cur = str;*cur != 0;cur++) {
5875 if (buf->use + 10 >= buf->size) {
5876 if (!xmlBufferResize(buf, buf->use+10)){
5877 xmlGenericError(xmlGenericErrorContext,
5878 "xmlBufferCCat : out of memory!\n");
5879 return;
5880 }
5881 }
5882 buf->content[buf->use++] = *cur;
5883 }
5884 buf->content[buf->use] = 0;
5885}
5886
5887/**
5888 * xmlBufferWriteCHAR:
5889 * @buf: the XML buffer
5890 * @string: the string to add
5891 *
5892 * routine which manages and grows an output buffer. This one adds
5893 * xmlChars at the end of the buffer.
5894 */
5895void
Owen Taylor3473f882001-02-23 17:55:21 +00005896xmlBufferWriteCHAR
Owen Taylor3473f882001-02-23 17:55:21 +00005897(xmlBufferPtr buf, const xmlChar *string) {
5898 xmlBufferCat(buf, string);
5899}
5900
5901/**
5902 * xmlBufferWriteChar:
5903 * @buf: the XML buffer output
5904 * @string: the string to add
5905 *
5906 * routine which manage and grows an output buffer. This one add
5907 * C chars at the end of the array.
5908 */
5909void
5910xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5911 xmlBufferCCat(buf, string);
5912}
5913
5914
5915/**
5916 * xmlBufferWriteQuotedString:
5917 * @buf: the XML buffer output
5918 * @string: the string to add
5919 *
5920 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005921 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005922 * quote or double-quotes internally
5923 */
5924void
5925xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5926 if (xmlStrchr(string, '"')) {
5927 if (xmlStrchr(string, '\'')) {
5928#ifdef DEBUG_BUFFER
5929 xmlGenericError(xmlGenericErrorContext,
5930 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5931#endif
5932 }
5933 xmlBufferCCat(buf, "'");
5934 xmlBufferCat(buf, string);
5935 xmlBufferCCat(buf, "'");
5936 } else {
5937 xmlBufferCCat(buf, "\"");
5938 xmlBufferCat(buf, string);
5939 xmlBufferCCat(buf, "\"");
5940 }
5941}
5942
5943
5944/************************************************************************
5945 * *
5946 * Dumping XML tree content to a simple buffer *
5947 * *
5948 ************************************************************************/
5949
Owen Taylor3473f882001-02-23 17:55:21 +00005950static void
5951xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5952 int format);
5953void
5954htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5955
5956/**
5957 * xmlNsDump:
5958 * @buf: the XML buffer output
5959 * @cur: a namespace
5960 *
5961 * Dump a local Namespace definition.
5962 * Should be called in the context of attributes dumps.
5963 */
5964static void
5965xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5966 if (cur == NULL) {
5967#ifdef DEBUG_TREE
5968 xmlGenericError(xmlGenericErrorContext,
5969 "xmlNsDump : Ns == NULL\n");
5970#endif
5971 return;
5972 }
5973 if (cur->type == XML_LOCAL_NAMESPACE) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005974 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
5975 return;
5976
Owen Taylor3473f882001-02-23 17:55:21 +00005977 /* Within the context of an element attributes */
5978 if (cur->prefix != NULL) {
5979 xmlBufferWriteChar(buf, " xmlns:");
5980 xmlBufferWriteCHAR(buf, cur->prefix);
5981 } else
5982 xmlBufferWriteChar(buf, " xmlns");
5983 xmlBufferWriteChar(buf, "=");
5984 xmlBufferWriteQuotedString(buf, cur->href);
5985 }
5986}
5987
5988/**
5989 * xmlNsListDump:
5990 * @buf: the XML buffer output
5991 * @cur: the first namespace
5992 *
5993 * Dump a list of local Namespace definitions.
5994 * Should be called in the context of attributes dumps.
5995 */
5996static void
5997xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5998 while (cur != NULL) {
5999 xmlNsDump(buf, cur);
6000 cur = cur->next;
6001 }
6002}
6003
6004/**
6005 * xmlDtdDump:
6006 * @buf: the XML buffer output
Daniel Veillardd1640922001-12-17 15:30:10 +00006007 * @dtd: the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00006008 *
6009 * Dump the XML document DTD, if any.
6010 */
6011static void
6012xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
6013 if (dtd == NULL) {
6014#ifdef DEBUG_TREE
6015 xmlGenericError(xmlGenericErrorContext,
6016 "xmlDtdDump : no internal subset\n");
6017#endif
6018 return;
6019 }
6020 xmlBufferWriteChar(buf, "<!DOCTYPE ");
6021 xmlBufferWriteCHAR(buf, dtd->name);
6022 if (dtd->ExternalID != NULL) {
6023 xmlBufferWriteChar(buf, " PUBLIC ");
6024 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
6025 xmlBufferWriteChar(buf, " ");
6026 xmlBufferWriteQuotedString(buf, dtd->SystemID);
6027 } else if (dtd->SystemID != NULL) {
6028 xmlBufferWriteChar(buf, " SYSTEM ");
6029 xmlBufferWriteQuotedString(buf, dtd->SystemID);
6030 }
6031 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6032 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6033 xmlBufferWriteChar(buf, ">");
6034 return;
6035 }
6036 xmlBufferWriteChar(buf, " [\n");
6037 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
6038#if 0
6039 if (dtd->entities != NULL)
6040 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
6041 if (dtd->notations != NULL)
6042 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
6043 if (dtd->elements != NULL)
6044 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
6045 if (dtd->attributes != NULL)
6046 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
6047#endif
6048 xmlBufferWriteChar(buf, "]>");
6049}
6050
6051/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00006052 * xmlAttrSerializeContent:
6053 * @buf: the XML buffer output
6054 * @doc: the document
6055 * @attr: the attribute pointer
6056 *
6057 * Serialize the attribute in the buffer
6058 */
6059static void
6060xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr) {
6061 const xmlChar *cur, *base;
6062 xmlNodePtr children;
6063
6064 children = attr->children;
6065 while (children != NULL) {
6066 switch (children->type) {
6067 case XML_TEXT_NODE:
6068 base = cur = children->content;
6069 while (*cur != 0) {
6070 if (*cur == '\n') {
6071 if (base != cur)
6072 xmlBufferAdd(buf, base, cur - base);
6073 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
6074 cur++;
6075 base = cur;
6076#if 0
6077 } else if (*cur == '\'') {
6078 if (base != cur)
6079 xmlBufferAdd(buf, base, cur - base);
6080 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
6081 cur++;
6082 base = cur;
6083#endif
6084 } else if (*cur == '"') {
6085 if (base != cur)
6086 xmlBufferAdd(buf, base, cur - base);
6087 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6088 cur++;
6089 base = cur;
6090 } else if (*cur == '<') {
6091 if (base != cur)
6092 xmlBufferAdd(buf, base, cur - base);
6093 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6094 cur++;
6095 base = cur;
6096 } else if (*cur == '>') {
6097 if (base != cur)
6098 xmlBufferAdd(buf, base, cur - base);
6099 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6100 cur++;
6101 base = cur;
6102 } else if (*cur == '&') {
6103 if (base != cur)
6104 xmlBufferAdd(buf, base, cur - base);
6105 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6106 cur++;
6107 base = cur;
6108 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6109 (doc->encoding == NULL))) {
6110 /*
6111 * We assume we have UTF-8 content.
6112 */
6113 char tmp[10];
6114 int val = 0, l = 1;
6115
6116 if (base != cur)
6117 xmlBufferAdd(buf, base, cur - base);
6118 if (*cur < 0xC0) {
6119 xmlGenericError(xmlGenericErrorContext,
6120 "xmlAttrSerializeContent : input not UTF-8\n");
6121 if (doc != NULL)
6122 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
6123 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6124 tmp[sizeof(tmp) - 1] = 0;
6125 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6126 cur++;
6127 base = cur;
6128 continue;
6129 } else if (*cur < 0xE0) {
6130 val = (cur[0]) & 0x1F;
6131 val <<= 6;
6132 val |= (cur[1]) & 0x3F;
6133 l = 2;
6134 } else if (*cur < 0xF0) {
6135 val = (cur[0]) & 0x0F;
6136 val <<= 6;
6137 val |= (cur[1]) & 0x3F;
6138 val <<= 6;
6139 val |= (cur[2]) & 0x3F;
6140 l = 3;
6141 } else if (*cur < 0xF8) {
6142 val = (cur[0]) & 0x07;
6143 val <<= 6;
6144 val |= (cur[1]) & 0x3F;
6145 val <<= 6;
6146 val |= (cur[2]) & 0x3F;
6147 val <<= 6;
6148 val |= (cur[3]) & 0x3F;
6149 l = 4;
6150 }
6151 if ((l == 1) || (!IS_CHAR(val))) {
6152 xmlGenericError(xmlGenericErrorContext,
6153 "xmlAttrSerializeContent : char out of range\n");
6154 if (doc != NULL)
6155 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
6156 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6157 tmp[sizeof(tmp) - 1] = 0;
6158 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6159 cur++;
6160 base = cur;
6161 continue;
6162 }
6163 /*
6164 * We could do multiple things here. Just save
6165 * as a char ref
6166 */
6167 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6168 tmp[sizeof(tmp) - 1] = 0;
6169 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6170 cur += l;
6171 base = cur;
6172 } else {
6173 cur++;
6174 }
6175 }
6176 if (base != cur)
6177 xmlBufferAdd(buf, base, cur - base);
6178 break;
6179 case XML_ENTITY_REF_NODE:
6180 xmlBufferAdd(buf, BAD_CAST "&", 1);
6181 xmlBufferAdd(buf, children->name, xmlStrlen(children->name));
6182 xmlBufferAdd(buf, BAD_CAST ";", 1);
6183 break;
6184 default:
6185 /* should not happen unless we have a badly built tree */
6186 break;
6187 }
6188 children = children->next;
6189 }
6190}
6191
6192/**
Owen Taylor3473f882001-02-23 17:55:21 +00006193 * xmlAttrDump:
6194 * @buf: the XML buffer output
6195 * @doc: the document
6196 * @cur: the attribute pointer
6197 *
6198 * Dump an XML attribute
6199 */
6200static void
6201xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00006202 if (cur == NULL) {
6203#ifdef DEBUG_TREE
6204 xmlGenericError(xmlGenericErrorContext,
6205 "xmlAttrDump : property == NULL\n");
6206#endif
6207 return;
6208 }
6209 xmlBufferWriteChar(buf, " ");
6210 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6211 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6212 xmlBufferWriteChar(buf, ":");
6213 }
6214 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006215 xmlBufferWriteChar(buf, "=\"");
6216 xmlAttrSerializeContent(buf, doc, cur);
6217 xmlBufferWriteChar(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006218}
6219
6220/**
6221 * xmlAttrListDump:
6222 * @buf: the XML buffer output
6223 * @doc: the document
6224 * @cur: the first attribute pointer
6225 *
6226 * Dump a list of XML attributes
6227 */
6228static void
6229xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
6230 if (cur == NULL) {
6231#ifdef DEBUG_TREE
6232 xmlGenericError(xmlGenericErrorContext,
6233 "xmlAttrListDump : property == NULL\n");
6234#endif
6235 return;
6236 }
6237 while (cur != NULL) {
6238 xmlAttrDump(buf, doc, cur);
6239 cur = cur->next;
6240 }
6241}
6242
6243
6244
6245/**
6246 * xmlNodeListDump:
6247 * @buf: the XML buffer output
6248 * @doc: the document
6249 * @cur: the first node
6250 * @level: the imbrication level for indenting
6251 * @format: is formatting allowed
6252 *
6253 * Dump an XML node list, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006254 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6255 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006256 */
6257static void
6258xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
6259 int format) {
6260 int i;
6261
6262 if (cur == NULL) {
6263#ifdef DEBUG_TREE
6264 xmlGenericError(xmlGenericErrorContext,
6265 "xmlNodeListDump : node == NULL\n");
6266#endif
6267 return;
6268 }
6269 while (cur != NULL) {
6270 if ((format) && (xmlIndentTreeOutput) &&
6271 (cur->type == XML_ELEMENT_NODE))
6272 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006273 xmlBufferWriteChar(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006274 xmlNodeDump(buf, doc, cur, level, format);
6275 if (format) {
6276 xmlBufferWriteChar(buf, "\n");
6277 }
6278 cur = cur->next;
6279 }
6280}
6281
6282/**
6283 * xmlNodeDump:
6284 * @buf: the XML buffer output
6285 * @doc: the document
6286 * @cur: the current node
6287 * @level: the imbrication level for indenting
6288 * @format: is formatting allowed
6289 *
6290 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006291 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6292 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006293 */
6294void
6295xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
6296 int format) {
6297 int i;
6298 xmlNodePtr tmp;
6299
6300 if (cur == NULL) {
6301#ifdef DEBUG_TREE
6302 xmlGenericError(xmlGenericErrorContext,
6303 "xmlNodeDump : node == NULL\n");
6304#endif
6305 return;
6306 }
6307 if (cur->type == XML_XINCLUDE_START)
6308 return;
6309 if (cur->type == XML_XINCLUDE_END)
6310 return;
6311 if (cur->type == XML_DTD_NODE) {
6312 xmlDtdDump(buf, (xmlDtdPtr) cur);
6313 return;
6314 }
6315 if (cur->type == XML_ELEMENT_DECL) {
6316 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
6317 return;
6318 }
Daniel Veillard78d12092001-10-11 09:12:24 +00006319 if (cur->type == XML_ATTRIBUTE_NODE){
6320 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
6321 return;
6322 }
Owen Taylor3473f882001-02-23 17:55:21 +00006323 if (cur->type == XML_ATTRIBUTE_DECL) {
6324 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
6325 return;
6326 }
6327 if (cur->type == XML_ENTITY_DECL) {
6328 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
6329 return;
6330 }
6331 if (cur->type == XML_TEXT_NODE) {
6332 if (cur->content != NULL) {
6333 if ((cur->name == xmlStringText) ||
6334 (cur->name != xmlStringTextNoenc)) {
6335 xmlChar *buffer;
6336
Owen Taylor3473f882001-02-23 17:55:21 +00006337 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006338 if (buffer != NULL) {
6339 xmlBufferWriteCHAR(buf, buffer);
6340 xmlFree(buffer);
6341 }
6342 } else {
6343 /*
6344 * Disable escaping, needed for XSLT
6345 */
Owen Taylor3473f882001-02-23 17:55:21 +00006346 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006347 }
6348 }
6349 return;
6350 }
6351 if (cur->type == XML_PI_NODE) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00006352 xmlBufferWriteChar(buf, "<?");
6353 xmlBufferWriteCHAR(buf, cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006354 if (cur->content != NULL) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00006355 xmlBufferWriteChar(buf, " ");
Daniel Veillard2c748c62002-01-16 15:37:50 +00006356 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006357 }
Daniel Veillard2c748c62002-01-16 15:37:50 +00006358 xmlBufferWriteChar(buf, "?>");
Owen Taylor3473f882001-02-23 17:55:21 +00006359 return;
6360 }
6361 if (cur->type == XML_COMMENT_NODE) {
6362 if (cur->content != NULL) {
6363 xmlBufferWriteChar(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006364 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006365 xmlBufferWriteChar(buf, "-->");
6366 }
6367 return;
6368 }
6369 if (cur->type == XML_ENTITY_REF_NODE) {
6370 xmlBufferWriteChar(buf, "&");
6371 xmlBufferWriteCHAR(buf, cur->name);
6372 xmlBufferWriteChar(buf, ";");
6373 return;
6374 }
6375 if (cur->type == XML_CDATA_SECTION_NODE) {
6376 xmlBufferWriteChar(buf, "<![CDATA[");
6377 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006378 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006379 xmlBufferWriteChar(buf, "]]>");
6380 return;
6381 }
6382
6383 if (format == 1) {
6384 tmp = cur->children;
6385 while (tmp != NULL) {
6386 if ((tmp->type == XML_TEXT_NODE) ||
6387 (tmp->type == XML_ENTITY_REF_NODE)) {
6388 format = 0;
6389 break;
6390 }
6391 tmp = tmp->next;
6392 }
6393 }
6394 xmlBufferWriteChar(buf, "<");
6395 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6396 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6397 xmlBufferWriteChar(buf, ":");
6398 }
6399
6400 xmlBufferWriteCHAR(buf, cur->name);
6401 if (cur->nsDef)
6402 xmlNsListDump(buf, cur->nsDef);
6403 if (cur->properties != NULL)
6404 xmlAttrListDump(buf, doc, cur->properties);
6405
Daniel Veillard7db37732001-07-12 01:20:08 +00006406 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6407 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00006408 (!xmlSaveNoEmptyTags)) {
6409 xmlBufferWriteChar(buf, "/>");
6410 return;
6411 }
6412 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006413 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006414 xmlChar *buffer;
6415
Owen Taylor3473f882001-02-23 17:55:21 +00006416 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006417 if (buffer != NULL) {
6418 xmlBufferWriteCHAR(buf, buffer);
6419 xmlFree(buffer);
6420 }
6421 }
6422 if (cur->children != NULL) {
6423 if (format) xmlBufferWriteChar(buf, "\n");
6424 xmlNodeListDump(buf, doc, cur->children,
6425 (level >= 0?level+1:-1), format);
6426 if ((xmlIndentTreeOutput) && (format))
6427 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006428 xmlBufferWriteChar(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006429 }
6430 xmlBufferWriteChar(buf, "</");
6431 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6432 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6433 xmlBufferWriteChar(buf, ":");
6434 }
6435
6436 xmlBufferWriteCHAR(buf, cur->name);
6437 xmlBufferWriteChar(buf, ">");
6438}
6439
6440/**
6441 * xmlElemDump:
6442 * @f: the FILE * for the output
6443 * @doc: the document
6444 * @cur: the current node
6445 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006446 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006447 */
6448void
6449xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
6450 xmlBufferPtr buf;
6451
6452 if (cur == NULL) {
6453#ifdef DEBUG_TREE
6454 xmlGenericError(xmlGenericErrorContext,
6455 "xmlElemDump : cur == NULL\n");
6456#endif
6457 return;
6458 }
Owen Taylor3473f882001-02-23 17:55:21 +00006459#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006460 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006461 xmlGenericError(xmlGenericErrorContext,
6462 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006463 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006464#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00006465
Owen Taylor3473f882001-02-23 17:55:21 +00006466 buf = xmlBufferCreate();
6467 if (buf == NULL) return;
6468 if ((doc != NULL) &&
6469 (doc->type == XML_HTML_DOCUMENT_NODE)) {
6470#ifdef LIBXML_HTML_ENABLED
6471 htmlNodeDump(buf, doc, cur);
6472#else
6473 xmlGenericError(xmlGenericErrorContext,
6474 "HTML support not compiled in\n");
6475#endif /* LIBXML_HTML_ENABLED */
6476 } else
6477 xmlNodeDump(buf, doc, cur, 0, 1);
6478 xmlBufferDump(f, buf);
6479 xmlBufferFree(buf);
6480}
6481
6482/************************************************************************
6483 * *
6484 * Dumping XML tree content to an I/O output buffer *
6485 * *
6486 ************************************************************************/
6487
Owen Taylor3473f882001-02-23 17:55:21 +00006488static void
6489xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6490 int level, int format, const char *encoding);
6491/**
6492 * xmlNsDumpOutput:
6493 * @buf: the XML buffer output
6494 * @cur: a namespace
6495 *
6496 * Dump a local Namespace definition.
6497 * Should be called in the context of attributes dumps.
6498 */
6499static void
6500xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6501 if (cur == NULL) {
6502#ifdef DEBUG_TREE
6503 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006504 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006505#endif
6506 return;
6507 }
6508 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006509 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6510 return;
6511
Owen Taylor3473f882001-02-23 17:55:21 +00006512 /* Within the context of an element attributes */
6513 if (cur->prefix != NULL) {
6514 xmlOutputBufferWriteString(buf, " xmlns:");
6515 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6516 } else
6517 xmlOutputBufferWriteString(buf, " xmlns");
6518 xmlOutputBufferWriteString(buf, "=");
6519 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6520 }
6521}
6522
6523/**
6524 * xmlNsListDumpOutput:
6525 * @buf: the XML buffer output
6526 * @cur: the first namespace
6527 *
6528 * Dump a list of local Namespace definitions.
6529 * Should be called in the context of attributes dumps.
6530 */
6531static void
6532xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6533 while (cur != NULL) {
6534 xmlNsDumpOutput(buf, cur);
6535 cur = cur->next;
6536 }
6537}
6538
6539/**
6540 * xmlDtdDumpOutput:
6541 * @buf: the XML buffer output
6542 * @doc: the document
6543 * @encoding: an optional encoding string
6544 *
6545 * Dump the XML document DTD, if any.
6546 */
6547static void
6548xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6549 if (dtd == NULL) {
6550#ifdef DEBUG_TREE
6551 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006552 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006553#endif
6554 return;
6555 }
6556 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6557 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6558 if (dtd->ExternalID != NULL) {
6559 xmlOutputBufferWriteString(buf, " PUBLIC ");
6560 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6561 xmlOutputBufferWriteString(buf, " ");
6562 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6563 } else if (dtd->SystemID != NULL) {
6564 xmlOutputBufferWriteString(buf, " SYSTEM ");
6565 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6566 }
6567 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6568 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6569 xmlOutputBufferWriteString(buf, ">");
6570 return;
6571 }
6572 xmlOutputBufferWriteString(buf, " [\n");
6573 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6574 xmlOutputBufferWriteString(buf, "]>");
6575}
6576
6577/**
6578 * xmlAttrDumpOutput:
6579 * @buf: the XML buffer output
6580 * @doc: the document
6581 * @cur: the attribute pointer
6582 * @encoding: an optional encoding string
6583 *
6584 * Dump an XML attribute
6585 */
6586static void
6587xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006588 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006589 if (cur == NULL) {
6590#ifdef DEBUG_TREE
6591 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006592 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006593#endif
6594 return;
6595 }
6596 xmlOutputBufferWriteString(buf, " ");
6597 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6598 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6599 xmlOutputBufferWriteString(buf, ":");
6600 }
6601 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006602 xmlOutputBufferWriteString(buf, "=\"");
6603 xmlAttrSerializeContent(buf->buffer, doc, cur);
6604 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006605}
6606
6607/**
6608 * xmlAttrListDumpOutput:
6609 * @buf: the XML buffer output
6610 * @doc: the document
6611 * @cur: the first attribute pointer
6612 * @encoding: an optional encoding string
6613 *
6614 * Dump a list of XML attributes
6615 */
6616static void
6617xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6618 xmlAttrPtr cur, const char *encoding) {
6619 if (cur == NULL) {
6620#ifdef DEBUG_TREE
6621 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006622 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006623#endif
6624 return;
6625 }
6626 while (cur != NULL) {
6627 xmlAttrDumpOutput(buf, doc, cur, encoding);
6628 cur = cur->next;
6629 }
6630}
6631
6632
6633
6634/**
6635 * xmlNodeListDumpOutput:
6636 * @buf: the XML buffer output
6637 * @doc: the document
6638 * @cur: the first node
6639 * @level: the imbrication level for indenting
6640 * @format: is formatting allowed
6641 * @encoding: an optional encoding string
6642 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006643 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006644 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6645 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006646 */
6647static void
6648xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6649 xmlNodePtr cur, int level, int format, const char *encoding) {
6650 int i;
6651
6652 if (cur == NULL) {
6653#ifdef DEBUG_TREE
6654 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006655 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006656#endif
6657 return;
6658 }
6659 while (cur != NULL) {
6660 if ((format) && (xmlIndentTreeOutput) &&
6661 (cur->type == XML_ELEMENT_NODE))
6662 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006663 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006664 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6665 if (format) {
6666 xmlOutputBufferWriteString(buf, "\n");
6667 }
6668 cur = cur->next;
6669 }
6670}
6671
6672/**
6673 * xmlNodeDumpOutput:
6674 * @buf: the XML buffer output
6675 * @doc: the document
6676 * @cur: the current node
6677 * @level: the imbrication level for indenting
6678 * @format: is formatting allowed
6679 * @encoding: an optional encoding string
6680 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006681 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006682 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6683 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006684 */
6685void
6686xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6687 int level, int format, const char *encoding) {
6688 int i;
6689 xmlNodePtr tmp;
6690
6691 if (cur == NULL) {
6692#ifdef DEBUG_TREE
6693 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006694 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006695#endif
6696 return;
6697 }
6698 if (cur->type == XML_XINCLUDE_START)
6699 return;
6700 if (cur->type == XML_XINCLUDE_END)
6701 return;
6702 if (cur->type == XML_DTD_NODE) {
6703 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6704 return;
6705 }
6706 if (cur->type == XML_ELEMENT_DECL) {
6707 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6708 return;
6709 }
6710 if (cur->type == XML_ATTRIBUTE_DECL) {
6711 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6712 return;
6713 }
6714 if (cur->type == XML_ENTITY_DECL) {
6715 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6716 return;
6717 }
6718 if (cur->type == XML_TEXT_NODE) {
6719 if (cur->content != NULL) {
6720 if ((cur->name == xmlStringText) ||
6721 (cur->name != xmlStringTextNoenc)) {
6722 xmlChar *buffer;
6723
Owen Taylor3473f882001-02-23 17:55:21 +00006724 if (encoding == NULL)
6725 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6726 else
6727 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006728 if (buffer != NULL) {
6729 xmlOutputBufferWriteString(buf, (const char *)buffer);
6730 xmlFree(buffer);
6731 }
6732 } else {
6733 /*
6734 * Disable escaping, needed for XSLT
6735 */
Owen Taylor3473f882001-02-23 17:55:21 +00006736 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006737 }
6738 }
6739
6740 return;
6741 }
6742 if (cur->type == XML_PI_NODE) {
6743 if (cur->content != NULL) {
6744 xmlOutputBufferWriteString(buf, "<?");
6745 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6746 if (cur->content != NULL) {
6747 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006748 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006749 }
6750 xmlOutputBufferWriteString(buf, "?>");
6751 } else {
6752 xmlOutputBufferWriteString(buf, "<?");
6753 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6754 xmlOutputBufferWriteString(buf, "?>");
6755 }
6756 return;
6757 }
6758 if (cur->type == XML_COMMENT_NODE) {
6759 if (cur->content != NULL) {
6760 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006761 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006762 xmlOutputBufferWriteString(buf, "-->");
6763 }
6764 return;
6765 }
6766 if (cur->type == XML_ENTITY_REF_NODE) {
6767 xmlOutputBufferWriteString(buf, "&");
6768 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6769 xmlOutputBufferWriteString(buf, ";");
6770 return;
6771 }
6772 if (cur->type == XML_CDATA_SECTION_NODE) {
6773 xmlOutputBufferWriteString(buf, "<![CDATA[");
6774 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006775 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006776 xmlOutputBufferWriteString(buf, "]]>");
6777 return;
6778 }
6779
6780 if (format == 1) {
6781 tmp = cur->children;
6782 while (tmp != NULL) {
6783 if ((tmp->type == XML_TEXT_NODE) ||
6784 (tmp->type == XML_ENTITY_REF_NODE)) {
6785 format = 0;
6786 break;
6787 }
6788 tmp = tmp->next;
6789 }
6790 }
6791 xmlOutputBufferWriteString(buf, "<");
6792 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6793 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6794 xmlOutputBufferWriteString(buf, ":");
6795 }
6796
6797 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6798 if (cur->nsDef)
6799 xmlNsListDumpOutput(buf, cur->nsDef);
6800 if (cur->properties != NULL)
6801 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6802
Daniel Veillard7db37732001-07-12 01:20:08 +00006803 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6804 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006805 xmlOutputBufferWriteString(buf, "/>");
6806 return;
6807 }
6808 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006809 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006810 xmlChar *buffer;
6811
Owen Taylor3473f882001-02-23 17:55:21 +00006812 if (encoding == NULL)
6813 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6814 else
6815 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006816 if (buffer != NULL) {
6817 xmlOutputBufferWriteString(buf, (const char *)buffer);
6818 xmlFree(buffer);
6819 }
6820 }
6821 if (cur->children != NULL) {
6822 if (format) xmlOutputBufferWriteString(buf, "\n");
6823 xmlNodeListDumpOutput(buf, doc, cur->children,
6824 (level >= 0?level+1:-1), format, encoding);
6825 if ((xmlIndentTreeOutput) && (format))
6826 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006827 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006828 }
6829 xmlOutputBufferWriteString(buf, "</");
6830 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6831 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6832 xmlOutputBufferWriteString(buf, ":");
6833 }
6834
6835 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6836 xmlOutputBufferWriteString(buf, ">");
6837}
6838
6839/**
6840 * xmlDocContentDumpOutput:
6841 * @buf: the XML buffer output
6842 * @cur: the document
6843 * @encoding: an optional encoding string
6844 * @format: should formatting spaces been added
6845 *
6846 * Dump an XML document.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006847 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6848 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006849 */
6850static void
6851xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6852 const char *encoding, int format) {
6853 xmlOutputBufferWriteString(buf, "<?xml version=");
6854 if (cur->version != NULL)
6855 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6856 else
6857 xmlOutputBufferWriteString(buf, "\"1.0\"");
6858 if (encoding == NULL) {
6859 if (cur->encoding != NULL)
6860 encoding = (const char *) cur->encoding;
6861 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6862 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6863 }
6864 if (encoding != NULL) {
6865 xmlOutputBufferWriteString(buf, " encoding=");
6866 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6867 }
6868 switch (cur->standalone) {
6869 case 0:
6870 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6871 break;
6872 case 1:
6873 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6874 break;
6875 }
6876 xmlOutputBufferWriteString(buf, "?>\n");
6877 if (cur->children != NULL) {
6878 xmlNodePtr child = cur->children;
6879
6880 while (child != NULL) {
6881 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6882 xmlOutputBufferWriteString(buf, "\n");
6883 child = child->next;
6884 }
6885 }
6886}
6887
6888/************************************************************************
6889 * *
6890 * Saving functions front-ends *
6891 * *
6892 ************************************************************************/
6893
6894/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006895 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006896 * @out_doc: Document to generate XML text from
6897 * @doc_txt_ptr: Memory pointer for allocated XML text
6898 * @doc_txt_len: Length of the generated XML text
6899 * @txt_encoding: Character encoding to use when generating XML text
6900 * @format: should formatting spaces been added
6901 *
6902 * Dump the current DOM tree into memory using the character encoding specified
6903 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006904 * allocated memory with xmlFree().
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006905 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6906 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006907 */
6908
6909void
6910xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006911 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006912 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006913 int dummy = 0;
6914
6915 xmlCharEncoding doc_charset;
6916 xmlOutputBufferPtr out_buff = NULL;
6917 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6918
6919 if (doc_txt_len == NULL) {
6920 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6921 }
6922
6923 if (doc_txt_ptr == NULL) {
6924 *doc_txt_len = 0;
6925 xmlGenericError(xmlGenericErrorContext,
6926 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6927 return;
6928 }
6929
6930 *doc_txt_ptr = NULL;
6931 *doc_txt_len = 0;
6932
6933 if (out_doc == NULL) {
6934 /* No document, no output */
6935 xmlGenericError(xmlGenericErrorContext,
6936 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6937 return;
6938 }
6939
6940 /*
6941 * Validate the encoding value, if provided.
6942 * This logic is copied from xmlSaveFileEnc.
6943 */
6944
6945 if (txt_encoding == NULL)
6946 txt_encoding = (const char *) out_doc->encoding;
6947 if (txt_encoding != NULL) {
6948 doc_charset = xmlParseCharEncoding(txt_encoding);
6949
6950 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6951 xmlGenericError(xmlGenericErrorContext,
6952 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6953 return;
6954
6955 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6956 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6957 if ( conv_hdlr == NULL ) {
6958 xmlGenericError(xmlGenericErrorContext,
6959 "%s: %s %s '%s'\n",
6960 "xmlDocDumpFormatMemoryEnc",
6961 "Failed to identify encoding handler for",
6962 "character set",
6963 txt_encoding);
6964 return;
6965 }
6966 }
6967 }
6968
6969 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6970 xmlGenericError(xmlGenericErrorContext,
6971 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6972 return;
6973 }
6974
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006975 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006976 xmlOutputBufferFlush(out_buff);
6977 if (out_buff->conv != NULL) {
6978 *doc_txt_len = out_buff->conv->use;
6979 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6980 } else {
6981 *doc_txt_len = out_buff->buffer->use;
6982 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6983 }
6984 (void)xmlOutputBufferClose(out_buff);
6985
6986 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6987 *doc_txt_len = 0;
6988 xmlGenericError(xmlGenericErrorContext,
6989 "xmlDocDumpFormatMemoryEnc: %s\n",
6990 "Failed to allocate memory for document text representation.");
6991 }
6992
6993 return;
6994}
6995
6996/**
6997 * xmlDocDumpMemory:
6998 * @cur: the document
6999 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007000 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007001 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007002 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007003 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007004 */
7005void
7006xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
7007 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
7008}
7009
7010/**
7011 * xmlDocDumpFormatMemory:
7012 * @cur: the document
7013 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007014 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007015 * @format: should formatting spaces been added
7016 *
7017 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007018 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007019 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007020 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7021 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007022 */
7023void
7024xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
7025 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
7026}
7027
7028/**
7029 * xmlDocDumpMemoryEnc:
7030 * @out_doc: Document to generate XML text from
7031 * @doc_txt_ptr: Memory pointer for allocated XML text
7032 * @doc_txt_len: Length of the generated XML text
7033 * @txt_encoding: Character encoding to use when generating XML text
7034 *
7035 * Dump the current DOM tree into memory using the character encoding specified
7036 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007037 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007038 */
7039
7040void
7041xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
7042 int * doc_txt_len, const char * txt_encoding) {
7043 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007044 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007045}
7046
7047/**
7048 * xmlGetDocCompressMode:
7049 * @doc: the document
7050 *
7051 * get the compression ratio for a document, ZLIB based
7052 * Returns 0 (uncompressed) to 9 (max compression)
7053 */
7054int
7055xmlGetDocCompressMode (xmlDocPtr doc) {
7056 if (doc == NULL) return(-1);
7057 return(doc->compression);
7058}
7059
7060/**
7061 * xmlSetDocCompressMode:
7062 * @doc: the document
7063 * @mode: the compression ratio
7064 *
7065 * set the compression ratio for a document, ZLIB based
7066 * Correct values: 0 (uncompressed) to 9 (max compression)
7067 */
7068void
7069xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7070 if (doc == NULL) return;
7071 if (mode < 0) doc->compression = 0;
7072 else if (mode > 9) doc->compression = 9;
7073 else doc->compression = mode;
7074}
7075
7076/**
7077 * xmlGetCompressMode:
7078 *
7079 * get the default compression mode used, ZLIB based.
7080 * Returns 0 (uncompressed) to 9 (max compression)
7081 */
7082int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007083xmlGetCompressMode(void)
7084{
7085 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00007086}
7087
7088/**
7089 * xmlSetCompressMode:
7090 * @mode: the compression ratio
7091 *
7092 * set the default compression mode used, ZLIB based
7093 * Correct values: 0 (uncompressed) to 9 (max compression)
7094 */
7095void
7096xmlSetCompressMode(int mode) {
7097 if (mode < 0) xmlCompressMode = 0;
7098 else if (mode > 9) xmlCompressMode = 9;
7099 else xmlCompressMode = mode;
7100}
7101
7102/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007103 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00007104 * @f: the FILE*
7105 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00007106 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007107 *
7108 * Dump an XML document to an open FILE.
7109 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007110 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007111 */
7112int
Daniel Veillard9e412302002-06-10 15:59:44 +00007113xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007114 xmlOutputBufferPtr buf;
7115 const char * encoding;
7116 xmlCharEncodingHandlerPtr handler = NULL;
7117 int ret;
7118
7119 if (cur == NULL) {
7120#ifdef DEBUG_TREE
7121 xmlGenericError(xmlGenericErrorContext,
7122 "xmlDocDump : document == NULL\n");
7123#endif
7124 return(-1);
7125 }
7126 encoding = (const char *) cur->encoding;
7127
7128 if (encoding != NULL) {
7129 xmlCharEncoding enc;
7130
7131 enc = xmlParseCharEncoding(encoding);
7132
7133 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7134 xmlGenericError(xmlGenericErrorContext,
7135 "xmlDocDump: document not in UTF8\n");
7136 return(-1);
7137 }
7138 if (enc != XML_CHAR_ENCODING_UTF8) {
7139 handler = xmlFindCharEncodingHandler(encoding);
7140 if (handler == NULL) {
7141 xmlFree((char *) cur->encoding);
7142 cur->encoding = NULL;
7143 }
7144 }
7145 }
7146 buf = xmlOutputBufferCreateFile(f, handler);
7147 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00007148 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007149
7150 ret = xmlOutputBufferClose(buf);
7151 return(ret);
7152}
7153
7154/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007155 * xmlDocDump:
7156 * @f: the FILE*
7157 * @cur: the document
7158 *
7159 * Dump an XML document to an open FILE.
7160 *
7161 * returns: the number of bytes written or -1 in case of failure.
7162 */
7163int
7164xmlDocDump(FILE *f, xmlDocPtr cur) {
7165 return(xmlDocFormatDump (f, cur, 0));
7166}
7167
7168/**
Owen Taylor3473f882001-02-23 17:55:21 +00007169 * xmlSaveFileTo:
7170 * @buf: an output I/O buffer
7171 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007172 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00007173 *
7174 * Dump an XML document to an I/O buffer.
7175 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007176 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007177 */
7178int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007179xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007180 int ret;
7181
7182 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007183 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007184 ret = xmlOutputBufferClose(buf);
7185 return(ret);
7186}
7187
7188/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00007189 * xmlSaveFormatFileTo:
7190 * @buf: an output I/O buffer
7191 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007192 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00007193 * @format: should formatting spaces been added
7194 *
7195 * Dump an XML document to an I/O buffer.
7196 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007197 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00007198 */
7199int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007200xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00007201 int ret;
7202
7203 if (buf == NULL) return(0);
7204 xmlDocContentDumpOutput(buf, cur, encoding, format);
7205 ret = xmlOutputBufferClose(buf);
7206 return(ret);
7207}
7208
7209/**
Daniel Veillardf012a642001-07-23 19:10:52 +00007210 * xmlSaveFormatFileEnc
7211 * @filename: the filename or URL to output
7212 * @cur: the document being saved
7213 * @encoding: the name of the encoding to use or NULL.
7214 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00007215 *
7216 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00007217 */
7218int
Daniel Veillardf012a642001-07-23 19:10:52 +00007219xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
7220 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00007221 xmlOutputBufferPtr buf;
7222 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00007223 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00007224 int ret;
7225
Daniel Veillardfb25a512002-01-13 20:32:08 +00007226 if (encoding == NULL)
7227 encoding = (const char *) cur->encoding;
7228
Owen Taylor3473f882001-02-23 17:55:21 +00007229 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007230
7231 enc = xmlParseCharEncoding(encoding);
7232 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7233 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007234 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007235 return(-1);
7236 }
7237 if (enc != XML_CHAR_ENCODING_UTF8) {
7238 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00007239 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007240 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007241 }
7242 }
7243
Daniel Veillardf012a642001-07-23 19:10:52 +00007244#ifdef HAVE_ZLIB_H
7245 if (cur->compression < 0) cur->compression = xmlCompressMode;
7246#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007247 /*
7248 * save the content to a temp buffer.
7249 */
Daniel Veillardf012a642001-07-23 19:10:52 +00007250 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00007251 if (buf == NULL) return(-1);
7252
Daniel Veillardf012a642001-07-23 19:10:52 +00007253 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007254
7255 ret = xmlOutputBufferClose(buf);
7256 return(ret);
7257}
7258
Daniel Veillardf012a642001-07-23 19:10:52 +00007259
7260/**
7261 * xmlSaveFileEnc:
7262 * @filename: the filename (or URL)
7263 * @cur: the document
7264 * @encoding: the name of an encoding (or NULL)
7265 *
7266 * Dump an XML document, converting it to the given encoding
7267 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007268 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00007269 */
7270int
7271xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
7272 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
7273}
7274
Owen Taylor3473f882001-02-23 17:55:21 +00007275/**
Daniel Veillard67fee942001-04-26 18:59:03 +00007276 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00007277 * @filename: the filename (or URL)
7278 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00007279 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007280 *
7281 * Dump an XML document to a file. Will use compression if
7282 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00007283 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00007284 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007285 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007286 */
7287int
Daniel Veillard67fee942001-04-26 18:59:03 +00007288xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007289 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00007290}
7291
Daniel Veillard67fee942001-04-26 18:59:03 +00007292/**
7293 * xmlSaveFile:
7294 * @filename: the filename (or URL)
7295 * @cur: the document
7296 *
7297 * Dump an XML document to a file. Will use compression if
7298 * compiled in and enabled. If @filename is "-" the stdout file is
7299 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00007300 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00007301 */
7302int
7303xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007304 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00007305}
7306