blob: 2a2c68ffa61fa148cc7af9f9f41cd07c0091d0ca [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 *
Daniel Veillardd5c2f922002-11-21 14:10:52 +00004 * References:
5 * XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
6 *
Owen Taylor3473f882001-02-23 17:55:21 +00007 * See Copyright for the status of this software.
8 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00009 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000010 *
Owen Taylor3473f882001-02-23 17:55:21 +000011 */
12
Daniel Veillard34ce8be2002-03-18 19:37:11 +000013#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000014#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000015
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24#ifdef HAVE_ZLIB_H
25#include <zlib.h>
26#endif
27
28#include <libxml/xmlmemory.h>
29#include <libxml/tree.h>
30#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000031#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000032#include <libxml/entities.h>
33#include <libxml/valid.h>
34#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000035#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000036#include <libxml/globals.h>
Daniel Veillardd5c2f922002-11-21 14:10:52 +000037#ifdef LIBXML_HTML_ENABLED
38#include <libxml/HTMLtree.h>
39#endif
Owen Taylor3473f882001-02-23 17:55:21 +000040
Daniel Veillard56a4cb82001-03-24 17:00:36 +000041xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
42
43/************************************************************************
44 * *
45 * A few static variables and macros *
46 * *
47 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000048/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000049const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000050/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000051const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000052 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000053/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +000054const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
55
Owen Taylor3473f882001-02-23 17:55:21 +000056static int xmlCompressMode = 0;
57static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000058
Owen Taylor3473f882001-02-23 17:55:21 +000059#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
60 xmlNodePtr ulccur = (n)->children; \
61 if (ulccur == NULL) { \
62 (n)->last = NULL; \
63 } else { \
64 while (ulccur->next != NULL) { \
65 ulccur->parent = (n); \
66 ulccur = ulccur->next; \
67 } \
68 ulccur->parent = (n); \
69 (n)->last = ulccur; \
70}}
71
72/* #define DEBUG_BUFFER */
73/* #define DEBUG_TREE */
74
75/************************************************************************
76 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +000077 * Functions to move to entities.c once the *
78 * API freeze is smoothen and they can be made public. *
79 * *
80 ************************************************************************/
81#include <libxml/hash.h>
82
83/**
84 * xmlGetEntityFromDtd:
85 * @dtd: A pointer to the DTD to search
86 * @name: The entity name
87 *
88 * Do an entity lookup in the DTD entity hash table and
89 * return the corresponding entity, if found.
90 *
91 * Returns A pointer to the entity structure or NULL if not found.
92 */
93static xmlEntityPtr
94xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
95 xmlEntitiesTablePtr table;
96
97 if((dtd != NULL) && (dtd->entities != NULL)) {
98 table = (xmlEntitiesTablePtr) dtd->entities;
99 return((xmlEntityPtr) xmlHashLookup(table, name));
100 /* return(xmlGetEntityFromTable(table, name)); */
101 }
102 return(NULL);
103}
104/**
105 * xmlGetParameterEntityFromDtd:
106 * @dtd: A pointer to the DTD to search
107 * @name: The entity name
108 *
109 * Do an entity lookup in the DTD pararmeter entity hash table and
110 * return the corresponding entity, if found.
111 *
112 * Returns A pointer to the entity structure or NULL if not found.
113 */
114static xmlEntityPtr
115xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
116 xmlEntitiesTablePtr table;
117
118 if ((dtd != NULL) && (dtd->pentities != NULL)) {
119 table = (xmlEntitiesTablePtr) dtd->pentities;
120 return((xmlEntityPtr) xmlHashLookup(table, name));
121 /* return(xmlGetEntityFromTable(table, name)); */
122 }
123 return(NULL);
124}
125
126/************************************************************************
127 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000128 * Allocation and deallocation of basic structures *
129 * *
130 ************************************************************************/
131
132/**
133 * xmlSetBufferAllocationScheme:
134 * @scheme: allocation method to use
135 *
136 * Set the buffer allocation method. Types are
137 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
138 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
139 * improves performance
140 */
141void
142xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
143 xmlBufferAllocScheme = scheme;
144}
145
146/**
147 * xmlGetBufferAllocationScheme:
148 *
149 * Types are
150 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
151 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
152 * improves performance
153 *
154 * Returns the current allocation scheme
155 */
156xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000157xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000158 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000159}
160
161/**
162 * xmlNewNs:
163 * @node: the element carrying the namespace
164 * @href: the URI associated
165 * @prefix: the prefix for the namespace
166 *
167 * Creation of a new Namespace. This function will refuse to create
168 * a namespace with a similar prefix than an existing one present on this
169 * node.
170 * We use href==NULL in the case of an element creation where the namespace
171 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000172 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000173 */
174xmlNsPtr
175xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
176 xmlNsPtr cur;
177
178 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
179 return(NULL);
180
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000181 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
182 return(NULL);
183
Owen Taylor3473f882001-02-23 17:55:21 +0000184 /*
185 * Allocate a new Namespace and fill the fields.
186 */
187 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
188 if (cur == NULL) {
189 xmlGenericError(xmlGenericErrorContext,
190 "xmlNewNs : malloc failed\n");
191 return(NULL);
192 }
193 memset(cur, 0, sizeof(xmlNs));
194 cur->type = XML_LOCAL_NAMESPACE;
195
196 if (href != NULL)
197 cur->href = xmlStrdup(href);
198 if (prefix != NULL)
199 cur->prefix = xmlStrdup(prefix);
200
201 /*
202 * Add it at the end to preserve parsing order ...
203 * and checks for existing use of the prefix
204 */
205 if (node != NULL) {
206 if (node->nsDef == NULL) {
207 node->nsDef = cur;
208 } else {
209 xmlNsPtr prev = node->nsDef;
210
211 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
212 (xmlStrEqual(prev->prefix, cur->prefix))) {
213 xmlFreeNs(cur);
214 return(NULL);
215 }
216 while (prev->next != NULL) {
217 prev = prev->next;
218 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
219 (xmlStrEqual(prev->prefix, cur->prefix))) {
220 xmlFreeNs(cur);
221 return(NULL);
222 }
223 }
224 prev->next = cur;
225 }
226 }
227 return(cur);
228}
229
230/**
231 * xmlSetNs:
232 * @node: a node in the document
233 * @ns: a namespace pointer
234 *
235 * Associate a namespace to a node, a posteriori.
236 */
237void
238xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
239 if (node == NULL) {
240#ifdef DEBUG_TREE
241 xmlGenericError(xmlGenericErrorContext,
242 "xmlSetNs: node == NULL\n");
243#endif
244 return;
245 }
246 node->ns = ns;
247}
248
249/**
250 * xmlFreeNs:
251 * @cur: the namespace pointer
252 *
253 * Free up the structures associated to a namespace
254 */
255void
256xmlFreeNs(xmlNsPtr cur) {
257 if (cur == NULL) {
258#ifdef DEBUG_TREE
259 xmlGenericError(xmlGenericErrorContext,
260 "xmlFreeNs : ns == NULL\n");
261#endif
262 return;
263 }
264 if (cur->href != NULL) xmlFree((char *) cur->href);
265 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000266 xmlFree(cur);
267}
268
269/**
270 * xmlFreeNsList:
271 * @cur: the first namespace pointer
272 *
273 * Free up all the structures associated to the chained namespaces.
274 */
275void
276xmlFreeNsList(xmlNsPtr cur) {
277 xmlNsPtr next;
278 if (cur == NULL) {
279#ifdef DEBUG_TREE
280 xmlGenericError(xmlGenericErrorContext,
281 "xmlFreeNsList : ns == NULL\n");
282#endif
283 return;
284 }
285 while (cur != NULL) {
286 next = cur->next;
287 xmlFreeNs(cur);
288 cur = next;
289 }
290}
291
292/**
293 * xmlNewDtd:
294 * @doc: the document pointer
295 * @name: the DTD name
296 * @ExternalID: the external ID
297 * @SystemID: the system ID
298 *
299 * Creation of a new DTD for the external subset. To create an
300 * internal subset, use xmlCreateIntSubset().
301 *
302 * Returns a pointer to the new DTD structure
303 */
304xmlDtdPtr
305xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
306 const xmlChar *ExternalID, const xmlChar *SystemID) {
307 xmlDtdPtr cur;
308
309 if ((doc != NULL) && (doc->extSubset != NULL)) {
310#ifdef DEBUG_TREE
311 xmlGenericError(xmlGenericErrorContext,
312 "xmlNewDtd(%s): document %s already have a DTD %s\n",
313 /* !!! */ (char *) name, doc->name,
314 /* !!! */ (char *)doc->extSubset->name);
315#endif
316 return(NULL);
317 }
318
319 /*
320 * Allocate a new DTD and fill the fields.
321 */
322 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
323 if (cur == NULL) {
324 xmlGenericError(xmlGenericErrorContext,
325 "xmlNewDtd : malloc failed\n");
326 return(NULL);
327 }
328 memset(cur, 0 , sizeof(xmlDtd));
329 cur->type = XML_DTD_NODE;
330
331 if (name != NULL)
332 cur->name = xmlStrdup(name);
333 if (ExternalID != NULL)
334 cur->ExternalID = xmlStrdup(ExternalID);
335 if (SystemID != NULL)
336 cur->SystemID = xmlStrdup(SystemID);
337 if (doc != NULL)
338 doc->extSubset = cur;
339 cur->doc = doc;
340
Daniel Veillard5335dc52003-01-01 20:59:38 +0000341 if (xmlRegisterNodeDefaultValue)
342 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000343 return(cur);
344}
345
346/**
347 * xmlGetIntSubset:
348 * @doc: the document pointer
349 *
350 * Get the internal subset of a document
351 * Returns a pointer to the DTD structure or NULL if not found
352 */
353
354xmlDtdPtr
355xmlGetIntSubset(xmlDocPtr doc) {
356 xmlNodePtr cur;
357
358 if (doc == NULL)
359 return(NULL);
360 cur = doc->children;
361 while (cur != NULL) {
362 if (cur->type == XML_DTD_NODE)
363 return((xmlDtdPtr) cur);
364 cur = cur->next;
365 }
366 return((xmlDtdPtr) doc->intSubset);
367}
368
369/**
370 * xmlCreateIntSubset:
371 * @doc: the document pointer
372 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000373 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000374 * @SystemID: the system ID
375 *
376 * Create the internal subset of a document
377 * Returns a pointer to the new DTD structure
378 */
379xmlDtdPtr
380xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
381 const xmlChar *ExternalID, const xmlChar *SystemID) {
382 xmlDtdPtr cur;
383
384 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
385#ifdef DEBUG_TREE
386 xmlGenericError(xmlGenericErrorContext,
387
388 "xmlCreateIntSubset(): document %s already have an internal subset\n",
389 doc->name);
390#endif
391 return(NULL);
392 }
393
394 /*
395 * Allocate a new DTD and fill the fields.
396 */
397 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
398 if (cur == NULL) {
399 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000400 "xmlCreateIntSubset : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000401 return(NULL);
402 }
403 memset(cur, 0, sizeof(xmlDtd));
404 cur->type = XML_DTD_NODE;
405
406 if (name != NULL)
407 cur->name = xmlStrdup(name);
408 if (ExternalID != NULL)
409 cur->ExternalID = xmlStrdup(ExternalID);
410 if (SystemID != NULL)
411 cur->SystemID = xmlStrdup(SystemID);
412 if (doc != NULL) {
413 doc->intSubset = cur;
414 cur->parent = doc;
415 cur->doc = doc;
416 if (doc->children == NULL) {
417 doc->children = (xmlNodePtr) cur;
418 doc->last = (xmlNodePtr) cur;
419 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000420 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000421 xmlNodePtr prev;
422
Owen Taylor3473f882001-02-23 17:55:21 +0000423 prev = doc->children;
424 prev->prev = (xmlNodePtr) cur;
425 cur->next = prev;
426 doc->children = (xmlNodePtr) cur;
427 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000428 xmlNodePtr next;
429
430 next = doc->children;
431 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
432 next = next->next;
433 if (next == NULL) {
434 cur->prev = doc->last;
435 cur->prev->next = (xmlNodePtr) cur;
436 cur->next = NULL;
437 doc->last = (xmlNodePtr) cur;
438 } else {
439 cur->next = next;
440 cur->prev = next->prev;
441 if (cur->prev == NULL)
442 doc->children = (xmlNodePtr) cur;
443 else
444 cur->prev->next = (xmlNodePtr) cur;
445 next->prev = (xmlNodePtr) cur;
446 }
Owen Taylor3473f882001-02-23 17:55:21 +0000447 }
448 }
449 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000450
451 if (xmlRegisterNodeDefaultValue)
452 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000453 return(cur);
454}
455
456/**
457 * xmlFreeDtd:
458 * @cur: the DTD structure to free up
459 *
460 * Free a DTD structure.
461 */
462void
463xmlFreeDtd(xmlDtdPtr cur) {
464 if (cur == NULL) {
465#ifdef DEBUG_TREE
466 xmlGenericError(xmlGenericErrorContext,
467 "xmlFreeDtd : DTD == NULL\n");
468#endif
469 return;
470 }
Daniel Veillard5335dc52003-01-01 20:59:38 +0000471
472 if (xmlDeregisterNodeDefaultValue)
473 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
474
Owen Taylor3473f882001-02-23 17:55:21 +0000475 if (cur->children != NULL) {
476 xmlNodePtr next, c = cur->children;
477
478 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000479 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000480 * indexes.
481 */
482 while (c != NULL) {
483 next = c->next;
484 if (c->type == XML_COMMENT_NODE) {
485 xmlUnlinkNode(c);
486 xmlFreeNode(c);
487 }
488 c = next;
489 }
490 }
491 if (cur->name != NULL) xmlFree((char *) cur->name);
492 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
493 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
494 /* TODO !!! */
495 if (cur->notations != NULL)
496 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
497
498 if (cur->elements != NULL)
499 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
500 if (cur->attributes != NULL)
501 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
502 if (cur->entities != NULL)
503 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
504 if (cur->pentities != NULL)
505 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
506
Owen Taylor3473f882001-02-23 17:55:21 +0000507 xmlFree(cur);
508}
509
510/**
511 * xmlNewDoc:
512 * @version: xmlChar string giving the version of XML "1.0"
513 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000514 * Creates a new XML document
515 *
Owen Taylor3473f882001-02-23 17:55:21 +0000516 * Returns a new document
517 */
518xmlDocPtr
519xmlNewDoc(const xmlChar *version) {
520 xmlDocPtr cur;
521
522 if (version == NULL)
523 version = (const xmlChar *) "1.0";
524
525 /*
526 * Allocate a new document and fill the fields.
527 */
528 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
529 if (cur == NULL) {
530 xmlGenericError(xmlGenericErrorContext,
531 "xmlNewDoc : malloc failed\n");
532 return(NULL);
533 }
534 memset(cur, 0, sizeof(xmlDoc));
535 cur->type = XML_DOCUMENT_NODE;
536
537 cur->version = xmlStrdup(version);
538 cur->standalone = -1;
539 cur->compression = -1; /* not initialized */
540 cur->doc = cur;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000541 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +0000542
543 if (xmlRegisterNodeDefaultValue)
544 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000545 return(cur);
546}
547
548/**
549 * xmlFreeDoc:
550 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +0000551 *
552 * Free up all the structures used by a document, tree included.
553 */
554void
555xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000556 xmlDtdPtr extSubset, intSubset;
557
Owen Taylor3473f882001-02-23 17:55:21 +0000558 if (cur == NULL) {
559#ifdef DEBUG_TREE
560 xmlGenericError(xmlGenericErrorContext,
561 "xmlFreeDoc : document == NULL\n");
562#endif
563 return;
564 }
Daniel Veillard5335dc52003-01-01 20:59:38 +0000565
566 if (xmlDeregisterNodeDefaultValue)
567 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
568
Daniel Veillard76d66f42001-05-16 21:05:17 +0000569 /*
570 * Do this before freeing the children list to avoid ID lookups
571 */
572 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
573 cur->ids = NULL;
574 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
575 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000576 extSubset = cur->extSubset;
577 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +0000578 if (intSubset == extSubset)
579 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000580 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000581 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000582 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000583 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000584 }
Daniel Veillarda9142e72001-06-19 11:07:54 +0000585 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000586 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000587 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000588 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000589 }
590
591 if (cur->children != NULL) xmlFreeNodeList(cur->children);
592
Owen Taylor3473f882001-02-23 17:55:21 +0000593 if (cur->version != NULL) xmlFree((char *) cur->version);
594 if (cur->name != NULL) xmlFree((char *) cur->name);
595 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +0000596 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +0000597 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000598 xmlFree(cur);
599}
600
601/**
602 * xmlStringLenGetNodeList:
603 * @doc: the document
604 * @value: the value of the text
605 * @len: the length of the string value
606 *
607 * Parse the value string and build the node list associated. Should
608 * produce a flat tree with only TEXTs and ENTITY_REFs.
609 * Returns a pointer to the first child
610 */
611xmlNodePtr
612xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
613 xmlNodePtr ret = NULL, last = NULL;
614 xmlNodePtr node;
615 xmlChar *val;
616 const xmlChar *cur = value;
617 const xmlChar *q;
618 xmlEntityPtr ent;
619
620 if (value == NULL) return(NULL);
621
622 q = cur;
623 while ((*cur != 0) && (cur - value < len)) {
624 if (*cur == '&') {
625 /*
626 * Save the current text.
627 */
628 if (cur != q) {
629 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
630 xmlNodeAddContentLen(last, q, cur - q);
631 } else {
632 node = xmlNewDocTextLen(doc, q, cur - q);
633 if (node == NULL) return(ret);
634 if (last == NULL)
635 last = ret = node;
636 else {
637 last->next = node;
638 node->prev = last;
639 last = node;
640 }
641 }
642 }
643 /*
644 * Read the entity string
645 */
646 cur++;
647 q = cur;
648 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
649 if ((*cur == 0) || (cur - value >= len)) {
650#ifdef DEBUG_TREE
651 xmlGenericError(xmlGenericErrorContext,
652 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
653#endif
654 return(ret);
655 }
656 if (cur != q) {
657 /*
658 * Predefined entities don't generate nodes
659 */
660 val = xmlStrndup(q, cur - q);
661 ent = xmlGetDocEntity(doc, val);
662 if ((ent != NULL) &&
663 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
664 if (last == NULL) {
665 node = xmlNewDocText(doc, ent->content);
666 last = ret = node;
667 } else
668 xmlNodeAddContent(last, ent->content);
669
670 } else {
671 /*
672 * Create a new REFERENCE_REF node
673 */
674 node = xmlNewReference(doc, val);
675 if (node == NULL) {
676 if (val != NULL) xmlFree(val);
677 return(ret);
678 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000679 else if ((ent != NULL) && (ent->children == NULL)) {
680 xmlNodePtr tmp;
681
682 ent->children =
683 xmlStringGetNodeList(doc, (const xmlChar*)node->content);
684 tmp = ent->children;
685 while (tmp) {
686 tmp->parent = (xmlNodePtr)ent;
687 tmp = tmp->next;
688 }
689 }
Owen Taylor3473f882001-02-23 17:55:21 +0000690 if (last == NULL)
691 last = ret = node;
692 else {
693 last->next = node;
694 node->prev = last;
695 last = node;
696 }
697 }
698 xmlFree(val);
699 }
700 cur++;
701 q = cur;
702 } else
703 cur++;
704 }
705 if (cur != q) {
706 /*
707 * Handle the last piece of text.
708 */
709 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
710 xmlNodeAddContentLen(last, q, cur - q);
711 } else {
712 node = xmlNewDocTextLen(doc, q, cur - q);
713 if (node == NULL) return(ret);
714 if (last == NULL)
715 last = ret = node;
716 else {
717 last->next = node;
718 node->prev = last;
719 last = node;
720 }
721 }
722 }
723 return(ret);
724}
725
726/**
727 * xmlStringGetNodeList:
728 * @doc: the document
729 * @value: the value of the attribute
730 *
731 * Parse the value string and build the node list associated. Should
732 * produce a flat tree with only TEXTs and ENTITY_REFs.
733 * Returns a pointer to the first child
734 */
735xmlNodePtr
736xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
737 xmlNodePtr ret = NULL, last = NULL;
738 xmlNodePtr node;
739 xmlChar *val;
740 const xmlChar *cur = value;
741 const xmlChar *q;
742 xmlEntityPtr ent;
743
744 if (value == NULL) return(NULL);
745
746 q = cur;
747 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000748 if (cur[0] == '&') {
749 int charval = 0;
750 xmlChar tmp;
751
Owen Taylor3473f882001-02-23 17:55:21 +0000752 /*
753 * Save the current text.
754 */
755 if (cur != q) {
756 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
757 xmlNodeAddContentLen(last, q, cur - q);
758 } else {
759 node = xmlNewDocTextLen(doc, q, cur - q);
760 if (node == NULL) return(ret);
761 if (last == NULL)
762 last = ret = node;
763 else {
764 last->next = node;
765 node->prev = last;
766 last = node;
767 }
768 }
769 }
Owen Taylor3473f882001-02-23 17:55:21 +0000770 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000771 if ((cur[1] == '#') && (cur[2] == 'x')) {
772 cur += 3;
773 tmp = *cur;
774 while (tmp != ';') { /* Non input consuming loop */
775 if ((tmp >= '0') && (tmp <= '9'))
776 charval = charval * 16 + (tmp - '0');
777 else if ((tmp >= 'a') && (tmp <= 'f'))
778 charval = charval * 16 + (tmp - 'a') + 10;
779 else if ((tmp >= 'A') && (tmp <= 'F'))
780 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +0000781 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000782 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000783 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000784 charval = 0;
785 break;
786 }
787 cur++;
788 tmp = *cur;
789 }
790 if (tmp == ';')
791 cur++;
792 q = cur;
793 } else if (cur[1] == '#') {
794 cur += 2;
795 tmp = *cur;
796 while (tmp != ';') { /* Non input consuming loops */
797 if ((tmp >= '0') && (tmp <= '9'))
798 charval = charval * 10 + (tmp - '0');
799 else {
800 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000801 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000802 charval = 0;
803 break;
804 }
805 cur++;
806 tmp = *cur;
807 }
808 if (tmp == ';')
809 cur++;
810 q = cur;
811 } else {
812 /*
813 * Read the entity string
814 */
815 cur++;
816 q = cur;
817 while ((*cur != 0) && (*cur != ';')) cur++;
818 if (*cur == 0) {
819#ifdef DEBUG_TREE
820 xmlGenericError(xmlGenericErrorContext,
821 "xmlStringGetNodeList: unterminated entity %30s\n", q);
822#endif
823 return(ret);
824 }
825 if (cur != q) {
826 /*
827 * Predefined entities don't generate nodes
828 */
829 val = xmlStrndup(q, cur - q);
830 ent = xmlGetDocEntity(doc, val);
831 if ((ent != NULL) &&
832 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
833 if (last == NULL) {
834 node = xmlNewDocText(doc, ent->content);
835 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +0000836 } else if (last->type != XML_TEXT_NODE) {
837 node = xmlNewDocText(doc, ent->content);
838 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000839 } else
840 xmlNodeAddContent(last, ent->content);
841
842 } else {
843 /*
844 * Create a new REFERENCE_REF node
845 */
846 node = xmlNewReference(doc, val);
847 if (node == NULL) {
848 if (val != NULL) xmlFree(val);
849 return(ret);
850 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000851 else if ((ent != NULL) && (ent->children == NULL)) {
852 xmlNodePtr temp;
853
854 ent->children = xmlStringGetNodeList(doc,
855 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +0000856 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000857 temp = ent->children;
858 while (temp) {
859 temp->parent = (xmlNodePtr)ent;
860 temp = temp->next;
861 }
862 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000863 if (last == NULL) {
864 last = ret = node;
865 } else {
866 last = xmlAddNextSibling(last, node);
867 }
868 }
869 xmlFree(val);
870 }
871 cur++;
872 q = cur;
873 }
874 if (charval != 0) {
875 xmlChar buf[10];
876 int len;
877
878 len = xmlCopyCharMultiByte(buf, charval);
879 buf[len] = 0;
880 node = xmlNewDocText(doc, buf);
881 if (node != NULL) {
882 if (last == NULL) {
883 last = ret = node;
884 } else {
885 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000886 }
887 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000888
889 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000890 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000891 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000892 cur++;
893 }
Daniel Veillard75bea542001-05-11 17:41:21 +0000894 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000895 /*
896 * Handle the last piece of text.
897 */
898 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
899 xmlNodeAddContentLen(last, q, cur - q);
900 } else {
901 node = xmlNewDocTextLen(doc, q, cur - q);
902 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000903 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000904 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000905 } else {
906 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000907 }
908 }
909 }
910 return(ret);
911}
912
913/**
914 * xmlNodeListGetString:
915 * @doc: the document
916 * @list: a Node list
917 * @inLine: should we replace entity contents or show their external form
918 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000919 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +0000920 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000921 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +0000922 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +0000923 */
924xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +0000925xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
926{
Owen Taylor3473f882001-02-23 17:55:21 +0000927 xmlNodePtr node = list;
928 xmlChar *ret = NULL;
929 xmlEntityPtr ent;
930
Daniel Veillard7646b182002-04-20 06:41:40 +0000931 if (list == NULL)
932 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000933
934 while (node != NULL) {
935 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +0000936 (node->type == XML_CDATA_SECTION_NODE)) {
937 if (inLine) {
938 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000939 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +0000940 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +0000941
Daniel Veillard7646b182002-04-20 06:41:40 +0000942 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
943 if (buffer != NULL) {
944 ret = xmlStrcat(ret, buffer);
945 xmlFree(buffer);
946 }
947 }
948 } else if (node->type == XML_ENTITY_REF_NODE) {
949 if (inLine) {
950 ent = xmlGetDocEntity(doc, node->name);
951 if (ent != NULL) {
952 xmlChar *buffer;
953
954 /* an entity content can be any "well balanced chunk",
955 * i.e. the result of the content [43] production:
956 * http://www.w3.org/TR/REC-xml#NT-content.
957 * So it can contain text, CDATA section or nested
958 * entity reference nodes (among others).
959 * -> we recursive call xmlNodeListGetString()
960 * which handles these types */
961 buffer = xmlNodeListGetString(doc, ent->children, 1);
962 if (buffer != NULL) {
963 ret = xmlStrcat(ret, buffer);
964 xmlFree(buffer);
965 }
966 } else {
967 ret = xmlStrcat(ret, node->content);
968 }
969 } else {
970 xmlChar buf[2];
971
972 buf[0] = '&';
973 buf[1] = 0;
974 ret = xmlStrncat(ret, buf, 1);
975 ret = xmlStrcat(ret, node->name);
976 buf[0] = ';';
977 buf[1] = 0;
978 ret = xmlStrncat(ret, buf, 1);
979 }
980 }
981#if 0
982 else {
983 xmlGenericError(xmlGenericErrorContext,
984 "xmlGetNodeListString : invalid node type %d\n",
985 node->type);
986 }
987#endif
988 node = node->next;
989 }
990 return (ret);
991}
Owen Taylor3473f882001-02-23 17:55:21 +0000992/**
993 * xmlNodeListGetRawString:
994 * @doc: the document
995 * @list: a Node list
996 * @inLine: should we replace entity contents or show their external form
997 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000998 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +0000999 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1000 * this function doesn't do any character encoding handling.
1001 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001002 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001003 */
1004xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001005xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1006{
Owen Taylor3473f882001-02-23 17:55:21 +00001007 xmlNodePtr node = list;
1008 xmlChar *ret = NULL;
1009 xmlEntityPtr ent;
1010
Daniel Veillard7646b182002-04-20 06:41:40 +00001011 if (list == NULL)
1012 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001013
1014 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001015 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001016 (node->type == XML_CDATA_SECTION_NODE)) {
1017 if (inLine) {
1018 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001019 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001020 xmlChar *buffer;
1021
1022 buffer = xmlEncodeSpecialChars(doc, node->content);
1023 if (buffer != NULL) {
1024 ret = xmlStrcat(ret, buffer);
1025 xmlFree(buffer);
1026 }
1027 }
1028 } else if (node->type == XML_ENTITY_REF_NODE) {
1029 if (inLine) {
1030 ent = xmlGetDocEntity(doc, node->name);
1031 if (ent != NULL) {
1032 xmlChar *buffer;
1033
1034 /* an entity content can be any "well balanced chunk",
1035 * i.e. the result of the content [43] production:
1036 * http://www.w3.org/TR/REC-xml#NT-content.
1037 * So it can contain text, CDATA section or nested
1038 * entity reference nodes (among others).
1039 * -> we recursive call xmlNodeListGetRawString()
1040 * which handles these types */
1041 buffer =
1042 xmlNodeListGetRawString(doc, ent->children, 1);
1043 if (buffer != NULL) {
1044 ret = xmlStrcat(ret, buffer);
1045 xmlFree(buffer);
1046 }
1047 } else {
1048 ret = xmlStrcat(ret, node->content);
1049 }
1050 } else {
1051 xmlChar buf[2];
1052
1053 buf[0] = '&';
1054 buf[1] = 0;
1055 ret = xmlStrncat(ret, buf, 1);
1056 ret = xmlStrcat(ret, node->name);
1057 buf[0] = ';';
1058 buf[1] = 0;
1059 ret = xmlStrncat(ret, buf, 1);
1060 }
1061 }
Owen Taylor3473f882001-02-23 17:55:21 +00001062#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001063 else {
1064 xmlGenericError(xmlGenericErrorContext,
1065 "xmlGetNodeListString : invalid node type %d\n",
1066 node->type);
1067 }
Owen Taylor3473f882001-02-23 17:55:21 +00001068#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001069 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001070 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001071 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001072}
1073
1074/**
1075 * xmlNewProp:
1076 * @node: the holding node
1077 * @name: the name of the attribute
1078 * @value: the value of the attribute
1079 *
1080 * Create a new property carried by a node.
1081 * Returns a pointer to the attribute
1082 */
1083xmlAttrPtr
1084xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1085 xmlAttrPtr cur;
1086 xmlDocPtr doc = NULL;
1087
1088 if (name == NULL) {
1089#ifdef DEBUG_TREE
1090 xmlGenericError(xmlGenericErrorContext,
1091 "xmlNewProp : name == NULL\n");
1092#endif
1093 return(NULL);
1094 }
1095
1096 /*
1097 * Allocate a new property and fill the fields.
1098 */
1099 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1100 if (cur == NULL) {
1101 xmlGenericError(xmlGenericErrorContext,
1102 "xmlNewProp : malloc failed\n");
1103 return(NULL);
1104 }
1105 memset(cur, 0, sizeof(xmlAttr));
1106 cur->type = XML_ATTRIBUTE_NODE;
1107
1108 cur->parent = node;
1109 if (node != NULL) {
1110 doc = node->doc;
1111 cur->doc = doc;
1112 }
1113 cur->name = xmlStrdup(name);
1114 if (value != NULL) {
1115 xmlChar *buffer;
1116 xmlNodePtr tmp;
1117
1118 buffer = xmlEncodeEntitiesReentrant(doc, value);
1119 cur->children = xmlStringGetNodeList(doc, buffer);
1120 cur->last = NULL;
1121 tmp = cur->children;
1122 while (tmp != NULL) {
1123 tmp->parent = (xmlNodePtr) cur;
1124 tmp->doc = doc;
1125 if (tmp->next == NULL)
1126 cur->last = tmp;
1127 tmp = tmp->next;
1128 }
1129 xmlFree(buffer);
1130 }
1131
1132 /*
1133 * Add it at the end to preserve parsing order ...
1134 */
1135 if (node != NULL) {
1136 if (node->properties == NULL) {
1137 node->properties = cur;
1138 } else {
1139 xmlAttrPtr prev = node->properties;
1140
1141 while (prev->next != NULL) prev = prev->next;
1142 prev->next = cur;
1143 cur->prev = prev;
1144 }
1145 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001146
1147 if (xmlRegisterNodeDefaultValue)
1148 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001149 return(cur);
1150}
1151
1152/**
1153 * xmlNewNsProp:
1154 * @node: the holding node
1155 * @ns: the namespace
1156 * @name: the name of the attribute
1157 * @value: the value of the attribute
1158 *
1159 * Create a new property tagged with a namespace and carried by a node.
1160 * Returns a pointer to the attribute
1161 */
1162xmlAttrPtr
1163xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1164 const xmlChar *value) {
1165 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001166 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001167
1168 if (name == NULL) {
1169#ifdef DEBUG_TREE
1170 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001171 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001172#endif
1173 return(NULL);
1174 }
1175
1176 /*
1177 * Allocate a new property and fill the fields.
1178 */
1179 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1180 if (cur == NULL) {
1181 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001182 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001183 return(NULL);
1184 }
1185 memset(cur, 0, sizeof(xmlAttr));
1186 cur->type = XML_ATTRIBUTE_NODE;
1187
1188 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001189 if (node != NULL) {
1190 doc = node->doc;
1191 cur->doc = doc;
1192 }
Owen Taylor3473f882001-02-23 17:55:21 +00001193 cur->ns = ns;
1194 cur->name = xmlStrdup(name);
1195 if (value != NULL) {
1196 xmlChar *buffer;
1197 xmlNodePtr tmp;
1198
Daniel Veillarda682b212001-06-07 19:59:42 +00001199 buffer = xmlEncodeEntitiesReentrant(doc, value);
1200 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001201 cur->last = NULL;
1202 tmp = cur->children;
1203 while (tmp != NULL) {
1204 tmp->parent = (xmlNodePtr) cur;
1205 if (tmp->next == NULL)
1206 cur->last = tmp;
1207 tmp = tmp->next;
1208 }
1209 xmlFree(buffer);
1210 }
1211
1212 /*
1213 * Add it at the end to preserve parsing order ...
1214 */
1215 if (node != NULL) {
1216 if (node->properties == NULL) {
1217 node->properties = cur;
1218 } else {
1219 xmlAttrPtr prev = node->properties;
1220
1221 while (prev->next != NULL) prev = prev->next;
1222 prev->next = cur;
1223 cur->prev = prev;
1224 }
1225 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001226
1227 if (xmlRegisterNodeDefaultValue)
1228 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001229 return(cur);
1230}
1231
1232/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001233 * xmlNewNsPropEatName:
1234 * @node: the holding node
1235 * @ns: the namespace
1236 * @name: the name of the attribute
1237 * @value: the value of the attribute
1238 *
1239 * Create a new property tagged with a namespace and carried by a node.
1240 * Returns a pointer to the attribute
1241 */
1242xmlAttrPtr
1243xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1244 const xmlChar *value) {
1245 xmlAttrPtr cur;
1246 xmlDocPtr doc = NULL;
1247
1248 if (name == NULL) {
1249#ifdef DEBUG_TREE
1250 xmlGenericError(xmlGenericErrorContext,
1251 "xmlNewNsPropEatName : name == NULL\n");
1252#endif
1253 return(NULL);
1254 }
1255
1256 /*
1257 * Allocate a new property and fill the fields.
1258 */
1259 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1260 if (cur == NULL) {
1261 xmlGenericError(xmlGenericErrorContext,
1262 "xmlNewNsPropEatName : malloc failed\n");
1263 return(NULL);
1264 }
1265 memset(cur, 0, sizeof(xmlAttr));
1266 cur->type = XML_ATTRIBUTE_NODE;
1267
1268 cur->parent = node;
1269 if (node != NULL) {
1270 doc = node->doc;
1271 cur->doc = doc;
1272 }
1273 cur->ns = ns;
1274 cur->name = name;
1275 if (value != NULL) {
1276 xmlChar *buffer;
1277 xmlNodePtr tmp;
1278
1279 buffer = xmlEncodeEntitiesReentrant(doc, value);
1280 cur->children = xmlStringGetNodeList(doc, buffer);
1281 cur->last = NULL;
1282 tmp = cur->children;
1283 while (tmp != NULL) {
1284 tmp->parent = (xmlNodePtr) cur;
1285 if (tmp->next == NULL)
1286 cur->last = tmp;
1287 tmp = tmp->next;
1288 }
1289 xmlFree(buffer);
1290 }
1291
1292 /*
1293 * Add it at the end to preserve parsing order ...
1294 */
1295 if (node != NULL) {
1296 if (node->properties == NULL) {
1297 node->properties = cur;
1298 } else {
1299 xmlAttrPtr prev = node->properties;
1300
1301 while (prev->next != NULL) prev = prev->next;
1302 prev->next = cur;
1303 cur->prev = prev;
1304 }
1305 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001306
1307 if (xmlRegisterNodeDefaultValue)
1308 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001309 return(cur);
1310}
1311
1312/**
Owen Taylor3473f882001-02-23 17:55:21 +00001313 * xmlNewDocProp:
1314 * @doc: the document
1315 * @name: the name of the attribute
1316 * @value: the value of the attribute
1317 *
1318 * Create a new property carried by a document.
1319 * Returns a pointer to the attribute
1320 */
1321xmlAttrPtr
1322xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1323 xmlAttrPtr cur;
1324
1325 if (name == NULL) {
1326#ifdef DEBUG_TREE
1327 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001328 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001329#endif
1330 return(NULL);
1331 }
1332
1333 /*
1334 * Allocate a new property and fill the fields.
1335 */
1336 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1337 if (cur == NULL) {
1338 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001339 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001340 return(NULL);
1341 }
1342 memset(cur, 0, sizeof(xmlAttr));
1343 cur->type = XML_ATTRIBUTE_NODE;
1344
1345 cur->name = xmlStrdup(name);
1346 cur->doc = doc;
1347 if (value != NULL) {
1348 xmlNodePtr tmp;
1349
1350 cur->children = xmlStringGetNodeList(doc, value);
1351 cur->last = NULL;
1352
1353 tmp = cur->children;
1354 while (tmp != NULL) {
1355 tmp->parent = (xmlNodePtr) cur;
1356 if (tmp->next == NULL)
1357 cur->last = tmp;
1358 tmp = tmp->next;
1359 }
1360 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001361
1362 if (xmlRegisterNodeDefaultValue)
1363 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001364 return(cur);
1365}
1366
1367/**
1368 * xmlFreePropList:
1369 * @cur: the first property in the list
1370 *
1371 * Free a property and all its siblings, all the children are freed too.
1372 */
1373void
1374xmlFreePropList(xmlAttrPtr cur) {
1375 xmlAttrPtr next;
1376 if (cur == NULL) {
1377#ifdef DEBUG_TREE
1378 xmlGenericError(xmlGenericErrorContext,
1379 "xmlFreePropList : property == NULL\n");
1380#endif
1381 return;
1382 }
1383 while (cur != NULL) {
1384 next = cur->next;
1385 xmlFreeProp(cur);
1386 cur = next;
1387 }
1388}
1389
1390/**
1391 * xmlFreeProp:
1392 * @cur: an attribute
1393 *
1394 * Free one attribute, all the content is freed too
1395 */
1396void
1397xmlFreeProp(xmlAttrPtr cur) {
1398 if (cur == NULL) {
1399#ifdef DEBUG_TREE
1400 xmlGenericError(xmlGenericErrorContext,
1401 "xmlFreeProp : property == NULL\n");
1402#endif
1403 return;
1404 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001405
1406 if (xmlDeregisterNodeDefaultValue)
1407 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1408
Owen Taylor3473f882001-02-23 17:55:21 +00001409 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001410 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1411 ((cur->parent->doc->intSubset != NULL) ||
1412 (cur->parent->doc->extSubset != NULL))) {
1413 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1414 xmlRemoveID(cur->parent->doc, cur);
1415 }
Owen Taylor3473f882001-02-23 17:55:21 +00001416 if (cur->name != NULL) xmlFree((char *) cur->name);
1417 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001418 xmlFree(cur);
1419}
1420
1421/**
1422 * xmlRemoveProp:
1423 * @cur: an attribute
1424 *
1425 * Unlink and free one attribute, all the content is freed too
1426 * Note this doesn't work for namespace definition attributes
1427 *
1428 * Returns 0 if success and -1 in case of error.
1429 */
1430int
1431xmlRemoveProp(xmlAttrPtr cur) {
1432 xmlAttrPtr tmp;
1433 if (cur == NULL) {
1434#ifdef DEBUG_TREE
1435 xmlGenericError(xmlGenericErrorContext,
1436 "xmlRemoveProp : cur == NULL\n");
1437#endif
1438 return(-1);
1439 }
1440 if (cur->parent == NULL) {
1441#ifdef DEBUG_TREE
1442 xmlGenericError(xmlGenericErrorContext,
1443 "xmlRemoveProp : cur->parent == NULL\n");
1444#endif
1445 return(-1);
1446 }
1447 tmp = cur->parent->properties;
1448 if (tmp == cur) {
1449 cur->parent->properties = cur->next;
1450 xmlFreeProp(cur);
1451 return(0);
1452 }
1453 while (tmp != NULL) {
1454 if (tmp->next == cur) {
1455 tmp->next = cur->next;
1456 if (tmp->next != NULL)
1457 tmp->next->prev = tmp;
1458 xmlFreeProp(cur);
1459 return(0);
1460 }
1461 tmp = tmp->next;
1462 }
1463#ifdef DEBUG_TREE
1464 xmlGenericError(xmlGenericErrorContext,
1465 "xmlRemoveProp : attribute not owned by its node\n");
1466#endif
1467 return(-1);
1468}
1469
1470/**
1471 * xmlNewPI:
1472 * @name: the processing instruction name
1473 * @content: the PI content
1474 *
1475 * Creation of a processing instruction element.
1476 * Returns a pointer to the new node object.
1477 */
1478xmlNodePtr
1479xmlNewPI(const xmlChar *name, const xmlChar *content) {
1480 xmlNodePtr cur;
1481
1482 if (name == NULL) {
1483#ifdef DEBUG_TREE
1484 xmlGenericError(xmlGenericErrorContext,
1485 "xmlNewPI : 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 "xmlNewPI : malloc failed\n");
1497 return(NULL);
1498 }
1499 memset(cur, 0, sizeof(xmlNode));
1500 cur->type = XML_PI_NODE;
1501
1502 cur->name = xmlStrdup(name);
1503 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001504 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001505 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001506
1507 if (xmlRegisterNodeDefaultValue)
1508 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001509 return(cur);
1510}
1511
1512/**
1513 * xmlNewNode:
1514 * @ns: namespace if any
1515 * @name: the node name
1516 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001517 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001518 *
1519 * Returns a pointer to the new node object.
1520 */
1521xmlNodePtr
1522xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1523 xmlNodePtr cur;
1524
1525 if (name == NULL) {
1526#ifdef DEBUG_TREE
1527 xmlGenericError(xmlGenericErrorContext,
1528 "xmlNewNode : name == NULL\n");
1529#endif
1530 return(NULL);
1531 }
1532
1533 /*
1534 * Allocate a new node and fill the fields.
1535 */
1536 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1537 if (cur == NULL) {
1538 xmlGenericError(xmlGenericErrorContext,
1539 "xmlNewNode : malloc failed\n");
1540 return(NULL);
1541 }
1542 memset(cur, 0, sizeof(xmlNode));
1543 cur->type = XML_ELEMENT_NODE;
1544
1545 cur->name = xmlStrdup(name);
1546 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001547
1548 if (xmlRegisterNodeDefaultValue)
1549 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001550 return(cur);
1551}
1552
1553/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001554 * xmlNewNodeEatName:
1555 * @ns: namespace if any
1556 * @name: the node name
1557 *
1558 * Creation of a new node element. @ns is optional (NULL).
1559 *
1560 * Returns a pointer to the new node object.
1561 */
1562xmlNodePtr
1563xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
1564 xmlNodePtr cur;
1565
1566 if (name == NULL) {
1567#ifdef DEBUG_TREE
1568 xmlGenericError(xmlGenericErrorContext,
1569 "xmlNewNode : name == NULL\n");
1570#endif
1571 return(NULL);
1572 }
1573
1574 /*
1575 * Allocate a new node and fill the fields.
1576 */
1577 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1578 if (cur == NULL) {
1579 xmlGenericError(xmlGenericErrorContext,
1580 "xmlNewNode : malloc failed\n");
1581 return(NULL);
1582 }
1583 memset(cur, 0, sizeof(xmlNode));
1584 cur->type = XML_ELEMENT_NODE;
1585
1586 cur->name = name;
1587 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001588
1589 if (xmlRegisterNodeDefaultValue)
1590 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001591 return(cur);
1592}
1593
1594/**
Owen Taylor3473f882001-02-23 17:55:21 +00001595 * xmlNewDocNode:
1596 * @doc: the document
1597 * @ns: namespace if any
1598 * @name: the node name
1599 * @content: the XML text content if any
1600 *
1601 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001602 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001603 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1604 * references, but XML special chars need to be escaped first by using
1605 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1606 * need entities support.
1607 *
1608 * Returns a pointer to the new node object.
1609 */
1610xmlNodePtr
1611xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1612 const xmlChar *name, const xmlChar *content) {
1613 xmlNodePtr cur;
1614
1615 cur = xmlNewNode(ns, name);
1616 if (cur != NULL) {
1617 cur->doc = doc;
1618 if (content != NULL) {
1619 cur->children = xmlStringGetNodeList(doc, content);
1620 UPDATE_LAST_CHILD_AND_PARENT(cur)
1621 }
1622 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001623
Owen Taylor3473f882001-02-23 17:55:21 +00001624 return(cur);
1625}
1626
Daniel Veillard46de64e2002-05-29 08:21:33 +00001627/**
1628 * xmlNewDocNodeEatName:
1629 * @doc: the document
1630 * @ns: namespace if any
1631 * @name: the node name
1632 * @content: the XML text content if any
1633 *
1634 * Creation of a new node element within a document. @ns and @content
1635 * are optional (NULL).
1636 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1637 * references, but XML special chars need to be escaped first by using
1638 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1639 * need entities support.
1640 *
1641 * Returns a pointer to the new node object.
1642 */
1643xmlNodePtr
1644xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
1645 xmlChar *name, const xmlChar *content) {
1646 xmlNodePtr cur;
1647
1648 cur = xmlNewNodeEatName(ns, name);
1649 if (cur != NULL) {
1650 cur->doc = doc;
1651 if (content != NULL) {
1652 cur->children = xmlStringGetNodeList(doc, content);
1653 UPDATE_LAST_CHILD_AND_PARENT(cur)
1654 }
1655 }
1656 return(cur);
1657}
1658
Owen Taylor3473f882001-02-23 17:55:21 +00001659
1660/**
1661 * xmlNewDocRawNode:
1662 * @doc: the document
1663 * @ns: namespace if any
1664 * @name: the node name
1665 * @content: the text content if any
1666 *
1667 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001668 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001669 *
1670 * Returns a pointer to the new node object.
1671 */
1672xmlNodePtr
1673xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1674 const xmlChar *name, const xmlChar *content) {
1675 xmlNodePtr cur;
1676
1677 cur = xmlNewNode(ns, name);
1678 if (cur != NULL) {
1679 cur->doc = doc;
1680 if (content != NULL) {
1681 cur->children = xmlNewDocText(doc, content);
1682 UPDATE_LAST_CHILD_AND_PARENT(cur)
1683 }
1684 }
1685 return(cur);
1686}
1687
1688/**
1689 * xmlNewDocFragment:
1690 * @doc: the document owning the fragment
1691 *
1692 * Creation of a new Fragment node.
1693 * Returns a pointer to the new node object.
1694 */
1695xmlNodePtr
1696xmlNewDocFragment(xmlDocPtr doc) {
1697 xmlNodePtr cur;
1698
1699 /*
1700 * Allocate a new DocumentFragment node and fill the fields.
1701 */
1702 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1703 if (cur == NULL) {
1704 xmlGenericError(xmlGenericErrorContext,
1705 "xmlNewDocFragment : malloc failed\n");
1706 return(NULL);
1707 }
1708 memset(cur, 0, sizeof(xmlNode));
1709 cur->type = XML_DOCUMENT_FRAG_NODE;
1710
1711 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001712
1713 if (xmlRegisterNodeDefaultValue)
1714 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001715 return(cur);
1716}
1717
1718/**
1719 * xmlNewText:
1720 * @content: the text content
1721 *
1722 * Creation of a new text node.
1723 * Returns a pointer to the new node object.
1724 */
1725xmlNodePtr
1726xmlNewText(const xmlChar *content) {
1727 xmlNodePtr cur;
1728
1729 /*
1730 * Allocate a new node and fill the fields.
1731 */
1732 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1733 if (cur == NULL) {
1734 xmlGenericError(xmlGenericErrorContext,
1735 "xmlNewText : malloc failed\n");
1736 return(NULL);
1737 }
1738 memset(cur, 0, sizeof(xmlNode));
1739 cur->type = XML_TEXT_NODE;
1740
1741 cur->name = xmlStringText;
1742 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001743 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001744 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001745
1746 if (xmlRegisterNodeDefaultValue)
1747 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001748 return(cur);
1749}
1750
1751/**
1752 * xmlNewTextChild:
1753 * @parent: the parent node
1754 * @ns: a namespace if any
1755 * @name: the name of the child
1756 * @content: the text content of the child if any.
1757 *
1758 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001759 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001760 * a child TEXT node will be created containing the string content.
1761 *
1762 * Returns a pointer to the new node object.
1763 */
1764xmlNodePtr
1765xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1766 const xmlChar *name, const xmlChar *content) {
1767 xmlNodePtr cur, prev;
1768
1769 if (parent == NULL) {
1770#ifdef DEBUG_TREE
1771 xmlGenericError(xmlGenericErrorContext,
1772 "xmlNewTextChild : parent == NULL\n");
1773#endif
1774 return(NULL);
1775 }
1776
1777 if (name == NULL) {
1778#ifdef DEBUG_TREE
1779 xmlGenericError(xmlGenericErrorContext,
1780 "xmlNewTextChild : name == NULL\n");
1781#endif
1782 return(NULL);
1783 }
1784
1785 /*
1786 * Allocate a new node
1787 */
1788 if (ns == NULL)
1789 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1790 else
1791 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1792 if (cur == NULL) return(NULL);
1793
1794 /*
1795 * add the new element at the end of the children list.
1796 */
1797 cur->type = XML_ELEMENT_NODE;
1798 cur->parent = parent;
1799 cur->doc = parent->doc;
1800 if (parent->children == NULL) {
1801 parent->children = cur;
1802 parent->last = cur;
1803 } else {
1804 prev = parent->last;
1805 prev->next = cur;
1806 cur->prev = prev;
1807 parent->last = cur;
1808 }
1809
1810 return(cur);
1811}
1812
1813/**
1814 * xmlNewCharRef:
1815 * @doc: the document
1816 * @name: the char ref string, starting with # or "&# ... ;"
1817 *
1818 * Creation of a new character reference node.
1819 * Returns a pointer to the new node object.
1820 */
1821xmlNodePtr
1822xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1823 xmlNodePtr cur;
1824
1825 /*
1826 * Allocate a new node and fill the fields.
1827 */
1828 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1829 if (cur == NULL) {
1830 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001831 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001832 return(NULL);
1833 }
1834 memset(cur, 0, sizeof(xmlNode));
1835 cur->type = XML_ENTITY_REF_NODE;
1836
1837 cur->doc = doc;
1838 if (name[0] == '&') {
1839 int len;
1840 name++;
1841 len = xmlStrlen(name);
1842 if (name[len - 1] == ';')
1843 cur->name = xmlStrndup(name, len - 1);
1844 else
1845 cur->name = xmlStrndup(name, len);
1846 } else
1847 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00001848
1849 if (xmlRegisterNodeDefaultValue)
1850 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001851 return(cur);
1852}
1853
1854/**
1855 * xmlNewReference:
1856 * @doc: the document
1857 * @name: the reference name, or the reference string with & and ;
1858 *
1859 * Creation of a new reference node.
1860 * Returns a pointer to the new node object.
1861 */
1862xmlNodePtr
1863xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1864 xmlNodePtr cur;
1865 xmlEntityPtr ent;
1866
1867 /*
1868 * Allocate a new node and fill the fields.
1869 */
1870 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1871 if (cur == NULL) {
1872 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001873 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001874 return(NULL);
1875 }
1876 memset(cur, 0, sizeof(xmlNode));
1877 cur->type = XML_ENTITY_REF_NODE;
1878
1879 cur->doc = doc;
1880 if (name[0] == '&') {
1881 int len;
1882 name++;
1883 len = xmlStrlen(name);
1884 if (name[len - 1] == ';')
1885 cur->name = xmlStrndup(name, len - 1);
1886 else
1887 cur->name = xmlStrndup(name, len);
1888 } else
1889 cur->name = xmlStrdup(name);
1890
1891 ent = xmlGetDocEntity(doc, cur->name);
1892 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001893 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00001894 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001895 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00001896 * updated. Not sure if this is 100% correct.
1897 * -George
1898 */
1899 cur->children = (xmlNodePtr) ent;
1900 cur->last = (xmlNodePtr) ent;
1901 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001902
1903 if (xmlRegisterNodeDefaultValue)
1904 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001905 return(cur);
1906}
1907
1908/**
1909 * xmlNewDocText:
1910 * @doc: the document
1911 * @content: the text content
1912 *
1913 * Creation of a new text node within a document.
1914 * Returns a pointer to the new node object.
1915 */
1916xmlNodePtr
1917xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1918 xmlNodePtr cur;
1919
1920 cur = xmlNewText(content);
1921 if (cur != NULL) cur->doc = doc;
1922 return(cur);
1923}
1924
1925/**
1926 * xmlNewTextLen:
1927 * @content: the text content
1928 * @len: the text len.
1929 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001930 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00001931 * Returns a pointer to the new node object.
1932 */
1933xmlNodePtr
1934xmlNewTextLen(const xmlChar *content, int len) {
1935 xmlNodePtr cur;
1936
1937 /*
1938 * Allocate a new node and fill the fields.
1939 */
1940 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1941 if (cur == NULL) {
1942 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001943 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001944 return(NULL);
1945 }
1946 memset(cur, 0, sizeof(xmlNode));
1947 cur->type = XML_TEXT_NODE;
1948
1949 cur->name = xmlStringText;
1950 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001951 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001952 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001953
1954 if (xmlRegisterNodeDefaultValue)
1955 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001956 return(cur);
1957}
1958
1959/**
1960 * xmlNewDocTextLen:
1961 * @doc: the document
1962 * @content: the text content
1963 * @len: the text len.
1964 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001965 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00001966 * text node pertain to a given document.
1967 * Returns a pointer to the new node object.
1968 */
1969xmlNodePtr
1970xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1971 xmlNodePtr cur;
1972
1973 cur = xmlNewTextLen(content, len);
1974 if (cur != NULL) cur->doc = doc;
1975 return(cur);
1976}
1977
1978/**
1979 * xmlNewComment:
1980 * @content: the comment content
1981 *
1982 * Creation of a new node containing a comment.
1983 * Returns a pointer to the new node object.
1984 */
1985xmlNodePtr
1986xmlNewComment(const xmlChar *content) {
1987 xmlNodePtr cur;
1988
1989 /*
1990 * Allocate a new node and fill the fields.
1991 */
1992 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1993 if (cur == NULL) {
1994 xmlGenericError(xmlGenericErrorContext,
1995 "xmlNewComment : malloc failed\n");
1996 return(NULL);
1997 }
1998 memset(cur, 0, sizeof(xmlNode));
1999 cur->type = XML_COMMENT_NODE;
2000
2001 cur->name = xmlStringComment;
2002 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002003 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002004 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002005
2006 if (xmlRegisterNodeDefaultValue)
2007 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002008 return(cur);
2009}
2010
2011/**
2012 * xmlNewCDataBlock:
2013 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002014 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002015 * @len: the length of the block
2016 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002017 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002018 * Returns a pointer to the new node object.
2019 */
2020xmlNodePtr
2021xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2022 xmlNodePtr cur;
2023
2024 /*
2025 * Allocate a new node and fill the fields.
2026 */
2027 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2028 if (cur == NULL) {
2029 xmlGenericError(xmlGenericErrorContext,
2030 "xmlNewCDataBlock : malloc failed\n");
2031 return(NULL);
2032 }
2033 memset(cur, 0, sizeof(xmlNode));
2034 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002035 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002036
2037 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002038 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002039 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002040
2041 if (xmlRegisterNodeDefaultValue)
2042 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002043 return(cur);
2044}
2045
2046/**
2047 * xmlNewDocComment:
2048 * @doc: the document
2049 * @content: the comment content
2050 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002051 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002052 * Returns a pointer to the new node object.
2053 */
2054xmlNodePtr
2055xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2056 xmlNodePtr cur;
2057
2058 cur = xmlNewComment(content);
2059 if (cur != NULL) cur->doc = doc;
2060 return(cur);
2061}
2062
2063/**
2064 * xmlSetTreeDoc:
2065 * @tree: the top element
2066 * @doc: the document
2067 *
2068 * update all nodes under the tree to point to the right document
2069 */
2070void
2071xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002072 xmlAttrPtr prop;
2073
Owen Taylor3473f882001-02-23 17:55:21 +00002074 if (tree == NULL)
2075 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002076 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002077 if(tree->type == XML_ELEMENT_NODE) {
2078 prop = tree->properties;
2079 while (prop != NULL) {
2080 prop->doc = doc;
2081 xmlSetListDoc(prop->children, doc);
2082 prop = prop->next;
2083 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002084 }
Owen Taylor3473f882001-02-23 17:55:21 +00002085 if (tree->children != NULL)
2086 xmlSetListDoc(tree->children, doc);
2087 tree->doc = doc;
2088 }
2089}
2090
2091/**
2092 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002093 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002094 * @doc: the document
2095 *
2096 * update all nodes in the list to point to the right document
2097 */
2098void
2099xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2100 xmlNodePtr cur;
2101
2102 if (list == NULL)
2103 return;
2104 cur = list;
2105 while (cur != NULL) {
2106 if (cur->doc != doc)
2107 xmlSetTreeDoc(cur, doc);
2108 cur = cur->next;
2109 }
2110}
2111
2112
2113/**
2114 * xmlNewChild:
2115 * @parent: the parent node
2116 * @ns: a namespace if any
2117 * @name: the name of the child
2118 * @content: the XML content of the child if any.
2119 *
2120 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002121 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002122 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2123 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2124 * references, but XML special chars need to be escaped first by using
2125 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2126 * support is not needed.
2127 *
2128 * Returns a pointer to the new node object.
2129 */
2130xmlNodePtr
2131xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2132 const xmlChar *name, const xmlChar *content) {
2133 xmlNodePtr cur, prev;
2134
2135 if (parent == NULL) {
2136#ifdef DEBUG_TREE
2137 xmlGenericError(xmlGenericErrorContext,
2138 "xmlNewChild : parent == NULL\n");
2139#endif
2140 return(NULL);
2141 }
2142
2143 if (name == NULL) {
2144#ifdef DEBUG_TREE
2145 xmlGenericError(xmlGenericErrorContext,
2146 "xmlNewChild : name == NULL\n");
2147#endif
2148 return(NULL);
2149 }
2150
2151 /*
2152 * Allocate a new node
2153 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002154 if (parent->type == XML_ELEMENT_NODE) {
2155 if (ns == NULL)
2156 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2157 else
2158 cur = xmlNewDocNode(parent->doc, ns, name, content);
2159 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2160 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2161 if (ns == NULL)
2162 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2163 else
2164 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002165 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2166 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002167 } else {
2168 return(NULL);
2169 }
Owen Taylor3473f882001-02-23 17:55:21 +00002170 if (cur == NULL) return(NULL);
2171
2172 /*
2173 * add the new element at the end of the children list.
2174 */
2175 cur->type = XML_ELEMENT_NODE;
2176 cur->parent = parent;
2177 cur->doc = parent->doc;
2178 if (parent->children == NULL) {
2179 parent->children = cur;
2180 parent->last = cur;
2181 } else {
2182 prev = parent->last;
2183 prev->next = cur;
2184 cur->prev = prev;
2185 parent->last = cur;
2186 }
2187
2188 return(cur);
2189}
2190
2191/**
2192 * xmlAddNextSibling:
2193 * @cur: the child node
2194 * @elem: the new node
2195 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002196 * Add a new node @elem as the next sibling of @cur
2197 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002198 * first unlinked from its existing context.
2199 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002200 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2201 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002202 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002203 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002204 */
2205xmlNodePtr
2206xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2207 if (cur == NULL) {
2208#ifdef DEBUG_TREE
2209 xmlGenericError(xmlGenericErrorContext,
2210 "xmlAddNextSibling : cur == NULL\n");
2211#endif
2212 return(NULL);
2213 }
2214 if (elem == NULL) {
2215#ifdef DEBUG_TREE
2216 xmlGenericError(xmlGenericErrorContext,
2217 "xmlAddNextSibling : elem == NULL\n");
2218#endif
2219 return(NULL);
2220 }
2221
2222 xmlUnlinkNode(elem);
2223
2224 if (elem->type == XML_TEXT_NODE) {
2225 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002226 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002227 xmlFreeNode(elem);
2228 return(cur);
2229 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002230 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2231 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002232 xmlChar *tmp;
2233
2234 tmp = xmlStrdup(elem->content);
2235 tmp = xmlStrcat(tmp, cur->next->content);
2236 xmlNodeSetContent(cur->next, tmp);
2237 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002238 xmlFreeNode(elem);
2239 return(cur->next);
2240 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002241 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2242 /* check if an attribute with the same name exists */
2243 xmlAttrPtr attr;
2244
2245 if (elem->ns == NULL)
2246 attr = xmlHasProp(cur->parent, elem->name);
2247 else
2248 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2249 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2250 /* different instance, destroy it (attributes must be unique) */
2251 xmlFreeProp(attr);
2252 }
Owen Taylor3473f882001-02-23 17:55:21 +00002253 }
2254
2255 if (elem->doc != cur->doc) {
2256 xmlSetTreeDoc(elem, cur->doc);
2257 }
2258 elem->parent = cur->parent;
2259 elem->prev = cur;
2260 elem->next = cur->next;
2261 cur->next = elem;
2262 if (elem->next != NULL)
2263 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002264 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002265 elem->parent->last = elem;
2266 return(elem);
2267}
2268
2269/**
2270 * xmlAddPrevSibling:
2271 * @cur: the child node
2272 * @elem: the new node
2273 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002274 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002275 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002276 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002277 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002278 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2279 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002280 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002281 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002282 */
2283xmlNodePtr
2284xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2285 if (cur == NULL) {
2286#ifdef DEBUG_TREE
2287 xmlGenericError(xmlGenericErrorContext,
2288 "xmlAddPrevSibling : cur == NULL\n");
2289#endif
2290 return(NULL);
2291 }
2292 if (elem == NULL) {
2293#ifdef DEBUG_TREE
2294 xmlGenericError(xmlGenericErrorContext,
2295 "xmlAddPrevSibling : elem == NULL\n");
2296#endif
2297 return(NULL);
2298 }
2299
2300 xmlUnlinkNode(elem);
2301
2302 if (elem->type == XML_TEXT_NODE) {
2303 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002304 xmlChar *tmp;
2305
2306 tmp = xmlStrdup(elem->content);
2307 tmp = xmlStrcat(tmp, cur->content);
2308 xmlNodeSetContent(cur, tmp);
2309 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002310 xmlFreeNode(elem);
2311 return(cur);
2312 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002313 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2314 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002315 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002316 xmlFreeNode(elem);
2317 return(cur->prev);
2318 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002319 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2320 /* check if an attribute with the same name exists */
2321 xmlAttrPtr attr;
2322
2323 if (elem->ns == NULL)
2324 attr = xmlHasProp(cur->parent, elem->name);
2325 else
2326 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2327 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2328 /* different instance, destroy it (attributes must be unique) */
2329 xmlFreeProp(attr);
2330 }
Owen Taylor3473f882001-02-23 17:55:21 +00002331 }
2332
2333 if (elem->doc != cur->doc) {
2334 xmlSetTreeDoc(elem, cur->doc);
2335 }
2336 elem->parent = cur->parent;
2337 elem->next = cur;
2338 elem->prev = cur->prev;
2339 cur->prev = elem;
2340 if (elem->prev != NULL)
2341 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002342 if (elem->parent != NULL) {
2343 if (elem->type == XML_ATTRIBUTE_NODE) {
2344 if (elem->parent->properties == (xmlAttrPtr) cur) {
2345 elem->parent->properties = (xmlAttrPtr) elem;
2346 }
2347 } else {
2348 if (elem->parent->children == cur) {
2349 elem->parent->children = elem;
2350 }
2351 }
2352 }
Owen Taylor3473f882001-02-23 17:55:21 +00002353 return(elem);
2354}
2355
2356/**
2357 * xmlAddSibling:
2358 * @cur: the child node
2359 * @elem: the new node
2360 *
2361 * Add a new element @elem to the list of siblings of @cur
2362 * merging adjacent TEXT nodes (@elem may be freed)
2363 * If the new element was already inserted in a document it is
2364 * first unlinked from its existing context.
2365 *
2366 * Returns the new element or NULL in case of error.
2367 */
2368xmlNodePtr
2369xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2370 xmlNodePtr parent;
2371
2372 if (cur == NULL) {
2373#ifdef DEBUG_TREE
2374 xmlGenericError(xmlGenericErrorContext,
2375 "xmlAddSibling : cur == NULL\n");
2376#endif
2377 return(NULL);
2378 }
2379
2380 if (elem == NULL) {
2381#ifdef DEBUG_TREE
2382 xmlGenericError(xmlGenericErrorContext,
2383 "xmlAddSibling : elem == NULL\n");
2384#endif
2385 return(NULL);
2386 }
2387
2388 /*
2389 * Constant time is we can rely on the ->parent->last to find
2390 * the last sibling.
2391 */
2392 if ((cur->parent != NULL) &&
2393 (cur->parent->children != NULL) &&
2394 (cur->parent->last != NULL) &&
2395 (cur->parent->last->next == NULL)) {
2396 cur = cur->parent->last;
2397 } else {
2398 while (cur->next != NULL) cur = cur->next;
2399 }
2400
2401 xmlUnlinkNode(elem);
2402
2403 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002404 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002405 xmlFreeNode(elem);
2406 return(cur);
2407 }
2408
2409 if (elem->doc != cur->doc) {
2410 xmlSetTreeDoc(elem, cur->doc);
2411 }
2412 parent = cur->parent;
2413 elem->prev = cur;
2414 elem->next = NULL;
2415 elem->parent = parent;
2416 cur->next = elem;
2417 if (parent != NULL)
2418 parent->last = elem;
2419
2420 return(elem);
2421}
2422
2423/**
2424 * xmlAddChildList:
2425 * @parent: the parent node
2426 * @cur: the first node in the list
2427 *
2428 * Add a list of node at the end of the child list of the parent
2429 * merging adjacent TEXT nodes (@cur may be freed)
2430 *
2431 * Returns the last child or NULL in case of error.
2432 */
2433xmlNodePtr
2434xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2435 xmlNodePtr prev;
2436
2437 if (parent == NULL) {
2438#ifdef DEBUG_TREE
2439 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002440 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002441#endif
2442 return(NULL);
2443 }
2444
2445 if (cur == NULL) {
2446#ifdef DEBUG_TREE
2447 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002448 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002449#endif
2450 return(NULL);
2451 }
2452
2453 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2454 (cur->doc != parent->doc)) {
2455#ifdef DEBUG_TREE
2456 xmlGenericError(xmlGenericErrorContext,
2457 "Elements moved to a different document\n");
2458#endif
2459 }
2460
2461 /*
2462 * add the first element at the end of the children list.
2463 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002464
Owen Taylor3473f882001-02-23 17:55:21 +00002465 if (parent->children == NULL) {
2466 parent->children = cur;
2467 } else {
2468 /*
2469 * If cur and parent->last both are TEXT nodes, then merge them.
2470 */
2471 if ((cur->type == XML_TEXT_NODE) &&
2472 (parent->last->type == XML_TEXT_NODE) &&
2473 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00002474 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002475 /*
2476 * if it's the only child, nothing more to be done.
2477 */
2478 if (cur->next == NULL) {
2479 xmlFreeNode(cur);
2480 return(parent->last);
2481 }
2482 prev = cur;
2483 cur = cur->next;
2484 xmlFreeNode(prev);
2485 }
2486 prev = parent->last;
2487 prev->next = cur;
2488 cur->prev = prev;
2489 }
2490 while (cur->next != NULL) {
2491 cur->parent = parent;
2492 if (cur->doc != parent->doc) {
2493 xmlSetTreeDoc(cur, parent->doc);
2494 }
2495 cur = cur->next;
2496 }
2497 cur->parent = parent;
2498 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2499 parent->last = cur;
2500
2501 return(cur);
2502}
2503
2504/**
2505 * xmlAddChild:
2506 * @parent: the parent node
2507 * @cur: the child node
2508 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002509 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002510 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002511 * If the new node was already inserted in a document it is
2512 * first unlinked from its existing context.
2513 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2514 * If there is an attribute with equal name, it is first destroyed.
2515 *
Owen Taylor3473f882001-02-23 17:55:21 +00002516 * Returns the child or NULL in case of error.
2517 */
2518xmlNodePtr
2519xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2520 xmlNodePtr prev;
2521
2522 if (parent == NULL) {
2523#ifdef DEBUG_TREE
2524 xmlGenericError(xmlGenericErrorContext,
2525 "xmlAddChild : parent == NULL\n");
2526#endif
2527 return(NULL);
2528 }
2529
2530 if (cur == NULL) {
2531#ifdef DEBUG_TREE
2532 xmlGenericError(xmlGenericErrorContext,
2533 "xmlAddChild : child == NULL\n");
2534#endif
2535 return(NULL);
2536 }
2537
Owen Taylor3473f882001-02-23 17:55:21 +00002538 /*
2539 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002540 * cur is then freed.
2541 */
2542 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002543 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002544 (parent->content != NULL) &&
2545 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002546 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002547 xmlFreeNode(cur);
2548 return(parent);
2549 }
2550 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002551 (parent->last->name == cur->name) &&
2552 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002553 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002554 xmlFreeNode(cur);
2555 return(parent->last);
2556 }
2557 }
2558
2559 /*
2560 * add the new element at the end of the children list.
2561 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002562 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00002563 cur->parent = parent;
2564 if (cur->doc != parent->doc) {
2565 xmlSetTreeDoc(cur, parent->doc);
2566 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002567 /* this check prevents a loop on tree-traversions if a developer
2568 * tries to add a node to its parent multiple times
2569 */
2570 if (prev == parent)
2571 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002572
2573 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002574 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002575 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002576 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002577 (parent->content != NULL) &&
2578 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002579 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002580 xmlFreeNode(cur);
2581 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002582 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002583 if (cur->type == XML_ATTRIBUTE_NODE) {
2584 if (parent->properties == NULL) {
2585 parent->properties = (xmlAttrPtr) cur;
2586 } else {
2587 /* check if an attribute with the same name exists */
2588 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002589
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002590 if (cur->ns == NULL)
2591 lastattr = xmlHasProp(parent, cur->name);
2592 else
2593 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2594 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2595 /* different instance, destroy it (attributes must be unique) */
2596 xmlFreeProp(lastattr);
2597 }
2598 /* find the end */
2599 lastattr = parent->properties;
2600 while (lastattr->next != NULL) {
2601 lastattr = lastattr->next;
2602 }
2603 lastattr->next = (xmlAttrPtr) cur;
2604 ((xmlAttrPtr) cur)->prev = lastattr;
2605 }
2606 } else {
2607 if (parent->children == NULL) {
2608 parent->children = cur;
2609 parent->last = cur;
2610 } else {
2611 prev = parent->last;
2612 prev->next = cur;
2613 cur->prev = prev;
2614 parent->last = cur;
2615 }
2616 }
Owen Taylor3473f882001-02-23 17:55:21 +00002617 return(cur);
2618}
2619
2620/**
2621 * xmlGetLastChild:
2622 * @parent: the parent node
2623 *
2624 * Search the last child of a node.
2625 * Returns the last child or NULL if none.
2626 */
2627xmlNodePtr
2628xmlGetLastChild(xmlNodePtr parent) {
2629 if (parent == NULL) {
2630#ifdef DEBUG_TREE
2631 xmlGenericError(xmlGenericErrorContext,
2632 "xmlGetLastChild : parent == NULL\n");
2633#endif
2634 return(NULL);
2635 }
2636 return(parent->last);
2637}
2638
2639/**
2640 * xmlFreeNodeList:
2641 * @cur: the first node in the list
2642 *
2643 * Free a node and all its siblings, this is a recursive behaviour, all
2644 * the children are freed too.
2645 */
2646void
2647xmlFreeNodeList(xmlNodePtr cur) {
2648 xmlNodePtr next;
2649 if (cur == NULL) {
2650#ifdef DEBUG_TREE
2651 xmlGenericError(xmlGenericErrorContext,
2652 "xmlFreeNodeList : node == NULL\n");
2653#endif
2654 return;
2655 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002656 if (cur->type == XML_NAMESPACE_DECL) {
2657 xmlFreeNsList((xmlNsPtr) cur);
2658 return;
2659 }
Owen Taylor3473f882001-02-23 17:55:21 +00002660 while (cur != NULL) {
2661 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002662 /* unroll to speed up freeing the document */
2663 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00002664
2665 if (xmlDeregisterNodeDefaultValue)
2666 xmlDeregisterNodeDefaultValue(cur);
2667
Daniel Veillard02141ea2001-04-30 11:46:40 +00002668 if ((cur->children != NULL) &&
2669 (cur->type != XML_ENTITY_REF_NODE))
2670 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00002671 if (((cur->type == XML_ELEMENT_NODE) ||
2672 (cur->type == XML_XINCLUDE_START) ||
2673 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002674 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00002675 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002676 if ((cur->type != XML_ELEMENT_NODE) &&
2677 (cur->type != XML_XINCLUDE_START) &&
2678 (cur->type != XML_XINCLUDE_END) &&
2679 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002680 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002681 }
2682 if (((cur->type == XML_ELEMENT_NODE) ||
2683 (cur->type == XML_XINCLUDE_START) ||
2684 (cur->type == XML_XINCLUDE_END)) &&
2685 (cur->nsDef != NULL))
2686 xmlFreeNsList(cur->nsDef);
2687
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002688 /*
2689 * When a node is a text node or a comment, it uses a global static
2690 * variable for the name of the node.
2691 *
2692 * The xmlStrEqual comparisons need to be done when (happened with
2693 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002694 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002695 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002696 * the string addresses compare are not sufficient.
2697 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002698 if ((cur->name != NULL) &&
2699 (cur->name != xmlStringText) &&
2700 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002701 (cur->name != xmlStringComment)) {
2702 if (cur->type == XML_TEXT_NODE) {
2703 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2704 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2705 xmlFree((char *) cur->name);
2706 } else if (cur->type == XML_COMMENT_NODE) {
2707 if (!xmlStrEqual(cur->name, xmlStringComment))
2708 xmlFree((char *) cur->name);
2709 } else
2710 xmlFree((char *) cur->name);
2711 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002712 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002713 xmlFree(cur);
2714 }
Owen Taylor3473f882001-02-23 17:55:21 +00002715 cur = next;
2716 }
2717}
2718
2719/**
2720 * xmlFreeNode:
2721 * @cur: the node
2722 *
2723 * Free a node, this is a recursive behaviour, all the children are freed too.
2724 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2725 */
2726void
2727xmlFreeNode(xmlNodePtr cur) {
2728 if (cur == NULL) {
2729#ifdef DEBUG_TREE
2730 xmlGenericError(xmlGenericErrorContext,
2731 "xmlFreeNode : node == NULL\n");
2732#endif
2733 return;
2734 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002735
Daniel Veillard02141ea2001-04-30 11:46:40 +00002736 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002737 if (cur->type == XML_DTD_NODE) {
2738 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002739 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002740 }
2741 if (cur->type == XML_NAMESPACE_DECL) {
2742 xmlFreeNs((xmlNsPtr) cur);
2743 return;
2744 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00002745 if (cur->type == XML_ATTRIBUTE_NODE) {
2746 xmlFreeProp((xmlAttrPtr) cur);
2747 return;
2748 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002749
2750 if (xmlDeregisterNodeDefaultValue)
2751 xmlDeregisterNodeDefaultValue(cur);
2752
Owen Taylor3473f882001-02-23 17:55:21 +00002753 if ((cur->children != NULL) &&
2754 (cur->type != XML_ENTITY_REF_NODE))
2755 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00002756 if (((cur->type == XML_ELEMENT_NODE) ||
2757 (cur->type == XML_XINCLUDE_START) ||
2758 (cur->type == XML_XINCLUDE_END)) &&
2759 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00002760 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002761 if ((cur->type != XML_ELEMENT_NODE) &&
2762 (cur->content != NULL) &&
2763 (cur->type != XML_ENTITY_REF_NODE) &&
2764 (cur->type != XML_XINCLUDE_END) &&
2765 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002766 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002767 }
2768
Daniel Veillardacd370f2001-06-09 17:17:51 +00002769 /*
2770 * When a node is a text node or a comment, it uses a global static
2771 * variable for the name of the node.
2772 *
2773 * The xmlStrEqual comparisons need to be done when (happened with
2774 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002775 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002776 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002777 * are not sufficient.
2778 */
Owen Taylor3473f882001-02-23 17:55:21 +00002779 if ((cur->name != NULL) &&
2780 (cur->name != xmlStringText) &&
2781 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002782 (cur->name != xmlStringComment)) {
2783 if (cur->type == XML_TEXT_NODE) {
2784 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2785 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2786 xmlFree((char *) cur->name);
2787 } else if (cur->type == XML_COMMENT_NODE) {
2788 if (!xmlStrEqual(cur->name, xmlStringComment))
2789 xmlFree((char *) cur->name);
2790 } else
2791 xmlFree((char *) cur->name);
2792 }
2793
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002794 if (((cur->type == XML_ELEMENT_NODE) ||
2795 (cur->type == XML_XINCLUDE_START) ||
2796 (cur->type == XML_XINCLUDE_END)) &&
2797 (cur->nsDef != NULL))
2798 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002799 xmlFree(cur);
2800}
2801
2802/**
2803 * xmlUnlinkNode:
2804 * @cur: the node
2805 *
2806 * Unlink a node from it's current context, the node is not freed
2807 */
2808void
2809xmlUnlinkNode(xmlNodePtr cur) {
2810 if (cur == NULL) {
2811#ifdef DEBUG_TREE
2812 xmlGenericError(xmlGenericErrorContext,
2813 "xmlUnlinkNode : node == NULL\n");
2814#endif
2815 return;
2816 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002817 if (cur->type == XML_DTD_NODE) {
2818 xmlDocPtr doc;
2819 doc = cur->doc;
2820 if (doc->intSubset == (xmlDtdPtr) cur)
2821 doc->intSubset = NULL;
2822 if (doc->extSubset == (xmlDtdPtr) cur)
2823 doc->extSubset = NULL;
2824 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002825 if (cur->parent != NULL) {
2826 xmlNodePtr parent;
2827 parent = cur->parent;
2828 if (cur->type == XML_ATTRIBUTE_NODE) {
2829 if (parent->properties == (xmlAttrPtr) cur)
2830 parent->properties = ((xmlAttrPtr) cur)->next;
2831 } else {
2832 if (parent->children == cur)
2833 parent->children = cur->next;
2834 if (parent->last == cur)
2835 parent->last = cur->prev;
2836 }
2837 cur->parent = NULL;
2838 }
Owen Taylor3473f882001-02-23 17:55:21 +00002839 if (cur->next != NULL)
2840 cur->next->prev = cur->prev;
2841 if (cur->prev != NULL)
2842 cur->prev->next = cur->next;
2843 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002844}
2845
2846/**
2847 * xmlReplaceNode:
2848 * @old: the old node
2849 * @cur: the node
2850 *
2851 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002852 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002853 * first unlinked from its existing context.
2854 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002855 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002856 */
2857xmlNodePtr
2858xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2859 if (old == NULL) {
2860#ifdef DEBUG_TREE
2861 xmlGenericError(xmlGenericErrorContext,
2862 "xmlReplaceNode : old == NULL\n");
2863#endif
2864 return(NULL);
2865 }
2866 if (cur == NULL) {
2867 xmlUnlinkNode(old);
2868 return(old);
2869 }
2870 if (cur == old) {
2871 return(old);
2872 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002873 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2874#ifdef DEBUG_TREE
2875 xmlGenericError(xmlGenericErrorContext,
2876 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2877#endif
2878 return(old);
2879 }
2880 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2881#ifdef DEBUG_TREE
2882 xmlGenericError(xmlGenericErrorContext,
2883 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2884#endif
2885 return(old);
2886 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002887 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2888#ifdef DEBUG_TREE
2889 xmlGenericError(xmlGenericErrorContext,
2890 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2891#endif
2892 return(old);
2893 }
2894 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2895#ifdef DEBUG_TREE
2896 xmlGenericError(xmlGenericErrorContext,
2897 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2898#endif
2899 return(old);
2900 }
Owen Taylor3473f882001-02-23 17:55:21 +00002901 xmlUnlinkNode(cur);
2902 cur->doc = old->doc;
2903 cur->parent = old->parent;
2904 cur->next = old->next;
2905 if (cur->next != NULL)
2906 cur->next->prev = cur;
2907 cur->prev = old->prev;
2908 if (cur->prev != NULL)
2909 cur->prev->next = cur;
2910 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002911 if (cur->type == XML_ATTRIBUTE_NODE) {
2912 if (cur->parent->properties == (xmlAttrPtr)old)
2913 cur->parent->properties = ((xmlAttrPtr) cur);
2914 } else {
2915 if (cur->parent->children == old)
2916 cur->parent->children = cur;
2917 if (cur->parent->last == old)
2918 cur->parent->last = cur;
2919 }
Owen Taylor3473f882001-02-23 17:55:21 +00002920 }
2921 old->next = old->prev = NULL;
2922 old->parent = NULL;
2923 return(old);
2924}
2925
2926/************************************************************************
2927 * *
2928 * Copy operations *
2929 * *
2930 ************************************************************************/
2931
2932/**
2933 * xmlCopyNamespace:
2934 * @cur: the namespace
2935 *
2936 * Do a copy of the namespace.
2937 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002938 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002939 */
2940xmlNsPtr
2941xmlCopyNamespace(xmlNsPtr cur) {
2942 xmlNsPtr ret;
2943
2944 if (cur == NULL) return(NULL);
2945 switch (cur->type) {
2946 case XML_LOCAL_NAMESPACE:
2947 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2948 break;
2949 default:
2950#ifdef DEBUG_TREE
2951 xmlGenericError(xmlGenericErrorContext,
2952 "xmlCopyNamespace: invalid type %d\n", cur->type);
2953#endif
2954 return(NULL);
2955 }
2956 return(ret);
2957}
2958
2959/**
2960 * xmlCopyNamespaceList:
2961 * @cur: the first namespace
2962 *
2963 * Do a copy of an namespace list.
2964 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002965 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002966 */
2967xmlNsPtr
2968xmlCopyNamespaceList(xmlNsPtr cur) {
2969 xmlNsPtr ret = NULL;
2970 xmlNsPtr p = NULL,q;
2971
2972 while (cur != NULL) {
2973 q = xmlCopyNamespace(cur);
2974 if (p == NULL) {
2975 ret = p = q;
2976 } else {
2977 p->next = q;
2978 p = q;
2979 }
2980 cur = cur->next;
2981 }
2982 return(ret);
2983}
2984
2985static xmlNodePtr
2986xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2987/**
2988 * xmlCopyProp:
2989 * @target: the element where the attribute will be grafted
2990 * @cur: the attribute
2991 *
2992 * Do a copy of the attribute.
2993 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002994 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002995 */
2996xmlAttrPtr
2997xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2998 xmlAttrPtr ret;
2999
3000 if (cur == NULL) return(NULL);
3001 if (target != NULL)
3002 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3003 else if (cur->parent != NULL)
3004 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3005 else if (cur->children != NULL)
3006 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3007 else
3008 ret = xmlNewDocProp(NULL, cur->name, NULL);
3009 if (ret == NULL) return(NULL);
3010 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003011
Owen Taylor3473f882001-02-23 17:55:21 +00003012 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003013 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003014/*
3015 * if (target->doc)
3016 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3017 * else if (cur->doc) / * target may not yet have a doc : KPI * /
3018 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
3019 * else
3020 * ns = NULL;
3021 * ret->ns = ns;
3022 */
3023 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3024 if (ns == NULL) {
3025 /*
3026 * Humm, we are copying an element whose namespace is defined
3027 * out of the new tree scope. Search it in the original tree
3028 * and add it at the top of the new tree
3029 */
3030 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3031 if (ns != NULL) {
3032 xmlNodePtr root = target;
3033 xmlNodePtr pred = NULL;
3034
3035 while (root->parent != NULL) {
3036 pred = root;
3037 root = root->parent;
3038 }
3039 if (root == (xmlNodePtr) target->doc) {
3040 /* correct possibly cycling above the document elt */
3041 root = pred;
3042 }
3043 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3044 }
3045 } else {
3046 /*
3047 * we have to find something appropriate here since
3048 * we cant be sure, that the namespce we found is identified
3049 * by the prefix
3050 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003051 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003052 /* this is the nice case */
3053 ret->ns = ns;
3054 } else {
3055 /*
3056 * we are in trouble: we need a new reconcilied namespace.
3057 * This is expensive
3058 */
3059 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3060 }
3061 }
3062
Owen Taylor3473f882001-02-23 17:55:21 +00003063 } else
3064 ret->ns = NULL;
3065
3066 if (cur->children != NULL) {
3067 xmlNodePtr tmp;
3068
3069 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3070 ret->last = NULL;
3071 tmp = ret->children;
3072 while (tmp != NULL) {
3073 /* tmp->parent = (xmlNodePtr)ret; */
3074 if (tmp->next == NULL)
3075 ret->last = tmp;
3076 tmp = tmp->next;
3077 }
3078 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003079 /*
3080 * Try to handle IDs
3081 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003082 if ((target!= NULL) && (cur!= NULL) &&
3083 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003084 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3085 if (xmlIsID(cur->doc, cur->parent, cur)) {
3086 xmlChar *id;
3087
3088 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3089 if (id != NULL) {
3090 xmlAddID(NULL, target->doc, id, ret);
3091 xmlFree(id);
3092 }
3093 }
3094 }
Owen Taylor3473f882001-02-23 17:55:21 +00003095 return(ret);
3096}
3097
3098/**
3099 * xmlCopyPropList:
3100 * @target: the element where the attributes will be grafted
3101 * @cur: the first attribute
3102 *
3103 * Do a copy of an attribute list.
3104 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003105 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003106 */
3107xmlAttrPtr
3108xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3109 xmlAttrPtr ret = NULL;
3110 xmlAttrPtr p = NULL,q;
3111
3112 while (cur != NULL) {
3113 q = xmlCopyProp(target, cur);
3114 if (p == NULL) {
3115 ret = p = q;
3116 } else {
3117 p->next = q;
3118 q->prev = p;
3119 p = q;
3120 }
3121 cur = cur->next;
3122 }
3123 return(ret);
3124}
3125
3126/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003127 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003128 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003129 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003130 * tricky reason: namespaces. Doing a direct copy of a node
3131 * say RPM:Copyright without changing the namespace pointer to
3132 * something else can produce stale links. One way to do it is
3133 * to keep a reference counter but this doesn't work as soon
3134 * as one move the element or the subtree out of the scope of
3135 * the existing namespace. The actual solution seems to add
3136 * a copy of the namespace at the top of the copied tree if
3137 * not available in the subtree.
3138 * Hence two functions, the public front-end call the inner ones
3139 */
3140
3141static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003142xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003143 int recursive) {
3144 xmlNodePtr ret;
3145
3146 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003147 switch (node->type) {
3148 case XML_TEXT_NODE:
3149 case XML_CDATA_SECTION_NODE:
3150 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003151 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003152 case XML_ENTITY_REF_NODE:
3153 case XML_ENTITY_NODE:
3154 case XML_PI_NODE:
3155 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003156 case XML_XINCLUDE_START:
3157 case XML_XINCLUDE_END:
3158 break;
3159 case XML_ATTRIBUTE_NODE:
3160 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3161 case XML_NAMESPACE_DECL:
3162 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3163
Daniel Veillard39196eb2001-06-19 18:09:42 +00003164 case XML_DOCUMENT_NODE:
3165 case XML_HTML_DOCUMENT_NODE:
3166#ifdef LIBXML_DOCB_ENABLED
3167 case XML_DOCB_DOCUMENT_NODE:
3168#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003169 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003170 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003171 case XML_NOTATION_NODE:
3172 case XML_DTD_NODE:
3173 case XML_ELEMENT_DECL:
3174 case XML_ATTRIBUTE_DECL:
3175 case XML_ENTITY_DECL:
3176 return(NULL);
3177 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003178
Owen Taylor3473f882001-02-23 17:55:21 +00003179 /*
3180 * Allocate a new node and fill the fields.
3181 */
3182 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3183 if (ret == NULL) {
3184 xmlGenericError(xmlGenericErrorContext,
3185 "xmlStaticCopyNode : malloc failed\n");
3186 return(NULL);
3187 }
3188 memset(ret, 0, sizeof(xmlNode));
3189 ret->type = node->type;
3190
3191 ret->doc = doc;
3192 ret->parent = parent;
3193 if (node->name == xmlStringText)
3194 ret->name = xmlStringText;
3195 else if (node->name == xmlStringTextNoenc)
3196 ret->name = xmlStringTextNoenc;
3197 else if (node->name == xmlStringComment)
3198 ret->name = xmlStringComment;
3199 else if (node->name != NULL)
3200 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003201 if ((node->type != XML_ELEMENT_NODE) &&
3202 (node->content != NULL) &&
3203 (node->type != XML_ENTITY_REF_NODE) &&
3204 (node->type != XML_XINCLUDE_END) &&
3205 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003206 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003207 }else{
3208 if (node->type == XML_ELEMENT_NODE)
3209 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003210 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003211 if (parent != NULL) {
3212 xmlNodePtr tmp;
3213
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003214 /*
3215 * this is a tricky part for the node register thing:
3216 * in case ret does get coalesced in xmlAddChild
3217 * the deregister-node callback is called; so we register ret now already
3218 */
3219 if (xmlRegisterNodeDefaultValue)
3220 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3221
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003222 tmp = xmlAddChild(parent, ret);
3223 /* node could have coalesced */
3224 if (tmp != ret)
3225 return(tmp);
3226 }
Owen Taylor3473f882001-02-23 17:55:21 +00003227
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003228 if (!recursive)
3229 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003230 if (node->nsDef != NULL)
3231 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3232
3233 if (node->ns != NULL) {
3234 xmlNsPtr ns;
3235
3236 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3237 if (ns == NULL) {
3238 /*
3239 * Humm, we are copying an element whose namespace is defined
3240 * out of the new tree scope. Search it in the original tree
3241 * and add it at the top of the new tree
3242 */
3243 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3244 if (ns != NULL) {
3245 xmlNodePtr root = ret;
3246
3247 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003248 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003249 }
3250 } else {
3251 /*
3252 * reference the existing namespace definition in our own tree.
3253 */
3254 ret->ns = ns;
3255 }
3256 }
3257 if (node->properties != NULL)
3258 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003259 if (node->type == XML_ENTITY_REF_NODE) {
3260 if ((doc == NULL) || (node->doc != doc)) {
3261 /*
3262 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003263 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003264 * we cannot keep the reference. Try to find it in the
3265 * target document.
3266 */
3267 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3268 } else {
3269 ret->children = node->children;
3270 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003271 ret->last = ret->children;
3272 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003273 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003274 UPDATE_LAST_CHILD_AND_PARENT(ret)
3275 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003276
3277out:
3278 /* if parent != NULL we already registered the node above */
3279 if (parent == NULL && xmlRegisterNodeDefaultValue)
3280 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003281 return(ret);
3282}
3283
3284static xmlNodePtr
3285xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3286 xmlNodePtr ret = NULL;
3287 xmlNodePtr p = NULL,q;
3288
3289 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003290 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003291 if (doc == NULL) {
3292 node = node->next;
3293 continue;
3294 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003295 if (doc->intSubset == NULL) {
3296 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3297 q->doc = doc;
3298 q->parent = parent;
3299 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003300 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003301 } else {
3302 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003303 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003304 }
3305 } else
3306 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003307 if (ret == NULL) {
3308 q->prev = NULL;
3309 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003310 } else if (p != q) {
3311 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003312 p->next = q;
3313 q->prev = p;
3314 p = q;
3315 }
3316 node = node->next;
3317 }
3318 return(ret);
3319}
3320
3321/**
3322 * xmlCopyNode:
3323 * @node: the node
3324 * @recursive: if 1 do a recursive copy.
3325 *
3326 * Do a copy of the node.
3327 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003328 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003329 */
3330xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003331xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003332 xmlNodePtr ret;
3333
3334 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3335 return(ret);
3336}
3337
3338/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003339 * xmlDocCopyNode:
3340 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003341 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003342 * @recursive: if 1 do a recursive copy.
3343 *
3344 * Do a copy of the node to a given document.
3345 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003346 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003347 */
3348xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003349xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003350 xmlNodePtr ret;
3351
3352 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3353 return(ret);
3354}
3355
3356/**
Owen Taylor3473f882001-02-23 17:55:21 +00003357 * xmlCopyNodeList:
3358 * @node: the first node in the list.
3359 *
3360 * Do a recursive copy of the node list.
3361 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003362 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003363 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003364xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003365 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3366 return(ret);
3367}
3368
3369/**
Owen Taylor3473f882001-02-23 17:55:21 +00003370 * xmlCopyDtd:
3371 * @dtd: the dtd
3372 *
3373 * Do a copy of the dtd.
3374 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003375 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003376 */
3377xmlDtdPtr
3378xmlCopyDtd(xmlDtdPtr dtd) {
3379 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003380 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003381
3382 if (dtd == NULL) return(NULL);
3383 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3384 if (ret == NULL) return(NULL);
3385 if (dtd->entities != NULL)
3386 ret->entities = (void *) xmlCopyEntitiesTable(
3387 (xmlEntitiesTablePtr) dtd->entities);
3388 if (dtd->notations != NULL)
3389 ret->notations = (void *) xmlCopyNotationTable(
3390 (xmlNotationTablePtr) dtd->notations);
3391 if (dtd->elements != NULL)
3392 ret->elements = (void *) xmlCopyElementTable(
3393 (xmlElementTablePtr) dtd->elements);
3394 if (dtd->attributes != NULL)
3395 ret->attributes = (void *) xmlCopyAttributeTable(
3396 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003397 if (dtd->pentities != NULL)
3398 ret->pentities = (void *) xmlCopyEntitiesTable(
3399 (xmlEntitiesTablePtr) dtd->pentities);
3400
3401 cur = dtd->children;
3402 while (cur != NULL) {
3403 q = NULL;
3404
3405 if (cur->type == XML_ENTITY_DECL) {
3406 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3407 switch (tmp->etype) {
3408 case XML_INTERNAL_GENERAL_ENTITY:
3409 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3410 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3411 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3412 break;
3413 case XML_INTERNAL_PARAMETER_ENTITY:
3414 case XML_EXTERNAL_PARAMETER_ENTITY:
3415 q = (xmlNodePtr)
3416 xmlGetParameterEntityFromDtd(ret, tmp->name);
3417 break;
3418 case XML_INTERNAL_PREDEFINED_ENTITY:
3419 break;
3420 }
3421 } else if (cur->type == XML_ELEMENT_DECL) {
3422 xmlElementPtr tmp = (xmlElementPtr) cur;
3423 q = (xmlNodePtr)
3424 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3425 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3426 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3427 q = (xmlNodePtr)
3428 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3429 } else if (cur->type == XML_COMMENT_NODE) {
3430 q = xmlCopyNode(cur, 0);
3431 }
3432
3433 if (q == NULL) {
3434 cur = cur->next;
3435 continue;
3436 }
3437
3438 if (p == NULL)
3439 ret->children = q;
3440 else
3441 p->next = q;
3442
3443 q->prev = p;
3444 q->parent = (xmlNodePtr) ret;
3445 q->next = NULL;
3446 ret->last = q;
3447 p = q;
3448 cur = cur->next;
3449 }
3450
Owen Taylor3473f882001-02-23 17:55:21 +00003451 return(ret);
3452}
3453
3454/**
3455 * xmlCopyDoc:
3456 * @doc: the document
3457 * @recursive: if 1 do a recursive copy.
3458 *
3459 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003460 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003461 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003462 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003463 */
3464xmlDocPtr
3465xmlCopyDoc(xmlDocPtr doc, int recursive) {
3466 xmlDocPtr ret;
3467
3468 if (doc == NULL) return(NULL);
3469 ret = xmlNewDoc(doc->version);
3470 if (ret == NULL) return(NULL);
3471 if (doc->name != NULL)
3472 ret->name = xmlMemStrdup(doc->name);
3473 if (doc->encoding != NULL)
3474 ret->encoding = xmlStrdup(doc->encoding);
3475 ret->charset = doc->charset;
3476 ret->compression = doc->compression;
3477 ret->standalone = doc->standalone;
3478 if (!recursive) return(ret);
3479
Daniel Veillardb33c2012001-04-25 12:59:04 +00003480 ret->last = NULL;
3481 ret->children = NULL;
3482 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003483 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003484 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003485 ret->intSubset->parent = ret;
3486 }
Owen Taylor3473f882001-02-23 17:55:21 +00003487 if (doc->oldNs != NULL)
3488 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3489 if (doc->children != NULL) {
3490 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003491
3492 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3493 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003494 ret->last = NULL;
3495 tmp = ret->children;
3496 while (tmp != NULL) {
3497 if (tmp->next == NULL)
3498 ret->last = tmp;
3499 tmp = tmp->next;
3500 }
3501 }
3502 return(ret);
3503}
3504
3505/************************************************************************
3506 * *
3507 * Content access functions *
3508 * *
3509 ************************************************************************/
3510
3511/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003512 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003513 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00003514 *
3515 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003516 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003517 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003518 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003519 */
3520long
3521xmlGetLineNo(xmlNodePtr node)
3522{
3523 long result = -1;
3524
3525 if (!node)
3526 return result;
3527 if (node->type == XML_ELEMENT_NODE)
3528 result = (long) node->content;
3529 else if ((node->prev != NULL) &&
3530 ((node->prev->type == XML_ELEMENT_NODE) ||
3531 (node->prev->type == XML_TEXT_NODE)))
3532 result = xmlGetLineNo(node->prev);
3533 else if ((node->parent != NULL) &&
3534 ((node->parent->type == XML_ELEMENT_NODE) ||
3535 (node->parent->type == XML_TEXT_NODE)))
3536 result = xmlGetLineNo(node->parent);
3537
3538 return result;
3539}
3540
3541/**
3542 * xmlGetNodePath:
3543 * @node: a node
3544 *
3545 * Build a structure based Path for the given node
3546 *
3547 * Returns the new path or NULL in case of error. The caller must free
3548 * the returned string
3549 */
3550xmlChar *
3551xmlGetNodePath(xmlNodePtr node)
3552{
3553 xmlNodePtr cur, tmp, next;
3554 xmlChar *buffer = NULL, *temp;
3555 size_t buf_len;
3556 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00003557 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00003558 const char *name;
3559 char nametemp[100];
3560 int occur = 0;
3561
3562 if (node == NULL)
3563 return (NULL);
3564
3565 buf_len = 500;
3566 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3567 if (buffer == NULL)
3568 return (NULL);
3569 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3570 if (buf == NULL) {
3571 xmlFree(buffer);
3572 return (NULL);
3573 }
3574
3575 buffer[0] = 0;
3576 cur = node;
3577 do {
3578 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003579 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003580 occur = 0;
3581 if ((cur->type == XML_DOCUMENT_NODE) ||
3582 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3583 if (buffer[0] == '/')
3584 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003585 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003586 next = NULL;
3587 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003588 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003589 name = (const char *) cur->name;
3590 if (cur->ns) {
3591 snprintf(nametemp, sizeof(nametemp) - 1,
3592 "%s:%s", cur->ns->prefix, cur->name);
3593 nametemp[sizeof(nametemp) - 1] = 0;
3594 name = nametemp;
3595 }
3596 next = cur->parent;
3597
3598 /*
3599 * Thumbler index computation
3600 */
3601 tmp = cur->prev;
3602 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00003603 if ((tmp->type == XML_ELEMENT_NODE) &&
3604 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003605 occur++;
3606 tmp = tmp->prev;
3607 }
3608 if (occur == 0) {
3609 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003610 while (tmp != NULL && occur == 0) {
3611 if ((tmp->type == XML_ELEMENT_NODE) &&
3612 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003613 occur++;
3614 tmp = tmp->next;
3615 }
3616 if (occur != 0)
3617 occur = 1;
3618 } else
3619 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003620 } else if (cur->type == XML_COMMENT_NODE) {
3621 sep = "/";
3622 name = "comment()";
3623 next = cur->parent;
3624
3625 /*
3626 * Thumbler index computation
3627 */
3628 tmp = cur->prev;
3629 while (tmp != NULL) {
3630 if (tmp->type == XML_COMMENT_NODE)
3631 occur++;
3632 tmp = tmp->prev;
3633 }
3634 if (occur == 0) {
3635 tmp = cur->next;
3636 while (tmp != NULL && occur == 0) {
3637 if (tmp->type == XML_COMMENT_NODE)
3638 occur++;
3639 tmp = tmp->next;
3640 }
3641 if (occur != 0)
3642 occur = 1;
3643 } else
3644 occur++;
3645 } else if ((cur->type == XML_TEXT_NODE) ||
3646 (cur->type == XML_CDATA_SECTION_NODE)) {
3647 sep = "/";
3648 name = "text()";
3649 next = cur->parent;
3650
3651 /*
3652 * Thumbler index computation
3653 */
3654 tmp = cur->prev;
3655 while (tmp != NULL) {
3656 if ((cur->type == XML_TEXT_NODE) ||
3657 (cur->type == XML_CDATA_SECTION_NODE))
3658 occur++;
3659 tmp = tmp->prev;
3660 }
3661 if (occur == 0) {
3662 tmp = cur->next;
3663 while (tmp != NULL && occur == 0) {
3664 if ((cur->type == XML_TEXT_NODE) ||
3665 (cur->type == XML_CDATA_SECTION_NODE))
3666 occur++;
3667 tmp = tmp->next;
3668 }
3669 if (occur != 0)
3670 occur = 1;
3671 } else
3672 occur++;
3673 } else if (cur->type == XML_PI_NODE) {
3674 sep = "/";
3675 snprintf(nametemp, sizeof(nametemp) - 1,
3676 "processing-instruction('%s')", cur->name);
3677 nametemp[sizeof(nametemp) - 1] = 0;
3678 name = nametemp;
3679
3680 next = cur->parent;
3681
3682 /*
3683 * Thumbler index computation
3684 */
3685 tmp = cur->prev;
3686 while (tmp != NULL) {
3687 if ((tmp->type == XML_PI_NODE) &&
3688 (xmlStrEqual(cur->name, tmp->name)))
3689 occur++;
3690 tmp = tmp->prev;
3691 }
3692 if (occur == 0) {
3693 tmp = cur->next;
3694 while (tmp != NULL && occur == 0) {
3695 if ((tmp->type == XML_PI_NODE) &&
3696 (xmlStrEqual(cur->name, tmp->name)))
3697 occur++;
3698 tmp = tmp->next;
3699 }
3700 if (occur != 0)
3701 occur = 1;
3702 } else
3703 occur++;
3704
Daniel Veillard8faa7832001-11-26 15:58:08 +00003705 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003706 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003707 name = (const char *) (((xmlAttrPtr) cur)->name);
3708 next = ((xmlAttrPtr) cur)->parent;
3709 } else {
3710 next = cur->parent;
3711 }
3712
3713 /*
3714 * Make sure there is enough room
3715 */
3716 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3717 buf_len =
3718 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3719 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3720 if (temp == NULL) {
3721 xmlFree(buf);
3722 xmlFree(buffer);
3723 return (NULL);
3724 }
3725 buffer = temp;
3726 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3727 if (temp == NULL) {
3728 xmlFree(buf);
3729 xmlFree(buffer);
3730 return (NULL);
3731 }
3732 buf = temp;
3733 }
3734 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003735 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00003736 sep, name, (char *) buffer);
3737 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003738 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00003739 sep, name, occur, (char *) buffer);
3740 snprintf((char *) buffer, buf_len, "%s", buf);
3741 cur = next;
3742 } while (cur != NULL);
3743 xmlFree(buf);
3744 return (buffer);
3745}
3746
3747/**
Owen Taylor3473f882001-02-23 17:55:21 +00003748 * xmlDocGetRootElement:
3749 * @doc: the document
3750 *
3751 * Get the root element of the document (doc->children is a list
3752 * containing possibly comments, PIs, etc ...).
3753 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003754 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003755 */
3756xmlNodePtr
3757xmlDocGetRootElement(xmlDocPtr doc) {
3758 xmlNodePtr ret;
3759
3760 if (doc == NULL) return(NULL);
3761 ret = doc->children;
3762 while (ret != NULL) {
3763 if (ret->type == XML_ELEMENT_NODE)
3764 return(ret);
3765 ret = ret->next;
3766 }
3767 return(ret);
3768}
3769
3770/**
3771 * xmlDocSetRootElement:
3772 * @doc: the document
3773 * @root: the new document root element
3774 *
3775 * Set the root element of the document (doc->children is a list
3776 * containing possibly comments, PIs, etc ...).
3777 *
3778 * Returns the old root element if any was found
3779 */
3780xmlNodePtr
3781xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3782 xmlNodePtr old = NULL;
3783
3784 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00003785 if (root == NULL)
3786 return(NULL);
3787 xmlUnlinkNode(root);
3788 root->doc = doc;
3789 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00003790 old = doc->children;
3791 while (old != NULL) {
3792 if (old->type == XML_ELEMENT_NODE)
3793 break;
3794 old = old->next;
3795 }
3796 if (old == NULL) {
3797 if (doc->children == NULL) {
3798 doc->children = root;
3799 doc->last = root;
3800 } else {
3801 xmlAddSibling(doc->children, root);
3802 }
3803 } else {
3804 xmlReplaceNode(old, root);
3805 }
3806 return(old);
3807}
3808
3809/**
3810 * xmlNodeSetLang:
3811 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003812 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003813 *
3814 * Set the language of a node, i.e. the values of the xml:lang
3815 * attribute.
3816 */
3817void
3818xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003819 xmlNsPtr ns;
3820
Owen Taylor3473f882001-02-23 17:55:21 +00003821 if (cur == NULL) return;
3822 switch(cur->type) {
3823 case XML_TEXT_NODE:
3824 case XML_CDATA_SECTION_NODE:
3825 case XML_COMMENT_NODE:
3826 case XML_DOCUMENT_NODE:
3827 case XML_DOCUMENT_TYPE_NODE:
3828 case XML_DOCUMENT_FRAG_NODE:
3829 case XML_NOTATION_NODE:
3830 case XML_HTML_DOCUMENT_NODE:
3831 case XML_DTD_NODE:
3832 case XML_ELEMENT_DECL:
3833 case XML_ATTRIBUTE_DECL:
3834 case XML_ENTITY_DECL:
3835 case XML_PI_NODE:
3836 case XML_ENTITY_REF_NODE:
3837 case XML_ENTITY_NODE:
3838 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003839#ifdef LIBXML_DOCB_ENABLED
3840 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003841#endif
3842 case XML_XINCLUDE_START:
3843 case XML_XINCLUDE_END:
3844 return;
3845 case XML_ELEMENT_NODE:
3846 case XML_ATTRIBUTE_NODE:
3847 break;
3848 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003849 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3850 if (ns == NULL)
3851 return;
3852 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003853}
3854
3855/**
3856 * xmlNodeGetLang:
3857 * @cur: the node being checked
3858 *
3859 * Searches the language of a node, i.e. the values of the xml:lang
3860 * attribute or the one carried by the nearest ancestor.
3861 *
3862 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003863 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003864 */
3865xmlChar *
3866xmlNodeGetLang(xmlNodePtr cur) {
3867 xmlChar *lang;
3868
3869 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003870 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003871 if (lang != NULL)
3872 return(lang);
3873 cur = cur->parent;
3874 }
3875 return(NULL);
3876}
3877
3878
3879/**
3880 * xmlNodeSetSpacePreserve:
3881 * @cur: the node being changed
3882 * @val: the xml:space value ("0": default, 1: "preserve")
3883 *
3884 * Set (or reset) the space preserving behaviour of a node, i.e. the
3885 * value of the xml:space attribute.
3886 */
3887void
3888xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003889 xmlNsPtr ns;
3890
Owen Taylor3473f882001-02-23 17:55:21 +00003891 if (cur == NULL) return;
3892 switch(cur->type) {
3893 case XML_TEXT_NODE:
3894 case XML_CDATA_SECTION_NODE:
3895 case XML_COMMENT_NODE:
3896 case XML_DOCUMENT_NODE:
3897 case XML_DOCUMENT_TYPE_NODE:
3898 case XML_DOCUMENT_FRAG_NODE:
3899 case XML_NOTATION_NODE:
3900 case XML_HTML_DOCUMENT_NODE:
3901 case XML_DTD_NODE:
3902 case XML_ELEMENT_DECL:
3903 case XML_ATTRIBUTE_DECL:
3904 case XML_ENTITY_DECL:
3905 case XML_PI_NODE:
3906 case XML_ENTITY_REF_NODE:
3907 case XML_ENTITY_NODE:
3908 case XML_NAMESPACE_DECL:
3909 case XML_XINCLUDE_START:
3910 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003911#ifdef LIBXML_DOCB_ENABLED
3912 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003913#endif
3914 return;
3915 case XML_ELEMENT_NODE:
3916 case XML_ATTRIBUTE_NODE:
3917 break;
3918 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003919 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3920 if (ns == NULL)
3921 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003922 switch (val) {
3923 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003924 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003925 break;
3926 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003927 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003928 break;
3929 }
3930}
3931
3932/**
3933 * xmlNodeGetSpacePreserve:
3934 * @cur: the node being checked
3935 *
3936 * Searches the space preserving behaviour of a node, i.e. the values
3937 * of the xml:space attribute or the one carried by the nearest
3938 * ancestor.
3939 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003940 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003941 */
3942int
3943xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3944 xmlChar *space;
3945
3946 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003947 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003948 if (space != NULL) {
3949 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3950 xmlFree(space);
3951 return(1);
3952 }
3953 if (xmlStrEqual(space, BAD_CAST "default")) {
3954 xmlFree(space);
3955 return(0);
3956 }
3957 xmlFree(space);
3958 }
3959 cur = cur->parent;
3960 }
3961 return(-1);
3962}
3963
3964/**
3965 * xmlNodeSetName:
3966 * @cur: the node being changed
3967 * @name: the new tag name
3968 *
3969 * Set (or reset) the name of a node.
3970 */
3971void
3972xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3973 if (cur == NULL) return;
3974 if (name == NULL) return;
3975 switch(cur->type) {
3976 case XML_TEXT_NODE:
3977 case XML_CDATA_SECTION_NODE:
3978 case XML_COMMENT_NODE:
3979 case XML_DOCUMENT_TYPE_NODE:
3980 case XML_DOCUMENT_FRAG_NODE:
3981 case XML_NOTATION_NODE:
3982 case XML_HTML_DOCUMENT_NODE:
3983 case XML_NAMESPACE_DECL:
3984 case XML_XINCLUDE_START:
3985 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003986#ifdef LIBXML_DOCB_ENABLED
3987 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003988#endif
3989 return;
3990 case XML_ELEMENT_NODE:
3991 case XML_ATTRIBUTE_NODE:
3992 case XML_PI_NODE:
3993 case XML_ENTITY_REF_NODE:
3994 case XML_ENTITY_NODE:
3995 case XML_DTD_NODE:
3996 case XML_DOCUMENT_NODE:
3997 case XML_ELEMENT_DECL:
3998 case XML_ATTRIBUTE_DECL:
3999 case XML_ENTITY_DECL:
4000 break;
4001 }
4002 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4003 cur->name = xmlStrdup(name);
4004}
4005
4006/**
4007 * xmlNodeSetBase:
4008 * @cur: the node being changed
4009 * @uri: the new base URI
4010 *
4011 * Set (or reset) the base URI of a node, i.e. the value of the
4012 * xml:base attribute.
4013 */
4014void
4015xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004016 xmlNsPtr ns;
4017
Owen Taylor3473f882001-02-23 17:55:21 +00004018 if (cur == NULL) return;
4019 switch(cur->type) {
4020 case XML_TEXT_NODE:
4021 case XML_CDATA_SECTION_NODE:
4022 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004023 case XML_DOCUMENT_TYPE_NODE:
4024 case XML_DOCUMENT_FRAG_NODE:
4025 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004026 case XML_DTD_NODE:
4027 case XML_ELEMENT_DECL:
4028 case XML_ATTRIBUTE_DECL:
4029 case XML_ENTITY_DECL:
4030 case XML_PI_NODE:
4031 case XML_ENTITY_REF_NODE:
4032 case XML_ENTITY_NODE:
4033 case XML_NAMESPACE_DECL:
4034 case XML_XINCLUDE_START:
4035 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004036 return;
4037 case XML_ELEMENT_NODE:
4038 case XML_ATTRIBUTE_NODE:
4039 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004040 case XML_DOCUMENT_NODE:
4041#ifdef LIBXML_DOCB_ENABLED
4042 case XML_DOCB_DOCUMENT_NODE:
4043#endif
4044 case XML_HTML_DOCUMENT_NODE: {
4045 xmlDocPtr doc = (xmlDocPtr) cur;
4046
4047 if (doc->URL != NULL)
4048 xmlFree((xmlChar *) doc->URL);
4049 if (uri == NULL)
4050 doc->URL = NULL;
4051 else
4052 doc->URL = xmlStrdup(uri);
4053 return;
4054 }
Owen Taylor3473f882001-02-23 17:55:21 +00004055 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004056
4057 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4058 if (ns == NULL)
4059 return;
4060 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004061}
4062
4063/**
Owen Taylor3473f882001-02-23 17:55:21 +00004064 * xmlNodeGetBase:
4065 * @doc: the document the node pertains to
4066 * @cur: the node being checked
4067 *
4068 * Searches for the BASE URL. The code should work on both XML
4069 * and HTML document even if base mechanisms are completely different.
4070 * It returns the base as defined in RFC 2396 sections
4071 * 5.1.1. Base URI within Document Content
4072 * and
4073 * 5.1.2. Base URI from the Encapsulating Entity
4074 * However it does not return the document base (5.1.3), use
4075 * xmlDocumentGetBase() for this
4076 *
4077 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004078 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004079 */
4080xmlChar *
4081xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004082 xmlChar *oldbase = NULL;
4083 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004084
4085 if ((cur == NULL) && (doc == NULL))
4086 return(NULL);
4087 if (doc == NULL) doc = cur->doc;
4088 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4089 cur = doc->children;
4090 while ((cur != NULL) && (cur->name != NULL)) {
4091 if (cur->type != XML_ELEMENT_NODE) {
4092 cur = cur->next;
4093 continue;
4094 }
4095 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4096 cur = cur->children;
4097 continue;
4098 }
4099 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4100 cur = cur->children;
4101 continue;
4102 }
4103 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4104 return(xmlGetProp(cur, BAD_CAST "href"));
4105 }
4106 cur = cur->next;
4107 }
4108 return(NULL);
4109 }
4110 while (cur != NULL) {
4111 if (cur->type == XML_ENTITY_DECL) {
4112 xmlEntityPtr ent = (xmlEntityPtr) cur;
4113 return(xmlStrdup(ent->URI));
4114 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004115 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004116 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004117 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004118 if (oldbase != NULL) {
4119 newbase = xmlBuildURI(oldbase, base);
4120 if (newbase != NULL) {
4121 xmlFree(oldbase);
4122 xmlFree(base);
4123 oldbase = newbase;
4124 } else {
4125 xmlFree(oldbase);
4126 xmlFree(base);
4127 return(NULL);
4128 }
4129 } else {
4130 oldbase = base;
4131 }
4132 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4133 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4134 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4135 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004136 }
4137 }
Owen Taylor3473f882001-02-23 17:55:21 +00004138 cur = cur->parent;
4139 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004140 if ((doc != NULL) && (doc->URL != NULL)) {
4141 if (oldbase == NULL)
4142 return(xmlStrdup(doc->URL));
4143 newbase = xmlBuildURI(oldbase, doc->URL);
4144 xmlFree(oldbase);
4145 return(newbase);
4146 }
4147 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004148}
4149
4150/**
4151 * xmlNodeGetContent:
4152 * @cur: the node being read
4153 *
4154 * Read the value of a node, this can be either the text carried
4155 * directly by this node if it's a TEXT node or the aggregate string
4156 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004157 * Entity references are substituted.
4158 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004159 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004160 */
4161xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004162xmlNodeGetContent(xmlNodePtr cur)
4163{
4164 if (cur == NULL)
4165 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004166 switch (cur->type) {
4167 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004168 case XML_ELEMENT_NODE:{
4169 xmlNodePtr tmp = cur;
4170 xmlBufferPtr buffer;
4171 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004172
Daniel Veillard814a76d2003-01-23 18:24:20 +00004173 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004174 if (buffer == NULL)
4175 return (NULL);
4176 while (tmp != NULL) {
4177 switch (tmp->type) {
4178 case XML_CDATA_SECTION_NODE:
4179 case XML_TEXT_NODE:
4180 if (tmp->content != NULL)
4181 xmlBufferCat(buffer, tmp->content);
4182 break;
4183 case XML_ENTITY_REF_NODE:{
4184 /* recursive substitution of entity references */
4185 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00004186
Daniel Veillard7646b182002-04-20 06:41:40 +00004187 if (cont) {
4188 xmlBufferCat(buffer,
4189 (const xmlChar *) cont);
4190 xmlFree(cont);
4191 }
4192 break;
4193 }
4194 default:
4195 break;
4196 }
4197 /*
4198 * Skip to next node
4199 */
4200 if (tmp->children != NULL) {
4201 if (tmp->children->type != XML_ENTITY_DECL) {
4202 tmp = tmp->children;
4203 continue;
4204 }
4205 }
4206 if (tmp == cur)
4207 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004208
Daniel Veillard7646b182002-04-20 06:41:40 +00004209 if (tmp->next != NULL) {
4210 tmp = tmp->next;
4211 continue;
4212 }
4213
4214 do {
4215 tmp = tmp->parent;
4216 if (tmp == NULL)
4217 break;
4218 if (tmp == cur) {
4219 tmp = NULL;
4220 break;
4221 }
4222 if (tmp->next != NULL) {
4223 tmp = tmp->next;
4224 break;
4225 }
4226 } while (tmp != NULL);
4227 }
4228 ret = buffer->content;
4229 buffer->content = NULL;
4230 xmlBufferFree(buffer);
4231 return (ret);
4232 }
4233 case XML_ATTRIBUTE_NODE:{
4234 xmlAttrPtr attr = (xmlAttrPtr) cur;
4235
4236 if (attr->parent != NULL)
4237 return (xmlNodeListGetString
4238 (attr->parent->doc, attr->children, 1));
4239 else
4240 return (xmlNodeListGetString(NULL, attr->children, 1));
4241 break;
4242 }
Owen Taylor3473f882001-02-23 17:55:21 +00004243 case XML_COMMENT_NODE:
4244 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004245 if (cur->content != NULL)
4246 return (xmlStrdup(cur->content));
4247 return (NULL);
4248 case XML_ENTITY_REF_NODE:{
4249 xmlEntityPtr ent;
4250 xmlNodePtr tmp;
4251 xmlBufferPtr buffer;
4252 xmlChar *ret;
4253
4254 /* lookup entity declaration */
4255 ent = xmlGetDocEntity(cur->doc, cur->name);
4256 if (ent == NULL)
4257 return (NULL);
4258
4259 buffer = xmlBufferCreate();
4260 if (buffer == NULL)
4261 return (NULL);
4262
4263 /* an entity content can be any "well balanced chunk",
4264 * i.e. the result of the content [43] production:
4265 * http://www.w3.org/TR/REC-xml#NT-content
4266 * -> we iterate through child nodes and recursive call
4267 * xmlNodeGetContent() which handles all possible node types */
4268 tmp = ent->children;
4269 while (tmp) {
4270 xmlChar *cont = xmlNodeGetContent(tmp);
4271
4272 if (cont) {
4273 xmlBufferCat(buffer, (const xmlChar *) cont);
4274 xmlFree(cont);
4275 }
4276 tmp = tmp->next;
4277 }
4278
4279 ret = buffer->content;
4280 buffer->content = NULL;
4281 xmlBufferFree(buffer);
4282 return (ret);
4283 }
Owen Taylor3473f882001-02-23 17:55:21 +00004284 case XML_ENTITY_NODE:
4285 case XML_DOCUMENT_NODE:
4286 case XML_HTML_DOCUMENT_NODE:
4287 case XML_DOCUMENT_TYPE_NODE:
4288 case XML_NOTATION_NODE:
4289 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004290 case XML_XINCLUDE_START:
4291 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004292#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004293 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004294#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00004295 return (NULL);
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004296 case XML_NAMESPACE_DECL: {
4297 xmlChar *tmp;
4298
4299 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4300 return (tmp);
4301 }
Owen Taylor3473f882001-02-23 17:55:21 +00004302 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004303 /* TODO !!! */
4304 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004305 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004306 /* TODO !!! */
4307 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004308 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004309 /* TODO !!! */
4310 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004311 case XML_CDATA_SECTION_NODE:
4312 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004313 if (cur->content != NULL)
4314 return (xmlStrdup(cur->content));
4315 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004316 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004317 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004318}
Owen Taylor3473f882001-02-23 17:55:21 +00004319/**
4320 * xmlNodeSetContent:
4321 * @cur: the node being modified
4322 * @content: the new value of the content
4323 *
4324 * Replace the content of a node.
4325 */
4326void
4327xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4328 if (cur == NULL) {
4329#ifdef DEBUG_TREE
4330 xmlGenericError(xmlGenericErrorContext,
4331 "xmlNodeSetContent : node == NULL\n");
4332#endif
4333 return;
4334 }
4335 switch (cur->type) {
4336 case XML_DOCUMENT_FRAG_NODE:
4337 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004338 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004339 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4340 cur->children = xmlStringGetNodeList(cur->doc, content);
4341 UPDATE_LAST_CHILD_AND_PARENT(cur)
4342 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004343 case XML_TEXT_NODE:
4344 case XML_CDATA_SECTION_NODE:
4345 case XML_ENTITY_REF_NODE:
4346 case XML_ENTITY_NODE:
4347 case XML_PI_NODE:
4348 case XML_COMMENT_NODE:
4349 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004350 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004351 }
4352 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4353 cur->last = cur->children = NULL;
4354 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004355 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004356 } else
4357 cur->content = NULL;
4358 break;
4359 case XML_DOCUMENT_NODE:
4360 case XML_HTML_DOCUMENT_NODE:
4361 case XML_DOCUMENT_TYPE_NODE:
4362 case XML_XINCLUDE_START:
4363 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004364#ifdef LIBXML_DOCB_ENABLED
4365 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004366#endif
4367 break;
4368 case XML_NOTATION_NODE:
4369 break;
4370 case XML_DTD_NODE:
4371 break;
4372 case XML_NAMESPACE_DECL:
4373 break;
4374 case XML_ELEMENT_DECL:
4375 /* TODO !!! */
4376 break;
4377 case XML_ATTRIBUTE_DECL:
4378 /* TODO !!! */
4379 break;
4380 case XML_ENTITY_DECL:
4381 /* TODO !!! */
4382 break;
4383 }
4384}
4385
4386/**
4387 * xmlNodeSetContentLen:
4388 * @cur: the node being modified
4389 * @content: the new value of the content
4390 * @len: the size of @content
4391 *
4392 * Replace the content of a node.
4393 */
4394void
4395xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4396 if (cur == NULL) {
4397#ifdef DEBUG_TREE
4398 xmlGenericError(xmlGenericErrorContext,
4399 "xmlNodeSetContentLen : node == NULL\n");
4400#endif
4401 return;
4402 }
4403 switch (cur->type) {
4404 case XML_DOCUMENT_FRAG_NODE:
4405 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004406 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004407 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4408 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4409 UPDATE_LAST_CHILD_AND_PARENT(cur)
4410 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004411 case XML_TEXT_NODE:
4412 case XML_CDATA_SECTION_NODE:
4413 case XML_ENTITY_REF_NODE:
4414 case XML_ENTITY_NODE:
4415 case XML_PI_NODE:
4416 case XML_COMMENT_NODE:
4417 case XML_NOTATION_NODE:
4418 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004419 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004420 }
4421 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4422 cur->children = cur->last = NULL;
4423 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004424 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004425 } else
4426 cur->content = NULL;
4427 break;
4428 case XML_DOCUMENT_NODE:
4429 case XML_DTD_NODE:
4430 case XML_HTML_DOCUMENT_NODE:
4431 case XML_DOCUMENT_TYPE_NODE:
4432 case XML_NAMESPACE_DECL:
4433 case XML_XINCLUDE_START:
4434 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004435#ifdef LIBXML_DOCB_ENABLED
4436 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004437#endif
4438 break;
4439 case XML_ELEMENT_DECL:
4440 /* TODO !!! */
4441 break;
4442 case XML_ATTRIBUTE_DECL:
4443 /* TODO !!! */
4444 break;
4445 case XML_ENTITY_DECL:
4446 /* TODO !!! */
4447 break;
4448 }
4449}
4450
4451/**
4452 * xmlNodeAddContentLen:
4453 * @cur: the node being modified
4454 * @content: extra content
4455 * @len: the size of @content
4456 *
4457 * Append the extra substring to the node content.
4458 */
4459void
4460xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4461 if (cur == NULL) {
4462#ifdef DEBUG_TREE
4463 xmlGenericError(xmlGenericErrorContext,
4464 "xmlNodeAddContentLen : node == NULL\n");
4465#endif
4466 return;
4467 }
4468 if (len <= 0) return;
4469 switch (cur->type) {
4470 case XML_DOCUMENT_FRAG_NODE:
4471 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004472 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004473
Daniel Veillard7db37732001-07-12 01:20:08 +00004474 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004475 newNode = xmlNewTextLen(content, len);
4476 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004477 tmp = xmlAddChild(cur, newNode);
4478 if (tmp != newNode)
4479 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004480 if ((last != NULL) && (last->next == newNode)) {
4481 xmlTextMerge(last, newNode);
4482 }
4483 }
4484 break;
4485 }
4486 case XML_ATTRIBUTE_NODE:
4487 break;
4488 case XML_TEXT_NODE:
4489 case XML_CDATA_SECTION_NODE:
4490 case XML_ENTITY_REF_NODE:
4491 case XML_ENTITY_NODE:
4492 case XML_PI_NODE:
4493 case XML_COMMENT_NODE:
4494 case XML_NOTATION_NODE:
4495 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004496 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004497 }
4498 case XML_DOCUMENT_NODE:
4499 case XML_DTD_NODE:
4500 case XML_HTML_DOCUMENT_NODE:
4501 case XML_DOCUMENT_TYPE_NODE:
4502 case XML_NAMESPACE_DECL:
4503 case XML_XINCLUDE_START:
4504 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004505#ifdef LIBXML_DOCB_ENABLED
4506 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004507#endif
4508 break;
4509 case XML_ELEMENT_DECL:
4510 case XML_ATTRIBUTE_DECL:
4511 case XML_ENTITY_DECL:
4512 break;
4513 }
4514}
4515
4516/**
4517 * xmlNodeAddContent:
4518 * @cur: the node being modified
4519 * @content: extra content
4520 *
4521 * Append the extra substring to the node content.
4522 */
4523void
4524xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4525 int len;
4526
4527 if (cur == NULL) {
4528#ifdef DEBUG_TREE
4529 xmlGenericError(xmlGenericErrorContext,
4530 "xmlNodeAddContent : node == NULL\n");
4531#endif
4532 return;
4533 }
4534 if (content == NULL) return;
4535 len = xmlStrlen(content);
4536 xmlNodeAddContentLen(cur, content, len);
4537}
4538
4539/**
4540 * xmlTextMerge:
4541 * @first: the first text node
4542 * @second: the second text node being merged
4543 *
4544 * Merge two text nodes into one
4545 * Returns the first text node augmented
4546 */
4547xmlNodePtr
4548xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4549 if (first == NULL) return(second);
4550 if (second == NULL) return(first);
4551 if (first->type != XML_TEXT_NODE) return(first);
4552 if (second->type != XML_TEXT_NODE) return(first);
4553 if (second->name != first->name)
4554 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004555 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004556 xmlUnlinkNode(second);
4557 xmlFreeNode(second);
4558 return(first);
4559}
4560
4561/**
4562 * xmlGetNsList:
4563 * @doc: the document
4564 * @node: the current node
4565 *
4566 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004567 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004568 * that need to be freed by the caller or NULL if no
4569 * namespace if defined
4570 */
4571xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004572xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4573{
Owen Taylor3473f882001-02-23 17:55:21 +00004574 xmlNsPtr cur;
4575 xmlNsPtr *ret = NULL;
4576 int nbns = 0;
4577 int maxns = 10;
4578 int i;
4579
4580 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004581 if (node->type == XML_ELEMENT_NODE) {
4582 cur = node->nsDef;
4583 while (cur != NULL) {
4584 if (ret == NULL) {
4585 ret =
4586 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4587 sizeof(xmlNsPtr));
4588 if (ret == NULL) {
4589 xmlGenericError(xmlGenericErrorContext,
4590 "xmlGetNsList : out of memory!\n");
4591 return (NULL);
4592 }
4593 ret[nbns] = NULL;
4594 }
4595 for (i = 0; i < nbns; i++) {
4596 if ((cur->prefix == ret[i]->prefix) ||
4597 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4598 break;
4599 }
4600 if (i >= nbns) {
4601 if (nbns >= maxns) {
4602 maxns *= 2;
4603 ret = (xmlNsPtr *) xmlRealloc(ret,
4604 (maxns +
4605 1) *
4606 sizeof(xmlNsPtr));
4607 if (ret == NULL) {
4608 xmlGenericError(xmlGenericErrorContext,
4609 "xmlGetNsList : realloc failed!\n");
4610 return (NULL);
4611 }
4612 }
4613 ret[nbns++] = cur;
4614 ret[nbns] = NULL;
4615 }
Owen Taylor3473f882001-02-23 17:55:21 +00004616
Daniel Veillard77044732001-06-29 21:31:07 +00004617 cur = cur->next;
4618 }
4619 }
4620 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004621 }
Daniel Veillard77044732001-06-29 21:31:07 +00004622 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004623}
4624
4625/**
4626 * xmlSearchNs:
4627 * @doc: the document
4628 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004629 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004630 *
4631 * Search a Ns registered under a given name space for a document.
4632 * recurse on the parents until it finds the defined namespace
4633 * or return NULL otherwise.
4634 * @nameSpace can be NULL, this is a search for the default namespace.
4635 * We don't allow to cross entities boundaries. If you don't declare
4636 * the namespace within those you will be in troubles !!! A warning
4637 * is generated to cover this case.
4638 *
4639 * Returns the namespace pointer or NULL.
4640 */
4641xmlNsPtr
4642xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4643 xmlNsPtr cur;
4644
4645 if (node == NULL) return(NULL);
4646 if ((nameSpace != NULL) &&
4647 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00004648 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4649 /*
4650 * The XML-1.0 namespace is normally held on the root
4651 * element. In this case exceptionally create it on the
4652 * node element.
4653 */
4654 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4655 if (cur == NULL) {
4656 xmlGenericError(xmlGenericErrorContext,
4657 "xmlSearchNs : malloc failed\n");
4658 return(NULL);
4659 }
4660 memset(cur, 0, sizeof(xmlNs));
4661 cur->type = XML_LOCAL_NAMESPACE;
4662 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4663 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4664 cur->next = node->nsDef;
4665 node->nsDef = cur;
4666 return(cur);
4667 }
Owen Taylor3473f882001-02-23 17:55:21 +00004668 if (doc->oldNs == NULL) {
4669 /*
4670 * Allocate a new Namespace and fill the fields.
4671 */
4672 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4673 if (doc->oldNs == NULL) {
4674 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004675 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004676 return(NULL);
4677 }
4678 memset(doc->oldNs, 0, sizeof(xmlNs));
4679 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4680
4681 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4682 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4683 }
4684 return(doc->oldNs);
4685 }
4686 while (node != NULL) {
4687 if ((node->type == XML_ENTITY_REF_NODE) ||
4688 (node->type == XML_ENTITY_NODE) ||
4689 (node->type == XML_ENTITY_DECL))
4690 return(NULL);
4691 if (node->type == XML_ELEMENT_NODE) {
4692 cur = node->nsDef;
4693 while (cur != NULL) {
4694 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4695 (cur->href != NULL))
4696 return(cur);
4697 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4698 (cur->href != NULL) &&
4699 (xmlStrEqual(cur->prefix, nameSpace)))
4700 return(cur);
4701 cur = cur->next;
4702 }
4703 }
4704 node = node->parent;
4705 }
4706 return(NULL);
4707}
4708
4709/**
4710 * xmlSearchNsByHref:
4711 * @doc: the document
4712 * @node: the current node
4713 * @href: the namespace value
4714 *
4715 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4716 * the defined namespace or return NULL otherwise.
4717 * Returns the namespace pointer or NULL.
4718 */
4719xmlNsPtr
4720xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4721 xmlNsPtr cur;
4722 xmlNodePtr orig = node;
4723
4724 if ((node == NULL) || (href == NULL)) return(NULL);
4725 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004726 /*
4727 * Only the document can hold the XML spec namespace.
4728 */
Daniel Veillardc1a0da32002-08-14 08:32:18 +00004729 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4730 /*
4731 * The XML-1.0 namespace is normally held on the root
4732 * element. In this case exceptionally create it on the
4733 * node element.
4734 */
4735 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4736 if (cur == NULL) {
4737 xmlGenericError(xmlGenericErrorContext,
4738 "xmlSearchNs : malloc failed\n");
4739 return(NULL);
4740 }
4741 memset(cur, 0, sizeof(xmlNs));
4742 cur->type = XML_LOCAL_NAMESPACE;
4743 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4744 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4745 cur->next = node->nsDef;
4746 node->nsDef = cur;
4747 return(cur);
4748 }
Owen Taylor3473f882001-02-23 17:55:21 +00004749 if (doc->oldNs == NULL) {
4750 /*
4751 * Allocate a new Namespace and fill the fields.
4752 */
4753 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4754 if (doc->oldNs == NULL) {
4755 xmlGenericError(xmlGenericErrorContext,
4756 "xmlSearchNsByHref : malloc failed\n");
4757 return(NULL);
4758 }
4759 memset(doc->oldNs, 0, sizeof(xmlNs));
4760 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4761
4762 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4763 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4764 }
4765 return(doc->oldNs);
4766 }
4767 while (node != NULL) {
4768 cur = node->nsDef;
4769 while (cur != NULL) {
4770 if ((cur->href != NULL) && (href != NULL) &&
4771 (xmlStrEqual(cur->href, href))) {
4772 /*
4773 * Check that the prefix is not shadowed between orig and node
4774 */
4775 xmlNodePtr check = orig;
4776 xmlNsPtr tst;
4777
4778 while (check != node) {
4779 tst = check->nsDef;
4780 while (tst != NULL) {
4781 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4782 goto shadowed;
4783 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4784 (xmlStrEqual(tst->prefix, cur->prefix)))
4785 goto shadowed;
4786 tst = tst->next;
4787 }
4788 check = check->parent;
4789 }
4790 return(cur);
4791 }
4792shadowed:
4793 cur = cur->next;
4794 }
4795 node = node->parent;
4796 }
4797 return(NULL);
4798}
4799
4800/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004801 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00004802 * @doc: the document
4803 * @tree: a node expected to hold the new namespace
4804 * @ns: the original namespace
4805 *
4806 * This function tries to locate a namespace definition in a tree
4807 * ancestors, or create a new namespace definition node similar to
4808 * @ns trying to reuse the same prefix. However if the given prefix is
4809 * null (default namespace) or reused within the subtree defined by
4810 * @tree or on one of its ancestors then a new prefix is generated.
4811 * Returns the (new) namespace definition or NULL in case of error
4812 */
4813xmlNsPtr
4814xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4815 xmlNsPtr def;
4816 xmlChar prefix[50];
4817 int counter = 1;
4818
4819 if (tree == NULL) {
4820#ifdef DEBUG_TREE
4821 xmlGenericError(xmlGenericErrorContext,
4822 "xmlNewReconciliedNs : tree == NULL\n");
4823#endif
4824 return(NULL);
4825 }
4826 if (ns == NULL) {
4827#ifdef DEBUG_TREE
4828 xmlGenericError(xmlGenericErrorContext,
4829 "xmlNewReconciliedNs : ns == NULL\n");
4830#endif
4831 return(NULL);
4832 }
4833 /*
4834 * Search an existing namespace definition inherited.
4835 */
4836 def = xmlSearchNsByHref(doc, tree, ns->href);
4837 if (def != NULL)
4838 return(def);
4839
4840 /*
4841 * Find a close prefix which is not already in use.
4842 * Let's strip namespace prefixes longer than 20 chars !
4843 */
Daniel Veillardf742d342002-03-07 00:05:35 +00004844 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004845 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00004846 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004847 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00004848
Owen Taylor3473f882001-02-23 17:55:21 +00004849 def = xmlSearchNs(doc, tree, prefix);
4850 while (def != NULL) {
4851 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00004852 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004853 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00004854 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004855 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00004856 def = xmlSearchNs(doc, tree, prefix);
4857 }
4858
4859 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004860 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004861 */
4862 def = xmlNewNs(tree, ns->href, prefix);
4863 return(def);
4864}
4865
4866/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004867 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00004868 * @doc: the document
4869 * @tree: a node defining the subtree to reconciliate
4870 *
4871 * This function checks that all the namespaces declared within the given
4872 * tree are properly declared. This is needed for example after Copy or Cut
4873 * and then paste operations. The subtree may still hold pointers to
4874 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004875 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004876 * the new environment. If not possible the new namespaces are redeclared
4877 * on @tree at the top of the given subtree.
4878 * Returns the number of namespace declarations created or -1 in case of error.
4879 */
4880int
4881xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4882 xmlNsPtr *oldNs = NULL;
4883 xmlNsPtr *newNs = NULL;
4884 int sizeCache = 0;
4885 int nbCache = 0;
4886
4887 xmlNsPtr n;
4888 xmlNodePtr node = tree;
4889 xmlAttrPtr attr;
4890 int ret = 0, i;
4891
4892 while (node != NULL) {
4893 /*
4894 * Reconciliate the node namespace
4895 */
4896 if (node->ns != NULL) {
4897 /*
4898 * initialize the cache if needed
4899 */
4900 if (sizeCache == 0) {
4901 sizeCache = 10;
4902 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4903 sizeof(xmlNsPtr));
4904 if (oldNs == NULL) {
4905 xmlGenericError(xmlGenericErrorContext,
4906 "xmlReconciliateNs : memory pbm\n");
4907 return(-1);
4908 }
4909 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4910 sizeof(xmlNsPtr));
4911 if (newNs == NULL) {
4912 xmlGenericError(xmlGenericErrorContext,
4913 "xmlReconciliateNs : memory pbm\n");
4914 xmlFree(oldNs);
4915 return(-1);
4916 }
4917 }
4918 for (i = 0;i < nbCache;i++) {
4919 if (oldNs[i] == node->ns) {
4920 node->ns = newNs[i];
4921 break;
4922 }
4923 }
4924 if (i == nbCache) {
4925 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004926 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004927 */
4928 n = xmlNewReconciliedNs(doc, tree, node->ns);
4929 if (n != NULL) { /* :-( what if else ??? */
4930 /*
4931 * check if we need to grow the cache buffers.
4932 */
4933 if (sizeCache <= nbCache) {
4934 sizeCache *= 2;
4935 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4936 sizeof(xmlNsPtr));
4937 if (oldNs == NULL) {
4938 xmlGenericError(xmlGenericErrorContext,
4939 "xmlReconciliateNs : memory pbm\n");
4940 xmlFree(newNs);
4941 return(-1);
4942 }
4943 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4944 sizeof(xmlNsPtr));
4945 if (newNs == NULL) {
4946 xmlGenericError(xmlGenericErrorContext,
4947 "xmlReconciliateNs : memory pbm\n");
4948 xmlFree(oldNs);
4949 return(-1);
4950 }
4951 }
4952 newNs[nbCache] = n;
4953 oldNs[nbCache++] = node->ns;
4954 node->ns = n;
4955 }
4956 }
4957 }
4958 /*
4959 * now check for namespace hold by attributes on the node.
4960 */
4961 attr = node->properties;
4962 while (attr != NULL) {
4963 if (attr->ns != NULL) {
4964 /*
4965 * initialize the cache if needed
4966 */
4967 if (sizeCache == 0) {
4968 sizeCache = 10;
4969 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4970 sizeof(xmlNsPtr));
4971 if (oldNs == NULL) {
4972 xmlGenericError(xmlGenericErrorContext,
4973 "xmlReconciliateNs : memory pbm\n");
4974 return(-1);
4975 }
4976 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4977 sizeof(xmlNsPtr));
4978 if (newNs == NULL) {
4979 xmlGenericError(xmlGenericErrorContext,
4980 "xmlReconciliateNs : memory pbm\n");
4981 xmlFree(oldNs);
4982 return(-1);
4983 }
4984 }
4985 for (i = 0;i < nbCache;i++) {
4986 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00004987 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00004988 break;
4989 }
4990 }
4991 if (i == nbCache) {
4992 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004993 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004994 */
4995 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4996 if (n != NULL) { /* :-( what if else ??? */
4997 /*
4998 * check if we need to grow the cache buffers.
4999 */
5000 if (sizeCache <= nbCache) {
5001 sizeCache *= 2;
5002 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5003 sizeof(xmlNsPtr));
5004 if (oldNs == NULL) {
5005 xmlGenericError(xmlGenericErrorContext,
5006 "xmlReconciliateNs : memory pbm\n");
5007 xmlFree(newNs);
5008 return(-1);
5009 }
5010 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5011 sizeof(xmlNsPtr));
5012 if (newNs == NULL) {
5013 xmlGenericError(xmlGenericErrorContext,
5014 "xmlReconciliateNs : memory pbm\n");
5015 xmlFree(oldNs);
5016 return(-1);
5017 }
5018 }
5019 newNs[nbCache] = n;
5020 oldNs[nbCache++] = attr->ns;
5021 attr->ns = n;
5022 }
5023 }
5024 }
5025 attr = attr->next;
5026 }
5027
5028 /*
5029 * Browse the full subtree, deep first
5030 */
5031 if (node->children != NULL) {
5032 /* deep first */
5033 node = node->children;
5034 } else if ((node != tree) && (node->next != NULL)) {
5035 /* then siblings */
5036 node = node->next;
5037 } else if (node != tree) {
5038 /* go up to parents->next if needed */
5039 while (node != tree) {
5040 if (node->parent != NULL)
5041 node = node->parent;
5042 if ((node != tree) && (node->next != NULL)) {
5043 node = node->next;
5044 break;
5045 }
5046 if (node->parent == NULL) {
5047 node = NULL;
5048 break;
5049 }
5050 }
5051 /* exit condition */
5052 if (node == tree)
5053 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005054 } else
5055 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005056 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005057 if (oldNs != NULL)
5058 xmlFree(oldNs);
5059 if (newNs != NULL)
5060 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005061 return(ret);
5062}
5063
5064/**
5065 * xmlHasProp:
5066 * @node: the node
5067 * @name: the attribute name
5068 *
5069 * Search an attribute associated to a node
5070 * This function also looks in DTD attribute declaration for #FIXED or
5071 * default declaration values unless DTD use has been turned off.
5072 *
5073 * Returns the attribute or the attribute declaration or NULL if
5074 * neither was found.
5075 */
5076xmlAttrPtr
5077xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5078 xmlAttrPtr prop;
5079 xmlDocPtr doc;
5080
5081 if ((node == NULL) || (name == NULL)) return(NULL);
5082 /*
5083 * Check on the properties attached to the node
5084 */
5085 prop = node->properties;
5086 while (prop != NULL) {
5087 if (xmlStrEqual(prop->name, name)) {
5088 return(prop);
5089 }
5090 prop = prop->next;
5091 }
5092 if (!xmlCheckDTD) return(NULL);
5093
5094 /*
5095 * Check if there is a default declaration in the internal
5096 * or external subsets
5097 */
5098 doc = node->doc;
5099 if (doc != NULL) {
5100 xmlAttributePtr attrDecl;
5101 if (doc->intSubset != NULL) {
5102 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5103 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5104 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5105 if (attrDecl != NULL)
5106 return((xmlAttrPtr) attrDecl);
5107 }
5108 }
5109 return(NULL);
5110}
5111
5112/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005113 * xmlHasNsProp:
5114 * @node: the node
5115 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005116 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005117 *
5118 * Search for an attribute associated to a node
5119 * This attribute has to be anchored in the namespace specified.
5120 * This does the entity substitution.
5121 * This function looks in DTD attribute declaration for #FIXED or
5122 * default declaration values unless DTD use has been turned off.
5123 *
5124 * Returns the attribute or the attribute declaration or NULL
5125 * if neither was found.
5126 */
5127xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005128xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005129 xmlAttrPtr prop;
5130 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005131
5132 if (node == NULL)
5133 return(NULL);
5134
5135 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005136 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005137 return(xmlHasProp(node, name));
5138 while (prop != NULL) {
5139 /*
5140 * One need to have
5141 * - same attribute names
5142 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005143 */
5144 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005145 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5146 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005147 }
5148 prop = prop->next;
5149 }
5150 if (!xmlCheckDTD) return(NULL);
5151
5152 /*
5153 * Check if there is a default declaration in the internal
5154 * or external subsets
5155 */
5156 doc = node->doc;
5157 if (doc != NULL) {
5158 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005159 xmlAttributePtr attrDecl = NULL;
5160 xmlNsPtr *nsList, *cur;
5161 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005162
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005163 nsList = xmlGetNsList(node->doc, node);
5164 if (nsList == NULL)
5165 return(NULL);
5166 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5167 ename = xmlStrdup(node->ns->prefix);
5168 ename = xmlStrcat(ename, BAD_CAST ":");
5169 ename = xmlStrcat(ename, node->name);
5170 } else {
5171 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005172 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005173 if (ename == NULL) {
5174 xmlFree(nsList);
5175 return(NULL);
5176 }
5177
5178 cur = nsList;
5179 while (*cur != NULL) {
5180 if (xmlStrEqual((*cur)->href, nameSpace)) {
5181 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5182 name, (*cur)->prefix);
5183 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5184 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5185 name, (*cur)->prefix);
5186 }
5187 cur++;
5188 }
5189 xmlFree(nsList);
5190 xmlFree(ename);
5191 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005192 }
5193 }
5194 return(NULL);
5195}
5196
5197/**
Owen Taylor3473f882001-02-23 17:55:21 +00005198 * xmlGetProp:
5199 * @node: the node
5200 * @name: the attribute name
5201 *
5202 * Search and get the value of an attribute associated to a node
5203 * This does the entity substitution.
5204 * This function looks in DTD attribute declaration for #FIXED or
5205 * default declaration values unless DTD use has been turned off.
5206 *
5207 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005208 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005209 */
5210xmlChar *
5211xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5212 xmlAttrPtr prop;
5213 xmlDocPtr doc;
5214
5215 if ((node == NULL) || (name == NULL)) return(NULL);
5216 /*
5217 * Check on the properties attached to the node
5218 */
5219 prop = node->properties;
5220 while (prop != NULL) {
5221 if (xmlStrEqual(prop->name, name)) {
5222 xmlChar *ret;
5223
5224 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5225 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5226 return(ret);
5227 }
5228 prop = prop->next;
5229 }
5230 if (!xmlCheckDTD) return(NULL);
5231
5232 /*
5233 * Check if there is a default declaration in the internal
5234 * or external subsets
5235 */
5236 doc = node->doc;
5237 if (doc != NULL) {
5238 xmlAttributePtr attrDecl;
5239 if (doc->intSubset != NULL) {
5240 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5241 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5242 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5243 if (attrDecl != NULL)
5244 return(xmlStrdup(attrDecl->defaultValue));
5245 }
5246 }
5247 return(NULL);
5248}
5249
5250/**
5251 * xmlGetNsProp:
5252 * @node: the node
5253 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005254 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005255 *
5256 * Search and get the value of an attribute associated to a node
5257 * This attribute has to be anchored in the namespace specified.
5258 * This does the entity substitution.
5259 * This function looks in DTD attribute declaration for #FIXED or
5260 * default declaration values unless DTD use has been turned off.
5261 *
5262 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005263 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005264 */
5265xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005266xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005267 xmlAttrPtr prop;
5268 xmlDocPtr doc;
5269 xmlNsPtr ns;
5270
5271 if (node == NULL)
5272 return(NULL);
5273
5274 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005275 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005276 return(xmlGetProp(node, name));
5277 while (prop != NULL) {
5278 /*
5279 * One need to have
5280 * - same attribute names
5281 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005282 */
5283 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005284 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005285 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005286 xmlChar *ret;
5287
5288 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5289 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5290 return(ret);
5291 }
5292 prop = prop->next;
5293 }
5294 if (!xmlCheckDTD) return(NULL);
5295
5296 /*
5297 * Check if there is a default declaration in the internal
5298 * or external subsets
5299 */
5300 doc = node->doc;
5301 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005302 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005303 xmlAttributePtr attrDecl;
5304
Owen Taylor3473f882001-02-23 17:55:21 +00005305 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5306 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5307 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5308
5309 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5310 /*
5311 * The DTD declaration only allows a prefix search
5312 */
5313 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005314 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005315 return(xmlStrdup(attrDecl->defaultValue));
5316 }
5317 }
5318 }
5319 return(NULL);
5320}
5321
5322/**
5323 * xmlSetProp:
5324 * @node: the node
5325 * @name: the attribute name
5326 * @value: the attribute value
5327 *
5328 * Set (or reset) an attribute carried by a node.
5329 * Returns the attribute pointer.
5330 */
5331xmlAttrPtr
5332xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005333 xmlAttrPtr prop;
5334 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005335
5336 if ((node == NULL) || (name == NULL))
5337 return(NULL);
5338 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005339 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005340 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005341 if ((xmlStrEqual(prop->name, name)) &&
5342 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005343 xmlNodePtr oldprop = prop->children;
5344
Owen Taylor3473f882001-02-23 17:55:21 +00005345 prop->children = NULL;
5346 prop->last = NULL;
5347 if (value != NULL) {
5348 xmlChar *buffer;
5349 xmlNodePtr tmp;
5350
5351 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5352 prop->children = xmlStringGetNodeList(node->doc, buffer);
5353 prop->last = NULL;
5354 prop->doc = doc;
5355 tmp = prop->children;
5356 while (tmp != NULL) {
5357 tmp->parent = (xmlNodePtr) prop;
5358 tmp->doc = doc;
5359 if (tmp->next == NULL)
5360 prop->last = tmp;
5361 tmp = tmp->next;
5362 }
5363 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005364 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005365 if (oldprop != NULL)
5366 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005367 return(prop);
5368 }
5369 prop = prop->next;
5370 }
5371 prop = xmlNewProp(node, name, value);
5372 return(prop);
5373}
5374
5375/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005376 * xmlUnsetProp:
5377 * @node: the node
5378 * @name: the attribute name
5379 *
5380 * Remove an attribute carried by a node.
5381 * Returns 0 if successful, -1 if not found
5382 */
5383int
5384xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard814a76d2003-01-23 18:24:20 +00005385 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard75bea542001-05-11 17:41:21 +00005386
5387 if ((node == NULL) || (name == NULL))
5388 return(-1);
Daniel Veillard814a76d2003-01-23 18:24:20 +00005389 prop = node->properties;
Daniel Veillard75bea542001-05-11 17:41:21 +00005390 while (prop != NULL) {
5391 if ((xmlStrEqual(prop->name, name)) &&
5392 (prop->ns == NULL)) {
5393 if (prev == NULL)
5394 node->properties = prop->next;
5395 else
5396 prev->next = prop->next;
5397 xmlFreeProp(prop);
5398 return(0);
5399 }
5400 prev = prop;
5401 prop = prop->next;
5402 }
5403 return(-1);
5404}
5405
5406/**
Owen Taylor3473f882001-02-23 17:55:21 +00005407 * xmlSetNsProp:
5408 * @node: the node
5409 * @ns: the namespace definition
5410 * @name: the attribute name
5411 * @value: the attribute value
5412 *
5413 * Set (or reset) an attribute carried by a node.
5414 * The ns structure must be in scope, this is not checked.
5415 *
5416 * Returns the attribute pointer.
5417 */
5418xmlAttrPtr
5419xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5420 const xmlChar *value) {
5421 xmlAttrPtr prop;
5422
5423 if ((node == NULL) || (name == NULL))
5424 return(NULL);
5425
5426 if (ns == NULL)
5427 return(xmlSetProp(node, name, value));
5428 if (ns->href == NULL)
5429 return(NULL);
5430 prop = node->properties;
5431
5432 while (prop != NULL) {
5433 /*
5434 * One need to have
5435 * - same attribute names
5436 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005437 */
5438 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00005439 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005440 if (prop->children != NULL)
5441 xmlFreeNodeList(prop->children);
5442 prop->children = NULL;
5443 prop->last = NULL;
5444 prop->ns = ns;
5445 if (value != NULL) {
5446 xmlChar *buffer;
5447 xmlNodePtr tmp;
5448
5449 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5450 prop->children = xmlStringGetNodeList(node->doc, buffer);
5451 prop->last = NULL;
5452 tmp = prop->children;
5453 while (tmp != NULL) {
5454 tmp->parent = (xmlNodePtr) prop;
5455 if (tmp->next == NULL)
5456 prop->last = tmp;
5457 tmp = tmp->next;
5458 }
5459 xmlFree(buffer);
5460 }
5461 return(prop);
5462 }
5463 prop = prop->next;
5464 }
5465 prop = xmlNewNsProp(node, ns, name, value);
5466 return(prop);
5467}
5468
5469/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005470 * xmlUnsetNsProp:
5471 * @node: the node
5472 * @ns: the namespace definition
5473 * @name: the attribute name
5474 *
5475 * Remove an attribute carried by a node.
5476 * Returns 0 if successful, -1 if not found
5477 */
5478int
5479xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5480 xmlAttrPtr prop = node->properties, prev = NULL;;
5481
5482 if ((node == NULL) || (name == NULL))
5483 return(-1);
5484 if (ns == NULL)
5485 return(xmlUnsetProp(node, name));
5486 if (ns->href == NULL)
5487 return(-1);
5488 while (prop != NULL) {
5489 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00005490 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005491 if (prev == NULL)
5492 node->properties = prop->next;
5493 else
5494 prev->next = prop->next;
5495 xmlFreeProp(prop);
5496 return(0);
5497 }
5498 prev = prop;
5499 prop = prop->next;
5500 }
5501 return(-1);
5502}
5503
5504/**
Owen Taylor3473f882001-02-23 17:55:21 +00005505 * xmlNodeIsText:
5506 * @node: the node
5507 *
5508 * Is this node a Text node ?
5509 * Returns 1 yes, 0 no
5510 */
5511int
5512xmlNodeIsText(xmlNodePtr node) {
5513 if (node == NULL) return(0);
5514
5515 if (node->type == XML_TEXT_NODE) return(1);
5516 return(0);
5517}
5518
5519/**
5520 * xmlIsBlankNode:
5521 * @node: the node
5522 *
5523 * Checks whether this node is an empty or whitespace only
5524 * (and possibly ignorable) text-node.
5525 *
5526 * Returns 1 yes, 0 no
5527 */
5528int
5529xmlIsBlankNode(xmlNodePtr node) {
5530 const xmlChar *cur;
5531 if (node == NULL) return(0);
5532
Daniel Veillard7db37732001-07-12 01:20:08 +00005533 if ((node->type != XML_TEXT_NODE) &&
5534 (node->type != XML_CDATA_SECTION_NODE))
5535 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005536 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005537 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005538 while (*cur != 0) {
5539 if (!IS_BLANK(*cur)) return(0);
5540 cur++;
5541 }
5542
5543 return(1);
5544}
5545
5546/**
5547 * xmlTextConcat:
5548 * @node: the node
5549 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005550 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005551 *
5552 * Concat the given string at the end of the existing node content
5553 */
5554
5555void
5556xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5557 if (node == NULL) return;
5558
5559 if ((node->type != XML_TEXT_NODE) &&
5560 (node->type != XML_CDATA_SECTION_NODE)) {
5561#ifdef DEBUG_TREE
5562 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005563 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005564#endif
5565 return;
5566 }
Owen Taylor3473f882001-02-23 17:55:21 +00005567 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005568}
5569
5570/************************************************************************
5571 * *
5572 * Output : to a FILE or in memory *
5573 * *
5574 ************************************************************************/
5575
Owen Taylor3473f882001-02-23 17:55:21 +00005576/**
5577 * xmlBufferCreate:
5578 *
5579 * routine to create an XML buffer.
5580 * returns the new structure.
5581 */
5582xmlBufferPtr
5583xmlBufferCreate(void) {
5584 xmlBufferPtr ret;
5585
5586 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5587 if (ret == NULL) {
5588 xmlGenericError(xmlGenericErrorContext,
5589 "xmlBufferCreate : out of memory!\n");
5590 return(NULL);
5591 }
5592 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005593 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005594 ret->alloc = xmlBufferAllocScheme;
5595 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5596 if (ret->content == NULL) {
5597 xmlGenericError(xmlGenericErrorContext,
5598 "xmlBufferCreate : out of memory!\n");
5599 xmlFree(ret);
5600 return(NULL);
5601 }
5602 ret->content[0] = 0;
5603 return(ret);
5604}
5605
5606/**
5607 * xmlBufferCreateSize:
5608 * @size: initial size of buffer
5609 *
5610 * routine to create an XML buffer.
5611 * returns the new structure.
5612 */
5613xmlBufferPtr
5614xmlBufferCreateSize(size_t size) {
5615 xmlBufferPtr ret;
5616
5617 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5618 if (ret == NULL) {
5619 xmlGenericError(xmlGenericErrorContext,
5620 "xmlBufferCreate : out of memory!\n");
5621 return(NULL);
5622 }
5623 ret->use = 0;
5624 ret->alloc = xmlBufferAllocScheme;
5625 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5626 if (ret->size){
5627 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5628 if (ret->content == NULL) {
5629 xmlGenericError(xmlGenericErrorContext,
5630 "xmlBufferCreate : out of memory!\n");
5631 xmlFree(ret);
5632 return(NULL);
5633 }
5634 ret->content[0] = 0;
5635 } else
5636 ret->content = NULL;
5637 return(ret);
5638}
5639
5640/**
5641 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005642 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00005643 * @scheme: allocation scheme to use
5644 *
5645 * Sets the allocation scheme for this buffer
5646 */
5647void
5648xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5649 xmlBufferAllocationScheme scheme) {
5650 if (buf == NULL) {
5651#ifdef DEBUG_BUFFER
5652 xmlGenericError(xmlGenericErrorContext,
5653 "xmlBufferSetAllocationScheme: buf == NULL\n");
5654#endif
5655 return;
5656 }
5657
5658 buf->alloc = scheme;
5659}
5660
5661/**
5662 * xmlBufferFree:
5663 * @buf: the buffer to free
5664 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005665 * Frees an XML buffer. It frees both the content and the structure which
5666 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005667 */
5668void
5669xmlBufferFree(xmlBufferPtr buf) {
5670 if (buf == NULL) {
5671#ifdef DEBUG_BUFFER
5672 xmlGenericError(xmlGenericErrorContext,
5673 "xmlBufferFree: buf == NULL\n");
5674#endif
5675 return;
5676 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00005677 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005678 xmlFree(buf->content);
5679 }
Owen Taylor3473f882001-02-23 17:55:21 +00005680 xmlFree(buf);
5681}
5682
5683/**
5684 * xmlBufferEmpty:
5685 * @buf: the buffer
5686 *
5687 * empty a buffer.
5688 */
5689void
5690xmlBufferEmpty(xmlBufferPtr buf) {
5691 if (buf->content == NULL) return;
5692 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005693 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005694}
5695
5696/**
5697 * xmlBufferShrink:
5698 * @buf: the buffer to dump
5699 * @len: the number of xmlChar to remove
5700 *
5701 * Remove the beginning of an XML buffer.
5702 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005703 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005704 */
5705int
5706xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5707 if (len == 0) return(0);
5708 if (len > buf->use) return(-1);
5709
5710 buf->use -= len;
5711 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5712
5713 buf->content[buf->use] = 0;
5714 return(len);
5715}
5716
5717/**
5718 * xmlBufferGrow:
5719 * @buf: the buffer
5720 * @len: the minimum free size to allocate
5721 *
5722 * Grow the available space of an XML buffer.
5723 *
5724 * Returns the new available space or -1 in case of error
5725 */
5726int
5727xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5728 int size;
5729 xmlChar *newbuf;
5730
5731 if (len + buf->use < buf->size) return(0);
5732
5733 size = buf->use + len + 100;
5734
5735 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5736 if (newbuf == NULL) return(-1);
5737 buf->content = newbuf;
5738 buf->size = size;
5739 return(buf->size - buf->use);
5740}
5741
5742/**
5743 * xmlBufferDump:
5744 * @file: the file output
5745 * @buf: the buffer to dump
5746 *
5747 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005748 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005749 */
5750int
5751xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5752 int ret;
5753
5754 if (buf == NULL) {
5755#ifdef DEBUG_BUFFER
5756 xmlGenericError(xmlGenericErrorContext,
5757 "xmlBufferDump: buf == NULL\n");
5758#endif
5759 return(0);
5760 }
5761 if (buf->content == NULL) {
5762#ifdef DEBUG_BUFFER
5763 xmlGenericError(xmlGenericErrorContext,
5764 "xmlBufferDump: buf->content == NULL\n");
5765#endif
5766 return(0);
5767 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005768 if (file == NULL)
5769 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005770 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5771 return(ret);
5772}
5773
5774/**
5775 * xmlBufferContent:
5776 * @buf: the buffer
5777 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005778 * Function to extract the content of a buffer
5779 *
Owen Taylor3473f882001-02-23 17:55:21 +00005780 * Returns the internal content
5781 */
5782
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005783const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005784xmlBufferContent(const xmlBufferPtr buf)
5785{
5786 if(!buf)
5787 return NULL;
5788
5789 return buf->content;
5790}
5791
5792/**
5793 * xmlBufferLength:
5794 * @buf: the buffer
5795 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005796 * Function to get the length of a buffer
5797 *
Owen Taylor3473f882001-02-23 17:55:21 +00005798 * Returns the length of data in the internal content
5799 */
5800
5801int
5802xmlBufferLength(const xmlBufferPtr buf)
5803{
5804 if(!buf)
5805 return 0;
5806
5807 return buf->use;
5808}
5809
5810/**
5811 * xmlBufferResize:
5812 * @buf: the buffer to resize
5813 * @size: the desired size
5814 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005815 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005816 *
5817 * Returns 0 in case of problems, 1 otherwise
5818 */
5819int
5820xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5821{
5822 unsigned int newSize;
5823 xmlChar* rebuf = NULL;
5824
5825 /*take care of empty case*/
5826 newSize = (buf->size ? buf->size*2 : size);
5827
5828 /* Don't resize if we don't have to */
5829 if (size < buf->size)
5830 return 1;
5831
5832 /* figure out new size */
5833 switch (buf->alloc){
5834 case XML_BUFFER_ALLOC_DOUBLEIT:
5835 while (size > newSize) newSize *= 2;
5836 break;
5837 case XML_BUFFER_ALLOC_EXACT:
5838 newSize = size+10;
5839 break;
5840 default:
5841 newSize = size+10;
5842 break;
5843 }
5844
5845 if (buf->content == NULL)
5846 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5847 else
5848 rebuf = (xmlChar *) xmlRealloc(buf->content,
5849 newSize * sizeof(xmlChar));
5850 if (rebuf == NULL) {
5851 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005852 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005853 return 0;
5854 }
5855 buf->content = rebuf;
5856 buf->size = newSize;
5857
5858 return 1;
5859}
5860
5861/**
5862 * xmlBufferAdd:
5863 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005864 * @str: the #xmlChar string
5865 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005866 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005867 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005868 * str is recomputed.
5869 */
5870void
5871xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5872 unsigned int needSize;
5873
5874 if (str == NULL) {
5875#ifdef DEBUG_BUFFER
5876 xmlGenericError(xmlGenericErrorContext,
5877 "xmlBufferAdd: str == NULL\n");
5878#endif
5879 return;
5880 }
5881 if (len < -1) {
5882#ifdef DEBUG_BUFFER
5883 xmlGenericError(xmlGenericErrorContext,
5884 "xmlBufferAdd: len < 0\n");
5885#endif
5886 return;
5887 }
5888 if (len == 0) return;
5889
5890 if (len < 0)
5891 len = xmlStrlen(str);
5892
5893 if (len <= 0) return;
5894
5895 needSize = buf->use + len + 2;
5896 if (needSize > buf->size){
5897 if (!xmlBufferResize(buf, needSize)){
5898 xmlGenericError(xmlGenericErrorContext,
5899 "xmlBufferAdd : out of memory!\n");
5900 return;
5901 }
5902 }
5903
5904 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5905 buf->use += len;
5906 buf->content[buf->use] = 0;
5907}
5908
5909/**
5910 * xmlBufferAddHead:
5911 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005912 * @str: the #xmlChar string
5913 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005914 *
5915 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005916 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005917 */
5918void
5919xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5920 unsigned int needSize;
5921
5922 if (str == NULL) {
5923#ifdef DEBUG_BUFFER
5924 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005925 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005926#endif
5927 return;
5928 }
5929 if (len < -1) {
5930#ifdef DEBUG_BUFFER
5931 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005932 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005933#endif
5934 return;
5935 }
5936 if (len == 0) return;
5937
5938 if (len < 0)
5939 len = xmlStrlen(str);
5940
5941 if (len <= 0) return;
5942
5943 needSize = buf->use + len + 2;
5944 if (needSize > buf->size){
5945 if (!xmlBufferResize(buf, needSize)){
5946 xmlGenericError(xmlGenericErrorContext,
5947 "xmlBufferAddHead : out of memory!\n");
5948 return;
5949 }
5950 }
5951
5952 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5953 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5954 buf->use += len;
5955 buf->content[buf->use] = 0;
5956}
5957
5958/**
5959 * xmlBufferCat:
5960 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005961 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005962 *
5963 * Append a zero terminated string to an XML buffer.
5964 */
5965void
5966xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5967 if (str != NULL)
5968 xmlBufferAdd(buf, str, -1);
5969}
5970
5971/**
5972 * xmlBufferCCat:
5973 * @buf: the buffer to dump
5974 * @str: the C char string
5975 *
5976 * Append a zero terminated C string to an XML buffer.
5977 */
5978void
5979xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5980 const char *cur;
5981
5982 if (str == NULL) {
5983#ifdef DEBUG_BUFFER
5984 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005985 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005986#endif
5987 return;
5988 }
5989 for (cur = str;*cur != 0;cur++) {
5990 if (buf->use + 10 >= buf->size) {
5991 if (!xmlBufferResize(buf, buf->use+10)){
5992 xmlGenericError(xmlGenericErrorContext,
5993 "xmlBufferCCat : out of memory!\n");
5994 return;
5995 }
5996 }
5997 buf->content[buf->use++] = *cur;
5998 }
5999 buf->content[buf->use] = 0;
6000}
6001
6002/**
6003 * xmlBufferWriteCHAR:
6004 * @buf: the XML buffer
6005 * @string: the string to add
6006 *
6007 * routine which manages and grows an output buffer. This one adds
6008 * xmlChars at the end of the buffer.
6009 */
6010void
Owen Taylor3473f882001-02-23 17:55:21 +00006011xmlBufferWriteCHAR
Owen Taylor3473f882001-02-23 17:55:21 +00006012(xmlBufferPtr buf, const xmlChar *string) {
6013 xmlBufferCat(buf, string);
6014}
6015
6016/**
6017 * xmlBufferWriteChar:
6018 * @buf: the XML buffer output
6019 * @string: the string to add
6020 *
6021 * routine which manage and grows an output buffer. This one add
6022 * C chars at the end of the array.
6023 */
6024void
6025xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
6026 xmlBufferCCat(buf, string);
6027}
6028
6029
6030/**
6031 * xmlBufferWriteQuotedString:
6032 * @buf: the XML buffer output
6033 * @string: the string to add
6034 *
6035 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006036 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006037 * quote or double-quotes internally
6038 */
6039void
6040xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
6041 if (xmlStrchr(string, '"')) {
6042 if (xmlStrchr(string, '\'')) {
6043#ifdef DEBUG_BUFFER
6044 xmlGenericError(xmlGenericErrorContext,
6045 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6046#endif
6047 }
6048 xmlBufferCCat(buf, "'");
6049 xmlBufferCat(buf, string);
6050 xmlBufferCCat(buf, "'");
6051 } else {
6052 xmlBufferCCat(buf, "\"");
6053 xmlBufferCat(buf, string);
6054 xmlBufferCCat(buf, "\"");
6055 }
6056}
6057
6058
6059/************************************************************************
6060 * *
6061 * Dumping XML tree content to a simple buffer *
6062 * *
6063 ************************************************************************/
6064
Owen Taylor3473f882001-02-23 17:55:21 +00006065/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00006066 * xmlAttrSerializeContent:
6067 * @buf: the XML buffer output
6068 * @doc: the document
6069 * @attr: the attribute pointer
6070 *
6071 * Serialize the attribute in the buffer
6072 */
6073static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006074xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
6075{
Daniel Veillarda6d05382002-02-13 13:07:41 +00006076 const xmlChar *cur, *base;
6077 xmlNodePtr children;
6078
6079 children = attr->children;
6080 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006081 switch (children->type) {
6082 case XML_TEXT_NODE:
6083 base = cur = children->content;
6084 while (*cur != 0) {
6085 if (*cur == '\n') {
6086 if (base != cur)
6087 xmlBufferAdd(buf, base, cur - base);
6088 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
6089 cur++;
6090 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006091#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006092 } else if (*cur == '\'') {
6093 if (base != cur)
6094 xmlBufferAdd(buf, base, cur - base);
6095 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
6096 cur++;
6097 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006098#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006099 } else if (*cur == '"') {
6100 if (base != cur)
6101 xmlBufferAdd(buf, base, cur - base);
6102 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6103 cur++;
6104 base = cur;
6105 } else if (*cur == '<') {
6106 if (base != cur)
6107 xmlBufferAdd(buf, base, cur - base);
6108 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6109 cur++;
6110 base = cur;
6111 } else if (*cur == '>') {
6112 if (base != cur)
6113 xmlBufferAdd(buf, base, cur - base);
6114 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6115 cur++;
6116 base = cur;
6117 } else if (*cur == '&') {
6118 if (base != cur)
6119 xmlBufferAdd(buf, base, cur - base);
6120 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6121 cur++;
6122 base = cur;
6123 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6124 (doc->encoding ==
6125 NULL))) {
6126 /*
6127 * We assume we have UTF-8 content.
6128 */
6129 char tmp[10];
6130 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006131
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006132 if (base != cur)
6133 xmlBufferAdd(buf, base, cur - base);
6134 if (*cur < 0xC0) {
6135 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6d05382002-02-13 13:07:41 +00006136 "xmlAttrSerializeContent : input not UTF-8\n");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006137 if (doc != NULL)
6138 doc->encoding =
6139 xmlStrdup(BAD_CAST "ISO-8859-1");
6140 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6141 tmp[sizeof(tmp) - 1] = 0;
6142 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6143 cur++;
6144 base = cur;
6145 continue;
6146 } else if (*cur < 0xE0) {
6147 val = (cur[0]) & 0x1F;
6148 val <<= 6;
6149 val |= (cur[1]) & 0x3F;
6150 l = 2;
6151 } else if (*cur < 0xF0) {
6152 val = (cur[0]) & 0x0F;
6153 val <<= 6;
6154 val |= (cur[1]) & 0x3F;
6155 val <<= 6;
6156 val |= (cur[2]) & 0x3F;
6157 l = 3;
6158 } else if (*cur < 0xF8) {
6159 val = (cur[0]) & 0x07;
6160 val <<= 6;
6161 val |= (cur[1]) & 0x3F;
6162 val <<= 6;
6163 val |= (cur[2]) & 0x3F;
6164 val <<= 6;
6165 val |= (cur[3]) & 0x3F;
6166 l = 4;
6167 }
6168 if ((l == 1) || (!IS_CHAR(val))) {
6169 xmlGenericError(xmlGenericErrorContext,
6170 "xmlAttrSerializeContent : char out of range\n");
6171 if (doc != NULL)
6172 doc->encoding =
6173 xmlStrdup(BAD_CAST "ISO-8859-1");
6174 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6175 tmp[sizeof(tmp) - 1] = 0;
6176 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6177 cur++;
6178 base = cur;
6179 continue;
6180 }
6181 /*
6182 * We could do multiple things here. Just save
6183 * as a char ref
6184 */
6185 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6186 tmp[sizeof(tmp) - 1] = 0;
6187 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6188 cur += l;
6189 base = cur;
6190 } else {
6191 cur++;
6192 }
6193 }
6194 if (base != cur)
6195 xmlBufferAdd(buf, base, cur - base);
6196 break;
6197 case XML_ENTITY_REF_NODE:
6198 xmlBufferAdd(buf, BAD_CAST "&", 1);
6199 xmlBufferAdd(buf, children->name,
6200 xmlStrlen(children->name));
6201 xmlBufferAdd(buf, BAD_CAST ";", 1);
6202 break;
6203 default:
6204 /* should not happen unless we have a badly built tree */
6205 break;
6206 }
6207 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006208 }
6209}
6210
6211/**
6212 * xmlNodeDump:
6213 * @buf: the XML buffer output
6214 * @doc: the document
6215 * @cur: the current node
6216 * @level: the imbrication level for indenting
6217 * @format: is formatting allowed
6218 *
6219 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006220 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6221 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006222 *
6223 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00006224 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006225int
Owen Taylor3473f882001-02-23 17:55:21 +00006226xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006227 int format)
6228{
6229 unsigned int use;
6230 int ret;
6231 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006232
6233 if (cur == NULL) {
6234#ifdef DEBUG_TREE
6235 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006236 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006237#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006238 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006239 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006240 if (buf == NULL) {
6241#ifdef DEBUG_TREE
6242 xmlGenericError(xmlGenericErrorContext,
6243 "xmlNodeDump : buf == NULL\n");
6244#endif
6245 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006246 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006247 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
6248 if (outbuf == NULL) {
6249 xmlGenericError(xmlGenericErrorContext,
6250 "xmlNodeDump: out of memory!\n");
6251 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006252 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006253 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
6254 outbuf->buffer = buf;
6255 outbuf->encoder = NULL;
6256 outbuf->writecallback = NULL;
6257 outbuf->closecallback = NULL;
6258 outbuf->context = NULL;
6259 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006260
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006261 use = buf->use;
6262 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
6263 xmlFree(outbuf);
6264 ret = buf->use - use;
6265 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006266}
6267
6268/**
6269 * xmlElemDump:
6270 * @f: the FILE * for the output
6271 * @doc: the document
6272 * @cur: the current node
6273 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006274 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006275 */
6276void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006277xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
6278{
6279 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006280
6281 if (cur == NULL) {
6282#ifdef DEBUG_TREE
6283 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006284 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006285#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006286 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006287 }
Owen Taylor3473f882001-02-23 17:55:21 +00006288#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006289 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006290 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006291 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006292 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006293#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006294
6295 outbuf = xmlOutputBufferCreateFile(f, NULL);
6296 if (outbuf == NULL)
6297 return;
6298 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006299#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006300 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
6301#else
6302 xmlGenericError(xmlGenericErrorContext,
6303 "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006304#endif /* LIBXML_HTML_ENABLED */
6305 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006306 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
6307 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00006308}
6309
6310/************************************************************************
6311 * *
6312 * Dumping XML tree content to an I/O output buffer *
6313 * *
6314 ************************************************************************/
6315
Owen Taylor3473f882001-02-23 17:55:21 +00006316static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006317xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6318 int level, int format, const char *encoding);
6319static void
Owen Taylor3473f882001-02-23 17:55:21 +00006320xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6321 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006322static void
6323xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6324 xmlNodePtr cur, int level, int format, const char *encoding);
6325
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006326void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
6327
Owen Taylor3473f882001-02-23 17:55:21 +00006328/**
6329 * xmlNsDumpOutput:
6330 * @buf: the XML buffer output
6331 * @cur: a namespace
6332 *
6333 * Dump a local Namespace definition.
6334 * Should be called in the context of attributes dumps.
6335 */
6336static void
6337xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6338 if (cur == NULL) {
6339#ifdef DEBUG_TREE
6340 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006341 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006342#endif
6343 return;
6344 }
6345 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006346 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6347 return;
6348
Owen Taylor3473f882001-02-23 17:55:21 +00006349 /* Within the context of an element attributes */
6350 if (cur->prefix != NULL) {
6351 xmlOutputBufferWriteString(buf, " xmlns:");
6352 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6353 } else
6354 xmlOutputBufferWriteString(buf, " xmlns");
6355 xmlOutputBufferWriteString(buf, "=");
6356 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6357 }
6358}
6359
6360/**
6361 * xmlNsListDumpOutput:
6362 * @buf: the XML buffer output
6363 * @cur: the first namespace
6364 *
6365 * Dump a list of local Namespace definitions.
6366 * Should be called in the context of attributes dumps.
6367 */
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006368void
Owen Taylor3473f882001-02-23 17:55:21 +00006369xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6370 while (cur != NULL) {
6371 xmlNsDumpOutput(buf, cur);
6372 cur = cur->next;
6373 }
6374}
6375
6376/**
6377 * xmlDtdDumpOutput:
6378 * @buf: the XML buffer output
6379 * @doc: the document
6380 * @encoding: an optional encoding string
6381 *
6382 * Dump the XML document DTD, if any.
6383 */
6384static void
6385xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6386 if (dtd == NULL) {
6387#ifdef DEBUG_TREE
6388 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006389 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006390#endif
6391 return;
6392 }
6393 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6394 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6395 if (dtd->ExternalID != NULL) {
6396 xmlOutputBufferWriteString(buf, " PUBLIC ");
6397 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6398 xmlOutputBufferWriteString(buf, " ");
6399 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6400 } else if (dtd->SystemID != NULL) {
6401 xmlOutputBufferWriteString(buf, " SYSTEM ");
6402 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6403 }
6404 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6405 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6406 xmlOutputBufferWriteString(buf, ">");
6407 return;
6408 }
6409 xmlOutputBufferWriteString(buf, " [\n");
6410 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6411 xmlOutputBufferWriteString(buf, "]>");
6412}
6413
6414/**
6415 * xmlAttrDumpOutput:
6416 * @buf: the XML buffer output
6417 * @doc: the document
6418 * @cur: the attribute pointer
6419 * @encoding: an optional encoding string
6420 *
6421 * Dump an XML attribute
6422 */
6423static void
6424xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006425 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006426 if (cur == NULL) {
6427#ifdef DEBUG_TREE
6428 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006429 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006430#endif
6431 return;
6432 }
6433 xmlOutputBufferWriteString(buf, " ");
6434 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6435 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6436 xmlOutputBufferWriteString(buf, ":");
6437 }
6438 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006439 xmlOutputBufferWriteString(buf, "=\"");
6440 xmlAttrSerializeContent(buf->buffer, doc, cur);
6441 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006442}
6443
6444/**
6445 * xmlAttrListDumpOutput:
6446 * @buf: the XML buffer output
6447 * @doc: the document
6448 * @cur: the first attribute pointer
6449 * @encoding: an optional encoding string
6450 *
6451 * Dump a list of XML attributes
6452 */
6453static void
6454xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6455 xmlAttrPtr cur, const char *encoding) {
6456 if (cur == NULL) {
6457#ifdef DEBUG_TREE
6458 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006459 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006460#endif
6461 return;
6462 }
6463 while (cur != NULL) {
6464 xmlAttrDumpOutput(buf, doc, cur, encoding);
6465 cur = cur->next;
6466 }
6467}
6468
6469
6470
6471/**
6472 * xmlNodeListDumpOutput:
6473 * @buf: the XML buffer output
6474 * @doc: the document
6475 * @cur: the first node
6476 * @level: the imbrication level for indenting
6477 * @format: is formatting allowed
6478 * @encoding: an optional encoding string
6479 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006480 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006481 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6482 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006483 */
6484static void
6485xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6486 xmlNodePtr cur, int level, int format, const char *encoding) {
6487 int i;
6488
6489 if (cur == NULL) {
6490#ifdef DEBUG_TREE
6491 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006492 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006493#endif
6494 return;
6495 }
6496 while (cur != NULL) {
6497 if ((format) && (xmlIndentTreeOutput) &&
6498 (cur->type == XML_ELEMENT_NODE))
6499 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006500 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006501 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00006502 if (format) {
6503 xmlOutputBufferWriteString(buf, "\n");
6504 }
6505 cur = cur->next;
6506 }
6507}
6508
6509/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006510 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00006511 * @buf: the XML buffer output
6512 * @doc: the document
6513 * @cur: the current node
6514 * @level: the imbrication level for indenting
6515 * @format: is formatting allowed
6516 * @encoding: an optional encoding string
6517 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006518 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006519 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6520 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006521 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006522static void
6523xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6524 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006525 int i;
6526 xmlNodePtr tmp;
6527
6528 if (cur == NULL) {
6529#ifdef DEBUG_TREE
6530 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006531 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006532#endif
6533 return;
6534 }
6535 if (cur->type == XML_XINCLUDE_START)
6536 return;
6537 if (cur->type == XML_XINCLUDE_END)
6538 return;
6539 if (cur->type == XML_DTD_NODE) {
6540 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6541 return;
6542 }
6543 if (cur->type == XML_ELEMENT_DECL) {
6544 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6545 return;
6546 }
6547 if (cur->type == XML_ATTRIBUTE_DECL) {
6548 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6549 return;
6550 }
6551 if (cur->type == XML_ENTITY_DECL) {
6552 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6553 return;
6554 }
6555 if (cur->type == XML_TEXT_NODE) {
6556 if (cur->content != NULL) {
6557 if ((cur->name == xmlStringText) ||
6558 (cur->name != xmlStringTextNoenc)) {
6559 xmlChar *buffer;
6560
Owen Taylor3473f882001-02-23 17:55:21 +00006561 if (encoding == NULL)
6562 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6563 else
6564 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006565 if (buffer != NULL) {
6566 xmlOutputBufferWriteString(buf, (const char *)buffer);
6567 xmlFree(buffer);
6568 }
6569 } else {
6570 /*
6571 * Disable escaping, needed for XSLT
6572 */
Owen Taylor3473f882001-02-23 17:55:21 +00006573 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006574 }
6575 }
6576
6577 return;
6578 }
6579 if (cur->type == XML_PI_NODE) {
6580 if (cur->content != NULL) {
6581 xmlOutputBufferWriteString(buf, "<?");
6582 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6583 if (cur->content != NULL) {
6584 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006585 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006586 }
6587 xmlOutputBufferWriteString(buf, "?>");
6588 } else {
6589 xmlOutputBufferWriteString(buf, "<?");
6590 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6591 xmlOutputBufferWriteString(buf, "?>");
6592 }
6593 return;
6594 }
6595 if (cur->type == XML_COMMENT_NODE) {
6596 if (cur->content != NULL) {
6597 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006598 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006599 xmlOutputBufferWriteString(buf, "-->");
6600 }
6601 return;
6602 }
6603 if (cur->type == XML_ENTITY_REF_NODE) {
6604 xmlOutputBufferWriteString(buf, "&");
6605 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6606 xmlOutputBufferWriteString(buf, ";");
6607 return;
6608 }
6609 if (cur->type == XML_CDATA_SECTION_NODE) {
6610 xmlOutputBufferWriteString(buf, "<![CDATA[");
6611 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006612 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006613 xmlOutputBufferWriteString(buf, "]]>");
6614 return;
6615 }
6616
6617 if (format == 1) {
6618 tmp = cur->children;
6619 while (tmp != NULL) {
6620 if ((tmp->type == XML_TEXT_NODE) ||
6621 (tmp->type == XML_ENTITY_REF_NODE)) {
6622 format = 0;
6623 break;
6624 }
6625 tmp = tmp->next;
6626 }
6627 }
6628 xmlOutputBufferWriteString(buf, "<");
6629 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6630 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6631 xmlOutputBufferWriteString(buf, ":");
6632 }
6633
6634 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6635 if (cur->nsDef)
6636 xmlNsListDumpOutput(buf, cur->nsDef);
6637 if (cur->properties != NULL)
6638 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6639
Daniel Veillard7db37732001-07-12 01:20:08 +00006640 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6641 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006642 xmlOutputBufferWriteString(buf, "/>");
6643 return;
6644 }
6645 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006646 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006647 xmlChar *buffer;
6648
Owen Taylor3473f882001-02-23 17:55:21 +00006649 if (encoding == NULL)
6650 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6651 else
6652 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006653 if (buffer != NULL) {
6654 xmlOutputBufferWriteString(buf, (const char *)buffer);
6655 xmlFree(buffer);
6656 }
6657 }
6658 if (cur->children != NULL) {
6659 if (format) xmlOutputBufferWriteString(buf, "\n");
6660 xmlNodeListDumpOutput(buf, doc, cur->children,
6661 (level >= 0?level+1:-1), format, encoding);
6662 if ((xmlIndentTreeOutput) && (format))
6663 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006664 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006665 }
6666 xmlOutputBufferWriteString(buf, "</");
6667 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6668 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6669 xmlOutputBufferWriteString(buf, ":");
6670 }
6671
6672 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6673 xmlOutputBufferWriteString(buf, ">");
6674}
6675
6676/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006677 * xmlNodeDumpOutput:
6678 * @buf: the XML buffer output
6679 * @doc: the document
6680 * @cur: the current node
6681 * @level: the imbrication level for indenting
6682 * @format: is formatting allowed
6683 * @encoding: an optional encoding string
6684 *
6685 * Dump an XML node, recursive behaviour, children are printed too.
6686 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6687 * or xmlKeepBlanksDefault(0) was called
6688 */
6689void
6690xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006691 int level, int format, const char *encoding)
6692{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006693#ifdef LIBXML_HTML_ENABLED
6694 xmlDtdPtr dtd;
6695 int is_xhtml = 0;
6696
6697 dtd = xmlGetIntSubset(doc);
6698 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006699 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
6700 if (is_xhtml < 0)
6701 is_xhtml = 0;
6702 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
6703 (cur->type == XML_ELEMENT_NODE) &&
6704 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
6705 if (encoding != NULL)
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00006706 htmlSetMetaEncoding((htmlDocPtr) doc,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006707 (const xmlChar *) encoding);
6708 else
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00006709 htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006710 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006711 }
6712
6713 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006714 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006715 else
6716#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006717 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006718}
6719
6720/**
Owen Taylor3473f882001-02-23 17:55:21 +00006721 * xmlDocContentDumpOutput:
6722 * @buf: the XML buffer output
6723 * @cur: the document
6724 * @encoding: an optional encoding string
6725 * @format: should formatting spaces been added
6726 *
6727 * Dump an XML document.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006728 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6729 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006730 */
6731static void
6732xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6733 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006734#ifdef LIBXML_HTML_ENABLED
6735 xmlDtdPtr dtd;
6736 int is_xhtml = 0;
6737#endif
6738
Owen Taylor3473f882001-02-23 17:55:21 +00006739 xmlOutputBufferWriteString(buf, "<?xml version=");
6740 if (cur->version != NULL)
6741 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6742 else
6743 xmlOutputBufferWriteString(buf, "\"1.0\"");
6744 if (encoding == NULL) {
6745 if (cur->encoding != NULL)
6746 encoding = (const char *) cur->encoding;
6747 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6748 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6749 }
6750 if (encoding != NULL) {
6751 xmlOutputBufferWriteString(buf, " encoding=");
6752 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6753 }
6754 switch (cur->standalone) {
6755 case 0:
6756 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6757 break;
6758 case 1:
6759 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6760 break;
6761 }
6762 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006763
6764#ifdef LIBXML_HTML_ENABLED
6765 dtd = xmlGetIntSubset(cur);
6766 if (dtd != NULL) {
6767 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
6768 if (is_xhtml < 0) is_xhtml = 0;
6769 }
6770 if (is_xhtml) {
6771 if (encoding != NULL)
6772 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
6773 else
6774 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
6775 }
6776#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006777 if (cur->children != NULL) {
6778 xmlNodePtr child = cur->children;
6779
6780 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006781#ifdef LIBXML_HTML_ENABLED
6782 if (is_xhtml)
6783 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6784 else
6785#endif
6786 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00006787 xmlOutputBufferWriteString(buf, "\n");
6788 child = child->next;
6789 }
6790 }
6791}
6792
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006793#ifdef LIBXML_HTML_ENABLED
6794/************************************************************************
6795 * *
6796 * Functions specific to XHTML serialization *
6797 * *
6798 ************************************************************************/
6799
6800#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
6801 "-//W3C//DTD XHTML 1.0 Strict//EN"
6802#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
6803 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
6804#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
6805 "-//W3C//DTD XHTML 1.0 Frameset//EN"
6806#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
6807 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
6808#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
6809 "-//W3C//DTD XHTML 1.0 Transitional//EN"
6810#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
6811 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
6812
6813#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
6814/**
6815 * xmlIsXHTML:
6816 * @systemID: the system identifier
6817 * @publicID: the public identifier
6818 *
6819 * Try to find if the document correspond to an XHTML DTD
6820 *
6821 * Returns 1 if true, 0 if not and -1 in case of error
6822 */
6823int
6824xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
6825 if ((systemID == NULL) && (publicID == NULL))
6826 return(-1);
6827 if (publicID != NULL) {
6828 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
6829 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
6830 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
6831 }
6832 if (systemID != NULL) {
6833 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
6834 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
6835 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
6836 }
6837 return(0);
6838}
6839
6840/**
6841 * xhtmlIsEmpty:
6842 * @node: the node
6843 *
6844 * Check if a node is an empty xhtml node
6845 *
6846 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
6847 */
6848static int
6849xhtmlIsEmpty(xmlNodePtr node) {
6850 if (node == NULL)
6851 return(-1);
6852 if (node->type != XML_ELEMENT_NODE)
6853 return(0);
6854 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
6855 return(0);
6856 if (node->children != NULL)
6857 return(0);
6858 switch (node->name[0]) {
6859 case 'a':
6860 if (xmlStrEqual(node->name, BAD_CAST "area"))
6861 return(1);
6862 return(0);
6863 case 'b':
6864 if (xmlStrEqual(node->name, BAD_CAST "br"))
6865 return(1);
6866 if (xmlStrEqual(node->name, BAD_CAST "base"))
6867 return(1);
6868 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
6869 return(1);
6870 return(0);
6871 case 'c':
6872 if (xmlStrEqual(node->name, BAD_CAST "col"))
6873 return(1);
6874 return(0);
6875 case 'f':
6876 if (xmlStrEqual(node->name, BAD_CAST "frame"))
6877 return(1);
6878 return(0);
6879 case 'h':
6880 if (xmlStrEqual(node->name, BAD_CAST "hr"))
6881 return(1);
6882 return(0);
6883 case 'i':
6884 if (xmlStrEqual(node->name, BAD_CAST "img"))
6885 return(1);
6886 if (xmlStrEqual(node->name, BAD_CAST "input"))
6887 return(1);
6888 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
6889 return(1);
6890 return(0);
6891 case 'l':
6892 if (xmlStrEqual(node->name, BAD_CAST "link"))
6893 return(1);
6894 return(0);
6895 case 'm':
6896 if (xmlStrEqual(node->name, BAD_CAST "meta"))
6897 return(1);
6898 return(0);
6899 case 'p':
6900 if (xmlStrEqual(node->name, BAD_CAST "param"))
6901 return(1);
6902 return(0);
6903 }
6904 return(0);
6905}
6906
6907/**
6908 * xhtmlAttrListDumpOutput:
6909 * @buf: the XML buffer output
6910 * @doc: the document
6911 * @cur: the first attribute pointer
6912 * @encoding: an optional encoding string
6913 *
6914 * Dump a list of XML attributes
6915 */
6916static void
6917xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6918 xmlAttrPtr cur, const char *encoding) {
6919 xmlAttrPtr xml_lang = NULL;
6920 xmlAttrPtr lang = NULL;
6921 xmlAttrPtr name = NULL;
6922 xmlAttrPtr id = NULL;
6923
6924 if (cur == NULL) {
6925#ifdef DEBUG_TREE
6926 xmlGenericError(xmlGenericErrorContext,
6927 "xmlAttrListDumpOutput : property == NULL\n");
6928#endif
6929 return;
6930 }
6931 while (cur != NULL) {
6932 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
6933 id = cur;
6934 else
6935 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
6936 name = cur;
6937 else
6938 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
6939 lang = cur;
6940 else
6941 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
6942 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
6943 xml_lang = cur;
6944 else if ((cur->ns == NULL) &&
6945 ((cur->children == NULL) ||
6946 (cur->children->content == NULL) ||
6947 (cur->children->content[0] == 0)) &&
6948 (htmlIsBooleanAttr(cur->name))) {
6949 if (cur->children != NULL)
6950 xmlFreeNode(cur->children);
6951 cur->children = xmlNewText(cur->name);
6952 if (cur->children != NULL)
6953 cur->children->parent = (xmlNodePtr) cur;
6954 }
6955 xmlAttrDumpOutput(buf, doc, cur, encoding);
6956 cur = cur->next;
6957 }
6958 /*
6959 * C.8
6960 */
6961 if ((name != NULL) && (id == NULL)) {
6962 xmlOutputBufferWriteString(buf, " id=\"");
6963 xmlAttrSerializeContent(buf->buffer, doc, name);
6964 xmlOutputBufferWriteString(buf, "\"");
6965 }
6966 /*
6967 * C.7.
6968 */
6969 if ((lang != NULL) && (xml_lang == NULL)) {
6970 xmlOutputBufferWriteString(buf, " xml:lang=\"");
6971 xmlAttrSerializeContent(buf->buffer, doc, lang);
6972 xmlOutputBufferWriteString(buf, "\"");
6973 } else
6974 if ((xml_lang != NULL) && (lang == NULL)) {
6975 xmlOutputBufferWriteString(buf, " lang=\"");
6976 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
6977 xmlOutputBufferWriteString(buf, "\"");
6978 }
6979}
6980
6981/**
6982 * xhtmlNodeListDumpOutput:
6983 * @buf: the XML buffer output
6984 * @doc: the XHTML document
6985 * @cur: the first node
6986 * @level: the imbrication level for indenting
6987 * @format: is formatting allowed
6988 * @encoding: an optional encoding string
6989 *
6990 * Dump an XML node list, recursive behaviour, children are printed too.
6991 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6992 * or xmlKeepBlanksDefault(0) was called
6993 */
6994static void
6995xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6996 xmlNodePtr cur, int level, int format, const char *encoding) {
6997 int i;
6998
6999 if (cur == NULL) {
7000#ifdef DEBUG_TREE
7001 xmlGenericError(xmlGenericErrorContext,
7002 "xhtmlNodeListDumpOutput : node == NULL\n");
7003#endif
7004 return;
7005 }
7006 while (cur != NULL) {
7007 if ((format) && (xmlIndentTreeOutput) &&
7008 (cur->type == XML_ELEMENT_NODE))
7009 for (i = 0;i < level;i++)
7010 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7011 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
7012 if (format) {
7013 xmlOutputBufferWriteString(buf, "\n");
7014 }
7015 cur = cur->next;
7016 }
7017}
7018
7019/**
7020 * xhtmlNodeDumpOutput:
7021 * @buf: the XML buffer output
7022 * @doc: the XHTML document
7023 * @cur: the current node
7024 * @level: the imbrication level for indenting
7025 * @format: is formatting allowed
7026 * @encoding: an optional encoding string
7027 *
7028 * Dump an XHTML node, recursive behaviour, children are printed too.
7029 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7030 * or xmlKeepBlanksDefault(0) was called
7031 */
7032static void
7033xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7034 int level, int format, const char *encoding) {
7035 int i;
7036 xmlNodePtr tmp;
7037
7038 if (cur == NULL) {
7039#ifdef DEBUG_TREE
7040 xmlGenericError(xmlGenericErrorContext,
7041 "xmlNodeDumpOutput : node == NULL\n");
7042#endif
7043 return;
7044 }
7045 if (cur->type == XML_XINCLUDE_START)
7046 return;
7047 if (cur->type == XML_XINCLUDE_END)
7048 return;
7049 if (cur->type == XML_DTD_NODE) {
7050 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7051 return;
7052 }
7053 if (cur->type == XML_ELEMENT_DECL) {
7054 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7055 return;
7056 }
7057 if (cur->type == XML_ATTRIBUTE_DECL) {
7058 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7059 return;
7060 }
7061 if (cur->type == XML_ENTITY_DECL) {
7062 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7063 return;
7064 }
7065 if (cur->type == XML_TEXT_NODE) {
7066 if (cur->content != NULL) {
7067 if ((cur->name == xmlStringText) ||
7068 (cur->name != xmlStringTextNoenc)) {
7069 xmlChar *buffer;
7070
7071 if (encoding == NULL)
7072 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7073 else
7074 buffer = xmlEncodeSpecialChars(doc, cur->content);
7075 if (buffer != NULL) {
7076 xmlOutputBufferWriteString(buf, (const char *)buffer);
7077 xmlFree(buffer);
7078 }
7079 } else {
7080 /*
7081 * Disable escaping, needed for XSLT
7082 */
7083 xmlOutputBufferWriteString(buf, (const char *) cur->content);
7084 }
7085 }
7086
7087 return;
7088 }
7089 if (cur->type == XML_PI_NODE) {
7090 if (cur->content != NULL) {
7091 xmlOutputBufferWriteString(buf, "<?");
7092 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7093 if (cur->content != NULL) {
7094 xmlOutputBufferWriteString(buf, " ");
7095 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7096 }
7097 xmlOutputBufferWriteString(buf, "?>");
7098 } else {
7099 xmlOutputBufferWriteString(buf, "<?");
7100 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7101 xmlOutputBufferWriteString(buf, "?>");
7102 }
7103 return;
7104 }
7105 if (cur->type == XML_COMMENT_NODE) {
7106 if (cur->content != NULL) {
7107 xmlOutputBufferWriteString(buf, "<!--");
7108 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7109 xmlOutputBufferWriteString(buf, "-->");
7110 }
7111 return;
7112 }
7113 if (cur->type == XML_ENTITY_REF_NODE) {
7114 xmlOutputBufferWriteString(buf, "&");
7115 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7116 xmlOutputBufferWriteString(buf, ";");
7117 return;
7118 }
7119 if (cur->type == XML_CDATA_SECTION_NODE) {
7120 xmlOutputBufferWriteString(buf, "<![CDATA[");
7121 if (cur->content != NULL)
7122 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7123 xmlOutputBufferWriteString(buf, "]]>");
7124 return;
7125 }
7126
7127 if (format == 1) {
7128 tmp = cur->children;
7129 while (tmp != NULL) {
7130 if ((tmp->type == XML_TEXT_NODE) ||
7131 (tmp->type == XML_ENTITY_REF_NODE)) {
7132 format = 0;
7133 break;
7134 }
7135 tmp = tmp->next;
7136 }
7137 }
7138 xmlOutputBufferWriteString(buf, "<");
7139 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7140 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7141 xmlOutputBufferWriteString(buf, ":");
7142 }
7143
7144 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7145 if (cur->nsDef)
7146 xmlNsListDumpOutput(buf, cur->nsDef);
7147 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
7148 (cur->ns == NULL) && (cur->nsDef == NULL))) {
7149 /*
7150 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
7151 */
7152 xmlOutputBufferWriteString(buf,
7153 " xmlns=\"http://www.w3.org/1999/xhtml\"");
7154 }
7155 if (cur->properties != NULL)
7156 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7157
7158 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
7159 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
7160 (xhtmlIsEmpty(cur) == 1)) {
7161 /*
7162 * C.2. Empty Elements
7163 */
7164 xmlOutputBufferWriteString(buf, " />");
7165 } else {
7166 /*
7167 * C.3. Element Minimization and Empty Element Content
7168 */
7169 xmlOutputBufferWriteString(buf, "></");
7170 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7171 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7172 xmlOutputBufferWriteString(buf, ":");
7173 }
7174 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7175 xmlOutputBufferWriteString(buf, ">");
7176 }
7177 return;
7178 }
7179 xmlOutputBufferWriteString(buf, ">");
7180 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
7181 xmlChar *buffer;
7182
7183 if (encoding == NULL)
7184 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7185 else
7186 buffer = xmlEncodeSpecialChars(doc, cur->content);
7187 if (buffer != NULL) {
7188 xmlOutputBufferWriteString(buf, (const char *)buffer);
7189 xmlFree(buffer);
7190 }
7191 }
7192
7193 /*
7194 * 4.8. Script and Style elements
7195 */
7196 if ((cur->type == XML_ELEMENT_NODE) &&
7197 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
7198 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
7199 ((cur->ns == NULL) ||
7200 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
7201 xmlNodePtr child = cur->children;
7202
7203 while (child != NULL) {
7204 if ((child->type == XML_TEXT_NODE) ||
7205 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00007206 /*
7207 * Apparently CDATA escaping for style just break on IE,
7208 * mozilla and galeon, so ...
7209 */
7210 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
7211 (xmlStrchr(child->content, '<') == NULL) &&
7212 (xmlStrchr(child->content, '>') == NULL) &&
7213 (xmlStrchr(child->content, '&') == NULL)) {
7214 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7215 } else {
7216 xmlOutputBufferWriteString(buf, "<![CDATA[");
7217 if (child->content != NULL)
7218 xmlOutputBufferWriteString(buf,
7219 (const char *)child->content);
7220 xmlOutputBufferWriteString(buf, "]]>");
7221 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007222 } else {
7223 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7224 }
7225 child = child->next;
7226 }
7227 } else if (cur->children != NULL) {
7228 if (format) xmlOutputBufferWriteString(buf, "\n");
7229 xhtmlNodeListDumpOutput(buf, doc, cur->children,
7230 (level >= 0?level+1:-1), format, encoding);
7231 if ((xmlIndentTreeOutput) && (format))
7232 for (i = 0;i < level;i++)
7233 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7234 }
7235 xmlOutputBufferWriteString(buf, "</");
7236 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7237 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7238 xmlOutputBufferWriteString(buf, ":");
7239 }
7240
7241 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7242 xmlOutputBufferWriteString(buf, ">");
7243}
7244#endif
7245
Owen Taylor3473f882001-02-23 17:55:21 +00007246/************************************************************************
7247 * *
7248 * Saving functions front-ends *
7249 * *
7250 ************************************************************************/
7251
7252/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007253 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00007254 * @out_doc: Document to generate XML text from
7255 * @doc_txt_ptr: Memory pointer for allocated XML text
7256 * @doc_txt_len: Length of the generated XML text
7257 * @txt_encoding: Character encoding to use when generating XML text
7258 * @format: should formatting spaces been added
7259 *
7260 * Dump the current DOM tree into memory using the character encoding specified
7261 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007262 * allocated memory with xmlFree().
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007263 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7264 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007265 */
7266
7267void
7268xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007269 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007270 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007271 int dummy = 0;
7272
7273 xmlCharEncoding doc_charset;
7274 xmlOutputBufferPtr out_buff = NULL;
7275 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
7276
7277 if (doc_txt_len == NULL) {
7278 doc_txt_len = &dummy; /* Continue, caller just won't get length */
7279 }
7280
7281 if (doc_txt_ptr == NULL) {
7282 *doc_txt_len = 0;
7283 xmlGenericError(xmlGenericErrorContext,
7284 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
7285 return;
7286 }
7287
7288 *doc_txt_ptr = NULL;
7289 *doc_txt_len = 0;
7290
7291 if (out_doc == NULL) {
7292 /* No document, no output */
7293 xmlGenericError(xmlGenericErrorContext,
7294 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
7295 return;
7296 }
7297
7298 /*
7299 * Validate the encoding value, if provided.
7300 * This logic is copied from xmlSaveFileEnc.
7301 */
7302
7303 if (txt_encoding == NULL)
7304 txt_encoding = (const char *) out_doc->encoding;
7305 if (txt_encoding != NULL) {
7306 doc_charset = xmlParseCharEncoding(txt_encoding);
7307
7308 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
7309 xmlGenericError(xmlGenericErrorContext,
7310 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
7311 return;
7312
7313 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
7314 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
7315 if ( conv_hdlr == NULL ) {
7316 xmlGenericError(xmlGenericErrorContext,
7317 "%s: %s %s '%s'\n",
7318 "xmlDocDumpFormatMemoryEnc",
7319 "Failed to identify encoding handler for",
7320 "character set",
7321 txt_encoding);
7322 return;
7323 }
7324 }
7325 }
7326
7327 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
7328 xmlGenericError(xmlGenericErrorContext,
7329 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
7330 return;
7331 }
7332
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007333 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007334 xmlOutputBufferFlush(out_buff);
7335 if (out_buff->conv != NULL) {
7336 *doc_txt_len = out_buff->conv->use;
7337 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
7338 } else {
7339 *doc_txt_len = out_buff->buffer->use;
7340 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
7341 }
7342 (void)xmlOutputBufferClose(out_buff);
7343
7344 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
7345 *doc_txt_len = 0;
7346 xmlGenericError(xmlGenericErrorContext,
7347 "xmlDocDumpFormatMemoryEnc: %s\n",
7348 "Failed to allocate memory for document text representation.");
7349 }
7350
7351 return;
7352}
7353
7354/**
7355 * xmlDocDumpMemory:
7356 * @cur: the document
7357 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007358 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007359 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007360 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007361 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007362 */
7363void
7364xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
7365 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
7366}
7367
7368/**
7369 * xmlDocDumpFormatMemory:
7370 * @cur: the document
7371 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007372 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007373 * @format: should formatting spaces been added
7374 *
7375 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007376 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007377 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007378 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7379 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007380 */
7381void
7382xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
7383 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
7384}
7385
7386/**
7387 * xmlDocDumpMemoryEnc:
7388 * @out_doc: Document to generate XML text from
7389 * @doc_txt_ptr: Memory pointer for allocated XML text
7390 * @doc_txt_len: Length of the generated XML text
7391 * @txt_encoding: Character encoding to use when generating XML text
7392 *
7393 * Dump the current DOM tree into memory using the character encoding specified
7394 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007395 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007396 */
7397
7398void
7399xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
7400 int * doc_txt_len, const char * txt_encoding) {
7401 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007402 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007403}
7404
7405/**
7406 * xmlGetDocCompressMode:
7407 * @doc: the document
7408 *
7409 * get the compression ratio for a document, ZLIB based
7410 * Returns 0 (uncompressed) to 9 (max compression)
7411 */
7412int
7413xmlGetDocCompressMode (xmlDocPtr doc) {
7414 if (doc == NULL) return(-1);
7415 return(doc->compression);
7416}
7417
7418/**
7419 * xmlSetDocCompressMode:
7420 * @doc: the document
7421 * @mode: the compression ratio
7422 *
7423 * set the compression ratio for a document, ZLIB based
7424 * Correct values: 0 (uncompressed) to 9 (max compression)
7425 */
7426void
7427xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7428 if (doc == NULL) return;
7429 if (mode < 0) doc->compression = 0;
7430 else if (mode > 9) doc->compression = 9;
7431 else doc->compression = mode;
7432}
7433
7434/**
7435 * xmlGetCompressMode:
7436 *
7437 * get the default compression mode used, ZLIB based.
7438 * Returns 0 (uncompressed) to 9 (max compression)
7439 */
7440int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007441xmlGetCompressMode(void)
7442{
7443 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00007444}
7445
7446/**
7447 * xmlSetCompressMode:
7448 * @mode: the compression ratio
7449 *
7450 * set the default compression mode used, ZLIB based
7451 * Correct values: 0 (uncompressed) to 9 (max compression)
7452 */
7453void
7454xmlSetCompressMode(int mode) {
7455 if (mode < 0) xmlCompressMode = 0;
7456 else if (mode > 9) xmlCompressMode = 9;
7457 else xmlCompressMode = mode;
7458}
7459
7460/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007461 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00007462 * @f: the FILE*
7463 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00007464 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007465 *
7466 * Dump an XML document to an open FILE.
7467 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007468 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007469 */
7470int
Daniel Veillard9e412302002-06-10 15:59:44 +00007471xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007472 xmlOutputBufferPtr buf;
7473 const char * encoding;
7474 xmlCharEncodingHandlerPtr handler = NULL;
7475 int ret;
7476
7477 if (cur == NULL) {
7478#ifdef DEBUG_TREE
7479 xmlGenericError(xmlGenericErrorContext,
7480 "xmlDocDump : document == NULL\n");
7481#endif
7482 return(-1);
7483 }
7484 encoding = (const char *) cur->encoding;
7485
7486 if (encoding != NULL) {
7487 xmlCharEncoding enc;
7488
7489 enc = xmlParseCharEncoding(encoding);
7490
7491 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7492 xmlGenericError(xmlGenericErrorContext,
7493 "xmlDocDump: document not in UTF8\n");
7494 return(-1);
7495 }
7496 if (enc != XML_CHAR_ENCODING_UTF8) {
7497 handler = xmlFindCharEncodingHandler(encoding);
7498 if (handler == NULL) {
7499 xmlFree((char *) cur->encoding);
7500 cur->encoding = NULL;
7501 }
7502 }
7503 }
7504 buf = xmlOutputBufferCreateFile(f, handler);
7505 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00007506 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007507
7508 ret = xmlOutputBufferClose(buf);
7509 return(ret);
7510}
7511
7512/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007513 * xmlDocDump:
7514 * @f: the FILE*
7515 * @cur: the document
7516 *
7517 * Dump an XML document to an open FILE.
7518 *
7519 * returns: the number of bytes written or -1 in case of failure.
7520 */
7521int
7522xmlDocDump(FILE *f, xmlDocPtr cur) {
7523 return(xmlDocFormatDump (f, cur, 0));
7524}
7525
7526/**
Owen Taylor3473f882001-02-23 17:55:21 +00007527 * xmlSaveFileTo:
7528 * @buf: an output I/O buffer
7529 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007530 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00007531 *
7532 * Dump an XML document to an I/O buffer.
7533 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007534 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007535 */
7536int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007537xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007538 int ret;
7539
7540 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007541 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007542 ret = xmlOutputBufferClose(buf);
7543 return(ret);
7544}
7545
7546/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00007547 * xmlSaveFormatFileTo:
7548 * @buf: an output I/O buffer
7549 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007550 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00007551 * @format: should formatting spaces been added
7552 *
7553 * Dump an XML document to an I/O buffer.
7554 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007555 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00007556 */
7557int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007558xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00007559 int ret;
7560
7561 if (buf == NULL) return(0);
7562 xmlDocContentDumpOutput(buf, cur, encoding, format);
7563 ret = xmlOutputBufferClose(buf);
7564 return(ret);
7565}
7566
7567/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00007568 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00007569 * @filename: the filename or URL to output
7570 * @cur: the document being saved
7571 * @encoding: the name of the encoding to use or NULL.
7572 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00007573 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00007574 * Dump an XML document to a file or an URL.
7575 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007576 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00007577 */
7578int
Daniel Veillardf012a642001-07-23 19:10:52 +00007579xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
7580 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00007581 xmlOutputBufferPtr buf;
7582 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00007583 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00007584 int ret;
7585
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00007586 if (cur == NULL)
7587 return(-1);
7588
Daniel Veillardfb25a512002-01-13 20:32:08 +00007589 if (encoding == NULL)
7590 encoding = (const char *) cur->encoding;
7591
Owen Taylor3473f882001-02-23 17:55:21 +00007592 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007593
7594 enc = xmlParseCharEncoding(encoding);
7595 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7596 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007597 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007598 return(-1);
7599 }
7600 if (enc != XML_CHAR_ENCODING_UTF8) {
7601 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00007602 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007603 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007604 }
7605 }
7606
Daniel Veillardf012a642001-07-23 19:10:52 +00007607#ifdef HAVE_ZLIB_H
7608 if (cur->compression < 0) cur->compression = xmlCompressMode;
7609#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007610 /*
7611 * save the content to a temp buffer.
7612 */
Daniel Veillardf012a642001-07-23 19:10:52 +00007613 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00007614 if (buf == NULL) return(-1);
7615
Daniel Veillardf012a642001-07-23 19:10:52 +00007616 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007617
7618 ret = xmlOutputBufferClose(buf);
7619 return(ret);
7620}
7621
Daniel Veillardf012a642001-07-23 19:10:52 +00007622
7623/**
7624 * xmlSaveFileEnc:
7625 * @filename: the filename (or URL)
7626 * @cur: the document
7627 * @encoding: the name of an encoding (or NULL)
7628 *
7629 * Dump an XML document, converting it to the given encoding
7630 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007631 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00007632 */
7633int
7634xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
7635 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
7636}
7637
Owen Taylor3473f882001-02-23 17:55:21 +00007638/**
Daniel Veillard67fee942001-04-26 18:59:03 +00007639 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00007640 * @filename: the filename (or URL)
7641 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00007642 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007643 *
7644 * Dump an XML document to a file. Will use compression if
7645 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00007646 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00007647 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007648 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007649 */
7650int
Daniel Veillard67fee942001-04-26 18:59:03 +00007651xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007652 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00007653}
7654
Daniel Veillard67fee942001-04-26 18:59:03 +00007655/**
7656 * xmlSaveFile:
7657 * @filename: the filename (or URL)
7658 * @cur: the document
7659 *
7660 * Dump an XML document to a file. Will use compression if
7661 * compiled in and enabled. If @filename is "-" the stdout file is
7662 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00007663 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00007664 */
7665int
7666xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007667 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00007668}
7669