blob: 1eea2688315b0634bf202266edacc72206bc0a28 [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 Veillarda880b122003-04-21 21:36:41 +000041int __xmlRegisterCallbacks = 0;
42
Daniel Veillard56a4cb82001-03-24 17:00:36 +000043xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
44
45/************************************************************************
46 * *
Daniel Veillard18ec16e2003-10-07 23:16:40 +000047 * Tree memory error handler *
48 * *
49 ************************************************************************/
50/**
51 * xmlTreeErrMemory:
52 * @extra: extra informations
53 *
54 * Handle an out of memory condition
55 */
56static void
57xmlTreeErrMemory(const char *extra)
58{
59 __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
60}
61
62/**
63 * xmlTreeErr:
64 * @code: the error number
65 * @extra: extra informations
66 *
67 * Handle an out of memory condition
68 */
69static void
70xmlTreeErr(int code, xmlNodePtr node, const char *extra)
71{
72 const char *msg = NULL;
73
74 switch(code) {
75 case XML_TREE_INVALID_HEX:
Daniel Veillardac996a12004-07-30 12:02:58 +000076 msg = "invalid hexadecimal character value\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000077 break;
78 case XML_TREE_INVALID_DEC:
Daniel Veillardac996a12004-07-30 12:02:58 +000079 msg = "invalid decimal character value\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000080 break;
81 case XML_TREE_UNTERMINATED_ENTITY:
Daniel Veillardac996a12004-07-30 12:02:58 +000082 msg = "unterminated entity reference %15s\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000083 break;
84 default:
Daniel Veillardac996a12004-07-30 12:02:58 +000085 msg = "unexpected error number\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000086 }
87 __xmlSimpleError(XML_FROM_TREE, code, node, msg, extra);
88}
89
90/************************************************************************
91 * *
Daniel Veillard56a4cb82001-03-24 17:00:36 +000092 * A few static variables and macros *
93 * *
94 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000095/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000096const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000097/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000098const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000099 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +0000100/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +0000101const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
102
Owen Taylor3473f882001-02-23 17:55:21 +0000103static int xmlCompressMode = 0;
104static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000105
Owen Taylor3473f882001-02-23 17:55:21 +0000106#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
107 xmlNodePtr ulccur = (n)->children; \
108 if (ulccur == NULL) { \
109 (n)->last = NULL; \
110 } else { \
111 while (ulccur->next != NULL) { \
112 ulccur->parent = (n); \
113 ulccur = ulccur->next; \
114 } \
115 ulccur->parent = (n); \
116 (n)->last = ulccur; \
117}}
118
119/* #define DEBUG_BUFFER */
120/* #define DEBUG_TREE */
121
122/************************************************************************
123 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000124 * Functions to move to entities.c once the *
125 * API freeze is smoothen and they can be made public. *
126 * *
127 ************************************************************************/
128#include <libxml/hash.h>
129
Daniel Veillard652327a2003-09-29 18:02:38 +0000130#ifdef LIBXML_TREE_ENABLED
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000131/**
132 * xmlGetEntityFromDtd:
133 * @dtd: A pointer to the DTD to search
134 * @name: The entity name
135 *
136 * Do an entity lookup in the DTD entity hash table and
137 * return the corresponding entity, if found.
138 *
139 * Returns A pointer to the entity structure or NULL if not found.
140 */
141static xmlEntityPtr
142xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
143 xmlEntitiesTablePtr table;
144
145 if((dtd != NULL) && (dtd->entities != NULL)) {
146 table = (xmlEntitiesTablePtr) dtd->entities;
147 return((xmlEntityPtr) xmlHashLookup(table, name));
148 /* return(xmlGetEntityFromTable(table, name)); */
149 }
150 return(NULL);
151}
152/**
153 * xmlGetParameterEntityFromDtd:
154 * @dtd: A pointer to the DTD to search
155 * @name: The entity name
156 *
157 * Do an entity lookup in the DTD pararmeter entity hash table and
158 * return the corresponding entity, if found.
159 *
160 * Returns A pointer to the entity structure or NULL if not found.
161 */
162static xmlEntityPtr
163xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
164 xmlEntitiesTablePtr table;
165
166 if ((dtd != NULL) && (dtd->pentities != NULL)) {
167 table = (xmlEntitiesTablePtr) dtd->pentities;
168 return((xmlEntityPtr) xmlHashLookup(table, name));
169 /* return(xmlGetEntityFromTable(table, name)); */
170 }
171 return(NULL);
172}
Daniel Veillard652327a2003-09-29 18:02:38 +0000173#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000174
175/************************************************************************
176 * *
Daniel Veillardc00cda82003-04-07 10:22:39 +0000177 * QName handling helper *
178 * *
179 ************************************************************************/
180
181/**
182 * xmlBuildQName:
183 * @ncname: the Name
184 * @prefix: the prefix
185 * @memory: preallocated memory
186 * @len: preallocated memory length
187 *
188 * Builds the QName @prefix:@ncname in @memory if there is enough space
189 * and prefix is not NULL nor empty, otherwise allocate a new string.
190 * If prefix is NULL or empty it returns ncname.
191 *
192 * Returns the new string which must be freed by the caller if different from
193 * @memory and @ncname or NULL in case of error
194 */
195xmlChar *
196xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
197 xmlChar *memory, int len) {
198 int lenn, lenp;
199 xmlChar *ret;
200
Daniel Veillard3b7840c2003-09-11 23:42:01 +0000201 if (ncname == NULL) return(NULL);
202 if (prefix == NULL) return((xmlChar *) ncname);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000203
204 lenn = strlen((char *) ncname);
205 lenp = strlen((char *) prefix);
206
207 if ((memory == NULL) || (len < lenn + lenp + 2)) {
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000208 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000209 if (ret == NULL) {
210 xmlTreeErrMemory("building QName");
211 return(NULL);
212 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000213 } else {
214 ret = memory;
215 }
216 memcpy(&ret[0], prefix, lenp);
217 ret[lenp] = ':';
218 memcpy(&ret[lenp + 1], ncname, lenn);
219 ret[lenn + lenp + 1] = 0;
220 return(ret);
221}
222
223/**
224 * xmlSplitQName2:
225 * @name: the full QName
226 * @prefix: a xmlChar **
227 *
228 * parse an XML qualified name string
229 *
230 * [NS 5] QName ::= (Prefix ':')? LocalPart
231 *
232 * [NS 6] Prefix ::= NCName
233 *
234 * [NS 7] LocalPart ::= NCName
235 *
236 * Returns NULL if not a QName, otherwise the local part, and prefix
237 * is updated to get the Prefix if any.
238 */
239
240xmlChar *
241xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
242 int len = 0;
243 xmlChar *ret = NULL;
244
245 *prefix = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000246 if (name == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000247
248#ifndef XML_XML_NAMESPACE
249 /* xml: prefix is not really a namespace */
250 if ((name[0] == 'x') && (name[1] == 'm') &&
251 (name[2] == 'l') && (name[3] == ':'))
252 return(NULL);
253#endif
254
255 /* nasty but valid */
256 if (name[0] == ':')
257 return(NULL);
258
259 /*
260 * we are not trying to validate but just to cut, and yes it will
261 * work even if this is as set of UTF-8 encoded chars
262 */
263 while ((name[len] != 0) && (name[len] != ':'))
264 len++;
265
266 if (name[len] == 0)
267 return(NULL);
268
269 *prefix = xmlStrndup(name, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000270 if (*prefix == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000271 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000272 return(NULL);
273 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000274 ret = xmlStrdup(&name[len + 1]);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000275 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000276 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000277 if (*prefix != NULL) {
278 xmlFree(*prefix);
279 *prefix = NULL;
280 }
281 return(NULL);
282 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000283
284 return(ret);
285}
286
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000287/**
288 * xmlSplitQName3:
289 * @name: the full QName
290 * @len: an int *
291 *
292 * parse an XML qualified name string,i
293 *
294 * returns NULL if it is not a Qualified Name, otherwise, update len
295 * with the lenght in byte of the prefix and return a pointer
296 */
297
298const xmlChar *
299xmlSplitQName3(const xmlChar *name, int *len) {
300 int l = 0;
301
302 if (name == NULL) return(NULL);
303 if (len == NULL) return(NULL);
304
305 /* nasty but valid */
306 if (name[0] == ':')
307 return(NULL);
308
309 /*
310 * we are not trying to validate but just to cut, and yes it will
311 * work even if this is as set of UTF-8 encoded chars
312 */
313 while ((name[l] != 0) && (name[l] != ':'))
314 l++;
315
316 if (name[l] == 0)
317 return(NULL);
318
319 *len = l;
320
321 return(&name[l+1]);
322}
323
Daniel Veillardc00cda82003-04-07 10:22:39 +0000324/************************************************************************
325 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000326 * Check Name, NCName and QName strings *
327 * *
328 ************************************************************************/
329
330#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
331
Daniel Veillard03a53c32004-10-26 16:06:51 +0000332#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000333/**
334 * xmlValidateNCName:
335 * @value: the value to check
336 * @space: allow spaces in front and end of the string
337 *
338 * Check that a value conforms to the lexical space of NCName
339 *
340 * Returns 0 if this validates, a positive error code number otherwise
341 * and -1 in case of internal or API error.
342 */
343int
344xmlValidateNCName(const xmlChar *value, int space) {
345 const xmlChar *cur = value;
346 int c,l;
347
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000348 if (value == NULL)
349 return(-1);
350
Daniel Veillardd2298792003-02-14 16:54:11 +0000351 /*
352 * First quick algorithm for ASCII range
353 */
354 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000355 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000356 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
357 (*cur == '_'))
358 cur++;
359 else
360 goto try_complex;
361 while (((*cur >= 'a') && (*cur <= 'z')) ||
362 ((*cur >= 'A') && (*cur <= 'Z')) ||
363 ((*cur >= '0') && (*cur <= '9')) ||
364 (*cur == '_') || (*cur == '-') || (*cur == '.'))
365 cur++;
366 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000367 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000368 if (*cur == 0)
369 return(0);
370
371try_complex:
372 /*
373 * Second check for chars outside the ASCII range
374 */
375 cur = value;
376 c = CUR_SCHAR(cur, l);
377 if (space) {
378 while (IS_BLANK(c)) {
379 cur += l;
380 c = CUR_SCHAR(cur, l);
381 }
382 }
William M. Brack871611b2003-10-18 04:53:14 +0000383 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000384 return(1);
385 cur += l;
386 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000387 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
388 (c == '-') || (c == '_') || IS_COMBINING(c) ||
389 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000390 cur += l;
391 c = CUR_SCHAR(cur, l);
392 }
393 if (space) {
394 while (IS_BLANK(c)) {
395 cur += l;
396 c = CUR_SCHAR(cur, l);
397 }
398 }
399 if (c != 0)
400 return(1);
401
402 return(0);
403}
Daniel Veillard2156d432004-03-04 15:59:36 +0000404#endif
Daniel Veillardd2298792003-02-14 16:54:11 +0000405
Daniel Veillard2156d432004-03-04 15:59:36 +0000406#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000407/**
408 * xmlValidateQName:
409 * @value: the value to check
410 * @space: allow spaces in front and end of the string
411 *
412 * Check that a value conforms to the lexical space of QName
413 *
414 * Returns 0 if this validates, a positive error code number otherwise
415 * and -1 in case of internal or API error.
416 */
417int
418xmlValidateQName(const xmlChar *value, int space) {
419 const xmlChar *cur = value;
420 int c,l;
421
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000422 if (value == NULL)
423 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +0000424 /*
425 * First quick algorithm for ASCII range
426 */
427 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000428 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000429 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
430 (*cur == '_'))
431 cur++;
432 else
433 goto try_complex;
434 while (((*cur >= 'a') && (*cur <= 'z')) ||
435 ((*cur >= 'A') && (*cur <= 'Z')) ||
436 ((*cur >= '0') && (*cur <= '9')) ||
437 (*cur == '_') || (*cur == '-') || (*cur == '.'))
438 cur++;
439 if (*cur == ':') {
440 cur++;
441 if (((*cur >= 'a') && (*cur <= 'z')) ||
442 ((*cur >= 'A') && (*cur <= 'Z')) ||
443 (*cur == '_'))
444 cur++;
445 else
446 goto try_complex;
447 while (((*cur >= 'a') && (*cur <= 'z')) ||
448 ((*cur >= 'A') && (*cur <= 'Z')) ||
449 ((*cur >= '0') && (*cur <= '9')) ||
450 (*cur == '_') || (*cur == '-') || (*cur == '.'))
451 cur++;
452 }
453 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000454 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000455 if (*cur == 0)
456 return(0);
457
458try_complex:
459 /*
460 * Second check for chars outside the ASCII range
461 */
462 cur = value;
463 c = CUR_SCHAR(cur, l);
464 if (space) {
465 while (IS_BLANK(c)) {
466 cur += l;
467 c = CUR_SCHAR(cur, l);
468 }
469 }
William M. Brack871611b2003-10-18 04:53:14 +0000470 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000471 return(1);
472 cur += l;
473 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000474 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
475 (c == '-') || (c == '_') || IS_COMBINING(c) ||
476 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000477 cur += l;
478 c = CUR_SCHAR(cur, l);
479 }
480 if (c == ':') {
481 cur += l;
482 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000483 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000484 return(1);
485 cur += l;
486 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000487 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
488 (c == '-') || (c == '_') || IS_COMBINING(c) ||
489 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000490 cur += l;
491 c = CUR_SCHAR(cur, l);
492 }
493 }
494 if (space) {
495 while (IS_BLANK(c)) {
496 cur += l;
497 c = CUR_SCHAR(cur, l);
498 }
499 }
500 if (c != 0)
501 return(1);
502 return(0);
503}
504
505/**
506 * xmlValidateName:
507 * @value: the value to check
508 * @space: allow spaces in front and end of the string
509 *
510 * Check that a value conforms to the lexical space of Name
511 *
512 * Returns 0 if this validates, a positive error code number otherwise
513 * and -1 in case of internal or API error.
514 */
515int
516xmlValidateName(const xmlChar *value, int space) {
517 const xmlChar *cur = value;
518 int c,l;
519
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000520 if (value == NULL)
521 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +0000522 /*
523 * First quick algorithm for ASCII range
524 */
525 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000526 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000527 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
528 (*cur == '_') || (*cur == ':'))
529 cur++;
530 else
531 goto try_complex;
532 while (((*cur >= 'a') && (*cur <= 'z')) ||
533 ((*cur >= 'A') && (*cur <= 'Z')) ||
534 ((*cur >= '0') && (*cur <= '9')) ||
535 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
536 cur++;
537 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000538 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000539 if (*cur == 0)
540 return(0);
541
542try_complex:
543 /*
544 * Second check for chars outside the ASCII range
545 */
546 cur = value;
547 c = CUR_SCHAR(cur, l);
548 if (space) {
549 while (IS_BLANK(c)) {
550 cur += l;
551 c = CUR_SCHAR(cur, l);
552 }
553 }
William M. Brack871611b2003-10-18 04:53:14 +0000554 if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000555 return(1);
556 cur += l;
557 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000558 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
559 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000560 cur += l;
561 c = CUR_SCHAR(cur, l);
562 }
563 if (space) {
564 while (IS_BLANK(c)) {
565 cur += l;
566 c = CUR_SCHAR(cur, l);
567 }
568 }
569 if (c != 0)
570 return(1);
571 return(0);
572}
573
Daniel Veillardd4310742003-02-18 21:12:46 +0000574/**
575 * xmlValidateNMToken:
576 * @value: the value to check
577 * @space: allow spaces in front and end of the string
578 *
579 * Check that a value conforms to the lexical space of NMToken
580 *
581 * Returns 0 if this validates, a positive error code number otherwise
582 * and -1 in case of internal or API error.
583 */
584int
585xmlValidateNMToken(const xmlChar *value, int space) {
586 const xmlChar *cur = value;
587 int c,l;
588
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000589 if (value == NULL)
590 return(-1);
Daniel Veillardd4310742003-02-18 21:12:46 +0000591 /*
592 * First quick algorithm for ASCII range
593 */
594 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000595 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000596 if (((*cur >= 'a') && (*cur <= 'z')) ||
597 ((*cur >= 'A') && (*cur <= 'Z')) ||
598 ((*cur >= '0') && (*cur <= '9')) ||
599 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
600 cur++;
601 else
602 goto try_complex;
603 while (((*cur >= 'a') && (*cur <= 'z')) ||
604 ((*cur >= 'A') && (*cur <= 'Z')) ||
605 ((*cur >= '0') && (*cur <= '9')) ||
606 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
607 cur++;
608 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000609 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000610 if (*cur == 0)
611 return(0);
612
613try_complex:
614 /*
615 * Second check for chars outside the ASCII range
616 */
617 cur = value;
618 c = CUR_SCHAR(cur, l);
619 if (space) {
620 while (IS_BLANK(c)) {
621 cur += l;
622 c = CUR_SCHAR(cur, l);
623 }
624 }
William M. Brack871611b2003-10-18 04:53:14 +0000625 if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
626 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
Daniel Veillardd4310742003-02-18 21:12:46 +0000627 return(1);
628 cur += l;
629 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000630 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
631 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd4310742003-02-18 21:12:46 +0000632 cur += l;
633 c = CUR_SCHAR(cur, l);
634 }
635 if (space) {
636 while (IS_BLANK(c)) {
637 cur += l;
638 c = CUR_SCHAR(cur, l);
639 }
640 }
641 if (c != 0)
642 return(1);
643 return(0);
644}
Daniel Veillard652327a2003-09-29 18:02:38 +0000645#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardd4310742003-02-18 21:12:46 +0000646
Daniel Veillardd2298792003-02-14 16:54:11 +0000647/************************************************************************
648 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000649 * Allocation and deallocation of basic structures *
650 * *
651 ************************************************************************/
652
653/**
654 * xmlSetBufferAllocationScheme:
655 * @scheme: allocation method to use
656 *
657 * Set the buffer allocation method. Types are
658 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
659 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
660 * improves performance
661 */
662void
663xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
664 xmlBufferAllocScheme = scheme;
665}
666
667/**
668 * xmlGetBufferAllocationScheme:
669 *
670 * Types are
671 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
672 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
673 * improves performance
674 *
675 * Returns the current allocation scheme
676 */
677xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000678xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000679 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000680}
681
682/**
683 * xmlNewNs:
684 * @node: the element carrying the namespace
685 * @href: the URI associated
686 * @prefix: the prefix for the namespace
687 *
688 * Creation of a new Namespace. This function will refuse to create
689 * a namespace with a similar prefix than an existing one present on this
690 * node.
691 * We use href==NULL in the case of an element creation where the namespace
692 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000693 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000694 */
695xmlNsPtr
696xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
697 xmlNsPtr cur;
698
699 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
700 return(NULL);
701
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000702 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
703 return(NULL);
704
Owen Taylor3473f882001-02-23 17:55:21 +0000705 /*
706 * Allocate a new Namespace and fill the fields.
707 */
708 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
709 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000710 xmlTreeErrMemory("building namespace");
Owen Taylor3473f882001-02-23 17:55:21 +0000711 return(NULL);
712 }
713 memset(cur, 0, sizeof(xmlNs));
714 cur->type = XML_LOCAL_NAMESPACE;
715
716 if (href != NULL)
717 cur->href = xmlStrdup(href);
718 if (prefix != NULL)
719 cur->prefix = xmlStrdup(prefix);
720
721 /*
722 * Add it at the end to preserve parsing order ...
723 * and checks for existing use of the prefix
724 */
725 if (node != NULL) {
726 if (node->nsDef == NULL) {
727 node->nsDef = cur;
728 } else {
729 xmlNsPtr prev = node->nsDef;
730
731 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
732 (xmlStrEqual(prev->prefix, cur->prefix))) {
733 xmlFreeNs(cur);
734 return(NULL);
735 }
736 while (prev->next != NULL) {
737 prev = prev->next;
738 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
739 (xmlStrEqual(prev->prefix, cur->prefix))) {
740 xmlFreeNs(cur);
741 return(NULL);
742 }
743 }
744 prev->next = cur;
745 }
746 }
747 return(cur);
748}
749
750/**
751 * xmlSetNs:
752 * @node: a node in the document
753 * @ns: a namespace pointer
754 *
755 * Associate a namespace to a node, a posteriori.
756 */
757void
758xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
759 if (node == NULL) {
760#ifdef DEBUG_TREE
761 xmlGenericError(xmlGenericErrorContext,
762 "xmlSetNs: node == NULL\n");
763#endif
764 return;
765 }
766 node->ns = ns;
767}
768
769/**
770 * xmlFreeNs:
771 * @cur: the namespace pointer
772 *
773 * Free up the structures associated to a namespace
774 */
775void
776xmlFreeNs(xmlNsPtr cur) {
777 if (cur == NULL) {
778#ifdef DEBUG_TREE
779 xmlGenericError(xmlGenericErrorContext,
780 "xmlFreeNs : ns == NULL\n");
781#endif
782 return;
783 }
784 if (cur->href != NULL) xmlFree((char *) cur->href);
785 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000786 xmlFree(cur);
787}
788
789/**
790 * xmlFreeNsList:
791 * @cur: the first namespace pointer
792 *
793 * Free up all the structures associated to the chained namespaces.
794 */
795void
796xmlFreeNsList(xmlNsPtr cur) {
797 xmlNsPtr next;
798 if (cur == NULL) {
799#ifdef DEBUG_TREE
800 xmlGenericError(xmlGenericErrorContext,
801 "xmlFreeNsList : ns == NULL\n");
802#endif
803 return;
804 }
805 while (cur != NULL) {
806 next = cur->next;
807 xmlFreeNs(cur);
808 cur = next;
809 }
810}
811
812/**
813 * xmlNewDtd:
814 * @doc: the document pointer
815 * @name: the DTD name
816 * @ExternalID: the external ID
817 * @SystemID: the system ID
818 *
819 * Creation of a new DTD for the external subset. To create an
820 * internal subset, use xmlCreateIntSubset().
821 *
822 * Returns a pointer to the new DTD structure
823 */
824xmlDtdPtr
825xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
826 const xmlChar *ExternalID, const xmlChar *SystemID) {
827 xmlDtdPtr cur;
828
829 if ((doc != NULL) && (doc->extSubset != NULL)) {
830#ifdef DEBUG_TREE
831 xmlGenericError(xmlGenericErrorContext,
832 "xmlNewDtd(%s): document %s already have a DTD %s\n",
833 /* !!! */ (char *) name, doc->name,
834 /* !!! */ (char *)doc->extSubset->name);
835#endif
836 return(NULL);
837 }
838
839 /*
840 * Allocate a new DTD and fill the fields.
841 */
842 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
843 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000844 xmlTreeErrMemory("building DTD");
Owen Taylor3473f882001-02-23 17:55:21 +0000845 return(NULL);
846 }
847 memset(cur, 0 , sizeof(xmlDtd));
848 cur->type = XML_DTD_NODE;
849
850 if (name != NULL)
851 cur->name = xmlStrdup(name);
852 if (ExternalID != NULL)
853 cur->ExternalID = xmlStrdup(ExternalID);
854 if (SystemID != NULL)
855 cur->SystemID = xmlStrdup(SystemID);
856 if (doc != NULL)
857 doc->extSubset = cur;
858 cur->doc = doc;
859
Daniel Veillarda880b122003-04-21 21:36:41 +0000860 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000861 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000862 return(cur);
863}
864
865/**
866 * xmlGetIntSubset:
867 * @doc: the document pointer
868 *
869 * Get the internal subset of a document
870 * Returns a pointer to the DTD structure or NULL if not found
871 */
872
873xmlDtdPtr
874xmlGetIntSubset(xmlDocPtr doc) {
875 xmlNodePtr cur;
876
877 if (doc == NULL)
878 return(NULL);
879 cur = doc->children;
880 while (cur != NULL) {
881 if (cur->type == XML_DTD_NODE)
882 return((xmlDtdPtr) cur);
883 cur = cur->next;
884 }
885 return((xmlDtdPtr) doc->intSubset);
886}
887
888/**
889 * xmlCreateIntSubset:
890 * @doc: the document pointer
891 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000892 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000893 * @SystemID: the system ID
894 *
895 * Create the internal subset of a document
896 * Returns a pointer to the new DTD structure
897 */
898xmlDtdPtr
899xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
900 const xmlChar *ExternalID, const xmlChar *SystemID) {
901 xmlDtdPtr cur;
902
903 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
904#ifdef DEBUG_TREE
905 xmlGenericError(xmlGenericErrorContext,
906
907 "xmlCreateIntSubset(): document %s already have an internal subset\n",
908 doc->name);
909#endif
910 return(NULL);
911 }
912
913 /*
914 * Allocate a new DTD and fill the fields.
915 */
916 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
917 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000918 xmlTreeErrMemory("building internal subset");
Owen Taylor3473f882001-02-23 17:55:21 +0000919 return(NULL);
920 }
921 memset(cur, 0, sizeof(xmlDtd));
922 cur->type = XML_DTD_NODE;
923
William M. Bracka3215c72004-07-31 16:24:01 +0000924 if (name != NULL) {
925 cur->name = xmlStrdup(name);
926 if (cur->name == NULL) {
927 xmlTreeErrMemory("building internal subset");
928 xmlFree(cur);
929 return(NULL);
930 }
931 }
932 if (ExternalID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000933 cur->ExternalID = xmlStrdup(ExternalID);
William M. Bracka3215c72004-07-31 16:24:01 +0000934 if (cur->ExternalID == NULL) {
935 xmlTreeErrMemory("building internal subset");
936 if (cur->name != NULL)
937 xmlFree((char *)cur->name);
938 xmlFree(cur);
939 return(NULL);
940 }
941 }
942 if (SystemID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000943 cur->SystemID = xmlStrdup(SystemID);
William M. Bracka3215c72004-07-31 16:24:01 +0000944 if (cur->SystemID == NULL) {
945 xmlTreeErrMemory("building internal subset");
946 if (cur->name != NULL)
947 xmlFree((char *)cur->name);
948 if (cur->ExternalID != NULL)
949 xmlFree((char *)cur->ExternalID);
950 xmlFree(cur);
951 return(NULL);
952 }
953 }
Owen Taylor3473f882001-02-23 17:55:21 +0000954 if (doc != NULL) {
955 doc->intSubset = cur;
956 cur->parent = doc;
957 cur->doc = doc;
958 if (doc->children == NULL) {
959 doc->children = (xmlNodePtr) cur;
960 doc->last = (xmlNodePtr) cur;
961 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000962 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000963 xmlNodePtr prev;
964
Owen Taylor3473f882001-02-23 17:55:21 +0000965 prev = doc->children;
966 prev->prev = (xmlNodePtr) cur;
967 cur->next = prev;
968 doc->children = (xmlNodePtr) cur;
969 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000970 xmlNodePtr next;
971
972 next = doc->children;
973 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
974 next = next->next;
975 if (next == NULL) {
976 cur->prev = doc->last;
977 cur->prev->next = (xmlNodePtr) cur;
978 cur->next = NULL;
979 doc->last = (xmlNodePtr) cur;
980 } else {
981 cur->next = next;
982 cur->prev = next->prev;
983 if (cur->prev == NULL)
984 doc->children = (xmlNodePtr) cur;
985 else
986 cur->prev->next = (xmlNodePtr) cur;
987 next->prev = (xmlNodePtr) cur;
988 }
Owen Taylor3473f882001-02-23 17:55:21 +0000989 }
990 }
991 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000992
Daniel Veillarda880b122003-04-21 21:36:41 +0000993 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000994 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000995 return(cur);
996}
997
998/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000999 * DICT_FREE:
1000 * @str: a string
1001 *
1002 * Free a string if it is not owned by the "dict" dictionnary in the
1003 * current scope
1004 */
1005#define DICT_FREE(str) \
1006 if ((str) && ((!dict) || \
1007 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
1008 xmlFree((char *)(str));
1009
1010/**
Owen Taylor3473f882001-02-23 17:55:21 +00001011 * xmlFreeDtd:
1012 * @cur: the DTD structure to free up
1013 *
1014 * Free a DTD structure.
1015 */
1016void
1017xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001018 xmlDictPtr dict = NULL;
1019
Owen Taylor3473f882001-02-23 17:55:21 +00001020 if (cur == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001021 return;
1022 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001023 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001024
Daniel Veillarda880b122003-04-21 21:36:41 +00001025 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001026 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1027
Owen Taylor3473f882001-02-23 17:55:21 +00001028 if (cur->children != NULL) {
1029 xmlNodePtr next, c = cur->children;
1030
1031 /*
William M. Brack18a04f22004-08-03 16:42:37 +00001032 * Cleanup all nodes which are not part of the specific lists
1033 * of notations, elements, attributes and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00001034 */
1035 while (c != NULL) {
1036 next = c->next;
William M. Brack18a04f22004-08-03 16:42:37 +00001037 if ((c->type != XML_NOTATION_NODE) &&
1038 (c->type != XML_ELEMENT_DECL) &&
1039 (c->type != XML_ATTRIBUTE_DECL) &&
1040 (c->type != XML_ENTITY_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001041 xmlUnlinkNode(c);
1042 xmlFreeNode(c);
1043 }
1044 c = next;
1045 }
1046 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001047 DICT_FREE(cur->name)
1048 DICT_FREE(cur->SystemID)
1049 DICT_FREE(cur->ExternalID)
Owen Taylor3473f882001-02-23 17:55:21 +00001050 /* TODO !!! */
1051 if (cur->notations != NULL)
1052 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1053
1054 if (cur->elements != NULL)
1055 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1056 if (cur->attributes != NULL)
1057 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1058 if (cur->entities != NULL)
1059 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1060 if (cur->pentities != NULL)
1061 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1062
Owen Taylor3473f882001-02-23 17:55:21 +00001063 xmlFree(cur);
1064}
1065
1066/**
1067 * xmlNewDoc:
1068 * @version: xmlChar string giving the version of XML "1.0"
1069 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001070 * Creates a new XML document
1071 *
Owen Taylor3473f882001-02-23 17:55:21 +00001072 * Returns a new document
1073 */
1074xmlDocPtr
1075xmlNewDoc(const xmlChar *version) {
1076 xmlDocPtr cur;
1077
1078 if (version == NULL)
1079 version = (const xmlChar *) "1.0";
1080
1081 /*
1082 * Allocate a new document and fill the fields.
1083 */
1084 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1085 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001086 xmlTreeErrMemory("building doc");
Owen Taylor3473f882001-02-23 17:55:21 +00001087 return(NULL);
1088 }
1089 memset(cur, 0, sizeof(xmlDoc));
1090 cur->type = XML_DOCUMENT_NODE;
1091
1092 cur->version = xmlStrdup(version);
William M. Bracka3215c72004-07-31 16:24:01 +00001093 if (cur->version == NULL) {
1094 xmlTreeErrMemory("building doc");
1095 xmlFree(cur);
1096 return(NULL);
1097 }
Owen Taylor3473f882001-02-23 17:55:21 +00001098 cur->standalone = -1;
1099 cur->compression = -1; /* not initialized */
1100 cur->doc = cur;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001101 /*
1102 * The in memory encoding is always UTF8
1103 * This field will never change and would
1104 * be obsolete if not for binary compatibility.
1105 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001106 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001107
Daniel Veillarda880b122003-04-21 21:36:41 +00001108 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001109 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001110 return(cur);
1111}
1112
1113/**
1114 * xmlFreeDoc:
1115 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001116 *
1117 * Free up all the structures used by a document, tree included.
1118 */
1119void
1120xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001121 xmlDtdPtr extSubset, intSubset;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001122 xmlDictPtr dict = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001123
Owen Taylor3473f882001-02-23 17:55:21 +00001124 if (cur == NULL) {
1125#ifdef DEBUG_TREE
1126 xmlGenericError(xmlGenericErrorContext,
1127 "xmlFreeDoc : document == NULL\n");
1128#endif
1129 return;
1130 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001131#ifdef LIBXML_DEBUG_RUNTIME
1132 xmlDebugCheckDocument(stderr, cur);
1133#endif
1134
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001135 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001136
Daniel Veillarda880b122003-04-21 21:36:41 +00001137 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001138 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1139
Daniel Veillard76d66f42001-05-16 21:05:17 +00001140 /*
1141 * Do this before freeing the children list to avoid ID lookups
1142 */
1143 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1144 cur->ids = NULL;
1145 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1146 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001147 extSubset = cur->extSubset;
1148 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001149 if (intSubset == extSubset)
1150 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001151 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001152 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001153 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001154 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001155 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001156 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001157 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001158 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001159 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001160 }
1161
1162 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001163 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001164
1165 DICT_FREE(cur->version)
1166 DICT_FREE(cur->name)
1167 DICT_FREE(cur->encoding)
1168 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001169 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001170 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001171}
1172
1173/**
1174 * xmlStringLenGetNodeList:
1175 * @doc: the document
1176 * @value: the value of the text
1177 * @len: the length of the string value
1178 *
1179 * Parse the value string and build the node list associated. Should
1180 * produce a flat tree with only TEXTs and ENTITY_REFs.
1181 * Returns a pointer to the first child
1182 */
1183xmlNodePtr
1184xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1185 xmlNodePtr ret = NULL, last = NULL;
1186 xmlNodePtr node;
1187 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001188 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001189 const xmlChar *q;
1190 xmlEntityPtr ent;
1191
1192 if (value == NULL) return(NULL);
1193
1194 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001195 while ((cur < end) && (*cur != 0)) {
1196 if (cur[0] == '&') {
1197 int charval = 0;
1198 xmlChar tmp;
1199
Owen Taylor3473f882001-02-23 17:55:21 +00001200 /*
1201 * Save the current text.
1202 */
1203 if (cur != q) {
1204 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1205 xmlNodeAddContentLen(last, q, cur - q);
1206 } else {
1207 node = xmlNewDocTextLen(doc, q, cur - q);
1208 if (node == NULL) return(ret);
1209 if (last == NULL)
1210 last = ret = node;
1211 else {
1212 last->next = node;
1213 node->prev = last;
1214 last = node;
1215 }
1216 }
1217 }
Owen Taylor3473f882001-02-23 17:55:21 +00001218 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001219 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1220 cur += 3;
1221 if (cur < end)
1222 tmp = *cur;
1223 else
1224 tmp = 0;
1225 while (tmp != ';') { /* Non input consuming loop */
1226 if ((tmp >= '0') && (tmp <= '9'))
1227 charval = charval * 16 + (tmp - '0');
1228 else if ((tmp >= 'a') && (tmp <= 'f'))
1229 charval = charval * 16 + (tmp - 'a') + 10;
1230 else if ((tmp >= 'A') && (tmp <= 'F'))
1231 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001232 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001233 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1234 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001235 charval = 0;
1236 break;
1237 }
1238 cur++;
1239 if (cur < end)
1240 tmp = *cur;
1241 else
1242 tmp = 0;
1243 }
1244 if (tmp == ';')
1245 cur++;
1246 q = cur;
1247 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1248 cur += 2;
1249 if (cur < end)
1250 tmp = *cur;
1251 else
1252 tmp = 0;
1253 while (tmp != ';') { /* Non input consuming loops */
1254 if ((tmp >= '0') && (tmp <= '9'))
1255 charval = charval * 10 + (tmp - '0');
1256 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001257 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1258 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001259 charval = 0;
1260 break;
1261 }
1262 cur++;
1263 if (cur < end)
1264 tmp = *cur;
1265 else
1266 tmp = 0;
1267 }
1268 if (tmp == ';')
1269 cur++;
1270 q = cur;
1271 } else {
1272 /*
1273 * Read the entity string
1274 */
1275 cur++;
1276 q = cur;
1277 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1278 if ((cur >= end) || (*cur == 0)) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001279 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1280 (const char *) q);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001281 return(ret);
1282 }
1283 if (cur != q) {
1284 /*
1285 * Predefined entities don't generate nodes
1286 */
1287 val = xmlStrndup(q, cur - q);
1288 ent = xmlGetDocEntity(doc, val);
1289 if ((ent != NULL) &&
1290 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1291 if (last == NULL) {
1292 node = xmlNewDocText(doc, ent->content);
1293 last = ret = node;
1294 } else if (last->type != XML_TEXT_NODE) {
1295 node = xmlNewDocText(doc, ent->content);
1296 last = xmlAddNextSibling(last, node);
1297 } else
1298 xmlNodeAddContent(last, ent->content);
1299
1300 } else {
1301 /*
1302 * Create a new REFERENCE_REF node
1303 */
1304 node = xmlNewReference(doc, val);
1305 if (node == NULL) {
1306 if (val != NULL) xmlFree(val);
1307 return(ret);
1308 }
1309 else if ((ent != NULL) && (ent->children == NULL)) {
1310 xmlNodePtr temp;
1311
1312 ent->children = xmlStringGetNodeList(doc,
1313 (const xmlChar*)node->content);
1314 ent->owner = 1;
1315 temp = ent->children;
1316 while (temp) {
1317 temp->parent = (xmlNodePtr)ent;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001318 ent->last = temp;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001319 temp = temp->next;
1320 }
1321 }
1322 if (last == NULL) {
1323 last = ret = node;
1324 } else {
1325 last = xmlAddNextSibling(last, node);
1326 }
1327 }
1328 xmlFree(val);
1329 }
1330 cur++;
1331 q = cur;
1332 }
1333 if (charval != 0) {
1334 xmlChar buf[10];
1335 int l;
1336
1337 l = xmlCopyCharMultiByte(buf, charval);
1338 buf[l] = 0;
1339 node = xmlNewDocText(doc, buf);
1340 if (node != NULL) {
1341 if (last == NULL) {
1342 last = ret = node;
1343 } else {
1344 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001345 }
1346 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001347 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001348 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001349 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001350 cur++;
1351 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001352 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001353 /*
1354 * Handle the last piece of text.
1355 */
1356 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1357 xmlNodeAddContentLen(last, q, cur - q);
1358 } else {
1359 node = xmlNewDocTextLen(doc, q, cur - q);
1360 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001361 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001362 last = ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001363 } else {
1364 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001365 }
1366 }
1367 }
1368 return(ret);
1369}
1370
1371/**
1372 * xmlStringGetNodeList:
1373 * @doc: the document
1374 * @value: the value of the attribute
1375 *
1376 * Parse the value string and build the node list associated. Should
1377 * produce a flat tree with only TEXTs and ENTITY_REFs.
1378 * Returns a pointer to the first child
1379 */
1380xmlNodePtr
1381xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1382 xmlNodePtr ret = NULL, last = NULL;
1383 xmlNodePtr node;
1384 xmlChar *val;
1385 const xmlChar *cur = value;
1386 const xmlChar *q;
1387 xmlEntityPtr ent;
1388
1389 if (value == NULL) return(NULL);
1390
1391 q = cur;
1392 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001393 if (cur[0] == '&') {
1394 int charval = 0;
1395 xmlChar tmp;
1396
Owen Taylor3473f882001-02-23 17:55:21 +00001397 /*
1398 * Save the current text.
1399 */
1400 if (cur != q) {
1401 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1402 xmlNodeAddContentLen(last, q, cur - q);
1403 } else {
1404 node = xmlNewDocTextLen(doc, q, cur - q);
1405 if (node == NULL) return(ret);
1406 if (last == NULL)
1407 last = ret = node;
1408 else {
1409 last->next = node;
1410 node->prev = last;
1411 last = node;
1412 }
1413 }
1414 }
Owen Taylor3473f882001-02-23 17:55:21 +00001415 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001416 if ((cur[1] == '#') && (cur[2] == 'x')) {
1417 cur += 3;
1418 tmp = *cur;
1419 while (tmp != ';') { /* Non input consuming loop */
1420 if ((tmp >= '0') && (tmp <= '9'))
1421 charval = charval * 16 + (tmp - '0');
1422 else if ((tmp >= 'a') && (tmp <= 'f'))
1423 charval = charval * 16 + (tmp - 'a') + 10;
1424 else if ((tmp >= 'A') && (tmp <= 'F'))
1425 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001426 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001427 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1428 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001429 charval = 0;
1430 break;
1431 }
1432 cur++;
1433 tmp = *cur;
1434 }
1435 if (tmp == ';')
1436 cur++;
1437 q = cur;
1438 } else if (cur[1] == '#') {
1439 cur += 2;
1440 tmp = *cur;
1441 while (tmp != ';') { /* Non input consuming loops */
1442 if ((tmp >= '0') && (tmp <= '9'))
1443 charval = charval * 10 + (tmp - '0');
1444 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001445 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1446 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001447 charval = 0;
1448 break;
1449 }
1450 cur++;
1451 tmp = *cur;
1452 }
1453 if (tmp == ';')
1454 cur++;
1455 q = cur;
1456 } else {
1457 /*
1458 * Read the entity string
1459 */
1460 cur++;
1461 q = cur;
1462 while ((*cur != 0) && (*cur != ';')) cur++;
1463 if (*cur == 0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001464 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1465 (xmlNodePtr) doc, (const char *) q);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001466 return(ret);
1467 }
1468 if (cur != q) {
1469 /*
1470 * Predefined entities don't generate nodes
1471 */
1472 val = xmlStrndup(q, cur - q);
1473 ent = xmlGetDocEntity(doc, val);
1474 if ((ent != NULL) &&
1475 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1476 if (last == NULL) {
1477 node = xmlNewDocText(doc, ent->content);
1478 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001479 } else if (last->type != XML_TEXT_NODE) {
1480 node = xmlNewDocText(doc, ent->content);
1481 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001482 } else
1483 xmlNodeAddContent(last, ent->content);
1484
1485 } else {
1486 /*
1487 * Create a new REFERENCE_REF node
1488 */
1489 node = xmlNewReference(doc, val);
1490 if (node == NULL) {
1491 if (val != NULL) xmlFree(val);
1492 return(ret);
1493 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001494 else if ((ent != NULL) && (ent->children == NULL)) {
1495 xmlNodePtr temp;
1496
1497 ent->children = xmlStringGetNodeList(doc,
1498 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001499 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001500 temp = ent->children;
1501 while (temp) {
1502 temp->parent = (xmlNodePtr)ent;
1503 temp = temp->next;
1504 }
1505 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001506 if (last == NULL) {
1507 last = ret = node;
1508 } else {
1509 last = xmlAddNextSibling(last, node);
1510 }
1511 }
1512 xmlFree(val);
1513 }
1514 cur++;
1515 q = cur;
1516 }
1517 if (charval != 0) {
1518 xmlChar buf[10];
1519 int len;
1520
1521 len = xmlCopyCharMultiByte(buf, charval);
1522 buf[len] = 0;
1523 node = xmlNewDocText(doc, buf);
1524 if (node != NULL) {
1525 if (last == NULL) {
1526 last = ret = node;
1527 } else {
1528 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001529 }
1530 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001531
1532 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001533 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001534 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001535 cur++;
1536 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001537 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001538 /*
1539 * Handle the last piece of text.
1540 */
1541 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1542 xmlNodeAddContentLen(last, q, cur - q);
1543 } else {
1544 node = xmlNewDocTextLen(doc, q, cur - q);
1545 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001546 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001547 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001548 } else {
1549 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001550 }
1551 }
1552 }
1553 return(ret);
1554}
1555
1556/**
1557 * xmlNodeListGetString:
1558 * @doc: the document
1559 * @list: a Node list
1560 * @inLine: should we replace entity contents or show their external form
1561 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001562 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001563 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001564 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001565 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001566 */
1567xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001568xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1569{
Owen Taylor3473f882001-02-23 17:55:21 +00001570 xmlNodePtr node = list;
1571 xmlChar *ret = NULL;
1572 xmlEntityPtr ent;
1573
Daniel Veillard7646b182002-04-20 06:41:40 +00001574 if (list == NULL)
1575 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001576
1577 while (node != NULL) {
1578 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001579 (node->type == XML_CDATA_SECTION_NODE)) {
1580 if (inLine) {
1581 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001582 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001583 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001584
Daniel Veillard7646b182002-04-20 06:41:40 +00001585 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1586 if (buffer != NULL) {
1587 ret = xmlStrcat(ret, buffer);
1588 xmlFree(buffer);
1589 }
1590 }
1591 } else if (node->type == XML_ENTITY_REF_NODE) {
1592 if (inLine) {
1593 ent = xmlGetDocEntity(doc, node->name);
1594 if (ent != NULL) {
1595 xmlChar *buffer;
1596
1597 /* an entity content can be any "well balanced chunk",
1598 * i.e. the result of the content [43] production:
1599 * http://www.w3.org/TR/REC-xml#NT-content.
1600 * So it can contain text, CDATA section or nested
1601 * entity reference nodes (among others).
1602 * -> we recursive call xmlNodeListGetString()
1603 * which handles these types */
1604 buffer = xmlNodeListGetString(doc, ent->children, 1);
1605 if (buffer != NULL) {
1606 ret = xmlStrcat(ret, buffer);
1607 xmlFree(buffer);
1608 }
1609 } else {
1610 ret = xmlStrcat(ret, node->content);
1611 }
1612 } else {
1613 xmlChar buf[2];
1614
1615 buf[0] = '&';
1616 buf[1] = 0;
1617 ret = xmlStrncat(ret, buf, 1);
1618 ret = xmlStrcat(ret, node->name);
1619 buf[0] = ';';
1620 buf[1] = 0;
1621 ret = xmlStrncat(ret, buf, 1);
1622 }
1623 }
1624#if 0
1625 else {
1626 xmlGenericError(xmlGenericErrorContext,
1627 "xmlGetNodeListString : invalid node type %d\n",
1628 node->type);
1629 }
1630#endif
1631 node = node->next;
1632 }
1633 return (ret);
1634}
Daniel Veillard652327a2003-09-29 18:02:38 +00001635
1636#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001637/**
1638 * xmlNodeListGetRawString:
1639 * @doc: the document
1640 * @list: a Node list
1641 * @inLine: should we replace entity contents or show their external form
1642 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001643 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001644 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1645 * this function doesn't do any character encoding handling.
1646 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001647 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001648 */
1649xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001650xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1651{
Owen Taylor3473f882001-02-23 17:55:21 +00001652 xmlNodePtr node = list;
1653 xmlChar *ret = NULL;
1654 xmlEntityPtr ent;
1655
Daniel Veillard7646b182002-04-20 06:41:40 +00001656 if (list == NULL)
1657 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001658
1659 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001660 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001661 (node->type == XML_CDATA_SECTION_NODE)) {
1662 if (inLine) {
1663 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001664 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001665 xmlChar *buffer;
1666
1667 buffer = xmlEncodeSpecialChars(doc, node->content);
1668 if (buffer != NULL) {
1669 ret = xmlStrcat(ret, buffer);
1670 xmlFree(buffer);
1671 }
1672 }
1673 } else if (node->type == XML_ENTITY_REF_NODE) {
1674 if (inLine) {
1675 ent = xmlGetDocEntity(doc, node->name);
1676 if (ent != NULL) {
1677 xmlChar *buffer;
1678
1679 /* an entity content can be any "well balanced chunk",
1680 * i.e. the result of the content [43] production:
1681 * http://www.w3.org/TR/REC-xml#NT-content.
1682 * So it can contain text, CDATA section or nested
1683 * entity reference nodes (among others).
1684 * -> we recursive call xmlNodeListGetRawString()
1685 * which handles these types */
1686 buffer =
1687 xmlNodeListGetRawString(doc, ent->children, 1);
1688 if (buffer != NULL) {
1689 ret = xmlStrcat(ret, buffer);
1690 xmlFree(buffer);
1691 }
1692 } else {
1693 ret = xmlStrcat(ret, node->content);
1694 }
1695 } else {
1696 xmlChar buf[2];
1697
1698 buf[0] = '&';
1699 buf[1] = 0;
1700 ret = xmlStrncat(ret, buf, 1);
1701 ret = xmlStrcat(ret, node->name);
1702 buf[0] = ';';
1703 buf[1] = 0;
1704 ret = xmlStrncat(ret, buf, 1);
1705 }
1706 }
Owen Taylor3473f882001-02-23 17:55:21 +00001707#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001708 else {
1709 xmlGenericError(xmlGenericErrorContext,
1710 "xmlGetNodeListString : invalid node type %d\n",
1711 node->type);
1712 }
Owen Taylor3473f882001-02-23 17:55:21 +00001713#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001714 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001715 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001716 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001717}
Daniel Veillard652327a2003-09-29 18:02:38 +00001718#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001719
Daniel Veillard2156d432004-03-04 15:59:36 +00001720#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00001721/**
1722 * xmlNewProp:
1723 * @node: the holding node
1724 * @name: the name of the attribute
1725 * @value: the value of the attribute
1726 *
1727 * Create a new property carried by a node.
1728 * Returns a pointer to the attribute
1729 */
1730xmlAttrPtr
1731xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1732 xmlAttrPtr cur;
1733 xmlDocPtr doc = NULL;
1734
1735 if (name == NULL) {
1736#ifdef DEBUG_TREE
1737 xmlGenericError(xmlGenericErrorContext,
1738 "xmlNewProp : name == NULL\n");
1739#endif
1740 return(NULL);
1741 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001742 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1743 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001744
1745 /*
1746 * Allocate a new property and fill the fields.
1747 */
1748 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1749 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001750 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001751 return(NULL);
1752 }
1753 memset(cur, 0, sizeof(xmlAttr));
1754 cur->type = XML_ATTRIBUTE_NODE;
1755
1756 cur->parent = node;
1757 if (node != NULL) {
1758 doc = node->doc;
1759 cur->doc = doc;
1760 }
Daniel Veillard03a53c32004-10-26 16:06:51 +00001761 if ((doc != NULL) && (doc->dict != NULL))
1762 cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
1763 else
1764 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00001765 if (value != NULL) {
1766 xmlChar *buffer;
1767 xmlNodePtr tmp;
1768
1769 buffer = xmlEncodeEntitiesReentrant(doc, value);
1770 cur->children = xmlStringGetNodeList(doc, buffer);
1771 cur->last = NULL;
1772 tmp = cur->children;
1773 while (tmp != NULL) {
1774 tmp->parent = (xmlNodePtr) cur;
1775 tmp->doc = doc;
1776 if (tmp->next == NULL)
1777 cur->last = tmp;
1778 tmp = tmp->next;
1779 }
1780 xmlFree(buffer);
1781 }
1782
1783 /*
1784 * Add it at the end to preserve parsing order ...
1785 */
1786 if (node != NULL) {
1787 if (node->properties == NULL) {
1788 node->properties = cur;
1789 } else {
1790 xmlAttrPtr prev = node->properties;
1791
1792 while (prev->next != NULL) prev = prev->next;
1793 prev->next = cur;
1794 cur->prev = prev;
1795 }
1796 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001797
Daniel Veillarda880b122003-04-21 21:36:41 +00001798 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001799 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001800 return(cur);
1801}
Daniel Veillard652327a2003-09-29 18:02:38 +00001802#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001803
1804/**
1805 * xmlNewNsProp:
1806 * @node: the holding node
1807 * @ns: the namespace
1808 * @name: the name of the attribute
1809 * @value: the value of the attribute
1810 *
1811 * Create a new property tagged with a namespace and carried by a node.
1812 * Returns a pointer to the attribute
1813 */
1814xmlAttrPtr
1815xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1816 const xmlChar *value) {
1817 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001818 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001819
1820 if (name == NULL) {
1821#ifdef DEBUG_TREE
1822 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001823 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001824#endif
1825 return(NULL);
1826 }
1827
1828 /*
1829 * Allocate a new property and fill the fields.
1830 */
1831 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1832 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001833 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001834 return(NULL);
1835 }
1836 memset(cur, 0, sizeof(xmlAttr));
1837 cur->type = XML_ATTRIBUTE_NODE;
1838
1839 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001840 if (node != NULL) {
1841 doc = node->doc;
1842 cur->doc = doc;
1843 }
Owen Taylor3473f882001-02-23 17:55:21 +00001844 cur->ns = ns;
Daniel Veillard03a53c32004-10-26 16:06:51 +00001845 if ((doc != NULL) && (doc->dict != NULL))
1846 cur->name = xmlDictLookup(doc->dict, name, -1);
1847 else
1848 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00001849 if (value != NULL) {
1850 xmlChar *buffer;
1851 xmlNodePtr tmp;
1852
Daniel Veillarda682b212001-06-07 19:59:42 +00001853 buffer = xmlEncodeEntitiesReentrant(doc, value);
1854 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001855 cur->last = NULL;
1856 tmp = cur->children;
1857 while (tmp != NULL) {
1858 tmp->parent = (xmlNodePtr) cur;
1859 if (tmp->next == NULL)
1860 cur->last = tmp;
1861 tmp = tmp->next;
1862 }
1863 xmlFree(buffer);
1864 }
1865
1866 /*
1867 * Add it at the end to preserve parsing order ...
1868 */
1869 if (node != NULL) {
1870 if (node->properties == NULL) {
1871 node->properties = cur;
1872 } else {
1873 xmlAttrPtr prev = node->properties;
1874
1875 while (prev->next != NULL) prev = prev->next;
1876 prev->next = cur;
1877 cur->prev = prev;
1878 }
1879 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001880
Daniel Veillarda880b122003-04-21 21:36:41 +00001881 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001882 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001883 return(cur);
1884}
1885
1886/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001887 * xmlNewNsPropEatName:
1888 * @node: the holding node
1889 * @ns: the namespace
1890 * @name: the name of the attribute
1891 * @value: the value of the attribute
1892 *
1893 * Create a new property tagged with a namespace and carried by a node.
1894 * Returns a pointer to the attribute
1895 */
1896xmlAttrPtr
1897xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1898 const xmlChar *value) {
1899 xmlAttrPtr cur;
1900 xmlDocPtr doc = NULL;
1901
1902 if (name == NULL) {
1903#ifdef DEBUG_TREE
1904 xmlGenericError(xmlGenericErrorContext,
1905 "xmlNewNsPropEatName : name == NULL\n");
1906#endif
1907 return(NULL);
1908 }
1909
1910 /*
1911 * Allocate a new property and fill the fields.
1912 */
1913 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1914 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001915 xmlTreeErrMemory("building attribute");
Daniel Veillard46de64e2002-05-29 08:21:33 +00001916 return(NULL);
1917 }
1918 memset(cur, 0, sizeof(xmlAttr));
1919 cur->type = XML_ATTRIBUTE_NODE;
1920
1921 cur->parent = node;
1922 if (node != NULL) {
1923 doc = node->doc;
1924 cur->doc = doc;
1925 }
1926 cur->ns = ns;
1927 cur->name = name;
1928 if (value != NULL) {
1929 xmlChar *buffer;
1930 xmlNodePtr tmp;
1931
1932 buffer = xmlEncodeEntitiesReentrant(doc, value);
1933 cur->children = xmlStringGetNodeList(doc, buffer);
1934 cur->last = NULL;
1935 tmp = cur->children;
1936 while (tmp != NULL) {
1937 tmp->parent = (xmlNodePtr) cur;
1938 if (tmp->next == NULL)
1939 cur->last = tmp;
1940 tmp = tmp->next;
1941 }
1942 xmlFree(buffer);
1943 }
1944
1945 /*
1946 * Add it at the end to preserve parsing order ...
1947 */
1948 if (node != NULL) {
1949 if (node->properties == NULL) {
1950 node->properties = cur;
1951 } else {
1952 xmlAttrPtr prev = node->properties;
1953
1954 while (prev->next != NULL) prev = prev->next;
1955 prev->next = cur;
1956 cur->prev = prev;
1957 }
1958 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001959
Daniel Veillarda880b122003-04-21 21:36:41 +00001960 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001961 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001962 return(cur);
1963}
1964
1965/**
Owen Taylor3473f882001-02-23 17:55:21 +00001966 * xmlNewDocProp:
1967 * @doc: the document
1968 * @name: the name of the attribute
1969 * @value: the value of the attribute
1970 *
1971 * Create a new property carried by a document.
1972 * Returns a pointer to the attribute
1973 */
1974xmlAttrPtr
1975xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1976 xmlAttrPtr cur;
1977
1978 if (name == NULL) {
1979#ifdef DEBUG_TREE
1980 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001981 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001982#endif
1983 return(NULL);
1984 }
1985
1986 /*
1987 * Allocate a new property and fill the fields.
1988 */
1989 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1990 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001991 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001992 return(NULL);
1993 }
1994 memset(cur, 0, sizeof(xmlAttr));
1995 cur->type = XML_ATTRIBUTE_NODE;
1996
Daniel Veillard03a53c32004-10-26 16:06:51 +00001997 if ((doc != NULL) && (doc->dict != NULL))
1998 cur->name = xmlDictLookup(doc->dict, name, -1);
1999 else
2000 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00002001 cur->doc = doc;
2002 if (value != NULL) {
2003 xmlNodePtr tmp;
2004
2005 cur->children = xmlStringGetNodeList(doc, value);
2006 cur->last = NULL;
2007
2008 tmp = cur->children;
2009 while (tmp != NULL) {
2010 tmp->parent = (xmlNodePtr) cur;
2011 if (tmp->next == NULL)
2012 cur->last = tmp;
2013 tmp = tmp->next;
2014 }
2015 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002016
Daniel Veillarda880b122003-04-21 21:36:41 +00002017 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002018 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002019 return(cur);
2020}
2021
2022/**
2023 * xmlFreePropList:
2024 * @cur: the first property in the list
2025 *
2026 * Free a property and all its siblings, all the children are freed too.
2027 */
2028void
2029xmlFreePropList(xmlAttrPtr cur) {
2030 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002031 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002032 while (cur != NULL) {
2033 next = cur->next;
2034 xmlFreeProp(cur);
2035 cur = next;
2036 }
2037}
2038
2039/**
2040 * xmlFreeProp:
2041 * @cur: an attribute
2042 *
2043 * Free one attribute, all the content is freed too
2044 */
2045void
2046xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002047 xmlDictPtr dict = NULL;
2048 if (cur == NULL) return;
2049
2050 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002051
Daniel Veillarda880b122003-04-21 21:36:41 +00002052 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002053 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
2054
Owen Taylor3473f882001-02-23 17:55:21 +00002055 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00002056 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
2057 ((cur->parent->doc->intSubset != NULL) ||
2058 (cur->parent->doc->extSubset != NULL))) {
2059 if (xmlIsID(cur->parent->doc, cur->parent, cur))
2060 xmlRemoveID(cur->parent->doc, cur);
2061 }
Owen Taylor3473f882001-02-23 17:55:21 +00002062 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002063 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002064 xmlFree(cur);
2065}
2066
Daniel Veillard652327a2003-09-29 18:02:38 +00002067#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002068/**
2069 * xmlRemoveProp:
2070 * @cur: an attribute
2071 *
2072 * Unlink and free one attribute, all the content is freed too
2073 * Note this doesn't work for namespace definition attributes
2074 *
2075 * Returns 0 if success and -1 in case of error.
2076 */
2077int
2078xmlRemoveProp(xmlAttrPtr cur) {
2079 xmlAttrPtr tmp;
2080 if (cur == NULL) {
2081#ifdef DEBUG_TREE
2082 xmlGenericError(xmlGenericErrorContext,
2083 "xmlRemoveProp : cur == NULL\n");
2084#endif
2085 return(-1);
2086 }
2087 if (cur->parent == NULL) {
2088#ifdef DEBUG_TREE
2089 xmlGenericError(xmlGenericErrorContext,
2090 "xmlRemoveProp : cur->parent == NULL\n");
2091#endif
2092 return(-1);
2093 }
2094 tmp = cur->parent->properties;
2095 if (tmp == cur) {
2096 cur->parent->properties = cur->next;
2097 xmlFreeProp(cur);
2098 return(0);
2099 }
2100 while (tmp != NULL) {
2101 if (tmp->next == cur) {
2102 tmp->next = cur->next;
2103 if (tmp->next != NULL)
2104 tmp->next->prev = tmp;
2105 xmlFreeProp(cur);
2106 return(0);
2107 }
2108 tmp = tmp->next;
2109 }
2110#ifdef DEBUG_TREE
2111 xmlGenericError(xmlGenericErrorContext,
2112 "xmlRemoveProp : attribute not owned by its node\n");
2113#endif
2114 return(-1);
2115}
Daniel Veillard652327a2003-09-29 18:02:38 +00002116#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002117
2118/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002119 * xmlNewDocPI:
2120 * @doc: the target document
Owen Taylor3473f882001-02-23 17:55:21 +00002121 * @name: the processing instruction name
2122 * @content: the PI content
2123 *
2124 * Creation of a processing instruction element.
2125 * Returns a pointer to the new node object.
2126 */
2127xmlNodePtr
Daniel Veillard03a53c32004-10-26 16:06:51 +00002128xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
Owen Taylor3473f882001-02-23 17:55:21 +00002129 xmlNodePtr cur;
2130
2131 if (name == NULL) {
2132#ifdef DEBUG_TREE
2133 xmlGenericError(xmlGenericErrorContext,
2134 "xmlNewPI : name == NULL\n");
2135#endif
2136 return(NULL);
2137 }
2138
2139 /*
2140 * Allocate a new node and fill the fields.
2141 */
2142 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2143 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002144 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002145 return(NULL);
2146 }
2147 memset(cur, 0, sizeof(xmlNode));
2148 cur->type = XML_PI_NODE;
2149
Daniel Veillard03a53c32004-10-26 16:06:51 +00002150 if ((doc != NULL) && (doc->dict != NULL))
2151 cur->name = xmlDictLookup(doc->dict, name, -1);
2152 else
2153 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00002154 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002155 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002156 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002157
Daniel Veillarda880b122003-04-21 21:36:41 +00002158 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002159 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002160 return(cur);
2161}
2162
2163/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002164 * xmlNewPI:
2165 * @name: the processing instruction name
2166 * @content: the PI content
2167 *
2168 * Creation of a processing instruction element.
2169 * Use xmlDocNewPI preferably to get string interning
2170 *
2171 * Returns a pointer to the new node object.
2172 */
2173xmlNodePtr
2174xmlNewPI(const xmlChar *name, const xmlChar *content) {
2175 return(xmlNewDocPI(NULL, name, content));
2176}
2177
2178/**
Owen Taylor3473f882001-02-23 17:55:21 +00002179 * xmlNewNode:
2180 * @ns: namespace if any
2181 * @name: the node name
2182 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002183 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002184 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002185 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2186 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002187 */
2188xmlNodePtr
2189xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2190 xmlNodePtr cur;
2191
2192 if (name == NULL) {
2193#ifdef DEBUG_TREE
2194 xmlGenericError(xmlGenericErrorContext,
2195 "xmlNewNode : name == NULL\n");
2196#endif
2197 return(NULL);
2198 }
2199
2200 /*
2201 * Allocate a new node and fill the fields.
2202 */
2203 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2204 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002205 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002206 return(NULL);
2207 }
2208 memset(cur, 0, sizeof(xmlNode));
2209 cur->type = XML_ELEMENT_NODE;
2210
2211 cur->name = xmlStrdup(name);
2212 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002213
Daniel Veillarda880b122003-04-21 21:36:41 +00002214 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002215 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002216 return(cur);
2217}
2218
2219/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002220 * xmlNewNodeEatName:
2221 * @ns: namespace if any
2222 * @name: the node name
2223 *
2224 * Creation of a new node element. @ns is optional (NULL).
2225 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002226 * Returns a pointer to the new node object, with pointer @name as
2227 * new node's name. Use xmlNewNode() if a copy of @name string is
2228 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002229 */
2230xmlNodePtr
2231xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2232 xmlNodePtr cur;
2233
2234 if (name == NULL) {
2235#ifdef DEBUG_TREE
2236 xmlGenericError(xmlGenericErrorContext,
2237 "xmlNewNode : name == NULL\n");
2238#endif
2239 return(NULL);
2240 }
2241
2242 /*
2243 * Allocate a new node and fill the fields.
2244 */
2245 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2246 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002247 xmlTreeErrMemory("building node");
Daniel Veillard46de64e2002-05-29 08:21:33 +00002248 return(NULL);
2249 }
2250 memset(cur, 0, sizeof(xmlNode));
2251 cur->type = XML_ELEMENT_NODE;
2252
2253 cur->name = name;
2254 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002255
Daniel Veillarda880b122003-04-21 21:36:41 +00002256 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002257 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002258 return(cur);
2259}
2260
2261/**
Owen Taylor3473f882001-02-23 17:55:21 +00002262 * xmlNewDocNode:
2263 * @doc: the document
2264 * @ns: namespace if any
2265 * @name: the node name
2266 * @content: the XML text content if any
2267 *
2268 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002269 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002270 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2271 * references, but XML special chars need to be escaped first by using
2272 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2273 * need entities support.
2274 *
2275 * Returns a pointer to the new node object.
2276 */
2277xmlNodePtr
2278xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2279 const xmlChar *name, const xmlChar *content) {
2280 xmlNodePtr cur;
2281
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002282 if ((doc != NULL) && (doc->dict != NULL))
Daniel Veillard03a53c32004-10-26 16:06:51 +00002283 cur = xmlNewNodeEatName(ns, (xmlChar *)
2284 xmlDictLookup(doc->dict, name, -1));
2285 else
2286 cur = xmlNewNode(ns, name);
Owen Taylor3473f882001-02-23 17:55:21 +00002287 if (cur != NULL) {
2288 cur->doc = doc;
2289 if (content != NULL) {
2290 cur->children = xmlStringGetNodeList(doc, content);
2291 UPDATE_LAST_CHILD_AND_PARENT(cur)
2292 }
2293 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002294
Owen Taylor3473f882001-02-23 17:55:21 +00002295 return(cur);
2296}
2297
Daniel Veillard46de64e2002-05-29 08:21:33 +00002298/**
2299 * xmlNewDocNodeEatName:
2300 * @doc: the document
2301 * @ns: namespace if any
2302 * @name: the node name
2303 * @content: the XML text content if any
2304 *
2305 * Creation of a new node element within a document. @ns and @content
2306 * are optional (NULL).
2307 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2308 * references, but XML special chars need to be escaped first by using
2309 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2310 * need entities support.
2311 *
2312 * Returns a pointer to the new node object.
2313 */
2314xmlNodePtr
2315xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2316 xmlChar *name, const xmlChar *content) {
2317 xmlNodePtr cur;
2318
2319 cur = xmlNewNodeEatName(ns, name);
2320 if (cur != NULL) {
2321 cur->doc = doc;
2322 if (content != NULL) {
2323 cur->children = xmlStringGetNodeList(doc, content);
2324 UPDATE_LAST_CHILD_AND_PARENT(cur)
2325 }
2326 }
2327 return(cur);
2328}
2329
Daniel Veillard652327a2003-09-29 18:02:38 +00002330#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002331/**
2332 * xmlNewDocRawNode:
2333 * @doc: the document
2334 * @ns: namespace if any
2335 * @name: the node name
2336 * @content: the text content if any
2337 *
2338 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002339 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002340 *
2341 * Returns a pointer to the new node object.
2342 */
2343xmlNodePtr
2344xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2345 const xmlChar *name, const xmlChar *content) {
2346 xmlNodePtr cur;
2347
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002348 cur = xmlNewDocNode(doc, ns, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002349 if (cur != NULL) {
2350 cur->doc = doc;
2351 if (content != NULL) {
2352 cur->children = xmlNewDocText(doc, content);
2353 UPDATE_LAST_CHILD_AND_PARENT(cur)
2354 }
2355 }
2356 return(cur);
2357}
2358
2359/**
2360 * xmlNewDocFragment:
2361 * @doc: the document owning the fragment
2362 *
2363 * Creation of a new Fragment node.
2364 * Returns a pointer to the new node object.
2365 */
2366xmlNodePtr
2367xmlNewDocFragment(xmlDocPtr doc) {
2368 xmlNodePtr cur;
2369
2370 /*
2371 * Allocate a new DocumentFragment node and fill the fields.
2372 */
2373 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2374 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002375 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002376 return(NULL);
2377 }
2378 memset(cur, 0, sizeof(xmlNode));
2379 cur->type = XML_DOCUMENT_FRAG_NODE;
2380
2381 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002382
Daniel Veillarda880b122003-04-21 21:36:41 +00002383 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002384 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002385 return(cur);
2386}
Daniel Veillard652327a2003-09-29 18:02:38 +00002387#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002388
2389/**
2390 * xmlNewText:
2391 * @content: the text content
2392 *
2393 * Creation of a new text node.
2394 * Returns a pointer to the new node object.
2395 */
2396xmlNodePtr
2397xmlNewText(const xmlChar *content) {
2398 xmlNodePtr cur;
2399
2400 /*
2401 * Allocate a new node and fill the fields.
2402 */
2403 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2404 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002405 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002406 return(NULL);
2407 }
2408 memset(cur, 0, sizeof(xmlNode));
2409 cur->type = XML_TEXT_NODE;
2410
2411 cur->name = xmlStringText;
2412 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002413 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002414 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002415
Daniel Veillarda880b122003-04-21 21:36:41 +00002416 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002417 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002418 return(cur);
2419}
2420
Daniel Veillard652327a2003-09-29 18:02:38 +00002421#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002422/**
2423 * xmlNewTextChild:
2424 * @parent: the parent node
2425 * @ns: a namespace if any
2426 * @name: the name of the child
2427 * @content: the text content of the child if any.
2428 *
2429 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002430 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2431 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002432 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002433 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2434 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2435 * reserved XML chars that might appear in @content, such as the ampersand,
2436 * greater-than or less-than signs, are automatically replaced by their XML
2437 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002438 *
2439 * Returns a pointer to the new node object.
2440 */
2441xmlNodePtr
2442xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2443 const xmlChar *name, const xmlChar *content) {
2444 xmlNodePtr cur, prev;
2445
2446 if (parent == NULL) {
2447#ifdef DEBUG_TREE
2448 xmlGenericError(xmlGenericErrorContext,
2449 "xmlNewTextChild : parent == NULL\n");
2450#endif
2451 return(NULL);
2452 }
2453
2454 if (name == NULL) {
2455#ifdef DEBUG_TREE
2456 xmlGenericError(xmlGenericErrorContext,
2457 "xmlNewTextChild : name == NULL\n");
2458#endif
2459 return(NULL);
2460 }
2461
2462 /*
2463 * Allocate a new node
2464 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002465 if (parent->type == XML_ELEMENT_NODE) {
2466 if (ns == NULL)
2467 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2468 else
2469 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2470 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2471 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2472 if (ns == NULL)
2473 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2474 else
2475 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2476 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2477 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2478 } else {
2479 return(NULL);
2480 }
Owen Taylor3473f882001-02-23 17:55:21 +00002481 if (cur == NULL) return(NULL);
2482
2483 /*
2484 * add the new element at the end of the children list.
2485 */
2486 cur->type = XML_ELEMENT_NODE;
2487 cur->parent = parent;
2488 cur->doc = parent->doc;
2489 if (parent->children == NULL) {
2490 parent->children = cur;
2491 parent->last = cur;
2492 } else {
2493 prev = parent->last;
2494 prev->next = cur;
2495 cur->prev = prev;
2496 parent->last = cur;
2497 }
2498
2499 return(cur);
2500}
Daniel Veillard652327a2003-09-29 18:02:38 +00002501#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002502
2503/**
2504 * xmlNewCharRef:
2505 * @doc: the document
2506 * @name: the char ref string, starting with # or "&# ... ;"
2507 *
2508 * Creation of a new character reference node.
2509 * Returns a pointer to the new node object.
2510 */
2511xmlNodePtr
2512xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2513 xmlNodePtr cur;
2514
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002515 if (name == NULL)
2516 return(NULL);
2517
Owen Taylor3473f882001-02-23 17:55:21 +00002518 /*
2519 * Allocate a new node and fill the fields.
2520 */
2521 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2522 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002523 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002524 return(NULL);
2525 }
2526 memset(cur, 0, sizeof(xmlNode));
2527 cur->type = XML_ENTITY_REF_NODE;
2528
2529 cur->doc = doc;
2530 if (name[0] == '&') {
2531 int len;
2532 name++;
2533 len = xmlStrlen(name);
2534 if (name[len - 1] == ';')
2535 cur->name = xmlStrndup(name, len - 1);
2536 else
2537 cur->name = xmlStrndup(name, len);
2538 } else
2539 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002540
Daniel Veillarda880b122003-04-21 21:36:41 +00002541 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002542 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002543 return(cur);
2544}
2545
2546/**
2547 * xmlNewReference:
2548 * @doc: the document
2549 * @name: the reference name, or the reference string with & and ;
2550 *
2551 * Creation of a new reference node.
2552 * Returns a pointer to the new node object.
2553 */
2554xmlNodePtr
2555xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2556 xmlNodePtr cur;
2557 xmlEntityPtr ent;
2558
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002559 if (name == NULL)
2560 return(NULL);
2561
Owen Taylor3473f882001-02-23 17:55:21 +00002562 /*
2563 * Allocate a new node and fill the fields.
2564 */
2565 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2566 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002567 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002568 return(NULL);
2569 }
2570 memset(cur, 0, sizeof(xmlNode));
2571 cur->type = XML_ENTITY_REF_NODE;
2572
2573 cur->doc = doc;
2574 if (name[0] == '&') {
2575 int len;
2576 name++;
2577 len = xmlStrlen(name);
2578 if (name[len - 1] == ';')
2579 cur->name = xmlStrndup(name, len - 1);
2580 else
2581 cur->name = xmlStrndup(name, len);
2582 } else
2583 cur->name = xmlStrdup(name);
2584
2585 ent = xmlGetDocEntity(doc, cur->name);
2586 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002587 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002588 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002589 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002590 * updated. Not sure if this is 100% correct.
2591 * -George
2592 */
2593 cur->children = (xmlNodePtr) ent;
2594 cur->last = (xmlNodePtr) ent;
2595 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002596
Daniel Veillarda880b122003-04-21 21:36:41 +00002597 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002598 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002599 return(cur);
2600}
2601
2602/**
2603 * xmlNewDocText:
2604 * @doc: the document
2605 * @content: the text content
2606 *
2607 * Creation of a new text node within a document.
2608 * Returns a pointer to the new node object.
2609 */
2610xmlNodePtr
2611xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2612 xmlNodePtr cur;
2613
2614 cur = xmlNewText(content);
2615 if (cur != NULL) cur->doc = doc;
2616 return(cur);
2617}
2618
2619/**
2620 * xmlNewTextLen:
2621 * @content: the text content
2622 * @len: the text len.
2623 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002624 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002625 * Returns a pointer to the new node object.
2626 */
2627xmlNodePtr
2628xmlNewTextLen(const xmlChar *content, int len) {
2629 xmlNodePtr cur;
2630
2631 /*
2632 * Allocate a new node and fill the fields.
2633 */
2634 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2635 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002636 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002637 return(NULL);
2638 }
2639 memset(cur, 0, sizeof(xmlNode));
2640 cur->type = XML_TEXT_NODE;
2641
2642 cur->name = xmlStringText;
2643 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002644 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002645 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002646
Daniel Veillarda880b122003-04-21 21:36:41 +00002647 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002648 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002649 return(cur);
2650}
2651
2652/**
2653 * xmlNewDocTextLen:
2654 * @doc: the document
2655 * @content: the text content
2656 * @len: the text len.
2657 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002658 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002659 * text node pertain to a given document.
2660 * Returns a pointer to the new node object.
2661 */
2662xmlNodePtr
2663xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2664 xmlNodePtr cur;
2665
2666 cur = xmlNewTextLen(content, len);
2667 if (cur != NULL) cur->doc = doc;
2668 return(cur);
2669}
2670
2671/**
2672 * xmlNewComment:
2673 * @content: the comment content
2674 *
2675 * Creation of a new node containing a comment.
2676 * Returns a pointer to the new node object.
2677 */
2678xmlNodePtr
2679xmlNewComment(const xmlChar *content) {
2680 xmlNodePtr cur;
2681
2682 /*
2683 * Allocate a new node and fill the fields.
2684 */
2685 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2686 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002687 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002688 return(NULL);
2689 }
2690 memset(cur, 0, sizeof(xmlNode));
2691 cur->type = XML_COMMENT_NODE;
2692
2693 cur->name = xmlStringComment;
2694 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002695 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002696 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002697
Daniel Veillarda880b122003-04-21 21:36:41 +00002698 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002699 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002700 return(cur);
2701}
2702
2703/**
2704 * xmlNewCDataBlock:
2705 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002706 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002707 * @len: the length of the block
2708 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002709 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002710 * Returns a pointer to the new node object.
2711 */
2712xmlNodePtr
2713xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2714 xmlNodePtr cur;
2715
2716 /*
2717 * Allocate a new node and fill the fields.
2718 */
2719 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2720 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002721 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002722 return(NULL);
2723 }
2724 memset(cur, 0, sizeof(xmlNode));
2725 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002726 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002727
2728 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002729 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002730 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002731
Daniel Veillarda880b122003-04-21 21:36:41 +00002732 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002733 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002734 return(cur);
2735}
2736
2737/**
2738 * xmlNewDocComment:
2739 * @doc: the document
2740 * @content: the comment content
2741 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002742 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002743 * Returns a pointer to the new node object.
2744 */
2745xmlNodePtr
2746xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2747 xmlNodePtr cur;
2748
2749 cur = xmlNewComment(content);
2750 if (cur != NULL) cur->doc = doc;
2751 return(cur);
2752}
2753
2754/**
2755 * xmlSetTreeDoc:
2756 * @tree: the top element
2757 * @doc: the document
2758 *
2759 * update all nodes under the tree to point to the right document
2760 */
2761void
2762xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002763 xmlAttrPtr prop;
2764
Owen Taylor3473f882001-02-23 17:55:21 +00002765 if (tree == NULL)
2766 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002767 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002768 if(tree->type == XML_ELEMENT_NODE) {
2769 prop = tree->properties;
2770 while (prop != NULL) {
2771 prop->doc = doc;
2772 xmlSetListDoc(prop->children, doc);
2773 prop = prop->next;
2774 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002775 }
Owen Taylor3473f882001-02-23 17:55:21 +00002776 if (tree->children != NULL)
2777 xmlSetListDoc(tree->children, doc);
2778 tree->doc = doc;
2779 }
2780}
2781
2782/**
2783 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002784 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002785 * @doc: the document
2786 *
2787 * update all nodes in the list to point to the right document
2788 */
2789void
2790xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2791 xmlNodePtr cur;
2792
2793 if (list == NULL)
2794 return;
2795 cur = list;
2796 while (cur != NULL) {
2797 if (cur->doc != doc)
2798 xmlSetTreeDoc(cur, doc);
2799 cur = cur->next;
2800 }
2801}
2802
Daniel Veillard2156d432004-03-04 15:59:36 +00002803#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002804/**
2805 * xmlNewChild:
2806 * @parent: the parent node
2807 * @ns: a namespace if any
2808 * @name: the name of the child
2809 * @content: the XML content of the child if any.
2810 *
2811 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002812 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2813 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002814 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002815 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2816 * references. XML special chars must be escaped first by using
2817 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002818 *
2819 * Returns a pointer to the new node object.
2820 */
2821xmlNodePtr
2822xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2823 const xmlChar *name, const xmlChar *content) {
2824 xmlNodePtr cur, prev;
2825
2826 if (parent == NULL) {
2827#ifdef DEBUG_TREE
2828 xmlGenericError(xmlGenericErrorContext,
2829 "xmlNewChild : parent == NULL\n");
2830#endif
2831 return(NULL);
2832 }
2833
2834 if (name == NULL) {
2835#ifdef DEBUG_TREE
2836 xmlGenericError(xmlGenericErrorContext,
2837 "xmlNewChild : name == NULL\n");
2838#endif
2839 return(NULL);
2840 }
2841
2842 /*
2843 * Allocate a new node
2844 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002845 if (parent->type == XML_ELEMENT_NODE) {
2846 if (ns == NULL)
2847 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2848 else
2849 cur = xmlNewDocNode(parent->doc, ns, name, content);
2850 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2851 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2852 if (ns == NULL)
2853 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2854 else
2855 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002856 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2857 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002858 } else {
2859 return(NULL);
2860 }
Owen Taylor3473f882001-02-23 17:55:21 +00002861 if (cur == NULL) return(NULL);
2862
2863 /*
2864 * add the new element at the end of the children list.
2865 */
2866 cur->type = XML_ELEMENT_NODE;
2867 cur->parent = parent;
2868 cur->doc = parent->doc;
2869 if (parent->children == NULL) {
2870 parent->children = cur;
2871 parent->last = cur;
2872 } else {
2873 prev = parent->last;
2874 prev->next = cur;
2875 cur->prev = prev;
2876 parent->last = cur;
2877 }
2878
2879 return(cur);
2880}
Daniel Veillard652327a2003-09-29 18:02:38 +00002881#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002882
2883/**
2884 * xmlAddNextSibling:
2885 * @cur: the child node
2886 * @elem: the new node
2887 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002888 * Add a new node @elem as the next sibling of @cur
2889 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002890 * first unlinked from its existing context.
2891 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002892 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2893 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002894 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002895 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002896 */
2897xmlNodePtr
2898xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2899 if (cur == NULL) {
2900#ifdef DEBUG_TREE
2901 xmlGenericError(xmlGenericErrorContext,
2902 "xmlAddNextSibling : cur == NULL\n");
2903#endif
2904 return(NULL);
2905 }
2906 if (elem == NULL) {
2907#ifdef DEBUG_TREE
2908 xmlGenericError(xmlGenericErrorContext,
2909 "xmlAddNextSibling : elem == NULL\n");
2910#endif
2911 return(NULL);
2912 }
2913
2914 xmlUnlinkNode(elem);
2915
2916 if (elem->type == XML_TEXT_NODE) {
2917 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002918 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002919 xmlFreeNode(elem);
2920 return(cur);
2921 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002922 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2923 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002924 xmlChar *tmp;
2925
2926 tmp = xmlStrdup(elem->content);
2927 tmp = xmlStrcat(tmp, cur->next->content);
2928 xmlNodeSetContent(cur->next, tmp);
2929 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002930 xmlFreeNode(elem);
2931 return(cur->next);
2932 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002933 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2934 /* check if an attribute with the same name exists */
2935 xmlAttrPtr attr;
2936
2937 if (elem->ns == NULL)
2938 attr = xmlHasProp(cur->parent, elem->name);
2939 else
2940 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2941 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2942 /* different instance, destroy it (attributes must be unique) */
2943 xmlFreeProp(attr);
2944 }
Owen Taylor3473f882001-02-23 17:55:21 +00002945 }
2946
2947 if (elem->doc != cur->doc) {
2948 xmlSetTreeDoc(elem, cur->doc);
2949 }
2950 elem->parent = cur->parent;
2951 elem->prev = cur;
2952 elem->next = cur->next;
2953 cur->next = elem;
2954 if (elem->next != NULL)
2955 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002956 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002957 elem->parent->last = elem;
2958 return(elem);
2959}
2960
Daniel Veillard2156d432004-03-04 15:59:36 +00002961#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002962/**
2963 * xmlAddPrevSibling:
2964 * @cur: the child node
2965 * @elem: the new node
2966 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002967 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002968 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002969 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002970 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002971 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2972 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002973 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002974 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002975 */
2976xmlNodePtr
2977xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2978 if (cur == NULL) {
2979#ifdef DEBUG_TREE
2980 xmlGenericError(xmlGenericErrorContext,
2981 "xmlAddPrevSibling : cur == NULL\n");
2982#endif
2983 return(NULL);
2984 }
2985 if (elem == NULL) {
2986#ifdef DEBUG_TREE
2987 xmlGenericError(xmlGenericErrorContext,
2988 "xmlAddPrevSibling : elem == NULL\n");
2989#endif
2990 return(NULL);
2991 }
2992
2993 xmlUnlinkNode(elem);
2994
2995 if (elem->type == XML_TEXT_NODE) {
2996 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002997 xmlChar *tmp;
2998
2999 tmp = xmlStrdup(elem->content);
3000 tmp = xmlStrcat(tmp, cur->content);
3001 xmlNodeSetContent(cur, tmp);
3002 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00003003 xmlFreeNode(elem);
3004 return(cur);
3005 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00003006 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
3007 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003008 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003009 xmlFreeNode(elem);
3010 return(cur->prev);
3011 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003012 } else if (elem->type == XML_ATTRIBUTE_NODE) {
3013 /* check if an attribute with the same name exists */
3014 xmlAttrPtr attr;
3015
3016 if (elem->ns == NULL)
3017 attr = xmlHasProp(cur->parent, elem->name);
3018 else
3019 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
3020 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
3021 /* different instance, destroy it (attributes must be unique) */
3022 xmlFreeProp(attr);
3023 }
Owen Taylor3473f882001-02-23 17:55:21 +00003024 }
3025
3026 if (elem->doc != cur->doc) {
3027 xmlSetTreeDoc(elem, cur->doc);
3028 }
3029 elem->parent = cur->parent;
3030 elem->next = cur;
3031 elem->prev = cur->prev;
3032 cur->prev = elem;
3033 if (elem->prev != NULL)
3034 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003035 if (elem->parent != NULL) {
3036 if (elem->type == XML_ATTRIBUTE_NODE) {
3037 if (elem->parent->properties == (xmlAttrPtr) cur) {
3038 elem->parent->properties = (xmlAttrPtr) elem;
3039 }
3040 } else {
3041 if (elem->parent->children == cur) {
3042 elem->parent->children = elem;
3043 }
3044 }
3045 }
Owen Taylor3473f882001-02-23 17:55:21 +00003046 return(elem);
3047}
Daniel Veillard652327a2003-09-29 18:02:38 +00003048#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003049
3050/**
3051 * xmlAddSibling:
3052 * @cur: the child node
3053 * @elem: the new node
3054 *
3055 * Add a new element @elem to the list of siblings of @cur
3056 * merging adjacent TEXT nodes (@elem may be freed)
3057 * If the new element was already inserted in a document it is
3058 * first unlinked from its existing context.
3059 *
3060 * Returns the new element or NULL in case of error.
3061 */
3062xmlNodePtr
3063xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
3064 xmlNodePtr parent;
3065
3066 if (cur == NULL) {
3067#ifdef DEBUG_TREE
3068 xmlGenericError(xmlGenericErrorContext,
3069 "xmlAddSibling : cur == NULL\n");
3070#endif
3071 return(NULL);
3072 }
3073
3074 if (elem == NULL) {
3075#ifdef DEBUG_TREE
3076 xmlGenericError(xmlGenericErrorContext,
3077 "xmlAddSibling : elem == NULL\n");
3078#endif
3079 return(NULL);
3080 }
3081
3082 /*
3083 * Constant time is we can rely on the ->parent->last to find
3084 * the last sibling.
3085 */
3086 if ((cur->parent != NULL) &&
3087 (cur->parent->children != NULL) &&
3088 (cur->parent->last != NULL) &&
3089 (cur->parent->last->next == NULL)) {
3090 cur = cur->parent->last;
3091 } else {
3092 while (cur->next != NULL) cur = cur->next;
3093 }
3094
3095 xmlUnlinkNode(elem);
3096
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003097 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3098 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003099 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003100 xmlFreeNode(elem);
3101 return(cur);
3102 }
3103
3104 if (elem->doc != cur->doc) {
3105 xmlSetTreeDoc(elem, cur->doc);
3106 }
3107 parent = cur->parent;
3108 elem->prev = cur;
3109 elem->next = NULL;
3110 elem->parent = parent;
3111 cur->next = elem;
3112 if (parent != NULL)
3113 parent->last = elem;
3114
3115 return(elem);
3116}
3117
3118/**
3119 * xmlAddChildList:
3120 * @parent: the parent node
3121 * @cur: the first node in the list
3122 *
3123 * Add a list of node at the end of the child list of the parent
3124 * merging adjacent TEXT nodes (@cur may be freed)
3125 *
3126 * Returns the last child or NULL in case of error.
3127 */
3128xmlNodePtr
3129xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3130 xmlNodePtr prev;
3131
3132 if (parent == NULL) {
3133#ifdef DEBUG_TREE
3134 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003135 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003136#endif
3137 return(NULL);
3138 }
3139
3140 if (cur == NULL) {
3141#ifdef DEBUG_TREE
3142 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003143 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003144#endif
3145 return(NULL);
3146 }
3147
3148 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3149 (cur->doc != parent->doc)) {
3150#ifdef DEBUG_TREE
3151 xmlGenericError(xmlGenericErrorContext,
3152 "Elements moved to a different document\n");
3153#endif
3154 }
3155
3156 /*
3157 * add the first element at the end of the children list.
3158 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003159
Owen Taylor3473f882001-02-23 17:55:21 +00003160 if (parent->children == NULL) {
3161 parent->children = cur;
3162 } else {
3163 /*
3164 * If cur and parent->last both are TEXT nodes, then merge them.
3165 */
3166 if ((cur->type == XML_TEXT_NODE) &&
3167 (parent->last->type == XML_TEXT_NODE) &&
3168 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003169 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003170 /*
3171 * if it's the only child, nothing more to be done.
3172 */
3173 if (cur->next == NULL) {
3174 xmlFreeNode(cur);
3175 return(parent->last);
3176 }
3177 prev = cur;
3178 cur = cur->next;
3179 xmlFreeNode(prev);
3180 }
3181 prev = parent->last;
3182 prev->next = cur;
3183 cur->prev = prev;
3184 }
3185 while (cur->next != NULL) {
3186 cur->parent = parent;
3187 if (cur->doc != parent->doc) {
3188 xmlSetTreeDoc(cur, parent->doc);
3189 }
3190 cur = cur->next;
3191 }
3192 cur->parent = parent;
3193 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3194 parent->last = cur;
3195
3196 return(cur);
3197}
3198
3199/**
3200 * xmlAddChild:
3201 * @parent: the parent node
3202 * @cur: the child node
3203 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003204 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003205 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003206 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3207 * If there is an attribute with equal name, it is first destroyed.
3208 *
Owen Taylor3473f882001-02-23 17:55:21 +00003209 * Returns the child or NULL in case of error.
3210 */
3211xmlNodePtr
3212xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3213 xmlNodePtr prev;
3214
3215 if (parent == NULL) {
3216#ifdef DEBUG_TREE
3217 xmlGenericError(xmlGenericErrorContext,
3218 "xmlAddChild : parent == NULL\n");
3219#endif
3220 return(NULL);
3221 }
3222
3223 if (cur == NULL) {
3224#ifdef DEBUG_TREE
3225 xmlGenericError(xmlGenericErrorContext,
3226 "xmlAddChild : child == NULL\n");
3227#endif
3228 return(NULL);
3229 }
3230
Owen Taylor3473f882001-02-23 17:55:21 +00003231 /*
3232 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003233 * cur is then freed.
3234 */
3235 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003236 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003237 (parent->content != NULL) &&
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003238 (parent->name == cur->name) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003239 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003240 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003241 xmlFreeNode(cur);
3242 return(parent);
3243 }
3244 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003245 (parent->last->name == cur->name) &&
3246 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003247 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003248 xmlFreeNode(cur);
3249 return(parent->last);
3250 }
3251 }
3252
3253 /*
3254 * add the new element at the end of the children list.
3255 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003256 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003257 cur->parent = parent;
3258 if (cur->doc != parent->doc) {
3259 xmlSetTreeDoc(cur, parent->doc);
3260 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003261 /* this check prevents a loop on tree-traversions if a developer
3262 * tries to add a node to its parent multiple times
3263 */
3264 if (prev == parent)
3265 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003266
3267 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003268 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003269 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003270 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003271 (parent->content != NULL) &&
3272 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003273 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003274 xmlFreeNode(cur);
3275 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003276 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003277 if (cur->type == XML_ATTRIBUTE_NODE) {
3278 if (parent->properties == NULL) {
3279 parent->properties = (xmlAttrPtr) cur;
3280 } else {
3281 /* check if an attribute with the same name exists */
3282 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003283
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003284 if (cur->ns == NULL)
3285 lastattr = xmlHasProp(parent, cur->name);
3286 else
3287 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3288 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3289 /* different instance, destroy it (attributes must be unique) */
3290 xmlFreeProp(lastattr);
3291 }
3292 /* find the end */
3293 lastattr = parent->properties;
3294 while (lastattr->next != NULL) {
3295 lastattr = lastattr->next;
3296 }
3297 lastattr->next = (xmlAttrPtr) cur;
3298 ((xmlAttrPtr) cur)->prev = lastattr;
3299 }
3300 } else {
3301 if (parent->children == NULL) {
3302 parent->children = cur;
3303 parent->last = cur;
3304 } else {
3305 prev = parent->last;
3306 prev->next = cur;
3307 cur->prev = prev;
3308 parent->last = cur;
3309 }
3310 }
Owen Taylor3473f882001-02-23 17:55:21 +00003311 return(cur);
3312}
3313
3314/**
3315 * xmlGetLastChild:
3316 * @parent: the parent node
3317 *
3318 * Search the last child of a node.
3319 * Returns the last child or NULL if none.
3320 */
3321xmlNodePtr
3322xmlGetLastChild(xmlNodePtr parent) {
3323 if (parent == NULL) {
3324#ifdef DEBUG_TREE
3325 xmlGenericError(xmlGenericErrorContext,
3326 "xmlGetLastChild : parent == NULL\n");
3327#endif
3328 return(NULL);
3329 }
3330 return(parent->last);
3331}
3332
3333/**
3334 * xmlFreeNodeList:
3335 * @cur: the first node in the list
3336 *
3337 * Free a node and all its siblings, this is a recursive behaviour, all
3338 * the children are freed too.
3339 */
3340void
3341xmlFreeNodeList(xmlNodePtr cur) {
3342 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003343 xmlDictPtr dict = NULL;
3344
3345 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003346 if (cur->type == XML_NAMESPACE_DECL) {
3347 xmlFreeNsList((xmlNsPtr) cur);
3348 return;
3349 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003350 if ((cur->type == XML_DOCUMENT_NODE) ||
3351#ifdef LIBXML_DOCB_ENABLED
3352 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003353#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003354 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003355 xmlFreeDoc((xmlDocPtr) cur);
3356 return;
3357 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003358 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003359 while (cur != NULL) {
3360 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003361 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003362
Daniel Veillarda880b122003-04-21 21:36:41 +00003363 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003364 xmlDeregisterNodeDefaultValue(cur);
3365
Daniel Veillard02141ea2001-04-30 11:46:40 +00003366 if ((cur->children != NULL) &&
3367 (cur->type != XML_ENTITY_REF_NODE))
3368 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003369 if (((cur->type == XML_ELEMENT_NODE) ||
3370 (cur->type == XML_XINCLUDE_START) ||
3371 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003372 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003373 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003374 if ((cur->type != XML_ELEMENT_NODE) &&
3375 (cur->type != XML_XINCLUDE_START) &&
3376 (cur->type != XML_XINCLUDE_END) &&
3377 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003378 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003379 }
3380 if (((cur->type == XML_ELEMENT_NODE) ||
3381 (cur->type == XML_XINCLUDE_START) ||
3382 (cur->type == XML_XINCLUDE_END)) &&
3383 (cur->nsDef != NULL))
3384 xmlFreeNsList(cur->nsDef);
3385
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003386 /*
3387 * When a node is a text node or a comment, it uses a global static
3388 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003389 * Otherwise the node name might come from the document's
3390 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003391 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003392 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003393 (cur->type != XML_TEXT_NODE) &&
3394 (cur->type != XML_COMMENT_NODE))
3395 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003396 xmlFree(cur);
3397 }
Owen Taylor3473f882001-02-23 17:55:21 +00003398 cur = next;
3399 }
3400}
3401
3402/**
3403 * xmlFreeNode:
3404 * @cur: the node
3405 *
3406 * Free a node, this is a recursive behaviour, all the children are freed too.
3407 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3408 */
3409void
3410xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003411 xmlDictPtr dict = NULL;
3412
3413 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003414
Daniel Veillard02141ea2001-04-30 11:46:40 +00003415 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003416 if (cur->type == XML_DTD_NODE) {
3417 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003418 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003419 }
3420 if (cur->type == XML_NAMESPACE_DECL) {
3421 xmlFreeNs((xmlNsPtr) cur);
3422 return;
3423 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003424 if (cur->type == XML_ATTRIBUTE_NODE) {
3425 xmlFreeProp((xmlAttrPtr) cur);
3426 return;
3427 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003428
Daniel Veillarda880b122003-04-21 21:36:41 +00003429 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003430 xmlDeregisterNodeDefaultValue(cur);
3431
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003432 if (cur->doc != NULL) dict = cur->doc->dict;
3433
Owen Taylor3473f882001-02-23 17:55:21 +00003434 if ((cur->children != NULL) &&
3435 (cur->type != XML_ENTITY_REF_NODE))
3436 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003437 if (((cur->type == XML_ELEMENT_NODE) ||
3438 (cur->type == XML_XINCLUDE_START) ||
3439 (cur->type == XML_XINCLUDE_END)) &&
3440 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003441 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003442 if ((cur->type != XML_ELEMENT_NODE) &&
3443 (cur->content != NULL) &&
3444 (cur->type != XML_ENTITY_REF_NODE) &&
3445 (cur->type != XML_XINCLUDE_END) &&
3446 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003447 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003448 }
3449
Daniel Veillardacd370f2001-06-09 17:17:51 +00003450 /*
3451 * When a node is a text node or a comment, it uses a global static
3452 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003453 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003454 */
Owen Taylor3473f882001-02-23 17:55:21 +00003455 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003456 (cur->type != XML_TEXT_NODE) &&
3457 (cur->type != XML_COMMENT_NODE))
3458 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003459
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003460 if (((cur->type == XML_ELEMENT_NODE) ||
3461 (cur->type == XML_XINCLUDE_START) ||
3462 (cur->type == XML_XINCLUDE_END)) &&
3463 (cur->nsDef != NULL))
3464 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003465 xmlFree(cur);
3466}
3467
3468/**
3469 * xmlUnlinkNode:
3470 * @cur: the node
3471 *
3472 * Unlink a node from it's current context, the node is not freed
3473 */
3474void
3475xmlUnlinkNode(xmlNodePtr cur) {
3476 if (cur == NULL) {
3477#ifdef DEBUG_TREE
3478 xmlGenericError(xmlGenericErrorContext,
3479 "xmlUnlinkNode : node == NULL\n");
3480#endif
3481 return;
3482 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003483 if (cur->type == XML_DTD_NODE) {
3484 xmlDocPtr doc;
3485 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003486 if (doc != NULL) {
3487 if (doc->intSubset == (xmlDtdPtr) cur)
3488 doc->intSubset = NULL;
3489 if (doc->extSubset == (xmlDtdPtr) cur)
3490 doc->extSubset = NULL;
3491 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003492 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003493 if (cur->parent != NULL) {
3494 xmlNodePtr parent;
3495 parent = cur->parent;
3496 if (cur->type == XML_ATTRIBUTE_NODE) {
3497 if (parent->properties == (xmlAttrPtr) cur)
3498 parent->properties = ((xmlAttrPtr) cur)->next;
3499 } else {
3500 if (parent->children == cur)
3501 parent->children = cur->next;
3502 if (parent->last == cur)
3503 parent->last = cur->prev;
3504 }
3505 cur->parent = NULL;
3506 }
Owen Taylor3473f882001-02-23 17:55:21 +00003507 if (cur->next != NULL)
3508 cur->next->prev = cur->prev;
3509 if (cur->prev != NULL)
3510 cur->prev->next = cur->next;
3511 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003512}
3513
Daniel Veillard2156d432004-03-04 15:59:36 +00003514#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003515/**
3516 * xmlReplaceNode:
3517 * @old: the old node
3518 * @cur: the node
3519 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003520 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003521 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003522 * first unlinked from its existing context.
3523 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003524 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003525 */
3526xmlNodePtr
3527xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3528 if (old == NULL) {
3529#ifdef DEBUG_TREE
3530 xmlGenericError(xmlGenericErrorContext,
3531 "xmlReplaceNode : old == NULL\n");
3532#endif
3533 return(NULL);
3534 }
3535 if (cur == NULL) {
3536 xmlUnlinkNode(old);
3537 return(old);
3538 }
3539 if (cur == old) {
3540 return(old);
3541 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003542 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3543#ifdef DEBUG_TREE
3544 xmlGenericError(xmlGenericErrorContext,
3545 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3546#endif
3547 return(old);
3548 }
3549 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3550#ifdef DEBUG_TREE
3551 xmlGenericError(xmlGenericErrorContext,
3552 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3553#endif
3554 return(old);
3555 }
Owen Taylor3473f882001-02-23 17:55:21 +00003556 xmlUnlinkNode(cur);
3557 cur->doc = old->doc;
3558 cur->parent = old->parent;
3559 cur->next = old->next;
3560 if (cur->next != NULL)
3561 cur->next->prev = cur;
3562 cur->prev = old->prev;
3563 if (cur->prev != NULL)
3564 cur->prev->next = cur;
3565 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003566 if (cur->type == XML_ATTRIBUTE_NODE) {
3567 if (cur->parent->properties == (xmlAttrPtr)old)
3568 cur->parent->properties = ((xmlAttrPtr) cur);
3569 } else {
3570 if (cur->parent->children == old)
3571 cur->parent->children = cur;
3572 if (cur->parent->last == old)
3573 cur->parent->last = cur;
3574 }
Owen Taylor3473f882001-02-23 17:55:21 +00003575 }
3576 old->next = old->prev = NULL;
3577 old->parent = NULL;
3578 return(old);
3579}
Daniel Veillard652327a2003-09-29 18:02:38 +00003580#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003581
3582/************************************************************************
3583 * *
3584 * Copy operations *
3585 * *
3586 ************************************************************************/
3587
3588/**
3589 * xmlCopyNamespace:
3590 * @cur: the namespace
3591 *
3592 * Do a copy of the namespace.
3593 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003594 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003595 */
3596xmlNsPtr
3597xmlCopyNamespace(xmlNsPtr cur) {
3598 xmlNsPtr ret;
3599
3600 if (cur == NULL) return(NULL);
3601 switch (cur->type) {
3602 case XML_LOCAL_NAMESPACE:
3603 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3604 break;
3605 default:
3606#ifdef DEBUG_TREE
3607 xmlGenericError(xmlGenericErrorContext,
3608 "xmlCopyNamespace: invalid type %d\n", cur->type);
3609#endif
3610 return(NULL);
3611 }
3612 return(ret);
3613}
3614
3615/**
3616 * xmlCopyNamespaceList:
3617 * @cur: the first namespace
3618 *
3619 * Do a copy of an namespace list.
3620 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003621 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003622 */
3623xmlNsPtr
3624xmlCopyNamespaceList(xmlNsPtr cur) {
3625 xmlNsPtr ret = NULL;
3626 xmlNsPtr p = NULL,q;
3627
3628 while (cur != NULL) {
3629 q = xmlCopyNamespace(cur);
3630 if (p == NULL) {
3631 ret = p = q;
3632 } else {
3633 p->next = q;
3634 p = q;
3635 }
3636 cur = cur->next;
3637 }
3638 return(ret);
3639}
3640
3641static xmlNodePtr
3642xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3643/**
3644 * xmlCopyProp:
3645 * @target: the element where the attribute will be grafted
3646 * @cur: the attribute
3647 *
3648 * Do a copy of the attribute.
3649 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003650 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003651 */
3652xmlAttrPtr
3653xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3654 xmlAttrPtr ret;
3655
3656 if (cur == NULL) return(NULL);
3657 if (target != NULL)
3658 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3659 else if (cur->parent != NULL)
3660 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3661 else if (cur->children != NULL)
3662 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3663 else
3664 ret = xmlNewDocProp(NULL, cur->name, NULL);
3665 if (ret == NULL) return(NULL);
3666 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003667
Owen Taylor3473f882001-02-23 17:55:21 +00003668 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003669 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003670
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003671 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3672 if (ns == NULL) {
3673 /*
3674 * Humm, we are copying an element whose namespace is defined
3675 * out of the new tree scope. Search it in the original tree
3676 * and add it at the top of the new tree
3677 */
3678 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3679 if (ns != NULL) {
3680 xmlNodePtr root = target;
3681 xmlNodePtr pred = NULL;
3682
3683 while (root->parent != NULL) {
3684 pred = root;
3685 root = root->parent;
3686 }
3687 if (root == (xmlNodePtr) target->doc) {
3688 /* correct possibly cycling above the document elt */
3689 root = pred;
3690 }
3691 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3692 }
3693 } else {
3694 /*
3695 * we have to find something appropriate here since
3696 * we cant be sure, that the namespce we found is identified
3697 * by the prefix
3698 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003699 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003700 /* this is the nice case */
3701 ret->ns = ns;
3702 } else {
3703 /*
3704 * we are in trouble: we need a new reconcilied namespace.
3705 * This is expensive
3706 */
3707 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3708 }
3709 }
3710
Owen Taylor3473f882001-02-23 17:55:21 +00003711 } else
3712 ret->ns = NULL;
3713
3714 if (cur->children != NULL) {
3715 xmlNodePtr tmp;
3716
3717 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3718 ret->last = NULL;
3719 tmp = ret->children;
3720 while (tmp != NULL) {
3721 /* tmp->parent = (xmlNodePtr)ret; */
3722 if (tmp->next == NULL)
3723 ret->last = tmp;
3724 tmp = tmp->next;
3725 }
3726 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003727 /*
3728 * Try to handle IDs
3729 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003730 if ((target!= NULL) && (cur!= NULL) &&
3731 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003732 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3733 if (xmlIsID(cur->doc, cur->parent, cur)) {
3734 xmlChar *id;
3735
3736 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3737 if (id != NULL) {
3738 xmlAddID(NULL, target->doc, id, ret);
3739 xmlFree(id);
3740 }
3741 }
3742 }
Owen Taylor3473f882001-02-23 17:55:21 +00003743 return(ret);
3744}
3745
3746/**
3747 * xmlCopyPropList:
3748 * @target: the element where the attributes will be grafted
3749 * @cur: the first attribute
3750 *
3751 * Do a copy of an attribute list.
3752 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003753 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003754 */
3755xmlAttrPtr
3756xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3757 xmlAttrPtr ret = NULL;
3758 xmlAttrPtr p = NULL,q;
3759
3760 while (cur != NULL) {
3761 q = xmlCopyProp(target, cur);
William M. Brack13dfa872004-09-18 04:52:08 +00003762 if (q == NULL)
3763 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003764 if (p == NULL) {
3765 ret = p = q;
3766 } else {
3767 p->next = q;
3768 q->prev = p;
3769 p = q;
3770 }
3771 cur = cur->next;
3772 }
3773 return(ret);
3774}
3775
3776/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003777 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003778 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003779 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003780 * tricky reason: namespaces. Doing a direct copy of a node
3781 * say RPM:Copyright without changing the namespace pointer to
3782 * something else can produce stale links. One way to do it is
3783 * to keep a reference counter but this doesn't work as soon
3784 * as one move the element or the subtree out of the scope of
3785 * the existing namespace. The actual solution seems to add
3786 * a copy of the namespace at the top of the copied tree if
3787 * not available in the subtree.
3788 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00003789 * The argument "recursive" normally indicates a recursive copy
3790 * of the node with values 0 (no) and 1 (yes). For XInclude,
3791 * however, we allow a value of 2 to indicate copy properties and
3792 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00003793 */
3794
3795static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003796xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00003797 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003798 xmlNodePtr ret;
3799
3800 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003801 switch (node->type) {
3802 case XML_TEXT_NODE:
3803 case XML_CDATA_SECTION_NODE:
3804 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003805 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003806 case XML_ENTITY_REF_NODE:
3807 case XML_ENTITY_NODE:
3808 case XML_PI_NODE:
3809 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003810 case XML_XINCLUDE_START:
3811 case XML_XINCLUDE_END:
3812 break;
3813 case XML_ATTRIBUTE_NODE:
3814 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3815 case XML_NAMESPACE_DECL:
3816 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3817
Daniel Veillard39196eb2001-06-19 18:09:42 +00003818 case XML_DOCUMENT_NODE:
3819 case XML_HTML_DOCUMENT_NODE:
3820#ifdef LIBXML_DOCB_ENABLED
3821 case XML_DOCB_DOCUMENT_NODE:
3822#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003823#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00003824 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00003825#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003826 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003827 case XML_NOTATION_NODE:
3828 case XML_DTD_NODE:
3829 case XML_ELEMENT_DECL:
3830 case XML_ATTRIBUTE_DECL:
3831 case XML_ENTITY_DECL:
3832 return(NULL);
3833 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003834
Owen Taylor3473f882001-02-23 17:55:21 +00003835 /*
3836 * Allocate a new node and fill the fields.
3837 */
3838 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3839 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003840 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003841 return(NULL);
3842 }
3843 memset(ret, 0, sizeof(xmlNode));
3844 ret->type = node->type;
3845
3846 ret->doc = doc;
3847 ret->parent = parent;
3848 if (node->name == xmlStringText)
3849 ret->name = xmlStringText;
3850 else if (node->name == xmlStringTextNoenc)
3851 ret->name = xmlStringTextNoenc;
3852 else if (node->name == xmlStringComment)
3853 ret->name = xmlStringComment;
Daniel Veillard03a53c32004-10-26 16:06:51 +00003854 else if (node->name != NULL) {
3855 if ((doc != NULL) && (doc->dict != NULL))
3856 ret->name = xmlDictLookup(doc->dict, node->name, -1);
3857 else
3858 ret->name = xmlStrdup(node->name);
3859 }
Daniel Veillard7db37732001-07-12 01:20:08 +00003860 if ((node->type != XML_ELEMENT_NODE) &&
3861 (node->content != NULL) &&
3862 (node->type != XML_ENTITY_REF_NODE) &&
3863 (node->type != XML_XINCLUDE_END) &&
3864 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003865 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003866 }else{
3867 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003868 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003869 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003870 if (parent != NULL) {
3871 xmlNodePtr tmp;
3872
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003873 /*
3874 * this is a tricky part for the node register thing:
3875 * in case ret does get coalesced in xmlAddChild
3876 * the deregister-node callback is called; so we register ret now already
3877 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003878 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003879 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3880
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003881 tmp = xmlAddChild(parent, ret);
3882 /* node could have coalesced */
3883 if (tmp != ret)
3884 return(tmp);
3885 }
Owen Taylor3473f882001-02-23 17:55:21 +00003886
William M. Brack57e9e912004-03-09 16:19:02 +00003887 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003888 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003889 if (node->nsDef != NULL)
3890 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3891
3892 if (node->ns != NULL) {
3893 xmlNsPtr ns;
3894
3895 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3896 if (ns == NULL) {
3897 /*
3898 * Humm, we are copying an element whose namespace is defined
3899 * out of the new tree scope. Search it in the original tree
3900 * and add it at the top of the new tree
3901 */
3902 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3903 if (ns != NULL) {
3904 xmlNodePtr root = ret;
3905
3906 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003907 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003908 }
3909 } else {
3910 /*
3911 * reference the existing namespace definition in our own tree.
3912 */
3913 ret->ns = ns;
3914 }
3915 }
3916 if (node->properties != NULL)
3917 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003918 if (node->type == XML_ENTITY_REF_NODE) {
3919 if ((doc == NULL) || (node->doc != doc)) {
3920 /*
3921 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003922 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003923 * we cannot keep the reference. Try to find it in the
3924 * target document.
3925 */
3926 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3927 } else {
3928 ret->children = node->children;
3929 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003930 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00003931 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003932 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003933 UPDATE_LAST_CHILD_AND_PARENT(ret)
3934 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003935
3936out:
3937 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00003938 if ((parent == NULL) &&
3939 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003940 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003941 return(ret);
3942}
3943
3944static xmlNodePtr
3945xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3946 xmlNodePtr ret = NULL;
3947 xmlNodePtr p = NULL,q;
3948
3949 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003950#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003951 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003952 if (doc == NULL) {
3953 node = node->next;
3954 continue;
3955 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003956 if (doc->intSubset == NULL) {
3957 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3958 q->doc = doc;
3959 q->parent = parent;
3960 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003961 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003962 } else {
3963 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003964 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003965 }
3966 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003967#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003968 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003969 if (ret == NULL) {
3970 q->prev = NULL;
3971 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003972 } else if (p != q) {
3973 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003974 p->next = q;
3975 q->prev = p;
3976 p = q;
3977 }
3978 node = node->next;
3979 }
3980 return(ret);
3981}
3982
3983/**
3984 * xmlCopyNode:
3985 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00003986 * @extended: if 1 do a recursive copy (properties, namespaces and children
3987 * when applicable)
3988 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00003989 *
3990 * Do a copy of the node.
3991 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003992 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003993 */
3994xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003995xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003996 xmlNodePtr ret;
3997
William M. Brack57e9e912004-03-09 16:19:02 +00003998 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00003999 return(ret);
4000}
4001
4002/**
Daniel Veillard82daa812001-04-12 08:55:36 +00004003 * xmlDocCopyNode:
4004 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00004005 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004006 * @extended: if 1 do a recursive copy (properties, namespaces and children
4007 * when applicable)
4008 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00004009 *
4010 * Do a copy of the node to a given document.
4011 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004012 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00004013 */
4014xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00004015xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00004016 xmlNodePtr ret;
4017
William M. Brack57e9e912004-03-09 16:19:02 +00004018 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00004019 return(ret);
4020}
4021
4022/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00004023 * xmlDocCopyNodeList:
4024 * @doc: the target document
4025 * @node: the first node in the list.
4026 *
4027 * Do a recursive copy of the node list.
4028 *
4029 * Returns: a new #xmlNodePtr, or NULL in case of error.
4030 */
4031xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) {
4032 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
4033 return(ret);
4034}
4035
4036/**
Owen Taylor3473f882001-02-23 17:55:21 +00004037 * xmlCopyNodeList:
4038 * @node: the first node in the list.
4039 *
4040 * Do a recursive copy of the node list.
Daniel Veillard03a53c32004-10-26 16:06:51 +00004041 * Use xmlDocCopyNodeList() if possible to ensure string interning.
Owen Taylor3473f882001-02-23 17:55:21 +00004042 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004043 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004044 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00004045xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00004046 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
4047 return(ret);
4048}
4049
Daniel Veillard2156d432004-03-04 15:59:36 +00004050#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004051/**
Owen Taylor3473f882001-02-23 17:55:21 +00004052 * xmlCopyDtd:
4053 * @dtd: the dtd
4054 *
4055 * Do a copy of the dtd.
4056 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004057 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004058 */
4059xmlDtdPtr
4060xmlCopyDtd(xmlDtdPtr dtd) {
4061 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004062 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00004063
4064 if (dtd == NULL) return(NULL);
4065 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4066 if (ret == NULL) return(NULL);
4067 if (dtd->entities != NULL)
4068 ret->entities = (void *) xmlCopyEntitiesTable(
4069 (xmlEntitiesTablePtr) dtd->entities);
4070 if (dtd->notations != NULL)
4071 ret->notations = (void *) xmlCopyNotationTable(
4072 (xmlNotationTablePtr) dtd->notations);
4073 if (dtd->elements != NULL)
4074 ret->elements = (void *) xmlCopyElementTable(
4075 (xmlElementTablePtr) dtd->elements);
4076 if (dtd->attributes != NULL)
4077 ret->attributes = (void *) xmlCopyAttributeTable(
4078 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004079 if (dtd->pentities != NULL)
4080 ret->pentities = (void *) xmlCopyEntitiesTable(
4081 (xmlEntitiesTablePtr) dtd->pentities);
4082
4083 cur = dtd->children;
4084 while (cur != NULL) {
4085 q = NULL;
4086
4087 if (cur->type == XML_ENTITY_DECL) {
4088 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4089 switch (tmp->etype) {
4090 case XML_INTERNAL_GENERAL_ENTITY:
4091 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4092 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4093 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4094 break;
4095 case XML_INTERNAL_PARAMETER_ENTITY:
4096 case XML_EXTERNAL_PARAMETER_ENTITY:
4097 q = (xmlNodePtr)
4098 xmlGetParameterEntityFromDtd(ret, tmp->name);
4099 break;
4100 case XML_INTERNAL_PREDEFINED_ENTITY:
4101 break;
4102 }
4103 } else if (cur->type == XML_ELEMENT_DECL) {
4104 xmlElementPtr tmp = (xmlElementPtr) cur;
4105 q = (xmlNodePtr)
4106 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4107 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4108 xmlAttributePtr tmp = (xmlAttributePtr) cur;
4109 q = (xmlNodePtr)
4110 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4111 } else if (cur->type == XML_COMMENT_NODE) {
4112 q = xmlCopyNode(cur, 0);
4113 }
4114
4115 if (q == NULL) {
4116 cur = cur->next;
4117 continue;
4118 }
4119
4120 if (p == NULL)
4121 ret->children = q;
4122 else
4123 p->next = q;
4124
4125 q->prev = p;
4126 q->parent = (xmlNodePtr) ret;
4127 q->next = NULL;
4128 ret->last = q;
4129 p = q;
4130 cur = cur->next;
4131 }
4132
Owen Taylor3473f882001-02-23 17:55:21 +00004133 return(ret);
4134}
Daniel Veillard2156d432004-03-04 15:59:36 +00004135#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004136
Daniel Veillard2156d432004-03-04 15:59:36 +00004137#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004138/**
4139 * xmlCopyDoc:
4140 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004141 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004142 *
4143 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004144 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004145 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004146 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004147 */
4148xmlDocPtr
4149xmlCopyDoc(xmlDocPtr doc, int recursive) {
4150 xmlDocPtr ret;
4151
4152 if (doc == NULL) return(NULL);
4153 ret = xmlNewDoc(doc->version);
4154 if (ret == NULL) return(NULL);
4155 if (doc->name != NULL)
4156 ret->name = xmlMemStrdup(doc->name);
4157 if (doc->encoding != NULL)
4158 ret->encoding = xmlStrdup(doc->encoding);
4159 ret->charset = doc->charset;
4160 ret->compression = doc->compression;
4161 ret->standalone = doc->standalone;
4162 if (!recursive) return(ret);
4163
Daniel Veillardb33c2012001-04-25 12:59:04 +00004164 ret->last = NULL;
4165 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004166#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004167 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004168 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004169 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004170 ret->intSubset->parent = ret;
4171 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004172#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004173 if (doc->oldNs != NULL)
4174 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4175 if (doc->children != NULL) {
4176 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004177
4178 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4179 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004180 ret->last = NULL;
4181 tmp = ret->children;
4182 while (tmp != NULL) {
4183 if (tmp->next == NULL)
4184 ret->last = tmp;
4185 tmp = tmp->next;
4186 }
4187 }
4188 return(ret);
4189}
Daniel Veillard652327a2003-09-29 18:02:38 +00004190#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004191
4192/************************************************************************
4193 * *
4194 * Content access functions *
4195 * *
4196 ************************************************************************/
4197
4198/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004199 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004200 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004201 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004202 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004203 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004204 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004205 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004206 */
4207long
4208xmlGetLineNo(xmlNodePtr node)
4209{
4210 long result = -1;
4211
4212 if (!node)
4213 return result;
4214 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004215 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004216 else if ((node->prev != NULL) &&
4217 ((node->prev->type == XML_ELEMENT_NODE) ||
4218 (node->prev->type == XML_TEXT_NODE)))
4219 result = xmlGetLineNo(node->prev);
4220 else if ((node->parent != NULL) &&
4221 ((node->parent->type == XML_ELEMENT_NODE) ||
4222 (node->parent->type == XML_TEXT_NODE)))
4223 result = xmlGetLineNo(node->parent);
4224
4225 return result;
4226}
4227
Daniel Veillard2156d432004-03-04 15:59:36 +00004228#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004229/**
4230 * xmlGetNodePath:
4231 * @node: a node
4232 *
4233 * Build a structure based Path for the given node
4234 *
4235 * Returns the new path or NULL in case of error. The caller must free
4236 * the returned string
4237 */
4238xmlChar *
4239xmlGetNodePath(xmlNodePtr node)
4240{
4241 xmlNodePtr cur, tmp, next;
4242 xmlChar *buffer = NULL, *temp;
4243 size_t buf_len;
4244 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004245 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004246 const char *name;
4247 char nametemp[100];
4248 int occur = 0;
4249
4250 if (node == NULL)
4251 return (NULL);
4252
4253 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004254 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004255 if (buffer == NULL) {
4256 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004257 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004258 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004259 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004260 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004261 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004262 xmlFree(buffer);
4263 return (NULL);
4264 }
4265
4266 buffer[0] = 0;
4267 cur = node;
4268 do {
4269 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004270 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004271 occur = 0;
4272 if ((cur->type == XML_DOCUMENT_NODE) ||
4273 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4274 if (buffer[0] == '/')
4275 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004276 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004277 next = NULL;
4278 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004279 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004280 name = (const char *) cur->name;
4281 if (cur->ns) {
William M. Brack84d83e32003-12-23 03:45:17 +00004282 if (cur->ns->prefix != NULL)
William M. Brack13dfa872004-09-18 04:52:08 +00004283 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4284 (char *)cur->ns->prefix, (char *)cur->name);
William M. Brack84d83e32003-12-23 03:45:17 +00004285 else
William M. Brack13dfa872004-09-18 04:52:08 +00004286 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4287 (char *)cur->name);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004288 nametemp[sizeof(nametemp) - 1] = 0;
4289 name = nametemp;
4290 }
4291 next = cur->parent;
4292
4293 /*
4294 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004295 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004296 */
4297 tmp = cur->prev;
4298 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004299 if ((tmp->type == XML_ELEMENT_NODE) &&
4300 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004301 occur++;
4302 tmp = tmp->prev;
4303 }
4304 if (occur == 0) {
4305 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004306 while (tmp != NULL && occur == 0) {
4307 if ((tmp->type == XML_ELEMENT_NODE) &&
4308 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004309 occur++;
4310 tmp = tmp->next;
4311 }
4312 if (occur != 0)
4313 occur = 1;
4314 } else
4315 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004316 } else if (cur->type == XML_COMMENT_NODE) {
4317 sep = "/";
4318 name = "comment()";
4319 next = cur->parent;
4320
4321 /*
4322 * Thumbler index computation
4323 */
4324 tmp = cur->prev;
4325 while (tmp != NULL) {
4326 if (tmp->type == XML_COMMENT_NODE)
4327 occur++;
4328 tmp = tmp->prev;
4329 }
4330 if (occur == 0) {
4331 tmp = cur->next;
4332 while (tmp != NULL && occur == 0) {
4333 if (tmp->type == XML_COMMENT_NODE)
4334 occur++;
4335 tmp = tmp->next;
4336 }
4337 if (occur != 0)
4338 occur = 1;
4339 } else
4340 occur++;
4341 } else if ((cur->type == XML_TEXT_NODE) ||
4342 (cur->type == XML_CDATA_SECTION_NODE)) {
4343 sep = "/";
4344 name = "text()";
4345 next = cur->parent;
4346
4347 /*
4348 * Thumbler index computation
4349 */
4350 tmp = cur->prev;
4351 while (tmp != NULL) {
4352 if ((cur->type == XML_TEXT_NODE) ||
4353 (cur->type == XML_CDATA_SECTION_NODE))
4354 occur++;
4355 tmp = tmp->prev;
4356 }
4357 if (occur == 0) {
4358 tmp = cur->next;
4359 while (tmp != NULL && occur == 0) {
Daniel Veillard1f8658a2004-08-14 21:46:31 +00004360 if ((tmp->type == XML_TEXT_NODE) ||
4361 (tmp->type == XML_CDATA_SECTION_NODE))
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004362 occur++;
4363 tmp = tmp->next;
4364 }
4365 if (occur != 0)
4366 occur = 1;
4367 } else
4368 occur++;
4369 } else if (cur->type == XML_PI_NODE) {
4370 sep = "/";
4371 snprintf(nametemp, sizeof(nametemp) - 1,
William M. Brack13dfa872004-09-18 04:52:08 +00004372 "processing-instruction('%s')", (char *)cur->name);
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004373 nametemp[sizeof(nametemp) - 1] = 0;
4374 name = nametemp;
4375
4376 next = cur->parent;
4377
4378 /*
4379 * Thumbler index computation
4380 */
4381 tmp = cur->prev;
4382 while (tmp != NULL) {
4383 if ((tmp->type == XML_PI_NODE) &&
4384 (xmlStrEqual(cur->name, tmp->name)))
4385 occur++;
4386 tmp = tmp->prev;
4387 }
4388 if (occur == 0) {
4389 tmp = cur->next;
4390 while (tmp != NULL && occur == 0) {
4391 if ((tmp->type == XML_PI_NODE) &&
4392 (xmlStrEqual(cur->name, tmp->name)))
4393 occur++;
4394 tmp = tmp->next;
4395 }
4396 if (occur != 0)
4397 occur = 1;
4398 } else
4399 occur++;
4400
Daniel Veillard8faa7832001-11-26 15:58:08 +00004401 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004402 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004403 name = (const char *) (((xmlAttrPtr) cur)->name);
4404 next = ((xmlAttrPtr) cur)->parent;
4405 } else {
4406 next = cur->parent;
4407 }
4408
4409 /*
4410 * Make sure there is enough room
4411 */
4412 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4413 buf_len =
4414 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4415 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4416 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004417 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004418 xmlFree(buf);
4419 xmlFree(buffer);
4420 return (NULL);
4421 }
4422 buffer = temp;
4423 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4424 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004425 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004426 xmlFree(buf);
4427 xmlFree(buffer);
4428 return (NULL);
4429 }
4430 buf = temp;
4431 }
4432 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004433 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004434 sep, name, (char *) buffer);
4435 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004436 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004437 sep, name, occur, (char *) buffer);
William M. Brack13dfa872004-09-18 04:52:08 +00004438 snprintf((char *) buffer, buf_len, "%s", (char *)buf);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004439 cur = next;
4440 } while (cur != NULL);
4441 xmlFree(buf);
4442 return (buffer);
4443}
Daniel Veillard652327a2003-09-29 18:02:38 +00004444#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004445
4446/**
Owen Taylor3473f882001-02-23 17:55:21 +00004447 * xmlDocGetRootElement:
4448 * @doc: the document
4449 *
4450 * Get the root element of the document (doc->children is a list
4451 * containing possibly comments, PIs, etc ...).
4452 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004453 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004454 */
4455xmlNodePtr
4456xmlDocGetRootElement(xmlDocPtr doc) {
4457 xmlNodePtr ret;
4458
4459 if (doc == NULL) return(NULL);
4460 ret = doc->children;
4461 while (ret != NULL) {
4462 if (ret->type == XML_ELEMENT_NODE)
4463 return(ret);
4464 ret = ret->next;
4465 }
4466 return(ret);
4467}
4468
Daniel Veillard2156d432004-03-04 15:59:36 +00004469#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004470/**
4471 * xmlDocSetRootElement:
4472 * @doc: the document
4473 * @root: the new document root element
4474 *
4475 * Set the root element of the document (doc->children is a list
4476 * containing possibly comments, PIs, etc ...).
4477 *
4478 * Returns the old root element if any was found
4479 */
4480xmlNodePtr
4481xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4482 xmlNodePtr old = NULL;
4483
4484 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004485 if (root == NULL)
4486 return(NULL);
4487 xmlUnlinkNode(root);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00004488 xmlSetTreeDoc(root, doc);
Daniel Veillardc575b992002-02-08 13:28:40 +00004489 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004490 old = doc->children;
4491 while (old != NULL) {
4492 if (old->type == XML_ELEMENT_NODE)
4493 break;
4494 old = old->next;
4495 }
4496 if (old == NULL) {
4497 if (doc->children == NULL) {
4498 doc->children = root;
4499 doc->last = root;
4500 } else {
4501 xmlAddSibling(doc->children, root);
4502 }
4503 } else {
4504 xmlReplaceNode(old, root);
4505 }
4506 return(old);
4507}
Daniel Veillard2156d432004-03-04 15:59:36 +00004508#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004509
Daniel Veillard2156d432004-03-04 15:59:36 +00004510#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004511/**
4512 * xmlNodeSetLang:
4513 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004514 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004515 *
4516 * Set the language of a node, i.e. the values of the xml:lang
4517 * attribute.
4518 */
4519void
4520xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004521 xmlNsPtr ns;
4522
Owen Taylor3473f882001-02-23 17:55:21 +00004523 if (cur == NULL) return;
4524 switch(cur->type) {
4525 case XML_TEXT_NODE:
4526 case XML_CDATA_SECTION_NODE:
4527 case XML_COMMENT_NODE:
4528 case XML_DOCUMENT_NODE:
4529 case XML_DOCUMENT_TYPE_NODE:
4530 case XML_DOCUMENT_FRAG_NODE:
4531 case XML_NOTATION_NODE:
4532 case XML_HTML_DOCUMENT_NODE:
4533 case XML_DTD_NODE:
4534 case XML_ELEMENT_DECL:
4535 case XML_ATTRIBUTE_DECL:
4536 case XML_ENTITY_DECL:
4537 case XML_PI_NODE:
4538 case XML_ENTITY_REF_NODE:
4539 case XML_ENTITY_NODE:
4540 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004541#ifdef LIBXML_DOCB_ENABLED
4542 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004543#endif
4544 case XML_XINCLUDE_START:
4545 case XML_XINCLUDE_END:
4546 return;
4547 case XML_ELEMENT_NODE:
4548 case XML_ATTRIBUTE_NODE:
4549 break;
4550 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004551 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4552 if (ns == NULL)
4553 return;
4554 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004555}
Daniel Veillard652327a2003-09-29 18:02:38 +00004556#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004557
4558/**
4559 * xmlNodeGetLang:
4560 * @cur: the node being checked
4561 *
4562 * Searches the language of a node, i.e. the values of the xml:lang
4563 * attribute or the one carried by the nearest ancestor.
4564 *
4565 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004566 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004567 */
4568xmlChar *
4569xmlNodeGetLang(xmlNodePtr cur) {
4570 xmlChar *lang;
4571
4572 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004573 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004574 if (lang != NULL)
4575 return(lang);
4576 cur = cur->parent;
4577 }
4578 return(NULL);
4579}
4580
4581
Daniel Veillard652327a2003-09-29 18:02:38 +00004582#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004583/**
4584 * xmlNodeSetSpacePreserve:
4585 * @cur: the node being changed
4586 * @val: the xml:space value ("0": default, 1: "preserve")
4587 *
4588 * Set (or reset) the space preserving behaviour of a node, i.e. the
4589 * value of the xml:space attribute.
4590 */
4591void
4592xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004593 xmlNsPtr ns;
4594
Owen Taylor3473f882001-02-23 17:55:21 +00004595 if (cur == NULL) return;
4596 switch(cur->type) {
4597 case XML_TEXT_NODE:
4598 case XML_CDATA_SECTION_NODE:
4599 case XML_COMMENT_NODE:
4600 case XML_DOCUMENT_NODE:
4601 case XML_DOCUMENT_TYPE_NODE:
4602 case XML_DOCUMENT_FRAG_NODE:
4603 case XML_NOTATION_NODE:
4604 case XML_HTML_DOCUMENT_NODE:
4605 case XML_DTD_NODE:
4606 case XML_ELEMENT_DECL:
4607 case XML_ATTRIBUTE_DECL:
4608 case XML_ENTITY_DECL:
4609 case XML_PI_NODE:
4610 case XML_ENTITY_REF_NODE:
4611 case XML_ENTITY_NODE:
4612 case XML_NAMESPACE_DECL:
4613 case XML_XINCLUDE_START:
4614 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004615#ifdef LIBXML_DOCB_ENABLED
4616 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004617#endif
4618 return;
4619 case XML_ELEMENT_NODE:
4620 case XML_ATTRIBUTE_NODE:
4621 break;
4622 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004623 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4624 if (ns == NULL)
4625 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004626 switch (val) {
4627 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004628 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004629 break;
4630 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004631 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004632 break;
4633 }
4634}
Daniel Veillard652327a2003-09-29 18:02:38 +00004635#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004636
4637/**
4638 * xmlNodeGetSpacePreserve:
4639 * @cur: the node being checked
4640 *
4641 * Searches the space preserving behaviour of a node, i.e. the values
4642 * of the xml:space attribute or the one carried by the nearest
4643 * ancestor.
4644 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004645 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004646 */
4647int
4648xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4649 xmlChar *space;
4650
4651 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004652 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004653 if (space != NULL) {
4654 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4655 xmlFree(space);
4656 return(1);
4657 }
4658 if (xmlStrEqual(space, BAD_CAST "default")) {
4659 xmlFree(space);
4660 return(0);
4661 }
4662 xmlFree(space);
4663 }
4664 cur = cur->parent;
4665 }
4666 return(-1);
4667}
4668
Daniel Veillard652327a2003-09-29 18:02:38 +00004669#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004670/**
4671 * xmlNodeSetName:
4672 * @cur: the node being changed
4673 * @name: the new tag name
4674 *
4675 * Set (or reset) the name of a node.
4676 */
4677void
4678xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4679 if (cur == NULL) return;
4680 if (name == NULL) return;
4681 switch(cur->type) {
4682 case XML_TEXT_NODE:
4683 case XML_CDATA_SECTION_NODE:
4684 case XML_COMMENT_NODE:
4685 case XML_DOCUMENT_TYPE_NODE:
4686 case XML_DOCUMENT_FRAG_NODE:
4687 case XML_NOTATION_NODE:
4688 case XML_HTML_DOCUMENT_NODE:
4689 case XML_NAMESPACE_DECL:
4690 case XML_XINCLUDE_START:
4691 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004692#ifdef LIBXML_DOCB_ENABLED
4693 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004694#endif
4695 return;
4696 case XML_ELEMENT_NODE:
4697 case XML_ATTRIBUTE_NODE:
4698 case XML_PI_NODE:
4699 case XML_ENTITY_REF_NODE:
4700 case XML_ENTITY_NODE:
4701 case XML_DTD_NODE:
4702 case XML_DOCUMENT_NODE:
4703 case XML_ELEMENT_DECL:
4704 case XML_ATTRIBUTE_DECL:
4705 case XML_ENTITY_DECL:
4706 break;
4707 }
4708 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4709 cur->name = xmlStrdup(name);
4710}
Daniel Veillard2156d432004-03-04 15:59:36 +00004711#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004712
Daniel Veillard2156d432004-03-04 15:59:36 +00004713#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004714/**
4715 * xmlNodeSetBase:
4716 * @cur: the node being changed
4717 * @uri: the new base URI
4718 *
4719 * Set (or reset) the base URI of a node, i.e. the value of the
4720 * xml:base attribute.
4721 */
4722void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004723xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004724 xmlNsPtr ns;
4725
Owen Taylor3473f882001-02-23 17:55:21 +00004726 if (cur == NULL) return;
4727 switch(cur->type) {
4728 case XML_TEXT_NODE:
4729 case XML_CDATA_SECTION_NODE:
4730 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004731 case XML_DOCUMENT_TYPE_NODE:
4732 case XML_DOCUMENT_FRAG_NODE:
4733 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004734 case XML_DTD_NODE:
4735 case XML_ELEMENT_DECL:
4736 case XML_ATTRIBUTE_DECL:
4737 case XML_ENTITY_DECL:
4738 case XML_PI_NODE:
4739 case XML_ENTITY_REF_NODE:
4740 case XML_ENTITY_NODE:
4741 case XML_NAMESPACE_DECL:
4742 case XML_XINCLUDE_START:
4743 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004744 return;
4745 case XML_ELEMENT_NODE:
4746 case XML_ATTRIBUTE_NODE:
4747 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004748 case XML_DOCUMENT_NODE:
4749#ifdef LIBXML_DOCB_ENABLED
4750 case XML_DOCB_DOCUMENT_NODE:
4751#endif
4752 case XML_HTML_DOCUMENT_NODE: {
4753 xmlDocPtr doc = (xmlDocPtr) cur;
4754
4755 if (doc->URL != NULL)
4756 xmlFree((xmlChar *) doc->URL);
4757 if (uri == NULL)
4758 doc->URL = NULL;
4759 else
4760 doc->URL = xmlStrdup(uri);
4761 return;
4762 }
Owen Taylor3473f882001-02-23 17:55:21 +00004763 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004764
4765 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4766 if (ns == NULL)
4767 return;
4768 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004769}
Daniel Veillard652327a2003-09-29 18:02:38 +00004770#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004771
4772/**
Owen Taylor3473f882001-02-23 17:55:21 +00004773 * xmlNodeGetBase:
4774 * @doc: the document the node pertains to
4775 * @cur: the node being checked
4776 *
4777 * Searches for the BASE URL. The code should work on both XML
4778 * and HTML document even if base mechanisms are completely different.
4779 * It returns the base as defined in RFC 2396 sections
4780 * 5.1.1. Base URI within Document Content
4781 * and
4782 * 5.1.2. Base URI from the Encapsulating Entity
4783 * However it does not return the document base (5.1.3), use
4784 * xmlDocumentGetBase() for this
4785 *
4786 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004787 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004788 */
4789xmlChar *
4790xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004791 xmlChar *oldbase = NULL;
4792 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004793
4794 if ((cur == NULL) && (doc == NULL))
4795 return(NULL);
4796 if (doc == NULL) doc = cur->doc;
4797 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4798 cur = doc->children;
4799 while ((cur != NULL) && (cur->name != NULL)) {
4800 if (cur->type != XML_ELEMENT_NODE) {
4801 cur = cur->next;
4802 continue;
4803 }
4804 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4805 cur = cur->children;
4806 continue;
4807 }
4808 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4809 cur = cur->children;
4810 continue;
4811 }
4812 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4813 return(xmlGetProp(cur, BAD_CAST "href"));
4814 }
4815 cur = cur->next;
4816 }
4817 return(NULL);
4818 }
4819 while (cur != NULL) {
4820 if (cur->type == XML_ENTITY_DECL) {
4821 xmlEntityPtr ent = (xmlEntityPtr) cur;
4822 return(xmlStrdup(ent->URI));
4823 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004824 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004825 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004826 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004827 if (oldbase != NULL) {
4828 newbase = xmlBuildURI(oldbase, base);
4829 if (newbase != NULL) {
4830 xmlFree(oldbase);
4831 xmlFree(base);
4832 oldbase = newbase;
4833 } else {
4834 xmlFree(oldbase);
4835 xmlFree(base);
4836 return(NULL);
4837 }
4838 } else {
4839 oldbase = base;
4840 }
4841 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4842 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4843 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4844 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004845 }
4846 }
Owen Taylor3473f882001-02-23 17:55:21 +00004847 cur = cur->parent;
4848 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004849 if ((doc != NULL) && (doc->URL != NULL)) {
4850 if (oldbase == NULL)
4851 return(xmlStrdup(doc->URL));
4852 newbase = xmlBuildURI(oldbase, doc->URL);
4853 xmlFree(oldbase);
4854 return(newbase);
4855 }
4856 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004857}
4858
4859/**
Daniel Veillard78697292003-10-19 20:44:43 +00004860 * xmlNodeBufGetContent:
4861 * @buffer: a buffer
4862 * @cur: the node being read
4863 *
4864 * Read the value of a node @cur, this can be either the text carried
4865 * directly by this node if it's a TEXT node or the aggregate string
4866 * of the values carried by this node child's (TEXT and ENTITY_REF).
4867 * Entity references are substituted.
4868 * Fills up the buffer @buffer with this value
4869 *
4870 * Returns 0 in case of success and -1 in case of error.
4871 */
4872int
4873xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4874{
4875 if ((cur == NULL) || (buffer == NULL)) return(-1);
4876 switch (cur->type) {
4877 case XML_CDATA_SECTION_NODE:
4878 case XML_TEXT_NODE:
4879 xmlBufferCat(buffer, cur->content);
4880 break;
4881 case XML_DOCUMENT_FRAG_NODE:
4882 case XML_ELEMENT_NODE:{
4883 xmlNodePtr tmp = cur;
4884
4885 while (tmp != NULL) {
4886 switch (tmp->type) {
4887 case XML_CDATA_SECTION_NODE:
4888 case XML_TEXT_NODE:
4889 if (tmp->content != NULL)
4890 xmlBufferCat(buffer, tmp->content);
4891 break;
4892 case XML_ENTITY_REF_NODE:
4893 xmlNodeBufGetContent(buffer, tmp->children);
4894 break;
4895 default:
4896 break;
4897 }
4898 /*
4899 * Skip to next node
4900 */
4901 if (tmp->children != NULL) {
4902 if (tmp->children->type != XML_ENTITY_DECL) {
4903 tmp = tmp->children;
4904 continue;
4905 }
4906 }
4907 if (tmp == cur)
4908 break;
4909
4910 if (tmp->next != NULL) {
4911 tmp = tmp->next;
4912 continue;
4913 }
4914
4915 do {
4916 tmp = tmp->parent;
4917 if (tmp == NULL)
4918 break;
4919 if (tmp == cur) {
4920 tmp = NULL;
4921 break;
4922 }
4923 if (tmp->next != NULL) {
4924 tmp = tmp->next;
4925 break;
4926 }
4927 } while (tmp != NULL);
4928 }
4929 break;
4930 }
4931 case XML_ATTRIBUTE_NODE:{
4932 xmlAttrPtr attr = (xmlAttrPtr) cur;
4933 xmlNodePtr tmp = attr->children;
4934
4935 while (tmp != NULL) {
4936 if (tmp->type == XML_TEXT_NODE)
4937 xmlBufferCat(buffer, tmp->content);
4938 else
4939 xmlNodeBufGetContent(buffer, tmp);
4940 tmp = tmp->next;
4941 }
4942 break;
4943 }
4944 case XML_COMMENT_NODE:
4945 case XML_PI_NODE:
4946 xmlBufferCat(buffer, cur->content);
4947 break;
4948 case XML_ENTITY_REF_NODE:{
4949 xmlEntityPtr ent;
4950 xmlNodePtr tmp;
4951
4952 /* lookup entity declaration */
4953 ent = xmlGetDocEntity(cur->doc, cur->name);
4954 if (ent == NULL)
4955 return(-1);
4956
4957 /* an entity content can be any "well balanced chunk",
4958 * i.e. the result of the content [43] production:
4959 * http://www.w3.org/TR/REC-xml#NT-content
4960 * -> we iterate through child nodes and recursive call
4961 * xmlNodeGetContent() which handles all possible node types */
4962 tmp = ent->children;
4963 while (tmp) {
4964 xmlNodeBufGetContent(buffer, tmp);
4965 tmp = tmp->next;
4966 }
4967 break;
4968 }
4969 case XML_ENTITY_NODE:
4970 case XML_DOCUMENT_TYPE_NODE:
4971 case XML_NOTATION_NODE:
4972 case XML_DTD_NODE:
4973 case XML_XINCLUDE_START:
4974 case XML_XINCLUDE_END:
4975 break;
4976 case XML_DOCUMENT_NODE:
4977#ifdef LIBXML_DOCB_ENABLED
4978 case XML_DOCB_DOCUMENT_NODE:
4979#endif
4980 case XML_HTML_DOCUMENT_NODE:
4981 cur = cur->children;
4982 while (cur!= NULL) {
4983 if ((cur->type == XML_ELEMENT_NODE) ||
4984 (cur->type == XML_TEXT_NODE) ||
4985 (cur->type == XML_CDATA_SECTION_NODE)) {
4986 xmlNodeBufGetContent(buffer, cur);
4987 }
4988 cur = cur->next;
4989 }
4990 break;
4991 case XML_NAMESPACE_DECL:
4992 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
4993 break;
4994 case XML_ELEMENT_DECL:
4995 case XML_ATTRIBUTE_DECL:
4996 case XML_ENTITY_DECL:
4997 break;
4998 }
4999 return(0);
5000}
5001/**
Owen Taylor3473f882001-02-23 17:55:21 +00005002 * xmlNodeGetContent:
5003 * @cur: the node being read
5004 *
5005 * Read the value of a node, this can be either the text carried
5006 * directly by this node if it's a TEXT node or the aggregate string
5007 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00005008 * Entity references are substituted.
5009 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005010 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005011 */
5012xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00005013xmlNodeGetContent(xmlNodePtr cur)
5014{
5015 if (cur == NULL)
5016 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005017 switch (cur->type) {
5018 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005019 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00005020 xmlBufferPtr buffer;
5021 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00005022
Daniel Veillard814a76d2003-01-23 18:24:20 +00005023 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00005024 if (buffer == NULL)
5025 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00005026 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005027 ret = buffer->content;
5028 buffer->content = NULL;
5029 xmlBufferFree(buffer);
5030 return (ret);
5031 }
5032 case XML_ATTRIBUTE_NODE:{
5033 xmlAttrPtr attr = (xmlAttrPtr) cur;
5034
5035 if (attr->parent != NULL)
5036 return (xmlNodeListGetString
5037 (attr->parent->doc, attr->children, 1));
5038 else
5039 return (xmlNodeListGetString(NULL, attr->children, 1));
5040 break;
5041 }
Owen Taylor3473f882001-02-23 17:55:21 +00005042 case XML_COMMENT_NODE:
5043 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005044 if (cur->content != NULL)
5045 return (xmlStrdup(cur->content));
5046 return (NULL);
5047 case XML_ENTITY_REF_NODE:{
5048 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00005049 xmlBufferPtr buffer;
5050 xmlChar *ret;
5051
5052 /* lookup entity declaration */
5053 ent = xmlGetDocEntity(cur->doc, cur->name);
5054 if (ent == NULL)
5055 return (NULL);
5056
5057 buffer = xmlBufferCreate();
5058 if (buffer == NULL)
5059 return (NULL);
5060
Daniel Veillardc4696922003-10-19 21:47:14 +00005061 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005062
5063 ret = buffer->content;
5064 buffer->content = NULL;
5065 xmlBufferFree(buffer);
5066 return (ret);
5067 }
Owen Taylor3473f882001-02-23 17:55:21 +00005068 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005069 case XML_DOCUMENT_TYPE_NODE:
5070 case XML_NOTATION_NODE:
5071 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005072 case XML_XINCLUDE_START:
5073 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00005074 return (NULL);
5075 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005076#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005077 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005078#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005079 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00005080 xmlBufferPtr buffer;
5081 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005082
Daniel Veillardc4696922003-10-19 21:47:14 +00005083 buffer = xmlBufferCreate();
5084 if (buffer == NULL)
5085 return (NULL);
5086
5087 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5088
5089 ret = buffer->content;
5090 buffer->content = NULL;
5091 xmlBufferFree(buffer);
5092 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005093 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005094 case XML_NAMESPACE_DECL: {
5095 xmlChar *tmp;
5096
5097 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5098 return (tmp);
5099 }
Owen Taylor3473f882001-02-23 17:55:21 +00005100 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005101 /* TODO !!! */
5102 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005103 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005104 /* TODO !!! */
5105 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005106 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005107 /* TODO !!! */
5108 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005109 case XML_CDATA_SECTION_NODE:
5110 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005111 if (cur->content != NULL)
5112 return (xmlStrdup(cur->content));
5113 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005114 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005115 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005116}
Daniel Veillard652327a2003-09-29 18:02:38 +00005117
Owen Taylor3473f882001-02-23 17:55:21 +00005118/**
5119 * xmlNodeSetContent:
5120 * @cur: the node being modified
5121 * @content: the new value of the content
5122 *
5123 * Replace the content of a node.
5124 */
5125void
5126xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5127 if (cur == NULL) {
5128#ifdef DEBUG_TREE
5129 xmlGenericError(xmlGenericErrorContext,
5130 "xmlNodeSetContent : node == NULL\n");
5131#endif
5132 return;
5133 }
5134 switch (cur->type) {
5135 case XML_DOCUMENT_FRAG_NODE:
5136 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005137 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005138 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5139 cur->children = xmlStringGetNodeList(cur->doc, content);
5140 UPDATE_LAST_CHILD_AND_PARENT(cur)
5141 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005142 case XML_TEXT_NODE:
5143 case XML_CDATA_SECTION_NODE:
5144 case XML_ENTITY_REF_NODE:
5145 case XML_ENTITY_NODE:
5146 case XML_PI_NODE:
5147 case XML_COMMENT_NODE:
5148 if (cur->content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005149 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
Daniel Veillard370ba3d2004-10-25 16:23:56 +00005150 (!xmlDictOwns(cur->doc->dict, cur->content))))
William M. Brack7762bb12004-01-04 14:49:01 +00005151 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005152 }
5153 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5154 cur->last = cur->children = NULL;
5155 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005156 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005157 } else
5158 cur->content = NULL;
5159 break;
5160 case XML_DOCUMENT_NODE:
5161 case XML_HTML_DOCUMENT_NODE:
5162 case XML_DOCUMENT_TYPE_NODE:
5163 case XML_XINCLUDE_START:
5164 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005165#ifdef LIBXML_DOCB_ENABLED
5166 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005167#endif
5168 break;
5169 case XML_NOTATION_NODE:
5170 break;
5171 case XML_DTD_NODE:
5172 break;
5173 case XML_NAMESPACE_DECL:
5174 break;
5175 case XML_ELEMENT_DECL:
5176 /* TODO !!! */
5177 break;
5178 case XML_ATTRIBUTE_DECL:
5179 /* TODO !!! */
5180 break;
5181 case XML_ENTITY_DECL:
5182 /* TODO !!! */
5183 break;
5184 }
5185}
5186
Daniel Veillard652327a2003-09-29 18:02:38 +00005187#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005188/**
5189 * xmlNodeSetContentLen:
5190 * @cur: the node being modified
5191 * @content: the new value of the content
5192 * @len: the size of @content
5193 *
5194 * Replace the content of a node.
5195 */
5196void
5197xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5198 if (cur == NULL) {
5199#ifdef DEBUG_TREE
5200 xmlGenericError(xmlGenericErrorContext,
5201 "xmlNodeSetContentLen : node == NULL\n");
5202#endif
5203 return;
5204 }
5205 switch (cur->type) {
5206 case XML_DOCUMENT_FRAG_NODE:
5207 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005208 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005209 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5210 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5211 UPDATE_LAST_CHILD_AND_PARENT(cur)
5212 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005213 case XML_TEXT_NODE:
5214 case XML_CDATA_SECTION_NODE:
5215 case XML_ENTITY_REF_NODE:
5216 case XML_ENTITY_NODE:
5217 case XML_PI_NODE:
5218 case XML_COMMENT_NODE:
5219 case XML_NOTATION_NODE:
5220 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005221 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005222 }
5223 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5224 cur->children = cur->last = NULL;
5225 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005226 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005227 } else
5228 cur->content = NULL;
5229 break;
5230 case XML_DOCUMENT_NODE:
5231 case XML_DTD_NODE:
5232 case XML_HTML_DOCUMENT_NODE:
5233 case XML_DOCUMENT_TYPE_NODE:
5234 case XML_NAMESPACE_DECL:
5235 case XML_XINCLUDE_START:
5236 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005237#ifdef LIBXML_DOCB_ENABLED
5238 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005239#endif
5240 break;
5241 case XML_ELEMENT_DECL:
5242 /* TODO !!! */
5243 break;
5244 case XML_ATTRIBUTE_DECL:
5245 /* TODO !!! */
5246 break;
5247 case XML_ENTITY_DECL:
5248 /* TODO !!! */
5249 break;
5250 }
5251}
Daniel Veillard652327a2003-09-29 18:02:38 +00005252#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005253
5254/**
5255 * xmlNodeAddContentLen:
5256 * @cur: the node being modified
5257 * @content: extra content
5258 * @len: the size of @content
5259 *
5260 * Append the extra substring to the node content.
5261 */
5262void
5263xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5264 if (cur == NULL) {
5265#ifdef DEBUG_TREE
5266 xmlGenericError(xmlGenericErrorContext,
5267 "xmlNodeAddContentLen : node == NULL\n");
5268#endif
5269 return;
5270 }
5271 if (len <= 0) return;
5272 switch (cur->type) {
5273 case XML_DOCUMENT_FRAG_NODE:
5274 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005275 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005276
Daniel Veillard7db37732001-07-12 01:20:08 +00005277 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005278 newNode = xmlNewTextLen(content, len);
5279 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005280 tmp = xmlAddChild(cur, newNode);
5281 if (tmp != newNode)
5282 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005283 if ((last != NULL) && (last->next == newNode)) {
5284 xmlTextMerge(last, newNode);
5285 }
5286 }
5287 break;
5288 }
5289 case XML_ATTRIBUTE_NODE:
5290 break;
5291 case XML_TEXT_NODE:
5292 case XML_CDATA_SECTION_NODE:
5293 case XML_ENTITY_REF_NODE:
5294 case XML_ENTITY_NODE:
5295 case XML_PI_NODE:
5296 case XML_COMMENT_NODE:
5297 case XML_NOTATION_NODE:
5298 if (content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005299 if ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5300 xmlDictOwns(cur->doc->dict, cur->content)) {
5301 cur->content =
5302 xmlStrncatNew(cur->content, content, len);
5303 break;
5304 }
Owen Taylor3473f882001-02-23 17:55:21 +00005305 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005306 }
5307 case XML_DOCUMENT_NODE:
5308 case XML_DTD_NODE:
5309 case XML_HTML_DOCUMENT_NODE:
5310 case XML_DOCUMENT_TYPE_NODE:
5311 case XML_NAMESPACE_DECL:
5312 case XML_XINCLUDE_START:
5313 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005314#ifdef LIBXML_DOCB_ENABLED
5315 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005316#endif
5317 break;
5318 case XML_ELEMENT_DECL:
5319 case XML_ATTRIBUTE_DECL:
5320 case XML_ENTITY_DECL:
5321 break;
5322 }
5323}
5324
5325/**
5326 * xmlNodeAddContent:
5327 * @cur: the node being modified
5328 * @content: extra content
5329 *
5330 * Append the extra substring to the node content.
5331 */
5332void
5333xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5334 int len;
5335
5336 if (cur == NULL) {
5337#ifdef DEBUG_TREE
5338 xmlGenericError(xmlGenericErrorContext,
5339 "xmlNodeAddContent : node == NULL\n");
5340#endif
5341 return;
5342 }
5343 if (content == NULL) return;
5344 len = xmlStrlen(content);
5345 xmlNodeAddContentLen(cur, content, len);
5346}
5347
5348/**
5349 * xmlTextMerge:
5350 * @first: the first text node
5351 * @second: the second text node being merged
5352 *
5353 * Merge two text nodes into one
5354 * Returns the first text node augmented
5355 */
5356xmlNodePtr
5357xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5358 if (first == NULL) return(second);
5359 if (second == NULL) return(first);
5360 if (first->type != XML_TEXT_NODE) return(first);
5361 if (second->type != XML_TEXT_NODE) return(first);
5362 if (second->name != first->name)
5363 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005364 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005365 xmlUnlinkNode(second);
5366 xmlFreeNode(second);
5367 return(first);
5368}
5369
Daniel Veillard2156d432004-03-04 15:59:36 +00005370#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005371/**
5372 * xmlGetNsList:
5373 * @doc: the document
5374 * @node: the current node
5375 *
5376 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005377 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005378 * that need to be freed by the caller or NULL if no
5379 * namespace if defined
5380 */
5381xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005382xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5383{
Owen Taylor3473f882001-02-23 17:55:21 +00005384 xmlNsPtr cur;
5385 xmlNsPtr *ret = NULL;
5386 int nbns = 0;
5387 int maxns = 10;
5388 int i;
5389
5390 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005391 if (node->type == XML_ELEMENT_NODE) {
5392 cur = node->nsDef;
5393 while (cur != NULL) {
5394 if (ret == NULL) {
5395 ret =
5396 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5397 sizeof(xmlNsPtr));
5398 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005399 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005400 return (NULL);
5401 }
5402 ret[nbns] = NULL;
5403 }
5404 for (i = 0; i < nbns; i++) {
5405 if ((cur->prefix == ret[i]->prefix) ||
5406 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5407 break;
5408 }
5409 if (i >= nbns) {
5410 if (nbns >= maxns) {
5411 maxns *= 2;
5412 ret = (xmlNsPtr *) xmlRealloc(ret,
5413 (maxns +
5414 1) *
5415 sizeof(xmlNsPtr));
5416 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005417 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005418 return (NULL);
5419 }
5420 }
5421 ret[nbns++] = cur;
5422 ret[nbns] = NULL;
5423 }
Owen Taylor3473f882001-02-23 17:55:21 +00005424
Daniel Veillard77044732001-06-29 21:31:07 +00005425 cur = cur->next;
5426 }
5427 }
5428 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005429 }
Daniel Veillard77044732001-06-29 21:31:07 +00005430 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005431}
Daniel Veillard652327a2003-09-29 18:02:38 +00005432#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005433
5434/**
5435 * xmlSearchNs:
5436 * @doc: the document
5437 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005438 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005439 *
5440 * Search a Ns registered under a given name space for a document.
5441 * recurse on the parents until it finds the defined namespace
5442 * or return NULL otherwise.
5443 * @nameSpace can be NULL, this is a search for the default namespace.
5444 * We don't allow to cross entities boundaries. If you don't declare
5445 * the namespace within those you will be in troubles !!! A warning
5446 * is generated to cover this case.
5447 *
5448 * Returns the namespace pointer or NULL.
5449 */
5450xmlNsPtr
5451xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005452
Owen Taylor3473f882001-02-23 17:55:21 +00005453 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005454 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005455
5456 if (node == NULL) return(NULL);
5457 if ((nameSpace != NULL) &&
5458 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005459 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5460 /*
5461 * The XML-1.0 namespace is normally held on the root
5462 * element. In this case exceptionally create it on the
5463 * node element.
5464 */
5465 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5466 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005467 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005468 return(NULL);
5469 }
5470 memset(cur, 0, sizeof(xmlNs));
5471 cur->type = XML_LOCAL_NAMESPACE;
5472 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5473 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5474 cur->next = node->nsDef;
5475 node->nsDef = cur;
5476 return(cur);
5477 }
Owen Taylor3473f882001-02-23 17:55:21 +00005478 if (doc->oldNs == NULL) {
5479 /*
5480 * Allocate a new Namespace and fill the fields.
5481 */
5482 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5483 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005484 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005485 return(NULL);
5486 }
5487 memset(doc->oldNs, 0, sizeof(xmlNs));
5488 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5489
5490 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5491 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5492 }
5493 return(doc->oldNs);
5494 }
5495 while (node != NULL) {
5496 if ((node->type == XML_ENTITY_REF_NODE) ||
5497 (node->type == XML_ENTITY_NODE) ||
5498 (node->type == XML_ENTITY_DECL))
5499 return(NULL);
5500 if (node->type == XML_ELEMENT_NODE) {
5501 cur = node->nsDef;
5502 while (cur != NULL) {
5503 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5504 (cur->href != NULL))
5505 return(cur);
5506 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5507 (cur->href != NULL) &&
5508 (xmlStrEqual(cur->prefix, nameSpace)))
5509 return(cur);
5510 cur = cur->next;
5511 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005512 if (orig != node) {
5513 cur = node->ns;
5514 if (cur != NULL) {
5515 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5516 (cur->href != NULL))
5517 return(cur);
5518 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5519 (cur->href != NULL) &&
5520 (xmlStrEqual(cur->prefix, nameSpace)))
5521 return(cur);
5522 }
5523 }
Owen Taylor3473f882001-02-23 17:55:21 +00005524 }
5525 node = node->parent;
5526 }
5527 return(NULL);
5528}
5529
5530/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005531 * xmlNsInScope:
5532 * @doc: the document
5533 * @node: the current node
5534 * @ancestor: the ancestor carrying the namespace
5535 * @prefix: the namespace prefix
5536 *
5537 * Verify that the given namespace held on @ancestor is still in scope
5538 * on node.
5539 *
5540 * Returns 1 if true, 0 if false and -1 in case of error.
5541 */
5542static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005543xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5544 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005545{
5546 xmlNsPtr tst;
5547
5548 while ((node != NULL) && (node != ancestor)) {
5549 if ((node->type == XML_ENTITY_REF_NODE) ||
5550 (node->type == XML_ENTITY_NODE) ||
5551 (node->type == XML_ENTITY_DECL))
5552 return (-1);
5553 if (node->type == XML_ELEMENT_NODE) {
5554 tst = node->nsDef;
5555 while (tst != NULL) {
5556 if ((tst->prefix == NULL)
5557 && (prefix == NULL))
5558 return (0);
5559 if ((tst->prefix != NULL)
5560 && (prefix != NULL)
5561 && (xmlStrEqual(tst->prefix, prefix)))
5562 return (0);
5563 tst = tst->next;
5564 }
5565 }
5566 node = node->parent;
5567 }
5568 if (node != ancestor)
5569 return (-1);
5570 return (1);
5571}
5572
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005573/**
Owen Taylor3473f882001-02-23 17:55:21 +00005574 * xmlSearchNsByHref:
5575 * @doc: the document
5576 * @node: the current node
5577 * @href: the namespace value
5578 *
5579 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5580 * the defined namespace or return NULL otherwise.
5581 * Returns the namespace pointer or NULL.
5582 */
5583xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005584xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5585{
Owen Taylor3473f882001-02-23 17:55:21 +00005586 xmlNsPtr cur;
5587 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005588 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005589
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005590 if ((node == NULL) || (href == NULL))
5591 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005592 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005593 /*
5594 * Only the document can hold the XML spec namespace.
5595 */
5596 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5597 /*
5598 * The XML-1.0 namespace is normally held on the root
5599 * element. In this case exceptionally create it on the
5600 * node element.
5601 */
5602 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5603 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005604 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005605 return (NULL);
5606 }
5607 memset(cur, 0, sizeof(xmlNs));
5608 cur->type = XML_LOCAL_NAMESPACE;
5609 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5610 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5611 cur->next = node->nsDef;
5612 node->nsDef = cur;
5613 return (cur);
5614 }
5615 if (doc->oldNs == NULL) {
5616 /*
5617 * Allocate a new Namespace and fill the fields.
5618 */
5619 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5620 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005621 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005622 return (NULL);
5623 }
5624 memset(doc->oldNs, 0, sizeof(xmlNs));
5625 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005626
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005627 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5628 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5629 }
5630 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005631 }
Daniel Veillard62040be2004-05-17 03:17:26 +00005632 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00005633 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005634 if ((node->type == XML_ENTITY_REF_NODE) ||
5635 (node->type == XML_ENTITY_NODE) ||
5636 (node->type == XML_ENTITY_DECL))
5637 return (NULL);
5638 if (node->type == XML_ELEMENT_NODE) {
5639 cur = node->nsDef;
5640 while (cur != NULL) {
5641 if ((cur->href != NULL) && (href != NULL) &&
5642 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005643 if (((!is_attr) || (cur->prefix != NULL)) &&
5644 (xmlNsInScope(doc, orig, node, cur->href) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005645 return (cur);
5646 }
5647 cur = cur->next;
5648 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005649 if (orig != node) {
5650 cur = node->ns;
5651 if (cur != NULL) {
5652 if ((cur->href != NULL) && (href != NULL) &&
5653 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005654 if (((!is_attr) || (cur->prefix != NULL)) &&
5655 (xmlNsInScope(doc, orig, node, cur->href) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00005656 return (cur);
5657 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005658 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005659 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005660 }
5661 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005662 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005663 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005664}
5665
5666/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005667 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005668 * @doc: the document
5669 * @tree: a node expected to hold the new namespace
5670 * @ns: the original namespace
5671 *
5672 * This function tries to locate a namespace definition in a tree
5673 * ancestors, or create a new namespace definition node similar to
5674 * @ns trying to reuse the same prefix. However if the given prefix is
5675 * null (default namespace) or reused within the subtree defined by
5676 * @tree or on one of its ancestors then a new prefix is generated.
5677 * Returns the (new) namespace definition or NULL in case of error
5678 */
5679xmlNsPtr
5680xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5681 xmlNsPtr def;
5682 xmlChar prefix[50];
5683 int counter = 1;
5684
5685 if (tree == NULL) {
5686#ifdef DEBUG_TREE
5687 xmlGenericError(xmlGenericErrorContext,
5688 "xmlNewReconciliedNs : tree == NULL\n");
5689#endif
5690 return(NULL);
5691 }
5692 if (ns == NULL) {
5693#ifdef DEBUG_TREE
5694 xmlGenericError(xmlGenericErrorContext,
5695 "xmlNewReconciliedNs : ns == NULL\n");
5696#endif
5697 return(NULL);
5698 }
5699 /*
5700 * Search an existing namespace definition inherited.
5701 */
5702 def = xmlSearchNsByHref(doc, tree, ns->href);
5703 if (def != NULL)
5704 return(def);
5705
5706 /*
5707 * Find a close prefix which is not already in use.
5708 * Let's strip namespace prefixes longer than 20 chars !
5709 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005710 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005711 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005712 else
William M. Brack13dfa872004-09-18 04:52:08 +00005713 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005714
Owen Taylor3473f882001-02-23 17:55:21 +00005715 def = xmlSearchNs(doc, tree, prefix);
5716 while (def != NULL) {
5717 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005718 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005719 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005720 else
William M. Brack13dfa872004-09-18 04:52:08 +00005721 snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
5722 (char *)ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005723 def = xmlSearchNs(doc, tree, prefix);
5724 }
5725
5726 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005727 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005728 */
5729 def = xmlNewNs(tree, ns->href, prefix);
5730 return(def);
5731}
5732
Daniel Veillard652327a2003-09-29 18:02:38 +00005733#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005734/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005735 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005736 * @doc: the document
5737 * @tree: a node defining the subtree to reconciliate
5738 *
5739 * This function checks that all the namespaces declared within the given
5740 * tree are properly declared. This is needed for example after Copy or Cut
5741 * and then paste operations. The subtree may still hold pointers to
5742 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005743 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005744 * the new environment. If not possible the new namespaces are redeclared
5745 * on @tree at the top of the given subtree.
5746 * Returns the number of namespace declarations created or -1 in case of error.
5747 */
5748int
5749xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5750 xmlNsPtr *oldNs = NULL;
5751 xmlNsPtr *newNs = NULL;
5752 int sizeCache = 0;
5753 int nbCache = 0;
5754
5755 xmlNsPtr n;
5756 xmlNodePtr node = tree;
5757 xmlAttrPtr attr;
5758 int ret = 0, i;
5759
5760 while (node != NULL) {
5761 /*
5762 * Reconciliate the node namespace
5763 */
5764 if (node->ns != NULL) {
5765 /*
5766 * initialize the cache if needed
5767 */
5768 if (sizeCache == 0) {
5769 sizeCache = 10;
5770 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5771 sizeof(xmlNsPtr));
5772 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005773 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005774 return(-1);
5775 }
5776 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5777 sizeof(xmlNsPtr));
5778 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005779 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005780 xmlFree(oldNs);
5781 return(-1);
5782 }
5783 }
5784 for (i = 0;i < nbCache;i++) {
5785 if (oldNs[i] == node->ns) {
5786 node->ns = newNs[i];
5787 break;
5788 }
5789 }
5790 if (i == nbCache) {
5791 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005792 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005793 */
5794 n = xmlNewReconciliedNs(doc, tree, node->ns);
5795 if (n != NULL) { /* :-( what if else ??? */
5796 /*
5797 * check if we need to grow the cache buffers.
5798 */
5799 if (sizeCache <= nbCache) {
5800 sizeCache *= 2;
5801 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5802 sizeof(xmlNsPtr));
5803 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005804 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005805 xmlFree(newNs);
5806 return(-1);
5807 }
5808 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5809 sizeof(xmlNsPtr));
5810 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005811 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005812 xmlFree(oldNs);
5813 return(-1);
5814 }
5815 }
5816 newNs[nbCache] = n;
5817 oldNs[nbCache++] = node->ns;
5818 node->ns = n;
5819 }
5820 }
5821 }
5822 /*
5823 * now check for namespace hold by attributes on the node.
5824 */
5825 attr = node->properties;
5826 while (attr != NULL) {
5827 if (attr->ns != NULL) {
5828 /*
5829 * initialize the cache if needed
5830 */
5831 if (sizeCache == 0) {
5832 sizeCache = 10;
5833 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5834 sizeof(xmlNsPtr));
5835 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005836 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005837 return(-1);
5838 }
5839 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5840 sizeof(xmlNsPtr));
5841 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005842 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005843 xmlFree(oldNs);
5844 return(-1);
5845 }
5846 }
5847 for (i = 0;i < nbCache;i++) {
5848 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005849 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005850 break;
5851 }
5852 }
5853 if (i == nbCache) {
5854 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005855 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005856 */
5857 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5858 if (n != NULL) { /* :-( what if else ??? */
5859 /*
5860 * check if we need to grow the cache buffers.
5861 */
5862 if (sizeCache <= nbCache) {
5863 sizeCache *= 2;
5864 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5865 sizeof(xmlNsPtr));
5866 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005867 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005868 xmlFree(newNs);
5869 return(-1);
5870 }
5871 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5872 sizeof(xmlNsPtr));
5873 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005874 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005875 xmlFree(oldNs);
5876 return(-1);
5877 }
5878 }
5879 newNs[nbCache] = n;
5880 oldNs[nbCache++] = attr->ns;
5881 attr->ns = n;
5882 }
5883 }
5884 }
5885 attr = attr->next;
5886 }
5887
5888 /*
5889 * Browse the full subtree, deep first
5890 */
Daniel Veillardac996a12004-07-30 12:02:58 +00005891 if (node->children != NULL && node->type != XML_ENTITY_REF_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00005892 /* deep first */
5893 node = node->children;
5894 } else if ((node != tree) && (node->next != NULL)) {
5895 /* then siblings */
5896 node = node->next;
5897 } else if (node != tree) {
5898 /* go up to parents->next if needed */
5899 while (node != tree) {
5900 if (node->parent != NULL)
5901 node = node->parent;
5902 if ((node != tree) && (node->next != NULL)) {
5903 node = node->next;
5904 break;
5905 }
5906 if (node->parent == NULL) {
5907 node = NULL;
5908 break;
5909 }
5910 }
5911 /* exit condition */
5912 if (node == tree)
5913 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005914 } else
5915 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005916 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005917 if (oldNs != NULL)
5918 xmlFree(oldNs);
5919 if (newNs != NULL)
5920 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005921 return(ret);
5922}
Daniel Veillard652327a2003-09-29 18:02:38 +00005923#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005924
5925/**
5926 * xmlHasProp:
5927 * @node: the node
5928 * @name: the attribute name
5929 *
5930 * Search an attribute associated to a node
5931 * This function also looks in DTD attribute declaration for #FIXED or
5932 * default declaration values unless DTD use has been turned off.
5933 *
5934 * Returns the attribute or the attribute declaration or NULL if
5935 * neither was found.
5936 */
5937xmlAttrPtr
5938xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5939 xmlAttrPtr prop;
5940 xmlDocPtr doc;
5941
5942 if ((node == NULL) || (name == NULL)) return(NULL);
5943 /*
5944 * Check on the properties attached to the node
5945 */
5946 prop = node->properties;
5947 while (prop != NULL) {
5948 if (xmlStrEqual(prop->name, name)) {
5949 return(prop);
5950 }
5951 prop = prop->next;
5952 }
5953 if (!xmlCheckDTD) return(NULL);
5954
5955 /*
5956 * Check if there is a default declaration in the internal
5957 * or external subsets
5958 */
5959 doc = node->doc;
5960 if (doc != NULL) {
5961 xmlAttributePtr attrDecl;
5962 if (doc->intSubset != NULL) {
5963 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5964 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5965 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005966 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5967 /* return attribute declaration only if a default value is given
5968 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005969 return((xmlAttrPtr) attrDecl);
5970 }
5971 }
5972 return(NULL);
5973}
5974
5975/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005976 * xmlHasNsProp:
5977 * @node: the node
5978 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005979 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005980 *
5981 * Search for an attribute associated to a node
5982 * This attribute has to be anchored in the namespace specified.
5983 * This does the entity substitution.
5984 * This function looks in DTD attribute declaration for #FIXED or
5985 * default declaration values unless DTD use has been turned off.
William M. Brack2c228442004-10-03 04:10:00 +00005986 * Note that a namespace of NULL indicates to use the default namespace.
Daniel Veillarde95e2392001-06-06 10:46:28 +00005987 *
5988 * Returns the attribute or the attribute declaration or NULL
5989 * if neither was found.
5990 */
5991xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005992xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005993 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00005994#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005995 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00005996#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005997
5998 if (node == NULL)
5999 return(NULL);
6000
6001 prop = node->properties;
Daniel Veillarde95e2392001-06-06 10:46:28 +00006002 while (prop != NULL) {
6003 /*
6004 * One need to have
6005 * - same attribute names
6006 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00006007 */
William M. Brack2c228442004-10-03 04:10:00 +00006008 if (xmlStrEqual(prop->name, name)) {
6009 if (((prop->ns != NULL) &&
6010 (xmlStrEqual(prop->ns->href, nameSpace))) ||
6011 ((prop->ns == NULL) && (nameSpace == NULL))) {
6012 return(prop);
6013 }
Daniel Veillarde95e2392001-06-06 10:46:28 +00006014 }
6015 prop = prop->next;
6016 }
6017 if (!xmlCheckDTD) return(NULL);
6018
Daniel Veillard652327a2003-09-29 18:02:38 +00006019#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00006020 /*
6021 * Check if there is a default declaration in the internal
6022 * or external subsets
6023 */
6024 doc = node->doc;
6025 if (doc != NULL) {
6026 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006027 xmlAttributePtr attrDecl = NULL;
6028 xmlNsPtr *nsList, *cur;
6029 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00006030
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006031 nsList = xmlGetNsList(node->doc, node);
6032 if (nsList == NULL)
6033 return(NULL);
6034 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
6035 ename = xmlStrdup(node->ns->prefix);
6036 ename = xmlStrcat(ename, BAD_CAST ":");
6037 ename = xmlStrcat(ename, node->name);
6038 } else {
6039 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006040 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006041 if (ename == NULL) {
6042 xmlFree(nsList);
6043 return(NULL);
6044 }
6045
William M. Brack2c228442004-10-03 04:10:00 +00006046 if (nameSpace == NULL) {
6047 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
6048 name, NULL);
6049 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
6050 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6051 name, NULL);
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006052 }
William M. Brack2c228442004-10-03 04:10:00 +00006053 } else {
6054 cur = nsList;
6055 while (*cur != NULL) {
6056 if (xmlStrEqual((*cur)->href, nameSpace)) {
6057 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
6058 name, (*cur)->prefix);
6059 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6060 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6061 name, (*cur)->prefix);
6062 }
6063 cur++;
6064 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006065 }
6066 xmlFree(nsList);
6067 xmlFree(ename);
6068 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006069 }
6070 }
Daniel Veillard652327a2003-09-29 18:02:38 +00006071#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00006072 return(NULL);
6073}
6074
6075/**
Owen Taylor3473f882001-02-23 17:55:21 +00006076 * xmlGetProp:
6077 * @node: the node
6078 * @name: the attribute name
6079 *
6080 * Search and get the value of an attribute associated to a node
6081 * This does the entity substitution.
6082 * This function looks in DTD attribute declaration for #FIXED or
6083 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00006084 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00006085 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6086 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00006087 *
6088 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006089 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006090 */
6091xmlChar *
6092xmlGetProp(xmlNodePtr node, const xmlChar *name) {
6093 xmlAttrPtr prop;
6094 xmlDocPtr doc;
6095
6096 if ((node == NULL) || (name == NULL)) return(NULL);
6097 /*
6098 * Check on the properties attached to the node
6099 */
6100 prop = node->properties;
6101 while (prop != NULL) {
6102 if (xmlStrEqual(prop->name, name)) {
6103 xmlChar *ret;
6104
6105 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6106 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6107 return(ret);
6108 }
6109 prop = prop->next;
6110 }
6111 if (!xmlCheckDTD) return(NULL);
6112
6113 /*
6114 * Check if there is a default declaration in the internal
6115 * or external subsets
6116 */
6117 doc = node->doc;
6118 if (doc != NULL) {
6119 xmlAttributePtr attrDecl;
6120 if (doc->intSubset != NULL) {
6121 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6122 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6123 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006124 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6125 /* return attribute declaration only if a default value is given
6126 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006127 return(xmlStrdup(attrDecl->defaultValue));
6128 }
6129 }
6130 return(NULL);
6131}
6132
6133/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006134 * xmlGetNoNsProp:
6135 * @node: the node
6136 * @name: the attribute name
6137 *
6138 * Search and get the value of an attribute associated to a node
6139 * This does the entity substitution.
6140 * This function looks in DTD attribute declaration for #FIXED or
6141 * default declaration values unless DTD use has been turned off.
6142 * This function is similar to xmlGetProp except it will accept only
6143 * an attribute in no namespace.
6144 *
6145 * Returns the attribute value or NULL if not found.
6146 * It's up to the caller to free the memory with xmlFree().
6147 */
6148xmlChar *
6149xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6150 xmlAttrPtr prop;
6151 xmlDocPtr doc;
6152
6153 if ((node == NULL) || (name == NULL)) return(NULL);
6154 /*
6155 * Check on the properties attached to the node
6156 */
6157 prop = node->properties;
6158 while (prop != NULL) {
6159 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6160 xmlChar *ret;
6161
6162 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6163 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6164 return(ret);
6165 }
6166 prop = prop->next;
6167 }
6168 if (!xmlCheckDTD) return(NULL);
6169
6170 /*
6171 * Check if there is a default declaration in the internal
6172 * or external subsets
6173 */
6174 doc = node->doc;
6175 if (doc != NULL) {
6176 xmlAttributePtr attrDecl;
6177 if (doc->intSubset != NULL) {
6178 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6179 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6180 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006181 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6182 /* return attribute declaration only if a default value is given
6183 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006184 return(xmlStrdup(attrDecl->defaultValue));
6185 }
6186 }
6187 return(NULL);
6188}
6189
6190/**
Owen Taylor3473f882001-02-23 17:55:21 +00006191 * xmlGetNsProp:
6192 * @node: the node
6193 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006194 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006195 *
6196 * Search and get the value of an attribute associated to a node
6197 * This attribute has to be anchored in the namespace specified.
6198 * This does the entity substitution.
6199 * This function looks in DTD attribute declaration for #FIXED or
6200 * default declaration values unless DTD use has been turned off.
6201 *
6202 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006203 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006204 */
6205xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006206xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006207 xmlAttrPtr prop;
6208 xmlDocPtr doc;
6209 xmlNsPtr ns;
6210
6211 if (node == NULL)
6212 return(NULL);
6213
6214 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006215 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006216 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006217 while (prop != NULL) {
6218 /*
6219 * One need to have
6220 * - same attribute names
6221 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006222 */
6223 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006224 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006225 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006226 xmlChar *ret;
6227
6228 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6229 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6230 return(ret);
6231 }
6232 prop = prop->next;
6233 }
6234 if (!xmlCheckDTD) return(NULL);
6235
6236 /*
6237 * Check if there is a default declaration in the internal
6238 * or external subsets
6239 */
6240 doc = node->doc;
6241 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006242 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006243 xmlAttributePtr attrDecl;
6244
Owen Taylor3473f882001-02-23 17:55:21 +00006245 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6246 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6247 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6248
6249 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6250 /*
6251 * The DTD declaration only allows a prefix search
6252 */
6253 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006254 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006255 return(xmlStrdup(attrDecl->defaultValue));
6256 }
6257 }
6258 }
6259 return(NULL);
6260}
6261
Daniel Veillard2156d432004-03-04 15:59:36 +00006262#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6263/**
6264 * xmlUnsetProp:
6265 * @node: the node
6266 * @name: the attribute name
6267 *
6268 * Remove an attribute carried by a node.
6269 * Returns 0 if successful, -1 if not found
6270 */
6271int
6272xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
6273 xmlAttrPtr prop, prev = NULL;;
6274
6275 if ((node == NULL) || (name == NULL))
6276 return(-1);
6277 prop = node->properties;
6278 while (prop != NULL) {
6279 if ((xmlStrEqual(prop->name, name)) &&
6280 (prop->ns == NULL)) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006281 if (prev == NULL) {
Daniel Veillard2156d432004-03-04 15:59:36 +00006282 node->properties = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006283 if (prop->next != NULL)
6284 prop->next->prev = NULL;
6285 } else {
Daniel Veillard2156d432004-03-04 15:59:36 +00006286 prev->next = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006287 if (prop->next != NULL)
6288 prop->next->prev = NULL;
6289 }
6290 prop->next = NULL;
6291 prop->prev = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00006292 xmlFreeProp(prop);
6293 return(0);
6294 }
6295 prev = prop;
6296 prop = prop->next;
6297 }
6298 return(-1);
6299}
6300
6301/**
6302 * xmlUnsetNsProp:
6303 * @node: the node
6304 * @ns: the namespace definition
6305 * @name: the attribute name
6306 *
6307 * Remove an attribute carried by a node.
6308 * Returns 0 if successful, -1 if not found
6309 */
6310int
6311xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6312 xmlAttrPtr prop = node->properties, prev = NULL;;
6313
6314 if ((node == NULL) || (name == NULL))
6315 return(-1);
6316 if (ns == NULL)
6317 return(xmlUnsetProp(node, name));
6318 if (ns->href == NULL)
6319 return(-1);
6320 while (prop != NULL) {
6321 if ((xmlStrEqual(prop->name, name)) &&
6322 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006323 if (prev == NULL) {
Daniel Veillard2156d432004-03-04 15:59:36 +00006324 node->properties = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006325 if (prop->next != NULL)
6326 prop->next->prev = NULL;
6327 } else {
Daniel Veillard2156d432004-03-04 15:59:36 +00006328 prev->next = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006329 if (prop->next != NULL)
6330 prop->next->prev = NULL;
6331 }
6332 prop->next = NULL;
6333 prop->prev = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00006334 xmlFreeProp(prop);
6335 return(0);
6336 }
6337 prev = prop;
6338 prop = prop->next;
6339 }
6340 return(-1);
6341}
6342#endif
6343
6344#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006345/**
6346 * xmlSetProp:
6347 * @node: the node
6348 * @name: the attribute name
6349 * @value: the attribute value
6350 *
6351 * Set (or reset) an attribute carried by a node.
6352 * Returns the attribute pointer.
6353 */
6354xmlAttrPtr
6355xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006356 xmlAttrPtr prop;
6357 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006358
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006359 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006360 return(NULL);
6361 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006362 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006363 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006364 if ((xmlStrEqual(prop->name, name)) &&
6365 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006366 xmlNodePtr oldprop = prop->children;
6367
Owen Taylor3473f882001-02-23 17:55:21 +00006368 prop->children = NULL;
6369 prop->last = NULL;
6370 if (value != NULL) {
6371 xmlChar *buffer;
6372 xmlNodePtr tmp;
6373
6374 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6375 prop->children = xmlStringGetNodeList(node->doc, buffer);
6376 prop->last = NULL;
6377 prop->doc = doc;
6378 tmp = prop->children;
6379 while (tmp != NULL) {
6380 tmp->parent = (xmlNodePtr) prop;
6381 tmp->doc = doc;
6382 if (tmp->next == NULL)
6383 prop->last = tmp;
6384 tmp = tmp->next;
6385 }
6386 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006387 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006388 if (oldprop != NULL)
6389 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006390 return(prop);
6391 }
6392 prop = prop->next;
6393 }
6394 prop = xmlNewProp(node, name, value);
6395 return(prop);
6396}
6397
6398/**
6399 * xmlSetNsProp:
6400 * @node: the node
6401 * @ns: the namespace definition
6402 * @name: the attribute name
6403 * @value: the attribute value
6404 *
6405 * Set (or reset) an attribute carried by a node.
6406 * The ns structure must be in scope, this is not checked.
6407 *
6408 * Returns the attribute pointer.
6409 */
6410xmlAttrPtr
6411xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6412 const xmlChar *value) {
6413 xmlAttrPtr prop;
6414
6415 if ((node == NULL) || (name == NULL))
6416 return(NULL);
6417
6418 if (ns == NULL)
6419 return(xmlSetProp(node, name, value));
6420 if (ns->href == NULL)
6421 return(NULL);
6422 prop = node->properties;
6423
6424 while (prop != NULL) {
6425 /*
6426 * One need to have
6427 * - same attribute names
6428 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006429 */
6430 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006431 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006432 if (prop->children != NULL)
6433 xmlFreeNodeList(prop->children);
6434 prop->children = NULL;
6435 prop->last = NULL;
6436 prop->ns = ns;
6437 if (value != NULL) {
6438 xmlChar *buffer;
6439 xmlNodePtr tmp;
6440
6441 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6442 prop->children = xmlStringGetNodeList(node->doc, buffer);
6443 prop->last = NULL;
6444 tmp = prop->children;
6445 while (tmp != NULL) {
6446 tmp->parent = (xmlNodePtr) prop;
6447 if (tmp->next == NULL)
6448 prop->last = tmp;
6449 tmp = tmp->next;
6450 }
6451 xmlFree(buffer);
6452 }
6453 return(prop);
6454 }
6455 prop = prop->next;
6456 }
6457 prop = xmlNewNsProp(node, ns, name, value);
6458 return(prop);
6459}
6460
Daniel Veillard652327a2003-09-29 18:02:38 +00006461#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006462
6463/**
Owen Taylor3473f882001-02-23 17:55:21 +00006464 * xmlNodeIsText:
6465 * @node: the node
6466 *
6467 * Is this node a Text node ?
6468 * Returns 1 yes, 0 no
6469 */
6470int
6471xmlNodeIsText(xmlNodePtr node) {
6472 if (node == NULL) return(0);
6473
6474 if (node->type == XML_TEXT_NODE) return(1);
6475 return(0);
6476}
6477
6478/**
6479 * xmlIsBlankNode:
6480 * @node: the node
6481 *
6482 * Checks whether this node is an empty or whitespace only
6483 * (and possibly ignorable) text-node.
6484 *
6485 * Returns 1 yes, 0 no
6486 */
6487int
6488xmlIsBlankNode(xmlNodePtr node) {
6489 const xmlChar *cur;
6490 if (node == NULL) return(0);
6491
Daniel Veillard7db37732001-07-12 01:20:08 +00006492 if ((node->type != XML_TEXT_NODE) &&
6493 (node->type != XML_CDATA_SECTION_NODE))
6494 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006495 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006496 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006497 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006498 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006499 cur++;
6500 }
6501
6502 return(1);
6503}
6504
6505/**
6506 * xmlTextConcat:
6507 * @node: the node
6508 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006509 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006510 *
6511 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006512 *
6513 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006514 */
6515
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006516int
Owen Taylor3473f882001-02-23 17:55:21 +00006517xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006518 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006519
6520 if ((node->type != XML_TEXT_NODE) &&
6521 (node->type != XML_CDATA_SECTION_NODE)) {
6522#ifdef DEBUG_TREE
6523 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006524 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006525#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006526 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006527 }
William M. Brack7762bb12004-01-04 14:49:01 +00006528 /* need to check if content is currently in the dictionary */
6529 if ((node->doc != NULL) && (node->doc->dict != NULL) &&
6530 xmlDictOwns(node->doc->dict, node->content)) {
6531 node->content = xmlStrncatNew(node->content, content, len);
6532 } else {
6533 node->content = xmlStrncat(node->content, content, len);
6534 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006535 if (node->content == NULL)
6536 return(-1);
6537 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006538}
6539
6540/************************************************************************
6541 * *
6542 * Output : to a FILE or in memory *
6543 * *
6544 ************************************************************************/
6545
Owen Taylor3473f882001-02-23 17:55:21 +00006546/**
6547 * xmlBufferCreate:
6548 *
6549 * routine to create an XML buffer.
6550 * returns the new structure.
6551 */
6552xmlBufferPtr
6553xmlBufferCreate(void) {
6554 xmlBufferPtr ret;
6555
6556 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6557 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006558 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006559 return(NULL);
6560 }
6561 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006562 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006563 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006564 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006565 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006566 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006567 xmlFree(ret);
6568 return(NULL);
6569 }
6570 ret->content[0] = 0;
6571 return(ret);
6572}
6573
6574/**
6575 * xmlBufferCreateSize:
6576 * @size: initial size of buffer
6577 *
6578 * routine to create an XML buffer.
6579 * returns the new structure.
6580 */
6581xmlBufferPtr
6582xmlBufferCreateSize(size_t size) {
6583 xmlBufferPtr ret;
6584
6585 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6586 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006587 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006588 return(NULL);
6589 }
6590 ret->use = 0;
6591 ret->alloc = xmlBufferAllocScheme;
6592 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6593 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006594 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006595 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006596 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006597 xmlFree(ret);
6598 return(NULL);
6599 }
6600 ret->content[0] = 0;
6601 } else
6602 ret->content = NULL;
6603 return(ret);
6604}
6605
6606/**
Daniel Veillard53350552003-09-18 13:35:51 +00006607 * xmlBufferCreateStatic:
6608 * @mem: the memory area
6609 * @size: the size in byte
6610 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006611 * routine to create an XML buffer from an immutable memory area.
6612 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006613 * present until the end of the buffer lifetime.
6614 *
6615 * returns the new structure.
6616 */
6617xmlBufferPtr
6618xmlBufferCreateStatic(void *mem, size_t size) {
6619 xmlBufferPtr ret;
6620
6621 if ((mem == NULL) || (size == 0))
6622 return(NULL);
6623
6624 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6625 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006626 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006627 return(NULL);
6628 }
6629 ret->use = size;
6630 ret->size = size;
6631 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6632 ret->content = (xmlChar *) mem;
6633 return(ret);
6634}
6635
6636/**
Owen Taylor3473f882001-02-23 17:55:21 +00006637 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006638 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006639 * @scheme: allocation scheme to use
6640 *
6641 * Sets the allocation scheme for this buffer
6642 */
6643void
6644xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6645 xmlBufferAllocationScheme scheme) {
6646 if (buf == NULL) {
6647#ifdef DEBUG_BUFFER
6648 xmlGenericError(xmlGenericErrorContext,
6649 "xmlBufferSetAllocationScheme: buf == NULL\n");
6650#endif
6651 return;
6652 }
Daniel Veillard53350552003-09-18 13:35:51 +00006653 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006654
6655 buf->alloc = scheme;
6656}
6657
6658/**
6659 * xmlBufferFree:
6660 * @buf: the buffer to free
6661 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006662 * Frees an XML buffer. It frees both the content and the structure which
6663 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006664 */
6665void
6666xmlBufferFree(xmlBufferPtr buf) {
6667 if (buf == NULL) {
6668#ifdef DEBUG_BUFFER
6669 xmlGenericError(xmlGenericErrorContext,
6670 "xmlBufferFree: buf == NULL\n");
6671#endif
6672 return;
6673 }
Daniel Veillard53350552003-09-18 13:35:51 +00006674
6675 if ((buf->content != NULL) &&
6676 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006677 xmlFree(buf->content);
6678 }
Owen Taylor3473f882001-02-23 17:55:21 +00006679 xmlFree(buf);
6680}
6681
6682/**
6683 * xmlBufferEmpty:
6684 * @buf: the buffer
6685 *
6686 * empty a buffer.
6687 */
6688void
6689xmlBufferEmpty(xmlBufferPtr buf) {
6690 if (buf->content == NULL) return;
6691 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006692 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006693 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006694 } else {
6695 memset(buf->content, 0, buf->size);
6696 }
Owen Taylor3473f882001-02-23 17:55:21 +00006697}
6698
6699/**
6700 * xmlBufferShrink:
6701 * @buf: the buffer to dump
6702 * @len: the number of xmlChar to remove
6703 *
6704 * Remove the beginning of an XML buffer.
6705 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006706 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006707 */
6708int
6709xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6710 if (len == 0) return(0);
6711 if (len > buf->use) return(-1);
6712
6713 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006714 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6715 buf->content += len;
6716 } else {
6717 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6718 buf->content[buf->use] = 0;
6719 }
Owen Taylor3473f882001-02-23 17:55:21 +00006720 return(len);
6721}
6722
6723/**
6724 * xmlBufferGrow:
6725 * @buf: the buffer
6726 * @len: the minimum free size to allocate
6727 *
6728 * Grow the available space of an XML buffer.
6729 *
6730 * Returns the new available space or -1 in case of error
6731 */
6732int
6733xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6734 int size;
6735 xmlChar *newbuf;
6736
Daniel Veillard53350552003-09-18 13:35:51 +00006737 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006738 if (len + buf->use < buf->size) return(0);
6739
William M. Brack30fe43f2004-07-26 18:00:58 +00006740/*
6741 * Windows has a BIG problem on realloc timing, so we try to double
6742 * the buffer size (if that's enough) (bug 146697)
6743 */
6744#ifdef WIN32
6745 if (buf->size > len)
6746 size = buf->size * 2;
6747 else
6748 size = buf->use + len + 100;
6749#else
Owen Taylor3473f882001-02-23 17:55:21 +00006750 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00006751#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006752
6753 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006754 if (newbuf == NULL) {
6755 xmlTreeErrMemory("growing buffer");
6756 return(-1);
6757 }
Owen Taylor3473f882001-02-23 17:55:21 +00006758 buf->content = newbuf;
6759 buf->size = size;
6760 return(buf->size - buf->use);
6761}
6762
6763/**
6764 * xmlBufferDump:
6765 * @file: the file output
6766 * @buf: the buffer to dump
6767 *
6768 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006769 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006770 */
6771int
6772xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6773 int ret;
6774
6775 if (buf == NULL) {
6776#ifdef DEBUG_BUFFER
6777 xmlGenericError(xmlGenericErrorContext,
6778 "xmlBufferDump: buf == NULL\n");
6779#endif
6780 return(0);
6781 }
6782 if (buf->content == NULL) {
6783#ifdef DEBUG_BUFFER
6784 xmlGenericError(xmlGenericErrorContext,
6785 "xmlBufferDump: buf->content == NULL\n");
6786#endif
6787 return(0);
6788 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006789 if (file == NULL)
6790 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006791 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6792 return(ret);
6793}
6794
6795/**
6796 * xmlBufferContent:
6797 * @buf: the buffer
6798 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006799 * Function to extract the content of a buffer
6800 *
Owen Taylor3473f882001-02-23 17:55:21 +00006801 * Returns the internal content
6802 */
6803
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006804const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006805xmlBufferContent(const xmlBufferPtr buf)
6806{
6807 if(!buf)
6808 return NULL;
6809
6810 return buf->content;
6811}
6812
6813/**
6814 * xmlBufferLength:
6815 * @buf: the buffer
6816 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006817 * Function to get the length of a buffer
6818 *
Owen Taylor3473f882001-02-23 17:55:21 +00006819 * Returns the length of data in the internal content
6820 */
6821
6822int
6823xmlBufferLength(const xmlBufferPtr buf)
6824{
6825 if(!buf)
6826 return 0;
6827
6828 return buf->use;
6829}
6830
6831/**
6832 * xmlBufferResize:
6833 * @buf: the buffer to resize
6834 * @size: the desired size
6835 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006836 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006837 *
6838 * Returns 0 in case of problems, 1 otherwise
6839 */
6840int
6841xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6842{
6843 unsigned int newSize;
6844 xmlChar* rebuf = NULL;
6845
Daniel Veillard53350552003-09-18 13:35:51 +00006846 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6847
Owen Taylor3473f882001-02-23 17:55:21 +00006848 /* Don't resize if we don't have to */
6849 if (size < buf->size)
6850 return 1;
6851
6852 /* figure out new size */
6853 switch (buf->alloc){
6854 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillardbf629492004-04-20 22:20:59 +00006855 /*take care of empty case*/
6856 newSize = (buf->size ? buf->size*2 : size + 10);
Owen Taylor3473f882001-02-23 17:55:21 +00006857 while (size > newSize) newSize *= 2;
6858 break;
6859 case XML_BUFFER_ALLOC_EXACT:
6860 newSize = size+10;
6861 break;
6862 default:
6863 newSize = size+10;
6864 break;
6865 }
6866
6867 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006868 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006869 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006870 rebuf = (xmlChar *) xmlRealloc(buf->content,
6871 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006872 } else {
6873 /*
6874 * if we are reallocating a buffer far from being full, it's
6875 * better to make a new allocation and copy only the used range
6876 * and free the old one.
6877 */
6878 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6879 if (rebuf != NULL) {
6880 memcpy(rebuf, buf->content, buf->use);
6881 xmlFree(buf->content);
William M. Brack42331a92004-07-29 07:07:16 +00006882 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006883 }
6884 }
Owen Taylor3473f882001-02-23 17:55:21 +00006885 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006886 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006887 return 0;
6888 }
6889 buf->content = rebuf;
6890 buf->size = newSize;
6891
6892 return 1;
6893}
6894
6895/**
6896 * xmlBufferAdd:
6897 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006898 * @str: the #xmlChar string
6899 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006900 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006901 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006902 * str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006903 *
6904 * Returns 0 successful, a positive error code number otherwise
6905 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006906 */
William M. Bracka3215c72004-07-31 16:24:01 +00006907int
Owen Taylor3473f882001-02-23 17:55:21 +00006908xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6909 unsigned int needSize;
6910
6911 if (str == NULL) {
6912#ifdef DEBUG_BUFFER
6913 xmlGenericError(xmlGenericErrorContext,
6914 "xmlBufferAdd: str == NULL\n");
6915#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006916 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006917 }
William M. Bracka3215c72004-07-31 16:24:01 +00006918 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006919 if (len < -1) {
6920#ifdef DEBUG_BUFFER
6921 xmlGenericError(xmlGenericErrorContext,
6922 "xmlBufferAdd: len < 0\n");
6923#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006924 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006925 }
William M. Bracka3215c72004-07-31 16:24:01 +00006926 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006927
6928 if (len < 0)
6929 len = xmlStrlen(str);
6930
William M. Bracka3215c72004-07-31 16:24:01 +00006931 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006932
6933 needSize = buf->use + len + 2;
6934 if (needSize > buf->size){
6935 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006936 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006937 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006938 }
6939 }
6940
6941 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6942 buf->use += len;
6943 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006944 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006945}
6946
6947/**
6948 * xmlBufferAddHead:
6949 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006950 * @str: the #xmlChar string
6951 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006952 *
6953 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006954 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006955 *
6956 * Returns 0 successful, a positive error code number otherwise
6957 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006958 */
William M. Bracka3215c72004-07-31 16:24:01 +00006959int
Owen Taylor3473f882001-02-23 17:55:21 +00006960xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6961 unsigned int needSize;
6962
William M. Bracka3215c72004-07-31 16:24:01 +00006963 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006964 if (str == NULL) {
6965#ifdef DEBUG_BUFFER
6966 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006967 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006968#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006969 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006970 }
6971 if (len < -1) {
6972#ifdef DEBUG_BUFFER
6973 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006974 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006975#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006976 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006977 }
William M. Bracka3215c72004-07-31 16:24:01 +00006978 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006979
6980 if (len < 0)
6981 len = xmlStrlen(str);
6982
William M. Bracka3215c72004-07-31 16:24:01 +00006983 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006984
6985 needSize = buf->use + len + 2;
6986 if (needSize > buf->size){
6987 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006988 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006989 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006990 }
6991 }
6992
6993 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6994 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6995 buf->use += len;
6996 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006997 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006998}
6999
7000/**
7001 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00007002 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00007003 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00007004 *
7005 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007006 *
7007 * Returns 0 successful, a positive error code number otherwise
7008 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007009 */
William M. Bracka3215c72004-07-31 16:24:01 +00007010int
Owen Taylor3473f882001-02-23 17:55:21 +00007011xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
William M. Bracka3215c72004-07-31 16:24:01 +00007012 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
7013 if (str == NULL) return -1;
7014 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00007015}
7016
7017/**
7018 * xmlBufferCCat:
7019 * @buf: the buffer to dump
7020 * @str: the C char string
7021 *
7022 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007023 *
7024 * Returns 0 successful, a positive error code number otherwise
7025 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007026 */
William M. Bracka3215c72004-07-31 16:24:01 +00007027int
Owen Taylor3473f882001-02-23 17:55:21 +00007028xmlBufferCCat(xmlBufferPtr buf, const char *str) {
7029 const char *cur;
7030
William M. Bracka3215c72004-07-31 16:24:01 +00007031 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007032 if (str == NULL) {
7033#ifdef DEBUG_BUFFER
7034 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007035 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007036#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007037 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007038 }
7039 for (cur = str;*cur != 0;cur++) {
7040 if (buf->use + 10 >= buf->size) {
7041 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007042 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007043 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007044 }
7045 }
7046 buf->content[buf->use++] = *cur;
7047 }
7048 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007049 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007050}
7051
7052/**
7053 * xmlBufferWriteCHAR:
7054 * @buf: the XML buffer
7055 * @string: the string to add
7056 *
7057 * routine which manages and grows an output buffer. This one adds
7058 * xmlChars at the end of the buffer.
7059 */
7060void
Daniel Veillard53350552003-09-18 13:35:51 +00007061xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
7062 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007063 xmlBufferCat(buf, string);
7064}
7065
7066/**
7067 * xmlBufferWriteChar:
7068 * @buf: the XML buffer output
7069 * @string: the string to add
7070 *
7071 * routine which manage and grows an output buffer. This one add
7072 * C chars at the end of the array.
7073 */
7074void
7075xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillard53350552003-09-18 13:35:51 +00007076 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007077 xmlBufferCCat(buf, string);
7078}
7079
7080
7081/**
7082 * xmlBufferWriteQuotedString:
7083 * @buf: the XML buffer output
7084 * @string: the string to add
7085 *
7086 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00007087 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00007088 * quote or double-quotes internally
7089 */
7090void
7091xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00007092 const xmlChar *cur, *base;
Daniel Veillard53350552003-09-18 13:35:51 +00007093 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00007094 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00007095 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00007096#ifdef DEBUG_BUFFER
7097 xmlGenericError(xmlGenericErrorContext,
7098 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7099#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00007100 xmlBufferCCat(buf, "\"");
7101 base = cur = string;
7102 while(*cur != 0){
7103 if(*cur == '"'){
7104 if (base != cur)
7105 xmlBufferAdd(buf, base, cur - base);
7106 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7107 cur++;
7108 base = cur;
7109 }
7110 else {
7111 cur++;
7112 }
7113 }
7114 if (base != cur)
7115 xmlBufferAdd(buf, base, cur - base);
7116 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007117 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007118 else{
7119 xmlBufferCCat(buf, "\'");
7120 xmlBufferCat(buf, string);
7121 xmlBufferCCat(buf, "\'");
7122 }
Owen Taylor3473f882001-02-23 17:55:21 +00007123 } else {
7124 xmlBufferCCat(buf, "\"");
7125 xmlBufferCat(buf, string);
7126 xmlBufferCCat(buf, "\"");
7127 }
7128}
7129
7130
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007131/**
7132 * xmlGetDocCompressMode:
7133 * @doc: the document
7134 *
7135 * get the compression ratio for a document, ZLIB based
7136 * Returns 0 (uncompressed) to 9 (max compression)
7137 */
7138int
7139xmlGetDocCompressMode (xmlDocPtr doc) {
7140 if (doc == NULL) return(-1);
7141 return(doc->compression);
7142}
7143
7144/**
7145 * xmlSetDocCompressMode:
7146 * @doc: the document
7147 * @mode: the compression ratio
7148 *
7149 * set the compression ratio for a document, ZLIB based
7150 * Correct values: 0 (uncompressed) to 9 (max compression)
7151 */
7152void
7153xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7154 if (doc == NULL) return;
7155 if (mode < 0) doc->compression = 0;
7156 else if (mode > 9) doc->compression = 9;
7157 else doc->compression = mode;
7158}
7159
7160/**
7161 * xmlGetCompressMode:
7162 *
7163 * get the default compression mode used, ZLIB based.
7164 * Returns 0 (uncompressed) to 9 (max compression)
7165 */
7166int
7167xmlGetCompressMode(void)
7168{
7169 return (xmlCompressMode);
7170}
7171
7172/**
7173 * xmlSetCompressMode:
7174 * @mode: the compression ratio
7175 *
7176 * set the default compression mode used, ZLIB based
7177 * Correct values: 0 (uncompressed) to 9 (max compression)
7178 */
7179void
7180xmlSetCompressMode(int mode) {
7181 if (mode < 0) xmlCompressMode = 0;
7182 else if (mode > 9) xmlCompressMode = 9;
7183 else xmlCompressMode = mode;
7184}
7185