blob: 7df24d5e13f57526454ad06b52429050779a7545 [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 }
450 return(cur);
451}
452
453/**
454 * xmlFreeDtd:
455 * @cur: the DTD structure to free up
456 *
457 * Free a DTD structure.
458 */
459void
460xmlFreeDtd(xmlDtdPtr cur) {
461 if (cur == NULL) {
462#ifdef DEBUG_TREE
463 xmlGenericError(xmlGenericErrorContext,
464 "xmlFreeDtd : DTD == NULL\n");
465#endif
466 return;
467 }
Daniel Veillard5335dc52003-01-01 20:59:38 +0000468
469 if (xmlDeregisterNodeDefaultValue)
470 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
471
Owen Taylor3473f882001-02-23 17:55:21 +0000472 if (cur->children != NULL) {
473 xmlNodePtr next, c = cur->children;
474
475 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000476 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000477 * indexes.
478 */
479 while (c != NULL) {
480 next = c->next;
481 if (c->type == XML_COMMENT_NODE) {
482 xmlUnlinkNode(c);
483 xmlFreeNode(c);
484 }
485 c = next;
486 }
487 }
488 if (cur->name != NULL) xmlFree((char *) cur->name);
489 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
490 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
491 /* TODO !!! */
492 if (cur->notations != NULL)
493 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
494
495 if (cur->elements != NULL)
496 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
497 if (cur->attributes != NULL)
498 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
499 if (cur->entities != NULL)
500 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
501 if (cur->pentities != NULL)
502 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
503
Owen Taylor3473f882001-02-23 17:55:21 +0000504 xmlFree(cur);
505}
506
507/**
508 * xmlNewDoc:
509 * @version: xmlChar string giving the version of XML "1.0"
510 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000511 * Creates a new XML document
512 *
Owen Taylor3473f882001-02-23 17:55:21 +0000513 * Returns a new document
514 */
515xmlDocPtr
516xmlNewDoc(const xmlChar *version) {
517 xmlDocPtr cur;
518
519 if (version == NULL)
520 version = (const xmlChar *) "1.0";
521
522 /*
523 * Allocate a new document and fill the fields.
524 */
525 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
526 if (cur == NULL) {
527 xmlGenericError(xmlGenericErrorContext,
528 "xmlNewDoc : malloc failed\n");
529 return(NULL);
530 }
531 memset(cur, 0, sizeof(xmlDoc));
532 cur->type = XML_DOCUMENT_NODE;
533
534 cur->version = xmlStrdup(version);
535 cur->standalone = -1;
536 cur->compression = -1; /* not initialized */
537 cur->doc = cur;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000538 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +0000539
540 if (xmlRegisterNodeDefaultValue)
541 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000542 return(cur);
543}
544
545/**
546 * xmlFreeDoc:
547 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +0000548 *
549 * Free up all the structures used by a document, tree included.
550 */
551void
552xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000553 xmlDtdPtr extSubset, intSubset;
554
Owen Taylor3473f882001-02-23 17:55:21 +0000555 if (cur == NULL) {
556#ifdef DEBUG_TREE
557 xmlGenericError(xmlGenericErrorContext,
558 "xmlFreeDoc : document == NULL\n");
559#endif
560 return;
561 }
Daniel Veillard5335dc52003-01-01 20:59:38 +0000562
563 if (xmlDeregisterNodeDefaultValue)
564 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
565
Daniel Veillard76d66f42001-05-16 21:05:17 +0000566 /*
567 * Do this before freeing the children list to avoid ID lookups
568 */
569 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
570 cur->ids = NULL;
571 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
572 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000573 extSubset = cur->extSubset;
574 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +0000575 if (intSubset == extSubset)
576 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000577 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000578 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000579 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000580 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000581 }
Daniel Veillarda9142e72001-06-19 11:07:54 +0000582 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000583 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000584 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000585 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000586 }
587
588 if (cur->children != NULL) xmlFreeNodeList(cur->children);
589
Owen Taylor3473f882001-02-23 17:55:21 +0000590 if (cur->version != NULL) xmlFree((char *) cur->version);
591 if (cur->name != NULL) xmlFree((char *) cur->name);
592 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +0000593 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +0000594 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000595 xmlFree(cur);
596}
597
598/**
599 * xmlStringLenGetNodeList:
600 * @doc: the document
601 * @value: the value of the text
602 * @len: the length of the string value
603 *
604 * Parse the value string and build the node list associated. Should
605 * produce a flat tree with only TEXTs and ENTITY_REFs.
606 * Returns a pointer to the first child
607 */
608xmlNodePtr
609xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
610 xmlNodePtr ret = NULL, last = NULL;
611 xmlNodePtr node;
612 xmlChar *val;
613 const xmlChar *cur = value;
614 const xmlChar *q;
615 xmlEntityPtr ent;
616
617 if (value == NULL) return(NULL);
618
619 q = cur;
620 while ((*cur != 0) && (cur - value < len)) {
621 if (*cur == '&') {
622 /*
623 * Save the current text.
624 */
625 if (cur != q) {
626 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
627 xmlNodeAddContentLen(last, q, cur - q);
628 } else {
629 node = xmlNewDocTextLen(doc, q, cur - q);
630 if (node == NULL) return(ret);
631 if (last == NULL)
632 last = ret = node;
633 else {
634 last->next = node;
635 node->prev = last;
636 last = node;
637 }
638 }
639 }
640 /*
641 * Read the entity string
642 */
643 cur++;
644 q = cur;
645 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
646 if ((*cur == 0) || (cur - value >= len)) {
647#ifdef DEBUG_TREE
648 xmlGenericError(xmlGenericErrorContext,
649 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
650#endif
651 return(ret);
652 }
653 if (cur != q) {
654 /*
655 * Predefined entities don't generate nodes
656 */
657 val = xmlStrndup(q, cur - q);
658 ent = xmlGetDocEntity(doc, val);
659 if ((ent != NULL) &&
660 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
661 if (last == NULL) {
662 node = xmlNewDocText(doc, ent->content);
663 last = ret = node;
664 } else
665 xmlNodeAddContent(last, ent->content);
666
667 } else {
668 /*
669 * Create a new REFERENCE_REF node
670 */
671 node = xmlNewReference(doc, val);
672 if (node == NULL) {
673 if (val != NULL) xmlFree(val);
674 return(ret);
675 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000676 else if ((ent != NULL) && (ent->children == NULL)) {
677 xmlNodePtr tmp;
678
679 ent->children =
680 xmlStringGetNodeList(doc, (const xmlChar*)node->content);
681 tmp = ent->children;
682 while (tmp) {
683 tmp->parent = (xmlNodePtr)ent;
684 tmp = tmp->next;
685 }
686 }
Owen Taylor3473f882001-02-23 17:55:21 +0000687 if (last == NULL)
688 last = ret = node;
689 else {
690 last->next = node;
691 node->prev = last;
692 last = node;
693 }
694 }
695 xmlFree(val);
696 }
697 cur++;
698 q = cur;
699 } else
700 cur++;
701 }
702 if (cur != q) {
703 /*
704 * Handle the last piece of text.
705 */
706 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
707 xmlNodeAddContentLen(last, q, cur - q);
708 } else {
709 node = xmlNewDocTextLen(doc, q, cur - q);
710 if (node == NULL) return(ret);
711 if (last == NULL)
712 last = ret = node;
713 else {
714 last->next = node;
715 node->prev = last;
716 last = node;
717 }
718 }
719 }
720 return(ret);
721}
722
723/**
724 * xmlStringGetNodeList:
725 * @doc: the document
726 * @value: the value of the attribute
727 *
728 * Parse the value string and build the node list associated. Should
729 * produce a flat tree with only TEXTs and ENTITY_REFs.
730 * Returns a pointer to the first child
731 */
732xmlNodePtr
733xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
734 xmlNodePtr ret = NULL, last = NULL;
735 xmlNodePtr node;
736 xmlChar *val;
737 const xmlChar *cur = value;
738 const xmlChar *q;
739 xmlEntityPtr ent;
740
741 if (value == NULL) return(NULL);
742
743 q = cur;
744 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000745 if (cur[0] == '&') {
746 int charval = 0;
747 xmlChar tmp;
748
Owen Taylor3473f882001-02-23 17:55:21 +0000749 /*
750 * Save the current text.
751 */
752 if (cur != q) {
753 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
754 xmlNodeAddContentLen(last, q, cur - q);
755 } else {
756 node = xmlNewDocTextLen(doc, q, cur - q);
757 if (node == NULL) return(ret);
758 if (last == NULL)
759 last = ret = node;
760 else {
761 last->next = node;
762 node->prev = last;
763 last = node;
764 }
765 }
766 }
Owen Taylor3473f882001-02-23 17:55:21 +0000767 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000768 if ((cur[1] == '#') && (cur[2] == 'x')) {
769 cur += 3;
770 tmp = *cur;
771 while (tmp != ';') { /* Non input consuming loop */
772 if ((tmp >= '0') && (tmp <= '9'))
773 charval = charval * 16 + (tmp - '0');
774 else if ((tmp >= 'a') && (tmp <= 'f'))
775 charval = charval * 16 + (tmp - 'a') + 10;
776 else if ((tmp >= 'A') && (tmp <= 'F'))
777 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +0000778 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000779 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000780 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000781 charval = 0;
782 break;
783 }
784 cur++;
785 tmp = *cur;
786 }
787 if (tmp == ';')
788 cur++;
789 q = cur;
790 } else if (cur[1] == '#') {
791 cur += 2;
792 tmp = *cur;
793 while (tmp != ';') { /* Non input consuming loops */
794 if ((tmp >= '0') && (tmp <= '9'))
795 charval = charval * 10 + (tmp - '0');
796 else {
797 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000798 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000799 charval = 0;
800 break;
801 }
802 cur++;
803 tmp = *cur;
804 }
805 if (tmp == ';')
806 cur++;
807 q = cur;
808 } else {
809 /*
810 * Read the entity string
811 */
812 cur++;
813 q = cur;
814 while ((*cur != 0) && (*cur != ';')) cur++;
815 if (*cur == 0) {
816#ifdef DEBUG_TREE
817 xmlGenericError(xmlGenericErrorContext,
818 "xmlStringGetNodeList: unterminated entity %30s\n", q);
819#endif
820 return(ret);
821 }
822 if (cur != q) {
823 /*
824 * Predefined entities don't generate nodes
825 */
826 val = xmlStrndup(q, cur - q);
827 ent = xmlGetDocEntity(doc, val);
828 if ((ent != NULL) &&
829 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
830 if (last == NULL) {
831 node = xmlNewDocText(doc, ent->content);
832 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +0000833 } else if (last->type != XML_TEXT_NODE) {
834 node = xmlNewDocText(doc, ent->content);
835 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000836 } else
837 xmlNodeAddContent(last, ent->content);
838
839 } else {
840 /*
841 * Create a new REFERENCE_REF node
842 */
843 node = xmlNewReference(doc, val);
844 if (node == NULL) {
845 if (val != NULL) xmlFree(val);
846 return(ret);
847 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000848 else if ((ent != NULL) && (ent->children == NULL)) {
849 xmlNodePtr temp;
850
851 ent->children = xmlStringGetNodeList(doc,
852 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +0000853 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000854 temp = ent->children;
855 while (temp) {
856 temp->parent = (xmlNodePtr)ent;
857 temp = temp->next;
858 }
859 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000860 if (last == NULL) {
861 last = ret = node;
862 } else {
863 last = xmlAddNextSibling(last, node);
864 }
865 }
866 xmlFree(val);
867 }
868 cur++;
869 q = cur;
870 }
871 if (charval != 0) {
872 xmlChar buf[10];
873 int len;
874
875 len = xmlCopyCharMultiByte(buf, charval);
876 buf[len] = 0;
877 node = xmlNewDocText(doc, buf);
878 if (node != NULL) {
879 if (last == NULL) {
880 last = ret = node;
881 } else {
882 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000883 }
884 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000885
886 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000887 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000888 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000889 cur++;
890 }
Daniel Veillard75bea542001-05-11 17:41:21 +0000891 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000892 /*
893 * Handle the last piece of text.
894 */
895 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
896 xmlNodeAddContentLen(last, q, cur - q);
897 } else {
898 node = xmlNewDocTextLen(doc, q, cur - q);
899 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000900 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000901 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000902 } else {
903 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000904 }
905 }
906 }
907 return(ret);
908}
909
910/**
911 * xmlNodeListGetString:
912 * @doc: the document
913 * @list: a Node list
914 * @inLine: should we replace entity contents or show their external form
915 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000916 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +0000917 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000918 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +0000919 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +0000920 */
921xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +0000922xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
923{
Owen Taylor3473f882001-02-23 17:55:21 +0000924 xmlNodePtr node = list;
925 xmlChar *ret = NULL;
926 xmlEntityPtr ent;
927
Daniel Veillard7646b182002-04-20 06:41:40 +0000928 if (list == NULL)
929 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000930
931 while (node != NULL) {
932 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +0000933 (node->type == XML_CDATA_SECTION_NODE)) {
934 if (inLine) {
935 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000936 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +0000937 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +0000938
Daniel Veillard7646b182002-04-20 06:41:40 +0000939 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
940 if (buffer != NULL) {
941 ret = xmlStrcat(ret, buffer);
942 xmlFree(buffer);
943 }
944 }
945 } else if (node->type == XML_ENTITY_REF_NODE) {
946 if (inLine) {
947 ent = xmlGetDocEntity(doc, node->name);
948 if (ent != NULL) {
949 xmlChar *buffer;
950
951 /* an entity content can be any "well balanced chunk",
952 * i.e. the result of the content [43] production:
953 * http://www.w3.org/TR/REC-xml#NT-content.
954 * So it can contain text, CDATA section or nested
955 * entity reference nodes (among others).
956 * -> we recursive call xmlNodeListGetString()
957 * which handles these types */
958 buffer = xmlNodeListGetString(doc, ent->children, 1);
959 if (buffer != NULL) {
960 ret = xmlStrcat(ret, buffer);
961 xmlFree(buffer);
962 }
963 } else {
964 ret = xmlStrcat(ret, node->content);
965 }
966 } else {
967 xmlChar buf[2];
968
969 buf[0] = '&';
970 buf[1] = 0;
971 ret = xmlStrncat(ret, buf, 1);
972 ret = xmlStrcat(ret, node->name);
973 buf[0] = ';';
974 buf[1] = 0;
975 ret = xmlStrncat(ret, buf, 1);
976 }
977 }
978#if 0
979 else {
980 xmlGenericError(xmlGenericErrorContext,
981 "xmlGetNodeListString : invalid node type %d\n",
982 node->type);
983 }
984#endif
985 node = node->next;
986 }
987 return (ret);
988}
Owen Taylor3473f882001-02-23 17:55:21 +0000989/**
990 * xmlNodeListGetRawString:
991 * @doc: the document
992 * @list: a Node list
993 * @inLine: should we replace entity contents or show their external form
994 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000995 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +0000996 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
997 * this function doesn't do any character encoding handling.
998 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +0000999 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001000 */
1001xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001002xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1003{
Owen Taylor3473f882001-02-23 17:55:21 +00001004 xmlNodePtr node = list;
1005 xmlChar *ret = NULL;
1006 xmlEntityPtr ent;
1007
Daniel Veillard7646b182002-04-20 06:41:40 +00001008 if (list == NULL)
1009 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001010
1011 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001012 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001013 (node->type == XML_CDATA_SECTION_NODE)) {
1014 if (inLine) {
1015 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001016 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001017 xmlChar *buffer;
1018
1019 buffer = xmlEncodeSpecialChars(doc, node->content);
1020 if (buffer != NULL) {
1021 ret = xmlStrcat(ret, buffer);
1022 xmlFree(buffer);
1023 }
1024 }
1025 } else if (node->type == XML_ENTITY_REF_NODE) {
1026 if (inLine) {
1027 ent = xmlGetDocEntity(doc, node->name);
1028 if (ent != NULL) {
1029 xmlChar *buffer;
1030
1031 /* an entity content can be any "well balanced chunk",
1032 * i.e. the result of the content [43] production:
1033 * http://www.w3.org/TR/REC-xml#NT-content.
1034 * So it can contain text, CDATA section or nested
1035 * entity reference nodes (among others).
1036 * -> we recursive call xmlNodeListGetRawString()
1037 * which handles these types */
1038 buffer =
1039 xmlNodeListGetRawString(doc, ent->children, 1);
1040 if (buffer != NULL) {
1041 ret = xmlStrcat(ret, buffer);
1042 xmlFree(buffer);
1043 }
1044 } else {
1045 ret = xmlStrcat(ret, node->content);
1046 }
1047 } else {
1048 xmlChar buf[2];
1049
1050 buf[0] = '&';
1051 buf[1] = 0;
1052 ret = xmlStrncat(ret, buf, 1);
1053 ret = xmlStrcat(ret, node->name);
1054 buf[0] = ';';
1055 buf[1] = 0;
1056 ret = xmlStrncat(ret, buf, 1);
1057 }
1058 }
Owen Taylor3473f882001-02-23 17:55:21 +00001059#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001060 else {
1061 xmlGenericError(xmlGenericErrorContext,
1062 "xmlGetNodeListString : invalid node type %d\n",
1063 node->type);
1064 }
Owen Taylor3473f882001-02-23 17:55:21 +00001065#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001066 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001067 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001068 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001069}
1070
1071/**
1072 * xmlNewProp:
1073 * @node: the holding node
1074 * @name: the name of the attribute
1075 * @value: the value of the attribute
1076 *
1077 * Create a new property carried by a node.
1078 * Returns a pointer to the attribute
1079 */
1080xmlAttrPtr
1081xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1082 xmlAttrPtr cur;
1083 xmlDocPtr doc = NULL;
1084
1085 if (name == NULL) {
1086#ifdef DEBUG_TREE
1087 xmlGenericError(xmlGenericErrorContext,
1088 "xmlNewProp : name == NULL\n");
1089#endif
1090 return(NULL);
1091 }
1092
1093 /*
1094 * Allocate a new property and fill the fields.
1095 */
1096 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1097 if (cur == NULL) {
1098 xmlGenericError(xmlGenericErrorContext,
1099 "xmlNewProp : malloc failed\n");
1100 return(NULL);
1101 }
1102 memset(cur, 0, sizeof(xmlAttr));
1103 cur->type = XML_ATTRIBUTE_NODE;
1104
1105 cur->parent = node;
1106 if (node != NULL) {
1107 doc = node->doc;
1108 cur->doc = doc;
1109 }
1110 cur->name = xmlStrdup(name);
1111 if (value != NULL) {
1112 xmlChar *buffer;
1113 xmlNodePtr tmp;
1114
1115 buffer = xmlEncodeEntitiesReentrant(doc, value);
1116 cur->children = xmlStringGetNodeList(doc, buffer);
1117 cur->last = NULL;
1118 tmp = cur->children;
1119 while (tmp != NULL) {
1120 tmp->parent = (xmlNodePtr) cur;
1121 tmp->doc = doc;
1122 if (tmp->next == NULL)
1123 cur->last = tmp;
1124 tmp = tmp->next;
1125 }
1126 xmlFree(buffer);
1127 }
1128
1129 /*
1130 * Add it at the end to preserve parsing order ...
1131 */
1132 if (node != NULL) {
1133 if (node->properties == NULL) {
1134 node->properties = cur;
1135 } else {
1136 xmlAttrPtr prev = node->properties;
1137
1138 while (prev->next != NULL) prev = prev->next;
1139 prev->next = cur;
1140 cur->prev = prev;
1141 }
1142 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001143
1144 if (xmlRegisterNodeDefaultValue)
1145 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001146 return(cur);
1147}
1148
1149/**
1150 * xmlNewNsProp:
1151 * @node: the holding node
1152 * @ns: the namespace
1153 * @name: the name of the attribute
1154 * @value: the value of the attribute
1155 *
1156 * Create a new property tagged with a namespace and carried by a node.
1157 * Returns a pointer to the attribute
1158 */
1159xmlAttrPtr
1160xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1161 const xmlChar *value) {
1162 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001163 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001164
1165 if (name == NULL) {
1166#ifdef DEBUG_TREE
1167 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001168 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001169#endif
1170 return(NULL);
1171 }
1172
1173 /*
1174 * Allocate a new property and fill the fields.
1175 */
1176 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1177 if (cur == NULL) {
1178 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001179 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001180 return(NULL);
1181 }
1182 memset(cur, 0, sizeof(xmlAttr));
1183 cur->type = XML_ATTRIBUTE_NODE;
1184
1185 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001186 if (node != NULL) {
1187 doc = node->doc;
1188 cur->doc = doc;
1189 }
Owen Taylor3473f882001-02-23 17:55:21 +00001190 cur->ns = ns;
1191 cur->name = xmlStrdup(name);
1192 if (value != NULL) {
1193 xmlChar *buffer;
1194 xmlNodePtr tmp;
1195
Daniel Veillarda682b212001-06-07 19:59:42 +00001196 buffer = xmlEncodeEntitiesReentrant(doc, value);
1197 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001198 cur->last = NULL;
1199 tmp = cur->children;
1200 while (tmp != NULL) {
1201 tmp->parent = (xmlNodePtr) cur;
1202 if (tmp->next == NULL)
1203 cur->last = tmp;
1204 tmp = tmp->next;
1205 }
1206 xmlFree(buffer);
1207 }
1208
1209 /*
1210 * Add it at the end to preserve parsing order ...
1211 */
1212 if (node != NULL) {
1213 if (node->properties == NULL) {
1214 node->properties = cur;
1215 } else {
1216 xmlAttrPtr prev = node->properties;
1217
1218 while (prev->next != NULL) prev = prev->next;
1219 prev->next = cur;
1220 cur->prev = prev;
1221 }
1222 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001223
1224 if (xmlRegisterNodeDefaultValue)
1225 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001226 return(cur);
1227}
1228
1229/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001230 * xmlNewNsPropEatName:
1231 * @node: the holding node
1232 * @ns: the namespace
1233 * @name: the name of the attribute
1234 * @value: the value of the attribute
1235 *
1236 * Create a new property tagged with a namespace and carried by a node.
1237 * Returns a pointer to the attribute
1238 */
1239xmlAttrPtr
1240xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1241 const xmlChar *value) {
1242 xmlAttrPtr cur;
1243 xmlDocPtr doc = NULL;
1244
1245 if (name == NULL) {
1246#ifdef DEBUG_TREE
1247 xmlGenericError(xmlGenericErrorContext,
1248 "xmlNewNsPropEatName : name == NULL\n");
1249#endif
1250 return(NULL);
1251 }
1252
1253 /*
1254 * Allocate a new property and fill the fields.
1255 */
1256 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1257 if (cur == NULL) {
1258 xmlGenericError(xmlGenericErrorContext,
1259 "xmlNewNsPropEatName : malloc failed\n");
1260 return(NULL);
1261 }
1262 memset(cur, 0, sizeof(xmlAttr));
1263 cur->type = XML_ATTRIBUTE_NODE;
1264
1265 cur->parent = node;
1266 if (node != NULL) {
1267 doc = node->doc;
1268 cur->doc = doc;
1269 }
1270 cur->ns = ns;
1271 cur->name = name;
1272 if (value != NULL) {
1273 xmlChar *buffer;
1274 xmlNodePtr tmp;
1275
1276 buffer = xmlEncodeEntitiesReentrant(doc, value);
1277 cur->children = xmlStringGetNodeList(doc, buffer);
1278 cur->last = NULL;
1279 tmp = cur->children;
1280 while (tmp != NULL) {
1281 tmp->parent = (xmlNodePtr) cur;
1282 if (tmp->next == NULL)
1283 cur->last = tmp;
1284 tmp = tmp->next;
1285 }
1286 xmlFree(buffer);
1287 }
1288
1289 /*
1290 * Add it at the end to preserve parsing order ...
1291 */
1292 if (node != NULL) {
1293 if (node->properties == NULL) {
1294 node->properties = cur;
1295 } else {
1296 xmlAttrPtr prev = node->properties;
1297
1298 while (prev->next != NULL) prev = prev->next;
1299 prev->next = cur;
1300 cur->prev = prev;
1301 }
1302 }
1303 return(cur);
1304}
1305
1306/**
Owen Taylor3473f882001-02-23 17:55:21 +00001307 * xmlNewDocProp:
1308 * @doc: the document
1309 * @name: the name of the attribute
1310 * @value: the value of the attribute
1311 *
1312 * Create a new property carried by a document.
1313 * Returns a pointer to the attribute
1314 */
1315xmlAttrPtr
1316xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1317 xmlAttrPtr cur;
1318
1319 if (name == NULL) {
1320#ifdef DEBUG_TREE
1321 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001322 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001323#endif
1324 return(NULL);
1325 }
1326
1327 /*
1328 * Allocate a new property and fill the fields.
1329 */
1330 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1331 if (cur == NULL) {
1332 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001333 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001334 return(NULL);
1335 }
1336 memset(cur, 0, sizeof(xmlAttr));
1337 cur->type = XML_ATTRIBUTE_NODE;
1338
1339 cur->name = xmlStrdup(name);
1340 cur->doc = doc;
1341 if (value != NULL) {
1342 xmlNodePtr tmp;
1343
1344 cur->children = xmlStringGetNodeList(doc, value);
1345 cur->last = NULL;
1346
1347 tmp = cur->children;
1348 while (tmp != NULL) {
1349 tmp->parent = (xmlNodePtr) cur;
1350 if (tmp->next == NULL)
1351 cur->last = tmp;
1352 tmp = tmp->next;
1353 }
1354 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001355
1356 if (xmlRegisterNodeDefaultValue)
1357 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001358 return(cur);
1359}
1360
1361/**
1362 * xmlFreePropList:
1363 * @cur: the first property in the list
1364 *
1365 * Free a property and all its siblings, all the children are freed too.
1366 */
1367void
1368xmlFreePropList(xmlAttrPtr cur) {
1369 xmlAttrPtr next;
1370 if (cur == NULL) {
1371#ifdef DEBUG_TREE
1372 xmlGenericError(xmlGenericErrorContext,
1373 "xmlFreePropList : property == NULL\n");
1374#endif
1375 return;
1376 }
1377 while (cur != NULL) {
1378 next = cur->next;
1379 xmlFreeProp(cur);
1380 cur = next;
1381 }
1382}
1383
1384/**
1385 * xmlFreeProp:
1386 * @cur: an attribute
1387 *
1388 * Free one attribute, all the content is freed too
1389 */
1390void
1391xmlFreeProp(xmlAttrPtr cur) {
1392 if (cur == NULL) {
1393#ifdef DEBUG_TREE
1394 xmlGenericError(xmlGenericErrorContext,
1395 "xmlFreeProp : property == NULL\n");
1396#endif
1397 return;
1398 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001399
1400 if (xmlDeregisterNodeDefaultValue)
1401 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1402
Owen Taylor3473f882001-02-23 17:55:21 +00001403 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001404 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1405 ((cur->parent->doc->intSubset != NULL) ||
1406 (cur->parent->doc->extSubset != NULL))) {
1407 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1408 xmlRemoveID(cur->parent->doc, cur);
1409 }
Owen Taylor3473f882001-02-23 17:55:21 +00001410 if (cur->name != NULL) xmlFree((char *) cur->name);
1411 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001412 xmlFree(cur);
1413}
1414
1415/**
1416 * xmlRemoveProp:
1417 * @cur: an attribute
1418 *
1419 * Unlink and free one attribute, all the content is freed too
1420 * Note this doesn't work for namespace definition attributes
1421 *
1422 * Returns 0 if success and -1 in case of error.
1423 */
1424int
1425xmlRemoveProp(xmlAttrPtr cur) {
1426 xmlAttrPtr tmp;
1427 if (cur == NULL) {
1428#ifdef DEBUG_TREE
1429 xmlGenericError(xmlGenericErrorContext,
1430 "xmlRemoveProp : cur == NULL\n");
1431#endif
1432 return(-1);
1433 }
1434 if (cur->parent == NULL) {
1435#ifdef DEBUG_TREE
1436 xmlGenericError(xmlGenericErrorContext,
1437 "xmlRemoveProp : cur->parent == NULL\n");
1438#endif
1439 return(-1);
1440 }
1441 tmp = cur->parent->properties;
1442 if (tmp == cur) {
1443 cur->parent->properties = cur->next;
1444 xmlFreeProp(cur);
1445 return(0);
1446 }
1447 while (tmp != NULL) {
1448 if (tmp->next == cur) {
1449 tmp->next = cur->next;
1450 if (tmp->next != NULL)
1451 tmp->next->prev = tmp;
1452 xmlFreeProp(cur);
1453 return(0);
1454 }
1455 tmp = tmp->next;
1456 }
1457#ifdef DEBUG_TREE
1458 xmlGenericError(xmlGenericErrorContext,
1459 "xmlRemoveProp : attribute not owned by its node\n");
1460#endif
1461 return(-1);
1462}
1463
1464/**
1465 * xmlNewPI:
1466 * @name: the processing instruction name
1467 * @content: the PI content
1468 *
1469 * Creation of a processing instruction element.
1470 * Returns a pointer to the new node object.
1471 */
1472xmlNodePtr
1473xmlNewPI(const xmlChar *name, const xmlChar *content) {
1474 xmlNodePtr cur;
1475
1476 if (name == NULL) {
1477#ifdef DEBUG_TREE
1478 xmlGenericError(xmlGenericErrorContext,
1479 "xmlNewPI : name == NULL\n");
1480#endif
1481 return(NULL);
1482 }
1483
1484 /*
1485 * Allocate a new node and fill the fields.
1486 */
1487 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1488 if (cur == NULL) {
1489 xmlGenericError(xmlGenericErrorContext,
1490 "xmlNewPI : malloc failed\n");
1491 return(NULL);
1492 }
1493 memset(cur, 0, sizeof(xmlNode));
1494 cur->type = XML_PI_NODE;
1495
1496 cur->name = xmlStrdup(name);
1497 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001498 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001499 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001500
1501 if (xmlRegisterNodeDefaultValue)
1502 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001503 return(cur);
1504}
1505
1506/**
1507 * xmlNewNode:
1508 * @ns: namespace if any
1509 * @name: the node name
1510 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001511 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001512 *
1513 * Returns a pointer to the new node object.
1514 */
1515xmlNodePtr
1516xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1517 xmlNodePtr cur;
1518
1519 if (name == NULL) {
1520#ifdef DEBUG_TREE
1521 xmlGenericError(xmlGenericErrorContext,
1522 "xmlNewNode : name == NULL\n");
1523#endif
1524 return(NULL);
1525 }
1526
1527 /*
1528 * Allocate a new node and fill the fields.
1529 */
1530 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1531 if (cur == NULL) {
1532 xmlGenericError(xmlGenericErrorContext,
1533 "xmlNewNode : malloc failed\n");
1534 return(NULL);
1535 }
1536 memset(cur, 0, sizeof(xmlNode));
1537 cur->type = XML_ELEMENT_NODE;
1538
1539 cur->name = xmlStrdup(name);
1540 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001541
1542 if (xmlRegisterNodeDefaultValue)
1543 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001544 return(cur);
1545}
1546
1547/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001548 * xmlNewNodeEatName:
1549 * @ns: namespace if any
1550 * @name: the node name
1551 *
1552 * Creation of a new node element. @ns is optional (NULL).
1553 *
1554 * Returns a pointer to the new node object.
1555 */
1556xmlNodePtr
1557xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
1558 xmlNodePtr cur;
1559
1560 if (name == NULL) {
1561#ifdef DEBUG_TREE
1562 xmlGenericError(xmlGenericErrorContext,
1563 "xmlNewNode : name == NULL\n");
1564#endif
1565 return(NULL);
1566 }
1567
1568 /*
1569 * Allocate a new node and fill the fields.
1570 */
1571 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1572 if (cur == NULL) {
1573 xmlGenericError(xmlGenericErrorContext,
1574 "xmlNewNode : malloc failed\n");
1575 return(NULL);
1576 }
1577 memset(cur, 0, sizeof(xmlNode));
1578 cur->type = XML_ELEMENT_NODE;
1579
1580 cur->name = name;
1581 cur->ns = ns;
1582 return(cur);
1583}
1584
1585/**
Owen Taylor3473f882001-02-23 17:55:21 +00001586 * xmlNewDocNode:
1587 * @doc: the document
1588 * @ns: namespace if any
1589 * @name: the node name
1590 * @content: the XML text content if any
1591 *
1592 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001593 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001594 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1595 * references, but XML special chars need to be escaped first by using
1596 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1597 * need entities support.
1598 *
1599 * Returns a pointer to the new node object.
1600 */
1601xmlNodePtr
1602xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1603 const xmlChar *name, const xmlChar *content) {
1604 xmlNodePtr cur;
1605
1606 cur = xmlNewNode(ns, name);
1607 if (cur != NULL) {
1608 cur->doc = doc;
1609 if (content != NULL) {
1610 cur->children = xmlStringGetNodeList(doc, content);
1611 UPDATE_LAST_CHILD_AND_PARENT(cur)
1612 }
1613 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001614
Owen Taylor3473f882001-02-23 17:55:21 +00001615 return(cur);
1616}
1617
Daniel Veillard46de64e2002-05-29 08:21:33 +00001618/**
1619 * xmlNewDocNodeEatName:
1620 * @doc: the document
1621 * @ns: namespace if any
1622 * @name: the node name
1623 * @content: the XML text content if any
1624 *
1625 * Creation of a new node element within a document. @ns and @content
1626 * are optional (NULL).
1627 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1628 * references, but XML special chars need to be escaped first by using
1629 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1630 * need entities support.
1631 *
1632 * Returns a pointer to the new node object.
1633 */
1634xmlNodePtr
1635xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
1636 xmlChar *name, const xmlChar *content) {
1637 xmlNodePtr cur;
1638
1639 cur = xmlNewNodeEatName(ns, name);
1640 if (cur != NULL) {
1641 cur->doc = doc;
1642 if (content != NULL) {
1643 cur->children = xmlStringGetNodeList(doc, content);
1644 UPDATE_LAST_CHILD_AND_PARENT(cur)
1645 }
1646 }
1647 return(cur);
1648}
1649
Owen Taylor3473f882001-02-23 17:55:21 +00001650
1651/**
1652 * xmlNewDocRawNode:
1653 * @doc: the document
1654 * @ns: namespace if any
1655 * @name: the node name
1656 * @content: the text content if any
1657 *
1658 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001659 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001660 *
1661 * Returns a pointer to the new node object.
1662 */
1663xmlNodePtr
1664xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1665 const xmlChar *name, const xmlChar *content) {
1666 xmlNodePtr cur;
1667
1668 cur = xmlNewNode(ns, name);
1669 if (cur != NULL) {
1670 cur->doc = doc;
1671 if (content != NULL) {
1672 cur->children = xmlNewDocText(doc, content);
1673 UPDATE_LAST_CHILD_AND_PARENT(cur)
1674 }
1675 }
1676 return(cur);
1677}
1678
1679/**
1680 * xmlNewDocFragment:
1681 * @doc: the document owning the fragment
1682 *
1683 * Creation of a new Fragment node.
1684 * Returns a pointer to the new node object.
1685 */
1686xmlNodePtr
1687xmlNewDocFragment(xmlDocPtr doc) {
1688 xmlNodePtr cur;
1689
1690 /*
1691 * Allocate a new DocumentFragment node and fill the fields.
1692 */
1693 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1694 if (cur == NULL) {
1695 xmlGenericError(xmlGenericErrorContext,
1696 "xmlNewDocFragment : malloc failed\n");
1697 return(NULL);
1698 }
1699 memset(cur, 0, sizeof(xmlNode));
1700 cur->type = XML_DOCUMENT_FRAG_NODE;
1701
1702 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001703
1704 if (xmlRegisterNodeDefaultValue)
1705 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001706 return(cur);
1707}
1708
1709/**
1710 * xmlNewText:
1711 * @content: the text content
1712 *
1713 * Creation of a new text node.
1714 * Returns a pointer to the new node object.
1715 */
1716xmlNodePtr
1717xmlNewText(const xmlChar *content) {
1718 xmlNodePtr cur;
1719
1720 /*
1721 * Allocate a new node and fill the fields.
1722 */
1723 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1724 if (cur == NULL) {
1725 xmlGenericError(xmlGenericErrorContext,
1726 "xmlNewText : malloc failed\n");
1727 return(NULL);
1728 }
1729 memset(cur, 0, sizeof(xmlNode));
1730 cur->type = XML_TEXT_NODE;
1731
1732 cur->name = xmlStringText;
1733 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001734 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001735 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001736
1737 if (xmlRegisterNodeDefaultValue)
1738 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001739 return(cur);
1740}
1741
1742/**
1743 * xmlNewTextChild:
1744 * @parent: the parent node
1745 * @ns: a namespace if any
1746 * @name: the name of the child
1747 * @content: the text content of the child if any.
1748 *
1749 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001750 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001751 * a child TEXT node will be created containing the string content.
1752 *
1753 * Returns a pointer to the new node object.
1754 */
1755xmlNodePtr
1756xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1757 const xmlChar *name, const xmlChar *content) {
1758 xmlNodePtr cur, prev;
1759
1760 if (parent == NULL) {
1761#ifdef DEBUG_TREE
1762 xmlGenericError(xmlGenericErrorContext,
1763 "xmlNewTextChild : parent == NULL\n");
1764#endif
1765 return(NULL);
1766 }
1767
1768 if (name == NULL) {
1769#ifdef DEBUG_TREE
1770 xmlGenericError(xmlGenericErrorContext,
1771 "xmlNewTextChild : name == NULL\n");
1772#endif
1773 return(NULL);
1774 }
1775
1776 /*
1777 * Allocate a new node
1778 */
1779 if (ns == NULL)
1780 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1781 else
1782 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1783 if (cur == NULL) return(NULL);
1784
1785 /*
1786 * add the new element at the end of the children list.
1787 */
1788 cur->type = XML_ELEMENT_NODE;
1789 cur->parent = parent;
1790 cur->doc = parent->doc;
1791 if (parent->children == NULL) {
1792 parent->children = cur;
1793 parent->last = cur;
1794 } else {
1795 prev = parent->last;
1796 prev->next = cur;
1797 cur->prev = prev;
1798 parent->last = cur;
1799 }
1800
1801 return(cur);
1802}
1803
1804/**
1805 * xmlNewCharRef:
1806 * @doc: the document
1807 * @name: the char ref string, starting with # or "&# ... ;"
1808 *
1809 * Creation of a new character reference node.
1810 * Returns a pointer to the new node object.
1811 */
1812xmlNodePtr
1813xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1814 xmlNodePtr cur;
1815
1816 /*
1817 * Allocate a new node and fill the fields.
1818 */
1819 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1820 if (cur == NULL) {
1821 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001822 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001823 return(NULL);
1824 }
1825 memset(cur, 0, sizeof(xmlNode));
1826 cur->type = XML_ENTITY_REF_NODE;
1827
1828 cur->doc = doc;
1829 if (name[0] == '&') {
1830 int len;
1831 name++;
1832 len = xmlStrlen(name);
1833 if (name[len - 1] == ';')
1834 cur->name = xmlStrndup(name, len - 1);
1835 else
1836 cur->name = xmlStrndup(name, len);
1837 } else
1838 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00001839
1840 if (xmlRegisterNodeDefaultValue)
1841 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001842 return(cur);
1843}
1844
1845/**
1846 * xmlNewReference:
1847 * @doc: the document
1848 * @name: the reference name, or the reference string with & and ;
1849 *
1850 * Creation of a new reference node.
1851 * Returns a pointer to the new node object.
1852 */
1853xmlNodePtr
1854xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1855 xmlNodePtr cur;
1856 xmlEntityPtr ent;
1857
1858 /*
1859 * Allocate a new node and fill the fields.
1860 */
1861 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1862 if (cur == NULL) {
1863 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001864 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001865 return(NULL);
1866 }
1867 memset(cur, 0, sizeof(xmlNode));
1868 cur->type = XML_ENTITY_REF_NODE;
1869
1870 cur->doc = doc;
1871 if (name[0] == '&') {
1872 int len;
1873 name++;
1874 len = xmlStrlen(name);
1875 if (name[len - 1] == ';')
1876 cur->name = xmlStrndup(name, len - 1);
1877 else
1878 cur->name = xmlStrndup(name, len);
1879 } else
1880 cur->name = xmlStrdup(name);
1881
1882 ent = xmlGetDocEntity(doc, cur->name);
1883 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001884 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00001885 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001886 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00001887 * updated. Not sure if this is 100% correct.
1888 * -George
1889 */
1890 cur->children = (xmlNodePtr) ent;
1891 cur->last = (xmlNodePtr) ent;
1892 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001893
1894 if (xmlRegisterNodeDefaultValue)
1895 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001896 return(cur);
1897}
1898
1899/**
1900 * xmlNewDocText:
1901 * @doc: the document
1902 * @content: the text content
1903 *
1904 * Creation of a new text node within a document.
1905 * Returns a pointer to the new node object.
1906 */
1907xmlNodePtr
1908xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1909 xmlNodePtr cur;
1910
1911 cur = xmlNewText(content);
1912 if (cur != NULL) cur->doc = doc;
1913 return(cur);
1914}
1915
1916/**
1917 * xmlNewTextLen:
1918 * @content: the text content
1919 * @len: the text len.
1920 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001921 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00001922 * Returns a pointer to the new node object.
1923 */
1924xmlNodePtr
1925xmlNewTextLen(const xmlChar *content, int len) {
1926 xmlNodePtr cur;
1927
1928 /*
1929 * Allocate a new node and fill the fields.
1930 */
1931 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1932 if (cur == NULL) {
1933 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001934 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001935 return(NULL);
1936 }
1937 memset(cur, 0, sizeof(xmlNode));
1938 cur->type = XML_TEXT_NODE;
1939
1940 cur->name = xmlStringText;
1941 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001942 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001943 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001944
1945 if (xmlRegisterNodeDefaultValue)
1946 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001947 return(cur);
1948}
1949
1950/**
1951 * xmlNewDocTextLen:
1952 * @doc: the document
1953 * @content: the text content
1954 * @len: the text len.
1955 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001956 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00001957 * text node pertain to a given document.
1958 * Returns a pointer to the new node object.
1959 */
1960xmlNodePtr
1961xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1962 xmlNodePtr cur;
1963
1964 cur = xmlNewTextLen(content, len);
1965 if (cur != NULL) cur->doc = doc;
1966 return(cur);
1967}
1968
1969/**
1970 * xmlNewComment:
1971 * @content: the comment content
1972 *
1973 * Creation of a new node containing a comment.
1974 * Returns a pointer to the new node object.
1975 */
1976xmlNodePtr
1977xmlNewComment(const xmlChar *content) {
1978 xmlNodePtr cur;
1979
1980 /*
1981 * Allocate a new node and fill the fields.
1982 */
1983 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1984 if (cur == NULL) {
1985 xmlGenericError(xmlGenericErrorContext,
1986 "xmlNewComment : malloc failed\n");
1987 return(NULL);
1988 }
1989 memset(cur, 0, sizeof(xmlNode));
1990 cur->type = XML_COMMENT_NODE;
1991
1992 cur->name = xmlStringComment;
1993 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001994 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001995 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001996
1997 if (xmlRegisterNodeDefaultValue)
1998 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001999 return(cur);
2000}
2001
2002/**
2003 * xmlNewCDataBlock:
2004 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002005 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002006 * @len: the length of the block
2007 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002008 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002009 * Returns a pointer to the new node object.
2010 */
2011xmlNodePtr
2012xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2013 xmlNodePtr cur;
2014
2015 /*
2016 * Allocate a new node and fill the fields.
2017 */
2018 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2019 if (cur == NULL) {
2020 xmlGenericError(xmlGenericErrorContext,
2021 "xmlNewCDataBlock : malloc failed\n");
2022 return(NULL);
2023 }
2024 memset(cur, 0, sizeof(xmlNode));
2025 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002026 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002027
2028 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002029 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002030 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002031
2032 if (xmlRegisterNodeDefaultValue)
2033 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002034 return(cur);
2035}
2036
2037/**
2038 * xmlNewDocComment:
2039 * @doc: the document
2040 * @content: the comment content
2041 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002042 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002043 * Returns a pointer to the new node object.
2044 */
2045xmlNodePtr
2046xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2047 xmlNodePtr cur;
2048
2049 cur = xmlNewComment(content);
2050 if (cur != NULL) cur->doc = doc;
2051 return(cur);
2052}
2053
2054/**
2055 * xmlSetTreeDoc:
2056 * @tree: the top element
2057 * @doc: the document
2058 *
2059 * update all nodes under the tree to point to the right document
2060 */
2061void
2062xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002063 xmlAttrPtr prop;
2064
Owen Taylor3473f882001-02-23 17:55:21 +00002065 if (tree == NULL)
2066 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002067 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002068 if(tree->type == XML_ELEMENT_NODE) {
2069 prop = tree->properties;
2070 while (prop != NULL) {
2071 prop->doc = doc;
2072 xmlSetListDoc(prop->children, doc);
2073 prop = prop->next;
2074 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002075 }
Owen Taylor3473f882001-02-23 17:55:21 +00002076 if (tree->children != NULL)
2077 xmlSetListDoc(tree->children, doc);
2078 tree->doc = doc;
2079 }
2080}
2081
2082/**
2083 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002084 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002085 * @doc: the document
2086 *
2087 * update all nodes in the list to point to the right document
2088 */
2089void
2090xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2091 xmlNodePtr cur;
2092
2093 if (list == NULL)
2094 return;
2095 cur = list;
2096 while (cur != NULL) {
2097 if (cur->doc != doc)
2098 xmlSetTreeDoc(cur, doc);
2099 cur = cur->next;
2100 }
2101}
2102
2103
2104/**
2105 * xmlNewChild:
2106 * @parent: the parent node
2107 * @ns: a namespace if any
2108 * @name: the name of the child
2109 * @content: the XML content of the child if any.
2110 *
2111 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002112 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002113 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2114 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2115 * references, but XML special chars need to be escaped first by using
2116 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2117 * support is not needed.
2118 *
2119 * Returns a pointer to the new node object.
2120 */
2121xmlNodePtr
2122xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2123 const xmlChar *name, const xmlChar *content) {
2124 xmlNodePtr cur, prev;
2125
2126 if (parent == NULL) {
2127#ifdef DEBUG_TREE
2128 xmlGenericError(xmlGenericErrorContext,
2129 "xmlNewChild : parent == NULL\n");
2130#endif
2131 return(NULL);
2132 }
2133
2134 if (name == NULL) {
2135#ifdef DEBUG_TREE
2136 xmlGenericError(xmlGenericErrorContext,
2137 "xmlNewChild : name == NULL\n");
2138#endif
2139 return(NULL);
2140 }
2141
2142 /*
2143 * Allocate a new node
2144 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002145 if (parent->type == XML_ELEMENT_NODE) {
2146 if (ns == NULL)
2147 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2148 else
2149 cur = xmlNewDocNode(parent->doc, ns, name, content);
2150 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2151 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2152 if (ns == NULL)
2153 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2154 else
2155 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002156 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2157 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002158 } else {
2159 return(NULL);
2160 }
Owen Taylor3473f882001-02-23 17:55:21 +00002161 if (cur == NULL) return(NULL);
2162
2163 /*
2164 * add the new element at the end of the children list.
2165 */
2166 cur->type = XML_ELEMENT_NODE;
2167 cur->parent = parent;
2168 cur->doc = parent->doc;
2169 if (parent->children == NULL) {
2170 parent->children = cur;
2171 parent->last = cur;
2172 } else {
2173 prev = parent->last;
2174 prev->next = cur;
2175 cur->prev = prev;
2176 parent->last = cur;
2177 }
2178
2179 return(cur);
2180}
2181
2182/**
2183 * xmlAddNextSibling:
2184 * @cur: the child node
2185 * @elem: the new node
2186 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002187 * Add a new node @elem as the next sibling of @cur
2188 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002189 * first unlinked from its existing context.
2190 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002191 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2192 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002193 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002194 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002195 */
2196xmlNodePtr
2197xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2198 if (cur == NULL) {
2199#ifdef DEBUG_TREE
2200 xmlGenericError(xmlGenericErrorContext,
2201 "xmlAddNextSibling : cur == NULL\n");
2202#endif
2203 return(NULL);
2204 }
2205 if (elem == NULL) {
2206#ifdef DEBUG_TREE
2207 xmlGenericError(xmlGenericErrorContext,
2208 "xmlAddNextSibling : elem == NULL\n");
2209#endif
2210 return(NULL);
2211 }
2212
2213 xmlUnlinkNode(elem);
2214
2215 if (elem->type == XML_TEXT_NODE) {
2216 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002217 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002218 xmlFreeNode(elem);
2219 return(cur);
2220 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002221 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2222 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002223 xmlChar *tmp;
2224
2225 tmp = xmlStrdup(elem->content);
2226 tmp = xmlStrcat(tmp, cur->next->content);
2227 xmlNodeSetContent(cur->next, tmp);
2228 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002229 xmlFreeNode(elem);
2230 return(cur->next);
2231 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002232 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2233 /* check if an attribute with the same name exists */
2234 xmlAttrPtr attr;
2235
2236 if (elem->ns == NULL)
2237 attr = xmlHasProp(cur->parent, elem->name);
2238 else
2239 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2240 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2241 /* different instance, destroy it (attributes must be unique) */
2242 xmlFreeProp(attr);
2243 }
Owen Taylor3473f882001-02-23 17:55:21 +00002244 }
2245
2246 if (elem->doc != cur->doc) {
2247 xmlSetTreeDoc(elem, cur->doc);
2248 }
2249 elem->parent = cur->parent;
2250 elem->prev = cur;
2251 elem->next = cur->next;
2252 cur->next = elem;
2253 if (elem->next != NULL)
2254 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002255 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002256 elem->parent->last = elem;
2257 return(elem);
2258}
2259
2260/**
2261 * xmlAddPrevSibling:
2262 * @cur: the child node
2263 * @elem: the new node
2264 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002265 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002266 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002267 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002268 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002269 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2270 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002271 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002272 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002273 */
2274xmlNodePtr
2275xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2276 if (cur == NULL) {
2277#ifdef DEBUG_TREE
2278 xmlGenericError(xmlGenericErrorContext,
2279 "xmlAddPrevSibling : cur == NULL\n");
2280#endif
2281 return(NULL);
2282 }
2283 if (elem == NULL) {
2284#ifdef DEBUG_TREE
2285 xmlGenericError(xmlGenericErrorContext,
2286 "xmlAddPrevSibling : elem == NULL\n");
2287#endif
2288 return(NULL);
2289 }
2290
2291 xmlUnlinkNode(elem);
2292
2293 if (elem->type == XML_TEXT_NODE) {
2294 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002295 xmlChar *tmp;
2296
2297 tmp = xmlStrdup(elem->content);
2298 tmp = xmlStrcat(tmp, cur->content);
2299 xmlNodeSetContent(cur, tmp);
2300 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002301 xmlFreeNode(elem);
2302 return(cur);
2303 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002304 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2305 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002306 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002307 xmlFreeNode(elem);
2308 return(cur->prev);
2309 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002310 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2311 /* check if an attribute with the same name exists */
2312 xmlAttrPtr attr;
2313
2314 if (elem->ns == NULL)
2315 attr = xmlHasProp(cur->parent, elem->name);
2316 else
2317 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2318 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2319 /* different instance, destroy it (attributes must be unique) */
2320 xmlFreeProp(attr);
2321 }
Owen Taylor3473f882001-02-23 17:55:21 +00002322 }
2323
2324 if (elem->doc != cur->doc) {
2325 xmlSetTreeDoc(elem, cur->doc);
2326 }
2327 elem->parent = cur->parent;
2328 elem->next = cur;
2329 elem->prev = cur->prev;
2330 cur->prev = elem;
2331 if (elem->prev != NULL)
2332 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002333 if (elem->parent != NULL) {
2334 if (elem->type == XML_ATTRIBUTE_NODE) {
2335 if (elem->parent->properties == (xmlAttrPtr) cur) {
2336 elem->parent->properties = (xmlAttrPtr) elem;
2337 }
2338 } else {
2339 if (elem->parent->children == cur) {
2340 elem->parent->children = elem;
2341 }
2342 }
2343 }
Owen Taylor3473f882001-02-23 17:55:21 +00002344 return(elem);
2345}
2346
2347/**
2348 * xmlAddSibling:
2349 * @cur: the child node
2350 * @elem: the new node
2351 *
2352 * Add a new element @elem to the list of siblings of @cur
2353 * merging adjacent TEXT nodes (@elem may be freed)
2354 * If the new element was already inserted in a document it is
2355 * first unlinked from its existing context.
2356 *
2357 * Returns the new element or NULL in case of error.
2358 */
2359xmlNodePtr
2360xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2361 xmlNodePtr parent;
2362
2363 if (cur == NULL) {
2364#ifdef DEBUG_TREE
2365 xmlGenericError(xmlGenericErrorContext,
2366 "xmlAddSibling : cur == NULL\n");
2367#endif
2368 return(NULL);
2369 }
2370
2371 if (elem == NULL) {
2372#ifdef DEBUG_TREE
2373 xmlGenericError(xmlGenericErrorContext,
2374 "xmlAddSibling : elem == NULL\n");
2375#endif
2376 return(NULL);
2377 }
2378
2379 /*
2380 * Constant time is we can rely on the ->parent->last to find
2381 * the last sibling.
2382 */
2383 if ((cur->parent != NULL) &&
2384 (cur->parent->children != NULL) &&
2385 (cur->parent->last != NULL) &&
2386 (cur->parent->last->next == NULL)) {
2387 cur = cur->parent->last;
2388 } else {
2389 while (cur->next != NULL) cur = cur->next;
2390 }
2391
2392 xmlUnlinkNode(elem);
2393
2394 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002395 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002396 xmlFreeNode(elem);
2397 return(cur);
2398 }
2399
2400 if (elem->doc != cur->doc) {
2401 xmlSetTreeDoc(elem, cur->doc);
2402 }
2403 parent = cur->parent;
2404 elem->prev = cur;
2405 elem->next = NULL;
2406 elem->parent = parent;
2407 cur->next = elem;
2408 if (parent != NULL)
2409 parent->last = elem;
2410
2411 return(elem);
2412}
2413
2414/**
2415 * xmlAddChildList:
2416 * @parent: the parent node
2417 * @cur: the first node in the list
2418 *
2419 * Add a list of node at the end of the child list of the parent
2420 * merging adjacent TEXT nodes (@cur may be freed)
2421 *
2422 * Returns the last child or NULL in case of error.
2423 */
2424xmlNodePtr
2425xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2426 xmlNodePtr prev;
2427
2428 if (parent == NULL) {
2429#ifdef DEBUG_TREE
2430 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002431 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002432#endif
2433 return(NULL);
2434 }
2435
2436 if (cur == NULL) {
2437#ifdef DEBUG_TREE
2438 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002439 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002440#endif
2441 return(NULL);
2442 }
2443
2444 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2445 (cur->doc != parent->doc)) {
2446#ifdef DEBUG_TREE
2447 xmlGenericError(xmlGenericErrorContext,
2448 "Elements moved to a different document\n");
2449#endif
2450 }
2451
2452 /*
2453 * add the first element at the end of the children list.
2454 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002455 if (cur->parent == parent)
2456 return(cur);
2457
Owen Taylor3473f882001-02-23 17:55:21 +00002458 if (parent->children == NULL) {
2459 parent->children = cur;
2460 } else {
2461 /*
2462 * If cur and parent->last both are TEXT nodes, then merge them.
2463 */
2464 if ((cur->type == XML_TEXT_NODE) &&
2465 (parent->last->type == XML_TEXT_NODE) &&
2466 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00002467 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002468 /*
2469 * if it's the only child, nothing more to be done.
2470 */
2471 if (cur->next == NULL) {
2472 xmlFreeNode(cur);
2473 return(parent->last);
2474 }
2475 prev = cur;
2476 cur = cur->next;
2477 xmlFreeNode(prev);
2478 }
2479 prev = parent->last;
2480 prev->next = cur;
2481 cur->prev = prev;
2482 }
2483 while (cur->next != NULL) {
2484 cur->parent = parent;
2485 if (cur->doc != parent->doc) {
2486 xmlSetTreeDoc(cur, parent->doc);
2487 }
2488 cur = cur->next;
2489 }
2490 cur->parent = parent;
2491 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2492 parent->last = cur;
2493
2494 return(cur);
2495}
2496
2497/**
2498 * xmlAddChild:
2499 * @parent: the parent node
2500 * @cur: the child node
2501 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002502 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002503 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002504 * If the new node was already inserted in a document it is
2505 * first unlinked from its existing context.
2506 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2507 * If there is an attribute with equal name, it is first destroyed.
2508 *
Owen Taylor3473f882001-02-23 17:55:21 +00002509 * Returns the child or NULL in case of error.
2510 */
2511xmlNodePtr
2512xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2513 xmlNodePtr prev;
2514
2515 if (parent == NULL) {
2516#ifdef DEBUG_TREE
2517 xmlGenericError(xmlGenericErrorContext,
2518 "xmlAddChild : parent == NULL\n");
2519#endif
2520 return(NULL);
2521 }
2522
2523 if (cur == NULL) {
2524#ifdef DEBUG_TREE
2525 xmlGenericError(xmlGenericErrorContext,
2526 "xmlAddChild : child == NULL\n");
2527#endif
2528 return(NULL);
2529 }
2530
Owen Taylor3473f882001-02-23 17:55:21 +00002531 /*
2532 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002533 * cur is then freed.
2534 */
2535 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002536 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002537 (parent->content != NULL) &&
2538 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002539 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002540 xmlFreeNode(cur);
2541 return(parent);
2542 }
2543 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002544 (parent->last->name == cur->name) &&
2545 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002546 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002547 xmlFreeNode(cur);
2548 return(parent->last);
2549 }
2550 }
2551
2552 /*
2553 * add the new element at the end of the children list.
2554 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002555 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00002556 cur->parent = parent;
2557 if (cur->doc != parent->doc) {
2558 xmlSetTreeDoc(cur, parent->doc);
2559 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002560 /* this check prevents a loop on tree-traversions if a developer
2561 * tries to add a node to its parent multiple times
2562 */
2563 if (prev == parent)
2564 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002565
2566 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002567 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002568 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002569 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002570 (parent->content != NULL) &&
2571 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002572 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002573 xmlFreeNode(cur);
2574 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002575 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002576 if (cur->type == XML_ATTRIBUTE_NODE) {
2577 if (parent->properties == NULL) {
2578 parent->properties = (xmlAttrPtr) cur;
2579 } else {
2580 /* check if an attribute with the same name exists */
2581 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002582
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002583 if (cur->ns == NULL)
2584 lastattr = xmlHasProp(parent, cur->name);
2585 else
2586 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2587 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2588 /* different instance, destroy it (attributes must be unique) */
2589 xmlFreeProp(lastattr);
2590 }
2591 /* find the end */
2592 lastattr = parent->properties;
2593 while (lastattr->next != NULL) {
2594 lastattr = lastattr->next;
2595 }
2596 lastattr->next = (xmlAttrPtr) cur;
2597 ((xmlAttrPtr) cur)->prev = lastattr;
2598 }
2599 } else {
2600 if (parent->children == NULL) {
2601 parent->children = cur;
2602 parent->last = cur;
2603 } else {
2604 prev = parent->last;
2605 prev->next = cur;
2606 cur->prev = prev;
2607 parent->last = cur;
2608 }
2609 }
Owen Taylor3473f882001-02-23 17:55:21 +00002610 return(cur);
2611}
2612
2613/**
2614 * xmlGetLastChild:
2615 * @parent: the parent node
2616 *
2617 * Search the last child of a node.
2618 * Returns the last child or NULL if none.
2619 */
2620xmlNodePtr
2621xmlGetLastChild(xmlNodePtr parent) {
2622 if (parent == NULL) {
2623#ifdef DEBUG_TREE
2624 xmlGenericError(xmlGenericErrorContext,
2625 "xmlGetLastChild : parent == NULL\n");
2626#endif
2627 return(NULL);
2628 }
2629 return(parent->last);
2630}
2631
2632/**
2633 * xmlFreeNodeList:
2634 * @cur: the first node in the list
2635 *
2636 * Free a node and all its siblings, this is a recursive behaviour, all
2637 * the children are freed too.
2638 */
2639void
2640xmlFreeNodeList(xmlNodePtr cur) {
2641 xmlNodePtr next;
2642 if (cur == NULL) {
2643#ifdef DEBUG_TREE
2644 xmlGenericError(xmlGenericErrorContext,
2645 "xmlFreeNodeList : node == NULL\n");
2646#endif
2647 return;
2648 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002649 if (cur->type == XML_NAMESPACE_DECL) {
2650 xmlFreeNsList((xmlNsPtr) cur);
2651 return;
2652 }
Owen Taylor3473f882001-02-23 17:55:21 +00002653 while (cur != NULL) {
2654 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002655 /* unroll to speed up freeing the document */
2656 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00002657
2658 if (xmlDeregisterNodeDefaultValue)
2659 xmlDeregisterNodeDefaultValue(cur);
2660
Daniel Veillard02141ea2001-04-30 11:46:40 +00002661 if ((cur->children != NULL) &&
2662 (cur->type != XML_ENTITY_REF_NODE))
2663 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00002664 if (((cur->type == XML_ELEMENT_NODE) ||
2665 (cur->type == XML_XINCLUDE_START) ||
2666 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002667 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00002668 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002669 if ((cur->type != XML_ELEMENT_NODE) &&
2670 (cur->type != XML_XINCLUDE_START) &&
2671 (cur->type != XML_XINCLUDE_END) &&
2672 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002673 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002674 }
2675 if (((cur->type == XML_ELEMENT_NODE) ||
2676 (cur->type == XML_XINCLUDE_START) ||
2677 (cur->type == XML_XINCLUDE_END)) &&
2678 (cur->nsDef != NULL))
2679 xmlFreeNsList(cur->nsDef);
2680
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002681 /*
2682 * When a node is a text node or a comment, it uses a global static
2683 * variable for the name of the node.
2684 *
2685 * The xmlStrEqual comparisons need to be done when (happened with
2686 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002687 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002688 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002689 * the string addresses compare are not sufficient.
2690 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002691 if ((cur->name != NULL) &&
2692 (cur->name != xmlStringText) &&
2693 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002694 (cur->name != xmlStringComment)) {
2695 if (cur->type == XML_TEXT_NODE) {
2696 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2697 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2698 xmlFree((char *) cur->name);
2699 } else if (cur->type == XML_COMMENT_NODE) {
2700 if (!xmlStrEqual(cur->name, xmlStringComment))
2701 xmlFree((char *) cur->name);
2702 } else
2703 xmlFree((char *) cur->name);
2704 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002705 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002706 xmlFree(cur);
2707 }
Owen Taylor3473f882001-02-23 17:55:21 +00002708 cur = next;
2709 }
2710}
2711
2712/**
2713 * xmlFreeNode:
2714 * @cur: the node
2715 *
2716 * Free a node, this is a recursive behaviour, all the children are freed too.
2717 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2718 */
2719void
2720xmlFreeNode(xmlNodePtr cur) {
2721 if (cur == NULL) {
2722#ifdef DEBUG_TREE
2723 xmlGenericError(xmlGenericErrorContext,
2724 "xmlFreeNode : node == NULL\n");
2725#endif
2726 return;
2727 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002728
Daniel Veillard02141ea2001-04-30 11:46:40 +00002729 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002730 if (cur->type == XML_DTD_NODE) {
2731 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002732 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002733 }
2734 if (cur->type == XML_NAMESPACE_DECL) {
2735 xmlFreeNs((xmlNsPtr) cur);
2736 return;
2737 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00002738 if (cur->type == XML_ATTRIBUTE_NODE) {
2739 xmlFreeProp((xmlAttrPtr) cur);
2740 return;
2741 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002742
2743 if (xmlDeregisterNodeDefaultValue)
2744 xmlDeregisterNodeDefaultValue(cur);
2745
Owen Taylor3473f882001-02-23 17:55:21 +00002746 if ((cur->children != NULL) &&
2747 (cur->type != XML_ENTITY_REF_NODE))
2748 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00002749 if (((cur->type == XML_ELEMENT_NODE) ||
2750 (cur->type == XML_XINCLUDE_START) ||
2751 (cur->type == XML_XINCLUDE_END)) &&
2752 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00002753 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002754 if ((cur->type != XML_ELEMENT_NODE) &&
2755 (cur->content != NULL) &&
2756 (cur->type != XML_ENTITY_REF_NODE) &&
2757 (cur->type != XML_XINCLUDE_END) &&
2758 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002759 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002760 }
2761
Daniel Veillardacd370f2001-06-09 17:17:51 +00002762 /*
2763 * When a node is a text node or a comment, it uses a global static
2764 * variable for the name of the node.
2765 *
2766 * The xmlStrEqual comparisons need to be done when (happened with
2767 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002768 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002769 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002770 * are not sufficient.
2771 */
Owen Taylor3473f882001-02-23 17:55:21 +00002772 if ((cur->name != NULL) &&
2773 (cur->name != xmlStringText) &&
2774 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002775 (cur->name != xmlStringComment)) {
2776 if (cur->type == XML_TEXT_NODE) {
2777 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2778 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2779 xmlFree((char *) cur->name);
2780 } else if (cur->type == XML_COMMENT_NODE) {
2781 if (!xmlStrEqual(cur->name, xmlStringComment))
2782 xmlFree((char *) cur->name);
2783 } else
2784 xmlFree((char *) cur->name);
2785 }
2786
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002787 if (((cur->type == XML_ELEMENT_NODE) ||
2788 (cur->type == XML_XINCLUDE_START) ||
2789 (cur->type == XML_XINCLUDE_END)) &&
2790 (cur->nsDef != NULL))
2791 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002792 xmlFree(cur);
2793}
2794
2795/**
2796 * xmlUnlinkNode:
2797 * @cur: the node
2798 *
2799 * Unlink a node from it's current context, the node is not freed
2800 */
2801void
2802xmlUnlinkNode(xmlNodePtr cur) {
2803 if (cur == NULL) {
2804#ifdef DEBUG_TREE
2805 xmlGenericError(xmlGenericErrorContext,
2806 "xmlUnlinkNode : node == NULL\n");
2807#endif
2808 return;
2809 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002810 if (cur->type == XML_DTD_NODE) {
2811 xmlDocPtr doc;
2812 doc = cur->doc;
2813 if (doc->intSubset == (xmlDtdPtr) cur)
2814 doc->intSubset = NULL;
2815 if (doc->extSubset == (xmlDtdPtr) cur)
2816 doc->extSubset = NULL;
2817 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002818 if (cur->parent != NULL) {
2819 xmlNodePtr parent;
2820 parent = cur->parent;
2821 if (cur->type == XML_ATTRIBUTE_NODE) {
2822 if (parent->properties == (xmlAttrPtr) cur)
2823 parent->properties = ((xmlAttrPtr) cur)->next;
2824 } else {
2825 if (parent->children == cur)
2826 parent->children = cur->next;
2827 if (parent->last == cur)
2828 parent->last = cur->prev;
2829 }
2830 cur->parent = NULL;
2831 }
Owen Taylor3473f882001-02-23 17:55:21 +00002832 if (cur->next != NULL)
2833 cur->next->prev = cur->prev;
2834 if (cur->prev != NULL)
2835 cur->prev->next = cur->next;
2836 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002837}
2838
2839/**
2840 * xmlReplaceNode:
2841 * @old: the old node
2842 * @cur: the node
2843 *
2844 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002845 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002846 * first unlinked from its existing context.
2847 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002848 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002849 */
2850xmlNodePtr
2851xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2852 if (old == NULL) {
2853#ifdef DEBUG_TREE
2854 xmlGenericError(xmlGenericErrorContext,
2855 "xmlReplaceNode : old == NULL\n");
2856#endif
2857 return(NULL);
2858 }
2859 if (cur == NULL) {
2860 xmlUnlinkNode(old);
2861 return(old);
2862 }
2863 if (cur == old) {
2864 return(old);
2865 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002866 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2867#ifdef DEBUG_TREE
2868 xmlGenericError(xmlGenericErrorContext,
2869 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2870#endif
2871 return(old);
2872 }
2873 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2874#ifdef DEBUG_TREE
2875 xmlGenericError(xmlGenericErrorContext,
2876 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2877#endif
2878 return(old);
2879 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002880 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2881#ifdef DEBUG_TREE
2882 xmlGenericError(xmlGenericErrorContext,
2883 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2884#endif
2885 return(old);
2886 }
2887 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2888#ifdef DEBUG_TREE
2889 xmlGenericError(xmlGenericErrorContext,
2890 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2891#endif
2892 return(old);
2893 }
Owen Taylor3473f882001-02-23 17:55:21 +00002894 xmlUnlinkNode(cur);
2895 cur->doc = old->doc;
2896 cur->parent = old->parent;
2897 cur->next = old->next;
2898 if (cur->next != NULL)
2899 cur->next->prev = cur;
2900 cur->prev = old->prev;
2901 if (cur->prev != NULL)
2902 cur->prev->next = cur;
2903 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002904 if (cur->type == XML_ATTRIBUTE_NODE) {
2905 if (cur->parent->properties == (xmlAttrPtr)old)
2906 cur->parent->properties = ((xmlAttrPtr) cur);
2907 } else {
2908 if (cur->parent->children == old)
2909 cur->parent->children = cur;
2910 if (cur->parent->last == old)
2911 cur->parent->last = cur;
2912 }
Owen Taylor3473f882001-02-23 17:55:21 +00002913 }
2914 old->next = old->prev = NULL;
2915 old->parent = NULL;
2916 return(old);
2917}
2918
2919/************************************************************************
2920 * *
2921 * Copy operations *
2922 * *
2923 ************************************************************************/
2924
2925/**
2926 * xmlCopyNamespace:
2927 * @cur: the namespace
2928 *
2929 * Do a copy of the namespace.
2930 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002931 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002932 */
2933xmlNsPtr
2934xmlCopyNamespace(xmlNsPtr cur) {
2935 xmlNsPtr ret;
2936
2937 if (cur == NULL) return(NULL);
2938 switch (cur->type) {
2939 case XML_LOCAL_NAMESPACE:
2940 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2941 break;
2942 default:
2943#ifdef DEBUG_TREE
2944 xmlGenericError(xmlGenericErrorContext,
2945 "xmlCopyNamespace: invalid type %d\n", cur->type);
2946#endif
2947 return(NULL);
2948 }
2949 return(ret);
2950}
2951
2952/**
2953 * xmlCopyNamespaceList:
2954 * @cur: the first namespace
2955 *
2956 * Do a copy of an namespace list.
2957 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002958 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002959 */
2960xmlNsPtr
2961xmlCopyNamespaceList(xmlNsPtr cur) {
2962 xmlNsPtr ret = NULL;
2963 xmlNsPtr p = NULL,q;
2964
2965 while (cur != NULL) {
2966 q = xmlCopyNamespace(cur);
2967 if (p == NULL) {
2968 ret = p = q;
2969 } else {
2970 p->next = q;
2971 p = q;
2972 }
2973 cur = cur->next;
2974 }
2975 return(ret);
2976}
2977
2978static xmlNodePtr
2979xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2980/**
2981 * xmlCopyProp:
2982 * @target: the element where the attribute will be grafted
2983 * @cur: the attribute
2984 *
2985 * Do a copy of the attribute.
2986 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002987 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002988 */
2989xmlAttrPtr
2990xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2991 xmlAttrPtr ret;
2992
2993 if (cur == NULL) return(NULL);
2994 if (target != NULL)
2995 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2996 else if (cur->parent != NULL)
2997 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2998 else if (cur->children != NULL)
2999 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3000 else
3001 ret = xmlNewDocProp(NULL, cur->name, NULL);
3002 if (ret == NULL) return(NULL);
3003 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003004
Owen Taylor3473f882001-02-23 17:55:21 +00003005 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003006 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003007/*
3008 * if (target->doc)
3009 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3010 * else if (cur->doc) / * target may not yet have a doc : KPI * /
3011 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
3012 * else
3013 * ns = NULL;
3014 * ret->ns = ns;
3015 */
3016 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3017 if (ns == NULL) {
3018 /*
3019 * Humm, we are copying an element whose namespace is defined
3020 * out of the new tree scope. Search it in the original tree
3021 * and add it at the top of the new tree
3022 */
3023 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3024 if (ns != NULL) {
3025 xmlNodePtr root = target;
3026 xmlNodePtr pred = NULL;
3027
3028 while (root->parent != NULL) {
3029 pred = root;
3030 root = root->parent;
3031 }
3032 if (root == (xmlNodePtr) target->doc) {
3033 /* correct possibly cycling above the document elt */
3034 root = pred;
3035 }
3036 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3037 }
3038 } else {
3039 /*
3040 * we have to find something appropriate here since
3041 * we cant be sure, that the namespce we found is identified
3042 * by the prefix
3043 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003044 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003045 /* this is the nice case */
3046 ret->ns = ns;
3047 } else {
3048 /*
3049 * we are in trouble: we need a new reconcilied namespace.
3050 * This is expensive
3051 */
3052 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3053 }
3054 }
3055
Owen Taylor3473f882001-02-23 17:55:21 +00003056 } else
3057 ret->ns = NULL;
3058
3059 if (cur->children != NULL) {
3060 xmlNodePtr tmp;
3061
3062 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3063 ret->last = NULL;
3064 tmp = ret->children;
3065 while (tmp != NULL) {
3066 /* tmp->parent = (xmlNodePtr)ret; */
3067 if (tmp->next == NULL)
3068 ret->last = tmp;
3069 tmp = tmp->next;
3070 }
3071 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003072 /*
3073 * Try to handle IDs
3074 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003075 if ((target!= NULL) && (cur!= NULL) &&
3076 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003077 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3078 if (xmlIsID(cur->doc, cur->parent, cur)) {
3079 xmlChar *id;
3080
3081 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3082 if (id != NULL) {
3083 xmlAddID(NULL, target->doc, id, ret);
3084 xmlFree(id);
3085 }
3086 }
3087 }
Owen Taylor3473f882001-02-23 17:55:21 +00003088 return(ret);
3089}
3090
3091/**
3092 * xmlCopyPropList:
3093 * @target: the element where the attributes will be grafted
3094 * @cur: the first attribute
3095 *
3096 * Do a copy of an attribute list.
3097 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003098 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003099 */
3100xmlAttrPtr
3101xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3102 xmlAttrPtr ret = NULL;
3103 xmlAttrPtr p = NULL,q;
3104
3105 while (cur != NULL) {
3106 q = xmlCopyProp(target, cur);
3107 if (p == NULL) {
3108 ret = p = q;
3109 } else {
3110 p->next = q;
3111 q->prev = p;
3112 p = q;
3113 }
3114 cur = cur->next;
3115 }
3116 return(ret);
3117}
3118
3119/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003120 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003121 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003122 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003123 * tricky reason: namespaces. Doing a direct copy of a node
3124 * say RPM:Copyright without changing the namespace pointer to
3125 * something else can produce stale links. One way to do it is
3126 * to keep a reference counter but this doesn't work as soon
3127 * as one move the element or the subtree out of the scope of
3128 * the existing namespace. The actual solution seems to add
3129 * a copy of the namespace at the top of the copied tree if
3130 * not available in the subtree.
3131 * Hence two functions, the public front-end call the inner ones
3132 */
3133
3134static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003135xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003136 int recursive) {
3137 xmlNodePtr ret;
3138
3139 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003140 switch (node->type) {
3141 case XML_TEXT_NODE:
3142 case XML_CDATA_SECTION_NODE:
3143 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003144 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003145 case XML_ENTITY_REF_NODE:
3146 case XML_ENTITY_NODE:
3147 case XML_PI_NODE:
3148 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003149 case XML_XINCLUDE_START:
3150 case XML_XINCLUDE_END:
3151 break;
3152 case XML_ATTRIBUTE_NODE:
3153 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3154 case XML_NAMESPACE_DECL:
3155 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3156
Daniel Veillard39196eb2001-06-19 18:09:42 +00003157 case XML_DOCUMENT_NODE:
3158 case XML_HTML_DOCUMENT_NODE:
3159#ifdef LIBXML_DOCB_ENABLED
3160 case XML_DOCB_DOCUMENT_NODE:
3161#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003162 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003163 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003164 case XML_NOTATION_NODE:
3165 case XML_DTD_NODE:
3166 case XML_ELEMENT_DECL:
3167 case XML_ATTRIBUTE_DECL:
3168 case XML_ENTITY_DECL:
3169 return(NULL);
3170 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003171
Owen Taylor3473f882001-02-23 17:55:21 +00003172 /*
3173 * Allocate a new node and fill the fields.
3174 */
3175 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3176 if (ret == NULL) {
3177 xmlGenericError(xmlGenericErrorContext,
3178 "xmlStaticCopyNode : malloc failed\n");
3179 return(NULL);
3180 }
3181 memset(ret, 0, sizeof(xmlNode));
3182 ret->type = node->type;
3183
3184 ret->doc = doc;
3185 ret->parent = parent;
3186 if (node->name == xmlStringText)
3187 ret->name = xmlStringText;
3188 else if (node->name == xmlStringTextNoenc)
3189 ret->name = xmlStringTextNoenc;
3190 else if (node->name == xmlStringComment)
3191 ret->name = xmlStringComment;
3192 else if (node->name != NULL)
3193 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003194 if ((node->type != XML_ELEMENT_NODE) &&
3195 (node->content != NULL) &&
3196 (node->type != XML_ENTITY_REF_NODE) &&
3197 (node->type != XML_XINCLUDE_END) &&
3198 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003199 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003200 }else{
3201 if (node->type == XML_ELEMENT_NODE)
3202 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003203 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003204 if (parent != NULL) {
3205 xmlNodePtr tmp;
3206
3207 tmp = xmlAddChild(parent, ret);
3208 /* node could have coalesced */
3209 if (tmp != ret)
3210 return(tmp);
3211 }
Owen Taylor3473f882001-02-23 17:55:21 +00003212
3213 if (!recursive) return(ret);
3214 if (node->nsDef != NULL)
3215 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3216
3217 if (node->ns != NULL) {
3218 xmlNsPtr ns;
3219
3220 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3221 if (ns == NULL) {
3222 /*
3223 * Humm, we are copying an element whose namespace is defined
3224 * out of the new tree scope. Search it in the original tree
3225 * and add it at the top of the new tree
3226 */
3227 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3228 if (ns != NULL) {
3229 xmlNodePtr root = ret;
3230
3231 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003232 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003233 }
3234 } else {
3235 /*
3236 * reference the existing namespace definition in our own tree.
3237 */
3238 ret->ns = ns;
3239 }
3240 }
3241 if (node->properties != NULL)
3242 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003243 if (node->type == XML_ENTITY_REF_NODE) {
3244 if ((doc == NULL) || (node->doc != doc)) {
3245 /*
3246 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003247 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003248 * we cannot keep the reference. Try to find it in the
3249 * target document.
3250 */
3251 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3252 } else {
3253 ret->children = node->children;
3254 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003255 ret->last = ret->children;
3256 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003257 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003258 UPDATE_LAST_CHILD_AND_PARENT(ret)
3259 }
Owen Taylor3473f882001-02-23 17:55:21 +00003260 return(ret);
3261}
3262
3263static xmlNodePtr
3264xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3265 xmlNodePtr ret = NULL;
3266 xmlNodePtr p = NULL,q;
3267
3268 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003269 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003270 if (doc == NULL) {
3271 node = node->next;
3272 continue;
3273 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003274 if (doc->intSubset == NULL) {
3275 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3276 q->doc = doc;
3277 q->parent = parent;
3278 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003279 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003280 } else {
3281 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003282 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003283 }
3284 } else
3285 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003286 if (ret == NULL) {
3287 q->prev = NULL;
3288 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003289 } else if (p != q) {
3290 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003291 p->next = q;
3292 q->prev = p;
3293 p = q;
3294 }
3295 node = node->next;
3296 }
3297 return(ret);
3298}
3299
3300/**
3301 * xmlCopyNode:
3302 * @node: the node
3303 * @recursive: if 1 do a recursive copy.
3304 *
3305 * Do a copy of the node.
3306 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003307 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003308 */
3309xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003310xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003311 xmlNodePtr ret;
3312
3313 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3314 return(ret);
3315}
3316
3317/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003318 * xmlDocCopyNode:
3319 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003320 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003321 * @recursive: if 1 do a recursive copy.
3322 *
3323 * Do a copy of the node to a given document.
3324 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003325 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003326 */
3327xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003328xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003329 xmlNodePtr ret;
3330
3331 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3332 return(ret);
3333}
3334
3335/**
Owen Taylor3473f882001-02-23 17:55:21 +00003336 * xmlCopyNodeList:
3337 * @node: the first node in the list.
3338 *
3339 * Do a recursive copy of the node list.
3340 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003341 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003342 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003343xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003344 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3345 return(ret);
3346}
3347
3348/**
Owen Taylor3473f882001-02-23 17:55:21 +00003349 * xmlCopyDtd:
3350 * @dtd: the dtd
3351 *
3352 * Do a copy of the dtd.
3353 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003354 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003355 */
3356xmlDtdPtr
3357xmlCopyDtd(xmlDtdPtr dtd) {
3358 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003359 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003360
3361 if (dtd == NULL) return(NULL);
3362 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3363 if (ret == NULL) return(NULL);
3364 if (dtd->entities != NULL)
3365 ret->entities = (void *) xmlCopyEntitiesTable(
3366 (xmlEntitiesTablePtr) dtd->entities);
3367 if (dtd->notations != NULL)
3368 ret->notations = (void *) xmlCopyNotationTable(
3369 (xmlNotationTablePtr) dtd->notations);
3370 if (dtd->elements != NULL)
3371 ret->elements = (void *) xmlCopyElementTable(
3372 (xmlElementTablePtr) dtd->elements);
3373 if (dtd->attributes != NULL)
3374 ret->attributes = (void *) xmlCopyAttributeTable(
3375 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003376 if (dtd->pentities != NULL)
3377 ret->pentities = (void *) xmlCopyEntitiesTable(
3378 (xmlEntitiesTablePtr) dtd->pentities);
3379
3380 cur = dtd->children;
3381 while (cur != NULL) {
3382 q = NULL;
3383
3384 if (cur->type == XML_ENTITY_DECL) {
3385 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3386 switch (tmp->etype) {
3387 case XML_INTERNAL_GENERAL_ENTITY:
3388 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3389 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3390 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3391 break;
3392 case XML_INTERNAL_PARAMETER_ENTITY:
3393 case XML_EXTERNAL_PARAMETER_ENTITY:
3394 q = (xmlNodePtr)
3395 xmlGetParameterEntityFromDtd(ret, tmp->name);
3396 break;
3397 case XML_INTERNAL_PREDEFINED_ENTITY:
3398 break;
3399 }
3400 } else if (cur->type == XML_ELEMENT_DECL) {
3401 xmlElementPtr tmp = (xmlElementPtr) cur;
3402 q = (xmlNodePtr)
3403 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3404 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3405 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3406 q = (xmlNodePtr)
3407 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3408 } else if (cur->type == XML_COMMENT_NODE) {
3409 q = xmlCopyNode(cur, 0);
3410 }
3411
3412 if (q == NULL) {
3413 cur = cur->next;
3414 continue;
3415 }
3416
3417 if (p == NULL)
3418 ret->children = q;
3419 else
3420 p->next = q;
3421
3422 q->prev = p;
3423 q->parent = (xmlNodePtr) ret;
3424 q->next = NULL;
3425 ret->last = q;
3426 p = q;
3427 cur = cur->next;
3428 }
3429
Owen Taylor3473f882001-02-23 17:55:21 +00003430 return(ret);
3431}
3432
3433/**
3434 * xmlCopyDoc:
3435 * @doc: the document
3436 * @recursive: if 1 do a recursive copy.
3437 *
3438 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003439 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003440 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003441 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003442 */
3443xmlDocPtr
3444xmlCopyDoc(xmlDocPtr doc, int recursive) {
3445 xmlDocPtr ret;
3446
3447 if (doc == NULL) return(NULL);
3448 ret = xmlNewDoc(doc->version);
3449 if (ret == NULL) return(NULL);
3450 if (doc->name != NULL)
3451 ret->name = xmlMemStrdup(doc->name);
3452 if (doc->encoding != NULL)
3453 ret->encoding = xmlStrdup(doc->encoding);
3454 ret->charset = doc->charset;
3455 ret->compression = doc->compression;
3456 ret->standalone = doc->standalone;
3457 if (!recursive) return(ret);
3458
Daniel Veillardb33c2012001-04-25 12:59:04 +00003459 ret->last = NULL;
3460 ret->children = NULL;
3461 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003462 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003463 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003464 ret->intSubset->parent = ret;
3465 }
Owen Taylor3473f882001-02-23 17:55:21 +00003466 if (doc->oldNs != NULL)
3467 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3468 if (doc->children != NULL) {
3469 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003470
3471 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3472 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003473 ret->last = NULL;
3474 tmp = ret->children;
3475 while (tmp != NULL) {
3476 if (tmp->next == NULL)
3477 ret->last = tmp;
3478 tmp = tmp->next;
3479 }
3480 }
3481 return(ret);
3482}
3483
3484/************************************************************************
3485 * *
3486 * Content access functions *
3487 * *
3488 ************************************************************************/
3489
3490/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003491 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003492 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00003493 *
3494 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003495 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003496 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003497 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003498 */
3499long
3500xmlGetLineNo(xmlNodePtr node)
3501{
3502 long result = -1;
3503
3504 if (!node)
3505 return result;
3506 if (node->type == XML_ELEMENT_NODE)
3507 result = (long) node->content;
3508 else if ((node->prev != NULL) &&
3509 ((node->prev->type == XML_ELEMENT_NODE) ||
3510 (node->prev->type == XML_TEXT_NODE)))
3511 result = xmlGetLineNo(node->prev);
3512 else if ((node->parent != NULL) &&
3513 ((node->parent->type == XML_ELEMENT_NODE) ||
3514 (node->parent->type == XML_TEXT_NODE)))
3515 result = xmlGetLineNo(node->parent);
3516
3517 return result;
3518}
3519
3520/**
3521 * xmlGetNodePath:
3522 * @node: a node
3523 *
3524 * Build a structure based Path for the given node
3525 *
3526 * Returns the new path or NULL in case of error. The caller must free
3527 * the returned string
3528 */
3529xmlChar *
3530xmlGetNodePath(xmlNodePtr node)
3531{
3532 xmlNodePtr cur, tmp, next;
3533 xmlChar *buffer = NULL, *temp;
3534 size_t buf_len;
3535 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00003536 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00003537 const char *name;
3538 char nametemp[100];
3539 int occur = 0;
3540
3541 if (node == NULL)
3542 return (NULL);
3543
3544 buf_len = 500;
3545 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3546 if (buffer == NULL)
3547 return (NULL);
3548 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3549 if (buf == NULL) {
3550 xmlFree(buffer);
3551 return (NULL);
3552 }
3553
3554 buffer[0] = 0;
3555 cur = node;
3556 do {
3557 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003558 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003559 occur = 0;
3560 if ((cur->type == XML_DOCUMENT_NODE) ||
3561 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3562 if (buffer[0] == '/')
3563 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003564 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003565 next = NULL;
3566 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003567 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003568 name = (const char *) cur->name;
3569 if (cur->ns) {
3570 snprintf(nametemp, sizeof(nametemp) - 1,
3571 "%s:%s", cur->ns->prefix, cur->name);
3572 nametemp[sizeof(nametemp) - 1] = 0;
3573 name = nametemp;
3574 }
3575 next = cur->parent;
3576
3577 /*
3578 * Thumbler index computation
3579 */
3580 tmp = cur->prev;
3581 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00003582 if ((tmp->type == XML_ELEMENT_NODE) &&
3583 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003584 occur++;
3585 tmp = tmp->prev;
3586 }
3587 if (occur == 0) {
3588 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003589 while (tmp != NULL && occur == 0) {
3590 if ((tmp->type == XML_ELEMENT_NODE) &&
3591 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003592 occur++;
3593 tmp = tmp->next;
3594 }
3595 if (occur != 0)
3596 occur = 1;
3597 } else
3598 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003599 } else if (cur->type == XML_COMMENT_NODE) {
3600 sep = "/";
3601 name = "comment()";
3602 next = cur->parent;
3603
3604 /*
3605 * Thumbler index computation
3606 */
3607 tmp = cur->prev;
3608 while (tmp != NULL) {
3609 if (tmp->type == XML_COMMENT_NODE)
3610 occur++;
3611 tmp = tmp->prev;
3612 }
3613 if (occur == 0) {
3614 tmp = cur->next;
3615 while (tmp != NULL && occur == 0) {
3616 if (tmp->type == XML_COMMENT_NODE)
3617 occur++;
3618 tmp = tmp->next;
3619 }
3620 if (occur != 0)
3621 occur = 1;
3622 } else
3623 occur++;
3624 } else if ((cur->type == XML_TEXT_NODE) ||
3625 (cur->type == XML_CDATA_SECTION_NODE)) {
3626 sep = "/";
3627 name = "text()";
3628 next = cur->parent;
3629
3630 /*
3631 * Thumbler index computation
3632 */
3633 tmp = cur->prev;
3634 while (tmp != NULL) {
3635 if ((cur->type == XML_TEXT_NODE) ||
3636 (cur->type == XML_CDATA_SECTION_NODE))
3637 occur++;
3638 tmp = tmp->prev;
3639 }
3640 if (occur == 0) {
3641 tmp = cur->next;
3642 while (tmp != NULL && occur == 0) {
3643 if ((cur->type == XML_TEXT_NODE) ||
3644 (cur->type == XML_CDATA_SECTION_NODE))
3645 occur++;
3646 tmp = tmp->next;
3647 }
3648 if (occur != 0)
3649 occur = 1;
3650 } else
3651 occur++;
3652 } else if (cur->type == XML_PI_NODE) {
3653 sep = "/";
3654 snprintf(nametemp, sizeof(nametemp) - 1,
3655 "processing-instruction('%s')", cur->name);
3656 nametemp[sizeof(nametemp) - 1] = 0;
3657 name = nametemp;
3658
3659 next = cur->parent;
3660
3661 /*
3662 * Thumbler index computation
3663 */
3664 tmp = cur->prev;
3665 while (tmp != NULL) {
3666 if ((tmp->type == XML_PI_NODE) &&
3667 (xmlStrEqual(cur->name, tmp->name)))
3668 occur++;
3669 tmp = tmp->prev;
3670 }
3671 if (occur == 0) {
3672 tmp = cur->next;
3673 while (tmp != NULL && occur == 0) {
3674 if ((tmp->type == XML_PI_NODE) &&
3675 (xmlStrEqual(cur->name, tmp->name)))
3676 occur++;
3677 tmp = tmp->next;
3678 }
3679 if (occur != 0)
3680 occur = 1;
3681 } else
3682 occur++;
3683
Daniel Veillard8faa7832001-11-26 15:58:08 +00003684 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003685 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003686 name = (const char *) (((xmlAttrPtr) cur)->name);
3687 next = ((xmlAttrPtr) cur)->parent;
3688 } else {
3689 next = cur->parent;
3690 }
3691
3692 /*
3693 * Make sure there is enough room
3694 */
3695 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3696 buf_len =
3697 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3698 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3699 if (temp == NULL) {
3700 xmlFree(buf);
3701 xmlFree(buffer);
3702 return (NULL);
3703 }
3704 buffer = temp;
3705 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3706 if (temp == NULL) {
3707 xmlFree(buf);
3708 xmlFree(buffer);
3709 return (NULL);
3710 }
3711 buf = temp;
3712 }
3713 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003714 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00003715 sep, name, (char *) buffer);
3716 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003717 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00003718 sep, name, occur, (char *) buffer);
3719 snprintf((char *) buffer, buf_len, "%s", buf);
3720 cur = next;
3721 } while (cur != NULL);
3722 xmlFree(buf);
3723 return (buffer);
3724}
3725
3726/**
Owen Taylor3473f882001-02-23 17:55:21 +00003727 * xmlDocGetRootElement:
3728 * @doc: the document
3729 *
3730 * Get the root element of the document (doc->children is a list
3731 * containing possibly comments, PIs, etc ...).
3732 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003733 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003734 */
3735xmlNodePtr
3736xmlDocGetRootElement(xmlDocPtr doc) {
3737 xmlNodePtr ret;
3738
3739 if (doc == NULL) return(NULL);
3740 ret = doc->children;
3741 while (ret != NULL) {
3742 if (ret->type == XML_ELEMENT_NODE)
3743 return(ret);
3744 ret = ret->next;
3745 }
3746 return(ret);
3747}
3748
3749/**
3750 * xmlDocSetRootElement:
3751 * @doc: the document
3752 * @root: the new document root element
3753 *
3754 * Set the root element of the document (doc->children is a list
3755 * containing possibly comments, PIs, etc ...).
3756 *
3757 * Returns the old root element if any was found
3758 */
3759xmlNodePtr
3760xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3761 xmlNodePtr old = NULL;
3762
3763 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00003764 if (root == NULL)
3765 return(NULL);
3766 xmlUnlinkNode(root);
3767 root->doc = doc;
3768 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00003769 old = doc->children;
3770 while (old != NULL) {
3771 if (old->type == XML_ELEMENT_NODE)
3772 break;
3773 old = old->next;
3774 }
3775 if (old == NULL) {
3776 if (doc->children == NULL) {
3777 doc->children = root;
3778 doc->last = root;
3779 } else {
3780 xmlAddSibling(doc->children, root);
3781 }
3782 } else {
3783 xmlReplaceNode(old, root);
3784 }
3785 return(old);
3786}
3787
3788/**
3789 * xmlNodeSetLang:
3790 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003791 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003792 *
3793 * Set the language of a node, i.e. the values of the xml:lang
3794 * attribute.
3795 */
3796void
3797xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003798 xmlNsPtr ns;
3799
Owen Taylor3473f882001-02-23 17:55:21 +00003800 if (cur == NULL) return;
3801 switch(cur->type) {
3802 case XML_TEXT_NODE:
3803 case XML_CDATA_SECTION_NODE:
3804 case XML_COMMENT_NODE:
3805 case XML_DOCUMENT_NODE:
3806 case XML_DOCUMENT_TYPE_NODE:
3807 case XML_DOCUMENT_FRAG_NODE:
3808 case XML_NOTATION_NODE:
3809 case XML_HTML_DOCUMENT_NODE:
3810 case XML_DTD_NODE:
3811 case XML_ELEMENT_DECL:
3812 case XML_ATTRIBUTE_DECL:
3813 case XML_ENTITY_DECL:
3814 case XML_PI_NODE:
3815 case XML_ENTITY_REF_NODE:
3816 case XML_ENTITY_NODE:
3817 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003818#ifdef LIBXML_DOCB_ENABLED
3819 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003820#endif
3821 case XML_XINCLUDE_START:
3822 case XML_XINCLUDE_END:
3823 return;
3824 case XML_ELEMENT_NODE:
3825 case XML_ATTRIBUTE_NODE:
3826 break;
3827 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003828 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3829 if (ns == NULL)
3830 return;
3831 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003832}
3833
3834/**
3835 * xmlNodeGetLang:
3836 * @cur: the node being checked
3837 *
3838 * Searches the language of a node, i.e. the values of the xml:lang
3839 * attribute or the one carried by the nearest ancestor.
3840 *
3841 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003842 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003843 */
3844xmlChar *
3845xmlNodeGetLang(xmlNodePtr cur) {
3846 xmlChar *lang;
3847
3848 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003849 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003850 if (lang != NULL)
3851 return(lang);
3852 cur = cur->parent;
3853 }
3854 return(NULL);
3855}
3856
3857
3858/**
3859 * xmlNodeSetSpacePreserve:
3860 * @cur: the node being changed
3861 * @val: the xml:space value ("0": default, 1: "preserve")
3862 *
3863 * Set (or reset) the space preserving behaviour of a node, i.e. the
3864 * value of the xml:space attribute.
3865 */
3866void
3867xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003868 xmlNsPtr ns;
3869
Owen Taylor3473f882001-02-23 17:55:21 +00003870 if (cur == NULL) return;
3871 switch(cur->type) {
3872 case XML_TEXT_NODE:
3873 case XML_CDATA_SECTION_NODE:
3874 case XML_COMMENT_NODE:
3875 case XML_DOCUMENT_NODE:
3876 case XML_DOCUMENT_TYPE_NODE:
3877 case XML_DOCUMENT_FRAG_NODE:
3878 case XML_NOTATION_NODE:
3879 case XML_HTML_DOCUMENT_NODE:
3880 case XML_DTD_NODE:
3881 case XML_ELEMENT_DECL:
3882 case XML_ATTRIBUTE_DECL:
3883 case XML_ENTITY_DECL:
3884 case XML_PI_NODE:
3885 case XML_ENTITY_REF_NODE:
3886 case XML_ENTITY_NODE:
3887 case XML_NAMESPACE_DECL:
3888 case XML_XINCLUDE_START:
3889 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003890#ifdef LIBXML_DOCB_ENABLED
3891 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003892#endif
3893 return;
3894 case XML_ELEMENT_NODE:
3895 case XML_ATTRIBUTE_NODE:
3896 break;
3897 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003898 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3899 if (ns == NULL)
3900 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003901 switch (val) {
3902 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003903 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003904 break;
3905 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003906 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003907 break;
3908 }
3909}
3910
3911/**
3912 * xmlNodeGetSpacePreserve:
3913 * @cur: the node being checked
3914 *
3915 * Searches the space preserving behaviour of a node, i.e. the values
3916 * of the xml:space attribute or the one carried by the nearest
3917 * ancestor.
3918 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003919 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003920 */
3921int
3922xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3923 xmlChar *space;
3924
3925 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003926 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003927 if (space != NULL) {
3928 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3929 xmlFree(space);
3930 return(1);
3931 }
3932 if (xmlStrEqual(space, BAD_CAST "default")) {
3933 xmlFree(space);
3934 return(0);
3935 }
3936 xmlFree(space);
3937 }
3938 cur = cur->parent;
3939 }
3940 return(-1);
3941}
3942
3943/**
3944 * xmlNodeSetName:
3945 * @cur: the node being changed
3946 * @name: the new tag name
3947 *
3948 * Set (or reset) the name of a node.
3949 */
3950void
3951xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3952 if (cur == NULL) return;
3953 if (name == NULL) return;
3954 switch(cur->type) {
3955 case XML_TEXT_NODE:
3956 case XML_CDATA_SECTION_NODE:
3957 case XML_COMMENT_NODE:
3958 case XML_DOCUMENT_TYPE_NODE:
3959 case XML_DOCUMENT_FRAG_NODE:
3960 case XML_NOTATION_NODE:
3961 case XML_HTML_DOCUMENT_NODE:
3962 case XML_NAMESPACE_DECL:
3963 case XML_XINCLUDE_START:
3964 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003965#ifdef LIBXML_DOCB_ENABLED
3966 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003967#endif
3968 return;
3969 case XML_ELEMENT_NODE:
3970 case XML_ATTRIBUTE_NODE:
3971 case XML_PI_NODE:
3972 case XML_ENTITY_REF_NODE:
3973 case XML_ENTITY_NODE:
3974 case XML_DTD_NODE:
3975 case XML_DOCUMENT_NODE:
3976 case XML_ELEMENT_DECL:
3977 case XML_ATTRIBUTE_DECL:
3978 case XML_ENTITY_DECL:
3979 break;
3980 }
3981 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3982 cur->name = xmlStrdup(name);
3983}
3984
3985/**
3986 * xmlNodeSetBase:
3987 * @cur: the node being changed
3988 * @uri: the new base URI
3989 *
3990 * Set (or reset) the base URI of a node, i.e. the value of the
3991 * xml:base attribute.
3992 */
3993void
3994xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003995 xmlNsPtr ns;
3996
Owen Taylor3473f882001-02-23 17:55:21 +00003997 if (cur == NULL) return;
3998 switch(cur->type) {
3999 case XML_TEXT_NODE:
4000 case XML_CDATA_SECTION_NODE:
4001 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004002 case XML_DOCUMENT_TYPE_NODE:
4003 case XML_DOCUMENT_FRAG_NODE:
4004 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004005 case XML_DTD_NODE:
4006 case XML_ELEMENT_DECL:
4007 case XML_ATTRIBUTE_DECL:
4008 case XML_ENTITY_DECL:
4009 case XML_PI_NODE:
4010 case XML_ENTITY_REF_NODE:
4011 case XML_ENTITY_NODE:
4012 case XML_NAMESPACE_DECL:
4013 case XML_XINCLUDE_START:
4014 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004015 return;
4016 case XML_ELEMENT_NODE:
4017 case XML_ATTRIBUTE_NODE:
4018 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004019 case XML_DOCUMENT_NODE:
4020#ifdef LIBXML_DOCB_ENABLED
4021 case XML_DOCB_DOCUMENT_NODE:
4022#endif
4023 case XML_HTML_DOCUMENT_NODE: {
4024 xmlDocPtr doc = (xmlDocPtr) cur;
4025
4026 if (doc->URL != NULL)
4027 xmlFree((xmlChar *) doc->URL);
4028 if (uri == NULL)
4029 doc->URL = NULL;
4030 else
4031 doc->URL = xmlStrdup(uri);
4032 return;
4033 }
Owen Taylor3473f882001-02-23 17:55:21 +00004034 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004035
4036 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4037 if (ns == NULL)
4038 return;
4039 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004040}
4041
4042/**
Owen Taylor3473f882001-02-23 17:55:21 +00004043 * xmlNodeGetBase:
4044 * @doc: the document the node pertains to
4045 * @cur: the node being checked
4046 *
4047 * Searches for the BASE URL. The code should work on both XML
4048 * and HTML document even if base mechanisms are completely different.
4049 * It returns the base as defined in RFC 2396 sections
4050 * 5.1.1. Base URI within Document Content
4051 * and
4052 * 5.1.2. Base URI from the Encapsulating Entity
4053 * However it does not return the document base (5.1.3), use
4054 * xmlDocumentGetBase() for this
4055 *
4056 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004057 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004058 */
4059xmlChar *
4060xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004061 xmlChar *oldbase = NULL;
4062 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004063
4064 if ((cur == NULL) && (doc == NULL))
4065 return(NULL);
4066 if (doc == NULL) doc = cur->doc;
4067 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4068 cur = doc->children;
4069 while ((cur != NULL) && (cur->name != NULL)) {
4070 if (cur->type != XML_ELEMENT_NODE) {
4071 cur = cur->next;
4072 continue;
4073 }
4074 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4075 cur = cur->children;
4076 continue;
4077 }
4078 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4079 cur = cur->children;
4080 continue;
4081 }
4082 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4083 return(xmlGetProp(cur, BAD_CAST "href"));
4084 }
4085 cur = cur->next;
4086 }
4087 return(NULL);
4088 }
4089 while (cur != NULL) {
4090 if (cur->type == XML_ENTITY_DECL) {
4091 xmlEntityPtr ent = (xmlEntityPtr) cur;
4092 return(xmlStrdup(ent->URI));
4093 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004094 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004095 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004096 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004097 if (oldbase != NULL) {
4098 newbase = xmlBuildURI(oldbase, base);
4099 if (newbase != NULL) {
4100 xmlFree(oldbase);
4101 xmlFree(base);
4102 oldbase = newbase;
4103 } else {
4104 xmlFree(oldbase);
4105 xmlFree(base);
4106 return(NULL);
4107 }
4108 } else {
4109 oldbase = base;
4110 }
4111 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4112 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4113 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4114 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004115 }
4116 }
Owen Taylor3473f882001-02-23 17:55:21 +00004117 cur = cur->parent;
4118 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004119 if ((doc != NULL) && (doc->URL != NULL)) {
4120 if (oldbase == NULL)
4121 return(xmlStrdup(doc->URL));
4122 newbase = xmlBuildURI(oldbase, doc->URL);
4123 xmlFree(oldbase);
4124 return(newbase);
4125 }
4126 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004127}
4128
4129/**
4130 * xmlNodeGetContent:
4131 * @cur: the node being read
4132 *
4133 * Read the value of a node, this can be either the text carried
4134 * directly by this node if it's a TEXT node or the aggregate string
4135 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004136 * Entity references are substituted.
4137 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004138 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004139 */
4140xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004141xmlNodeGetContent(xmlNodePtr cur)
4142{
4143 if (cur == NULL)
4144 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004145 switch (cur->type) {
4146 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004147 case XML_ELEMENT_NODE:{
4148 xmlNodePtr tmp = cur;
4149 xmlBufferPtr buffer;
4150 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004151
Daniel Veillard7646b182002-04-20 06:41:40 +00004152 buffer = xmlBufferCreate();
4153 if (buffer == NULL)
4154 return (NULL);
4155 while (tmp != NULL) {
4156 switch (tmp->type) {
4157 case XML_CDATA_SECTION_NODE:
4158 case XML_TEXT_NODE:
4159 if (tmp->content != NULL)
4160 xmlBufferCat(buffer, tmp->content);
4161 break;
4162 case XML_ENTITY_REF_NODE:{
4163 /* recursive substitution of entity references */
4164 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00004165
Daniel Veillard7646b182002-04-20 06:41:40 +00004166 if (cont) {
4167 xmlBufferCat(buffer,
4168 (const xmlChar *) cont);
4169 xmlFree(cont);
4170 }
4171 break;
4172 }
4173 default:
4174 break;
4175 }
4176 /*
4177 * Skip to next node
4178 */
4179 if (tmp->children != NULL) {
4180 if (tmp->children->type != XML_ENTITY_DECL) {
4181 tmp = tmp->children;
4182 continue;
4183 }
4184 }
4185 if (tmp == cur)
4186 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004187
Daniel Veillard7646b182002-04-20 06:41:40 +00004188 if (tmp->next != NULL) {
4189 tmp = tmp->next;
4190 continue;
4191 }
4192
4193 do {
4194 tmp = tmp->parent;
4195 if (tmp == NULL)
4196 break;
4197 if (tmp == cur) {
4198 tmp = NULL;
4199 break;
4200 }
4201 if (tmp->next != NULL) {
4202 tmp = tmp->next;
4203 break;
4204 }
4205 } while (tmp != NULL);
4206 }
4207 ret = buffer->content;
4208 buffer->content = NULL;
4209 xmlBufferFree(buffer);
4210 return (ret);
4211 }
4212 case XML_ATTRIBUTE_NODE:{
4213 xmlAttrPtr attr = (xmlAttrPtr) cur;
4214
4215 if (attr->parent != NULL)
4216 return (xmlNodeListGetString
4217 (attr->parent->doc, attr->children, 1));
4218 else
4219 return (xmlNodeListGetString(NULL, attr->children, 1));
4220 break;
4221 }
Owen Taylor3473f882001-02-23 17:55:21 +00004222 case XML_COMMENT_NODE:
4223 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004224 if (cur->content != NULL)
4225 return (xmlStrdup(cur->content));
4226 return (NULL);
4227 case XML_ENTITY_REF_NODE:{
4228 xmlEntityPtr ent;
4229 xmlNodePtr tmp;
4230 xmlBufferPtr buffer;
4231 xmlChar *ret;
4232
4233 /* lookup entity declaration */
4234 ent = xmlGetDocEntity(cur->doc, cur->name);
4235 if (ent == NULL)
4236 return (NULL);
4237
4238 buffer = xmlBufferCreate();
4239 if (buffer == NULL)
4240 return (NULL);
4241
4242 /* an entity content can be any "well balanced chunk",
4243 * i.e. the result of the content [43] production:
4244 * http://www.w3.org/TR/REC-xml#NT-content
4245 * -> we iterate through child nodes and recursive call
4246 * xmlNodeGetContent() which handles all possible node types */
4247 tmp = ent->children;
4248 while (tmp) {
4249 xmlChar *cont = xmlNodeGetContent(tmp);
4250
4251 if (cont) {
4252 xmlBufferCat(buffer, (const xmlChar *) cont);
4253 xmlFree(cont);
4254 }
4255 tmp = tmp->next;
4256 }
4257
4258 ret = buffer->content;
4259 buffer->content = NULL;
4260 xmlBufferFree(buffer);
4261 return (ret);
4262 }
Owen Taylor3473f882001-02-23 17:55:21 +00004263 case XML_ENTITY_NODE:
4264 case XML_DOCUMENT_NODE:
4265 case XML_HTML_DOCUMENT_NODE:
4266 case XML_DOCUMENT_TYPE_NODE:
4267 case XML_NOTATION_NODE:
4268 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004269 case XML_XINCLUDE_START:
4270 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004271#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004272 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004273#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00004274 return (NULL);
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004275 case XML_NAMESPACE_DECL: {
4276 xmlChar *tmp;
4277
4278 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4279 return (tmp);
4280 }
Owen Taylor3473f882001-02-23 17:55:21 +00004281 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004282 /* TODO !!! */
4283 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004284 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004285 /* TODO !!! */
4286 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004287 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004288 /* TODO !!! */
4289 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004290 case XML_CDATA_SECTION_NODE:
4291 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004292 if (cur->content != NULL)
4293 return (xmlStrdup(cur->content));
4294 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004295 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004296 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004297}
Owen Taylor3473f882001-02-23 17:55:21 +00004298/**
4299 * xmlNodeSetContent:
4300 * @cur: the node being modified
4301 * @content: the new value of the content
4302 *
4303 * Replace the content of a node.
4304 */
4305void
4306xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4307 if (cur == NULL) {
4308#ifdef DEBUG_TREE
4309 xmlGenericError(xmlGenericErrorContext,
4310 "xmlNodeSetContent : node == NULL\n");
4311#endif
4312 return;
4313 }
4314 switch (cur->type) {
4315 case XML_DOCUMENT_FRAG_NODE:
4316 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004317 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004318 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4319 cur->children = xmlStringGetNodeList(cur->doc, content);
4320 UPDATE_LAST_CHILD_AND_PARENT(cur)
4321 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004322 case XML_TEXT_NODE:
4323 case XML_CDATA_SECTION_NODE:
4324 case XML_ENTITY_REF_NODE:
4325 case XML_ENTITY_NODE:
4326 case XML_PI_NODE:
4327 case XML_COMMENT_NODE:
4328 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004329 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004330 }
4331 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4332 cur->last = cur->children = NULL;
4333 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004334 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004335 } else
4336 cur->content = NULL;
4337 break;
4338 case XML_DOCUMENT_NODE:
4339 case XML_HTML_DOCUMENT_NODE:
4340 case XML_DOCUMENT_TYPE_NODE:
4341 case XML_XINCLUDE_START:
4342 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004343#ifdef LIBXML_DOCB_ENABLED
4344 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004345#endif
4346 break;
4347 case XML_NOTATION_NODE:
4348 break;
4349 case XML_DTD_NODE:
4350 break;
4351 case XML_NAMESPACE_DECL:
4352 break;
4353 case XML_ELEMENT_DECL:
4354 /* TODO !!! */
4355 break;
4356 case XML_ATTRIBUTE_DECL:
4357 /* TODO !!! */
4358 break;
4359 case XML_ENTITY_DECL:
4360 /* TODO !!! */
4361 break;
4362 }
4363}
4364
4365/**
4366 * xmlNodeSetContentLen:
4367 * @cur: the node being modified
4368 * @content: the new value of the content
4369 * @len: the size of @content
4370 *
4371 * Replace the content of a node.
4372 */
4373void
4374xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4375 if (cur == NULL) {
4376#ifdef DEBUG_TREE
4377 xmlGenericError(xmlGenericErrorContext,
4378 "xmlNodeSetContentLen : node == NULL\n");
4379#endif
4380 return;
4381 }
4382 switch (cur->type) {
4383 case XML_DOCUMENT_FRAG_NODE:
4384 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004385 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004386 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4387 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4388 UPDATE_LAST_CHILD_AND_PARENT(cur)
4389 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004390 case XML_TEXT_NODE:
4391 case XML_CDATA_SECTION_NODE:
4392 case XML_ENTITY_REF_NODE:
4393 case XML_ENTITY_NODE:
4394 case XML_PI_NODE:
4395 case XML_COMMENT_NODE:
4396 case XML_NOTATION_NODE:
4397 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004398 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004399 }
4400 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4401 cur->children = cur->last = NULL;
4402 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004403 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004404 } else
4405 cur->content = NULL;
4406 break;
4407 case XML_DOCUMENT_NODE:
4408 case XML_DTD_NODE:
4409 case XML_HTML_DOCUMENT_NODE:
4410 case XML_DOCUMENT_TYPE_NODE:
4411 case XML_NAMESPACE_DECL:
4412 case XML_XINCLUDE_START:
4413 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004414#ifdef LIBXML_DOCB_ENABLED
4415 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004416#endif
4417 break;
4418 case XML_ELEMENT_DECL:
4419 /* TODO !!! */
4420 break;
4421 case XML_ATTRIBUTE_DECL:
4422 /* TODO !!! */
4423 break;
4424 case XML_ENTITY_DECL:
4425 /* TODO !!! */
4426 break;
4427 }
4428}
4429
4430/**
4431 * xmlNodeAddContentLen:
4432 * @cur: the node being modified
4433 * @content: extra content
4434 * @len: the size of @content
4435 *
4436 * Append the extra substring to the node content.
4437 */
4438void
4439xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4440 if (cur == NULL) {
4441#ifdef DEBUG_TREE
4442 xmlGenericError(xmlGenericErrorContext,
4443 "xmlNodeAddContentLen : node == NULL\n");
4444#endif
4445 return;
4446 }
4447 if (len <= 0) return;
4448 switch (cur->type) {
4449 case XML_DOCUMENT_FRAG_NODE:
4450 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004451 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004452
Daniel Veillard7db37732001-07-12 01:20:08 +00004453 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004454 newNode = xmlNewTextLen(content, len);
4455 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004456 tmp = xmlAddChild(cur, newNode);
4457 if (tmp != newNode)
4458 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004459 if ((last != NULL) && (last->next == newNode)) {
4460 xmlTextMerge(last, newNode);
4461 }
4462 }
4463 break;
4464 }
4465 case XML_ATTRIBUTE_NODE:
4466 break;
4467 case XML_TEXT_NODE:
4468 case XML_CDATA_SECTION_NODE:
4469 case XML_ENTITY_REF_NODE:
4470 case XML_ENTITY_NODE:
4471 case XML_PI_NODE:
4472 case XML_COMMENT_NODE:
4473 case XML_NOTATION_NODE:
4474 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004475 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004476 }
4477 case XML_DOCUMENT_NODE:
4478 case XML_DTD_NODE:
4479 case XML_HTML_DOCUMENT_NODE:
4480 case XML_DOCUMENT_TYPE_NODE:
4481 case XML_NAMESPACE_DECL:
4482 case XML_XINCLUDE_START:
4483 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004484#ifdef LIBXML_DOCB_ENABLED
4485 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004486#endif
4487 break;
4488 case XML_ELEMENT_DECL:
4489 case XML_ATTRIBUTE_DECL:
4490 case XML_ENTITY_DECL:
4491 break;
4492 }
4493}
4494
4495/**
4496 * xmlNodeAddContent:
4497 * @cur: the node being modified
4498 * @content: extra content
4499 *
4500 * Append the extra substring to the node content.
4501 */
4502void
4503xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4504 int len;
4505
4506 if (cur == NULL) {
4507#ifdef DEBUG_TREE
4508 xmlGenericError(xmlGenericErrorContext,
4509 "xmlNodeAddContent : node == NULL\n");
4510#endif
4511 return;
4512 }
4513 if (content == NULL) return;
4514 len = xmlStrlen(content);
4515 xmlNodeAddContentLen(cur, content, len);
4516}
4517
4518/**
4519 * xmlTextMerge:
4520 * @first: the first text node
4521 * @second: the second text node being merged
4522 *
4523 * Merge two text nodes into one
4524 * Returns the first text node augmented
4525 */
4526xmlNodePtr
4527xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4528 if (first == NULL) return(second);
4529 if (second == NULL) return(first);
4530 if (first->type != XML_TEXT_NODE) return(first);
4531 if (second->type != XML_TEXT_NODE) return(first);
4532 if (second->name != first->name)
4533 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004534 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004535 xmlUnlinkNode(second);
4536 xmlFreeNode(second);
4537 return(first);
4538}
4539
4540/**
4541 * xmlGetNsList:
4542 * @doc: the document
4543 * @node: the current node
4544 *
4545 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004546 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004547 * that need to be freed by the caller or NULL if no
4548 * namespace if defined
4549 */
4550xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004551xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4552{
Owen Taylor3473f882001-02-23 17:55:21 +00004553 xmlNsPtr cur;
4554 xmlNsPtr *ret = NULL;
4555 int nbns = 0;
4556 int maxns = 10;
4557 int i;
4558
4559 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004560 if (node->type == XML_ELEMENT_NODE) {
4561 cur = node->nsDef;
4562 while (cur != NULL) {
4563 if (ret == NULL) {
4564 ret =
4565 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4566 sizeof(xmlNsPtr));
4567 if (ret == NULL) {
4568 xmlGenericError(xmlGenericErrorContext,
4569 "xmlGetNsList : out of memory!\n");
4570 return (NULL);
4571 }
4572 ret[nbns] = NULL;
4573 }
4574 for (i = 0; i < nbns; i++) {
4575 if ((cur->prefix == ret[i]->prefix) ||
4576 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4577 break;
4578 }
4579 if (i >= nbns) {
4580 if (nbns >= maxns) {
4581 maxns *= 2;
4582 ret = (xmlNsPtr *) xmlRealloc(ret,
4583 (maxns +
4584 1) *
4585 sizeof(xmlNsPtr));
4586 if (ret == NULL) {
4587 xmlGenericError(xmlGenericErrorContext,
4588 "xmlGetNsList : realloc failed!\n");
4589 return (NULL);
4590 }
4591 }
4592 ret[nbns++] = cur;
4593 ret[nbns] = NULL;
4594 }
Owen Taylor3473f882001-02-23 17:55:21 +00004595
Daniel Veillard77044732001-06-29 21:31:07 +00004596 cur = cur->next;
4597 }
4598 }
4599 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004600 }
Daniel Veillard77044732001-06-29 21:31:07 +00004601 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004602}
4603
4604/**
4605 * xmlSearchNs:
4606 * @doc: the document
4607 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004608 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004609 *
4610 * Search a Ns registered under a given name space for a document.
4611 * recurse on the parents until it finds the defined namespace
4612 * or return NULL otherwise.
4613 * @nameSpace can be NULL, this is a search for the default namespace.
4614 * We don't allow to cross entities boundaries. If you don't declare
4615 * the namespace within those you will be in troubles !!! A warning
4616 * is generated to cover this case.
4617 *
4618 * Returns the namespace pointer or NULL.
4619 */
4620xmlNsPtr
4621xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4622 xmlNsPtr cur;
4623
4624 if (node == NULL) return(NULL);
4625 if ((nameSpace != NULL) &&
4626 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00004627 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4628 /*
4629 * The XML-1.0 namespace is normally held on the root
4630 * element. In this case exceptionally create it on the
4631 * node element.
4632 */
4633 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4634 if (cur == NULL) {
4635 xmlGenericError(xmlGenericErrorContext,
4636 "xmlSearchNs : malloc failed\n");
4637 return(NULL);
4638 }
4639 memset(cur, 0, sizeof(xmlNs));
4640 cur->type = XML_LOCAL_NAMESPACE;
4641 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4642 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4643 cur->next = node->nsDef;
4644 node->nsDef = cur;
4645 return(cur);
4646 }
Owen Taylor3473f882001-02-23 17:55:21 +00004647 if (doc->oldNs == NULL) {
4648 /*
4649 * Allocate a new Namespace and fill the fields.
4650 */
4651 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4652 if (doc->oldNs == NULL) {
4653 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004654 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004655 return(NULL);
4656 }
4657 memset(doc->oldNs, 0, sizeof(xmlNs));
4658 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4659
4660 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4661 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4662 }
4663 return(doc->oldNs);
4664 }
4665 while (node != NULL) {
4666 if ((node->type == XML_ENTITY_REF_NODE) ||
4667 (node->type == XML_ENTITY_NODE) ||
4668 (node->type == XML_ENTITY_DECL))
4669 return(NULL);
4670 if (node->type == XML_ELEMENT_NODE) {
4671 cur = node->nsDef;
4672 while (cur != NULL) {
4673 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4674 (cur->href != NULL))
4675 return(cur);
4676 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4677 (cur->href != NULL) &&
4678 (xmlStrEqual(cur->prefix, nameSpace)))
4679 return(cur);
4680 cur = cur->next;
4681 }
4682 }
4683 node = node->parent;
4684 }
4685 return(NULL);
4686}
4687
4688/**
4689 * xmlSearchNsByHref:
4690 * @doc: the document
4691 * @node: the current node
4692 * @href: the namespace value
4693 *
4694 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4695 * the defined namespace or return NULL otherwise.
4696 * Returns the namespace pointer or NULL.
4697 */
4698xmlNsPtr
4699xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4700 xmlNsPtr cur;
4701 xmlNodePtr orig = node;
4702
4703 if ((node == NULL) || (href == NULL)) return(NULL);
4704 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004705 /*
4706 * Only the document can hold the XML spec namespace.
4707 */
Daniel Veillardc1a0da32002-08-14 08:32:18 +00004708 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4709 /*
4710 * The XML-1.0 namespace is normally held on the root
4711 * element. In this case exceptionally create it on the
4712 * node element.
4713 */
4714 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4715 if (cur == NULL) {
4716 xmlGenericError(xmlGenericErrorContext,
4717 "xmlSearchNs : malloc failed\n");
4718 return(NULL);
4719 }
4720 memset(cur, 0, sizeof(xmlNs));
4721 cur->type = XML_LOCAL_NAMESPACE;
4722 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4723 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4724 cur->next = node->nsDef;
4725 node->nsDef = cur;
4726 return(cur);
4727 }
Owen Taylor3473f882001-02-23 17:55:21 +00004728 if (doc->oldNs == NULL) {
4729 /*
4730 * Allocate a new Namespace and fill the fields.
4731 */
4732 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4733 if (doc->oldNs == NULL) {
4734 xmlGenericError(xmlGenericErrorContext,
4735 "xmlSearchNsByHref : malloc failed\n");
4736 return(NULL);
4737 }
4738 memset(doc->oldNs, 0, sizeof(xmlNs));
4739 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4740
4741 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4742 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4743 }
4744 return(doc->oldNs);
4745 }
4746 while (node != NULL) {
4747 cur = node->nsDef;
4748 while (cur != NULL) {
4749 if ((cur->href != NULL) && (href != NULL) &&
4750 (xmlStrEqual(cur->href, href))) {
4751 /*
4752 * Check that the prefix is not shadowed between orig and node
4753 */
4754 xmlNodePtr check = orig;
4755 xmlNsPtr tst;
4756
4757 while (check != node) {
4758 tst = check->nsDef;
4759 while (tst != NULL) {
4760 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4761 goto shadowed;
4762 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4763 (xmlStrEqual(tst->prefix, cur->prefix)))
4764 goto shadowed;
4765 tst = tst->next;
4766 }
4767 check = check->parent;
4768 }
4769 return(cur);
4770 }
4771shadowed:
4772 cur = cur->next;
4773 }
4774 node = node->parent;
4775 }
4776 return(NULL);
4777}
4778
4779/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004780 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00004781 * @doc: the document
4782 * @tree: a node expected to hold the new namespace
4783 * @ns: the original namespace
4784 *
4785 * This function tries to locate a namespace definition in a tree
4786 * ancestors, or create a new namespace definition node similar to
4787 * @ns trying to reuse the same prefix. However if the given prefix is
4788 * null (default namespace) or reused within the subtree defined by
4789 * @tree or on one of its ancestors then a new prefix is generated.
4790 * Returns the (new) namespace definition or NULL in case of error
4791 */
4792xmlNsPtr
4793xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4794 xmlNsPtr def;
4795 xmlChar prefix[50];
4796 int counter = 1;
4797
4798 if (tree == NULL) {
4799#ifdef DEBUG_TREE
4800 xmlGenericError(xmlGenericErrorContext,
4801 "xmlNewReconciliedNs : tree == NULL\n");
4802#endif
4803 return(NULL);
4804 }
4805 if (ns == NULL) {
4806#ifdef DEBUG_TREE
4807 xmlGenericError(xmlGenericErrorContext,
4808 "xmlNewReconciliedNs : ns == NULL\n");
4809#endif
4810 return(NULL);
4811 }
4812 /*
4813 * Search an existing namespace definition inherited.
4814 */
4815 def = xmlSearchNsByHref(doc, tree, ns->href);
4816 if (def != NULL)
4817 return(def);
4818
4819 /*
4820 * Find a close prefix which is not already in use.
4821 * Let's strip namespace prefixes longer than 20 chars !
4822 */
Daniel Veillardf742d342002-03-07 00:05:35 +00004823 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004824 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00004825 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004826 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00004827
Owen Taylor3473f882001-02-23 17:55:21 +00004828 def = xmlSearchNs(doc, tree, prefix);
4829 while (def != NULL) {
4830 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00004831 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004832 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00004833 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004834 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00004835 def = xmlSearchNs(doc, tree, prefix);
4836 }
4837
4838 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004839 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004840 */
4841 def = xmlNewNs(tree, ns->href, prefix);
4842 return(def);
4843}
4844
4845/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004846 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00004847 * @doc: the document
4848 * @tree: a node defining the subtree to reconciliate
4849 *
4850 * This function checks that all the namespaces declared within the given
4851 * tree are properly declared. This is needed for example after Copy or Cut
4852 * and then paste operations. The subtree may still hold pointers to
4853 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004854 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004855 * the new environment. If not possible the new namespaces are redeclared
4856 * on @tree at the top of the given subtree.
4857 * Returns the number of namespace declarations created or -1 in case of error.
4858 */
4859int
4860xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4861 xmlNsPtr *oldNs = NULL;
4862 xmlNsPtr *newNs = NULL;
4863 int sizeCache = 0;
4864 int nbCache = 0;
4865
4866 xmlNsPtr n;
4867 xmlNodePtr node = tree;
4868 xmlAttrPtr attr;
4869 int ret = 0, i;
4870
4871 while (node != NULL) {
4872 /*
4873 * Reconciliate the node namespace
4874 */
4875 if (node->ns != NULL) {
4876 /*
4877 * initialize the cache if needed
4878 */
4879 if (sizeCache == 0) {
4880 sizeCache = 10;
4881 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4882 sizeof(xmlNsPtr));
4883 if (oldNs == NULL) {
4884 xmlGenericError(xmlGenericErrorContext,
4885 "xmlReconciliateNs : memory pbm\n");
4886 return(-1);
4887 }
4888 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4889 sizeof(xmlNsPtr));
4890 if (newNs == NULL) {
4891 xmlGenericError(xmlGenericErrorContext,
4892 "xmlReconciliateNs : memory pbm\n");
4893 xmlFree(oldNs);
4894 return(-1);
4895 }
4896 }
4897 for (i = 0;i < nbCache;i++) {
4898 if (oldNs[i] == node->ns) {
4899 node->ns = newNs[i];
4900 break;
4901 }
4902 }
4903 if (i == nbCache) {
4904 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004905 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004906 */
4907 n = xmlNewReconciliedNs(doc, tree, node->ns);
4908 if (n != NULL) { /* :-( what if else ??? */
4909 /*
4910 * check if we need to grow the cache buffers.
4911 */
4912 if (sizeCache <= nbCache) {
4913 sizeCache *= 2;
4914 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4915 sizeof(xmlNsPtr));
4916 if (oldNs == NULL) {
4917 xmlGenericError(xmlGenericErrorContext,
4918 "xmlReconciliateNs : memory pbm\n");
4919 xmlFree(newNs);
4920 return(-1);
4921 }
4922 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4923 sizeof(xmlNsPtr));
4924 if (newNs == NULL) {
4925 xmlGenericError(xmlGenericErrorContext,
4926 "xmlReconciliateNs : memory pbm\n");
4927 xmlFree(oldNs);
4928 return(-1);
4929 }
4930 }
4931 newNs[nbCache] = n;
4932 oldNs[nbCache++] = node->ns;
4933 node->ns = n;
4934 }
4935 }
4936 }
4937 /*
4938 * now check for namespace hold by attributes on the node.
4939 */
4940 attr = node->properties;
4941 while (attr != NULL) {
4942 if (attr->ns != NULL) {
4943 /*
4944 * initialize the cache if needed
4945 */
4946 if (sizeCache == 0) {
4947 sizeCache = 10;
4948 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4949 sizeof(xmlNsPtr));
4950 if (oldNs == NULL) {
4951 xmlGenericError(xmlGenericErrorContext,
4952 "xmlReconciliateNs : memory pbm\n");
4953 return(-1);
4954 }
4955 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4956 sizeof(xmlNsPtr));
4957 if (newNs == NULL) {
4958 xmlGenericError(xmlGenericErrorContext,
4959 "xmlReconciliateNs : memory pbm\n");
4960 xmlFree(oldNs);
4961 return(-1);
4962 }
4963 }
4964 for (i = 0;i < nbCache;i++) {
4965 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00004966 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00004967 break;
4968 }
4969 }
4970 if (i == nbCache) {
4971 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004972 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004973 */
4974 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4975 if (n != NULL) { /* :-( what if else ??? */
4976 /*
4977 * check if we need to grow the cache buffers.
4978 */
4979 if (sizeCache <= nbCache) {
4980 sizeCache *= 2;
4981 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4982 sizeof(xmlNsPtr));
4983 if (oldNs == NULL) {
4984 xmlGenericError(xmlGenericErrorContext,
4985 "xmlReconciliateNs : memory pbm\n");
4986 xmlFree(newNs);
4987 return(-1);
4988 }
4989 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4990 sizeof(xmlNsPtr));
4991 if (newNs == NULL) {
4992 xmlGenericError(xmlGenericErrorContext,
4993 "xmlReconciliateNs : memory pbm\n");
4994 xmlFree(oldNs);
4995 return(-1);
4996 }
4997 }
4998 newNs[nbCache] = n;
4999 oldNs[nbCache++] = attr->ns;
5000 attr->ns = n;
5001 }
5002 }
5003 }
5004 attr = attr->next;
5005 }
5006
5007 /*
5008 * Browse the full subtree, deep first
5009 */
5010 if (node->children != NULL) {
5011 /* deep first */
5012 node = node->children;
5013 } else if ((node != tree) && (node->next != NULL)) {
5014 /* then siblings */
5015 node = node->next;
5016 } else if (node != tree) {
5017 /* go up to parents->next if needed */
5018 while (node != tree) {
5019 if (node->parent != NULL)
5020 node = node->parent;
5021 if ((node != tree) && (node->next != NULL)) {
5022 node = node->next;
5023 break;
5024 }
5025 if (node->parent == NULL) {
5026 node = NULL;
5027 break;
5028 }
5029 }
5030 /* exit condition */
5031 if (node == tree)
5032 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005033 } else
5034 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005035 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005036 if (oldNs != NULL)
5037 xmlFree(oldNs);
5038 if (newNs != NULL)
5039 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005040 return(ret);
5041}
5042
5043/**
5044 * xmlHasProp:
5045 * @node: the node
5046 * @name: the attribute name
5047 *
5048 * Search an attribute associated to a node
5049 * This function also looks in DTD attribute declaration for #FIXED or
5050 * default declaration values unless DTD use has been turned off.
5051 *
5052 * Returns the attribute or the attribute declaration or NULL if
5053 * neither was found.
5054 */
5055xmlAttrPtr
5056xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5057 xmlAttrPtr prop;
5058 xmlDocPtr doc;
5059
5060 if ((node == NULL) || (name == NULL)) return(NULL);
5061 /*
5062 * Check on the properties attached to the node
5063 */
5064 prop = node->properties;
5065 while (prop != NULL) {
5066 if (xmlStrEqual(prop->name, name)) {
5067 return(prop);
5068 }
5069 prop = prop->next;
5070 }
5071 if (!xmlCheckDTD) return(NULL);
5072
5073 /*
5074 * Check if there is a default declaration in the internal
5075 * or external subsets
5076 */
5077 doc = node->doc;
5078 if (doc != NULL) {
5079 xmlAttributePtr attrDecl;
5080 if (doc->intSubset != NULL) {
5081 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5082 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5083 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5084 if (attrDecl != NULL)
5085 return((xmlAttrPtr) attrDecl);
5086 }
5087 }
5088 return(NULL);
5089}
5090
5091/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005092 * xmlHasNsProp:
5093 * @node: the node
5094 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005095 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005096 *
5097 * Search for an attribute associated to a node
5098 * This attribute has to be anchored in the namespace specified.
5099 * This does the entity substitution.
5100 * This function looks in DTD attribute declaration for #FIXED or
5101 * default declaration values unless DTD use has been turned off.
5102 *
5103 * Returns the attribute or the attribute declaration or NULL
5104 * if neither was found.
5105 */
5106xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005107xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005108 xmlAttrPtr prop;
5109 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005110
5111 if (node == NULL)
5112 return(NULL);
5113
5114 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005115 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005116 return(xmlHasProp(node, name));
5117 while (prop != NULL) {
5118 /*
5119 * One need to have
5120 * - same attribute names
5121 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005122 */
5123 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005124 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5125 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005126 }
5127 prop = prop->next;
5128 }
5129 if (!xmlCheckDTD) return(NULL);
5130
5131 /*
5132 * Check if there is a default declaration in the internal
5133 * or external subsets
5134 */
5135 doc = node->doc;
5136 if (doc != NULL) {
5137 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005138 xmlAttributePtr attrDecl = NULL;
5139 xmlNsPtr *nsList, *cur;
5140 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005141
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005142 nsList = xmlGetNsList(node->doc, node);
5143 if (nsList == NULL)
5144 return(NULL);
5145 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5146 ename = xmlStrdup(node->ns->prefix);
5147 ename = xmlStrcat(ename, BAD_CAST ":");
5148 ename = xmlStrcat(ename, node->name);
5149 } else {
5150 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005151 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005152 if (ename == NULL) {
5153 xmlFree(nsList);
5154 return(NULL);
5155 }
5156
5157 cur = nsList;
5158 while (*cur != NULL) {
5159 if (xmlStrEqual((*cur)->href, nameSpace)) {
5160 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5161 name, (*cur)->prefix);
5162 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5163 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5164 name, (*cur)->prefix);
5165 }
5166 cur++;
5167 }
5168 xmlFree(nsList);
5169 xmlFree(ename);
5170 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005171 }
5172 }
5173 return(NULL);
5174}
5175
5176/**
Owen Taylor3473f882001-02-23 17:55:21 +00005177 * xmlGetProp:
5178 * @node: the node
5179 * @name: the attribute name
5180 *
5181 * Search and get the value of an attribute associated to a node
5182 * This does the entity substitution.
5183 * This function looks in DTD attribute declaration for #FIXED or
5184 * default declaration values unless DTD use has been turned off.
5185 *
5186 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005187 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005188 */
5189xmlChar *
5190xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5191 xmlAttrPtr prop;
5192 xmlDocPtr doc;
5193
5194 if ((node == NULL) || (name == NULL)) return(NULL);
5195 /*
5196 * Check on the properties attached to the node
5197 */
5198 prop = node->properties;
5199 while (prop != NULL) {
5200 if (xmlStrEqual(prop->name, name)) {
5201 xmlChar *ret;
5202
5203 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5204 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5205 return(ret);
5206 }
5207 prop = prop->next;
5208 }
5209 if (!xmlCheckDTD) return(NULL);
5210
5211 /*
5212 * Check if there is a default declaration in the internal
5213 * or external subsets
5214 */
5215 doc = node->doc;
5216 if (doc != NULL) {
5217 xmlAttributePtr attrDecl;
5218 if (doc->intSubset != NULL) {
5219 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5220 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5221 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5222 if (attrDecl != NULL)
5223 return(xmlStrdup(attrDecl->defaultValue));
5224 }
5225 }
5226 return(NULL);
5227}
5228
5229/**
5230 * xmlGetNsProp:
5231 * @node: the node
5232 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005233 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005234 *
5235 * Search and get the value of an attribute associated to a node
5236 * This attribute has to be anchored in the namespace specified.
5237 * This does the entity substitution.
5238 * This function looks in DTD attribute declaration for #FIXED or
5239 * default declaration values unless DTD use has been turned off.
5240 *
5241 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005242 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005243 */
5244xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005245xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005246 xmlAttrPtr prop;
5247 xmlDocPtr doc;
5248 xmlNsPtr ns;
5249
5250 if (node == NULL)
5251 return(NULL);
5252
5253 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005254 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005255 return(xmlGetProp(node, name));
5256 while (prop != NULL) {
5257 /*
5258 * One need to have
5259 * - same attribute names
5260 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005261 */
5262 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005263 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005264 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005265 xmlChar *ret;
5266
5267 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5268 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5269 return(ret);
5270 }
5271 prop = prop->next;
5272 }
5273 if (!xmlCheckDTD) return(NULL);
5274
5275 /*
5276 * Check if there is a default declaration in the internal
5277 * or external subsets
5278 */
5279 doc = node->doc;
5280 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005281 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005282 xmlAttributePtr attrDecl;
5283
Owen Taylor3473f882001-02-23 17:55:21 +00005284 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5285 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5286 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5287
5288 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5289 /*
5290 * The DTD declaration only allows a prefix search
5291 */
5292 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005293 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005294 return(xmlStrdup(attrDecl->defaultValue));
5295 }
5296 }
5297 }
5298 return(NULL);
5299}
5300
5301/**
5302 * xmlSetProp:
5303 * @node: the node
5304 * @name: the attribute name
5305 * @value: the attribute value
5306 *
5307 * Set (or reset) an attribute carried by a node.
5308 * Returns the attribute pointer.
5309 */
5310xmlAttrPtr
5311xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005312 xmlAttrPtr prop;
5313 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005314
5315 if ((node == NULL) || (name == NULL))
5316 return(NULL);
5317 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005318 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005319 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005320 if ((xmlStrEqual(prop->name, name)) &&
5321 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005322 xmlNodePtr oldprop = prop->children;
5323
Owen Taylor3473f882001-02-23 17:55:21 +00005324 prop->children = NULL;
5325 prop->last = NULL;
5326 if (value != NULL) {
5327 xmlChar *buffer;
5328 xmlNodePtr tmp;
5329
5330 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5331 prop->children = xmlStringGetNodeList(node->doc, buffer);
5332 prop->last = NULL;
5333 prop->doc = doc;
5334 tmp = prop->children;
5335 while (tmp != NULL) {
5336 tmp->parent = (xmlNodePtr) prop;
5337 tmp->doc = doc;
5338 if (tmp->next == NULL)
5339 prop->last = tmp;
5340 tmp = tmp->next;
5341 }
5342 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005343 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005344 if (oldprop != NULL)
5345 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005346 return(prop);
5347 }
5348 prop = prop->next;
5349 }
5350 prop = xmlNewProp(node, name, value);
5351 return(prop);
5352}
5353
5354/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005355 * xmlUnsetProp:
5356 * @node: the node
5357 * @name: the attribute name
5358 *
5359 * Remove an attribute carried by a node.
5360 * Returns 0 if successful, -1 if not found
5361 */
5362int
5363xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
5364 xmlAttrPtr prop = node->properties, prev = NULL;;
5365
5366 if ((node == NULL) || (name == NULL))
5367 return(-1);
5368 while (prop != NULL) {
5369 if ((xmlStrEqual(prop->name, name)) &&
5370 (prop->ns == NULL)) {
5371 if (prev == NULL)
5372 node->properties = prop->next;
5373 else
5374 prev->next = prop->next;
5375 xmlFreeProp(prop);
5376 return(0);
5377 }
5378 prev = prop;
5379 prop = prop->next;
5380 }
5381 return(-1);
5382}
5383
5384/**
Owen Taylor3473f882001-02-23 17:55:21 +00005385 * xmlSetNsProp:
5386 * @node: the node
5387 * @ns: the namespace definition
5388 * @name: the attribute name
5389 * @value: the attribute value
5390 *
5391 * Set (or reset) an attribute carried by a node.
5392 * The ns structure must be in scope, this is not checked.
5393 *
5394 * Returns the attribute pointer.
5395 */
5396xmlAttrPtr
5397xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5398 const xmlChar *value) {
5399 xmlAttrPtr prop;
5400
5401 if ((node == NULL) || (name == NULL))
5402 return(NULL);
5403
5404 if (ns == NULL)
5405 return(xmlSetProp(node, name, value));
5406 if (ns->href == NULL)
5407 return(NULL);
5408 prop = node->properties;
5409
5410 while (prop != NULL) {
5411 /*
5412 * One need to have
5413 * - same attribute names
5414 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005415 */
5416 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00005417 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005418 if (prop->children != NULL)
5419 xmlFreeNodeList(prop->children);
5420 prop->children = NULL;
5421 prop->last = NULL;
5422 prop->ns = ns;
5423 if (value != NULL) {
5424 xmlChar *buffer;
5425 xmlNodePtr tmp;
5426
5427 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5428 prop->children = xmlStringGetNodeList(node->doc, buffer);
5429 prop->last = NULL;
5430 tmp = prop->children;
5431 while (tmp != NULL) {
5432 tmp->parent = (xmlNodePtr) prop;
5433 if (tmp->next == NULL)
5434 prop->last = tmp;
5435 tmp = tmp->next;
5436 }
5437 xmlFree(buffer);
5438 }
5439 return(prop);
5440 }
5441 prop = prop->next;
5442 }
5443 prop = xmlNewNsProp(node, ns, name, value);
5444 return(prop);
5445}
5446
5447/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005448 * xmlUnsetNsProp:
5449 * @node: the node
5450 * @ns: the namespace definition
5451 * @name: the attribute name
5452 *
5453 * Remove an attribute carried by a node.
5454 * Returns 0 if successful, -1 if not found
5455 */
5456int
5457xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5458 xmlAttrPtr prop = node->properties, prev = NULL;;
5459
5460 if ((node == NULL) || (name == NULL))
5461 return(-1);
5462 if (ns == NULL)
5463 return(xmlUnsetProp(node, name));
5464 if (ns->href == NULL)
5465 return(-1);
5466 while (prop != NULL) {
5467 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00005468 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005469 if (prev == NULL)
5470 node->properties = prop->next;
5471 else
5472 prev->next = prop->next;
5473 xmlFreeProp(prop);
5474 return(0);
5475 }
5476 prev = prop;
5477 prop = prop->next;
5478 }
5479 return(-1);
5480}
5481
5482/**
Owen Taylor3473f882001-02-23 17:55:21 +00005483 * xmlNodeIsText:
5484 * @node: the node
5485 *
5486 * Is this node a Text node ?
5487 * Returns 1 yes, 0 no
5488 */
5489int
5490xmlNodeIsText(xmlNodePtr node) {
5491 if (node == NULL) return(0);
5492
5493 if (node->type == XML_TEXT_NODE) return(1);
5494 return(0);
5495}
5496
5497/**
5498 * xmlIsBlankNode:
5499 * @node: the node
5500 *
5501 * Checks whether this node is an empty or whitespace only
5502 * (and possibly ignorable) text-node.
5503 *
5504 * Returns 1 yes, 0 no
5505 */
5506int
5507xmlIsBlankNode(xmlNodePtr node) {
5508 const xmlChar *cur;
5509 if (node == NULL) return(0);
5510
Daniel Veillard7db37732001-07-12 01:20:08 +00005511 if ((node->type != XML_TEXT_NODE) &&
5512 (node->type != XML_CDATA_SECTION_NODE))
5513 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005514 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005515 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005516 while (*cur != 0) {
5517 if (!IS_BLANK(*cur)) return(0);
5518 cur++;
5519 }
5520
5521 return(1);
5522}
5523
5524/**
5525 * xmlTextConcat:
5526 * @node: the node
5527 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005528 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005529 *
5530 * Concat the given string at the end of the existing node content
5531 */
5532
5533void
5534xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5535 if (node == NULL) return;
5536
5537 if ((node->type != XML_TEXT_NODE) &&
5538 (node->type != XML_CDATA_SECTION_NODE)) {
5539#ifdef DEBUG_TREE
5540 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005541 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005542#endif
5543 return;
5544 }
Owen Taylor3473f882001-02-23 17:55:21 +00005545 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005546}
5547
5548/************************************************************************
5549 * *
5550 * Output : to a FILE or in memory *
5551 * *
5552 ************************************************************************/
5553
Owen Taylor3473f882001-02-23 17:55:21 +00005554/**
5555 * xmlBufferCreate:
5556 *
5557 * routine to create an XML buffer.
5558 * returns the new structure.
5559 */
5560xmlBufferPtr
5561xmlBufferCreate(void) {
5562 xmlBufferPtr ret;
5563
5564 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5565 if (ret == NULL) {
5566 xmlGenericError(xmlGenericErrorContext,
5567 "xmlBufferCreate : out of memory!\n");
5568 return(NULL);
5569 }
5570 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005571 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005572 ret->alloc = xmlBufferAllocScheme;
5573 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5574 if (ret->content == NULL) {
5575 xmlGenericError(xmlGenericErrorContext,
5576 "xmlBufferCreate : out of memory!\n");
5577 xmlFree(ret);
5578 return(NULL);
5579 }
5580 ret->content[0] = 0;
5581 return(ret);
5582}
5583
5584/**
5585 * xmlBufferCreateSize:
5586 * @size: initial size of buffer
5587 *
5588 * routine to create an XML buffer.
5589 * returns the new structure.
5590 */
5591xmlBufferPtr
5592xmlBufferCreateSize(size_t size) {
5593 xmlBufferPtr ret;
5594
5595 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5596 if (ret == NULL) {
5597 xmlGenericError(xmlGenericErrorContext,
5598 "xmlBufferCreate : out of memory!\n");
5599 return(NULL);
5600 }
5601 ret->use = 0;
5602 ret->alloc = xmlBufferAllocScheme;
5603 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5604 if (ret->size){
5605 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5606 if (ret->content == NULL) {
5607 xmlGenericError(xmlGenericErrorContext,
5608 "xmlBufferCreate : out of memory!\n");
5609 xmlFree(ret);
5610 return(NULL);
5611 }
5612 ret->content[0] = 0;
5613 } else
5614 ret->content = NULL;
5615 return(ret);
5616}
5617
5618/**
5619 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005620 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00005621 * @scheme: allocation scheme to use
5622 *
5623 * Sets the allocation scheme for this buffer
5624 */
5625void
5626xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5627 xmlBufferAllocationScheme scheme) {
5628 if (buf == NULL) {
5629#ifdef DEBUG_BUFFER
5630 xmlGenericError(xmlGenericErrorContext,
5631 "xmlBufferSetAllocationScheme: buf == NULL\n");
5632#endif
5633 return;
5634 }
5635
5636 buf->alloc = scheme;
5637}
5638
5639/**
5640 * xmlBufferFree:
5641 * @buf: the buffer to free
5642 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005643 * Frees an XML buffer. It frees both the content and the structure which
5644 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005645 */
5646void
5647xmlBufferFree(xmlBufferPtr buf) {
5648 if (buf == NULL) {
5649#ifdef DEBUG_BUFFER
5650 xmlGenericError(xmlGenericErrorContext,
5651 "xmlBufferFree: buf == NULL\n");
5652#endif
5653 return;
5654 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00005655 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005656 xmlFree(buf->content);
5657 }
Owen Taylor3473f882001-02-23 17:55:21 +00005658 xmlFree(buf);
5659}
5660
5661/**
5662 * xmlBufferEmpty:
5663 * @buf: the buffer
5664 *
5665 * empty a buffer.
5666 */
5667void
5668xmlBufferEmpty(xmlBufferPtr buf) {
5669 if (buf->content == NULL) return;
5670 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005671 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005672}
5673
5674/**
5675 * xmlBufferShrink:
5676 * @buf: the buffer to dump
5677 * @len: the number of xmlChar to remove
5678 *
5679 * Remove the beginning of an XML buffer.
5680 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005681 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005682 */
5683int
5684xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5685 if (len == 0) return(0);
5686 if (len > buf->use) return(-1);
5687
5688 buf->use -= len;
5689 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5690
5691 buf->content[buf->use] = 0;
5692 return(len);
5693}
5694
5695/**
5696 * xmlBufferGrow:
5697 * @buf: the buffer
5698 * @len: the minimum free size to allocate
5699 *
5700 * Grow the available space of an XML buffer.
5701 *
5702 * Returns the new available space or -1 in case of error
5703 */
5704int
5705xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5706 int size;
5707 xmlChar *newbuf;
5708
5709 if (len + buf->use < buf->size) return(0);
5710
5711 size = buf->use + len + 100;
5712
5713 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5714 if (newbuf == NULL) return(-1);
5715 buf->content = newbuf;
5716 buf->size = size;
5717 return(buf->size - buf->use);
5718}
5719
5720/**
5721 * xmlBufferDump:
5722 * @file: the file output
5723 * @buf: the buffer to dump
5724 *
5725 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005726 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005727 */
5728int
5729xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5730 int ret;
5731
5732 if (buf == NULL) {
5733#ifdef DEBUG_BUFFER
5734 xmlGenericError(xmlGenericErrorContext,
5735 "xmlBufferDump: buf == NULL\n");
5736#endif
5737 return(0);
5738 }
5739 if (buf->content == NULL) {
5740#ifdef DEBUG_BUFFER
5741 xmlGenericError(xmlGenericErrorContext,
5742 "xmlBufferDump: buf->content == NULL\n");
5743#endif
5744 return(0);
5745 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005746 if (file == NULL)
5747 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005748 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5749 return(ret);
5750}
5751
5752/**
5753 * xmlBufferContent:
5754 * @buf: the buffer
5755 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005756 * Function to extract the content of a buffer
5757 *
Owen Taylor3473f882001-02-23 17:55:21 +00005758 * Returns the internal content
5759 */
5760
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005761const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005762xmlBufferContent(const xmlBufferPtr buf)
5763{
5764 if(!buf)
5765 return NULL;
5766
5767 return buf->content;
5768}
5769
5770/**
5771 * xmlBufferLength:
5772 * @buf: the buffer
5773 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005774 * Function to get the length of a buffer
5775 *
Owen Taylor3473f882001-02-23 17:55:21 +00005776 * Returns the length of data in the internal content
5777 */
5778
5779int
5780xmlBufferLength(const xmlBufferPtr buf)
5781{
5782 if(!buf)
5783 return 0;
5784
5785 return buf->use;
5786}
5787
5788/**
5789 * xmlBufferResize:
5790 * @buf: the buffer to resize
5791 * @size: the desired size
5792 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005793 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005794 *
5795 * Returns 0 in case of problems, 1 otherwise
5796 */
5797int
5798xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5799{
5800 unsigned int newSize;
5801 xmlChar* rebuf = NULL;
5802
5803 /*take care of empty case*/
5804 newSize = (buf->size ? buf->size*2 : size);
5805
5806 /* Don't resize if we don't have to */
5807 if (size < buf->size)
5808 return 1;
5809
5810 /* figure out new size */
5811 switch (buf->alloc){
5812 case XML_BUFFER_ALLOC_DOUBLEIT:
5813 while (size > newSize) newSize *= 2;
5814 break;
5815 case XML_BUFFER_ALLOC_EXACT:
5816 newSize = size+10;
5817 break;
5818 default:
5819 newSize = size+10;
5820 break;
5821 }
5822
5823 if (buf->content == NULL)
5824 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5825 else
5826 rebuf = (xmlChar *) xmlRealloc(buf->content,
5827 newSize * sizeof(xmlChar));
5828 if (rebuf == NULL) {
5829 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005830 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005831 return 0;
5832 }
5833 buf->content = rebuf;
5834 buf->size = newSize;
5835
5836 return 1;
5837}
5838
5839/**
5840 * xmlBufferAdd:
5841 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005842 * @str: the #xmlChar string
5843 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005844 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005845 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005846 * str is recomputed.
5847 */
5848void
5849xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5850 unsigned int needSize;
5851
5852 if (str == NULL) {
5853#ifdef DEBUG_BUFFER
5854 xmlGenericError(xmlGenericErrorContext,
5855 "xmlBufferAdd: str == NULL\n");
5856#endif
5857 return;
5858 }
5859 if (len < -1) {
5860#ifdef DEBUG_BUFFER
5861 xmlGenericError(xmlGenericErrorContext,
5862 "xmlBufferAdd: len < 0\n");
5863#endif
5864 return;
5865 }
5866 if (len == 0) return;
5867
5868 if (len < 0)
5869 len = xmlStrlen(str);
5870
5871 if (len <= 0) return;
5872
5873 needSize = buf->use + len + 2;
5874 if (needSize > buf->size){
5875 if (!xmlBufferResize(buf, needSize)){
5876 xmlGenericError(xmlGenericErrorContext,
5877 "xmlBufferAdd : out of memory!\n");
5878 return;
5879 }
5880 }
5881
5882 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5883 buf->use += len;
5884 buf->content[buf->use] = 0;
5885}
5886
5887/**
5888 * xmlBufferAddHead:
5889 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005890 * @str: the #xmlChar string
5891 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005892 *
5893 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005894 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005895 */
5896void
5897xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5898 unsigned int needSize;
5899
5900 if (str == NULL) {
5901#ifdef DEBUG_BUFFER
5902 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005903 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005904#endif
5905 return;
5906 }
5907 if (len < -1) {
5908#ifdef DEBUG_BUFFER
5909 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005910 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005911#endif
5912 return;
5913 }
5914 if (len == 0) return;
5915
5916 if (len < 0)
5917 len = xmlStrlen(str);
5918
5919 if (len <= 0) return;
5920
5921 needSize = buf->use + len + 2;
5922 if (needSize > buf->size){
5923 if (!xmlBufferResize(buf, needSize)){
5924 xmlGenericError(xmlGenericErrorContext,
5925 "xmlBufferAddHead : out of memory!\n");
5926 return;
5927 }
5928 }
5929
5930 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5931 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5932 buf->use += len;
5933 buf->content[buf->use] = 0;
5934}
5935
5936/**
5937 * xmlBufferCat:
5938 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005939 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005940 *
5941 * Append a zero terminated string to an XML buffer.
5942 */
5943void
5944xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5945 if (str != NULL)
5946 xmlBufferAdd(buf, str, -1);
5947}
5948
5949/**
5950 * xmlBufferCCat:
5951 * @buf: the buffer to dump
5952 * @str: the C char string
5953 *
5954 * Append a zero terminated C string to an XML buffer.
5955 */
5956void
5957xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5958 const char *cur;
5959
5960 if (str == NULL) {
5961#ifdef DEBUG_BUFFER
5962 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005963 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005964#endif
5965 return;
5966 }
5967 for (cur = str;*cur != 0;cur++) {
5968 if (buf->use + 10 >= buf->size) {
5969 if (!xmlBufferResize(buf, buf->use+10)){
5970 xmlGenericError(xmlGenericErrorContext,
5971 "xmlBufferCCat : out of memory!\n");
5972 return;
5973 }
5974 }
5975 buf->content[buf->use++] = *cur;
5976 }
5977 buf->content[buf->use] = 0;
5978}
5979
5980/**
5981 * xmlBufferWriteCHAR:
5982 * @buf: the XML buffer
5983 * @string: the string to add
5984 *
5985 * routine which manages and grows an output buffer. This one adds
5986 * xmlChars at the end of the buffer.
5987 */
5988void
Owen Taylor3473f882001-02-23 17:55:21 +00005989xmlBufferWriteCHAR
Owen Taylor3473f882001-02-23 17:55:21 +00005990(xmlBufferPtr buf, const xmlChar *string) {
5991 xmlBufferCat(buf, string);
5992}
5993
5994/**
5995 * xmlBufferWriteChar:
5996 * @buf: the XML buffer output
5997 * @string: the string to add
5998 *
5999 * routine which manage and grows an output buffer. This one add
6000 * C chars at the end of the array.
6001 */
6002void
6003xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
6004 xmlBufferCCat(buf, string);
6005}
6006
6007
6008/**
6009 * xmlBufferWriteQuotedString:
6010 * @buf: the XML buffer output
6011 * @string: the string to add
6012 *
6013 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006014 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006015 * quote or double-quotes internally
6016 */
6017void
6018xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
6019 if (xmlStrchr(string, '"')) {
6020 if (xmlStrchr(string, '\'')) {
6021#ifdef DEBUG_BUFFER
6022 xmlGenericError(xmlGenericErrorContext,
6023 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6024#endif
6025 }
6026 xmlBufferCCat(buf, "'");
6027 xmlBufferCat(buf, string);
6028 xmlBufferCCat(buf, "'");
6029 } else {
6030 xmlBufferCCat(buf, "\"");
6031 xmlBufferCat(buf, string);
6032 xmlBufferCCat(buf, "\"");
6033 }
6034}
6035
6036
6037/************************************************************************
6038 * *
6039 * Dumping XML tree content to a simple buffer *
6040 * *
6041 ************************************************************************/
6042
Owen Taylor3473f882001-02-23 17:55:21 +00006043/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00006044 * xmlAttrSerializeContent:
6045 * @buf: the XML buffer output
6046 * @doc: the document
6047 * @attr: the attribute pointer
6048 *
6049 * Serialize the attribute in the buffer
6050 */
6051static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006052xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
6053{
Daniel Veillarda6d05382002-02-13 13:07:41 +00006054 const xmlChar *cur, *base;
6055 xmlNodePtr children;
6056
6057 children = attr->children;
6058 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006059 switch (children->type) {
6060 case XML_TEXT_NODE:
6061 base = cur = children->content;
6062 while (*cur != 0) {
6063 if (*cur == '\n') {
6064 if (base != cur)
6065 xmlBufferAdd(buf, base, cur - base);
6066 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
6067 cur++;
6068 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006069#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006070 } else if (*cur == '\'') {
6071 if (base != cur)
6072 xmlBufferAdd(buf, base, cur - base);
6073 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
6074 cur++;
6075 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006076#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006077 } else if (*cur == '"') {
6078 if (base != cur)
6079 xmlBufferAdd(buf, base, cur - base);
6080 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6081 cur++;
6082 base = cur;
6083 } else if (*cur == '<') {
6084 if (base != cur)
6085 xmlBufferAdd(buf, base, cur - base);
6086 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6087 cur++;
6088 base = cur;
6089 } else if (*cur == '>') {
6090 if (base != cur)
6091 xmlBufferAdd(buf, base, cur - base);
6092 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6093 cur++;
6094 base = cur;
6095 } else if (*cur == '&') {
6096 if (base != cur)
6097 xmlBufferAdd(buf, base, cur - base);
6098 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6099 cur++;
6100 base = cur;
6101 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6102 (doc->encoding ==
6103 NULL))) {
6104 /*
6105 * We assume we have UTF-8 content.
6106 */
6107 char tmp[10];
6108 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006109
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006110 if (base != cur)
6111 xmlBufferAdd(buf, base, cur - base);
6112 if (*cur < 0xC0) {
6113 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6d05382002-02-13 13:07:41 +00006114 "xmlAttrSerializeContent : input not UTF-8\n");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006115 if (doc != NULL)
6116 doc->encoding =
6117 xmlStrdup(BAD_CAST "ISO-8859-1");
6118 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6119 tmp[sizeof(tmp) - 1] = 0;
6120 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6121 cur++;
6122 base = cur;
6123 continue;
6124 } else if (*cur < 0xE0) {
6125 val = (cur[0]) & 0x1F;
6126 val <<= 6;
6127 val |= (cur[1]) & 0x3F;
6128 l = 2;
6129 } else if (*cur < 0xF0) {
6130 val = (cur[0]) & 0x0F;
6131 val <<= 6;
6132 val |= (cur[1]) & 0x3F;
6133 val <<= 6;
6134 val |= (cur[2]) & 0x3F;
6135 l = 3;
6136 } else if (*cur < 0xF8) {
6137 val = (cur[0]) & 0x07;
6138 val <<= 6;
6139 val |= (cur[1]) & 0x3F;
6140 val <<= 6;
6141 val |= (cur[2]) & 0x3F;
6142 val <<= 6;
6143 val |= (cur[3]) & 0x3F;
6144 l = 4;
6145 }
6146 if ((l == 1) || (!IS_CHAR(val))) {
6147 xmlGenericError(xmlGenericErrorContext,
6148 "xmlAttrSerializeContent : char out of range\n");
6149 if (doc != NULL)
6150 doc->encoding =
6151 xmlStrdup(BAD_CAST "ISO-8859-1");
6152 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6153 tmp[sizeof(tmp) - 1] = 0;
6154 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6155 cur++;
6156 base = cur;
6157 continue;
6158 }
6159 /*
6160 * We could do multiple things here. Just save
6161 * as a char ref
6162 */
6163 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6164 tmp[sizeof(tmp) - 1] = 0;
6165 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6166 cur += l;
6167 base = cur;
6168 } else {
6169 cur++;
6170 }
6171 }
6172 if (base != cur)
6173 xmlBufferAdd(buf, base, cur - base);
6174 break;
6175 case XML_ENTITY_REF_NODE:
6176 xmlBufferAdd(buf, BAD_CAST "&", 1);
6177 xmlBufferAdd(buf, children->name,
6178 xmlStrlen(children->name));
6179 xmlBufferAdd(buf, BAD_CAST ";", 1);
6180 break;
6181 default:
6182 /* should not happen unless we have a badly built tree */
6183 break;
6184 }
6185 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006186 }
6187}
6188
6189/**
6190 * xmlNodeDump:
6191 * @buf: the XML buffer output
6192 * @doc: the document
6193 * @cur: the current node
6194 * @level: the imbrication level for indenting
6195 * @format: is formatting allowed
6196 *
6197 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006198 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6199 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006200 *
6201 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00006202 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006203int
Owen Taylor3473f882001-02-23 17:55:21 +00006204xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006205 int format)
6206{
6207 unsigned int use;
6208 int ret;
6209 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006210
6211 if (cur == NULL) {
6212#ifdef DEBUG_TREE
6213 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006214 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006215#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006216 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006217 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006218 if (buf == NULL) {
6219#ifdef DEBUG_TREE
6220 xmlGenericError(xmlGenericErrorContext,
6221 "xmlNodeDump : buf == NULL\n");
6222#endif
6223 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006224 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006225 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
6226 if (outbuf == NULL) {
6227 xmlGenericError(xmlGenericErrorContext,
6228 "xmlNodeDump: out of memory!\n");
6229 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006230 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006231 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
6232 outbuf->buffer = buf;
6233 outbuf->encoder = NULL;
6234 outbuf->writecallback = NULL;
6235 outbuf->closecallback = NULL;
6236 outbuf->context = NULL;
6237 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006238
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006239 use = buf->use;
6240 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
6241 xmlFree(outbuf);
6242 ret = buf->use - use;
6243 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006244}
6245
6246/**
6247 * xmlElemDump:
6248 * @f: the FILE * for the output
6249 * @doc: the document
6250 * @cur: the current node
6251 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006252 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006253 */
6254void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006255xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
6256{
6257 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006258
6259 if (cur == NULL) {
6260#ifdef DEBUG_TREE
6261 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006262 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006263#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006264 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006265 }
Owen Taylor3473f882001-02-23 17:55:21 +00006266#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006267 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006268 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006269 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006270 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006271#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006272
6273 outbuf = xmlOutputBufferCreateFile(f, NULL);
6274 if (outbuf == NULL)
6275 return;
6276 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006277#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006278 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
6279#else
6280 xmlGenericError(xmlGenericErrorContext,
6281 "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006282#endif /* LIBXML_HTML_ENABLED */
6283 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006284 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
6285 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00006286}
6287
6288/************************************************************************
6289 * *
6290 * Dumping XML tree content to an I/O output buffer *
6291 * *
6292 ************************************************************************/
6293
Owen Taylor3473f882001-02-23 17:55:21 +00006294static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006295xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6296 int level, int format, const char *encoding);
6297static void
Owen Taylor3473f882001-02-23 17:55:21 +00006298xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6299 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006300static void
6301xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6302 xmlNodePtr cur, int level, int format, const char *encoding);
6303
Owen Taylor3473f882001-02-23 17:55:21 +00006304/**
6305 * xmlNsDumpOutput:
6306 * @buf: the XML buffer output
6307 * @cur: a namespace
6308 *
6309 * Dump a local Namespace definition.
6310 * Should be called in the context of attributes dumps.
6311 */
6312static void
6313xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6314 if (cur == NULL) {
6315#ifdef DEBUG_TREE
6316 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006317 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006318#endif
6319 return;
6320 }
6321 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006322 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6323 return;
6324
Owen Taylor3473f882001-02-23 17:55:21 +00006325 /* Within the context of an element attributes */
6326 if (cur->prefix != NULL) {
6327 xmlOutputBufferWriteString(buf, " xmlns:");
6328 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6329 } else
6330 xmlOutputBufferWriteString(buf, " xmlns");
6331 xmlOutputBufferWriteString(buf, "=");
6332 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6333 }
6334}
6335
6336/**
6337 * xmlNsListDumpOutput:
6338 * @buf: the XML buffer output
6339 * @cur: the first namespace
6340 *
6341 * Dump a list of local Namespace definitions.
6342 * Should be called in the context of attributes dumps.
6343 */
6344static void
6345xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6346 while (cur != NULL) {
6347 xmlNsDumpOutput(buf, cur);
6348 cur = cur->next;
6349 }
6350}
6351
6352/**
6353 * xmlDtdDumpOutput:
6354 * @buf: the XML buffer output
6355 * @doc: the document
6356 * @encoding: an optional encoding string
6357 *
6358 * Dump the XML document DTD, if any.
6359 */
6360static void
6361xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6362 if (dtd == NULL) {
6363#ifdef DEBUG_TREE
6364 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006365 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006366#endif
6367 return;
6368 }
6369 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6370 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6371 if (dtd->ExternalID != NULL) {
6372 xmlOutputBufferWriteString(buf, " PUBLIC ");
6373 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6374 xmlOutputBufferWriteString(buf, " ");
6375 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6376 } else if (dtd->SystemID != NULL) {
6377 xmlOutputBufferWriteString(buf, " SYSTEM ");
6378 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6379 }
6380 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6381 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6382 xmlOutputBufferWriteString(buf, ">");
6383 return;
6384 }
6385 xmlOutputBufferWriteString(buf, " [\n");
6386 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6387 xmlOutputBufferWriteString(buf, "]>");
6388}
6389
6390/**
6391 * xmlAttrDumpOutput:
6392 * @buf: the XML buffer output
6393 * @doc: the document
6394 * @cur: the attribute pointer
6395 * @encoding: an optional encoding string
6396 *
6397 * Dump an XML attribute
6398 */
6399static void
6400xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006401 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006402 if (cur == NULL) {
6403#ifdef DEBUG_TREE
6404 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006405 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006406#endif
6407 return;
6408 }
6409 xmlOutputBufferWriteString(buf, " ");
6410 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6411 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6412 xmlOutputBufferWriteString(buf, ":");
6413 }
6414 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006415 xmlOutputBufferWriteString(buf, "=\"");
6416 xmlAttrSerializeContent(buf->buffer, doc, cur);
6417 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006418}
6419
6420/**
6421 * xmlAttrListDumpOutput:
6422 * @buf: the XML buffer output
6423 * @doc: the document
6424 * @cur: the first attribute pointer
6425 * @encoding: an optional encoding string
6426 *
6427 * Dump a list of XML attributes
6428 */
6429static void
6430xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6431 xmlAttrPtr cur, const char *encoding) {
6432 if (cur == NULL) {
6433#ifdef DEBUG_TREE
6434 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006435 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006436#endif
6437 return;
6438 }
6439 while (cur != NULL) {
6440 xmlAttrDumpOutput(buf, doc, cur, encoding);
6441 cur = cur->next;
6442 }
6443}
6444
6445
6446
6447/**
6448 * xmlNodeListDumpOutput:
6449 * @buf: the XML buffer output
6450 * @doc: the document
6451 * @cur: the first node
6452 * @level: the imbrication level for indenting
6453 * @format: is formatting allowed
6454 * @encoding: an optional encoding string
6455 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006456 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006457 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6458 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006459 */
6460static void
6461xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6462 xmlNodePtr cur, int level, int format, const char *encoding) {
6463 int i;
6464
6465 if (cur == NULL) {
6466#ifdef DEBUG_TREE
6467 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006468 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006469#endif
6470 return;
6471 }
6472 while (cur != NULL) {
6473 if ((format) && (xmlIndentTreeOutput) &&
6474 (cur->type == XML_ELEMENT_NODE))
6475 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006476 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006477 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00006478 if (format) {
6479 xmlOutputBufferWriteString(buf, "\n");
6480 }
6481 cur = cur->next;
6482 }
6483}
6484
6485/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006486 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00006487 * @buf: the XML buffer output
6488 * @doc: the document
6489 * @cur: the current node
6490 * @level: the imbrication level for indenting
6491 * @format: is formatting allowed
6492 * @encoding: an optional encoding string
6493 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006494 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006495 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6496 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006497 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006498static void
6499xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6500 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006501 int i;
6502 xmlNodePtr tmp;
6503
6504 if (cur == NULL) {
6505#ifdef DEBUG_TREE
6506 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006507 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006508#endif
6509 return;
6510 }
6511 if (cur->type == XML_XINCLUDE_START)
6512 return;
6513 if (cur->type == XML_XINCLUDE_END)
6514 return;
6515 if (cur->type == XML_DTD_NODE) {
6516 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6517 return;
6518 }
6519 if (cur->type == XML_ELEMENT_DECL) {
6520 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6521 return;
6522 }
6523 if (cur->type == XML_ATTRIBUTE_DECL) {
6524 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6525 return;
6526 }
6527 if (cur->type == XML_ENTITY_DECL) {
6528 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6529 return;
6530 }
6531 if (cur->type == XML_TEXT_NODE) {
6532 if (cur->content != NULL) {
6533 if ((cur->name == xmlStringText) ||
6534 (cur->name != xmlStringTextNoenc)) {
6535 xmlChar *buffer;
6536
Owen Taylor3473f882001-02-23 17:55:21 +00006537 if (encoding == NULL)
6538 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6539 else
6540 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006541 if (buffer != NULL) {
6542 xmlOutputBufferWriteString(buf, (const char *)buffer);
6543 xmlFree(buffer);
6544 }
6545 } else {
6546 /*
6547 * Disable escaping, needed for XSLT
6548 */
Owen Taylor3473f882001-02-23 17:55:21 +00006549 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006550 }
6551 }
6552
6553 return;
6554 }
6555 if (cur->type == XML_PI_NODE) {
6556 if (cur->content != NULL) {
6557 xmlOutputBufferWriteString(buf, "<?");
6558 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6559 if (cur->content != NULL) {
6560 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006561 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006562 }
6563 xmlOutputBufferWriteString(buf, "?>");
6564 } else {
6565 xmlOutputBufferWriteString(buf, "<?");
6566 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6567 xmlOutputBufferWriteString(buf, "?>");
6568 }
6569 return;
6570 }
6571 if (cur->type == XML_COMMENT_NODE) {
6572 if (cur->content != NULL) {
6573 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006574 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006575 xmlOutputBufferWriteString(buf, "-->");
6576 }
6577 return;
6578 }
6579 if (cur->type == XML_ENTITY_REF_NODE) {
6580 xmlOutputBufferWriteString(buf, "&");
6581 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6582 xmlOutputBufferWriteString(buf, ";");
6583 return;
6584 }
6585 if (cur->type == XML_CDATA_SECTION_NODE) {
6586 xmlOutputBufferWriteString(buf, "<![CDATA[");
6587 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006588 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006589 xmlOutputBufferWriteString(buf, "]]>");
6590 return;
6591 }
6592
6593 if (format == 1) {
6594 tmp = cur->children;
6595 while (tmp != NULL) {
6596 if ((tmp->type == XML_TEXT_NODE) ||
6597 (tmp->type == XML_ENTITY_REF_NODE)) {
6598 format = 0;
6599 break;
6600 }
6601 tmp = tmp->next;
6602 }
6603 }
6604 xmlOutputBufferWriteString(buf, "<");
6605 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6606 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6607 xmlOutputBufferWriteString(buf, ":");
6608 }
6609
6610 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6611 if (cur->nsDef)
6612 xmlNsListDumpOutput(buf, cur->nsDef);
6613 if (cur->properties != NULL)
6614 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6615
Daniel Veillard7db37732001-07-12 01:20:08 +00006616 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6617 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006618 xmlOutputBufferWriteString(buf, "/>");
6619 return;
6620 }
6621 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006622 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006623 xmlChar *buffer;
6624
Owen Taylor3473f882001-02-23 17:55:21 +00006625 if (encoding == NULL)
6626 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6627 else
6628 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006629 if (buffer != NULL) {
6630 xmlOutputBufferWriteString(buf, (const char *)buffer);
6631 xmlFree(buffer);
6632 }
6633 }
6634 if (cur->children != NULL) {
6635 if (format) xmlOutputBufferWriteString(buf, "\n");
6636 xmlNodeListDumpOutput(buf, doc, cur->children,
6637 (level >= 0?level+1:-1), format, encoding);
6638 if ((xmlIndentTreeOutput) && (format))
6639 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006640 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006641 }
6642 xmlOutputBufferWriteString(buf, "</");
6643 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6644 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6645 xmlOutputBufferWriteString(buf, ":");
6646 }
6647
6648 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6649 xmlOutputBufferWriteString(buf, ">");
6650}
6651
6652/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006653 * xmlNodeDumpOutput:
6654 * @buf: the XML buffer output
6655 * @doc: the document
6656 * @cur: the current node
6657 * @level: the imbrication level for indenting
6658 * @format: is formatting allowed
6659 * @encoding: an optional encoding string
6660 *
6661 * Dump an XML node, recursive behaviour, children are printed too.
6662 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6663 * or xmlKeepBlanksDefault(0) was called
6664 */
6665void
6666xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006667 int level, int format, const char *encoding)
6668{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006669#ifdef LIBXML_HTML_ENABLED
6670 xmlDtdPtr dtd;
6671 int is_xhtml = 0;
6672
6673 dtd = xmlGetIntSubset(doc);
6674 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006675 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
6676 if (is_xhtml < 0)
6677 is_xhtml = 0;
6678 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
6679 (cur->type == XML_ELEMENT_NODE) &&
6680 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
6681 if (encoding != NULL)
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00006682 htmlSetMetaEncoding((htmlDocPtr) doc,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006683 (const xmlChar *) encoding);
6684 else
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00006685 htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006686 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006687 }
6688
6689 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006690 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006691 else
6692#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006693 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006694}
6695
6696/**
Owen Taylor3473f882001-02-23 17:55:21 +00006697 * xmlDocContentDumpOutput:
6698 * @buf: the XML buffer output
6699 * @cur: the document
6700 * @encoding: an optional encoding string
6701 * @format: should formatting spaces been added
6702 *
6703 * Dump an XML document.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006704 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6705 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006706 */
6707static void
6708xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6709 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006710#ifdef LIBXML_HTML_ENABLED
6711 xmlDtdPtr dtd;
6712 int is_xhtml = 0;
6713#endif
6714
Owen Taylor3473f882001-02-23 17:55:21 +00006715 xmlOutputBufferWriteString(buf, "<?xml version=");
6716 if (cur->version != NULL)
6717 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6718 else
6719 xmlOutputBufferWriteString(buf, "\"1.0\"");
6720 if (encoding == NULL) {
6721 if (cur->encoding != NULL)
6722 encoding = (const char *) cur->encoding;
6723 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6724 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6725 }
6726 if (encoding != NULL) {
6727 xmlOutputBufferWriteString(buf, " encoding=");
6728 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6729 }
6730 switch (cur->standalone) {
6731 case 0:
6732 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6733 break;
6734 case 1:
6735 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6736 break;
6737 }
6738 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006739
6740#ifdef LIBXML_HTML_ENABLED
6741 dtd = xmlGetIntSubset(cur);
6742 if (dtd != NULL) {
6743 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
6744 if (is_xhtml < 0) is_xhtml = 0;
6745 }
6746 if (is_xhtml) {
6747 if (encoding != NULL)
6748 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
6749 else
6750 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
6751 }
6752#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006753 if (cur->children != NULL) {
6754 xmlNodePtr child = cur->children;
6755
6756 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006757#ifdef LIBXML_HTML_ENABLED
6758 if (is_xhtml)
6759 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6760 else
6761#endif
6762 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00006763 xmlOutputBufferWriteString(buf, "\n");
6764 child = child->next;
6765 }
6766 }
6767}
6768
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006769#ifdef LIBXML_HTML_ENABLED
6770/************************************************************************
6771 * *
6772 * Functions specific to XHTML serialization *
6773 * *
6774 ************************************************************************/
6775
6776#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
6777 "-//W3C//DTD XHTML 1.0 Strict//EN"
6778#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
6779 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
6780#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
6781 "-//W3C//DTD XHTML 1.0 Frameset//EN"
6782#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
6783 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
6784#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
6785 "-//W3C//DTD XHTML 1.0 Transitional//EN"
6786#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
6787 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
6788
6789#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
6790/**
6791 * xmlIsXHTML:
6792 * @systemID: the system identifier
6793 * @publicID: the public identifier
6794 *
6795 * Try to find if the document correspond to an XHTML DTD
6796 *
6797 * Returns 1 if true, 0 if not and -1 in case of error
6798 */
6799int
6800xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
6801 if ((systemID == NULL) && (publicID == NULL))
6802 return(-1);
6803 if (publicID != NULL) {
6804 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
6805 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
6806 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
6807 }
6808 if (systemID != NULL) {
6809 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
6810 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
6811 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
6812 }
6813 return(0);
6814}
6815
6816/**
6817 * xhtmlIsEmpty:
6818 * @node: the node
6819 *
6820 * Check if a node is an empty xhtml node
6821 *
6822 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
6823 */
6824static int
6825xhtmlIsEmpty(xmlNodePtr node) {
6826 if (node == NULL)
6827 return(-1);
6828 if (node->type != XML_ELEMENT_NODE)
6829 return(0);
6830 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
6831 return(0);
6832 if (node->children != NULL)
6833 return(0);
6834 switch (node->name[0]) {
6835 case 'a':
6836 if (xmlStrEqual(node->name, BAD_CAST "area"))
6837 return(1);
6838 return(0);
6839 case 'b':
6840 if (xmlStrEqual(node->name, BAD_CAST "br"))
6841 return(1);
6842 if (xmlStrEqual(node->name, BAD_CAST "base"))
6843 return(1);
6844 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
6845 return(1);
6846 return(0);
6847 case 'c':
6848 if (xmlStrEqual(node->name, BAD_CAST "col"))
6849 return(1);
6850 return(0);
6851 case 'f':
6852 if (xmlStrEqual(node->name, BAD_CAST "frame"))
6853 return(1);
6854 return(0);
6855 case 'h':
6856 if (xmlStrEqual(node->name, BAD_CAST "hr"))
6857 return(1);
6858 return(0);
6859 case 'i':
6860 if (xmlStrEqual(node->name, BAD_CAST "img"))
6861 return(1);
6862 if (xmlStrEqual(node->name, BAD_CAST "input"))
6863 return(1);
6864 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
6865 return(1);
6866 return(0);
6867 case 'l':
6868 if (xmlStrEqual(node->name, BAD_CAST "link"))
6869 return(1);
6870 return(0);
6871 case 'm':
6872 if (xmlStrEqual(node->name, BAD_CAST "meta"))
6873 return(1);
6874 return(0);
6875 case 'p':
6876 if (xmlStrEqual(node->name, BAD_CAST "param"))
6877 return(1);
6878 return(0);
6879 }
6880 return(0);
6881}
6882
6883/**
6884 * xhtmlAttrListDumpOutput:
6885 * @buf: the XML buffer output
6886 * @doc: the document
6887 * @cur: the first attribute pointer
6888 * @encoding: an optional encoding string
6889 *
6890 * Dump a list of XML attributes
6891 */
6892static void
6893xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6894 xmlAttrPtr cur, const char *encoding) {
6895 xmlAttrPtr xml_lang = NULL;
6896 xmlAttrPtr lang = NULL;
6897 xmlAttrPtr name = NULL;
6898 xmlAttrPtr id = NULL;
6899
6900 if (cur == NULL) {
6901#ifdef DEBUG_TREE
6902 xmlGenericError(xmlGenericErrorContext,
6903 "xmlAttrListDumpOutput : property == NULL\n");
6904#endif
6905 return;
6906 }
6907 while (cur != NULL) {
6908 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
6909 id = cur;
6910 else
6911 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
6912 name = cur;
6913 else
6914 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
6915 lang = cur;
6916 else
6917 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
6918 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
6919 xml_lang = cur;
6920 else if ((cur->ns == NULL) &&
6921 ((cur->children == NULL) ||
6922 (cur->children->content == NULL) ||
6923 (cur->children->content[0] == 0)) &&
6924 (htmlIsBooleanAttr(cur->name))) {
6925 if (cur->children != NULL)
6926 xmlFreeNode(cur->children);
6927 cur->children = xmlNewText(cur->name);
6928 if (cur->children != NULL)
6929 cur->children->parent = (xmlNodePtr) cur;
6930 }
6931 xmlAttrDumpOutput(buf, doc, cur, encoding);
6932 cur = cur->next;
6933 }
6934 /*
6935 * C.8
6936 */
6937 if ((name != NULL) && (id == NULL)) {
6938 xmlOutputBufferWriteString(buf, " id=\"");
6939 xmlAttrSerializeContent(buf->buffer, doc, name);
6940 xmlOutputBufferWriteString(buf, "\"");
6941 }
6942 /*
6943 * C.7.
6944 */
6945 if ((lang != NULL) && (xml_lang == NULL)) {
6946 xmlOutputBufferWriteString(buf, " xml:lang=\"");
6947 xmlAttrSerializeContent(buf->buffer, doc, lang);
6948 xmlOutputBufferWriteString(buf, "\"");
6949 } else
6950 if ((xml_lang != NULL) && (lang == NULL)) {
6951 xmlOutputBufferWriteString(buf, " lang=\"");
6952 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
6953 xmlOutputBufferWriteString(buf, "\"");
6954 }
6955}
6956
6957/**
6958 * xhtmlNodeListDumpOutput:
6959 * @buf: the XML buffer output
6960 * @doc: the XHTML document
6961 * @cur: the first node
6962 * @level: the imbrication level for indenting
6963 * @format: is formatting allowed
6964 * @encoding: an optional encoding string
6965 *
6966 * Dump an XML node list, recursive behaviour, children are printed too.
6967 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6968 * or xmlKeepBlanksDefault(0) was called
6969 */
6970static void
6971xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6972 xmlNodePtr cur, int level, int format, const char *encoding) {
6973 int i;
6974
6975 if (cur == NULL) {
6976#ifdef DEBUG_TREE
6977 xmlGenericError(xmlGenericErrorContext,
6978 "xhtmlNodeListDumpOutput : node == NULL\n");
6979#endif
6980 return;
6981 }
6982 while (cur != NULL) {
6983 if ((format) && (xmlIndentTreeOutput) &&
6984 (cur->type == XML_ELEMENT_NODE))
6985 for (i = 0;i < level;i++)
6986 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
6987 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6988 if (format) {
6989 xmlOutputBufferWriteString(buf, "\n");
6990 }
6991 cur = cur->next;
6992 }
6993}
6994
6995/**
6996 * xhtmlNodeDumpOutput:
6997 * @buf: the XML buffer output
6998 * @doc: the XHTML document
6999 * @cur: the current node
7000 * @level: the imbrication level for indenting
7001 * @format: is formatting allowed
7002 * @encoding: an optional encoding string
7003 *
7004 * Dump an XHTML node, recursive behaviour, children are printed too.
7005 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7006 * or xmlKeepBlanksDefault(0) was called
7007 */
7008static void
7009xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7010 int level, int format, const char *encoding) {
7011 int i;
7012 xmlNodePtr tmp;
7013
7014 if (cur == NULL) {
7015#ifdef DEBUG_TREE
7016 xmlGenericError(xmlGenericErrorContext,
7017 "xmlNodeDumpOutput : node == NULL\n");
7018#endif
7019 return;
7020 }
7021 if (cur->type == XML_XINCLUDE_START)
7022 return;
7023 if (cur->type == XML_XINCLUDE_END)
7024 return;
7025 if (cur->type == XML_DTD_NODE) {
7026 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7027 return;
7028 }
7029 if (cur->type == XML_ELEMENT_DECL) {
7030 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7031 return;
7032 }
7033 if (cur->type == XML_ATTRIBUTE_DECL) {
7034 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7035 return;
7036 }
7037 if (cur->type == XML_ENTITY_DECL) {
7038 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7039 return;
7040 }
7041 if (cur->type == XML_TEXT_NODE) {
7042 if (cur->content != NULL) {
7043 if ((cur->name == xmlStringText) ||
7044 (cur->name != xmlStringTextNoenc)) {
7045 xmlChar *buffer;
7046
7047 if (encoding == NULL)
7048 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7049 else
7050 buffer = xmlEncodeSpecialChars(doc, cur->content);
7051 if (buffer != NULL) {
7052 xmlOutputBufferWriteString(buf, (const char *)buffer);
7053 xmlFree(buffer);
7054 }
7055 } else {
7056 /*
7057 * Disable escaping, needed for XSLT
7058 */
7059 xmlOutputBufferWriteString(buf, (const char *) cur->content);
7060 }
7061 }
7062
7063 return;
7064 }
7065 if (cur->type == XML_PI_NODE) {
7066 if (cur->content != NULL) {
7067 xmlOutputBufferWriteString(buf, "<?");
7068 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7069 if (cur->content != NULL) {
7070 xmlOutputBufferWriteString(buf, " ");
7071 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7072 }
7073 xmlOutputBufferWriteString(buf, "?>");
7074 } else {
7075 xmlOutputBufferWriteString(buf, "<?");
7076 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7077 xmlOutputBufferWriteString(buf, "?>");
7078 }
7079 return;
7080 }
7081 if (cur->type == XML_COMMENT_NODE) {
7082 if (cur->content != NULL) {
7083 xmlOutputBufferWriteString(buf, "<!--");
7084 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7085 xmlOutputBufferWriteString(buf, "-->");
7086 }
7087 return;
7088 }
7089 if (cur->type == XML_ENTITY_REF_NODE) {
7090 xmlOutputBufferWriteString(buf, "&");
7091 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7092 xmlOutputBufferWriteString(buf, ";");
7093 return;
7094 }
7095 if (cur->type == XML_CDATA_SECTION_NODE) {
7096 xmlOutputBufferWriteString(buf, "<![CDATA[");
7097 if (cur->content != NULL)
7098 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7099 xmlOutputBufferWriteString(buf, "]]>");
7100 return;
7101 }
7102
7103 if (format == 1) {
7104 tmp = cur->children;
7105 while (tmp != NULL) {
7106 if ((tmp->type == XML_TEXT_NODE) ||
7107 (tmp->type == XML_ENTITY_REF_NODE)) {
7108 format = 0;
7109 break;
7110 }
7111 tmp = tmp->next;
7112 }
7113 }
7114 xmlOutputBufferWriteString(buf, "<");
7115 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7116 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7117 xmlOutputBufferWriteString(buf, ":");
7118 }
7119
7120 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7121 if (cur->nsDef)
7122 xmlNsListDumpOutput(buf, cur->nsDef);
7123 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
7124 (cur->ns == NULL) && (cur->nsDef == NULL))) {
7125 /*
7126 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
7127 */
7128 xmlOutputBufferWriteString(buf,
7129 " xmlns=\"http://www.w3.org/1999/xhtml\"");
7130 }
7131 if (cur->properties != NULL)
7132 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7133
7134 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
7135 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
7136 (xhtmlIsEmpty(cur) == 1)) {
7137 /*
7138 * C.2. Empty Elements
7139 */
7140 xmlOutputBufferWriteString(buf, " />");
7141 } else {
7142 /*
7143 * C.3. Element Minimization and Empty Element Content
7144 */
7145 xmlOutputBufferWriteString(buf, "></");
7146 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7147 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7148 xmlOutputBufferWriteString(buf, ":");
7149 }
7150 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7151 xmlOutputBufferWriteString(buf, ">");
7152 }
7153 return;
7154 }
7155 xmlOutputBufferWriteString(buf, ">");
7156 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
7157 xmlChar *buffer;
7158
7159 if (encoding == NULL)
7160 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7161 else
7162 buffer = xmlEncodeSpecialChars(doc, cur->content);
7163 if (buffer != NULL) {
7164 xmlOutputBufferWriteString(buf, (const char *)buffer);
7165 xmlFree(buffer);
7166 }
7167 }
7168
7169 /*
7170 * 4.8. Script and Style elements
7171 */
7172 if ((cur->type == XML_ELEMENT_NODE) &&
7173 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
7174 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
7175 ((cur->ns == NULL) ||
7176 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
7177 xmlNodePtr child = cur->children;
7178
7179 while (child != NULL) {
7180 if ((child->type == XML_TEXT_NODE) ||
7181 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00007182 /*
7183 * Apparently CDATA escaping for style just break on IE,
7184 * mozilla and galeon, so ...
7185 */
7186 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
7187 (xmlStrchr(child->content, '<') == NULL) &&
7188 (xmlStrchr(child->content, '>') == NULL) &&
7189 (xmlStrchr(child->content, '&') == NULL)) {
7190 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7191 } else {
7192 xmlOutputBufferWriteString(buf, "<![CDATA[");
7193 if (child->content != NULL)
7194 xmlOutputBufferWriteString(buf,
7195 (const char *)child->content);
7196 xmlOutputBufferWriteString(buf, "]]>");
7197 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007198 } else {
7199 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7200 }
7201 child = child->next;
7202 }
7203 } else if (cur->children != NULL) {
7204 if (format) xmlOutputBufferWriteString(buf, "\n");
7205 xhtmlNodeListDumpOutput(buf, doc, cur->children,
7206 (level >= 0?level+1:-1), format, encoding);
7207 if ((xmlIndentTreeOutput) && (format))
7208 for (i = 0;i < level;i++)
7209 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7210 }
7211 xmlOutputBufferWriteString(buf, "</");
7212 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7213 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7214 xmlOutputBufferWriteString(buf, ":");
7215 }
7216
7217 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7218 xmlOutputBufferWriteString(buf, ">");
7219}
7220#endif
7221
Owen Taylor3473f882001-02-23 17:55:21 +00007222/************************************************************************
7223 * *
7224 * Saving functions front-ends *
7225 * *
7226 ************************************************************************/
7227
7228/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007229 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00007230 * @out_doc: Document to generate XML text from
7231 * @doc_txt_ptr: Memory pointer for allocated XML text
7232 * @doc_txt_len: Length of the generated XML text
7233 * @txt_encoding: Character encoding to use when generating XML text
7234 * @format: should formatting spaces been added
7235 *
7236 * Dump the current DOM tree into memory using the character encoding specified
7237 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007238 * allocated memory with xmlFree().
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007239 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7240 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007241 */
7242
7243void
7244xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007245 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007246 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007247 int dummy = 0;
7248
7249 xmlCharEncoding doc_charset;
7250 xmlOutputBufferPtr out_buff = NULL;
7251 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
7252
7253 if (doc_txt_len == NULL) {
7254 doc_txt_len = &dummy; /* Continue, caller just won't get length */
7255 }
7256
7257 if (doc_txt_ptr == NULL) {
7258 *doc_txt_len = 0;
7259 xmlGenericError(xmlGenericErrorContext,
7260 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
7261 return;
7262 }
7263
7264 *doc_txt_ptr = NULL;
7265 *doc_txt_len = 0;
7266
7267 if (out_doc == NULL) {
7268 /* No document, no output */
7269 xmlGenericError(xmlGenericErrorContext,
7270 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
7271 return;
7272 }
7273
7274 /*
7275 * Validate the encoding value, if provided.
7276 * This logic is copied from xmlSaveFileEnc.
7277 */
7278
7279 if (txt_encoding == NULL)
7280 txt_encoding = (const char *) out_doc->encoding;
7281 if (txt_encoding != NULL) {
7282 doc_charset = xmlParseCharEncoding(txt_encoding);
7283
7284 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
7285 xmlGenericError(xmlGenericErrorContext,
7286 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
7287 return;
7288
7289 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
7290 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
7291 if ( conv_hdlr == NULL ) {
7292 xmlGenericError(xmlGenericErrorContext,
7293 "%s: %s %s '%s'\n",
7294 "xmlDocDumpFormatMemoryEnc",
7295 "Failed to identify encoding handler for",
7296 "character set",
7297 txt_encoding);
7298 return;
7299 }
7300 }
7301 }
7302
7303 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
7304 xmlGenericError(xmlGenericErrorContext,
7305 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
7306 return;
7307 }
7308
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007309 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007310 xmlOutputBufferFlush(out_buff);
7311 if (out_buff->conv != NULL) {
7312 *doc_txt_len = out_buff->conv->use;
7313 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
7314 } else {
7315 *doc_txt_len = out_buff->buffer->use;
7316 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
7317 }
7318 (void)xmlOutputBufferClose(out_buff);
7319
7320 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
7321 *doc_txt_len = 0;
7322 xmlGenericError(xmlGenericErrorContext,
7323 "xmlDocDumpFormatMemoryEnc: %s\n",
7324 "Failed to allocate memory for document text representation.");
7325 }
7326
7327 return;
7328}
7329
7330/**
7331 * xmlDocDumpMemory:
7332 * @cur: the document
7333 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007334 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007335 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007336 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007337 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007338 */
7339void
7340xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
7341 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
7342}
7343
7344/**
7345 * xmlDocDumpFormatMemory:
7346 * @cur: the document
7347 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007348 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007349 * @format: should formatting spaces been added
7350 *
7351 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007352 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007353 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007354 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7355 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007356 */
7357void
7358xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
7359 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
7360}
7361
7362/**
7363 * xmlDocDumpMemoryEnc:
7364 * @out_doc: Document to generate XML text from
7365 * @doc_txt_ptr: Memory pointer for allocated XML text
7366 * @doc_txt_len: Length of the generated XML text
7367 * @txt_encoding: Character encoding to use when generating XML text
7368 *
7369 * Dump the current DOM tree into memory using the character encoding specified
7370 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007371 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007372 */
7373
7374void
7375xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
7376 int * doc_txt_len, const char * txt_encoding) {
7377 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007378 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007379}
7380
7381/**
7382 * xmlGetDocCompressMode:
7383 * @doc: the document
7384 *
7385 * get the compression ratio for a document, ZLIB based
7386 * Returns 0 (uncompressed) to 9 (max compression)
7387 */
7388int
7389xmlGetDocCompressMode (xmlDocPtr doc) {
7390 if (doc == NULL) return(-1);
7391 return(doc->compression);
7392}
7393
7394/**
7395 * xmlSetDocCompressMode:
7396 * @doc: the document
7397 * @mode: the compression ratio
7398 *
7399 * set the compression ratio for a document, ZLIB based
7400 * Correct values: 0 (uncompressed) to 9 (max compression)
7401 */
7402void
7403xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7404 if (doc == NULL) return;
7405 if (mode < 0) doc->compression = 0;
7406 else if (mode > 9) doc->compression = 9;
7407 else doc->compression = mode;
7408}
7409
7410/**
7411 * xmlGetCompressMode:
7412 *
7413 * get the default compression mode used, ZLIB based.
7414 * Returns 0 (uncompressed) to 9 (max compression)
7415 */
7416int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007417xmlGetCompressMode(void)
7418{
7419 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00007420}
7421
7422/**
7423 * xmlSetCompressMode:
7424 * @mode: the compression ratio
7425 *
7426 * set the default compression mode used, ZLIB based
7427 * Correct values: 0 (uncompressed) to 9 (max compression)
7428 */
7429void
7430xmlSetCompressMode(int mode) {
7431 if (mode < 0) xmlCompressMode = 0;
7432 else if (mode > 9) xmlCompressMode = 9;
7433 else xmlCompressMode = mode;
7434}
7435
7436/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007437 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00007438 * @f: the FILE*
7439 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00007440 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007441 *
7442 * Dump an XML document to an open FILE.
7443 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007444 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007445 */
7446int
Daniel Veillard9e412302002-06-10 15:59:44 +00007447xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007448 xmlOutputBufferPtr buf;
7449 const char * encoding;
7450 xmlCharEncodingHandlerPtr handler = NULL;
7451 int ret;
7452
7453 if (cur == NULL) {
7454#ifdef DEBUG_TREE
7455 xmlGenericError(xmlGenericErrorContext,
7456 "xmlDocDump : document == NULL\n");
7457#endif
7458 return(-1);
7459 }
7460 encoding = (const char *) cur->encoding;
7461
7462 if (encoding != NULL) {
7463 xmlCharEncoding enc;
7464
7465 enc = xmlParseCharEncoding(encoding);
7466
7467 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7468 xmlGenericError(xmlGenericErrorContext,
7469 "xmlDocDump: document not in UTF8\n");
7470 return(-1);
7471 }
7472 if (enc != XML_CHAR_ENCODING_UTF8) {
7473 handler = xmlFindCharEncodingHandler(encoding);
7474 if (handler == NULL) {
7475 xmlFree((char *) cur->encoding);
7476 cur->encoding = NULL;
7477 }
7478 }
7479 }
7480 buf = xmlOutputBufferCreateFile(f, handler);
7481 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00007482 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007483
7484 ret = xmlOutputBufferClose(buf);
7485 return(ret);
7486}
7487
7488/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007489 * xmlDocDump:
7490 * @f: the FILE*
7491 * @cur: the document
7492 *
7493 * Dump an XML document to an open FILE.
7494 *
7495 * returns: the number of bytes written or -1 in case of failure.
7496 */
7497int
7498xmlDocDump(FILE *f, xmlDocPtr cur) {
7499 return(xmlDocFormatDump (f, cur, 0));
7500}
7501
7502/**
Owen Taylor3473f882001-02-23 17:55:21 +00007503 * xmlSaveFileTo:
7504 * @buf: an output I/O buffer
7505 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007506 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00007507 *
7508 * Dump an XML document to an I/O buffer.
7509 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007510 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007511 */
7512int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007513xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007514 int ret;
7515
7516 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007517 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007518 ret = xmlOutputBufferClose(buf);
7519 return(ret);
7520}
7521
7522/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00007523 * xmlSaveFormatFileTo:
7524 * @buf: an output I/O buffer
7525 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007526 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00007527 * @format: should formatting spaces been added
7528 *
7529 * Dump an XML document to an I/O buffer.
7530 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007531 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00007532 */
7533int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007534xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00007535 int ret;
7536
7537 if (buf == NULL) return(0);
7538 xmlDocContentDumpOutput(buf, cur, encoding, format);
7539 ret = xmlOutputBufferClose(buf);
7540 return(ret);
7541}
7542
7543/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00007544 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00007545 * @filename: the filename or URL to output
7546 * @cur: the document being saved
7547 * @encoding: the name of the encoding to use or NULL.
7548 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00007549 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00007550 * Dump an XML document to a file or an URL.
7551 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007552 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00007553 */
7554int
Daniel Veillardf012a642001-07-23 19:10:52 +00007555xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
7556 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00007557 xmlOutputBufferPtr buf;
7558 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00007559 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00007560 int ret;
7561
Daniel Veillardfb25a512002-01-13 20:32:08 +00007562 if (encoding == NULL)
7563 encoding = (const char *) cur->encoding;
7564
Owen Taylor3473f882001-02-23 17:55:21 +00007565 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007566
7567 enc = xmlParseCharEncoding(encoding);
7568 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7569 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007570 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007571 return(-1);
7572 }
7573 if (enc != XML_CHAR_ENCODING_UTF8) {
7574 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00007575 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007576 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007577 }
7578 }
7579
Daniel Veillardf012a642001-07-23 19:10:52 +00007580#ifdef HAVE_ZLIB_H
7581 if (cur->compression < 0) cur->compression = xmlCompressMode;
7582#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007583 /*
7584 * save the content to a temp buffer.
7585 */
Daniel Veillardf012a642001-07-23 19:10:52 +00007586 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00007587 if (buf == NULL) return(-1);
7588
Daniel Veillardf012a642001-07-23 19:10:52 +00007589 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007590
7591 ret = xmlOutputBufferClose(buf);
7592 return(ret);
7593}
7594
Daniel Veillardf012a642001-07-23 19:10:52 +00007595
7596/**
7597 * xmlSaveFileEnc:
7598 * @filename: the filename (or URL)
7599 * @cur: the document
7600 * @encoding: the name of an encoding (or NULL)
7601 *
7602 * Dump an XML document, converting it to the given encoding
7603 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007604 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00007605 */
7606int
7607xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
7608 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
7609}
7610
Owen Taylor3473f882001-02-23 17:55:21 +00007611/**
Daniel Veillard67fee942001-04-26 18:59:03 +00007612 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00007613 * @filename: the filename (or URL)
7614 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00007615 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007616 *
7617 * Dump an XML document to a file. Will use compression if
7618 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00007619 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00007620 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007621 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007622 */
7623int
Daniel Veillard67fee942001-04-26 18:59:03 +00007624xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007625 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00007626}
7627
Daniel Veillard67fee942001-04-26 18:59:03 +00007628/**
7629 * xmlSaveFile:
7630 * @filename: the filename (or URL)
7631 * @cur: the document
7632 *
7633 * Dump an XML document to a file. Will use compression if
7634 * compiled in and enabled. If @filename is "-" the stdout file is
7635 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00007636 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00007637 */
7638int
7639xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007640 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00007641}
7642