blob: 61c5759eea3546c838a1cc4340e5deb9eacccfdb [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 is ATTRIBUTE, it is added into properties instead of children.
2512 * If there is an attribute with equal name, it is first destroyed.
2513 *
Owen Taylor3473f882001-02-23 17:55:21 +00002514 * Returns the child or NULL in case of error.
2515 */
2516xmlNodePtr
2517xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2518 xmlNodePtr prev;
2519
2520 if (parent == NULL) {
2521#ifdef DEBUG_TREE
2522 xmlGenericError(xmlGenericErrorContext,
2523 "xmlAddChild : parent == NULL\n");
2524#endif
2525 return(NULL);
2526 }
2527
2528 if (cur == NULL) {
2529#ifdef DEBUG_TREE
2530 xmlGenericError(xmlGenericErrorContext,
2531 "xmlAddChild : child == NULL\n");
2532#endif
2533 return(NULL);
2534 }
2535
Owen Taylor3473f882001-02-23 17:55:21 +00002536 /*
2537 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002538 * cur is then freed.
2539 */
2540 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002541 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002542 (parent->content != NULL) &&
2543 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002544 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002545 xmlFreeNode(cur);
2546 return(parent);
2547 }
2548 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002549 (parent->last->name == cur->name) &&
2550 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002551 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002552 xmlFreeNode(cur);
2553 return(parent->last);
2554 }
2555 }
2556
2557 /*
2558 * add the new element at the end of the children list.
2559 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002560 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00002561 cur->parent = parent;
2562 if (cur->doc != parent->doc) {
2563 xmlSetTreeDoc(cur, parent->doc);
2564 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002565 /* this check prevents a loop on tree-traversions if a developer
2566 * tries to add a node to its parent multiple times
2567 */
2568 if (prev == parent)
2569 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002570
2571 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002572 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002573 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002574 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002575 (parent->content != NULL) &&
2576 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002577 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002578 xmlFreeNode(cur);
2579 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002580 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002581 if (cur->type == XML_ATTRIBUTE_NODE) {
2582 if (parent->properties == NULL) {
2583 parent->properties = (xmlAttrPtr) cur;
2584 } else {
2585 /* check if an attribute with the same name exists */
2586 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002587
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002588 if (cur->ns == NULL)
2589 lastattr = xmlHasProp(parent, cur->name);
2590 else
2591 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2592 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2593 /* different instance, destroy it (attributes must be unique) */
2594 xmlFreeProp(lastattr);
2595 }
2596 /* find the end */
2597 lastattr = parent->properties;
2598 while (lastattr->next != NULL) {
2599 lastattr = lastattr->next;
2600 }
2601 lastattr->next = (xmlAttrPtr) cur;
2602 ((xmlAttrPtr) cur)->prev = lastattr;
2603 }
2604 } else {
2605 if (parent->children == NULL) {
2606 parent->children = cur;
2607 parent->last = cur;
2608 } else {
2609 prev = parent->last;
2610 prev->next = cur;
2611 cur->prev = prev;
2612 parent->last = cur;
2613 }
2614 }
Owen Taylor3473f882001-02-23 17:55:21 +00002615 return(cur);
2616}
2617
2618/**
2619 * xmlGetLastChild:
2620 * @parent: the parent node
2621 *
2622 * Search the last child of a node.
2623 * Returns the last child or NULL if none.
2624 */
2625xmlNodePtr
2626xmlGetLastChild(xmlNodePtr parent) {
2627 if (parent == NULL) {
2628#ifdef DEBUG_TREE
2629 xmlGenericError(xmlGenericErrorContext,
2630 "xmlGetLastChild : parent == NULL\n");
2631#endif
2632 return(NULL);
2633 }
2634 return(parent->last);
2635}
2636
2637/**
2638 * xmlFreeNodeList:
2639 * @cur: the first node in the list
2640 *
2641 * Free a node and all its siblings, this is a recursive behaviour, all
2642 * the children are freed too.
2643 */
2644void
2645xmlFreeNodeList(xmlNodePtr cur) {
2646 xmlNodePtr next;
2647 if (cur == NULL) {
2648#ifdef DEBUG_TREE
2649 xmlGenericError(xmlGenericErrorContext,
2650 "xmlFreeNodeList : node == NULL\n");
2651#endif
2652 return;
2653 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002654 if (cur->type == XML_NAMESPACE_DECL) {
2655 xmlFreeNsList((xmlNsPtr) cur);
2656 return;
2657 }
Owen Taylor3473f882001-02-23 17:55:21 +00002658 while (cur != NULL) {
2659 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002660 /* unroll to speed up freeing the document */
2661 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00002662
2663 if (xmlDeregisterNodeDefaultValue)
2664 xmlDeregisterNodeDefaultValue(cur);
2665
Daniel Veillard02141ea2001-04-30 11:46:40 +00002666 if ((cur->children != NULL) &&
2667 (cur->type != XML_ENTITY_REF_NODE))
2668 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00002669 if (((cur->type == XML_ELEMENT_NODE) ||
2670 (cur->type == XML_XINCLUDE_START) ||
2671 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002672 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00002673 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002674 if ((cur->type != XML_ELEMENT_NODE) &&
2675 (cur->type != XML_XINCLUDE_START) &&
2676 (cur->type != XML_XINCLUDE_END) &&
2677 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002678 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002679 }
2680 if (((cur->type == XML_ELEMENT_NODE) ||
2681 (cur->type == XML_XINCLUDE_START) ||
2682 (cur->type == XML_XINCLUDE_END)) &&
2683 (cur->nsDef != NULL))
2684 xmlFreeNsList(cur->nsDef);
2685
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002686 /*
2687 * When a node is a text node or a comment, it uses a global static
2688 * variable for the name of the node.
2689 *
2690 * The xmlStrEqual comparisons need to be done when (happened with
2691 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002692 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002693 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002694 * the string addresses compare are not sufficient.
2695 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002696 if ((cur->name != NULL) &&
2697 (cur->name != xmlStringText) &&
2698 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002699 (cur->name != xmlStringComment)) {
2700 if (cur->type == XML_TEXT_NODE) {
2701 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2702 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2703 xmlFree((char *) cur->name);
2704 } else if (cur->type == XML_COMMENT_NODE) {
2705 if (!xmlStrEqual(cur->name, xmlStringComment))
2706 xmlFree((char *) cur->name);
2707 } else
2708 xmlFree((char *) cur->name);
2709 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002710 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002711 xmlFree(cur);
2712 }
Owen Taylor3473f882001-02-23 17:55:21 +00002713 cur = next;
2714 }
2715}
2716
2717/**
2718 * xmlFreeNode:
2719 * @cur: the node
2720 *
2721 * Free a node, this is a recursive behaviour, all the children are freed too.
2722 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2723 */
2724void
2725xmlFreeNode(xmlNodePtr cur) {
2726 if (cur == NULL) {
2727#ifdef DEBUG_TREE
2728 xmlGenericError(xmlGenericErrorContext,
2729 "xmlFreeNode : node == NULL\n");
2730#endif
2731 return;
2732 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002733
Daniel Veillard02141ea2001-04-30 11:46:40 +00002734 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002735 if (cur->type == XML_DTD_NODE) {
2736 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002737 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002738 }
2739 if (cur->type == XML_NAMESPACE_DECL) {
2740 xmlFreeNs((xmlNsPtr) cur);
2741 return;
2742 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00002743 if (cur->type == XML_ATTRIBUTE_NODE) {
2744 xmlFreeProp((xmlAttrPtr) cur);
2745 return;
2746 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002747
2748 if (xmlDeregisterNodeDefaultValue)
2749 xmlDeregisterNodeDefaultValue(cur);
2750
Owen Taylor3473f882001-02-23 17:55:21 +00002751 if ((cur->children != NULL) &&
2752 (cur->type != XML_ENTITY_REF_NODE))
2753 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00002754 if (((cur->type == XML_ELEMENT_NODE) ||
2755 (cur->type == XML_XINCLUDE_START) ||
2756 (cur->type == XML_XINCLUDE_END)) &&
2757 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00002758 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002759 if ((cur->type != XML_ELEMENT_NODE) &&
2760 (cur->content != NULL) &&
2761 (cur->type != XML_ENTITY_REF_NODE) &&
2762 (cur->type != XML_XINCLUDE_END) &&
2763 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002764 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002765 }
2766
Daniel Veillardacd370f2001-06-09 17:17:51 +00002767 /*
2768 * When a node is a text node or a comment, it uses a global static
2769 * variable for the name of the node.
2770 *
2771 * The xmlStrEqual comparisons need to be done when (happened with
2772 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002773 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002774 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002775 * are not sufficient.
2776 */
Owen Taylor3473f882001-02-23 17:55:21 +00002777 if ((cur->name != NULL) &&
2778 (cur->name != xmlStringText) &&
2779 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002780 (cur->name != xmlStringComment)) {
2781 if (cur->type == XML_TEXT_NODE) {
2782 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2783 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2784 xmlFree((char *) cur->name);
2785 } else if (cur->type == XML_COMMENT_NODE) {
2786 if (!xmlStrEqual(cur->name, xmlStringComment))
2787 xmlFree((char *) cur->name);
2788 } else
2789 xmlFree((char *) cur->name);
2790 }
2791
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002792 if (((cur->type == XML_ELEMENT_NODE) ||
2793 (cur->type == XML_XINCLUDE_START) ||
2794 (cur->type == XML_XINCLUDE_END)) &&
2795 (cur->nsDef != NULL))
2796 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002797 xmlFree(cur);
2798}
2799
2800/**
2801 * xmlUnlinkNode:
2802 * @cur: the node
2803 *
2804 * Unlink a node from it's current context, the node is not freed
2805 */
2806void
2807xmlUnlinkNode(xmlNodePtr cur) {
2808 if (cur == NULL) {
2809#ifdef DEBUG_TREE
2810 xmlGenericError(xmlGenericErrorContext,
2811 "xmlUnlinkNode : node == NULL\n");
2812#endif
2813 return;
2814 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002815 if (cur->type == XML_DTD_NODE) {
2816 xmlDocPtr doc;
2817 doc = cur->doc;
2818 if (doc->intSubset == (xmlDtdPtr) cur)
2819 doc->intSubset = NULL;
2820 if (doc->extSubset == (xmlDtdPtr) cur)
2821 doc->extSubset = NULL;
2822 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002823 if (cur->parent != NULL) {
2824 xmlNodePtr parent;
2825 parent = cur->parent;
2826 if (cur->type == XML_ATTRIBUTE_NODE) {
2827 if (parent->properties == (xmlAttrPtr) cur)
2828 parent->properties = ((xmlAttrPtr) cur)->next;
2829 } else {
2830 if (parent->children == cur)
2831 parent->children = cur->next;
2832 if (parent->last == cur)
2833 parent->last = cur->prev;
2834 }
2835 cur->parent = NULL;
2836 }
Owen Taylor3473f882001-02-23 17:55:21 +00002837 if (cur->next != NULL)
2838 cur->next->prev = cur->prev;
2839 if (cur->prev != NULL)
2840 cur->prev->next = cur->next;
2841 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002842}
2843
2844/**
2845 * xmlReplaceNode:
2846 * @old: the old node
2847 * @cur: the node
2848 *
2849 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002850 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002851 * first unlinked from its existing context.
2852 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002853 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002854 */
2855xmlNodePtr
2856xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2857 if (old == NULL) {
2858#ifdef DEBUG_TREE
2859 xmlGenericError(xmlGenericErrorContext,
2860 "xmlReplaceNode : old == NULL\n");
2861#endif
2862 return(NULL);
2863 }
2864 if (cur == NULL) {
2865 xmlUnlinkNode(old);
2866 return(old);
2867 }
2868 if (cur == old) {
2869 return(old);
2870 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002871 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2872#ifdef DEBUG_TREE
2873 xmlGenericError(xmlGenericErrorContext,
2874 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2875#endif
2876 return(old);
2877 }
2878 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2879#ifdef DEBUG_TREE
2880 xmlGenericError(xmlGenericErrorContext,
2881 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2882#endif
2883 return(old);
2884 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002885 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2886#ifdef DEBUG_TREE
2887 xmlGenericError(xmlGenericErrorContext,
2888 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2889#endif
2890 return(old);
2891 }
2892 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2893#ifdef DEBUG_TREE
2894 xmlGenericError(xmlGenericErrorContext,
2895 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2896#endif
2897 return(old);
2898 }
Owen Taylor3473f882001-02-23 17:55:21 +00002899 xmlUnlinkNode(cur);
2900 cur->doc = old->doc;
2901 cur->parent = old->parent;
2902 cur->next = old->next;
2903 if (cur->next != NULL)
2904 cur->next->prev = cur;
2905 cur->prev = old->prev;
2906 if (cur->prev != NULL)
2907 cur->prev->next = cur;
2908 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002909 if (cur->type == XML_ATTRIBUTE_NODE) {
2910 if (cur->parent->properties == (xmlAttrPtr)old)
2911 cur->parent->properties = ((xmlAttrPtr) cur);
2912 } else {
2913 if (cur->parent->children == old)
2914 cur->parent->children = cur;
2915 if (cur->parent->last == old)
2916 cur->parent->last = cur;
2917 }
Owen Taylor3473f882001-02-23 17:55:21 +00002918 }
2919 old->next = old->prev = NULL;
2920 old->parent = NULL;
2921 return(old);
2922}
2923
2924/************************************************************************
2925 * *
2926 * Copy operations *
2927 * *
2928 ************************************************************************/
2929
2930/**
2931 * xmlCopyNamespace:
2932 * @cur: the namespace
2933 *
2934 * Do a copy of the namespace.
2935 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002936 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002937 */
2938xmlNsPtr
2939xmlCopyNamespace(xmlNsPtr cur) {
2940 xmlNsPtr ret;
2941
2942 if (cur == NULL) return(NULL);
2943 switch (cur->type) {
2944 case XML_LOCAL_NAMESPACE:
2945 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2946 break;
2947 default:
2948#ifdef DEBUG_TREE
2949 xmlGenericError(xmlGenericErrorContext,
2950 "xmlCopyNamespace: invalid type %d\n", cur->type);
2951#endif
2952 return(NULL);
2953 }
2954 return(ret);
2955}
2956
2957/**
2958 * xmlCopyNamespaceList:
2959 * @cur: the first namespace
2960 *
2961 * Do a copy of an namespace list.
2962 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002963 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002964 */
2965xmlNsPtr
2966xmlCopyNamespaceList(xmlNsPtr cur) {
2967 xmlNsPtr ret = NULL;
2968 xmlNsPtr p = NULL,q;
2969
2970 while (cur != NULL) {
2971 q = xmlCopyNamespace(cur);
2972 if (p == NULL) {
2973 ret = p = q;
2974 } else {
2975 p->next = q;
2976 p = q;
2977 }
2978 cur = cur->next;
2979 }
2980 return(ret);
2981}
2982
2983static xmlNodePtr
2984xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2985/**
2986 * xmlCopyProp:
2987 * @target: the element where the attribute will be grafted
2988 * @cur: the attribute
2989 *
2990 * Do a copy of the attribute.
2991 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002992 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002993 */
2994xmlAttrPtr
2995xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2996 xmlAttrPtr ret;
2997
2998 if (cur == NULL) return(NULL);
2999 if (target != NULL)
3000 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3001 else if (cur->parent != NULL)
3002 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3003 else if (cur->children != NULL)
3004 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3005 else
3006 ret = xmlNewDocProp(NULL, cur->name, NULL);
3007 if (ret == NULL) return(NULL);
3008 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003009
Owen Taylor3473f882001-02-23 17:55:21 +00003010 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003011 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003012/*
3013 * if (target->doc)
3014 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3015 * else if (cur->doc) / * target may not yet have a doc : KPI * /
3016 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
3017 * else
3018 * ns = NULL;
3019 * ret->ns = ns;
3020 */
3021 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3022 if (ns == NULL) {
3023 /*
3024 * Humm, we are copying an element whose namespace is defined
3025 * out of the new tree scope. Search it in the original tree
3026 * and add it at the top of the new tree
3027 */
3028 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3029 if (ns != NULL) {
3030 xmlNodePtr root = target;
3031 xmlNodePtr pred = NULL;
3032
3033 while (root->parent != NULL) {
3034 pred = root;
3035 root = root->parent;
3036 }
3037 if (root == (xmlNodePtr) target->doc) {
3038 /* correct possibly cycling above the document elt */
3039 root = pred;
3040 }
3041 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3042 }
3043 } else {
3044 /*
3045 * we have to find something appropriate here since
3046 * we cant be sure, that the namespce we found is identified
3047 * by the prefix
3048 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003049 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003050 /* this is the nice case */
3051 ret->ns = ns;
3052 } else {
3053 /*
3054 * we are in trouble: we need a new reconcilied namespace.
3055 * This is expensive
3056 */
3057 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3058 }
3059 }
3060
Owen Taylor3473f882001-02-23 17:55:21 +00003061 } else
3062 ret->ns = NULL;
3063
3064 if (cur->children != NULL) {
3065 xmlNodePtr tmp;
3066
3067 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3068 ret->last = NULL;
3069 tmp = ret->children;
3070 while (tmp != NULL) {
3071 /* tmp->parent = (xmlNodePtr)ret; */
3072 if (tmp->next == NULL)
3073 ret->last = tmp;
3074 tmp = tmp->next;
3075 }
3076 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003077 /*
3078 * Try to handle IDs
3079 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003080 if ((target!= NULL) && (cur!= NULL) &&
3081 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003082 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3083 if (xmlIsID(cur->doc, cur->parent, cur)) {
3084 xmlChar *id;
3085
3086 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3087 if (id != NULL) {
3088 xmlAddID(NULL, target->doc, id, ret);
3089 xmlFree(id);
3090 }
3091 }
3092 }
Owen Taylor3473f882001-02-23 17:55:21 +00003093 return(ret);
3094}
3095
3096/**
3097 * xmlCopyPropList:
3098 * @target: the element where the attributes will be grafted
3099 * @cur: the first attribute
3100 *
3101 * Do a copy of an attribute list.
3102 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003103 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003104 */
3105xmlAttrPtr
3106xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3107 xmlAttrPtr ret = NULL;
3108 xmlAttrPtr p = NULL,q;
3109
3110 while (cur != NULL) {
3111 q = xmlCopyProp(target, cur);
3112 if (p == NULL) {
3113 ret = p = q;
3114 } else {
3115 p->next = q;
3116 q->prev = p;
3117 p = q;
3118 }
3119 cur = cur->next;
3120 }
3121 return(ret);
3122}
3123
3124/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003125 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003126 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003127 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003128 * tricky reason: namespaces. Doing a direct copy of a node
3129 * say RPM:Copyright without changing the namespace pointer to
3130 * something else can produce stale links. One way to do it is
3131 * to keep a reference counter but this doesn't work as soon
3132 * as one move the element or the subtree out of the scope of
3133 * the existing namespace. The actual solution seems to add
3134 * a copy of the namespace at the top of the copied tree if
3135 * not available in the subtree.
3136 * Hence two functions, the public front-end call the inner ones
3137 */
3138
3139static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003140xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003141 int recursive) {
3142 xmlNodePtr ret;
3143
3144 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003145 switch (node->type) {
3146 case XML_TEXT_NODE:
3147 case XML_CDATA_SECTION_NODE:
3148 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003149 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003150 case XML_ENTITY_REF_NODE:
3151 case XML_ENTITY_NODE:
3152 case XML_PI_NODE:
3153 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003154 case XML_XINCLUDE_START:
3155 case XML_XINCLUDE_END:
3156 break;
3157 case XML_ATTRIBUTE_NODE:
3158 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3159 case XML_NAMESPACE_DECL:
3160 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3161
Daniel Veillard39196eb2001-06-19 18:09:42 +00003162 case XML_DOCUMENT_NODE:
3163 case XML_HTML_DOCUMENT_NODE:
3164#ifdef LIBXML_DOCB_ENABLED
3165 case XML_DOCB_DOCUMENT_NODE:
3166#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003167 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003168 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003169 case XML_NOTATION_NODE:
3170 case XML_DTD_NODE:
3171 case XML_ELEMENT_DECL:
3172 case XML_ATTRIBUTE_DECL:
3173 case XML_ENTITY_DECL:
3174 return(NULL);
3175 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003176
Owen Taylor3473f882001-02-23 17:55:21 +00003177 /*
3178 * Allocate a new node and fill the fields.
3179 */
3180 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3181 if (ret == NULL) {
3182 xmlGenericError(xmlGenericErrorContext,
3183 "xmlStaticCopyNode : malloc failed\n");
3184 return(NULL);
3185 }
3186 memset(ret, 0, sizeof(xmlNode));
3187 ret->type = node->type;
3188
3189 ret->doc = doc;
3190 ret->parent = parent;
3191 if (node->name == xmlStringText)
3192 ret->name = xmlStringText;
3193 else if (node->name == xmlStringTextNoenc)
3194 ret->name = xmlStringTextNoenc;
3195 else if (node->name == xmlStringComment)
3196 ret->name = xmlStringComment;
3197 else if (node->name != NULL)
3198 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003199 if ((node->type != XML_ELEMENT_NODE) &&
3200 (node->content != NULL) &&
3201 (node->type != XML_ENTITY_REF_NODE) &&
3202 (node->type != XML_XINCLUDE_END) &&
3203 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003204 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003205 }else{
3206 if (node->type == XML_ELEMENT_NODE)
3207 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003208 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003209 if (parent != NULL) {
3210 xmlNodePtr tmp;
3211
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003212 /*
3213 * this is a tricky part for the node register thing:
3214 * in case ret does get coalesced in xmlAddChild
3215 * the deregister-node callback is called; so we register ret now already
3216 */
3217 if (xmlRegisterNodeDefaultValue)
3218 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3219
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003220 tmp = xmlAddChild(parent, ret);
3221 /* node could have coalesced */
3222 if (tmp != ret)
3223 return(tmp);
3224 }
Owen Taylor3473f882001-02-23 17:55:21 +00003225
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003226 if (!recursive)
3227 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003228 if (node->nsDef != NULL)
3229 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3230
3231 if (node->ns != NULL) {
3232 xmlNsPtr ns;
3233
3234 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3235 if (ns == NULL) {
3236 /*
3237 * Humm, we are copying an element whose namespace is defined
3238 * out of the new tree scope. Search it in the original tree
3239 * and add it at the top of the new tree
3240 */
3241 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3242 if (ns != NULL) {
3243 xmlNodePtr root = ret;
3244
3245 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003246 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003247 }
3248 } else {
3249 /*
3250 * reference the existing namespace definition in our own tree.
3251 */
3252 ret->ns = ns;
3253 }
3254 }
3255 if (node->properties != NULL)
3256 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003257 if (node->type == XML_ENTITY_REF_NODE) {
3258 if ((doc == NULL) || (node->doc != doc)) {
3259 /*
3260 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003261 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003262 * we cannot keep the reference. Try to find it in the
3263 * target document.
3264 */
3265 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3266 } else {
3267 ret->children = node->children;
3268 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003269 ret->last = ret->children;
3270 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003271 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003272 UPDATE_LAST_CHILD_AND_PARENT(ret)
3273 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003274
3275out:
3276 /* if parent != NULL we already registered the node above */
3277 if (parent == NULL && xmlRegisterNodeDefaultValue)
3278 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003279 return(ret);
3280}
3281
3282static xmlNodePtr
3283xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3284 xmlNodePtr ret = NULL;
3285 xmlNodePtr p = NULL,q;
3286
3287 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003288 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003289 if (doc == NULL) {
3290 node = node->next;
3291 continue;
3292 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003293 if (doc->intSubset == NULL) {
3294 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3295 q->doc = doc;
3296 q->parent = parent;
3297 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003298 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003299 } else {
3300 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003301 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003302 }
3303 } else
3304 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003305 if (ret == NULL) {
3306 q->prev = NULL;
3307 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003308 } else if (p != q) {
3309 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003310 p->next = q;
3311 q->prev = p;
3312 p = q;
3313 }
3314 node = node->next;
3315 }
3316 return(ret);
3317}
3318
3319/**
3320 * xmlCopyNode:
3321 * @node: the node
3322 * @recursive: if 1 do a recursive copy.
3323 *
3324 * Do a copy of the node.
3325 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003326 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003327 */
3328xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003329xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003330 xmlNodePtr ret;
3331
3332 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3333 return(ret);
3334}
3335
3336/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003337 * xmlDocCopyNode:
3338 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003339 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003340 * @recursive: if 1 do a recursive copy.
3341 *
3342 * Do a copy of the node to a given document.
3343 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003344 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003345 */
3346xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003347xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003348 xmlNodePtr ret;
3349
3350 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3351 return(ret);
3352}
3353
3354/**
Owen Taylor3473f882001-02-23 17:55:21 +00003355 * xmlCopyNodeList:
3356 * @node: the first node in the list.
3357 *
3358 * Do a recursive copy of the node list.
3359 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003360 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003361 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003362xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003363 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3364 return(ret);
3365}
3366
3367/**
Owen Taylor3473f882001-02-23 17:55:21 +00003368 * xmlCopyDtd:
3369 * @dtd: the dtd
3370 *
3371 * Do a copy of the dtd.
3372 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003373 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003374 */
3375xmlDtdPtr
3376xmlCopyDtd(xmlDtdPtr dtd) {
3377 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003378 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003379
3380 if (dtd == NULL) return(NULL);
3381 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3382 if (ret == NULL) return(NULL);
3383 if (dtd->entities != NULL)
3384 ret->entities = (void *) xmlCopyEntitiesTable(
3385 (xmlEntitiesTablePtr) dtd->entities);
3386 if (dtd->notations != NULL)
3387 ret->notations = (void *) xmlCopyNotationTable(
3388 (xmlNotationTablePtr) dtd->notations);
3389 if (dtd->elements != NULL)
3390 ret->elements = (void *) xmlCopyElementTable(
3391 (xmlElementTablePtr) dtd->elements);
3392 if (dtd->attributes != NULL)
3393 ret->attributes = (void *) xmlCopyAttributeTable(
3394 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003395 if (dtd->pentities != NULL)
3396 ret->pentities = (void *) xmlCopyEntitiesTable(
3397 (xmlEntitiesTablePtr) dtd->pentities);
3398
3399 cur = dtd->children;
3400 while (cur != NULL) {
3401 q = NULL;
3402
3403 if (cur->type == XML_ENTITY_DECL) {
3404 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3405 switch (tmp->etype) {
3406 case XML_INTERNAL_GENERAL_ENTITY:
3407 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3408 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3409 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3410 break;
3411 case XML_INTERNAL_PARAMETER_ENTITY:
3412 case XML_EXTERNAL_PARAMETER_ENTITY:
3413 q = (xmlNodePtr)
3414 xmlGetParameterEntityFromDtd(ret, tmp->name);
3415 break;
3416 case XML_INTERNAL_PREDEFINED_ENTITY:
3417 break;
3418 }
3419 } else if (cur->type == XML_ELEMENT_DECL) {
3420 xmlElementPtr tmp = (xmlElementPtr) cur;
3421 q = (xmlNodePtr)
3422 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3423 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3424 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3425 q = (xmlNodePtr)
3426 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3427 } else if (cur->type == XML_COMMENT_NODE) {
3428 q = xmlCopyNode(cur, 0);
3429 }
3430
3431 if (q == NULL) {
3432 cur = cur->next;
3433 continue;
3434 }
3435
3436 if (p == NULL)
3437 ret->children = q;
3438 else
3439 p->next = q;
3440
3441 q->prev = p;
3442 q->parent = (xmlNodePtr) ret;
3443 q->next = NULL;
3444 ret->last = q;
3445 p = q;
3446 cur = cur->next;
3447 }
3448
Owen Taylor3473f882001-02-23 17:55:21 +00003449 return(ret);
3450}
3451
3452/**
3453 * xmlCopyDoc:
3454 * @doc: the document
3455 * @recursive: if 1 do a recursive copy.
3456 *
3457 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003458 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003459 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003460 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003461 */
3462xmlDocPtr
3463xmlCopyDoc(xmlDocPtr doc, int recursive) {
3464 xmlDocPtr ret;
3465
3466 if (doc == NULL) return(NULL);
3467 ret = xmlNewDoc(doc->version);
3468 if (ret == NULL) return(NULL);
3469 if (doc->name != NULL)
3470 ret->name = xmlMemStrdup(doc->name);
3471 if (doc->encoding != NULL)
3472 ret->encoding = xmlStrdup(doc->encoding);
3473 ret->charset = doc->charset;
3474 ret->compression = doc->compression;
3475 ret->standalone = doc->standalone;
3476 if (!recursive) return(ret);
3477
Daniel Veillardb33c2012001-04-25 12:59:04 +00003478 ret->last = NULL;
3479 ret->children = NULL;
3480 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003481 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003482 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003483 ret->intSubset->parent = ret;
3484 }
Owen Taylor3473f882001-02-23 17:55:21 +00003485 if (doc->oldNs != NULL)
3486 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3487 if (doc->children != NULL) {
3488 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003489
3490 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3491 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003492 ret->last = NULL;
3493 tmp = ret->children;
3494 while (tmp != NULL) {
3495 if (tmp->next == NULL)
3496 ret->last = tmp;
3497 tmp = tmp->next;
3498 }
3499 }
3500 return(ret);
3501}
3502
3503/************************************************************************
3504 * *
3505 * Content access functions *
3506 * *
3507 ************************************************************************/
3508
3509/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003510 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003511 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00003512 *
3513 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003514 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003515 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003516 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003517 */
3518long
3519xmlGetLineNo(xmlNodePtr node)
3520{
3521 long result = -1;
3522
3523 if (!node)
3524 return result;
3525 if (node->type == XML_ELEMENT_NODE)
3526 result = (long) node->content;
3527 else if ((node->prev != NULL) &&
3528 ((node->prev->type == XML_ELEMENT_NODE) ||
3529 (node->prev->type == XML_TEXT_NODE)))
3530 result = xmlGetLineNo(node->prev);
3531 else if ((node->parent != NULL) &&
3532 ((node->parent->type == XML_ELEMENT_NODE) ||
3533 (node->parent->type == XML_TEXT_NODE)))
3534 result = xmlGetLineNo(node->parent);
3535
3536 return result;
3537}
3538
3539/**
3540 * xmlGetNodePath:
3541 * @node: a node
3542 *
3543 * Build a structure based Path for the given node
3544 *
3545 * Returns the new path or NULL in case of error. The caller must free
3546 * the returned string
3547 */
3548xmlChar *
3549xmlGetNodePath(xmlNodePtr node)
3550{
3551 xmlNodePtr cur, tmp, next;
3552 xmlChar *buffer = NULL, *temp;
3553 size_t buf_len;
3554 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00003555 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00003556 const char *name;
3557 char nametemp[100];
3558 int occur = 0;
3559
3560 if (node == NULL)
3561 return (NULL);
3562
3563 buf_len = 500;
3564 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3565 if (buffer == NULL)
3566 return (NULL);
3567 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3568 if (buf == NULL) {
3569 xmlFree(buffer);
3570 return (NULL);
3571 }
3572
3573 buffer[0] = 0;
3574 cur = node;
3575 do {
3576 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003577 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003578 occur = 0;
3579 if ((cur->type == XML_DOCUMENT_NODE) ||
3580 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3581 if (buffer[0] == '/')
3582 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003583 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003584 next = NULL;
3585 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003586 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003587 name = (const char *) cur->name;
3588 if (cur->ns) {
3589 snprintf(nametemp, sizeof(nametemp) - 1,
3590 "%s:%s", cur->ns->prefix, cur->name);
3591 nametemp[sizeof(nametemp) - 1] = 0;
3592 name = nametemp;
3593 }
3594 next = cur->parent;
3595
3596 /*
3597 * Thumbler index computation
3598 */
3599 tmp = cur->prev;
3600 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00003601 if ((tmp->type == XML_ELEMENT_NODE) &&
3602 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003603 occur++;
3604 tmp = tmp->prev;
3605 }
3606 if (occur == 0) {
3607 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003608 while (tmp != NULL && occur == 0) {
3609 if ((tmp->type == XML_ELEMENT_NODE) &&
3610 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003611 occur++;
3612 tmp = tmp->next;
3613 }
3614 if (occur != 0)
3615 occur = 1;
3616 } else
3617 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003618 } else if (cur->type == XML_COMMENT_NODE) {
3619 sep = "/";
3620 name = "comment()";
3621 next = cur->parent;
3622
3623 /*
3624 * Thumbler index computation
3625 */
3626 tmp = cur->prev;
3627 while (tmp != NULL) {
3628 if (tmp->type == XML_COMMENT_NODE)
3629 occur++;
3630 tmp = tmp->prev;
3631 }
3632 if (occur == 0) {
3633 tmp = cur->next;
3634 while (tmp != NULL && occur == 0) {
3635 if (tmp->type == XML_COMMENT_NODE)
3636 occur++;
3637 tmp = tmp->next;
3638 }
3639 if (occur != 0)
3640 occur = 1;
3641 } else
3642 occur++;
3643 } else if ((cur->type == XML_TEXT_NODE) ||
3644 (cur->type == XML_CDATA_SECTION_NODE)) {
3645 sep = "/";
3646 name = "text()";
3647 next = cur->parent;
3648
3649 /*
3650 * Thumbler index computation
3651 */
3652 tmp = cur->prev;
3653 while (tmp != NULL) {
3654 if ((cur->type == XML_TEXT_NODE) ||
3655 (cur->type == XML_CDATA_SECTION_NODE))
3656 occur++;
3657 tmp = tmp->prev;
3658 }
3659 if (occur == 0) {
3660 tmp = cur->next;
3661 while (tmp != NULL && occur == 0) {
3662 if ((cur->type == XML_TEXT_NODE) ||
3663 (cur->type == XML_CDATA_SECTION_NODE))
3664 occur++;
3665 tmp = tmp->next;
3666 }
3667 if (occur != 0)
3668 occur = 1;
3669 } else
3670 occur++;
3671 } else if (cur->type == XML_PI_NODE) {
3672 sep = "/";
3673 snprintf(nametemp, sizeof(nametemp) - 1,
3674 "processing-instruction('%s')", cur->name);
3675 nametemp[sizeof(nametemp) - 1] = 0;
3676 name = nametemp;
3677
3678 next = cur->parent;
3679
3680 /*
3681 * Thumbler index computation
3682 */
3683 tmp = cur->prev;
3684 while (tmp != NULL) {
3685 if ((tmp->type == XML_PI_NODE) &&
3686 (xmlStrEqual(cur->name, tmp->name)))
3687 occur++;
3688 tmp = tmp->prev;
3689 }
3690 if (occur == 0) {
3691 tmp = cur->next;
3692 while (tmp != NULL && occur == 0) {
3693 if ((tmp->type == XML_PI_NODE) &&
3694 (xmlStrEqual(cur->name, tmp->name)))
3695 occur++;
3696 tmp = tmp->next;
3697 }
3698 if (occur != 0)
3699 occur = 1;
3700 } else
3701 occur++;
3702
Daniel Veillard8faa7832001-11-26 15:58:08 +00003703 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003704 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003705 name = (const char *) (((xmlAttrPtr) cur)->name);
3706 next = ((xmlAttrPtr) cur)->parent;
3707 } else {
3708 next = cur->parent;
3709 }
3710
3711 /*
3712 * Make sure there is enough room
3713 */
3714 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3715 buf_len =
3716 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3717 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3718 if (temp == NULL) {
3719 xmlFree(buf);
3720 xmlFree(buffer);
3721 return (NULL);
3722 }
3723 buffer = temp;
3724 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3725 if (temp == NULL) {
3726 xmlFree(buf);
3727 xmlFree(buffer);
3728 return (NULL);
3729 }
3730 buf = temp;
3731 }
3732 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003733 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00003734 sep, name, (char *) buffer);
3735 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003736 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00003737 sep, name, occur, (char *) buffer);
3738 snprintf((char *) buffer, buf_len, "%s", buf);
3739 cur = next;
3740 } while (cur != NULL);
3741 xmlFree(buf);
3742 return (buffer);
3743}
3744
3745/**
Owen Taylor3473f882001-02-23 17:55:21 +00003746 * xmlDocGetRootElement:
3747 * @doc: the document
3748 *
3749 * Get the root element of the document (doc->children is a list
3750 * containing possibly comments, PIs, etc ...).
3751 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003752 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003753 */
3754xmlNodePtr
3755xmlDocGetRootElement(xmlDocPtr doc) {
3756 xmlNodePtr ret;
3757
3758 if (doc == NULL) return(NULL);
3759 ret = doc->children;
3760 while (ret != NULL) {
3761 if (ret->type == XML_ELEMENT_NODE)
3762 return(ret);
3763 ret = ret->next;
3764 }
3765 return(ret);
3766}
3767
3768/**
3769 * xmlDocSetRootElement:
3770 * @doc: the document
3771 * @root: the new document root element
3772 *
3773 * Set the root element of the document (doc->children is a list
3774 * containing possibly comments, PIs, etc ...).
3775 *
3776 * Returns the old root element if any was found
3777 */
3778xmlNodePtr
3779xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3780 xmlNodePtr old = NULL;
3781
3782 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00003783 if (root == NULL)
3784 return(NULL);
3785 xmlUnlinkNode(root);
3786 root->doc = doc;
3787 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00003788 old = doc->children;
3789 while (old != NULL) {
3790 if (old->type == XML_ELEMENT_NODE)
3791 break;
3792 old = old->next;
3793 }
3794 if (old == NULL) {
3795 if (doc->children == NULL) {
3796 doc->children = root;
3797 doc->last = root;
3798 } else {
3799 xmlAddSibling(doc->children, root);
3800 }
3801 } else {
3802 xmlReplaceNode(old, root);
3803 }
3804 return(old);
3805}
3806
3807/**
3808 * xmlNodeSetLang:
3809 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003810 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003811 *
3812 * Set the language of a node, i.e. the values of the xml:lang
3813 * attribute.
3814 */
3815void
3816xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003817 xmlNsPtr ns;
3818
Owen Taylor3473f882001-02-23 17:55:21 +00003819 if (cur == NULL) return;
3820 switch(cur->type) {
3821 case XML_TEXT_NODE:
3822 case XML_CDATA_SECTION_NODE:
3823 case XML_COMMENT_NODE:
3824 case XML_DOCUMENT_NODE:
3825 case XML_DOCUMENT_TYPE_NODE:
3826 case XML_DOCUMENT_FRAG_NODE:
3827 case XML_NOTATION_NODE:
3828 case XML_HTML_DOCUMENT_NODE:
3829 case XML_DTD_NODE:
3830 case XML_ELEMENT_DECL:
3831 case XML_ATTRIBUTE_DECL:
3832 case XML_ENTITY_DECL:
3833 case XML_PI_NODE:
3834 case XML_ENTITY_REF_NODE:
3835 case XML_ENTITY_NODE:
3836 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003837#ifdef LIBXML_DOCB_ENABLED
3838 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003839#endif
3840 case XML_XINCLUDE_START:
3841 case XML_XINCLUDE_END:
3842 return;
3843 case XML_ELEMENT_NODE:
3844 case XML_ATTRIBUTE_NODE:
3845 break;
3846 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003847 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3848 if (ns == NULL)
3849 return;
3850 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003851}
3852
3853/**
3854 * xmlNodeGetLang:
3855 * @cur: the node being checked
3856 *
3857 * Searches the language of a node, i.e. the values of the xml:lang
3858 * attribute or the one carried by the nearest ancestor.
3859 *
3860 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003861 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003862 */
3863xmlChar *
3864xmlNodeGetLang(xmlNodePtr cur) {
3865 xmlChar *lang;
3866
3867 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003868 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003869 if (lang != NULL)
3870 return(lang);
3871 cur = cur->parent;
3872 }
3873 return(NULL);
3874}
3875
3876
3877/**
3878 * xmlNodeSetSpacePreserve:
3879 * @cur: the node being changed
3880 * @val: the xml:space value ("0": default, 1: "preserve")
3881 *
3882 * Set (or reset) the space preserving behaviour of a node, i.e. the
3883 * value of the xml:space attribute.
3884 */
3885void
3886xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003887 xmlNsPtr ns;
3888
Owen Taylor3473f882001-02-23 17:55:21 +00003889 if (cur == NULL) return;
3890 switch(cur->type) {
3891 case XML_TEXT_NODE:
3892 case XML_CDATA_SECTION_NODE:
3893 case XML_COMMENT_NODE:
3894 case XML_DOCUMENT_NODE:
3895 case XML_DOCUMENT_TYPE_NODE:
3896 case XML_DOCUMENT_FRAG_NODE:
3897 case XML_NOTATION_NODE:
3898 case XML_HTML_DOCUMENT_NODE:
3899 case XML_DTD_NODE:
3900 case XML_ELEMENT_DECL:
3901 case XML_ATTRIBUTE_DECL:
3902 case XML_ENTITY_DECL:
3903 case XML_PI_NODE:
3904 case XML_ENTITY_REF_NODE:
3905 case XML_ENTITY_NODE:
3906 case XML_NAMESPACE_DECL:
3907 case XML_XINCLUDE_START:
3908 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003909#ifdef LIBXML_DOCB_ENABLED
3910 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003911#endif
3912 return;
3913 case XML_ELEMENT_NODE:
3914 case XML_ATTRIBUTE_NODE:
3915 break;
3916 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003917 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3918 if (ns == NULL)
3919 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003920 switch (val) {
3921 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003922 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003923 break;
3924 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003925 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003926 break;
3927 }
3928}
3929
3930/**
3931 * xmlNodeGetSpacePreserve:
3932 * @cur: the node being checked
3933 *
3934 * Searches the space preserving behaviour of a node, i.e. the values
3935 * of the xml:space attribute or the one carried by the nearest
3936 * ancestor.
3937 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003938 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003939 */
3940int
3941xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3942 xmlChar *space;
3943
3944 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003945 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003946 if (space != NULL) {
3947 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3948 xmlFree(space);
3949 return(1);
3950 }
3951 if (xmlStrEqual(space, BAD_CAST "default")) {
3952 xmlFree(space);
3953 return(0);
3954 }
3955 xmlFree(space);
3956 }
3957 cur = cur->parent;
3958 }
3959 return(-1);
3960}
3961
3962/**
3963 * xmlNodeSetName:
3964 * @cur: the node being changed
3965 * @name: the new tag name
3966 *
3967 * Set (or reset) the name of a node.
3968 */
3969void
3970xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3971 if (cur == NULL) return;
3972 if (name == NULL) return;
3973 switch(cur->type) {
3974 case XML_TEXT_NODE:
3975 case XML_CDATA_SECTION_NODE:
3976 case XML_COMMENT_NODE:
3977 case XML_DOCUMENT_TYPE_NODE:
3978 case XML_DOCUMENT_FRAG_NODE:
3979 case XML_NOTATION_NODE:
3980 case XML_HTML_DOCUMENT_NODE:
3981 case XML_NAMESPACE_DECL:
3982 case XML_XINCLUDE_START:
3983 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003984#ifdef LIBXML_DOCB_ENABLED
3985 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003986#endif
3987 return;
3988 case XML_ELEMENT_NODE:
3989 case XML_ATTRIBUTE_NODE:
3990 case XML_PI_NODE:
3991 case XML_ENTITY_REF_NODE:
3992 case XML_ENTITY_NODE:
3993 case XML_DTD_NODE:
3994 case XML_DOCUMENT_NODE:
3995 case XML_ELEMENT_DECL:
3996 case XML_ATTRIBUTE_DECL:
3997 case XML_ENTITY_DECL:
3998 break;
3999 }
4000 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4001 cur->name = xmlStrdup(name);
4002}
4003
4004/**
4005 * xmlNodeSetBase:
4006 * @cur: the node being changed
4007 * @uri: the new base URI
4008 *
4009 * Set (or reset) the base URI of a node, i.e. the value of the
4010 * xml:base attribute.
4011 */
4012void
4013xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004014 xmlNsPtr ns;
4015
Owen Taylor3473f882001-02-23 17:55:21 +00004016 if (cur == NULL) return;
4017 switch(cur->type) {
4018 case XML_TEXT_NODE:
4019 case XML_CDATA_SECTION_NODE:
4020 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004021 case XML_DOCUMENT_TYPE_NODE:
4022 case XML_DOCUMENT_FRAG_NODE:
4023 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004024 case XML_DTD_NODE:
4025 case XML_ELEMENT_DECL:
4026 case XML_ATTRIBUTE_DECL:
4027 case XML_ENTITY_DECL:
4028 case XML_PI_NODE:
4029 case XML_ENTITY_REF_NODE:
4030 case XML_ENTITY_NODE:
4031 case XML_NAMESPACE_DECL:
4032 case XML_XINCLUDE_START:
4033 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004034 return;
4035 case XML_ELEMENT_NODE:
4036 case XML_ATTRIBUTE_NODE:
4037 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004038 case XML_DOCUMENT_NODE:
4039#ifdef LIBXML_DOCB_ENABLED
4040 case XML_DOCB_DOCUMENT_NODE:
4041#endif
4042 case XML_HTML_DOCUMENT_NODE: {
4043 xmlDocPtr doc = (xmlDocPtr) cur;
4044
4045 if (doc->URL != NULL)
4046 xmlFree((xmlChar *) doc->URL);
4047 if (uri == NULL)
4048 doc->URL = NULL;
4049 else
4050 doc->URL = xmlStrdup(uri);
4051 return;
4052 }
Owen Taylor3473f882001-02-23 17:55:21 +00004053 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004054
4055 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4056 if (ns == NULL)
4057 return;
4058 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004059}
4060
4061/**
Owen Taylor3473f882001-02-23 17:55:21 +00004062 * xmlNodeGetBase:
4063 * @doc: the document the node pertains to
4064 * @cur: the node being checked
4065 *
4066 * Searches for the BASE URL. The code should work on both XML
4067 * and HTML document even if base mechanisms are completely different.
4068 * It returns the base as defined in RFC 2396 sections
4069 * 5.1.1. Base URI within Document Content
4070 * and
4071 * 5.1.2. Base URI from the Encapsulating Entity
4072 * However it does not return the document base (5.1.3), use
4073 * xmlDocumentGetBase() for this
4074 *
4075 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004076 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004077 */
4078xmlChar *
4079xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004080 xmlChar *oldbase = NULL;
4081 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004082
4083 if ((cur == NULL) && (doc == NULL))
4084 return(NULL);
4085 if (doc == NULL) doc = cur->doc;
4086 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4087 cur = doc->children;
4088 while ((cur != NULL) && (cur->name != NULL)) {
4089 if (cur->type != XML_ELEMENT_NODE) {
4090 cur = cur->next;
4091 continue;
4092 }
4093 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4094 cur = cur->children;
4095 continue;
4096 }
4097 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4098 cur = cur->children;
4099 continue;
4100 }
4101 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4102 return(xmlGetProp(cur, BAD_CAST "href"));
4103 }
4104 cur = cur->next;
4105 }
4106 return(NULL);
4107 }
4108 while (cur != NULL) {
4109 if (cur->type == XML_ENTITY_DECL) {
4110 xmlEntityPtr ent = (xmlEntityPtr) cur;
4111 return(xmlStrdup(ent->URI));
4112 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004113 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004114 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004115 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004116 if (oldbase != NULL) {
4117 newbase = xmlBuildURI(oldbase, base);
4118 if (newbase != NULL) {
4119 xmlFree(oldbase);
4120 xmlFree(base);
4121 oldbase = newbase;
4122 } else {
4123 xmlFree(oldbase);
4124 xmlFree(base);
4125 return(NULL);
4126 }
4127 } else {
4128 oldbase = base;
4129 }
4130 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4131 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4132 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4133 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004134 }
4135 }
Owen Taylor3473f882001-02-23 17:55:21 +00004136 cur = cur->parent;
4137 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004138 if ((doc != NULL) && (doc->URL != NULL)) {
4139 if (oldbase == NULL)
4140 return(xmlStrdup(doc->URL));
4141 newbase = xmlBuildURI(oldbase, doc->URL);
4142 xmlFree(oldbase);
4143 return(newbase);
4144 }
4145 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004146}
4147
4148/**
4149 * xmlNodeGetContent:
4150 * @cur: the node being read
4151 *
4152 * Read the value of a node, this can be either the text carried
4153 * directly by this node if it's a TEXT node or the aggregate string
4154 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004155 * Entity references are substituted.
4156 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004157 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004158 */
4159xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004160xmlNodeGetContent(xmlNodePtr cur)
4161{
4162 if (cur == NULL)
4163 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004164 switch (cur->type) {
4165 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004166 case XML_ELEMENT_NODE:{
4167 xmlNodePtr tmp = cur;
4168 xmlBufferPtr buffer;
4169 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004170
Daniel Veillard814a76d2003-01-23 18:24:20 +00004171 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004172 if (buffer == NULL)
4173 return (NULL);
4174 while (tmp != NULL) {
4175 switch (tmp->type) {
4176 case XML_CDATA_SECTION_NODE:
4177 case XML_TEXT_NODE:
4178 if (tmp->content != NULL)
4179 xmlBufferCat(buffer, tmp->content);
4180 break;
4181 case XML_ENTITY_REF_NODE:{
4182 /* recursive substitution of entity references */
4183 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00004184
Daniel Veillard7646b182002-04-20 06:41:40 +00004185 if (cont) {
4186 xmlBufferCat(buffer,
4187 (const xmlChar *) cont);
4188 xmlFree(cont);
4189 }
4190 break;
4191 }
4192 default:
4193 break;
4194 }
4195 /*
4196 * Skip to next node
4197 */
4198 if (tmp->children != NULL) {
4199 if (tmp->children->type != XML_ENTITY_DECL) {
4200 tmp = tmp->children;
4201 continue;
4202 }
4203 }
4204 if (tmp == cur)
4205 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004206
Daniel Veillard7646b182002-04-20 06:41:40 +00004207 if (tmp->next != NULL) {
4208 tmp = tmp->next;
4209 continue;
4210 }
4211
4212 do {
4213 tmp = tmp->parent;
4214 if (tmp == NULL)
4215 break;
4216 if (tmp == cur) {
4217 tmp = NULL;
4218 break;
4219 }
4220 if (tmp->next != NULL) {
4221 tmp = tmp->next;
4222 break;
4223 }
4224 } while (tmp != NULL);
4225 }
4226 ret = buffer->content;
4227 buffer->content = NULL;
4228 xmlBufferFree(buffer);
4229 return (ret);
4230 }
4231 case XML_ATTRIBUTE_NODE:{
4232 xmlAttrPtr attr = (xmlAttrPtr) cur;
4233
4234 if (attr->parent != NULL)
4235 return (xmlNodeListGetString
4236 (attr->parent->doc, attr->children, 1));
4237 else
4238 return (xmlNodeListGetString(NULL, attr->children, 1));
4239 break;
4240 }
Owen Taylor3473f882001-02-23 17:55:21 +00004241 case XML_COMMENT_NODE:
4242 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004243 if (cur->content != NULL)
4244 return (xmlStrdup(cur->content));
4245 return (NULL);
4246 case XML_ENTITY_REF_NODE:{
4247 xmlEntityPtr ent;
4248 xmlNodePtr tmp;
4249 xmlBufferPtr buffer;
4250 xmlChar *ret;
4251
4252 /* lookup entity declaration */
4253 ent = xmlGetDocEntity(cur->doc, cur->name);
4254 if (ent == NULL)
4255 return (NULL);
4256
4257 buffer = xmlBufferCreate();
4258 if (buffer == NULL)
4259 return (NULL);
4260
4261 /* an entity content can be any "well balanced chunk",
4262 * i.e. the result of the content [43] production:
4263 * http://www.w3.org/TR/REC-xml#NT-content
4264 * -> we iterate through child nodes and recursive call
4265 * xmlNodeGetContent() which handles all possible node types */
4266 tmp = ent->children;
4267 while (tmp) {
4268 xmlChar *cont = xmlNodeGetContent(tmp);
4269
4270 if (cont) {
4271 xmlBufferCat(buffer, (const xmlChar *) cont);
4272 xmlFree(cont);
4273 }
4274 tmp = tmp->next;
4275 }
4276
4277 ret = buffer->content;
4278 buffer->content = NULL;
4279 xmlBufferFree(buffer);
4280 return (ret);
4281 }
Owen Taylor3473f882001-02-23 17:55:21 +00004282 case XML_ENTITY_NODE:
4283 case XML_DOCUMENT_NODE:
4284 case XML_HTML_DOCUMENT_NODE:
4285 case XML_DOCUMENT_TYPE_NODE:
4286 case XML_NOTATION_NODE:
4287 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004288 case XML_XINCLUDE_START:
4289 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004290#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004291 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004292#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00004293 return (NULL);
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004294 case XML_NAMESPACE_DECL: {
4295 xmlChar *tmp;
4296
4297 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4298 return (tmp);
4299 }
Owen Taylor3473f882001-02-23 17:55:21 +00004300 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004301 /* TODO !!! */
4302 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004303 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004304 /* TODO !!! */
4305 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004306 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004307 /* TODO !!! */
4308 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004309 case XML_CDATA_SECTION_NODE:
4310 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004311 if (cur->content != NULL)
4312 return (xmlStrdup(cur->content));
4313 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004314 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004315 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004316}
Owen Taylor3473f882001-02-23 17:55:21 +00004317/**
4318 * xmlNodeSetContent:
4319 * @cur: the node being modified
4320 * @content: the new value of the content
4321 *
4322 * Replace the content of a node.
4323 */
4324void
4325xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4326 if (cur == NULL) {
4327#ifdef DEBUG_TREE
4328 xmlGenericError(xmlGenericErrorContext,
4329 "xmlNodeSetContent : node == NULL\n");
4330#endif
4331 return;
4332 }
4333 switch (cur->type) {
4334 case XML_DOCUMENT_FRAG_NODE:
4335 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004336 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004337 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4338 cur->children = xmlStringGetNodeList(cur->doc, content);
4339 UPDATE_LAST_CHILD_AND_PARENT(cur)
4340 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004341 case XML_TEXT_NODE:
4342 case XML_CDATA_SECTION_NODE:
4343 case XML_ENTITY_REF_NODE:
4344 case XML_ENTITY_NODE:
4345 case XML_PI_NODE:
4346 case XML_COMMENT_NODE:
4347 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004348 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004349 }
4350 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4351 cur->last = cur->children = NULL;
4352 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004353 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004354 } else
4355 cur->content = NULL;
4356 break;
4357 case XML_DOCUMENT_NODE:
4358 case XML_HTML_DOCUMENT_NODE:
4359 case XML_DOCUMENT_TYPE_NODE:
4360 case XML_XINCLUDE_START:
4361 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004362#ifdef LIBXML_DOCB_ENABLED
4363 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004364#endif
4365 break;
4366 case XML_NOTATION_NODE:
4367 break;
4368 case XML_DTD_NODE:
4369 break;
4370 case XML_NAMESPACE_DECL:
4371 break;
4372 case XML_ELEMENT_DECL:
4373 /* TODO !!! */
4374 break;
4375 case XML_ATTRIBUTE_DECL:
4376 /* TODO !!! */
4377 break;
4378 case XML_ENTITY_DECL:
4379 /* TODO !!! */
4380 break;
4381 }
4382}
4383
4384/**
4385 * xmlNodeSetContentLen:
4386 * @cur: the node being modified
4387 * @content: the new value of the content
4388 * @len: the size of @content
4389 *
4390 * Replace the content of a node.
4391 */
4392void
4393xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4394 if (cur == NULL) {
4395#ifdef DEBUG_TREE
4396 xmlGenericError(xmlGenericErrorContext,
4397 "xmlNodeSetContentLen : node == NULL\n");
4398#endif
4399 return;
4400 }
4401 switch (cur->type) {
4402 case XML_DOCUMENT_FRAG_NODE:
4403 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004404 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004405 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4406 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4407 UPDATE_LAST_CHILD_AND_PARENT(cur)
4408 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004409 case XML_TEXT_NODE:
4410 case XML_CDATA_SECTION_NODE:
4411 case XML_ENTITY_REF_NODE:
4412 case XML_ENTITY_NODE:
4413 case XML_PI_NODE:
4414 case XML_COMMENT_NODE:
4415 case XML_NOTATION_NODE:
4416 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004417 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004418 }
4419 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4420 cur->children = cur->last = NULL;
4421 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004422 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004423 } else
4424 cur->content = NULL;
4425 break;
4426 case XML_DOCUMENT_NODE:
4427 case XML_DTD_NODE:
4428 case XML_HTML_DOCUMENT_NODE:
4429 case XML_DOCUMENT_TYPE_NODE:
4430 case XML_NAMESPACE_DECL:
4431 case XML_XINCLUDE_START:
4432 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004433#ifdef LIBXML_DOCB_ENABLED
4434 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004435#endif
4436 break;
4437 case XML_ELEMENT_DECL:
4438 /* TODO !!! */
4439 break;
4440 case XML_ATTRIBUTE_DECL:
4441 /* TODO !!! */
4442 break;
4443 case XML_ENTITY_DECL:
4444 /* TODO !!! */
4445 break;
4446 }
4447}
4448
4449/**
4450 * xmlNodeAddContentLen:
4451 * @cur: the node being modified
4452 * @content: extra content
4453 * @len: the size of @content
4454 *
4455 * Append the extra substring to the node content.
4456 */
4457void
4458xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4459 if (cur == NULL) {
4460#ifdef DEBUG_TREE
4461 xmlGenericError(xmlGenericErrorContext,
4462 "xmlNodeAddContentLen : node == NULL\n");
4463#endif
4464 return;
4465 }
4466 if (len <= 0) return;
4467 switch (cur->type) {
4468 case XML_DOCUMENT_FRAG_NODE:
4469 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004470 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004471
Daniel Veillard7db37732001-07-12 01:20:08 +00004472 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004473 newNode = xmlNewTextLen(content, len);
4474 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004475 tmp = xmlAddChild(cur, newNode);
4476 if (tmp != newNode)
4477 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004478 if ((last != NULL) && (last->next == newNode)) {
4479 xmlTextMerge(last, newNode);
4480 }
4481 }
4482 break;
4483 }
4484 case XML_ATTRIBUTE_NODE:
4485 break;
4486 case XML_TEXT_NODE:
4487 case XML_CDATA_SECTION_NODE:
4488 case XML_ENTITY_REF_NODE:
4489 case XML_ENTITY_NODE:
4490 case XML_PI_NODE:
4491 case XML_COMMENT_NODE:
4492 case XML_NOTATION_NODE:
4493 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004494 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004495 }
4496 case XML_DOCUMENT_NODE:
4497 case XML_DTD_NODE:
4498 case XML_HTML_DOCUMENT_NODE:
4499 case XML_DOCUMENT_TYPE_NODE:
4500 case XML_NAMESPACE_DECL:
4501 case XML_XINCLUDE_START:
4502 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004503#ifdef LIBXML_DOCB_ENABLED
4504 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004505#endif
4506 break;
4507 case XML_ELEMENT_DECL:
4508 case XML_ATTRIBUTE_DECL:
4509 case XML_ENTITY_DECL:
4510 break;
4511 }
4512}
4513
4514/**
4515 * xmlNodeAddContent:
4516 * @cur: the node being modified
4517 * @content: extra content
4518 *
4519 * Append the extra substring to the node content.
4520 */
4521void
4522xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4523 int len;
4524
4525 if (cur == NULL) {
4526#ifdef DEBUG_TREE
4527 xmlGenericError(xmlGenericErrorContext,
4528 "xmlNodeAddContent : node == NULL\n");
4529#endif
4530 return;
4531 }
4532 if (content == NULL) return;
4533 len = xmlStrlen(content);
4534 xmlNodeAddContentLen(cur, content, len);
4535}
4536
4537/**
4538 * xmlTextMerge:
4539 * @first: the first text node
4540 * @second: the second text node being merged
4541 *
4542 * Merge two text nodes into one
4543 * Returns the first text node augmented
4544 */
4545xmlNodePtr
4546xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4547 if (first == NULL) return(second);
4548 if (second == NULL) return(first);
4549 if (first->type != XML_TEXT_NODE) return(first);
4550 if (second->type != XML_TEXT_NODE) return(first);
4551 if (second->name != first->name)
4552 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004553 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004554 xmlUnlinkNode(second);
4555 xmlFreeNode(second);
4556 return(first);
4557}
4558
4559/**
4560 * xmlGetNsList:
4561 * @doc: the document
4562 * @node: the current node
4563 *
4564 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004565 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004566 * that need to be freed by the caller or NULL if no
4567 * namespace if defined
4568 */
4569xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004570xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4571{
Owen Taylor3473f882001-02-23 17:55:21 +00004572 xmlNsPtr cur;
4573 xmlNsPtr *ret = NULL;
4574 int nbns = 0;
4575 int maxns = 10;
4576 int i;
4577
4578 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004579 if (node->type == XML_ELEMENT_NODE) {
4580 cur = node->nsDef;
4581 while (cur != NULL) {
4582 if (ret == NULL) {
4583 ret =
4584 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4585 sizeof(xmlNsPtr));
4586 if (ret == NULL) {
4587 xmlGenericError(xmlGenericErrorContext,
4588 "xmlGetNsList : out of memory!\n");
4589 return (NULL);
4590 }
4591 ret[nbns] = NULL;
4592 }
4593 for (i = 0; i < nbns; i++) {
4594 if ((cur->prefix == ret[i]->prefix) ||
4595 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4596 break;
4597 }
4598 if (i >= nbns) {
4599 if (nbns >= maxns) {
4600 maxns *= 2;
4601 ret = (xmlNsPtr *) xmlRealloc(ret,
4602 (maxns +
4603 1) *
4604 sizeof(xmlNsPtr));
4605 if (ret == NULL) {
4606 xmlGenericError(xmlGenericErrorContext,
4607 "xmlGetNsList : realloc failed!\n");
4608 return (NULL);
4609 }
4610 }
4611 ret[nbns++] = cur;
4612 ret[nbns] = NULL;
4613 }
Owen Taylor3473f882001-02-23 17:55:21 +00004614
Daniel Veillard77044732001-06-29 21:31:07 +00004615 cur = cur->next;
4616 }
4617 }
4618 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004619 }
Daniel Veillard77044732001-06-29 21:31:07 +00004620 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004621}
4622
4623/**
4624 * xmlSearchNs:
4625 * @doc: the document
4626 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004627 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004628 *
4629 * Search a Ns registered under a given name space for a document.
4630 * recurse on the parents until it finds the defined namespace
4631 * or return NULL otherwise.
4632 * @nameSpace can be NULL, this is a search for the default namespace.
4633 * We don't allow to cross entities boundaries. If you don't declare
4634 * the namespace within those you will be in troubles !!! A warning
4635 * is generated to cover this case.
4636 *
4637 * Returns the namespace pointer or NULL.
4638 */
4639xmlNsPtr
4640xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4641 xmlNsPtr cur;
4642
4643 if (node == NULL) return(NULL);
4644 if ((nameSpace != NULL) &&
4645 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00004646 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4647 /*
4648 * The XML-1.0 namespace is normally held on the root
4649 * element. In this case exceptionally create it on the
4650 * node element.
4651 */
4652 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4653 if (cur == NULL) {
4654 xmlGenericError(xmlGenericErrorContext,
4655 "xmlSearchNs : malloc failed\n");
4656 return(NULL);
4657 }
4658 memset(cur, 0, sizeof(xmlNs));
4659 cur->type = XML_LOCAL_NAMESPACE;
4660 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4661 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4662 cur->next = node->nsDef;
4663 node->nsDef = cur;
4664 return(cur);
4665 }
Owen Taylor3473f882001-02-23 17:55:21 +00004666 if (doc->oldNs == NULL) {
4667 /*
4668 * Allocate a new Namespace and fill the fields.
4669 */
4670 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4671 if (doc->oldNs == NULL) {
4672 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004673 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004674 return(NULL);
4675 }
4676 memset(doc->oldNs, 0, sizeof(xmlNs));
4677 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4678
4679 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4680 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4681 }
4682 return(doc->oldNs);
4683 }
4684 while (node != NULL) {
4685 if ((node->type == XML_ENTITY_REF_NODE) ||
4686 (node->type == XML_ENTITY_NODE) ||
4687 (node->type == XML_ENTITY_DECL))
4688 return(NULL);
4689 if (node->type == XML_ELEMENT_NODE) {
4690 cur = node->nsDef;
4691 while (cur != NULL) {
4692 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4693 (cur->href != NULL))
4694 return(cur);
4695 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4696 (cur->href != NULL) &&
4697 (xmlStrEqual(cur->prefix, nameSpace)))
4698 return(cur);
4699 cur = cur->next;
4700 }
4701 }
4702 node = node->parent;
4703 }
4704 return(NULL);
4705}
4706
4707/**
4708 * xmlSearchNsByHref:
4709 * @doc: the document
4710 * @node: the current node
4711 * @href: the namespace value
4712 *
4713 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4714 * the defined namespace or return NULL otherwise.
4715 * Returns the namespace pointer or NULL.
4716 */
4717xmlNsPtr
4718xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4719 xmlNsPtr cur;
4720 xmlNodePtr orig = node;
4721
4722 if ((node == NULL) || (href == NULL)) return(NULL);
4723 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004724 /*
4725 * Only the document can hold the XML spec namespace.
4726 */
Daniel Veillardc1a0da32002-08-14 08:32:18 +00004727 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4728 /*
4729 * The XML-1.0 namespace is normally held on the root
4730 * element. In this case exceptionally create it on the
4731 * node element.
4732 */
4733 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4734 if (cur == NULL) {
4735 xmlGenericError(xmlGenericErrorContext,
4736 "xmlSearchNs : malloc failed\n");
4737 return(NULL);
4738 }
4739 memset(cur, 0, sizeof(xmlNs));
4740 cur->type = XML_LOCAL_NAMESPACE;
4741 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4742 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4743 cur->next = node->nsDef;
4744 node->nsDef = cur;
4745 return(cur);
4746 }
Owen Taylor3473f882001-02-23 17:55:21 +00004747 if (doc->oldNs == NULL) {
4748 /*
4749 * Allocate a new Namespace and fill the fields.
4750 */
4751 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4752 if (doc->oldNs == NULL) {
4753 xmlGenericError(xmlGenericErrorContext,
4754 "xmlSearchNsByHref : malloc failed\n");
4755 return(NULL);
4756 }
4757 memset(doc->oldNs, 0, sizeof(xmlNs));
4758 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4759
4760 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4761 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4762 }
4763 return(doc->oldNs);
4764 }
4765 while (node != NULL) {
4766 cur = node->nsDef;
4767 while (cur != NULL) {
4768 if ((cur->href != NULL) && (href != NULL) &&
4769 (xmlStrEqual(cur->href, href))) {
4770 /*
4771 * Check that the prefix is not shadowed between orig and node
4772 */
4773 xmlNodePtr check = orig;
4774 xmlNsPtr tst;
4775
4776 while (check != node) {
4777 tst = check->nsDef;
4778 while (tst != NULL) {
4779 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4780 goto shadowed;
4781 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4782 (xmlStrEqual(tst->prefix, cur->prefix)))
4783 goto shadowed;
4784 tst = tst->next;
4785 }
4786 check = check->parent;
4787 }
4788 return(cur);
4789 }
4790shadowed:
4791 cur = cur->next;
4792 }
4793 node = node->parent;
4794 }
4795 return(NULL);
4796}
4797
4798/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004799 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00004800 * @doc: the document
4801 * @tree: a node expected to hold the new namespace
4802 * @ns: the original namespace
4803 *
4804 * This function tries to locate a namespace definition in a tree
4805 * ancestors, or create a new namespace definition node similar to
4806 * @ns trying to reuse the same prefix. However if the given prefix is
4807 * null (default namespace) or reused within the subtree defined by
4808 * @tree or on one of its ancestors then a new prefix is generated.
4809 * Returns the (new) namespace definition or NULL in case of error
4810 */
4811xmlNsPtr
4812xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4813 xmlNsPtr def;
4814 xmlChar prefix[50];
4815 int counter = 1;
4816
4817 if (tree == NULL) {
4818#ifdef DEBUG_TREE
4819 xmlGenericError(xmlGenericErrorContext,
4820 "xmlNewReconciliedNs : tree == NULL\n");
4821#endif
4822 return(NULL);
4823 }
4824 if (ns == NULL) {
4825#ifdef DEBUG_TREE
4826 xmlGenericError(xmlGenericErrorContext,
4827 "xmlNewReconciliedNs : ns == NULL\n");
4828#endif
4829 return(NULL);
4830 }
4831 /*
4832 * Search an existing namespace definition inherited.
4833 */
4834 def = xmlSearchNsByHref(doc, tree, ns->href);
4835 if (def != NULL)
4836 return(def);
4837
4838 /*
4839 * Find a close prefix which is not already in use.
4840 * Let's strip namespace prefixes longer than 20 chars !
4841 */
Daniel Veillardf742d342002-03-07 00:05:35 +00004842 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004843 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00004844 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004845 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00004846
Owen Taylor3473f882001-02-23 17:55:21 +00004847 def = xmlSearchNs(doc, tree, prefix);
4848 while (def != NULL) {
4849 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00004850 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004851 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00004852 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004853 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00004854 def = xmlSearchNs(doc, tree, prefix);
4855 }
4856
4857 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004858 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004859 */
4860 def = xmlNewNs(tree, ns->href, prefix);
4861 return(def);
4862}
4863
4864/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004865 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00004866 * @doc: the document
4867 * @tree: a node defining the subtree to reconciliate
4868 *
4869 * This function checks that all the namespaces declared within the given
4870 * tree are properly declared. This is needed for example after Copy or Cut
4871 * and then paste operations. The subtree may still hold pointers to
4872 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004873 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004874 * the new environment. If not possible the new namespaces are redeclared
4875 * on @tree at the top of the given subtree.
4876 * Returns the number of namespace declarations created or -1 in case of error.
4877 */
4878int
4879xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4880 xmlNsPtr *oldNs = NULL;
4881 xmlNsPtr *newNs = NULL;
4882 int sizeCache = 0;
4883 int nbCache = 0;
4884
4885 xmlNsPtr n;
4886 xmlNodePtr node = tree;
4887 xmlAttrPtr attr;
4888 int ret = 0, i;
4889
4890 while (node != NULL) {
4891 /*
4892 * Reconciliate the node namespace
4893 */
4894 if (node->ns != NULL) {
4895 /*
4896 * initialize the cache if needed
4897 */
4898 if (sizeCache == 0) {
4899 sizeCache = 10;
4900 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4901 sizeof(xmlNsPtr));
4902 if (oldNs == NULL) {
4903 xmlGenericError(xmlGenericErrorContext,
4904 "xmlReconciliateNs : memory pbm\n");
4905 return(-1);
4906 }
4907 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4908 sizeof(xmlNsPtr));
4909 if (newNs == NULL) {
4910 xmlGenericError(xmlGenericErrorContext,
4911 "xmlReconciliateNs : memory pbm\n");
4912 xmlFree(oldNs);
4913 return(-1);
4914 }
4915 }
4916 for (i = 0;i < nbCache;i++) {
4917 if (oldNs[i] == node->ns) {
4918 node->ns = newNs[i];
4919 break;
4920 }
4921 }
4922 if (i == nbCache) {
4923 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004924 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004925 */
4926 n = xmlNewReconciliedNs(doc, tree, node->ns);
4927 if (n != NULL) { /* :-( what if else ??? */
4928 /*
4929 * check if we need to grow the cache buffers.
4930 */
4931 if (sizeCache <= nbCache) {
4932 sizeCache *= 2;
4933 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4934 sizeof(xmlNsPtr));
4935 if (oldNs == NULL) {
4936 xmlGenericError(xmlGenericErrorContext,
4937 "xmlReconciliateNs : memory pbm\n");
4938 xmlFree(newNs);
4939 return(-1);
4940 }
4941 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4942 sizeof(xmlNsPtr));
4943 if (newNs == NULL) {
4944 xmlGenericError(xmlGenericErrorContext,
4945 "xmlReconciliateNs : memory pbm\n");
4946 xmlFree(oldNs);
4947 return(-1);
4948 }
4949 }
4950 newNs[nbCache] = n;
4951 oldNs[nbCache++] = node->ns;
4952 node->ns = n;
4953 }
4954 }
4955 }
4956 /*
4957 * now check for namespace hold by attributes on the node.
4958 */
4959 attr = node->properties;
4960 while (attr != NULL) {
4961 if (attr->ns != NULL) {
4962 /*
4963 * initialize the cache if needed
4964 */
4965 if (sizeCache == 0) {
4966 sizeCache = 10;
4967 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4968 sizeof(xmlNsPtr));
4969 if (oldNs == NULL) {
4970 xmlGenericError(xmlGenericErrorContext,
4971 "xmlReconciliateNs : memory pbm\n");
4972 return(-1);
4973 }
4974 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4975 sizeof(xmlNsPtr));
4976 if (newNs == NULL) {
4977 xmlGenericError(xmlGenericErrorContext,
4978 "xmlReconciliateNs : memory pbm\n");
4979 xmlFree(oldNs);
4980 return(-1);
4981 }
4982 }
4983 for (i = 0;i < nbCache;i++) {
4984 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00004985 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00004986 break;
4987 }
4988 }
4989 if (i == nbCache) {
4990 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004991 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004992 */
4993 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4994 if (n != NULL) { /* :-( what if else ??? */
4995 /*
4996 * check if we need to grow the cache buffers.
4997 */
4998 if (sizeCache <= nbCache) {
4999 sizeCache *= 2;
5000 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5001 sizeof(xmlNsPtr));
5002 if (oldNs == NULL) {
5003 xmlGenericError(xmlGenericErrorContext,
5004 "xmlReconciliateNs : memory pbm\n");
5005 xmlFree(newNs);
5006 return(-1);
5007 }
5008 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5009 sizeof(xmlNsPtr));
5010 if (newNs == NULL) {
5011 xmlGenericError(xmlGenericErrorContext,
5012 "xmlReconciliateNs : memory pbm\n");
5013 xmlFree(oldNs);
5014 return(-1);
5015 }
5016 }
5017 newNs[nbCache] = n;
5018 oldNs[nbCache++] = attr->ns;
5019 attr->ns = n;
5020 }
5021 }
5022 }
5023 attr = attr->next;
5024 }
5025
5026 /*
5027 * Browse the full subtree, deep first
5028 */
5029 if (node->children != NULL) {
5030 /* deep first */
5031 node = node->children;
5032 } else if ((node != tree) && (node->next != NULL)) {
5033 /* then siblings */
5034 node = node->next;
5035 } else if (node != tree) {
5036 /* go up to parents->next if needed */
5037 while (node != tree) {
5038 if (node->parent != NULL)
5039 node = node->parent;
5040 if ((node != tree) && (node->next != NULL)) {
5041 node = node->next;
5042 break;
5043 }
5044 if (node->parent == NULL) {
5045 node = NULL;
5046 break;
5047 }
5048 }
5049 /* exit condition */
5050 if (node == tree)
5051 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005052 } else
5053 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005054 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005055 if (oldNs != NULL)
5056 xmlFree(oldNs);
5057 if (newNs != NULL)
5058 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005059 return(ret);
5060}
5061
5062/**
5063 * xmlHasProp:
5064 * @node: the node
5065 * @name: the attribute name
5066 *
5067 * Search an attribute associated to a node
5068 * This function also looks in DTD attribute declaration for #FIXED or
5069 * default declaration values unless DTD use has been turned off.
5070 *
5071 * Returns the attribute or the attribute declaration or NULL if
5072 * neither was found.
5073 */
5074xmlAttrPtr
5075xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5076 xmlAttrPtr prop;
5077 xmlDocPtr doc;
5078
5079 if ((node == NULL) || (name == NULL)) return(NULL);
5080 /*
5081 * Check on the properties attached to the node
5082 */
5083 prop = node->properties;
5084 while (prop != NULL) {
5085 if (xmlStrEqual(prop->name, name)) {
5086 return(prop);
5087 }
5088 prop = prop->next;
5089 }
5090 if (!xmlCheckDTD) return(NULL);
5091
5092 /*
5093 * Check if there is a default declaration in the internal
5094 * or external subsets
5095 */
5096 doc = node->doc;
5097 if (doc != NULL) {
5098 xmlAttributePtr attrDecl;
5099 if (doc->intSubset != NULL) {
5100 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5101 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5102 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5103 if (attrDecl != NULL)
5104 return((xmlAttrPtr) attrDecl);
5105 }
5106 }
5107 return(NULL);
5108}
5109
5110/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005111 * xmlHasNsProp:
5112 * @node: the node
5113 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005114 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005115 *
5116 * Search for an attribute associated to a node
5117 * This attribute has to be anchored in the namespace specified.
5118 * This does the entity substitution.
5119 * This function looks in DTD attribute declaration for #FIXED or
5120 * default declaration values unless DTD use has been turned off.
5121 *
5122 * Returns the attribute or the attribute declaration or NULL
5123 * if neither was found.
5124 */
5125xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005126xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005127 xmlAttrPtr prop;
5128 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005129
5130 if (node == NULL)
5131 return(NULL);
5132
5133 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005134 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005135 return(xmlHasProp(node, name));
5136 while (prop != NULL) {
5137 /*
5138 * One need to have
5139 * - same attribute names
5140 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005141 */
5142 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005143 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5144 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005145 }
5146 prop = prop->next;
5147 }
5148 if (!xmlCheckDTD) return(NULL);
5149
5150 /*
5151 * Check if there is a default declaration in the internal
5152 * or external subsets
5153 */
5154 doc = node->doc;
5155 if (doc != NULL) {
5156 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005157 xmlAttributePtr attrDecl = NULL;
5158 xmlNsPtr *nsList, *cur;
5159 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005160
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005161 nsList = xmlGetNsList(node->doc, node);
5162 if (nsList == NULL)
5163 return(NULL);
5164 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5165 ename = xmlStrdup(node->ns->prefix);
5166 ename = xmlStrcat(ename, BAD_CAST ":");
5167 ename = xmlStrcat(ename, node->name);
5168 } else {
5169 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005170 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005171 if (ename == NULL) {
5172 xmlFree(nsList);
5173 return(NULL);
5174 }
5175
5176 cur = nsList;
5177 while (*cur != NULL) {
5178 if (xmlStrEqual((*cur)->href, nameSpace)) {
5179 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5180 name, (*cur)->prefix);
5181 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5182 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5183 name, (*cur)->prefix);
5184 }
5185 cur++;
5186 }
5187 xmlFree(nsList);
5188 xmlFree(ename);
5189 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005190 }
5191 }
5192 return(NULL);
5193}
5194
5195/**
Owen Taylor3473f882001-02-23 17:55:21 +00005196 * xmlGetProp:
5197 * @node: the node
5198 * @name: the attribute name
5199 *
5200 * Search and get the value of an attribute associated to a node
5201 * This does the entity substitution.
5202 * This function looks in DTD attribute declaration for #FIXED or
5203 * default declaration values unless DTD use has been turned off.
Daniel Veillard71531f32003-02-05 13:19:53 +00005204 * NOTE: this function acts independantly of namespaces associated
5205 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5206 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005207 *
5208 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005209 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005210 */
5211xmlChar *
5212xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5213 xmlAttrPtr prop;
5214 xmlDocPtr doc;
5215
5216 if ((node == NULL) || (name == NULL)) return(NULL);
5217 /*
5218 * Check on the properties attached to the node
5219 */
5220 prop = node->properties;
5221 while (prop != NULL) {
5222 if (xmlStrEqual(prop->name, name)) {
5223 xmlChar *ret;
5224
5225 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5226 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5227 return(ret);
5228 }
5229 prop = prop->next;
5230 }
5231 if (!xmlCheckDTD) return(NULL);
5232
5233 /*
5234 * Check if there is a default declaration in the internal
5235 * or external subsets
5236 */
5237 doc = node->doc;
5238 if (doc != NULL) {
5239 xmlAttributePtr attrDecl;
5240 if (doc->intSubset != NULL) {
5241 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5242 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5243 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5244 if (attrDecl != NULL)
5245 return(xmlStrdup(attrDecl->defaultValue));
5246 }
5247 }
5248 return(NULL);
5249}
5250
5251/**
Daniel Veillard71531f32003-02-05 13:19:53 +00005252 * xmlGetNoNsProp:
5253 * @node: the node
5254 * @name: the attribute name
5255 *
5256 * Search and get the value of an attribute associated to a node
5257 * This does the entity substitution.
5258 * This function looks in DTD attribute declaration for #FIXED or
5259 * default declaration values unless DTD use has been turned off.
5260 * This function is similar to xmlGetProp except it will accept only
5261 * an attribute in no namespace.
5262 *
5263 * Returns the attribute value or NULL if not found.
5264 * It's up to the caller to free the memory with xmlFree().
5265 */
5266xmlChar *
5267xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
5268 xmlAttrPtr prop;
5269 xmlDocPtr doc;
5270
5271 if ((node == NULL) || (name == NULL)) return(NULL);
5272 /*
5273 * Check on the properties attached to the node
5274 */
5275 prop = node->properties;
5276 while (prop != NULL) {
5277 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
5278 xmlChar *ret;
5279
5280 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5281 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5282 return(ret);
5283 }
5284 prop = prop->next;
5285 }
5286 if (!xmlCheckDTD) return(NULL);
5287
5288 /*
5289 * Check if there is a default declaration in the internal
5290 * or external subsets
5291 */
5292 doc = node->doc;
5293 if (doc != NULL) {
5294 xmlAttributePtr attrDecl;
5295 if (doc->intSubset != NULL) {
5296 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5297 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5298 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5299 if (attrDecl != NULL)
5300 return(xmlStrdup(attrDecl->defaultValue));
5301 }
5302 }
5303 return(NULL);
5304}
5305
5306/**
Owen Taylor3473f882001-02-23 17:55:21 +00005307 * xmlGetNsProp:
5308 * @node: the node
5309 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005310 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005311 *
5312 * Search and get the value of an attribute associated to a node
5313 * This attribute has to be anchored in the namespace specified.
5314 * This does the entity substitution.
5315 * This function looks in DTD attribute declaration for #FIXED or
5316 * default declaration values unless DTD use has been turned off.
5317 *
5318 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005319 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005320 */
5321xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005322xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005323 xmlAttrPtr prop;
5324 xmlDocPtr doc;
5325 xmlNsPtr ns;
5326
5327 if (node == NULL)
5328 return(NULL);
5329
5330 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005331 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00005332 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00005333 while (prop != NULL) {
5334 /*
5335 * One need to have
5336 * - same attribute names
5337 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005338 */
5339 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005340 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005341 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005342 xmlChar *ret;
5343
5344 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5345 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5346 return(ret);
5347 }
5348 prop = prop->next;
5349 }
5350 if (!xmlCheckDTD) return(NULL);
5351
5352 /*
5353 * Check if there is a default declaration in the internal
5354 * or external subsets
5355 */
5356 doc = node->doc;
5357 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005358 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005359 xmlAttributePtr attrDecl;
5360
Owen Taylor3473f882001-02-23 17:55:21 +00005361 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5362 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5363 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5364
5365 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5366 /*
5367 * The DTD declaration only allows a prefix search
5368 */
5369 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005370 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005371 return(xmlStrdup(attrDecl->defaultValue));
5372 }
5373 }
5374 }
5375 return(NULL);
5376}
5377
5378/**
5379 * xmlSetProp:
5380 * @node: the node
5381 * @name: the attribute name
5382 * @value: the attribute value
5383 *
5384 * Set (or reset) an attribute carried by a node.
5385 * Returns the attribute pointer.
5386 */
5387xmlAttrPtr
5388xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005389 xmlAttrPtr prop;
5390 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005391
5392 if ((node == NULL) || (name == NULL))
5393 return(NULL);
5394 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005395 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005396 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005397 if ((xmlStrEqual(prop->name, name)) &&
5398 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005399 xmlNodePtr oldprop = prop->children;
5400
Owen Taylor3473f882001-02-23 17:55:21 +00005401 prop->children = NULL;
5402 prop->last = NULL;
5403 if (value != NULL) {
5404 xmlChar *buffer;
5405 xmlNodePtr tmp;
5406
5407 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5408 prop->children = xmlStringGetNodeList(node->doc, buffer);
5409 prop->last = NULL;
5410 prop->doc = doc;
5411 tmp = prop->children;
5412 while (tmp != NULL) {
5413 tmp->parent = (xmlNodePtr) prop;
5414 tmp->doc = doc;
5415 if (tmp->next == NULL)
5416 prop->last = tmp;
5417 tmp = tmp->next;
5418 }
5419 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005420 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005421 if (oldprop != NULL)
5422 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005423 return(prop);
5424 }
5425 prop = prop->next;
5426 }
5427 prop = xmlNewProp(node, name, value);
5428 return(prop);
5429}
5430
5431/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005432 * xmlUnsetProp:
5433 * @node: the node
5434 * @name: the attribute name
5435 *
5436 * Remove an attribute carried by a node.
5437 * Returns 0 if successful, -1 if not found
5438 */
5439int
5440xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard814a76d2003-01-23 18:24:20 +00005441 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard75bea542001-05-11 17:41:21 +00005442
5443 if ((node == NULL) || (name == NULL))
5444 return(-1);
Daniel Veillard814a76d2003-01-23 18:24:20 +00005445 prop = node->properties;
Daniel Veillard75bea542001-05-11 17:41:21 +00005446 while (prop != NULL) {
5447 if ((xmlStrEqual(prop->name, name)) &&
5448 (prop->ns == NULL)) {
5449 if (prev == NULL)
5450 node->properties = prop->next;
5451 else
5452 prev->next = prop->next;
5453 xmlFreeProp(prop);
5454 return(0);
5455 }
5456 prev = prop;
5457 prop = prop->next;
5458 }
5459 return(-1);
5460}
5461
5462/**
Owen Taylor3473f882001-02-23 17:55:21 +00005463 * xmlSetNsProp:
5464 * @node: the node
5465 * @ns: the namespace definition
5466 * @name: the attribute name
5467 * @value: the attribute value
5468 *
5469 * Set (or reset) an attribute carried by a node.
5470 * The ns structure must be in scope, this is not checked.
5471 *
5472 * Returns the attribute pointer.
5473 */
5474xmlAttrPtr
5475xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5476 const xmlChar *value) {
5477 xmlAttrPtr prop;
5478
5479 if ((node == NULL) || (name == NULL))
5480 return(NULL);
5481
5482 if (ns == NULL)
5483 return(xmlSetProp(node, name, value));
5484 if (ns->href == NULL)
5485 return(NULL);
5486 prop = node->properties;
5487
5488 while (prop != NULL) {
5489 /*
5490 * One need to have
5491 * - same attribute names
5492 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005493 */
5494 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00005495 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005496 if (prop->children != NULL)
5497 xmlFreeNodeList(prop->children);
5498 prop->children = NULL;
5499 prop->last = NULL;
5500 prop->ns = ns;
5501 if (value != NULL) {
5502 xmlChar *buffer;
5503 xmlNodePtr tmp;
5504
5505 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5506 prop->children = xmlStringGetNodeList(node->doc, buffer);
5507 prop->last = NULL;
5508 tmp = prop->children;
5509 while (tmp != NULL) {
5510 tmp->parent = (xmlNodePtr) prop;
5511 if (tmp->next == NULL)
5512 prop->last = tmp;
5513 tmp = tmp->next;
5514 }
5515 xmlFree(buffer);
5516 }
5517 return(prop);
5518 }
5519 prop = prop->next;
5520 }
5521 prop = xmlNewNsProp(node, ns, name, value);
5522 return(prop);
5523}
5524
5525/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005526 * xmlUnsetNsProp:
5527 * @node: the node
5528 * @ns: the namespace definition
5529 * @name: the attribute name
5530 *
5531 * Remove an attribute carried by a node.
5532 * Returns 0 if successful, -1 if not found
5533 */
5534int
5535xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5536 xmlAttrPtr prop = node->properties, prev = NULL;;
5537
5538 if ((node == NULL) || (name == NULL))
5539 return(-1);
5540 if (ns == NULL)
5541 return(xmlUnsetProp(node, name));
5542 if (ns->href == NULL)
5543 return(-1);
5544 while (prop != NULL) {
5545 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00005546 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005547 if (prev == NULL)
5548 node->properties = prop->next;
5549 else
5550 prev->next = prop->next;
5551 xmlFreeProp(prop);
5552 return(0);
5553 }
5554 prev = prop;
5555 prop = prop->next;
5556 }
5557 return(-1);
5558}
5559
5560/**
Owen Taylor3473f882001-02-23 17:55:21 +00005561 * xmlNodeIsText:
5562 * @node: the node
5563 *
5564 * Is this node a Text node ?
5565 * Returns 1 yes, 0 no
5566 */
5567int
5568xmlNodeIsText(xmlNodePtr node) {
5569 if (node == NULL) return(0);
5570
5571 if (node->type == XML_TEXT_NODE) return(1);
5572 return(0);
5573}
5574
5575/**
5576 * xmlIsBlankNode:
5577 * @node: the node
5578 *
5579 * Checks whether this node is an empty or whitespace only
5580 * (and possibly ignorable) text-node.
5581 *
5582 * Returns 1 yes, 0 no
5583 */
5584int
5585xmlIsBlankNode(xmlNodePtr node) {
5586 const xmlChar *cur;
5587 if (node == NULL) return(0);
5588
Daniel Veillard7db37732001-07-12 01:20:08 +00005589 if ((node->type != XML_TEXT_NODE) &&
5590 (node->type != XML_CDATA_SECTION_NODE))
5591 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005592 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005593 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005594 while (*cur != 0) {
5595 if (!IS_BLANK(*cur)) return(0);
5596 cur++;
5597 }
5598
5599 return(1);
5600}
5601
5602/**
5603 * xmlTextConcat:
5604 * @node: the node
5605 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005606 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005607 *
5608 * Concat the given string at the end of the existing node content
5609 */
5610
5611void
5612xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5613 if (node == NULL) return;
5614
5615 if ((node->type != XML_TEXT_NODE) &&
5616 (node->type != XML_CDATA_SECTION_NODE)) {
5617#ifdef DEBUG_TREE
5618 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005619 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005620#endif
5621 return;
5622 }
Owen Taylor3473f882001-02-23 17:55:21 +00005623 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005624}
5625
5626/************************************************************************
5627 * *
5628 * Output : to a FILE or in memory *
5629 * *
5630 ************************************************************************/
5631
Owen Taylor3473f882001-02-23 17:55:21 +00005632/**
5633 * xmlBufferCreate:
5634 *
5635 * routine to create an XML buffer.
5636 * returns the new structure.
5637 */
5638xmlBufferPtr
5639xmlBufferCreate(void) {
5640 xmlBufferPtr ret;
5641
5642 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5643 if (ret == NULL) {
5644 xmlGenericError(xmlGenericErrorContext,
5645 "xmlBufferCreate : out of memory!\n");
5646 return(NULL);
5647 }
5648 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005649 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005650 ret->alloc = xmlBufferAllocScheme;
5651 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5652 if (ret->content == NULL) {
5653 xmlGenericError(xmlGenericErrorContext,
5654 "xmlBufferCreate : out of memory!\n");
5655 xmlFree(ret);
5656 return(NULL);
5657 }
5658 ret->content[0] = 0;
5659 return(ret);
5660}
5661
5662/**
5663 * xmlBufferCreateSize:
5664 * @size: initial size of buffer
5665 *
5666 * routine to create an XML buffer.
5667 * returns the new structure.
5668 */
5669xmlBufferPtr
5670xmlBufferCreateSize(size_t size) {
5671 xmlBufferPtr ret;
5672
5673 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5674 if (ret == NULL) {
5675 xmlGenericError(xmlGenericErrorContext,
5676 "xmlBufferCreate : out of memory!\n");
5677 return(NULL);
5678 }
5679 ret->use = 0;
5680 ret->alloc = xmlBufferAllocScheme;
5681 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5682 if (ret->size){
5683 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5684 if (ret->content == NULL) {
5685 xmlGenericError(xmlGenericErrorContext,
5686 "xmlBufferCreate : out of memory!\n");
5687 xmlFree(ret);
5688 return(NULL);
5689 }
5690 ret->content[0] = 0;
5691 } else
5692 ret->content = NULL;
5693 return(ret);
5694}
5695
5696/**
5697 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005698 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00005699 * @scheme: allocation scheme to use
5700 *
5701 * Sets the allocation scheme for this buffer
5702 */
5703void
5704xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5705 xmlBufferAllocationScheme scheme) {
5706 if (buf == NULL) {
5707#ifdef DEBUG_BUFFER
5708 xmlGenericError(xmlGenericErrorContext,
5709 "xmlBufferSetAllocationScheme: buf == NULL\n");
5710#endif
5711 return;
5712 }
5713
5714 buf->alloc = scheme;
5715}
5716
5717/**
5718 * xmlBufferFree:
5719 * @buf: the buffer to free
5720 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005721 * Frees an XML buffer. It frees both the content and the structure which
5722 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005723 */
5724void
5725xmlBufferFree(xmlBufferPtr buf) {
5726 if (buf == NULL) {
5727#ifdef DEBUG_BUFFER
5728 xmlGenericError(xmlGenericErrorContext,
5729 "xmlBufferFree: buf == NULL\n");
5730#endif
5731 return;
5732 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00005733 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005734 xmlFree(buf->content);
5735 }
Owen Taylor3473f882001-02-23 17:55:21 +00005736 xmlFree(buf);
5737}
5738
5739/**
5740 * xmlBufferEmpty:
5741 * @buf: the buffer
5742 *
5743 * empty a buffer.
5744 */
5745void
5746xmlBufferEmpty(xmlBufferPtr buf) {
5747 if (buf->content == NULL) return;
5748 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005749 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005750}
5751
5752/**
5753 * xmlBufferShrink:
5754 * @buf: the buffer to dump
5755 * @len: the number of xmlChar to remove
5756 *
5757 * Remove the beginning of an XML buffer.
5758 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005759 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005760 */
5761int
5762xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5763 if (len == 0) return(0);
5764 if (len > buf->use) return(-1);
5765
5766 buf->use -= len;
5767 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5768
5769 buf->content[buf->use] = 0;
5770 return(len);
5771}
5772
5773/**
5774 * xmlBufferGrow:
5775 * @buf: the buffer
5776 * @len: the minimum free size to allocate
5777 *
5778 * Grow the available space of an XML buffer.
5779 *
5780 * Returns the new available space or -1 in case of error
5781 */
5782int
5783xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5784 int size;
5785 xmlChar *newbuf;
5786
5787 if (len + buf->use < buf->size) return(0);
5788
5789 size = buf->use + len + 100;
5790
5791 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5792 if (newbuf == NULL) return(-1);
5793 buf->content = newbuf;
5794 buf->size = size;
5795 return(buf->size - buf->use);
5796}
5797
5798/**
5799 * xmlBufferDump:
5800 * @file: the file output
5801 * @buf: the buffer to dump
5802 *
5803 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005804 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005805 */
5806int
5807xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5808 int ret;
5809
5810 if (buf == NULL) {
5811#ifdef DEBUG_BUFFER
5812 xmlGenericError(xmlGenericErrorContext,
5813 "xmlBufferDump: buf == NULL\n");
5814#endif
5815 return(0);
5816 }
5817 if (buf->content == NULL) {
5818#ifdef DEBUG_BUFFER
5819 xmlGenericError(xmlGenericErrorContext,
5820 "xmlBufferDump: buf->content == NULL\n");
5821#endif
5822 return(0);
5823 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005824 if (file == NULL)
5825 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005826 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5827 return(ret);
5828}
5829
5830/**
5831 * xmlBufferContent:
5832 * @buf: the buffer
5833 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005834 * Function to extract the content of a buffer
5835 *
Owen Taylor3473f882001-02-23 17:55:21 +00005836 * Returns the internal content
5837 */
5838
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005839const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005840xmlBufferContent(const xmlBufferPtr buf)
5841{
5842 if(!buf)
5843 return NULL;
5844
5845 return buf->content;
5846}
5847
5848/**
5849 * xmlBufferLength:
5850 * @buf: the buffer
5851 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005852 * Function to get the length of a buffer
5853 *
Owen Taylor3473f882001-02-23 17:55:21 +00005854 * Returns the length of data in the internal content
5855 */
5856
5857int
5858xmlBufferLength(const xmlBufferPtr buf)
5859{
5860 if(!buf)
5861 return 0;
5862
5863 return buf->use;
5864}
5865
5866/**
5867 * xmlBufferResize:
5868 * @buf: the buffer to resize
5869 * @size: the desired size
5870 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005871 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005872 *
5873 * Returns 0 in case of problems, 1 otherwise
5874 */
5875int
5876xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5877{
5878 unsigned int newSize;
5879 xmlChar* rebuf = NULL;
5880
5881 /*take care of empty case*/
5882 newSize = (buf->size ? buf->size*2 : size);
5883
5884 /* Don't resize if we don't have to */
5885 if (size < buf->size)
5886 return 1;
5887
5888 /* figure out new size */
5889 switch (buf->alloc){
5890 case XML_BUFFER_ALLOC_DOUBLEIT:
5891 while (size > newSize) newSize *= 2;
5892 break;
5893 case XML_BUFFER_ALLOC_EXACT:
5894 newSize = size+10;
5895 break;
5896 default:
5897 newSize = size+10;
5898 break;
5899 }
5900
5901 if (buf->content == NULL)
5902 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5903 else
5904 rebuf = (xmlChar *) xmlRealloc(buf->content,
5905 newSize * sizeof(xmlChar));
5906 if (rebuf == NULL) {
5907 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005908 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005909 return 0;
5910 }
5911 buf->content = rebuf;
5912 buf->size = newSize;
5913
5914 return 1;
5915}
5916
5917/**
5918 * xmlBufferAdd:
5919 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005920 * @str: the #xmlChar string
5921 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005922 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005923 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005924 * str is recomputed.
5925 */
5926void
5927xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5928 unsigned int needSize;
5929
5930 if (str == NULL) {
5931#ifdef DEBUG_BUFFER
5932 xmlGenericError(xmlGenericErrorContext,
5933 "xmlBufferAdd: str == NULL\n");
5934#endif
5935 return;
5936 }
5937 if (len < -1) {
5938#ifdef DEBUG_BUFFER
5939 xmlGenericError(xmlGenericErrorContext,
5940 "xmlBufferAdd: len < 0\n");
5941#endif
5942 return;
5943 }
5944 if (len == 0) return;
5945
5946 if (len < 0)
5947 len = xmlStrlen(str);
5948
5949 if (len <= 0) return;
5950
5951 needSize = buf->use + len + 2;
5952 if (needSize > buf->size){
5953 if (!xmlBufferResize(buf, needSize)){
5954 xmlGenericError(xmlGenericErrorContext,
5955 "xmlBufferAdd : out of memory!\n");
5956 return;
5957 }
5958 }
5959
5960 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5961 buf->use += len;
5962 buf->content[buf->use] = 0;
5963}
5964
5965/**
5966 * xmlBufferAddHead:
5967 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005968 * @str: the #xmlChar string
5969 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005970 *
5971 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005972 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005973 */
5974void
5975xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5976 unsigned int needSize;
5977
5978 if (str == NULL) {
5979#ifdef DEBUG_BUFFER
5980 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005981 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005982#endif
5983 return;
5984 }
5985 if (len < -1) {
5986#ifdef DEBUG_BUFFER
5987 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005988 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005989#endif
5990 return;
5991 }
5992 if (len == 0) return;
5993
5994 if (len < 0)
5995 len = xmlStrlen(str);
5996
5997 if (len <= 0) return;
5998
5999 needSize = buf->use + len + 2;
6000 if (needSize > buf->size){
6001 if (!xmlBufferResize(buf, needSize)){
6002 xmlGenericError(xmlGenericErrorContext,
6003 "xmlBufferAddHead : out of memory!\n");
6004 return;
6005 }
6006 }
6007
6008 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6009 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6010 buf->use += len;
6011 buf->content[buf->use] = 0;
6012}
6013
6014/**
6015 * xmlBufferCat:
6016 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006017 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006018 *
6019 * Append a zero terminated string to an XML buffer.
6020 */
6021void
6022xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
6023 if (str != NULL)
6024 xmlBufferAdd(buf, str, -1);
6025}
6026
6027/**
6028 * xmlBufferCCat:
6029 * @buf: the buffer to dump
6030 * @str: the C char string
6031 *
6032 * Append a zero terminated C string to an XML buffer.
6033 */
6034void
6035xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6036 const char *cur;
6037
6038 if (str == NULL) {
6039#ifdef DEBUG_BUFFER
6040 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006041 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006042#endif
6043 return;
6044 }
6045 for (cur = str;*cur != 0;cur++) {
6046 if (buf->use + 10 >= buf->size) {
6047 if (!xmlBufferResize(buf, buf->use+10)){
6048 xmlGenericError(xmlGenericErrorContext,
6049 "xmlBufferCCat : out of memory!\n");
6050 return;
6051 }
6052 }
6053 buf->content[buf->use++] = *cur;
6054 }
6055 buf->content[buf->use] = 0;
6056}
6057
6058/**
6059 * xmlBufferWriteCHAR:
6060 * @buf: the XML buffer
6061 * @string: the string to add
6062 *
6063 * routine which manages and grows an output buffer. This one adds
6064 * xmlChars at the end of the buffer.
6065 */
6066void
Owen Taylor3473f882001-02-23 17:55:21 +00006067xmlBufferWriteCHAR
Owen Taylor3473f882001-02-23 17:55:21 +00006068(xmlBufferPtr buf, const xmlChar *string) {
6069 xmlBufferCat(buf, string);
6070}
6071
6072/**
6073 * xmlBufferWriteChar:
6074 * @buf: the XML buffer output
6075 * @string: the string to add
6076 *
6077 * routine which manage and grows an output buffer. This one add
6078 * C chars at the end of the array.
6079 */
6080void
6081xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
6082 xmlBufferCCat(buf, string);
6083}
6084
6085
6086/**
6087 * xmlBufferWriteQuotedString:
6088 * @buf: the XML buffer output
6089 * @string: the string to add
6090 *
6091 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006092 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006093 * quote or double-quotes internally
6094 */
6095void
6096xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
6097 if (xmlStrchr(string, '"')) {
6098 if (xmlStrchr(string, '\'')) {
6099#ifdef DEBUG_BUFFER
6100 xmlGenericError(xmlGenericErrorContext,
6101 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6102#endif
6103 }
6104 xmlBufferCCat(buf, "'");
6105 xmlBufferCat(buf, string);
6106 xmlBufferCCat(buf, "'");
6107 } else {
6108 xmlBufferCCat(buf, "\"");
6109 xmlBufferCat(buf, string);
6110 xmlBufferCCat(buf, "\"");
6111 }
6112}
6113
6114
6115/************************************************************************
6116 * *
6117 * Dumping XML tree content to a simple buffer *
6118 * *
6119 ************************************************************************/
6120
Owen Taylor3473f882001-02-23 17:55:21 +00006121/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00006122 * xmlAttrSerializeContent:
6123 * @buf: the XML buffer output
6124 * @doc: the document
6125 * @attr: the attribute pointer
6126 *
6127 * Serialize the attribute in the buffer
6128 */
6129static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006130xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
6131{
Daniel Veillarda6d05382002-02-13 13:07:41 +00006132 const xmlChar *cur, *base;
6133 xmlNodePtr children;
6134
6135 children = attr->children;
6136 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006137 switch (children->type) {
6138 case XML_TEXT_NODE:
6139 base = cur = children->content;
6140 while (*cur != 0) {
6141 if (*cur == '\n') {
6142 if (base != cur)
6143 xmlBufferAdd(buf, base, cur - base);
6144 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
6145 cur++;
6146 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006147#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006148 } else if (*cur == '\'') {
6149 if (base != cur)
6150 xmlBufferAdd(buf, base, cur - base);
6151 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
6152 cur++;
6153 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006154#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006155 } else if (*cur == '"') {
6156 if (base != cur)
6157 xmlBufferAdd(buf, base, cur - base);
6158 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6159 cur++;
6160 base = cur;
6161 } else if (*cur == '<') {
6162 if (base != cur)
6163 xmlBufferAdd(buf, base, cur - base);
6164 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6165 cur++;
6166 base = cur;
6167 } else if (*cur == '>') {
6168 if (base != cur)
6169 xmlBufferAdd(buf, base, cur - base);
6170 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6171 cur++;
6172 base = cur;
6173 } else if (*cur == '&') {
6174 if (base != cur)
6175 xmlBufferAdd(buf, base, cur - base);
6176 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6177 cur++;
6178 base = cur;
6179 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6180 (doc->encoding ==
6181 NULL))) {
6182 /*
6183 * We assume we have UTF-8 content.
6184 */
6185 char tmp[10];
6186 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006187
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006188 if (base != cur)
6189 xmlBufferAdd(buf, base, cur - base);
6190 if (*cur < 0xC0) {
6191 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6d05382002-02-13 13:07:41 +00006192 "xmlAttrSerializeContent : input not UTF-8\n");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006193 if (doc != NULL)
6194 doc->encoding =
6195 xmlStrdup(BAD_CAST "ISO-8859-1");
6196 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6197 tmp[sizeof(tmp) - 1] = 0;
6198 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6199 cur++;
6200 base = cur;
6201 continue;
6202 } else if (*cur < 0xE0) {
6203 val = (cur[0]) & 0x1F;
6204 val <<= 6;
6205 val |= (cur[1]) & 0x3F;
6206 l = 2;
6207 } else if (*cur < 0xF0) {
6208 val = (cur[0]) & 0x0F;
6209 val <<= 6;
6210 val |= (cur[1]) & 0x3F;
6211 val <<= 6;
6212 val |= (cur[2]) & 0x3F;
6213 l = 3;
6214 } else if (*cur < 0xF8) {
6215 val = (cur[0]) & 0x07;
6216 val <<= 6;
6217 val |= (cur[1]) & 0x3F;
6218 val <<= 6;
6219 val |= (cur[2]) & 0x3F;
6220 val <<= 6;
6221 val |= (cur[3]) & 0x3F;
6222 l = 4;
6223 }
6224 if ((l == 1) || (!IS_CHAR(val))) {
6225 xmlGenericError(xmlGenericErrorContext,
6226 "xmlAttrSerializeContent : char out of range\n");
6227 if (doc != NULL)
6228 doc->encoding =
6229 xmlStrdup(BAD_CAST "ISO-8859-1");
6230 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6231 tmp[sizeof(tmp) - 1] = 0;
6232 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6233 cur++;
6234 base = cur;
6235 continue;
6236 }
6237 /*
6238 * We could do multiple things here. Just save
6239 * as a char ref
6240 */
6241 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6242 tmp[sizeof(tmp) - 1] = 0;
6243 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6244 cur += l;
6245 base = cur;
6246 } else {
6247 cur++;
6248 }
6249 }
6250 if (base != cur)
6251 xmlBufferAdd(buf, base, cur - base);
6252 break;
6253 case XML_ENTITY_REF_NODE:
6254 xmlBufferAdd(buf, BAD_CAST "&", 1);
6255 xmlBufferAdd(buf, children->name,
6256 xmlStrlen(children->name));
6257 xmlBufferAdd(buf, BAD_CAST ";", 1);
6258 break;
6259 default:
6260 /* should not happen unless we have a badly built tree */
6261 break;
6262 }
6263 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006264 }
6265}
6266
6267/**
6268 * xmlNodeDump:
6269 * @buf: the XML buffer output
6270 * @doc: the document
6271 * @cur: the current node
6272 * @level: the imbrication level for indenting
6273 * @format: is formatting allowed
6274 *
6275 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006276 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006277 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006278 *
6279 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00006280 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006281int
Owen Taylor3473f882001-02-23 17:55:21 +00006282xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006283 int format)
6284{
6285 unsigned int use;
6286 int ret;
6287 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006288
6289 if (cur == NULL) {
6290#ifdef DEBUG_TREE
6291 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006292 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006293#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006294 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006295 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006296 if (buf == NULL) {
6297#ifdef DEBUG_TREE
6298 xmlGenericError(xmlGenericErrorContext,
6299 "xmlNodeDump : buf == NULL\n");
6300#endif
6301 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006302 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006303 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
6304 if (outbuf == NULL) {
6305 xmlGenericError(xmlGenericErrorContext,
6306 "xmlNodeDump: out of memory!\n");
6307 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006308 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006309 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
6310 outbuf->buffer = buf;
6311 outbuf->encoder = NULL;
6312 outbuf->writecallback = NULL;
6313 outbuf->closecallback = NULL;
6314 outbuf->context = NULL;
6315 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006316
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006317 use = buf->use;
6318 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
6319 xmlFree(outbuf);
6320 ret = buf->use - use;
6321 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006322}
6323
6324/**
6325 * xmlElemDump:
6326 * @f: the FILE * for the output
6327 * @doc: the document
6328 * @cur: the current node
6329 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006330 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006331 */
6332void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006333xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
6334{
6335 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006336
6337 if (cur == NULL) {
6338#ifdef DEBUG_TREE
6339 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006340 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006341#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006342 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006343 }
Owen Taylor3473f882001-02-23 17:55:21 +00006344#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006345 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006346 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006347 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006348 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006349#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006350
6351 outbuf = xmlOutputBufferCreateFile(f, NULL);
6352 if (outbuf == NULL)
6353 return;
6354 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006355#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006356 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
6357#else
6358 xmlGenericError(xmlGenericErrorContext,
6359 "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006360#endif /* LIBXML_HTML_ENABLED */
6361 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006362 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
6363 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00006364}
6365
6366/************************************************************************
6367 * *
6368 * Dumping XML tree content to an I/O output buffer *
6369 * *
6370 ************************************************************************/
6371
Owen Taylor3473f882001-02-23 17:55:21 +00006372static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006373xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6374 int level, int format, const char *encoding);
6375static void
Owen Taylor3473f882001-02-23 17:55:21 +00006376xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6377 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006378static void
6379xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6380 xmlNodePtr cur, int level, int format, const char *encoding);
6381
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006382void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
6383
Owen Taylor3473f882001-02-23 17:55:21 +00006384/**
6385 * xmlNsDumpOutput:
6386 * @buf: the XML buffer output
6387 * @cur: a namespace
6388 *
6389 * Dump a local Namespace definition.
6390 * Should be called in the context of attributes dumps.
6391 */
6392static void
6393xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6394 if (cur == NULL) {
6395#ifdef DEBUG_TREE
6396 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006397 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006398#endif
6399 return;
6400 }
6401 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006402 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6403 return;
6404
Owen Taylor3473f882001-02-23 17:55:21 +00006405 /* Within the context of an element attributes */
6406 if (cur->prefix != NULL) {
6407 xmlOutputBufferWriteString(buf, " xmlns:");
6408 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6409 } else
6410 xmlOutputBufferWriteString(buf, " xmlns");
6411 xmlOutputBufferWriteString(buf, "=");
6412 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6413 }
6414}
6415
6416/**
6417 * xmlNsListDumpOutput:
6418 * @buf: the XML buffer output
6419 * @cur: the first namespace
6420 *
6421 * Dump a list of local Namespace definitions.
6422 * Should be called in the context of attributes dumps.
6423 */
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006424void
Owen Taylor3473f882001-02-23 17:55:21 +00006425xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6426 while (cur != NULL) {
6427 xmlNsDumpOutput(buf, cur);
6428 cur = cur->next;
6429 }
6430}
6431
6432/**
6433 * xmlDtdDumpOutput:
6434 * @buf: the XML buffer output
6435 * @doc: the document
6436 * @encoding: an optional encoding string
6437 *
6438 * Dump the XML document DTD, if any.
6439 */
6440static void
6441xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6442 if (dtd == NULL) {
6443#ifdef DEBUG_TREE
6444 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006445 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006446#endif
6447 return;
6448 }
6449 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6450 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6451 if (dtd->ExternalID != NULL) {
6452 xmlOutputBufferWriteString(buf, " PUBLIC ");
6453 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6454 xmlOutputBufferWriteString(buf, " ");
6455 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6456 } else if (dtd->SystemID != NULL) {
6457 xmlOutputBufferWriteString(buf, " SYSTEM ");
6458 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6459 }
6460 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6461 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6462 xmlOutputBufferWriteString(buf, ">");
6463 return;
6464 }
6465 xmlOutputBufferWriteString(buf, " [\n");
6466 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6467 xmlOutputBufferWriteString(buf, "]>");
6468}
6469
6470/**
6471 * xmlAttrDumpOutput:
6472 * @buf: the XML buffer output
6473 * @doc: the document
6474 * @cur: the attribute pointer
6475 * @encoding: an optional encoding string
6476 *
6477 * Dump an XML attribute
6478 */
6479static void
6480xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006481 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006482 if (cur == NULL) {
6483#ifdef DEBUG_TREE
6484 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006485 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006486#endif
6487 return;
6488 }
6489 xmlOutputBufferWriteString(buf, " ");
6490 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6491 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6492 xmlOutputBufferWriteString(buf, ":");
6493 }
6494 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006495 xmlOutputBufferWriteString(buf, "=\"");
6496 xmlAttrSerializeContent(buf->buffer, doc, cur);
6497 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006498}
6499
6500/**
6501 * xmlAttrListDumpOutput:
6502 * @buf: the XML buffer output
6503 * @doc: the document
6504 * @cur: the first attribute pointer
6505 * @encoding: an optional encoding string
6506 *
6507 * Dump a list of XML attributes
6508 */
6509static void
6510xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6511 xmlAttrPtr cur, const char *encoding) {
6512 if (cur == NULL) {
6513#ifdef DEBUG_TREE
6514 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006515 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006516#endif
6517 return;
6518 }
6519 while (cur != NULL) {
6520 xmlAttrDumpOutput(buf, doc, cur, encoding);
6521 cur = cur->next;
6522 }
6523}
6524
6525
6526
6527/**
6528 * xmlNodeListDumpOutput:
6529 * @buf: the XML buffer output
6530 * @doc: the document
6531 * @cur: the first node
6532 * @level: the imbrication level for indenting
6533 * @format: is formatting allowed
6534 * @encoding: an optional encoding string
6535 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006536 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006537 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006538 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006539 */
6540static void
6541xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6542 xmlNodePtr cur, int level, int format, const char *encoding) {
6543 int i;
6544
6545 if (cur == NULL) {
6546#ifdef DEBUG_TREE
6547 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006548 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006549#endif
6550 return;
6551 }
6552 while (cur != NULL) {
6553 if ((format) && (xmlIndentTreeOutput) &&
6554 (cur->type == XML_ELEMENT_NODE))
6555 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006556 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006557 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00006558 if (format) {
6559 xmlOutputBufferWriteString(buf, "\n");
6560 }
6561 cur = cur->next;
6562 }
6563}
6564
6565/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006566 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00006567 * @buf: the XML buffer output
6568 * @doc: the document
6569 * @cur: the current node
6570 * @level: the imbrication level for indenting
6571 * @format: is formatting allowed
6572 * @encoding: an optional encoding string
6573 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006574 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006575 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006576 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006577 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006578static void
6579xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6580 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006581 int i;
6582 xmlNodePtr tmp;
6583
6584 if (cur == NULL) {
6585#ifdef DEBUG_TREE
6586 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006587 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006588#endif
6589 return;
6590 }
6591 if (cur->type == XML_XINCLUDE_START)
6592 return;
6593 if (cur->type == XML_XINCLUDE_END)
6594 return;
6595 if (cur->type == XML_DTD_NODE) {
6596 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6597 return;
6598 }
6599 if (cur->type == XML_ELEMENT_DECL) {
6600 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6601 return;
6602 }
6603 if (cur->type == XML_ATTRIBUTE_DECL) {
6604 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6605 return;
6606 }
6607 if (cur->type == XML_ENTITY_DECL) {
6608 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6609 return;
6610 }
6611 if (cur->type == XML_TEXT_NODE) {
6612 if (cur->content != NULL) {
6613 if ((cur->name == xmlStringText) ||
6614 (cur->name != xmlStringTextNoenc)) {
6615 xmlChar *buffer;
6616
Owen Taylor3473f882001-02-23 17:55:21 +00006617 if (encoding == NULL)
6618 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6619 else
6620 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006621 if (buffer != NULL) {
6622 xmlOutputBufferWriteString(buf, (const char *)buffer);
6623 xmlFree(buffer);
6624 }
6625 } else {
6626 /*
6627 * Disable escaping, needed for XSLT
6628 */
Owen Taylor3473f882001-02-23 17:55:21 +00006629 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006630 }
6631 }
6632
6633 return;
6634 }
6635 if (cur->type == XML_PI_NODE) {
6636 if (cur->content != NULL) {
6637 xmlOutputBufferWriteString(buf, "<?");
6638 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6639 if (cur->content != NULL) {
6640 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006641 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006642 }
6643 xmlOutputBufferWriteString(buf, "?>");
6644 } else {
6645 xmlOutputBufferWriteString(buf, "<?");
6646 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6647 xmlOutputBufferWriteString(buf, "?>");
6648 }
6649 return;
6650 }
6651 if (cur->type == XML_COMMENT_NODE) {
6652 if (cur->content != NULL) {
6653 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006654 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006655 xmlOutputBufferWriteString(buf, "-->");
6656 }
6657 return;
6658 }
6659 if (cur->type == XML_ENTITY_REF_NODE) {
6660 xmlOutputBufferWriteString(buf, "&");
6661 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6662 xmlOutputBufferWriteString(buf, ";");
6663 return;
6664 }
6665 if (cur->type == XML_CDATA_SECTION_NODE) {
6666 xmlOutputBufferWriteString(buf, "<![CDATA[");
6667 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006668 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006669 xmlOutputBufferWriteString(buf, "]]>");
6670 return;
6671 }
6672
6673 if (format == 1) {
6674 tmp = cur->children;
6675 while (tmp != NULL) {
6676 if ((tmp->type == XML_TEXT_NODE) ||
6677 (tmp->type == XML_ENTITY_REF_NODE)) {
6678 format = 0;
6679 break;
6680 }
6681 tmp = tmp->next;
6682 }
6683 }
6684 xmlOutputBufferWriteString(buf, "<");
6685 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6686 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6687 xmlOutputBufferWriteString(buf, ":");
6688 }
6689
6690 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6691 if (cur->nsDef)
6692 xmlNsListDumpOutput(buf, cur->nsDef);
6693 if (cur->properties != NULL)
6694 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6695
Daniel Veillard7db37732001-07-12 01:20:08 +00006696 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6697 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006698 xmlOutputBufferWriteString(buf, "/>");
6699 return;
6700 }
6701 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006702 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006703 xmlChar *buffer;
6704
Owen Taylor3473f882001-02-23 17:55:21 +00006705 if (encoding == NULL)
6706 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6707 else
6708 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006709 if (buffer != NULL) {
6710 xmlOutputBufferWriteString(buf, (const char *)buffer);
6711 xmlFree(buffer);
6712 }
6713 }
6714 if (cur->children != NULL) {
6715 if (format) xmlOutputBufferWriteString(buf, "\n");
6716 xmlNodeListDumpOutput(buf, doc, cur->children,
6717 (level >= 0?level+1:-1), format, encoding);
6718 if ((xmlIndentTreeOutput) && (format))
6719 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006720 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006721 }
6722 xmlOutputBufferWriteString(buf, "</");
6723 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6724 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6725 xmlOutputBufferWriteString(buf, ":");
6726 }
6727
6728 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6729 xmlOutputBufferWriteString(buf, ">");
6730}
6731
6732/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006733 * xmlNodeDumpOutput:
6734 * @buf: the XML buffer output
6735 * @doc: the document
6736 * @cur: the current node
6737 * @level: the imbrication level for indenting
6738 * @format: is formatting allowed
6739 * @encoding: an optional encoding string
6740 *
6741 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006742 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006743 * or xmlKeepBlanksDefault(0) was called
6744 */
6745void
6746xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006747 int level, int format, const char *encoding)
6748{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006749#ifdef LIBXML_HTML_ENABLED
6750 xmlDtdPtr dtd;
6751 int is_xhtml = 0;
6752
6753 dtd = xmlGetIntSubset(doc);
6754 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006755 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
6756 if (is_xhtml < 0)
6757 is_xhtml = 0;
6758 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
6759 (cur->type == XML_ELEMENT_NODE) &&
6760 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
6761 if (encoding != NULL)
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00006762 htmlSetMetaEncoding((htmlDocPtr) doc,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006763 (const xmlChar *) encoding);
6764 else
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00006765 htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006766 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006767 }
6768
6769 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006770 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006771 else
6772#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006773 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006774}
6775
6776/**
Owen Taylor3473f882001-02-23 17:55:21 +00006777 * xmlDocContentDumpOutput:
6778 * @buf: the XML buffer output
6779 * @cur: the document
6780 * @encoding: an optional encoding string
6781 * @format: should formatting spaces been added
6782 *
6783 * Dump an XML document.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006784 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006785 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006786 */
6787static void
6788xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6789 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006790#ifdef LIBXML_HTML_ENABLED
6791 xmlDtdPtr dtd;
6792 int is_xhtml = 0;
6793#endif
6794
Owen Taylor3473f882001-02-23 17:55:21 +00006795 xmlOutputBufferWriteString(buf, "<?xml version=");
6796 if (cur->version != NULL)
6797 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6798 else
6799 xmlOutputBufferWriteString(buf, "\"1.0\"");
6800 if (encoding == NULL) {
6801 if (cur->encoding != NULL)
6802 encoding = (const char *) cur->encoding;
6803 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6804 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6805 }
6806 if (encoding != NULL) {
6807 xmlOutputBufferWriteString(buf, " encoding=");
6808 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6809 }
6810 switch (cur->standalone) {
6811 case 0:
6812 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6813 break;
6814 case 1:
6815 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6816 break;
6817 }
6818 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006819
6820#ifdef LIBXML_HTML_ENABLED
6821 dtd = xmlGetIntSubset(cur);
6822 if (dtd != NULL) {
6823 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
6824 if (is_xhtml < 0) is_xhtml = 0;
6825 }
6826 if (is_xhtml) {
6827 if (encoding != NULL)
6828 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
6829 else
6830 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
6831 }
6832#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006833 if (cur->children != NULL) {
6834 xmlNodePtr child = cur->children;
6835
6836 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006837#ifdef LIBXML_HTML_ENABLED
6838 if (is_xhtml)
6839 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6840 else
6841#endif
6842 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00006843 xmlOutputBufferWriteString(buf, "\n");
6844 child = child->next;
6845 }
6846 }
6847}
6848
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006849#ifdef LIBXML_HTML_ENABLED
6850/************************************************************************
6851 * *
6852 * Functions specific to XHTML serialization *
6853 * *
6854 ************************************************************************/
6855
6856#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
6857 "-//W3C//DTD XHTML 1.0 Strict//EN"
6858#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
6859 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
6860#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
6861 "-//W3C//DTD XHTML 1.0 Frameset//EN"
6862#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
6863 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
6864#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
6865 "-//W3C//DTD XHTML 1.0 Transitional//EN"
6866#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
6867 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
6868
6869#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
6870/**
6871 * xmlIsXHTML:
6872 * @systemID: the system identifier
6873 * @publicID: the public identifier
6874 *
6875 * Try to find if the document correspond to an XHTML DTD
6876 *
6877 * Returns 1 if true, 0 if not and -1 in case of error
6878 */
6879int
6880xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
6881 if ((systemID == NULL) && (publicID == NULL))
6882 return(-1);
6883 if (publicID != NULL) {
6884 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
6885 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
6886 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
6887 }
6888 if (systemID != NULL) {
6889 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
6890 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
6891 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
6892 }
6893 return(0);
6894}
6895
6896/**
6897 * xhtmlIsEmpty:
6898 * @node: the node
6899 *
6900 * Check if a node is an empty xhtml node
6901 *
6902 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
6903 */
6904static int
6905xhtmlIsEmpty(xmlNodePtr node) {
6906 if (node == NULL)
6907 return(-1);
6908 if (node->type != XML_ELEMENT_NODE)
6909 return(0);
6910 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
6911 return(0);
6912 if (node->children != NULL)
6913 return(0);
6914 switch (node->name[0]) {
6915 case 'a':
6916 if (xmlStrEqual(node->name, BAD_CAST "area"))
6917 return(1);
6918 return(0);
6919 case 'b':
6920 if (xmlStrEqual(node->name, BAD_CAST "br"))
6921 return(1);
6922 if (xmlStrEqual(node->name, BAD_CAST "base"))
6923 return(1);
6924 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
6925 return(1);
6926 return(0);
6927 case 'c':
6928 if (xmlStrEqual(node->name, BAD_CAST "col"))
6929 return(1);
6930 return(0);
6931 case 'f':
6932 if (xmlStrEqual(node->name, BAD_CAST "frame"))
6933 return(1);
6934 return(0);
6935 case 'h':
6936 if (xmlStrEqual(node->name, BAD_CAST "hr"))
6937 return(1);
6938 return(0);
6939 case 'i':
6940 if (xmlStrEqual(node->name, BAD_CAST "img"))
6941 return(1);
6942 if (xmlStrEqual(node->name, BAD_CAST "input"))
6943 return(1);
6944 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
6945 return(1);
6946 return(0);
6947 case 'l':
6948 if (xmlStrEqual(node->name, BAD_CAST "link"))
6949 return(1);
6950 return(0);
6951 case 'm':
6952 if (xmlStrEqual(node->name, BAD_CAST "meta"))
6953 return(1);
6954 return(0);
6955 case 'p':
6956 if (xmlStrEqual(node->name, BAD_CAST "param"))
6957 return(1);
6958 return(0);
6959 }
6960 return(0);
6961}
6962
6963/**
6964 * xhtmlAttrListDumpOutput:
6965 * @buf: the XML buffer output
6966 * @doc: the document
6967 * @cur: the first attribute pointer
6968 * @encoding: an optional encoding string
6969 *
6970 * Dump a list of XML attributes
6971 */
6972static void
6973xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6974 xmlAttrPtr cur, const char *encoding) {
6975 xmlAttrPtr xml_lang = NULL;
6976 xmlAttrPtr lang = NULL;
6977 xmlAttrPtr name = NULL;
6978 xmlAttrPtr id = NULL;
6979
6980 if (cur == NULL) {
6981#ifdef DEBUG_TREE
6982 xmlGenericError(xmlGenericErrorContext,
6983 "xmlAttrListDumpOutput : property == NULL\n");
6984#endif
6985 return;
6986 }
6987 while (cur != NULL) {
6988 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
6989 id = cur;
6990 else
6991 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
6992 name = cur;
6993 else
6994 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
6995 lang = cur;
6996 else
6997 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
6998 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
6999 xml_lang = cur;
7000 else if ((cur->ns == NULL) &&
7001 ((cur->children == NULL) ||
7002 (cur->children->content == NULL) ||
7003 (cur->children->content[0] == 0)) &&
7004 (htmlIsBooleanAttr(cur->name))) {
7005 if (cur->children != NULL)
7006 xmlFreeNode(cur->children);
7007 cur->children = xmlNewText(cur->name);
7008 if (cur->children != NULL)
7009 cur->children->parent = (xmlNodePtr) cur;
7010 }
7011 xmlAttrDumpOutput(buf, doc, cur, encoding);
7012 cur = cur->next;
7013 }
7014 /*
7015 * C.8
7016 */
7017 if ((name != NULL) && (id == NULL)) {
7018 xmlOutputBufferWriteString(buf, " id=\"");
7019 xmlAttrSerializeContent(buf->buffer, doc, name);
7020 xmlOutputBufferWriteString(buf, "\"");
7021 }
7022 /*
7023 * C.7.
7024 */
7025 if ((lang != NULL) && (xml_lang == NULL)) {
7026 xmlOutputBufferWriteString(buf, " xml:lang=\"");
7027 xmlAttrSerializeContent(buf->buffer, doc, lang);
7028 xmlOutputBufferWriteString(buf, "\"");
7029 } else
7030 if ((xml_lang != NULL) && (lang == NULL)) {
7031 xmlOutputBufferWriteString(buf, " lang=\"");
7032 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
7033 xmlOutputBufferWriteString(buf, "\"");
7034 }
7035}
7036
7037/**
7038 * xhtmlNodeListDumpOutput:
7039 * @buf: the XML buffer output
7040 * @doc: the XHTML document
7041 * @cur: the first node
7042 * @level: the imbrication level for indenting
7043 * @format: is formatting allowed
7044 * @encoding: an optional encoding string
7045 *
7046 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007047 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007048 * or xmlKeepBlanksDefault(0) was called
7049 */
7050static void
7051xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7052 xmlNodePtr cur, int level, int format, const char *encoding) {
7053 int i;
7054
7055 if (cur == NULL) {
7056#ifdef DEBUG_TREE
7057 xmlGenericError(xmlGenericErrorContext,
7058 "xhtmlNodeListDumpOutput : node == NULL\n");
7059#endif
7060 return;
7061 }
7062 while (cur != NULL) {
7063 if ((format) && (xmlIndentTreeOutput) &&
7064 (cur->type == XML_ELEMENT_NODE))
7065 for (i = 0;i < level;i++)
7066 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7067 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
7068 if (format) {
7069 xmlOutputBufferWriteString(buf, "\n");
7070 }
7071 cur = cur->next;
7072 }
7073}
7074
7075/**
7076 * xhtmlNodeDumpOutput:
7077 * @buf: the XML buffer output
7078 * @doc: the XHTML document
7079 * @cur: the current node
7080 * @level: the imbrication level for indenting
7081 * @format: is formatting allowed
7082 * @encoding: an optional encoding string
7083 *
7084 * Dump an XHTML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007085 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007086 * or xmlKeepBlanksDefault(0) was called
7087 */
7088static void
7089xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7090 int level, int format, const char *encoding) {
7091 int i;
7092 xmlNodePtr tmp;
7093
7094 if (cur == NULL) {
7095#ifdef DEBUG_TREE
7096 xmlGenericError(xmlGenericErrorContext,
7097 "xmlNodeDumpOutput : node == NULL\n");
7098#endif
7099 return;
7100 }
7101 if (cur->type == XML_XINCLUDE_START)
7102 return;
7103 if (cur->type == XML_XINCLUDE_END)
7104 return;
7105 if (cur->type == XML_DTD_NODE) {
7106 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7107 return;
7108 }
7109 if (cur->type == XML_ELEMENT_DECL) {
7110 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7111 return;
7112 }
7113 if (cur->type == XML_ATTRIBUTE_DECL) {
7114 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7115 return;
7116 }
7117 if (cur->type == XML_ENTITY_DECL) {
7118 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7119 return;
7120 }
7121 if (cur->type == XML_TEXT_NODE) {
7122 if (cur->content != NULL) {
7123 if ((cur->name == xmlStringText) ||
7124 (cur->name != xmlStringTextNoenc)) {
7125 xmlChar *buffer;
7126
7127 if (encoding == NULL)
7128 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7129 else
7130 buffer = xmlEncodeSpecialChars(doc, cur->content);
7131 if (buffer != NULL) {
7132 xmlOutputBufferWriteString(buf, (const char *)buffer);
7133 xmlFree(buffer);
7134 }
7135 } else {
7136 /*
7137 * Disable escaping, needed for XSLT
7138 */
7139 xmlOutputBufferWriteString(buf, (const char *) cur->content);
7140 }
7141 }
7142
7143 return;
7144 }
7145 if (cur->type == XML_PI_NODE) {
7146 if (cur->content != NULL) {
7147 xmlOutputBufferWriteString(buf, "<?");
7148 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7149 if (cur->content != NULL) {
7150 xmlOutputBufferWriteString(buf, " ");
7151 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7152 }
7153 xmlOutputBufferWriteString(buf, "?>");
7154 } else {
7155 xmlOutputBufferWriteString(buf, "<?");
7156 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7157 xmlOutputBufferWriteString(buf, "?>");
7158 }
7159 return;
7160 }
7161 if (cur->type == XML_COMMENT_NODE) {
7162 if (cur->content != NULL) {
7163 xmlOutputBufferWriteString(buf, "<!--");
7164 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7165 xmlOutputBufferWriteString(buf, "-->");
7166 }
7167 return;
7168 }
7169 if (cur->type == XML_ENTITY_REF_NODE) {
7170 xmlOutputBufferWriteString(buf, "&");
7171 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7172 xmlOutputBufferWriteString(buf, ";");
7173 return;
7174 }
7175 if (cur->type == XML_CDATA_SECTION_NODE) {
7176 xmlOutputBufferWriteString(buf, "<![CDATA[");
7177 if (cur->content != NULL)
7178 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7179 xmlOutputBufferWriteString(buf, "]]>");
7180 return;
7181 }
7182
7183 if (format == 1) {
7184 tmp = cur->children;
7185 while (tmp != NULL) {
7186 if ((tmp->type == XML_TEXT_NODE) ||
7187 (tmp->type == XML_ENTITY_REF_NODE)) {
7188 format = 0;
7189 break;
7190 }
7191 tmp = tmp->next;
7192 }
7193 }
7194 xmlOutputBufferWriteString(buf, "<");
7195 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7196 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7197 xmlOutputBufferWriteString(buf, ":");
7198 }
7199
7200 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7201 if (cur->nsDef)
7202 xmlNsListDumpOutput(buf, cur->nsDef);
7203 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
7204 (cur->ns == NULL) && (cur->nsDef == NULL))) {
7205 /*
7206 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
7207 */
7208 xmlOutputBufferWriteString(buf,
7209 " xmlns=\"http://www.w3.org/1999/xhtml\"");
7210 }
7211 if (cur->properties != NULL)
7212 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7213
7214 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
7215 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
7216 (xhtmlIsEmpty(cur) == 1)) {
7217 /*
7218 * C.2. Empty Elements
7219 */
7220 xmlOutputBufferWriteString(buf, " />");
7221 } else {
7222 /*
7223 * C.3. Element Minimization and Empty Element Content
7224 */
7225 xmlOutputBufferWriteString(buf, "></");
7226 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7227 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7228 xmlOutputBufferWriteString(buf, ":");
7229 }
7230 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7231 xmlOutputBufferWriteString(buf, ">");
7232 }
7233 return;
7234 }
7235 xmlOutputBufferWriteString(buf, ">");
7236 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
7237 xmlChar *buffer;
7238
7239 if (encoding == NULL)
7240 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7241 else
7242 buffer = xmlEncodeSpecialChars(doc, cur->content);
7243 if (buffer != NULL) {
7244 xmlOutputBufferWriteString(buf, (const char *)buffer);
7245 xmlFree(buffer);
7246 }
7247 }
7248
7249 /*
7250 * 4.8. Script and Style elements
7251 */
7252 if ((cur->type == XML_ELEMENT_NODE) &&
7253 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
7254 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
7255 ((cur->ns == NULL) ||
7256 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
7257 xmlNodePtr child = cur->children;
7258
7259 while (child != NULL) {
7260 if ((child->type == XML_TEXT_NODE) ||
7261 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00007262 /*
7263 * Apparently CDATA escaping for style just break on IE,
7264 * mozilla and galeon, so ...
7265 */
7266 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
7267 (xmlStrchr(child->content, '<') == NULL) &&
7268 (xmlStrchr(child->content, '>') == NULL) &&
7269 (xmlStrchr(child->content, '&') == NULL)) {
7270 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7271 } else {
7272 xmlOutputBufferWriteString(buf, "<![CDATA[");
7273 if (child->content != NULL)
7274 xmlOutputBufferWriteString(buf,
7275 (const char *)child->content);
7276 xmlOutputBufferWriteString(buf, "]]>");
7277 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007278 } else {
7279 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7280 }
7281 child = child->next;
7282 }
7283 } else if (cur->children != NULL) {
7284 if (format) xmlOutputBufferWriteString(buf, "\n");
7285 xhtmlNodeListDumpOutput(buf, doc, cur->children,
7286 (level >= 0?level+1:-1), format, encoding);
7287 if ((xmlIndentTreeOutput) && (format))
7288 for (i = 0;i < level;i++)
7289 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7290 }
7291 xmlOutputBufferWriteString(buf, "</");
7292 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7293 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7294 xmlOutputBufferWriteString(buf, ":");
7295 }
7296
7297 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7298 xmlOutputBufferWriteString(buf, ">");
7299}
7300#endif
7301
Owen Taylor3473f882001-02-23 17:55:21 +00007302/************************************************************************
7303 * *
7304 * Saving functions front-ends *
7305 * *
7306 ************************************************************************/
7307
7308/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007309 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00007310 * @out_doc: Document to generate XML text from
7311 * @doc_txt_ptr: Memory pointer for allocated XML text
7312 * @doc_txt_len: Length of the generated XML text
7313 * @txt_encoding: Character encoding to use when generating XML text
7314 * @format: should formatting spaces been added
7315 *
7316 * Dump the current DOM tree into memory using the character encoding specified
7317 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007318 * allocated memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00007319 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007320 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007321 */
7322
7323void
7324xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007325 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007326 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007327 int dummy = 0;
7328
7329 xmlCharEncoding doc_charset;
7330 xmlOutputBufferPtr out_buff = NULL;
7331 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
7332
7333 if (doc_txt_len == NULL) {
7334 doc_txt_len = &dummy; /* Continue, caller just won't get length */
7335 }
7336
7337 if (doc_txt_ptr == NULL) {
7338 *doc_txt_len = 0;
7339 xmlGenericError(xmlGenericErrorContext,
7340 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
7341 return;
7342 }
7343
7344 *doc_txt_ptr = NULL;
7345 *doc_txt_len = 0;
7346
7347 if (out_doc == NULL) {
7348 /* No document, no output */
7349 xmlGenericError(xmlGenericErrorContext,
7350 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
7351 return;
7352 }
7353
7354 /*
7355 * Validate the encoding value, if provided.
7356 * This logic is copied from xmlSaveFileEnc.
7357 */
7358
7359 if (txt_encoding == NULL)
7360 txt_encoding = (const char *) out_doc->encoding;
7361 if (txt_encoding != NULL) {
7362 doc_charset = xmlParseCharEncoding(txt_encoding);
7363
7364 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
7365 xmlGenericError(xmlGenericErrorContext,
7366 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
7367 return;
7368
7369 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
7370 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
7371 if ( conv_hdlr == NULL ) {
7372 xmlGenericError(xmlGenericErrorContext,
7373 "%s: %s %s '%s'\n",
7374 "xmlDocDumpFormatMemoryEnc",
7375 "Failed to identify encoding handler for",
7376 "character set",
7377 txt_encoding);
7378 return;
7379 }
7380 }
7381 }
7382
7383 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
7384 xmlGenericError(xmlGenericErrorContext,
7385 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
7386 return;
7387 }
7388
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007389 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007390 xmlOutputBufferFlush(out_buff);
7391 if (out_buff->conv != NULL) {
7392 *doc_txt_len = out_buff->conv->use;
7393 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
7394 } else {
7395 *doc_txt_len = out_buff->buffer->use;
7396 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
7397 }
7398 (void)xmlOutputBufferClose(out_buff);
7399
7400 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
7401 *doc_txt_len = 0;
7402 xmlGenericError(xmlGenericErrorContext,
7403 "xmlDocDumpFormatMemoryEnc: %s\n",
7404 "Failed to allocate memory for document text representation.");
7405 }
7406
7407 return;
7408}
7409
7410/**
7411 * xmlDocDumpMemory:
7412 * @cur: the document
7413 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007414 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007415 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007416 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007417 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007418 */
7419void
7420xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
7421 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
7422}
7423
7424/**
7425 * xmlDocDumpFormatMemory:
7426 * @cur: the document
7427 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007428 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007429 * @format: should formatting spaces been added
7430 *
7431 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007432 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007433 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00007434 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007435 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007436 */
7437void
7438xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
7439 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
7440}
7441
7442/**
7443 * xmlDocDumpMemoryEnc:
7444 * @out_doc: Document to generate XML text from
7445 * @doc_txt_ptr: Memory pointer for allocated XML text
7446 * @doc_txt_len: Length of the generated XML text
7447 * @txt_encoding: Character encoding to use when generating XML text
7448 *
7449 * Dump the current DOM tree into memory using the character encoding specified
7450 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007451 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007452 */
7453
7454void
7455xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
7456 int * doc_txt_len, const char * txt_encoding) {
7457 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007458 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007459}
7460
7461/**
7462 * xmlGetDocCompressMode:
7463 * @doc: the document
7464 *
7465 * get the compression ratio for a document, ZLIB based
7466 * Returns 0 (uncompressed) to 9 (max compression)
7467 */
7468int
7469xmlGetDocCompressMode (xmlDocPtr doc) {
7470 if (doc == NULL) return(-1);
7471 return(doc->compression);
7472}
7473
7474/**
7475 * xmlSetDocCompressMode:
7476 * @doc: the document
7477 * @mode: the compression ratio
7478 *
7479 * set the compression ratio for a document, ZLIB based
7480 * Correct values: 0 (uncompressed) to 9 (max compression)
7481 */
7482void
7483xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7484 if (doc == NULL) return;
7485 if (mode < 0) doc->compression = 0;
7486 else if (mode > 9) doc->compression = 9;
7487 else doc->compression = mode;
7488}
7489
7490/**
7491 * xmlGetCompressMode:
7492 *
7493 * get the default compression mode used, ZLIB based.
7494 * Returns 0 (uncompressed) to 9 (max compression)
7495 */
7496int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007497xmlGetCompressMode(void)
7498{
7499 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00007500}
7501
7502/**
7503 * xmlSetCompressMode:
7504 * @mode: the compression ratio
7505 *
7506 * set the default compression mode used, ZLIB based
7507 * Correct values: 0 (uncompressed) to 9 (max compression)
7508 */
7509void
7510xmlSetCompressMode(int mode) {
7511 if (mode < 0) xmlCompressMode = 0;
7512 else if (mode > 9) xmlCompressMode = 9;
7513 else xmlCompressMode = mode;
7514}
7515
7516/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007517 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00007518 * @f: the FILE*
7519 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00007520 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007521 *
7522 * Dump an XML document to an open FILE.
7523 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007524 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007525 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7526 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007527 */
7528int
Daniel Veillard9e412302002-06-10 15:59:44 +00007529xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007530 xmlOutputBufferPtr buf;
7531 const char * encoding;
7532 xmlCharEncodingHandlerPtr handler = NULL;
7533 int ret;
7534
7535 if (cur == NULL) {
7536#ifdef DEBUG_TREE
7537 xmlGenericError(xmlGenericErrorContext,
7538 "xmlDocDump : document == NULL\n");
7539#endif
7540 return(-1);
7541 }
7542 encoding = (const char *) cur->encoding;
7543
7544 if (encoding != NULL) {
7545 xmlCharEncoding enc;
7546
7547 enc = xmlParseCharEncoding(encoding);
7548
7549 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7550 xmlGenericError(xmlGenericErrorContext,
7551 "xmlDocDump: document not in UTF8\n");
7552 return(-1);
7553 }
7554 if (enc != XML_CHAR_ENCODING_UTF8) {
7555 handler = xmlFindCharEncodingHandler(encoding);
7556 if (handler == NULL) {
7557 xmlFree((char *) cur->encoding);
7558 cur->encoding = NULL;
7559 }
7560 }
7561 }
7562 buf = xmlOutputBufferCreateFile(f, handler);
7563 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00007564 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007565
7566 ret = xmlOutputBufferClose(buf);
7567 return(ret);
7568}
7569
7570/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007571 * xmlDocDump:
7572 * @f: the FILE*
7573 * @cur: the document
7574 *
7575 * Dump an XML document to an open FILE.
7576 *
7577 * returns: the number of bytes written or -1 in case of failure.
7578 */
7579int
7580xmlDocDump(FILE *f, xmlDocPtr cur) {
7581 return(xmlDocFormatDump (f, cur, 0));
7582}
7583
7584/**
Owen Taylor3473f882001-02-23 17:55:21 +00007585 * xmlSaveFileTo:
7586 * @buf: an output I/O buffer
7587 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007588 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00007589 *
7590 * Dump an XML document to an I/O buffer.
7591 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007592 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007593 */
7594int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007595xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007596 int ret;
7597
7598 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007599 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007600 ret = xmlOutputBufferClose(buf);
7601 return(ret);
7602}
7603
7604/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00007605 * xmlSaveFormatFileTo:
7606 * @buf: an output I/O buffer
7607 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007608 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00007609 * @format: should formatting spaces been added
7610 *
7611 * Dump an XML document to an I/O buffer.
7612 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007613 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007614 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7615 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardeefd4492001-04-28 16:55:50 +00007616 */
7617int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007618xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00007619 int ret;
7620
7621 if (buf == NULL) return(0);
7622 xmlDocContentDumpOutput(buf, cur, encoding, format);
7623 ret = xmlOutputBufferClose(buf);
7624 return(ret);
7625}
7626
7627/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00007628 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00007629 * @filename: the filename or URL to output
7630 * @cur: the document being saved
7631 * @encoding: the name of the encoding to use or NULL.
7632 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00007633 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00007634 * Dump an XML document to a file or an URL.
7635 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007636 * Returns the number of bytes written or -1 in case of error.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007637 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7638 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007639 */
7640int
Daniel Veillardf012a642001-07-23 19:10:52 +00007641xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
7642 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00007643 xmlOutputBufferPtr buf;
7644 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00007645 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00007646 int ret;
7647
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00007648 if (cur == NULL)
7649 return(-1);
7650
Daniel Veillardfb25a512002-01-13 20:32:08 +00007651 if (encoding == NULL)
7652 encoding = (const char *) cur->encoding;
7653
Owen Taylor3473f882001-02-23 17:55:21 +00007654 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007655
7656 enc = xmlParseCharEncoding(encoding);
7657 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7658 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007659 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007660 return(-1);
7661 }
7662 if (enc != XML_CHAR_ENCODING_UTF8) {
7663 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00007664 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007665 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007666 }
7667 }
7668
Daniel Veillardf012a642001-07-23 19:10:52 +00007669#ifdef HAVE_ZLIB_H
7670 if (cur->compression < 0) cur->compression = xmlCompressMode;
7671#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007672 /*
7673 * save the content to a temp buffer.
7674 */
Daniel Veillardf012a642001-07-23 19:10:52 +00007675 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00007676 if (buf == NULL) return(-1);
7677
Daniel Veillardf012a642001-07-23 19:10:52 +00007678 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007679
7680 ret = xmlOutputBufferClose(buf);
7681 return(ret);
7682}
7683
Daniel Veillardf012a642001-07-23 19:10:52 +00007684
7685/**
7686 * xmlSaveFileEnc:
7687 * @filename: the filename (or URL)
7688 * @cur: the document
7689 * @encoding: the name of an encoding (or NULL)
7690 *
7691 * Dump an XML document, converting it to the given encoding
7692 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007693 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00007694 */
7695int
7696xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
7697 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
7698}
7699
Owen Taylor3473f882001-02-23 17:55:21 +00007700/**
Daniel Veillard67fee942001-04-26 18:59:03 +00007701 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00007702 * @filename: the filename (or URL)
7703 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00007704 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007705 *
7706 * Dump an XML document to a file. Will use compression if
7707 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00007708 * used. If @format is set then the document will be indented on output.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007709 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7710 * or xmlKeepBlanksDefault(0) was called
Daniel Veillard67fee942001-04-26 18:59:03 +00007711 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007712 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007713 */
7714int
Daniel Veillard67fee942001-04-26 18:59:03 +00007715xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007716 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00007717}
7718
Daniel Veillard67fee942001-04-26 18:59:03 +00007719/**
7720 * xmlSaveFile:
7721 * @filename: the filename (or URL)
7722 * @cur: the document
7723 *
7724 * Dump an XML document to a file. Will use compression if
7725 * compiled in and enabled. If @filename is "-" the stdout file is
7726 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00007727 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00007728 */
7729int
7730xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007731 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00007732}
7733