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