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