blob: 87c455607215240d9ff7ba4e19247543af50b880 [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 Veillard2156d432004-03-04 15:59:36 +0000332#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_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
348 /*
349 * First quick algorithm for ASCII range
350 */
351 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000352 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000353 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
354 (*cur == '_'))
355 cur++;
356 else
357 goto try_complex;
358 while (((*cur >= 'a') && (*cur <= 'z')) ||
359 ((*cur >= 'A') && (*cur <= 'Z')) ||
360 ((*cur >= '0') && (*cur <= '9')) ||
361 (*cur == '_') || (*cur == '-') || (*cur == '.'))
362 cur++;
363 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000364 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000365 if (*cur == 0)
366 return(0);
367
368try_complex:
369 /*
370 * Second check for chars outside the ASCII range
371 */
372 cur = value;
373 c = CUR_SCHAR(cur, l);
374 if (space) {
375 while (IS_BLANK(c)) {
376 cur += l;
377 c = CUR_SCHAR(cur, l);
378 }
379 }
William M. Brack871611b2003-10-18 04:53:14 +0000380 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000381 return(1);
382 cur += l;
383 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000384 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
385 (c == '-') || (c == '_') || IS_COMBINING(c) ||
386 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000387 cur += l;
388 c = CUR_SCHAR(cur, l);
389 }
390 if (space) {
391 while (IS_BLANK(c)) {
392 cur += l;
393 c = CUR_SCHAR(cur, l);
394 }
395 }
396 if (c != 0)
397 return(1);
398
399 return(0);
400}
Daniel Veillard2156d432004-03-04 15:59:36 +0000401#endif
Daniel Veillardd2298792003-02-14 16:54:11 +0000402
Daniel Veillard2156d432004-03-04 15:59:36 +0000403#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000404/**
405 * xmlValidateQName:
406 * @value: the value to check
407 * @space: allow spaces in front and end of the string
408 *
409 * Check that a value conforms to the lexical space of QName
410 *
411 * Returns 0 if this validates, a positive error code number otherwise
412 * and -1 in case of internal or API error.
413 */
414int
415xmlValidateQName(const xmlChar *value, int space) {
416 const xmlChar *cur = value;
417 int c,l;
418
419 /*
420 * First quick algorithm for ASCII range
421 */
422 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000423 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000424 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
425 (*cur == '_'))
426 cur++;
427 else
428 goto try_complex;
429 while (((*cur >= 'a') && (*cur <= 'z')) ||
430 ((*cur >= 'A') && (*cur <= 'Z')) ||
431 ((*cur >= '0') && (*cur <= '9')) ||
432 (*cur == '_') || (*cur == '-') || (*cur == '.'))
433 cur++;
434 if (*cur == ':') {
435 cur++;
436 if (((*cur >= 'a') && (*cur <= 'z')) ||
437 ((*cur >= 'A') && (*cur <= 'Z')) ||
438 (*cur == '_'))
439 cur++;
440 else
441 goto try_complex;
442 while (((*cur >= 'a') && (*cur <= 'z')) ||
443 ((*cur >= 'A') && (*cur <= 'Z')) ||
444 ((*cur >= '0') && (*cur <= '9')) ||
445 (*cur == '_') || (*cur == '-') || (*cur == '.'))
446 cur++;
447 }
448 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000449 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000450 if (*cur == 0)
451 return(0);
452
453try_complex:
454 /*
455 * Second check for chars outside the ASCII range
456 */
457 cur = value;
458 c = CUR_SCHAR(cur, l);
459 if (space) {
460 while (IS_BLANK(c)) {
461 cur += l;
462 c = CUR_SCHAR(cur, l);
463 }
464 }
William M. Brack871611b2003-10-18 04:53:14 +0000465 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000466 return(1);
467 cur += l;
468 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000469 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
470 (c == '-') || (c == '_') || IS_COMBINING(c) ||
471 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000472 cur += l;
473 c = CUR_SCHAR(cur, l);
474 }
475 if (c == ':') {
476 cur += l;
477 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000478 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000479 return(1);
480 cur += l;
481 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000482 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
483 (c == '-') || (c == '_') || IS_COMBINING(c) ||
484 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000485 cur += l;
486 c = CUR_SCHAR(cur, l);
487 }
488 }
489 if (space) {
490 while (IS_BLANK(c)) {
491 cur += l;
492 c = CUR_SCHAR(cur, l);
493 }
494 }
495 if (c != 0)
496 return(1);
497 return(0);
498}
499
500/**
501 * xmlValidateName:
502 * @value: the value to check
503 * @space: allow spaces in front and end of the string
504 *
505 * Check that a value conforms to the lexical space of Name
506 *
507 * Returns 0 if this validates, a positive error code number otherwise
508 * and -1 in case of internal or API error.
509 */
510int
511xmlValidateName(const xmlChar *value, int space) {
512 const xmlChar *cur = value;
513 int c,l;
514
515 /*
516 * First quick algorithm for ASCII range
517 */
518 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000519 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000520 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
521 (*cur == '_') || (*cur == ':'))
522 cur++;
523 else
524 goto try_complex;
525 while (((*cur >= 'a') && (*cur <= 'z')) ||
526 ((*cur >= 'A') && (*cur <= 'Z')) ||
527 ((*cur >= '0') && (*cur <= '9')) ||
528 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
529 cur++;
530 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000531 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000532 if (*cur == 0)
533 return(0);
534
535try_complex:
536 /*
537 * Second check for chars outside the ASCII range
538 */
539 cur = value;
540 c = CUR_SCHAR(cur, l);
541 if (space) {
542 while (IS_BLANK(c)) {
543 cur += l;
544 c = CUR_SCHAR(cur, l);
545 }
546 }
William M. Brack871611b2003-10-18 04:53:14 +0000547 if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000548 return(1);
549 cur += l;
550 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000551 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
552 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000553 cur += l;
554 c = CUR_SCHAR(cur, l);
555 }
556 if (space) {
557 while (IS_BLANK(c)) {
558 cur += l;
559 c = CUR_SCHAR(cur, l);
560 }
561 }
562 if (c != 0)
563 return(1);
564 return(0);
565}
566
Daniel Veillardd4310742003-02-18 21:12:46 +0000567/**
568 * xmlValidateNMToken:
569 * @value: the value to check
570 * @space: allow spaces in front and end of the string
571 *
572 * Check that a value conforms to the lexical space of NMToken
573 *
574 * Returns 0 if this validates, a positive error code number otherwise
575 * and -1 in case of internal or API error.
576 */
577int
578xmlValidateNMToken(const xmlChar *value, int space) {
579 const xmlChar *cur = value;
580 int c,l;
581
582 /*
583 * First quick algorithm for ASCII range
584 */
585 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000586 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000587 if (((*cur >= 'a') && (*cur <= 'z')) ||
588 ((*cur >= 'A') && (*cur <= 'Z')) ||
589 ((*cur >= '0') && (*cur <= '9')) ||
590 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
591 cur++;
592 else
593 goto try_complex;
594 while (((*cur >= 'a') && (*cur <= 'z')) ||
595 ((*cur >= 'A') && (*cur <= 'Z')) ||
596 ((*cur >= '0') && (*cur <= '9')) ||
597 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
598 cur++;
599 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000600 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000601 if (*cur == 0)
602 return(0);
603
604try_complex:
605 /*
606 * Second check for chars outside the ASCII range
607 */
608 cur = value;
609 c = CUR_SCHAR(cur, l);
610 if (space) {
611 while (IS_BLANK(c)) {
612 cur += l;
613 c = CUR_SCHAR(cur, l);
614 }
615 }
William M. Brack871611b2003-10-18 04:53:14 +0000616 if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
617 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
Daniel Veillardd4310742003-02-18 21:12:46 +0000618 return(1);
619 cur += l;
620 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000621 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
622 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd4310742003-02-18 21:12:46 +0000623 cur += l;
624 c = CUR_SCHAR(cur, l);
625 }
626 if (space) {
627 while (IS_BLANK(c)) {
628 cur += l;
629 c = CUR_SCHAR(cur, l);
630 }
631 }
632 if (c != 0)
633 return(1);
634 return(0);
635}
Daniel Veillard652327a2003-09-29 18:02:38 +0000636#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardd4310742003-02-18 21:12:46 +0000637
Daniel Veillardd2298792003-02-14 16:54:11 +0000638/************************************************************************
639 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000640 * Allocation and deallocation of basic structures *
641 * *
642 ************************************************************************/
643
644/**
645 * xmlSetBufferAllocationScheme:
646 * @scheme: allocation method to use
647 *
648 * Set the buffer allocation method. Types are
649 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
650 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
651 * improves performance
652 */
653void
654xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
655 xmlBufferAllocScheme = scheme;
656}
657
658/**
659 * xmlGetBufferAllocationScheme:
660 *
661 * Types are
662 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
663 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
664 * improves performance
665 *
666 * Returns the current allocation scheme
667 */
668xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000669xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000670 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000671}
672
673/**
674 * xmlNewNs:
675 * @node: the element carrying the namespace
676 * @href: the URI associated
677 * @prefix: the prefix for the namespace
678 *
679 * Creation of a new Namespace. This function will refuse to create
680 * a namespace with a similar prefix than an existing one present on this
681 * node.
682 * We use href==NULL in the case of an element creation where the namespace
683 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000684 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000685 */
686xmlNsPtr
687xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
688 xmlNsPtr cur;
689
690 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
691 return(NULL);
692
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000693 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
694 return(NULL);
695
Owen Taylor3473f882001-02-23 17:55:21 +0000696 /*
697 * Allocate a new Namespace and fill the fields.
698 */
699 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
700 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000701 xmlTreeErrMemory("building namespace");
Owen Taylor3473f882001-02-23 17:55:21 +0000702 return(NULL);
703 }
704 memset(cur, 0, sizeof(xmlNs));
705 cur->type = XML_LOCAL_NAMESPACE;
706
707 if (href != NULL)
708 cur->href = xmlStrdup(href);
709 if (prefix != NULL)
710 cur->prefix = xmlStrdup(prefix);
711
712 /*
713 * Add it at the end to preserve parsing order ...
714 * and checks for existing use of the prefix
715 */
716 if (node != NULL) {
717 if (node->nsDef == NULL) {
718 node->nsDef = cur;
719 } else {
720 xmlNsPtr prev = node->nsDef;
721
722 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
723 (xmlStrEqual(prev->prefix, cur->prefix))) {
724 xmlFreeNs(cur);
725 return(NULL);
726 }
727 while (prev->next != NULL) {
728 prev = prev->next;
729 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
730 (xmlStrEqual(prev->prefix, cur->prefix))) {
731 xmlFreeNs(cur);
732 return(NULL);
733 }
734 }
735 prev->next = cur;
736 }
737 }
738 return(cur);
739}
740
741/**
742 * xmlSetNs:
743 * @node: a node in the document
744 * @ns: a namespace pointer
745 *
746 * Associate a namespace to a node, a posteriori.
747 */
748void
749xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
750 if (node == NULL) {
751#ifdef DEBUG_TREE
752 xmlGenericError(xmlGenericErrorContext,
753 "xmlSetNs: node == NULL\n");
754#endif
755 return;
756 }
757 node->ns = ns;
758}
759
760/**
761 * xmlFreeNs:
762 * @cur: the namespace pointer
763 *
764 * Free up the structures associated to a namespace
765 */
766void
767xmlFreeNs(xmlNsPtr cur) {
768 if (cur == NULL) {
769#ifdef DEBUG_TREE
770 xmlGenericError(xmlGenericErrorContext,
771 "xmlFreeNs : ns == NULL\n");
772#endif
773 return;
774 }
775 if (cur->href != NULL) xmlFree((char *) cur->href);
776 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000777 xmlFree(cur);
778}
779
780/**
781 * xmlFreeNsList:
782 * @cur: the first namespace pointer
783 *
784 * Free up all the structures associated to the chained namespaces.
785 */
786void
787xmlFreeNsList(xmlNsPtr cur) {
788 xmlNsPtr next;
789 if (cur == NULL) {
790#ifdef DEBUG_TREE
791 xmlGenericError(xmlGenericErrorContext,
792 "xmlFreeNsList : ns == NULL\n");
793#endif
794 return;
795 }
796 while (cur != NULL) {
797 next = cur->next;
798 xmlFreeNs(cur);
799 cur = next;
800 }
801}
802
803/**
804 * xmlNewDtd:
805 * @doc: the document pointer
806 * @name: the DTD name
807 * @ExternalID: the external ID
808 * @SystemID: the system ID
809 *
810 * Creation of a new DTD for the external subset. To create an
811 * internal subset, use xmlCreateIntSubset().
812 *
813 * Returns a pointer to the new DTD structure
814 */
815xmlDtdPtr
816xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
817 const xmlChar *ExternalID, const xmlChar *SystemID) {
818 xmlDtdPtr cur;
819
820 if ((doc != NULL) && (doc->extSubset != NULL)) {
821#ifdef DEBUG_TREE
822 xmlGenericError(xmlGenericErrorContext,
823 "xmlNewDtd(%s): document %s already have a DTD %s\n",
824 /* !!! */ (char *) name, doc->name,
825 /* !!! */ (char *)doc->extSubset->name);
826#endif
827 return(NULL);
828 }
829
830 /*
831 * Allocate a new DTD and fill the fields.
832 */
833 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
834 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000835 xmlTreeErrMemory("building DTD");
Owen Taylor3473f882001-02-23 17:55:21 +0000836 return(NULL);
837 }
838 memset(cur, 0 , sizeof(xmlDtd));
839 cur->type = XML_DTD_NODE;
840
841 if (name != NULL)
842 cur->name = xmlStrdup(name);
843 if (ExternalID != NULL)
844 cur->ExternalID = xmlStrdup(ExternalID);
845 if (SystemID != NULL)
846 cur->SystemID = xmlStrdup(SystemID);
847 if (doc != NULL)
848 doc->extSubset = cur;
849 cur->doc = doc;
850
Daniel Veillarda880b122003-04-21 21:36:41 +0000851 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000852 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000853 return(cur);
854}
855
856/**
857 * xmlGetIntSubset:
858 * @doc: the document pointer
859 *
860 * Get the internal subset of a document
861 * Returns a pointer to the DTD structure or NULL if not found
862 */
863
864xmlDtdPtr
865xmlGetIntSubset(xmlDocPtr doc) {
866 xmlNodePtr cur;
867
868 if (doc == NULL)
869 return(NULL);
870 cur = doc->children;
871 while (cur != NULL) {
872 if (cur->type == XML_DTD_NODE)
873 return((xmlDtdPtr) cur);
874 cur = cur->next;
875 }
876 return((xmlDtdPtr) doc->intSubset);
877}
878
879/**
880 * xmlCreateIntSubset:
881 * @doc: the document pointer
882 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000883 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000884 * @SystemID: the system ID
885 *
886 * Create the internal subset of a document
887 * Returns a pointer to the new DTD structure
888 */
889xmlDtdPtr
890xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
891 const xmlChar *ExternalID, const xmlChar *SystemID) {
892 xmlDtdPtr cur;
893
894 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
895#ifdef DEBUG_TREE
896 xmlGenericError(xmlGenericErrorContext,
897
898 "xmlCreateIntSubset(): document %s already have an internal subset\n",
899 doc->name);
900#endif
901 return(NULL);
902 }
903
904 /*
905 * Allocate a new DTD and fill the fields.
906 */
907 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
908 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000909 xmlTreeErrMemory("building internal subset");
Owen Taylor3473f882001-02-23 17:55:21 +0000910 return(NULL);
911 }
912 memset(cur, 0, sizeof(xmlDtd));
913 cur->type = XML_DTD_NODE;
914
William M. Bracka3215c72004-07-31 16:24:01 +0000915 if (name != NULL) {
916 cur->name = xmlStrdup(name);
917 if (cur->name == NULL) {
918 xmlTreeErrMemory("building internal subset");
919 xmlFree(cur);
920 return(NULL);
921 }
922 }
923 if (ExternalID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000924 cur->ExternalID = xmlStrdup(ExternalID);
William M. Bracka3215c72004-07-31 16:24:01 +0000925 if (cur->ExternalID == NULL) {
926 xmlTreeErrMemory("building internal subset");
927 if (cur->name != NULL)
928 xmlFree((char *)cur->name);
929 xmlFree(cur);
930 return(NULL);
931 }
932 }
933 if (SystemID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000934 cur->SystemID = xmlStrdup(SystemID);
William M. Bracka3215c72004-07-31 16:24:01 +0000935 if (cur->SystemID == NULL) {
936 xmlTreeErrMemory("building internal subset");
937 if (cur->name != NULL)
938 xmlFree((char *)cur->name);
939 if (cur->ExternalID != NULL)
940 xmlFree((char *)cur->ExternalID);
941 xmlFree(cur);
942 return(NULL);
943 }
944 }
Owen Taylor3473f882001-02-23 17:55:21 +0000945 if (doc != NULL) {
946 doc->intSubset = cur;
947 cur->parent = doc;
948 cur->doc = doc;
949 if (doc->children == NULL) {
950 doc->children = (xmlNodePtr) cur;
951 doc->last = (xmlNodePtr) cur;
952 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000953 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000954 xmlNodePtr prev;
955
Owen Taylor3473f882001-02-23 17:55:21 +0000956 prev = doc->children;
957 prev->prev = (xmlNodePtr) cur;
958 cur->next = prev;
959 doc->children = (xmlNodePtr) cur;
960 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000961 xmlNodePtr next;
962
963 next = doc->children;
964 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
965 next = next->next;
966 if (next == NULL) {
967 cur->prev = doc->last;
968 cur->prev->next = (xmlNodePtr) cur;
969 cur->next = NULL;
970 doc->last = (xmlNodePtr) cur;
971 } else {
972 cur->next = next;
973 cur->prev = next->prev;
974 if (cur->prev == NULL)
975 doc->children = (xmlNodePtr) cur;
976 else
977 cur->prev->next = (xmlNodePtr) cur;
978 next->prev = (xmlNodePtr) cur;
979 }
Owen Taylor3473f882001-02-23 17:55:21 +0000980 }
981 }
982 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000983
Daniel Veillarda880b122003-04-21 21:36:41 +0000984 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000985 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000986 return(cur);
987}
988
989/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000990 * DICT_FREE:
991 * @str: a string
992 *
993 * Free a string if it is not owned by the "dict" dictionnary in the
994 * current scope
995 */
996#define DICT_FREE(str) \
997 if ((str) && ((!dict) || \
998 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
999 xmlFree((char *)(str));
1000
1001/**
Owen Taylor3473f882001-02-23 17:55:21 +00001002 * xmlFreeDtd:
1003 * @cur: the DTD structure to free up
1004 *
1005 * Free a DTD structure.
1006 */
1007void
1008xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001009 xmlDictPtr dict = NULL;
1010
Owen Taylor3473f882001-02-23 17:55:21 +00001011 if (cur == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001012 return;
1013 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001014 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001015
Daniel Veillarda880b122003-04-21 21:36:41 +00001016 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001017 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1018
Owen Taylor3473f882001-02-23 17:55:21 +00001019 if (cur->children != NULL) {
1020 xmlNodePtr next, c = cur->children;
1021
1022 /*
William M. Brack18a04f22004-08-03 16:42:37 +00001023 * Cleanup all nodes which are not part of the specific lists
1024 * of notations, elements, attributes and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00001025 */
1026 while (c != NULL) {
1027 next = c->next;
William M. Brack18a04f22004-08-03 16:42:37 +00001028 if ((c->type != XML_NOTATION_NODE) &&
1029 (c->type != XML_ELEMENT_DECL) &&
1030 (c->type != XML_ATTRIBUTE_DECL) &&
1031 (c->type != XML_ENTITY_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001032 xmlUnlinkNode(c);
1033 xmlFreeNode(c);
1034 }
1035 c = next;
1036 }
1037 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001038 DICT_FREE(cur->name)
1039 DICT_FREE(cur->SystemID)
1040 DICT_FREE(cur->ExternalID)
Owen Taylor3473f882001-02-23 17:55:21 +00001041 /* TODO !!! */
1042 if (cur->notations != NULL)
1043 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1044
1045 if (cur->elements != NULL)
1046 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1047 if (cur->attributes != NULL)
1048 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1049 if (cur->entities != NULL)
1050 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1051 if (cur->pentities != NULL)
1052 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1053
Owen Taylor3473f882001-02-23 17:55:21 +00001054 xmlFree(cur);
1055}
1056
1057/**
1058 * xmlNewDoc:
1059 * @version: xmlChar string giving the version of XML "1.0"
1060 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001061 * Creates a new XML document
1062 *
Owen Taylor3473f882001-02-23 17:55:21 +00001063 * Returns a new document
1064 */
1065xmlDocPtr
1066xmlNewDoc(const xmlChar *version) {
1067 xmlDocPtr cur;
1068
1069 if (version == NULL)
1070 version = (const xmlChar *) "1.0";
1071
1072 /*
1073 * Allocate a new document and fill the fields.
1074 */
1075 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1076 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001077 xmlTreeErrMemory("building doc");
Owen Taylor3473f882001-02-23 17:55:21 +00001078 return(NULL);
1079 }
1080 memset(cur, 0, sizeof(xmlDoc));
1081 cur->type = XML_DOCUMENT_NODE;
1082
1083 cur->version = xmlStrdup(version);
William M. Bracka3215c72004-07-31 16:24:01 +00001084 if (cur->version == NULL) {
1085 xmlTreeErrMemory("building doc");
1086 xmlFree(cur);
1087 return(NULL);
1088 }
Owen Taylor3473f882001-02-23 17:55:21 +00001089 cur->standalone = -1;
1090 cur->compression = -1; /* not initialized */
1091 cur->doc = cur;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001092 /*
1093 * The in memory encoding is always UTF8
1094 * This field will never change and would
1095 * be obsolete if not for binary compatibility.
1096 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001097 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001098
Daniel Veillarda880b122003-04-21 21:36:41 +00001099 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001100 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001101 return(cur);
1102}
1103
1104/**
1105 * xmlFreeDoc:
1106 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001107 *
1108 * Free up all the structures used by a document, tree included.
1109 */
1110void
1111xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001112 xmlDtdPtr extSubset, intSubset;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001113 xmlDictPtr dict = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001114
Owen Taylor3473f882001-02-23 17:55:21 +00001115 if (cur == NULL) {
1116#ifdef DEBUG_TREE
1117 xmlGenericError(xmlGenericErrorContext,
1118 "xmlFreeDoc : document == NULL\n");
1119#endif
1120 return;
1121 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001122#ifdef LIBXML_DEBUG_RUNTIME
1123 xmlDebugCheckDocument(stderr, cur);
1124#endif
1125
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001126 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001127
Daniel Veillarda880b122003-04-21 21:36:41 +00001128 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001129 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1130
Daniel Veillard76d66f42001-05-16 21:05:17 +00001131 /*
1132 * Do this before freeing the children list to avoid ID lookups
1133 */
1134 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1135 cur->ids = NULL;
1136 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1137 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001138 extSubset = cur->extSubset;
1139 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001140 if (intSubset == extSubset)
1141 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001142 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001143 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001144 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001145 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001146 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001147 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001148 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001149 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001150 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001151 }
1152
1153 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001154 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001155
1156 DICT_FREE(cur->version)
1157 DICT_FREE(cur->name)
1158 DICT_FREE(cur->encoding)
1159 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001160 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001161 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001162}
1163
1164/**
1165 * xmlStringLenGetNodeList:
1166 * @doc: the document
1167 * @value: the value of the text
1168 * @len: the length of the string value
1169 *
1170 * Parse the value string and build the node list associated. Should
1171 * produce a flat tree with only TEXTs and ENTITY_REFs.
1172 * Returns a pointer to the first child
1173 */
1174xmlNodePtr
1175xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1176 xmlNodePtr ret = NULL, last = NULL;
1177 xmlNodePtr node;
1178 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001179 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001180 const xmlChar *q;
1181 xmlEntityPtr ent;
1182
1183 if (value == NULL) return(NULL);
1184
1185 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001186 while ((cur < end) && (*cur != 0)) {
1187 if (cur[0] == '&') {
1188 int charval = 0;
1189 xmlChar tmp;
1190
Owen Taylor3473f882001-02-23 17:55:21 +00001191 /*
1192 * Save the current text.
1193 */
1194 if (cur != q) {
1195 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1196 xmlNodeAddContentLen(last, q, cur - q);
1197 } else {
1198 node = xmlNewDocTextLen(doc, q, cur - q);
1199 if (node == NULL) return(ret);
1200 if (last == NULL)
1201 last = ret = node;
1202 else {
1203 last->next = node;
1204 node->prev = last;
1205 last = node;
1206 }
1207 }
1208 }
Owen Taylor3473f882001-02-23 17:55:21 +00001209 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001210 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1211 cur += 3;
1212 if (cur < end)
1213 tmp = *cur;
1214 else
1215 tmp = 0;
1216 while (tmp != ';') { /* Non input consuming loop */
1217 if ((tmp >= '0') && (tmp <= '9'))
1218 charval = charval * 16 + (tmp - '0');
1219 else if ((tmp >= 'a') && (tmp <= 'f'))
1220 charval = charval * 16 + (tmp - 'a') + 10;
1221 else if ((tmp >= 'A') && (tmp <= 'F'))
1222 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001223 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001224 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1225 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001226 charval = 0;
1227 break;
1228 }
1229 cur++;
1230 if (cur < end)
1231 tmp = *cur;
1232 else
1233 tmp = 0;
1234 }
1235 if (tmp == ';')
1236 cur++;
1237 q = cur;
1238 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1239 cur += 2;
1240 if (cur < end)
1241 tmp = *cur;
1242 else
1243 tmp = 0;
1244 while (tmp != ';') { /* Non input consuming loops */
1245 if ((tmp >= '0') && (tmp <= '9'))
1246 charval = charval * 10 + (tmp - '0');
1247 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001248 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1249 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001250 charval = 0;
1251 break;
1252 }
1253 cur++;
1254 if (cur < end)
1255 tmp = *cur;
1256 else
1257 tmp = 0;
1258 }
1259 if (tmp == ';')
1260 cur++;
1261 q = cur;
1262 } else {
1263 /*
1264 * Read the entity string
1265 */
1266 cur++;
1267 q = cur;
1268 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1269 if ((cur >= end) || (*cur == 0)) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001270 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1271 (const char *) q);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001272 return(ret);
1273 }
1274 if (cur != q) {
1275 /*
1276 * Predefined entities don't generate nodes
1277 */
1278 val = xmlStrndup(q, cur - q);
1279 ent = xmlGetDocEntity(doc, val);
1280 if ((ent != NULL) &&
1281 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1282 if (last == NULL) {
1283 node = xmlNewDocText(doc, ent->content);
1284 last = ret = node;
1285 } else if (last->type != XML_TEXT_NODE) {
1286 node = xmlNewDocText(doc, ent->content);
1287 last = xmlAddNextSibling(last, node);
1288 } else
1289 xmlNodeAddContent(last, ent->content);
1290
1291 } else {
1292 /*
1293 * Create a new REFERENCE_REF node
1294 */
1295 node = xmlNewReference(doc, val);
1296 if (node == NULL) {
1297 if (val != NULL) xmlFree(val);
1298 return(ret);
1299 }
1300 else if ((ent != NULL) && (ent->children == NULL)) {
1301 xmlNodePtr temp;
1302
1303 ent->children = xmlStringGetNodeList(doc,
1304 (const xmlChar*)node->content);
1305 ent->owner = 1;
1306 temp = ent->children;
1307 while (temp) {
1308 temp->parent = (xmlNodePtr)ent;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001309 ent->last = temp;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001310 temp = temp->next;
1311 }
1312 }
1313 if (last == NULL) {
1314 last = ret = node;
1315 } else {
1316 last = xmlAddNextSibling(last, node);
1317 }
1318 }
1319 xmlFree(val);
1320 }
1321 cur++;
1322 q = cur;
1323 }
1324 if (charval != 0) {
1325 xmlChar buf[10];
1326 int l;
1327
1328 l = xmlCopyCharMultiByte(buf, charval);
1329 buf[l] = 0;
1330 node = xmlNewDocText(doc, buf);
1331 if (node != NULL) {
1332 if (last == NULL) {
1333 last = ret = node;
1334 } else {
1335 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001336 }
1337 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001338 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001339 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001340 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001341 cur++;
1342 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001343 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001344 /*
1345 * Handle the last piece of text.
1346 */
1347 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1348 xmlNodeAddContentLen(last, q, cur - q);
1349 } else {
1350 node = xmlNewDocTextLen(doc, q, cur - q);
1351 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001352 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001353 last = ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001354 } else {
1355 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001356 }
1357 }
1358 }
1359 return(ret);
1360}
1361
1362/**
1363 * xmlStringGetNodeList:
1364 * @doc: the document
1365 * @value: the value of the attribute
1366 *
1367 * Parse the value string and build the node list associated. Should
1368 * produce a flat tree with only TEXTs and ENTITY_REFs.
1369 * Returns a pointer to the first child
1370 */
1371xmlNodePtr
1372xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1373 xmlNodePtr ret = NULL, last = NULL;
1374 xmlNodePtr node;
1375 xmlChar *val;
1376 const xmlChar *cur = value;
1377 const xmlChar *q;
1378 xmlEntityPtr ent;
1379
1380 if (value == NULL) return(NULL);
1381
1382 q = cur;
1383 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001384 if (cur[0] == '&') {
1385 int charval = 0;
1386 xmlChar tmp;
1387
Owen Taylor3473f882001-02-23 17:55:21 +00001388 /*
1389 * Save the current text.
1390 */
1391 if (cur != q) {
1392 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1393 xmlNodeAddContentLen(last, q, cur - q);
1394 } else {
1395 node = xmlNewDocTextLen(doc, q, cur - q);
1396 if (node == NULL) return(ret);
1397 if (last == NULL)
1398 last = ret = node;
1399 else {
1400 last->next = node;
1401 node->prev = last;
1402 last = node;
1403 }
1404 }
1405 }
Owen Taylor3473f882001-02-23 17:55:21 +00001406 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001407 if ((cur[1] == '#') && (cur[2] == 'x')) {
1408 cur += 3;
1409 tmp = *cur;
1410 while (tmp != ';') { /* Non input consuming loop */
1411 if ((tmp >= '0') && (tmp <= '9'))
1412 charval = charval * 16 + (tmp - '0');
1413 else if ((tmp >= 'a') && (tmp <= 'f'))
1414 charval = charval * 16 + (tmp - 'a') + 10;
1415 else if ((tmp >= 'A') && (tmp <= 'F'))
1416 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001417 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001418 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1419 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001420 charval = 0;
1421 break;
1422 }
1423 cur++;
1424 tmp = *cur;
1425 }
1426 if (tmp == ';')
1427 cur++;
1428 q = cur;
1429 } else if (cur[1] == '#') {
1430 cur += 2;
1431 tmp = *cur;
1432 while (tmp != ';') { /* Non input consuming loops */
1433 if ((tmp >= '0') && (tmp <= '9'))
1434 charval = charval * 10 + (tmp - '0');
1435 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001436 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1437 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001438 charval = 0;
1439 break;
1440 }
1441 cur++;
1442 tmp = *cur;
1443 }
1444 if (tmp == ';')
1445 cur++;
1446 q = cur;
1447 } else {
1448 /*
1449 * Read the entity string
1450 */
1451 cur++;
1452 q = cur;
1453 while ((*cur != 0) && (*cur != ';')) cur++;
1454 if (*cur == 0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001455 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1456 (xmlNodePtr) doc, (const char *) q);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001457 return(ret);
1458 }
1459 if (cur != q) {
1460 /*
1461 * Predefined entities don't generate nodes
1462 */
1463 val = xmlStrndup(q, cur - q);
1464 ent = xmlGetDocEntity(doc, val);
1465 if ((ent != NULL) &&
1466 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1467 if (last == NULL) {
1468 node = xmlNewDocText(doc, ent->content);
1469 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001470 } else if (last->type != XML_TEXT_NODE) {
1471 node = xmlNewDocText(doc, ent->content);
1472 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001473 } else
1474 xmlNodeAddContent(last, ent->content);
1475
1476 } else {
1477 /*
1478 * Create a new REFERENCE_REF node
1479 */
1480 node = xmlNewReference(doc, val);
1481 if (node == NULL) {
1482 if (val != NULL) xmlFree(val);
1483 return(ret);
1484 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001485 else if ((ent != NULL) && (ent->children == NULL)) {
1486 xmlNodePtr temp;
1487
1488 ent->children = xmlStringGetNodeList(doc,
1489 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001490 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001491 temp = ent->children;
1492 while (temp) {
1493 temp->parent = (xmlNodePtr)ent;
1494 temp = temp->next;
1495 }
1496 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001497 if (last == NULL) {
1498 last = ret = node;
1499 } else {
1500 last = xmlAddNextSibling(last, node);
1501 }
1502 }
1503 xmlFree(val);
1504 }
1505 cur++;
1506 q = cur;
1507 }
1508 if (charval != 0) {
1509 xmlChar buf[10];
1510 int len;
1511
1512 len = xmlCopyCharMultiByte(buf, charval);
1513 buf[len] = 0;
1514 node = xmlNewDocText(doc, buf);
1515 if (node != NULL) {
1516 if (last == NULL) {
1517 last = ret = node;
1518 } else {
1519 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001520 }
1521 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001522
1523 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001524 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001525 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001526 cur++;
1527 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001528 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001529 /*
1530 * Handle the last piece of text.
1531 */
1532 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1533 xmlNodeAddContentLen(last, q, cur - q);
1534 } else {
1535 node = xmlNewDocTextLen(doc, q, cur - q);
1536 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001537 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001538 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001539 } else {
1540 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001541 }
1542 }
1543 }
1544 return(ret);
1545}
1546
1547/**
1548 * xmlNodeListGetString:
1549 * @doc: the document
1550 * @list: a Node list
1551 * @inLine: should we replace entity contents or show their external form
1552 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001553 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001554 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001555 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001556 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001557 */
1558xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001559xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1560{
Owen Taylor3473f882001-02-23 17:55:21 +00001561 xmlNodePtr node = list;
1562 xmlChar *ret = NULL;
1563 xmlEntityPtr ent;
1564
Daniel Veillard7646b182002-04-20 06:41:40 +00001565 if (list == NULL)
1566 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001567
1568 while (node != NULL) {
1569 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001570 (node->type == XML_CDATA_SECTION_NODE)) {
1571 if (inLine) {
1572 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001573 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001574 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001575
Daniel Veillard7646b182002-04-20 06:41:40 +00001576 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1577 if (buffer != NULL) {
1578 ret = xmlStrcat(ret, buffer);
1579 xmlFree(buffer);
1580 }
1581 }
1582 } else if (node->type == XML_ENTITY_REF_NODE) {
1583 if (inLine) {
1584 ent = xmlGetDocEntity(doc, node->name);
1585 if (ent != NULL) {
1586 xmlChar *buffer;
1587
1588 /* an entity content can be any "well balanced chunk",
1589 * i.e. the result of the content [43] production:
1590 * http://www.w3.org/TR/REC-xml#NT-content.
1591 * So it can contain text, CDATA section or nested
1592 * entity reference nodes (among others).
1593 * -> we recursive call xmlNodeListGetString()
1594 * which handles these types */
1595 buffer = xmlNodeListGetString(doc, ent->children, 1);
1596 if (buffer != NULL) {
1597 ret = xmlStrcat(ret, buffer);
1598 xmlFree(buffer);
1599 }
1600 } else {
1601 ret = xmlStrcat(ret, node->content);
1602 }
1603 } else {
1604 xmlChar buf[2];
1605
1606 buf[0] = '&';
1607 buf[1] = 0;
1608 ret = xmlStrncat(ret, buf, 1);
1609 ret = xmlStrcat(ret, node->name);
1610 buf[0] = ';';
1611 buf[1] = 0;
1612 ret = xmlStrncat(ret, buf, 1);
1613 }
1614 }
1615#if 0
1616 else {
1617 xmlGenericError(xmlGenericErrorContext,
1618 "xmlGetNodeListString : invalid node type %d\n",
1619 node->type);
1620 }
1621#endif
1622 node = node->next;
1623 }
1624 return (ret);
1625}
Daniel Veillard652327a2003-09-29 18:02:38 +00001626
1627#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001628/**
1629 * xmlNodeListGetRawString:
1630 * @doc: the document
1631 * @list: a Node list
1632 * @inLine: should we replace entity contents or show their external form
1633 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001634 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001635 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1636 * this function doesn't do any character encoding handling.
1637 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001638 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001639 */
1640xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001641xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1642{
Owen Taylor3473f882001-02-23 17:55:21 +00001643 xmlNodePtr node = list;
1644 xmlChar *ret = NULL;
1645 xmlEntityPtr ent;
1646
Daniel Veillard7646b182002-04-20 06:41:40 +00001647 if (list == NULL)
1648 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001649
1650 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001651 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001652 (node->type == XML_CDATA_SECTION_NODE)) {
1653 if (inLine) {
1654 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001655 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001656 xmlChar *buffer;
1657
1658 buffer = xmlEncodeSpecialChars(doc, node->content);
1659 if (buffer != NULL) {
1660 ret = xmlStrcat(ret, buffer);
1661 xmlFree(buffer);
1662 }
1663 }
1664 } else if (node->type == XML_ENTITY_REF_NODE) {
1665 if (inLine) {
1666 ent = xmlGetDocEntity(doc, node->name);
1667 if (ent != NULL) {
1668 xmlChar *buffer;
1669
1670 /* an entity content can be any "well balanced chunk",
1671 * i.e. the result of the content [43] production:
1672 * http://www.w3.org/TR/REC-xml#NT-content.
1673 * So it can contain text, CDATA section or nested
1674 * entity reference nodes (among others).
1675 * -> we recursive call xmlNodeListGetRawString()
1676 * which handles these types */
1677 buffer =
1678 xmlNodeListGetRawString(doc, ent->children, 1);
1679 if (buffer != NULL) {
1680 ret = xmlStrcat(ret, buffer);
1681 xmlFree(buffer);
1682 }
1683 } else {
1684 ret = xmlStrcat(ret, node->content);
1685 }
1686 } else {
1687 xmlChar buf[2];
1688
1689 buf[0] = '&';
1690 buf[1] = 0;
1691 ret = xmlStrncat(ret, buf, 1);
1692 ret = xmlStrcat(ret, node->name);
1693 buf[0] = ';';
1694 buf[1] = 0;
1695 ret = xmlStrncat(ret, buf, 1);
1696 }
1697 }
Owen Taylor3473f882001-02-23 17:55:21 +00001698#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001699 else {
1700 xmlGenericError(xmlGenericErrorContext,
1701 "xmlGetNodeListString : invalid node type %d\n",
1702 node->type);
1703 }
Owen Taylor3473f882001-02-23 17:55:21 +00001704#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001705 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001706 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001707 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001708}
Daniel Veillard652327a2003-09-29 18:02:38 +00001709#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001710
Daniel Veillard2156d432004-03-04 15:59:36 +00001711#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00001712/**
1713 * xmlNewProp:
1714 * @node: the holding node
1715 * @name: the name of the attribute
1716 * @value: the value of the attribute
1717 *
1718 * Create a new property carried by a node.
1719 * Returns a pointer to the attribute
1720 */
1721xmlAttrPtr
1722xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1723 xmlAttrPtr cur;
1724 xmlDocPtr doc = NULL;
1725
1726 if (name == NULL) {
1727#ifdef DEBUG_TREE
1728 xmlGenericError(xmlGenericErrorContext,
1729 "xmlNewProp : name == NULL\n");
1730#endif
1731 return(NULL);
1732 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001733 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1734 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001735
1736 /*
1737 * Allocate a new property and fill the fields.
1738 */
1739 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1740 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001741 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001742 return(NULL);
1743 }
1744 memset(cur, 0, sizeof(xmlAttr));
1745 cur->type = XML_ATTRIBUTE_NODE;
1746
1747 cur->parent = node;
1748 if (node != NULL) {
1749 doc = node->doc;
1750 cur->doc = doc;
1751 }
1752 cur->name = xmlStrdup(name);
1753 if (value != NULL) {
1754 xmlChar *buffer;
1755 xmlNodePtr tmp;
1756
1757 buffer = xmlEncodeEntitiesReentrant(doc, value);
1758 cur->children = xmlStringGetNodeList(doc, buffer);
1759 cur->last = NULL;
1760 tmp = cur->children;
1761 while (tmp != NULL) {
1762 tmp->parent = (xmlNodePtr) cur;
1763 tmp->doc = doc;
1764 if (tmp->next == NULL)
1765 cur->last = tmp;
1766 tmp = tmp->next;
1767 }
1768 xmlFree(buffer);
1769 }
1770
1771 /*
1772 * Add it at the end to preserve parsing order ...
1773 */
1774 if (node != NULL) {
1775 if (node->properties == NULL) {
1776 node->properties = cur;
1777 } else {
1778 xmlAttrPtr prev = node->properties;
1779
1780 while (prev->next != NULL) prev = prev->next;
1781 prev->next = cur;
1782 cur->prev = prev;
1783 }
1784 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001785
Daniel Veillarda880b122003-04-21 21:36:41 +00001786 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001787 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001788 return(cur);
1789}
Daniel Veillard652327a2003-09-29 18:02:38 +00001790#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001791
1792/**
1793 * xmlNewNsProp:
1794 * @node: the holding node
1795 * @ns: the namespace
1796 * @name: the name of the attribute
1797 * @value: the value of the attribute
1798 *
1799 * Create a new property tagged with a namespace and carried by a node.
1800 * Returns a pointer to the attribute
1801 */
1802xmlAttrPtr
1803xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1804 const xmlChar *value) {
1805 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001806 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001807
1808 if (name == NULL) {
1809#ifdef DEBUG_TREE
1810 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001811 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001812#endif
1813 return(NULL);
1814 }
1815
1816 /*
1817 * Allocate a new property and fill the fields.
1818 */
1819 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1820 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001821 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001822 return(NULL);
1823 }
1824 memset(cur, 0, sizeof(xmlAttr));
1825 cur->type = XML_ATTRIBUTE_NODE;
1826
1827 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001828 if (node != NULL) {
1829 doc = node->doc;
1830 cur->doc = doc;
1831 }
Owen Taylor3473f882001-02-23 17:55:21 +00001832 cur->ns = ns;
1833 cur->name = xmlStrdup(name);
1834 if (value != NULL) {
1835 xmlChar *buffer;
1836 xmlNodePtr tmp;
1837
Daniel Veillarda682b212001-06-07 19:59:42 +00001838 buffer = xmlEncodeEntitiesReentrant(doc, value);
1839 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001840 cur->last = NULL;
1841 tmp = cur->children;
1842 while (tmp != NULL) {
1843 tmp->parent = (xmlNodePtr) cur;
1844 if (tmp->next == NULL)
1845 cur->last = tmp;
1846 tmp = tmp->next;
1847 }
1848 xmlFree(buffer);
1849 }
1850
1851 /*
1852 * Add it at the end to preserve parsing order ...
1853 */
1854 if (node != NULL) {
1855 if (node->properties == NULL) {
1856 node->properties = cur;
1857 } else {
1858 xmlAttrPtr prev = node->properties;
1859
1860 while (prev->next != NULL) prev = prev->next;
1861 prev->next = cur;
1862 cur->prev = prev;
1863 }
1864 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001865
Daniel Veillarda880b122003-04-21 21:36:41 +00001866 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001867 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001868 return(cur);
1869}
1870
1871/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001872 * xmlNewNsPropEatName:
1873 * @node: the holding node
1874 * @ns: the namespace
1875 * @name: the name of the attribute
1876 * @value: the value of the attribute
1877 *
1878 * Create a new property tagged with a namespace and carried by a node.
1879 * Returns a pointer to the attribute
1880 */
1881xmlAttrPtr
1882xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1883 const xmlChar *value) {
1884 xmlAttrPtr cur;
1885 xmlDocPtr doc = NULL;
1886
1887 if (name == NULL) {
1888#ifdef DEBUG_TREE
1889 xmlGenericError(xmlGenericErrorContext,
1890 "xmlNewNsPropEatName : name == NULL\n");
1891#endif
1892 return(NULL);
1893 }
1894
1895 /*
1896 * Allocate a new property and fill the fields.
1897 */
1898 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1899 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001900 xmlTreeErrMemory("building attribute");
Daniel Veillard46de64e2002-05-29 08:21:33 +00001901 return(NULL);
1902 }
1903 memset(cur, 0, sizeof(xmlAttr));
1904 cur->type = XML_ATTRIBUTE_NODE;
1905
1906 cur->parent = node;
1907 if (node != NULL) {
1908 doc = node->doc;
1909 cur->doc = doc;
1910 }
1911 cur->ns = ns;
1912 cur->name = name;
1913 if (value != NULL) {
1914 xmlChar *buffer;
1915 xmlNodePtr tmp;
1916
1917 buffer = xmlEncodeEntitiesReentrant(doc, value);
1918 cur->children = xmlStringGetNodeList(doc, buffer);
1919 cur->last = NULL;
1920 tmp = cur->children;
1921 while (tmp != NULL) {
1922 tmp->parent = (xmlNodePtr) cur;
1923 if (tmp->next == NULL)
1924 cur->last = tmp;
1925 tmp = tmp->next;
1926 }
1927 xmlFree(buffer);
1928 }
1929
1930 /*
1931 * Add it at the end to preserve parsing order ...
1932 */
1933 if (node != NULL) {
1934 if (node->properties == NULL) {
1935 node->properties = cur;
1936 } else {
1937 xmlAttrPtr prev = node->properties;
1938
1939 while (prev->next != NULL) prev = prev->next;
1940 prev->next = cur;
1941 cur->prev = prev;
1942 }
1943 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001944
Daniel Veillarda880b122003-04-21 21:36:41 +00001945 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001946 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001947 return(cur);
1948}
1949
1950/**
Owen Taylor3473f882001-02-23 17:55:21 +00001951 * xmlNewDocProp:
1952 * @doc: the document
1953 * @name: the name of the attribute
1954 * @value: the value of the attribute
1955 *
1956 * Create a new property carried by a document.
1957 * Returns a pointer to the attribute
1958 */
1959xmlAttrPtr
1960xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1961 xmlAttrPtr cur;
1962
1963 if (name == NULL) {
1964#ifdef DEBUG_TREE
1965 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001966 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001967#endif
1968 return(NULL);
1969 }
1970
1971 /*
1972 * Allocate a new property and fill the fields.
1973 */
1974 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1975 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001976 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001977 return(NULL);
1978 }
1979 memset(cur, 0, sizeof(xmlAttr));
1980 cur->type = XML_ATTRIBUTE_NODE;
1981
1982 cur->name = xmlStrdup(name);
1983 cur->doc = doc;
1984 if (value != NULL) {
1985 xmlNodePtr tmp;
1986
1987 cur->children = xmlStringGetNodeList(doc, value);
1988 cur->last = NULL;
1989
1990 tmp = cur->children;
1991 while (tmp != NULL) {
1992 tmp->parent = (xmlNodePtr) cur;
1993 if (tmp->next == NULL)
1994 cur->last = tmp;
1995 tmp = tmp->next;
1996 }
1997 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001998
Daniel Veillarda880b122003-04-21 21:36:41 +00001999 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002000 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002001 return(cur);
2002}
2003
2004/**
2005 * xmlFreePropList:
2006 * @cur: the first property in the list
2007 *
2008 * Free a property and all its siblings, all the children are freed too.
2009 */
2010void
2011xmlFreePropList(xmlAttrPtr cur) {
2012 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002013 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002014 while (cur != NULL) {
2015 next = cur->next;
2016 xmlFreeProp(cur);
2017 cur = next;
2018 }
2019}
2020
2021/**
2022 * xmlFreeProp:
2023 * @cur: an attribute
2024 *
2025 * Free one attribute, all the content is freed too
2026 */
2027void
2028xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002029 xmlDictPtr dict = NULL;
2030 if (cur == NULL) return;
2031
2032 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002033
Daniel Veillarda880b122003-04-21 21:36:41 +00002034 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002035 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
2036
Owen Taylor3473f882001-02-23 17:55:21 +00002037 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00002038 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
2039 ((cur->parent->doc->intSubset != NULL) ||
2040 (cur->parent->doc->extSubset != NULL))) {
2041 if (xmlIsID(cur->parent->doc, cur->parent, cur))
2042 xmlRemoveID(cur->parent->doc, cur);
2043 }
Owen Taylor3473f882001-02-23 17:55:21 +00002044 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002045 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002046 xmlFree(cur);
2047}
2048
Daniel Veillard652327a2003-09-29 18:02:38 +00002049#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002050/**
2051 * xmlRemoveProp:
2052 * @cur: an attribute
2053 *
2054 * Unlink and free one attribute, all the content is freed too
2055 * Note this doesn't work for namespace definition attributes
2056 *
2057 * Returns 0 if success and -1 in case of error.
2058 */
2059int
2060xmlRemoveProp(xmlAttrPtr cur) {
2061 xmlAttrPtr tmp;
2062 if (cur == NULL) {
2063#ifdef DEBUG_TREE
2064 xmlGenericError(xmlGenericErrorContext,
2065 "xmlRemoveProp : cur == NULL\n");
2066#endif
2067 return(-1);
2068 }
2069 if (cur->parent == NULL) {
2070#ifdef DEBUG_TREE
2071 xmlGenericError(xmlGenericErrorContext,
2072 "xmlRemoveProp : cur->parent == NULL\n");
2073#endif
2074 return(-1);
2075 }
2076 tmp = cur->parent->properties;
2077 if (tmp == cur) {
2078 cur->parent->properties = cur->next;
2079 xmlFreeProp(cur);
2080 return(0);
2081 }
2082 while (tmp != NULL) {
2083 if (tmp->next == cur) {
2084 tmp->next = cur->next;
2085 if (tmp->next != NULL)
2086 tmp->next->prev = tmp;
2087 xmlFreeProp(cur);
2088 return(0);
2089 }
2090 tmp = tmp->next;
2091 }
2092#ifdef DEBUG_TREE
2093 xmlGenericError(xmlGenericErrorContext,
2094 "xmlRemoveProp : attribute not owned by its node\n");
2095#endif
2096 return(-1);
2097}
Daniel Veillard652327a2003-09-29 18:02:38 +00002098#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002099
2100/**
2101 * xmlNewPI:
2102 * @name: the processing instruction name
2103 * @content: the PI content
2104 *
2105 * Creation of a processing instruction element.
2106 * Returns a pointer to the new node object.
2107 */
2108xmlNodePtr
2109xmlNewPI(const xmlChar *name, const xmlChar *content) {
2110 xmlNodePtr cur;
2111
2112 if (name == NULL) {
2113#ifdef DEBUG_TREE
2114 xmlGenericError(xmlGenericErrorContext,
2115 "xmlNewPI : name == NULL\n");
2116#endif
2117 return(NULL);
2118 }
2119
2120 /*
2121 * Allocate a new node and fill the fields.
2122 */
2123 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2124 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002125 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002126 return(NULL);
2127 }
2128 memset(cur, 0, sizeof(xmlNode));
2129 cur->type = XML_PI_NODE;
2130
2131 cur->name = xmlStrdup(name);
2132 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002133 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002134 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002135
Daniel Veillarda880b122003-04-21 21:36:41 +00002136 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002137 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002138 return(cur);
2139}
2140
2141/**
2142 * xmlNewNode:
2143 * @ns: namespace if any
2144 * @name: the node name
2145 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002146 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002147 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002148 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2149 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002150 */
2151xmlNodePtr
2152xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2153 xmlNodePtr cur;
2154
2155 if (name == NULL) {
2156#ifdef DEBUG_TREE
2157 xmlGenericError(xmlGenericErrorContext,
2158 "xmlNewNode : name == NULL\n");
2159#endif
2160 return(NULL);
2161 }
2162
2163 /*
2164 * Allocate a new node and fill the fields.
2165 */
2166 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2167 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002168 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002169 return(NULL);
2170 }
2171 memset(cur, 0, sizeof(xmlNode));
2172 cur->type = XML_ELEMENT_NODE;
2173
2174 cur->name = xmlStrdup(name);
2175 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002176
Daniel Veillarda880b122003-04-21 21:36:41 +00002177 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002178 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002179 return(cur);
2180}
2181
2182/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002183 * xmlNewNodeEatName:
2184 * @ns: namespace if any
2185 * @name: the node name
2186 *
2187 * Creation of a new node element. @ns is optional (NULL).
2188 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002189 * Returns a pointer to the new node object, with pointer @name as
2190 * new node's name. Use xmlNewNode() if a copy of @name string is
2191 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002192 */
2193xmlNodePtr
2194xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2195 xmlNodePtr cur;
2196
2197 if (name == NULL) {
2198#ifdef DEBUG_TREE
2199 xmlGenericError(xmlGenericErrorContext,
2200 "xmlNewNode : name == NULL\n");
2201#endif
2202 return(NULL);
2203 }
2204
2205 /*
2206 * Allocate a new node and fill the fields.
2207 */
2208 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2209 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002210 xmlTreeErrMemory("building node");
Daniel Veillard46de64e2002-05-29 08:21:33 +00002211 return(NULL);
2212 }
2213 memset(cur, 0, sizeof(xmlNode));
2214 cur->type = XML_ELEMENT_NODE;
2215
2216 cur->name = name;
2217 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002218
Daniel Veillarda880b122003-04-21 21:36:41 +00002219 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002220 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002221 return(cur);
2222}
2223
2224/**
Owen Taylor3473f882001-02-23 17:55:21 +00002225 * xmlNewDocNode:
2226 * @doc: the document
2227 * @ns: namespace if any
2228 * @name: the node name
2229 * @content: the XML text content if any
2230 *
2231 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002232 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002233 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2234 * references, but XML special chars need to be escaped first by using
2235 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2236 * need entities support.
2237 *
2238 * Returns a pointer to the new node object.
2239 */
2240xmlNodePtr
2241xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2242 const xmlChar *name, const xmlChar *content) {
2243 xmlNodePtr cur;
2244
2245 cur = xmlNewNode(ns, name);
2246 if (cur != NULL) {
2247 cur->doc = doc;
2248 if (content != NULL) {
2249 cur->children = xmlStringGetNodeList(doc, content);
2250 UPDATE_LAST_CHILD_AND_PARENT(cur)
2251 }
2252 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002253
Owen Taylor3473f882001-02-23 17:55:21 +00002254 return(cur);
2255}
2256
Daniel Veillard46de64e2002-05-29 08:21:33 +00002257/**
2258 * xmlNewDocNodeEatName:
2259 * @doc: the document
2260 * @ns: namespace if any
2261 * @name: the node name
2262 * @content: the XML text content if any
2263 *
2264 * Creation of a new node element within a document. @ns and @content
2265 * are optional (NULL).
2266 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2267 * references, but XML special chars need to be escaped first by using
2268 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2269 * need entities support.
2270 *
2271 * Returns a pointer to the new node object.
2272 */
2273xmlNodePtr
2274xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2275 xmlChar *name, const xmlChar *content) {
2276 xmlNodePtr cur;
2277
2278 cur = xmlNewNodeEatName(ns, name);
2279 if (cur != NULL) {
2280 cur->doc = doc;
2281 if (content != NULL) {
2282 cur->children = xmlStringGetNodeList(doc, content);
2283 UPDATE_LAST_CHILD_AND_PARENT(cur)
2284 }
2285 }
2286 return(cur);
2287}
2288
Daniel Veillard652327a2003-09-29 18:02:38 +00002289#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002290/**
2291 * xmlNewDocRawNode:
2292 * @doc: the document
2293 * @ns: namespace if any
2294 * @name: the node name
2295 * @content: the text content if any
2296 *
2297 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002298 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002299 *
2300 * Returns a pointer to the new node object.
2301 */
2302xmlNodePtr
2303xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2304 const xmlChar *name, const xmlChar *content) {
2305 xmlNodePtr cur;
2306
2307 cur = xmlNewNode(ns, name);
2308 if (cur != NULL) {
2309 cur->doc = doc;
2310 if (content != NULL) {
2311 cur->children = xmlNewDocText(doc, content);
2312 UPDATE_LAST_CHILD_AND_PARENT(cur)
2313 }
2314 }
2315 return(cur);
2316}
2317
2318/**
2319 * xmlNewDocFragment:
2320 * @doc: the document owning the fragment
2321 *
2322 * Creation of a new Fragment node.
2323 * Returns a pointer to the new node object.
2324 */
2325xmlNodePtr
2326xmlNewDocFragment(xmlDocPtr doc) {
2327 xmlNodePtr cur;
2328
2329 /*
2330 * Allocate a new DocumentFragment node and fill the fields.
2331 */
2332 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2333 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002334 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002335 return(NULL);
2336 }
2337 memset(cur, 0, sizeof(xmlNode));
2338 cur->type = XML_DOCUMENT_FRAG_NODE;
2339
2340 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002341
Daniel Veillarda880b122003-04-21 21:36:41 +00002342 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002343 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002344 return(cur);
2345}
Daniel Veillard652327a2003-09-29 18:02:38 +00002346#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002347
2348/**
2349 * xmlNewText:
2350 * @content: the text content
2351 *
2352 * Creation of a new text node.
2353 * Returns a pointer to the new node object.
2354 */
2355xmlNodePtr
2356xmlNewText(const xmlChar *content) {
2357 xmlNodePtr cur;
2358
2359 /*
2360 * Allocate a new node and fill the fields.
2361 */
2362 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2363 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002364 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002365 return(NULL);
2366 }
2367 memset(cur, 0, sizeof(xmlNode));
2368 cur->type = XML_TEXT_NODE;
2369
2370 cur->name = xmlStringText;
2371 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002372 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002373 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002374
Daniel Veillarda880b122003-04-21 21:36:41 +00002375 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002376 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002377 return(cur);
2378}
2379
Daniel Veillard652327a2003-09-29 18:02:38 +00002380#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002381/**
2382 * xmlNewTextChild:
2383 * @parent: the parent node
2384 * @ns: a namespace if any
2385 * @name: the name of the child
2386 * @content: the text content of the child if any.
2387 *
2388 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002389 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2390 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002391 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002392 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2393 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2394 * reserved XML chars that might appear in @content, such as the ampersand,
2395 * greater-than or less-than signs, are automatically replaced by their XML
2396 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002397 *
2398 * Returns a pointer to the new node object.
2399 */
2400xmlNodePtr
2401xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2402 const xmlChar *name, const xmlChar *content) {
2403 xmlNodePtr cur, prev;
2404
2405 if (parent == NULL) {
2406#ifdef DEBUG_TREE
2407 xmlGenericError(xmlGenericErrorContext,
2408 "xmlNewTextChild : parent == NULL\n");
2409#endif
2410 return(NULL);
2411 }
2412
2413 if (name == NULL) {
2414#ifdef DEBUG_TREE
2415 xmlGenericError(xmlGenericErrorContext,
2416 "xmlNewTextChild : name == NULL\n");
2417#endif
2418 return(NULL);
2419 }
2420
2421 /*
2422 * Allocate a new node
2423 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002424 if (parent->type == XML_ELEMENT_NODE) {
2425 if (ns == NULL)
2426 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2427 else
2428 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2429 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2430 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2431 if (ns == NULL)
2432 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2433 else
2434 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2435 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2436 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2437 } else {
2438 return(NULL);
2439 }
Owen Taylor3473f882001-02-23 17:55:21 +00002440 if (cur == NULL) return(NULL);
2441
2442 /*
2443 * add the new element at the end of the children list.
2444 */
2445 cur->type = XML_ELEMENT_NODE;
2446 cur->parent = parent;
2447 cur->doc = parent->doc;
2448 if (parent->children == NULL) {
2449 parent->children = cur;
2450 parent->last = cur;
2451 } else {
2452 prev = parent->last;
2453 prev->next = cur;
2454 cur->prev = prev;
2455 parent->last = cur;
2456 }
2457
2458 return(cur);
2459}
Daniel Veillard652327a2003-09-29 18:02:38 +00002460#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002461
2462/**
2463 * xmlNewCharRef:
2464 * @doc: the document
2465 * @name: the char ref string, starting with # or "&# ... ;"
2466 *
2467 * Creation of a new character reference node.
2468 * Returns a pointer to the new node object.
2469 */
2470xmlNodePtr
2471xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2472 xmlNodePtr cur;
2473
2474 /*
2475 * Allocate a new node and fill the fields.
2476 */
2477 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2478 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002479 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002480 return(NULL);
2481 }
2482 memset(cur, 0, sizeof(xmlNode));
2483 cur->type = XML_ENTITY_REF_NODE;
2484
2485 cur->doc = doc;
2486 if (name[0] == '&') {
2487 int len;
2488 name++;
2489 len = xmlStrlen(name);
2490 if (name[len - 1] == ';')
2491 cur->name = xmlStrndup(name, len - 1);
2492 else
2493 cur->name = xmlStrndup(name, len);
2494 } else
2495 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002496
Daniel Veillarda880b122003-04-21 21:36:41 +00002497 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002498 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002499 return(cur);
2500}
2501
2502/**
2503 * xmlNewReference:
2504 * @doc: the document
2505 * @name: the reference name, or the reference string with & and ;
2506 *
2507 * Creation of a new reference node.
2508 * Returns a pointer to the new node object.
2509 */
2510xmlNodePtr
2511xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2512 xmlNodePtr cur;
2513 xmlEntityPtr ent;
2514
2515 /*
2516 * Allocate a new node and fill the fields.
2517 */
2518 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2519 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002520 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002521 return(NULL);
2522 }
2523 memset(cur, 0, sizeof(xmlNode));
2524 cur->type = XML_ENTITY_REF_NODE;
2525
2526 cur->doc = doc;
2527 if (name[0] == '&') {
2528 int len;
2529 name++;
2530 len = xmlStrlen(name);
2531 if (name[len - 1] == ';')
2532 cur->name = xmlStrndup(name, len - 1);
2533 else
2534 cur->name = xmlStrndup(name, len);
2535 } else
2536 cur->name = xmlStrdup(name);
2537
2538 ent = xmlGetDocEntity(doc, cur->name);
2539 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002540 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002541 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002542 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002543 * updated. Not sure if this is 100% correct.
2544 * -George
2545 */
2546 cur->children = (xmlNodePtr) ent;
2547 cur->last = (xmlNodePtr) ent;
2548 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002549
Daniel Veillarda880b122003-04-21 21:36:41 +00002550 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002551 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002552 return(cur);
2553}
2554
2555/**
2556 * xmlNewDocText:
2557 * @doc: the document
2558 * @content: the text content
2559 *
2560 * Creation of a new text node within a document.
2561 * Returns a pointer to the new node object.
2562 */
2563xmlNodePtr
2564xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2565 xmlNodePtr cur;
2566
2567 cur = xmlNewText(content);
2568 if (cur != NULL) cur->doc = doc;
2569 return(cur);
2570}
2571
2572/**
2573 * xmlNewTextLen:
2574 * @content: the text content
2575 * @len: the text len.
2576 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002577 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002578 * Returns a pointer to the new node object.
2579 */
2580xmlNodePtr
2581xmlNewTextLen(const xmlChar *content, int len) {
2582 xmlNodePtr cur;
2583
2584 /*
2585 * Allocate a new node and fill the fields.
2586 */
2587 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2588 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002589 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002590 return(NULL);
2591 }
2592 memset(cur, 0, sizeof(xmlNode));
2593 cur->type = XML_TEXT_NODE;
2594
2595 cur->name = xmlStringText;
2596 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002597 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002598 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002599
Daniel Veillarda880b122003-04-21 21:36:41 +00002600 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002601 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002602 return(cur);
2603}
2604
2605/**
2606 * xmlNewDocTextLen:
2607 * @doc: the document
2608 * @content: the text content
2609 * @len: the text len.
2610 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002611 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002612 * text node pertain to a given document.
2613 * Returns a pointer to the new node object.
2614 */
2615xmlNodePtr
2616xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2617 xmlNodePtr cur;
2618
2619 cur = xmlNewTextLen(content, len);
2620 if (cur != NULL) cur->doc = doc;
2621 return(cur);
2622}
2623
2624/**
2625 * xmlNewComment:
2626 * @content: the comment content
2627 *
2628 * Creation of a new node containing a comment.
2629 * Returns a pointer to the new node object.
2630 */
2631xmlNodePtr
2632xmlNewComment(const xmlChar *content) {
2633 xmlNodePtr cur;
2634
2635 /*
2636 * Allocate a new node and fill the fields.
2637 */
2638 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2639 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002640 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002641 return(NULL);
2642 }
2643 memset(cur, 0, sizeof(xmlNode));
2644 cur->type = XML_COMMENT_NODE;
2645
2646 cur->name = xmlStringComment;
2647 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002648 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002649 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002650
Daniel Veillarda880b122003-04-21 21:36:41 +00002651 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002652 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002653 return(cur);
2654}
2655
2656/**
2657 * xmlNewCDataBlock:
2658 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002659 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002660 * @len: the length of the block
2661 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002662 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002663 * Returns a pointer to the new node object.
2664 */
2665xmlNodePtr
2666xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2667 xmlNodePtr cur;
2668
2669 /*
2670 * Allocate a new node and fill the fields.
2671 */
2672 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2673 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002674 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002675 return(NULL);
2676 }
2677 memset(cur, 0, sizeof(xmlNode));
2678 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002679 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002680
2681 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002682 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002683 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002684
Daniel Veillarda880b122003-04-21 21:36:41 +00002685 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002686 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002687 return(cur);
2688}
2689
2690/**
2691 * xmlNewDocComment:
2692 * @doc: the document
2693 * @content: the comment content
2694 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002695 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002696 * Returns a pointer to the new node object.
2697 */
2698xmlNodePtr
2699xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2700 xmlNodePtr cur;
2701
2702 cur = xmlNewComment(content);
2703 if (cur != NULL) cur->doc = doc;
2704 return(cur);
2705}
2706
2707/**
2708 * xmlSetTreeDoc:
2709 * @tree: the top element
2710 * @doc: the document
2711 *
2712 * update all nodes under the tree to point to the right document
2713 */
2714void
2715xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002716 xmlAttrPtr prop;
2717
Owen Taylor3473f882001-02-23 17:55:21 +00002718 if (tree == NULL)
2719 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002720 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002721 if(tree->type == XML_ELEMENT_NODE) {
2722 prop = tree->properties;
2723 while (prop != NULL) {
2724 prop->doc = doc;
2725 xmlSetListDoc(prop->children, doc);
2726 prop = prop->next;
2727 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002728 }
Owen Taylor3473f882001-02-23 17:55:21 +00002729 if (tree->children != NULL)
2730 xmlSetListDoc(tree->children, doc);
2731 tree->doc = doc;
2732 }
2733}
2734
2735/**
2736 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002737 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002738 * @doc: the document
2739 *
2740 * update all nodes in the list to point to the right document
2741 */
2742void
2743xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2744 xmlNodePtr cur;
2745
2746 if (list == NULL)
2747 return;
2748 cur = list;
2749 while (cur != NULL) {
2750 if (cur->doc != doc)
2751 xmlSetTreeDoc(cur, doc);
2752 cur = cur->next;
2753 }
2754}
2755
Daniel Veillard2156d432004-03-04 15:59:36 +00002756#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002757/**
2758 * xmlNewChild:
2759 * @parent: the parent node
2760 * @ns: a namespace if any
2761 * @name: the name of the child
2762 * @content: the XML content of the child if any.
2763 *
2764 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002765 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2766 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002767 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002768 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2769 * references. XML special chars must be escaped first by using
2770 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002771 *
2772 * Returns a pointer to the new node object.
2773 */
2774xmlNodePtr
2775xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2776 const xmlChar *name, const xmlChar *content) {
2777 xmlNodePtr cur, prev;
2778
2779 if (parent == NULL) {
2780#ifdef DEBUG_TREE
2781 xmlGenericError(xmlGenericErrorContext,
2782 "xmlNewChild : parent == NULL\n");
2783#endif
2784 return(NULL);
2785 }
2786
2787 if (name == NULL) {
2788#ifdef DEBUG_TREE
2789 xmlGenericError(xmlGenericErrorContext,
2790 "xmlNewChild : name == NULL\n");
2791#endif
2792 return(NULL);
2793 }
2794
2795 /*
2796 * Allocate a new node
2797 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002798 if (parent->type == XML_ELEMENT_NODE) {
2799 if (ns == NULL)
2800 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2801 else
2802 cur = xmlNewDocNode(parent->doc, ns, name, content);
2803 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2804 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2805 if (ns == NULL)
2806 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2807 else
2808 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002809 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2810 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002811 } else {
2812 return(NULL);
2813 }
Owen Taylor3473f882001-02-23 17:55:21 +00002814 if (cur == NULL) return(NULL);
2815
2816 /*
2817 * add the new element at the end of the children list.
2818 */
2819 cur->type = XML_ELEMENT_NODE;
2820 cur->parent = parent;
2821 cur->doc = parent->doc;
2822 if (parent->children == NULL) {
2823 parent->children = cur;
2824 parent->last = cur;
2825 } else {
2826 prev = parent->last;
2827 prev->next = cur;
2828 cur->prev = prev;
2829 parent->last = cur;
2830 }
2831
2832 return(cur);
2833}
Daniel Veillard652327a2003-09-29 18:02:38 +00002834#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002835
2836/**
2837 * xmlAddNextSibling:
2838 * @cur: the child node
2839 * @elem: the new node
2840 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002841 * Add a new node @elem as the next sibling of @cur
2842 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002843 * first unlinked from its existing context.
2844 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002845 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2846 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002847 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002848 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002849 */
2850xmlNodePtr
2851xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2852 if (cur == NULL) {
2853#ifdef DEBUG_TREE
2854 xmlGenericError(xmlGenericErrorContext,
2855 "xmlAddNextSibling : cur == NULL\n");
2856#endif
2857 return(NULL);
2858 }
2859 if (elem == NULL) {
2860#ifdef DEBUG_TREE
2861 xmlGenericError(xmlGenericErrorContext,
2862 "xmlAddNextSibling : elem == NULL\n");
2863#endif
2864 return(NULL);
2865 }
2866
2867 xmlUnlinkNode(elem);
2868
2869 if (elem->type == XML_TEXT_NODE) {
2870 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002871 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002872 xmlFreeNode(elem);
2873 return(cur);
2874 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002875 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2876 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002877 xmlChar *tmp;
2878
2879 tmp = xmlStrdup(elem->content);
2880 tmp = xmlStrcat(tmp, cur->next->content);
2881 xmlNodeSetContent(cur->next, tmp);
2882 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002883 xmlFreeNode(elem);
2884 return(cur->next);
2885 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002886 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2887 /* check if an attribute with the same name exists */
2888 xmlAttrPtr attr;
2889
2890 if (elem->ns == NULL)
2891 attr = xmlHasProp(cur->parent, elem->name);
2892 else
2893 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2894 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2895 /* different instance, destroy it (attributes must be unique) */
2896 xmlFreeProp(attr);
2897 }
Owen Taylor3473f882001-02-23 17:55:21 +00002898 }
2899
2900 if (elem->doc != cur->doc) {
2901 xmlSetTreeDoc(elem, cur->doc);
2902 }
2903 elem->parent = cur->parent;
2904 elem->prev = cur;
2905 elem->next = cur->next;
2906 cur->next = elem;
2907 if (elem->next != NULL)
2908 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002909 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002910 elem->parent->last = elem;
2911 return(elem);
2912}
2913
Daniel Veillard2156d432004-03-04 15:59:36 +00002914#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002915/**
2916 * xmlAddPrevSibling:
2917 * @cur: the child node
2918 * @elem: the new node
2919 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002920 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002921 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002922 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002923 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002924 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2925 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002926 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002927 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002928 */
2929xmlNodePtr
2930xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2931 if (cur == NULL) {
2932#ifdef DEBUG_TREE
2933 xmlGenericError(xmlGenericErrorContext,
2934 "xmlAddPrevSibling : cur == NULL\n");
2935#endif
2936 return(NULL);
2937 }
2938 if (elem == NULL) {
2939#ifdef DEBUG_TREE
2940 xmlGenericError(xmlGenericErrorContext,
2941 "xmlAddPrevSibling : elem == NULL\n");
2942#endif
2943 return(NULL);
2944 }
2945
2946 xmlUnlinkNode(elem);
2947
2948 if (elem->type == XML_TEXT_NODE) {
2949 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002950 xmlChar *tmp;
2951
2952 tmp = xmlStrdup(elem->content);
2953 tmp = xmlStrcat(tmp, cur->content);
2954 xmlNodeSetContent(cur, tmp);
2955 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002956 xmlFreeNode(elem);
2957 return(cur);
2958 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002959 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2960 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002961 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002962 xmlFreeNode(elem);
2963 return(cur->prev);
2964 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002965 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2966 /* check if an attribute with the same name exists */
2967 xmlAttrPtr attr;
2968
2969 if (elem->ns == NULL)
2970 attr = xmlHasProp(cur->parent, elem->name);
2971 else
2972 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2973 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2974 /* different instance, destroy it (attributes must be unique) */
2975 xmlFreeProp(attr);
2976 }
Owen Taylor3473f882001-02-23 17:55:21 +00002977 }
2978
2979 if (elem->doc != cur->doc) {
2980 xmlSetTreeDoc(elem, cur->doc);
2981 }
2982 elem->parent = cur->parent;
2983 elem->next = cur;
2984 elem->prev = cur->prev;
2985 cur->prev = elem;
2986 if (elem->prev != NULL)
2987 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002988 if (elem->parent != NULL) {
2989 if (elem->type == XML_ATTRIBUTE_NODE) {
2990 if (elem->parent->properties == (xmlAttrPtr) cur) {
2991 elem->parent->properties = (xmlAttrPtr) elem;
2992 }
2993 } else {
2994 if (elem->parent->children == cur) {
2995 elem->parent->children = elem;
2996 }
2997 }
2998 }
Owen Taylor3473f882001-02-23 17:55:21 +00002999 return(elem);
3000}
Daniel Veillard652327a2003-09-29 18:02:38 +00003001#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003002
3003/**
3004 * xmlAddSibling:
3005 * @cur: the child node
3006 * @elem: the new node
3007 *
3008 * Add a new element @elem to the list of siblings of @cur
3009 * merging adjacent TEXT nodes (@elem may be freed)
3010 * If the new element was already inserted in a document it is
3011 * first unlinked from its existing context.
3012 *
3013 * Returns the new element or NULL in case of error.
3014 */
3015xmlNodePtr
3016xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
3017 xmlNodePtr parent;
3018
3019 if (cur == NULL) {
3020#ifdef DEBUG_TREE
3021 xmlGenericError(xmlGenericErrorContext,
3022 "xmlAddSibling : cur == NULL\n");
3023#endif
3024 return(NULL);
3025 }
3026
3027 if (elem == NULL) {
3028#ifdef DEBUG_TREE
3029 xmlGenericError(xmlGenericErrorContext,
3030 "xmlAddSibling : elem == NULL\n");
3031#endif
3032 return(NULL);
3033 }
3034
3035 /*
3036 * Constant time is we can rely on the ->parent->last to find
3037 * the last sibling.
3038 */
3039 if ((cur->parent != NULL) &&
3040 (cur->parent->children != NULL) &&
3041 (cur->parent->last != NULL) &&
3042 (cur->parent->last->next == NULL)) {
3043 cur = cur->parent->last;
3044 } else {
3045 while (cur->next != NULL) cur = cur->next;
3046 }
3047
3048 xmlUnlinkNode(elem);
3049
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003050 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3051 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003052 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003053 xmlFreeNode(elem);
3054 return(cur);
3055 }
3056
3057 if (elem->doc != cur->doc) {
3058 xmlSetTreeDoc(elem, cur->doc);
3059 }
3060 parent = cur->parent;
3061 elem->prev = cur;
3062 elem->next = NULL;
3063 elem->parent = parent;
3064 cur->next = elem;
3065 if (parent != NULL)
3066 parent->last = elem;
3067
3068 return(elem);
3069}
3070
3071/**
3072 * xmlAddChildList:
3073 * @parent: the parent node
3074 * @cur: the first node in the list
3075 *
3076 * Add a list of node at the end of the child list of the parent
3077 * merging adjacent TEXT nodes (@cur may be freed)
3078 *
3079 * Returns the last child or NULL in case of error.
3080 */
3081xmlNodePtr
3082xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3083 xmlNodePtr prev;
3084
3085 if (parent == NULL) {
3086#ifdef DEBUG_TREE
3087 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003088 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003089#endif
3090 return(NULL);
3091 }
3092
3093 if (cur == NULL) {
3094#ifdef DEBUG_TREE
3095 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003096 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003097#endif
3098 return(NULL);
3099 }
3100
3101 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3102 (cur->doc != parent->doc)) {
3103#ifdef DEBUG_TREE
3104 xmlGenericError(xmlGenericErrorContext,
3105 "Elements moved to a different document\n");
3106#endif
3107 }
3108
3109 /*
3110 * add the first element at the end of the children list.
3111 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003112
Owen Taylor3473f882001-02-23 17:55:21 +00003113 if (parent->children == NULL) {
3114 parent->children = cur;
3115 } else {
3116 /*
3117 * If cur and parent->last both are TEXT nodes, then merge them.
3118 */
3119 if ((cur->type == XML_TEXT_NODE) &&
3120 (parent->last->type == XML_TEXT_NODE) &&
3121 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003122 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003123 /*
3124 * if it's the only child, nothing more to be done.
3125 */
3126 if (cur->next == NULL) {
3127 xmlFreeNode(cur);
3128 return(parent->last);
3129 }
3130 prev = cur;
3131 cur = cur->next;
3132 xmlFreeNode(prev);
3133 }
3134 prev = parent->last;
3135 prev->next = cur;
3136 cur->prev = prev;
3137 }
3138 while (cur->next != NULL) {
3139 cur->parent = parent;
3140 if (cur->doc != parent->doc) {
3141 xmlSetTreeDoc(cur, parent->doc);
3142 }
3143 cur = cur->next;
3144 }
3145 cur->parent = parent;
3146 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3147 parent->last = cur;
3148
3149 return(cur);
3150}
3151
3152/**
3153 * xmlAddChild:
3154 * @parent: the parent node
3155 * @cur: the child node
3156 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003157 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003158 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003159 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3160 * If there is an attribute with equal name, it is first destroyed.
3161 *
Owen Taylor3473f882001-02-23 17:55:21 +00003162 * Returns the child or NULL in case of error.
3163 */
3164xmlNodePtr
3165xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3166 xmlNodePtr prev;
3167
3168 if (parent == NULL) {
3169#ifdef DEBUG_TREE
3170 xmlGenericError(xmlGenericErrorContext,
3171 "xmlAddChild : parent == NULL\n");
3172#endif
3173 return(NULL);
3174 }
3175
3176 if (cur == NULL) {
3177#ifdef DEBUG_TREE
3178 xmlGenericError(xmlGenericErrorContext,
3179 "xmlAddChild : child == NULL\n");
3180#endif
3181 return(NULL);
3182 }
3183
Owen Taylor3473f882001-02-23 17:55:21 +00003184 /*
3185 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003186 * cur is then freed.
3187 */
3188 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003189 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003190 (parent->content != NULL) &&
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003191 (parent->name == cur->name) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003192 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003193 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003194 xmlFreeNode(cur);
3195 return(parent);
3196 }
3197 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003198 (parent->last->name == cur->name) &&
3199 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003200 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003201 xmlFreeNode(cur);
3202 return(parent->last);
3203 }
3204 }
3205
3206 /*
3207 * add the new element at the end of the children list.
3208 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003209 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003210 cur->parent = parent;
3211 if (cur->doc != parent->doc) {
3212 xmlSetTreeDoc(cur, parent->doc);
3213 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003214 /* this check prevents a loop on tree-traversions if a developer
3215 * tries to add a node to its parent multiple times
3216 */
3217 if (prev == parent)
3218 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003219
3220 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003221 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003222 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003223 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003224 (parent->content != NULL) &&
3225 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003226 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003227 xmlFreeNode(cur);
3228 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003229 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003230 if (cur->type == XML_ATTRIBUTE_NODE) {
3231 if (parent->properties == NULL) {
3232 parent->properties = (xmlAttrPtr) cur;
3233 } else {
3234 /* check if an attribute with the same name exists */
3235 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003236
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003237 if (cur->ns == NULL)
3238 lastattr = xmlHasProp(parent, cur->name);
3239 else
3240 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3241 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3242 /* different instance, destroy it (attributes must be unique) */
3243 xmlFreeProp(lastattr);
3244 }
3245 /* find the end */
3246 lastattr = parent->properties;
3247 while (lastattr->next != NULL) {
3248 lastattr = lastattr->next;
3249 }
3250 lastattr->next = (xmlAttrPtr) cur;
3251 ((xmlAttrPtr) cur)->prev = lastattr;
3252 }
3253 } else {
3254 if (parent->children == NULL) {
3255 parent->children = cur;
3256 parent->last = cur;
3257 } else {
3258 prev = parent->last;
3259 prev->next = cur;
3260 cur->prev = prev;
3261 parent->last = cur;
3262 }
3263 }
Owen Taylor3473f882001-02-23 17:55:21 +00003264 return(cur);
3265}
3266
3267/**
3268 * xmlGetLastChild:
3269 * @parent: the parent node
3270 *
3271 * Search the last child of a node.
3272 * Returns the last child or NULL if none.
3273 */
3274xmlNodePtr
3275xmlGetLastChild(xmlNodePtr parent) {
3276 if (parent == NULL) {
3277#ifdef DEBUG_TREE
3278 xmlGenericError(xmlGenericErrorContext,
3279 "xmlGetLastChild : parent == NULL\n");
3280#endif
3281 return(NULL);
3282 }
3283 return(parent->last);
3284}
3285
3286/**
3287 * xmlFreeNodeList:
3288 * @cur: the first node in the list
3289 *
3290 * Free a node and all its siblings, this is a recursive behaviour, all
3291 * the children are freed too.
3292 */
3293void
3294xmlFreeNodeList(xmlNodePtr cur) {
3295 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003296 xmlDictPtr dict = NULL;
3297
3298 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003299 if (cur->type == XML_NAMESPACE_DECL) {
3300 xmlFreeNsList((xmlNsPtr) cur);
3301 return;
3302 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003303 if ((cur->type == XML_DOCUMENT_NODE) ||
3304#ifdef LIBXML_DOCB_ENABLED
3305 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003306#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003307 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003308 xmlFreeDoc((xmlDocPtr) cur);
3309 return;
3310 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003311 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003312 while (cur != NULL) {
3313 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003314 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003315
Daniel Veillarda880b122003-04-21 21:36:41 +00003316 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003317 xmlDeregisterNodeDefaultValue(cur);
3318
Daniel Veillard02141ea2001-04-30 11:46:40 +00003319 if ((cur->children != NULL) &&
3320 (cur->type != XML_ENTITY_REF_NODE))
3321 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003322 if (((cur->type == XML_ELEMENT_NODE) ||
3323 (cur->type == XML_XINCLUDE_START) ||
3324 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003325 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003326 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003327 if ((cur->type != XML_ELEMENT_NODE) &&
3328 (cur->type != XML_XINCLUDE_START) &&
3329 (cur->type != XML_XINCLUDE_END) &&
3330 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003331 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003332 }
3333 if (((cur->type == XML_ELEMENT_NODE) ||
3334 (cur->type == XML_XINCLUDE_START) ||
3335 (cur->type == XML_XINCLUDE_END)) &&
3336 (cur->nsDef != NULL))
3337 xmlFreeNsList(cur->nsDef);
3338
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003339 /*
3340 * When a node is a text node or a comment, it uses a global static
3341 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003342 * Otherwise the node name might come from the document's
3343 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003344 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003345 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003346 (cur->type != XML_TEXT_NODE) &&
3347 (cur->type != XML_COMMENT_NODE))
3348 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003349 xmlFree(cur);
3350 }
Owen Taylor3473f882001-02-23 17:55:21 +00003351 cur = next;
3352 }
3353}
3354
3355/**
3356 * xmlFreeNode:
3357 * @cur: the node
3358 *
3359 * Free a node, this is a recursive behaviour, all the children are freed too.
3360 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3361 */
3362void
3363xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003364 xmlDictPtr dict = NULL;
3365
3366 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003367
Daniel Veillard02141ea2001-04-30 11:46:40 +00003368 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003369 if (cur->type == XML_DTD_NODE) {
3370 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003371 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003372 }
3373 if (cur->type == XML_NAMESPACE_DECL) {
3374 xmlFreeNs((xmlNsPtr) cur);
3375 return;
3376 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003377 if (cur->type == XML_ATTRIBUTE_NODE) {
3378 xmlFreeProp((xmlAttrPtr) cur);
3379 return;
3380 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003381
Daniel Veillarda880b122003-04-21 21:36:41 +00003382 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003383 xmlDeregisterNodeDefaultValue(cur);
3384
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003385 if (cur->doc != NULL) dict = cur->doc->dict;
3386
Owen Taylor3473f882001-02-23 17:55:21 +00003387 if ((cur->children != NULL) &&
3388 (cur->type != XML_ENTITY_REF_NODE))
3389 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003390 if (((cur->type == XML_ELEMENT_NODE) ||
3391 (cur->type == XML_XINCLUDE_START) ||
3392 (cur->type == XML_XINCLUDE_END)) &&
3393 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003394 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003395 if ((cur->type != XML_ELEMENT_NODE) &&
3396 (cur->content != NULL) &&
3397 (cur->type != XML_ENTITY_REF_NODE) &&
3398 (cur->type != XML_XINCLUDE_END) &&
3399 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003400 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003401 }
3402
Daniel Veillardacd370f2001-06-09 17:17:51 +00003403 /*
3404 * When a node is a text node or a comment, it uses a global static
3405 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003406 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003407 */
Owen Taylor3473f882001-02-23 17:55:21 +00003408 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003409 (cur->type != XML_TEXT_NODE) &&
3410 (cur->type != XML_COMMENT_NODE))
3411 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003412
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003413 if (((cur->type == XML_ELEMENT_NODE) ||
3414 (cur->type == XML_XINCLUDE_START) ||
3415 (cur->type == XML_XINCLUDE_END)) &&
3416 (cur->nsDef != NULL))
3417 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003418 xmlFree(cur);
3419}
3420
3421/**
3422 * xmlUnlinkNode:
3423 * @cur: the node
3424 *
3425 * Unlink a node from it's current context, the node is not freed
3426 */
3427void
3428xmlUnlinkNode(xmlNodePtr cur) {
3429 if (cur == NULL) {
3430#ifdef DEBUG_TREE
3431 xmlGenericError(xmlGenericErrorContext,
3432 "xmlUnlinkNode : node == NULL\n");
3433#endif
3434 return;
3435 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003436 if (cur->type == XML_DTD_NODE) {
3437 xmlDocPtr doc;
3438 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003439 if (doc != NULL) {
3440 if (doc->intSubset == (xmlDtdPtr) cur)
3441 doc->intSubset = NULL;
3442 if (doc->extSubset == (xmlDtdPtr) cur)
3443 doc->extSubset = NULL;
3444 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003445 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003446 if (cur->parent != NULL) {
3447 xmlNodePtr parent;
3448 parent = cur->parent;
3449 if (cur->type == XML_ATTRIBUTE_NODE) {
3450 if (parent->properties == (xmlAttrPtr) cur)
3451 parent->properties = ((xmlAttrPtr) cur)->next;
3452 } else {
3453 if (parent->children == cur)
3454 parent->children = cur->next;
3455 if (parent->last == cur)
3456 parent->last = cur->prev;
3457 }
3458 cur->parent = NULL;
3459 }
Owen Taylor3473f882001-02-23 17:55:21 +00003460 if (cur->next != NULL)
3461 cur->next->prev = cur->prev;
3462 if (cur->prev != NULL)
3463 cur->prev->next = cur->next;
3464 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003465}
3466
Daniel Veillard2156d432004-03-04 15:59:36 +00003467#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003468/**
3469 * xmlReplaceNode:
3470 * @old: the old node
3471 * @cur: the node
3472 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003473 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003474 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003475 * first unlinked from its existing context.
3476 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003477 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003478 */
3479xmlNodePtr
3480xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3481 if (old == NULL) {
3482#ifdef DEBUG_TREE
3483 xmlGenericError(xmlGenericErrorContext,
3484 "xmlReplaceNode : old == NULL\n");
3485#endif
3486 return(NULL);
3487 }
3488 if (cur == NULL) {
3489 xmlUnlinkNode(old);
3490 return(old);
3491 }
3492 if (cur == old) {
3493 return(old);
3494 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003495 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3496#ifdef DEBUG_TREE
3497 xmlGenericError(xmlGenericErrorContext,
3498 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3499#endif
3500 return(old);
3501 }
3502 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3503#ifdef DEBUG_TREE
3504 xmlGenericError(xmlGenericErrorContext,
3505 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3506#endif
3507 return(old);
3508 }
Owen Taylor3473f882001-02-23 17:55:21 +00003509 xmlUnlinkNode(cur);
3510 cur->doc = old->doc;
3511 cur->parent = old->parent;
3512 cur->next = old->next;
3513 if (cur->next != NULL)
3514 cur->next->prev = cur;
3515 cur->prev = old->prev;
3516 if (cur->prev != NULL)
3517 cur->prev->next = cur;
3518 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003519 if (cur->type == XML_ATTRIBUTE_NODE) {
3520 if (cur->parent->properties == (xmlAttrPtr)old)
3521 cur->parent->properties = ((xmlAttrPtr) cur);
3522 } else {
3523 if (cur->parent->children == old)
3524 cur->parent->children = cur;
3525 if (cur->parent->last == old)
3526 cur->parent->last = cur;
3527 }
Owen Taylor3473f882001-02-23 17:55:21 +00003528 }
3529 old->next = old->prev = NULL;
3530 old->parent = NULL;
3531 return(old);
3532}
Daniel Veillard652327a2003-09-29 18:02:38 +00003533#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003534
3535/************************************************************************
3536 * *
3537 * Copy operations *
3538 * *
3539 ************************************************************************/
3540
3541/**
3542 * xmlCopyNamespace:
3543 * @cur: the namespace
3544 *
3545 * Do a copy of the namespace.
3546 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003547 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003548 */
3549xmlNsPtr
3550xmlCopyNamespace(xmlNsPtr cur) {
3551 xmlNsPtr ret;
3552
3553 if (cur == NULL) return(NULL);
3554 switch (cur->type) {
3555 case XML_LOCAL_NAMESPACE:
3556 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3557 break;
3558 default:
3559#ifdef DEBUG_TREE
3560 xmlGenericError(xmlGenericErrorContext,
3561 "xmlCopyNamespace: invalid type %d\n", cur->type);
3562#endif
3563 return(NULL);
3564 }
3565 return(ret);
3566}
3567
3568/**
3569 * xmlCopyNamespaceList:
3570 * @cur: the first namespace
3571 *
3572 * Do a copy of an namespace list.
3573 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003574 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003575 */
3576xmlNsPtr
3577xmlCopyNamespaceList(xmlNsPtr cur) {
3578 xmlNsPtr ret = NULL;
3579 xmlNsPtr p = NULL,q;
3580
3581 while (cur != NULL) {
3582 q = xmlCopyNamespace(cur);
3583 if (p == NULL) {
3584 ret = p = q;
3585 } else {
3586 p->next = q;
3587 p = q;
3588 }
3589 cur = cur->next;
3590 }
3591 return(ret);
3592}
3593
3594static xmlNodePtr
3595xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3596/**
3597 * xmlCopyProp:
3598 * @target: the element where the attribute will be grafted
3599 * @cur: the attribute
3600 *
3601 * Do a copy of the attribute.
3602 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003603 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003604 */
3605xmlAttrPtr
3606xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3607 xmlAttrPtr ret;
3608
3609 if (cur == NULL) return(NULL);
3610 if (target != NULL)
3611 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3612 else if (cur->parent != NULL)
3613 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3614 else if (cur->children != NULL)
3615 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3616 else
3617 ret = xmlNewDocProp(NULL, cur->name, NULL);
3618 if (ret == NULL) return(NULL);
3619 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003620
Owen Taylor3473f882001-02-23 17:55:21 +00003621 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003622 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003623
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003624 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3625 if (ns == NULL) {
3626 /*
3627 * Humm, we are copying an element whose namespace is defined
3628 * out of the new tree scope. Search it in the original tree
3629 * and add it at the top of the new tree
3630 */
3631 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3632 if (ns != NULL) {
3633 xmlNodePtr root = target;
3634 xmlNodePtr pred = NULL;
3635
3636 while (root->parent != NULL) {
3637 pred = root;
3638 root = root->parent;
3639 }
3640 if (root == (xmlNodePtr) target->doc) {
3641 /* correct possibly cycling above the document elt */
3642 root = pred;
3643 }
3644 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3645 }
3646 } else {
3647 /*
3648 * we have to find something appropriate here since
3649 * we cant be sure, that the namespce we found is identified
3650 * by the prefix
3651 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003652 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003653 /* this is the nice case */
3654 ret->ns = ns;
3655 } else {
3656 /*
3657 * we are in trouble: we need a new reconcilied namespace.
3658 * This is expensive
3659 */
3660 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3661 }
3662 }
3663
Owen Taylor3473f882001-02-23 17:55:21 +00003664 } else
3665 ret->ns = NULL;
3666
3667 if (cur->children != NULL) {
3668 xmlNodePtr tmp;
3669
3670 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3671 ret->last = NULL;
3672 tmp = ret->children;
3673 while (tmp != NULL) {
3674 /* tmp->parent = (xmlNodePtr)ret; */
3675 if (tmp->next == NULL)
3676 ret->last = tmp;
3677 tmp = tmp->next;
3678 }
3679 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003680 /*
3681 * Try to handle IDs
3682 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003683 if ((target!= NULL) && (cur!= NULL) &&
3684 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003685 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3686 if (xmlIsID(cur->doc, cur->parent, cur)) {
3687 xmlChar *id;
3688
3689 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3690 if (id != NULL) {
3691 xmlAddID(NULL, target->doc, id, ret);
3692 xmlFree(id);
3693 }
3694 }
3695 }
Owen Taylor3473f882001-02-23 17:55:21 +00003696 return(ret);
3697}
3698
3699/**
3700 * xmlCopyPropList:
3701 * @target: the element where the attributes will be grafted
3702 * @cur: the first attribute
3703 *
3704 * Do a copy of an attribute list.
3705 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003706 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003707 */
3708xmlAttrPtr
3709xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3710 xmlAttrPtr ret = NULL;
3711 xmlAttrPtr p = NULL,q;
3712
3713 while (cur != NULL) {
3714 q = xmlCopyProp(target, cur);
William M. Brack13dfa872004-09-18 04:52:08 +00003715 if (q == NULL)
3716 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003717 if (p == NULL) {
3718 ret = p = q;
3719 } else {
3720 p->next = q;
3721 q->prev = p;
3722 p = q;
3723 }
3724 cur = cur->next;
3725 }
3726 return(ret);
3727}
3728
3729/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003730 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003731 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003732 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003733 * tricky reason: namespaces. Doing a direct copy of a node
3734 * say RPM:Copyright without changing the namespace pointer to
3735 * something else can produce stale links. One way to do it is
3736 * to keep a reference counter but this doesn't work as soon
3737 * as one move the element or the subtree out of the scope of
3738 * the existing namespace. The actual solution seems to add
3739 * a copy of the namespace at the top of the copied tree if
3740 * not available in the subtree.
3741 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00003742 * The argument "recursive" normally indicates a recursive copy
3743 * of the node with values 0 (no) and 1 (yes). For XInclude,
3744 * however, we allow a value of 2 to indicate copy properties and
3745 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00003746 */
3747
3748static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003749xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00003750 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003751 xmlNodePtr ret;
3752
3753 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003754 switch (node->type) {
3755 case XML_TEXT_NODE:
3756 case XML_CDATA_SECTION_NODE:
3757 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003758 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003759 case XML_ENTITY_REF_NODE:
3760 case XML_ENTITY_NODE:
3761 case XML_PI_NODE:
3762 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003763 case XML_XINCLUDE_START:
3764 case XML_XINCLUDE_END:
3765 break;
3766 case XML_ATTRIBUTE_NODE:
3767 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3768 case XML_NAMESPACE_DECL:
3769 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3770
Daniel Veillard39196eb2001-06-19 18:09:42 +00003771 case XML_DOCUMENT_NODE:
3772 case XML_HTML_DOCUMENT_NODE:
3773#ifdef LIBXML_DOCB_ENABLED
3774 case XML_DOCB_DOCUMENT_NODE:
3775#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003776#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00003777 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00003778#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003779 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003780 case XML_NOTATION_NODE:
3781 case XML_DTD_NODE:
3782 case XML_ELEMENT_DECL:
3783 case XML_ATTRIBUTE_DECL:
3784 case XML_ENTITY_DECL:
3785 return(NULL);
3786 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003787
Owen Taylor3473f882001-02-23 17:55:21 +00003788 /*
3789 * Allocate a new node and fill the fields.
3790 */
3791 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3792 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003793 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003794 return(NULL);
3795 }
3796 memset(ret, 0, sizeof(xmlNode));
3797 ret->type = node->type;
3798
3799 ret->doc = doc;
3800 ret->parent = parent;
3801 if (node->name == xmlStringText)
3802 ret->name = xmlStringText;
3803 else if (node->name == xmlStringTextNoenc)
3804 ret->name = xmlStringTextNoenc;
3805 else if (node->name == xmlStringComment)
3806 ret->name = xmlStringComment;
3807 else if (node->name != NULL)
3808 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003809 if ((node->type != XML_ELEMENT_NODE) &&
3810 (node->content != NULL) &&
3811 (node->type != XML_ENTITY_REF_NODE) &&
3812 (node->type != XML_XINCLUDE_END) &&
3813 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003814 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003815 }else{
3816 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003817 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003818 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003819 if (parent != NULL) {
3820 xmlNodePtr tmp;
3821
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003822 /*
3823 * this is a tricky part for the node register thing:
3824 * in case ret does get coalesced in xmlAddChild
3825 * the deregister-node callback is called; so we register ret now already
3826 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003827 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003828 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3829
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003830 tmp = xmlAddChild(parent, ret);
3831 /* node could have coalesced */
3832 if (tmp != ret)
3833 return(tmp);
3834 }
Owen Taylor3473f882001-02-23 17:55:21 +00003835
William M. Brack57e9e912004-03-09 16:19:02 +00003836 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003837 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003838 if (node->nsDef != NULL)
3839 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3840
3841 if (node->ns != NULL) {
3842 xmlNsPtr ns;
3843
3844 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3845 if (ns == NULL) {
3846 /*
3847 * Humm, we are copying an element whose namespace is defined
3848 * out of the new tree scope. Search it in the original tree
3849 * and add it at the top of the new tree
3850 */
3851 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3852 if (ns != NULL) {
3853 xmlNodePtr root = ret;
3854
3855 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003856 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003857 }
3858 } else {
3859 /*
3860 * reference the existing namespace definition in our own tree.
3861 */
3862 ret->ns = ns;
3863 }
3864 }
3865 if (node->properties != NULL)
3866 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003867 if (node->type == XML_ENTITY_REF_NODE) {
3868 if ((doc == NULL) || (node->doc != doc)) {
3869 /*
3870 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003871 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003872 * we cannot keep the reference. Try to find it in the
3873 * target document.
3874 */
3875 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3876 } else {
3877 ret->children = node->children;
3878 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003879 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00003880 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003881 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003882 UPDATE_LAST_CHILD_AND_PARENT(ret)
3883 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003884
3885out:
3886 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00003887 if ((parent == NULL) &&
3888 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003889 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003890 return(ret);
3891}
3892
3893static xmlNodePtr
3894xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3895 xmlNodePtr ret = NULL;
3896 xmlNodePtr p = NULL,q;
3897
3898 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003899#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003900 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003901 if (doc == NULL) {
3902 node = node->next;
3903 continue;
3904 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003905 if (doc->intSubset == NULL) {
3906 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3907 q->doc = doc;
3908 q->parent = parent;
3909 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003910 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003911 } else {
3912 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003913 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003914 }
3915 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003916#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003917 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003918 if (ret == NULL) {
3919 q->prev = NULL;
3920 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003921 } else if (p != q) {
3922 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003923 p->next = q;
3924 q->prev = p;
3925 p = q;
3926 }
3927 node = node->next;
3928 }
3929 return(ret);
3930}
3931
3932/**
3933 * xmlCopyNode:
3934 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00003935 * @extended: if 1 do a recursive copy (properties, namespaces and children
3936 * when applicable)
3937 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00003938 *
3939 * Do a copy of the node.
3940 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003941 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003942 */
3943xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003944xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003945 xmlNodePtr ret;
3946
William M. Brack57e9e912004-03-09 16:19:02 +00003947 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00003948 return(ret);
3949}
3950
3951/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003952 * xmlDocCopyNode:
3953 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003954 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00003955 * @extended: if 1 do a recursive copy (properties, namespaces and children
3956 * when applicable)
3957 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00003958 *
3959 * Do a copy of the node to a given document.
3960 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003961 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003962 */
3963xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003964xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003965 xmlNodePtr ret;
3966
William M. Brack57e9e912004-03-09 16:19:02 +00003967 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00003968 return(ret);
3969}
3970
3971/**
Owen Taylor3473f882001-02-23 17:55:21 +00003972 * xmlCopyNodeList:
3973 * @node: the first node in the list.
3974 *
3975 * Do a recursive copy of the node list.
3976 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003977 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003978 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003979xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003980 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3981 return(ret);
3982}
3983
Daniel Veillard2156d432004-03-04 15:59:36 +00003984#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003985/**
Owen Taylor3473f882001-02-23 17:55:21 +00003986 * xmlCopyDtd:
3987 * @dtd: the dtd
3988 *
3989 * Do a copy of the dtd.
3990 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003991 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003992 */
3993xmlDtdPtr
3994xmlCopyDtd(xmlDtdPtr dtd) {
3995 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003996 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003997
3998 if (dtd == NULL) return(NULL);
3999 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4000 if (ret == NULL) return(NULL);
4001 if (dtd->entities != NULL)
4002 ret->entities = (void *) xmlCopyEntitiesTable(
4003 (xmlEntitiesTablePtr) dtd->entities);
4004 if (dtd->notations != NULL)
4005 ret->notations = (void *) xmlCopyNotationTable(
4006 (xmlNotationTablePtr) dtd->notations);
4007 if (dtd->elements != NULL)
4008 ret->elements = (void *) xmlCopyElementTable(
4009 (xmlElementTablePtr) dtd->elements);
4010 if (dtd->attributes != NULL)
4011 ret->attributes = (void *) xmlCopyAttributeTable(
4012 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004013 if (dtd->pentities != NULL)
4014 ret->pentities = (void *) xmlCopyEntitiesTable(
4015 (xmlEntitiesTablePtr) dtd->pentities);
4016
4017 cur = dtd->children;
4018 while (cur != NULL) {
4019 q = NULL;
4020
4021 if (cur->type == XML_ENTITY_DECL) {
4022 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4023 switch (tmp->etype) {
4024 case XML_INTERNAL_GENERAL_ENTITY:
4025 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4026 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4027 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4028 break;
4029 case XML_INTERNAL_PARAMETER_ENTITY:
4030 case XML_EXTERNAL_PARAMETER_ENTITY:
4031 q = (xmlNodePtr)
4032 xmlGetParameterEntityFromDtd(ret, tmp->name);
4033 break;
4034 case XML_INTERNAL_PREDEFINED_ENTITY:
4035 break;
4036 }
4037 } else if (cur->type == XML_ELEMENT_DECL) {
4038 xmlElementPtr tmp = (xmlElementPtr) cur;
4039 q = (xmlNodePtr)
4040 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4041 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4042 xmlAttributePtr tmp = (xmlAttributePtr) cur;
4043 q = (xmlNodePtr)
4044 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4045 } else if (cur->type == XML_COMMENT_NODE) {
4046 q = xmlCopyNode(cur, 0);
4047 }
4048
4049 if (q == NULL) {
4050 cur = cur->next;
4051 continue;
4052 }
4053
4054 if (p == NULL)
4055 ret->children = q;
4056 else
4057 p->next = q;
4058
4059 q->prev = p;
4060 q->parent = (xmlNodePtr) ret;
4061 q->next = NULL;
4062 ret->last = q;
4063 p = q;
4064 cur = cur->next;
4065 }
4066
Owen Taylor3473f882001-02-23 17:55:21 +00004067 return(ret);
4068}
Daniel Veillard2156d432004-03-04 15:59:36 +00004069#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004070
Daniel Veillard2156d432004-03-04 15:59:36 +00004071#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004072/**
4073 * xmlCopyDoc:
4074 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004075 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004076 *
4077 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004078 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004079 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004080 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004081 */
4082xmlDocPtr
4083xmlCopyDoc(xmlDocPtr doc, int recursive) {
4084 xmlDocPtr ret;
4085
4086 if (doc == NULL) return(NULL);
4087 ret = xmlNewDoc(doc->version);
4088 if (ret == NULL) return(NULL);
4089 if (doc->name != NULL)
4090 ret->name = xmlMemStrdup(doc->name);
4091 if (doc->encoding != NULL)
4092 ret->encoding = xmlStrdup(doc->encoding);
4093 ret->charset = doc->charset;
4094 ret->compression = doc->compression;
4095 ret->standalone = doc->standalone;
4096 if (!recursive) return(ret);
4097
Daniel Veillardb33c2012001-04-25 12:59:04 +00004098 ret->last = NULL;
4099 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004100#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004101 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004102 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004103 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004104 ret->intSubset->parent = ret;
4105 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004106#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004107 if (doc->oldNs != NULL)
4108 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4109 if (doc->children != NULL) {
4110 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004111
4112 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4113 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004114 ret->last = NULL;
4115 tmp = ret->children;
4116 while (tmp != NULL) {
4117 if (tmp->next == NULL)
4118 ret->last = tmp;
4119 tmp = tmp->next;
4120 }
4121 }
4122 return(ret);
4123}
Daniel Veillard652327a2003-09-29 18:02:38 +00004124#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004125
4126/************************************************************************
4127 * *
4128 * Content access functions *
4129 * *
4130 ************************************************************************/
4131
4132/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004133 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004134 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004135 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004136 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004137 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004138 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004139 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004140 */
4141long
4142xmlGetLineNo(xmlNodePtr node)
4143{
4144 long result = -1;
4145
4146 if (!node)
4147 return result;
4148 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004149 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004150 else if ((node->prev != NULL) &&
4151 ((node->prev->type == XML_ELEMENT_NODE) ||
4152 (node->prev->type == XML_TEXT_NODE)))
4153 result = xmlGetLineNo(node->prev);
4154 else if ((node->parent != NULL) &&
4155 ((node->parent->type == XML_ELEMENT_NODE) ||
4156 (node->parent->type == XML_TEXT_NODE)))
4157 result = xmlGetLineNo(node->parent);
4158
4159 return result;
4160}
4161
Daniel Veillard2156d432004-03-04 15:59:36 +00004162#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004163/**
4164 * xmlGetNodePath:
4165 * @node: a node
4166 *
4167 * Build a structure based Path for the given node
4168 *
4169 * Returns the new path or NULL in case of error. The caller must free
4170 * the returned string
4171 */
4172xmlChar *
4173xmlGetNodePath(xmlNodePtr node)
4174{
4175 xmlNodePtr cur, tmp, next;
4176 xmlChar *buffer = NULL, *temp;
4177 size_t buf_len;
4178 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004179 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004180 const char *name;
4181 char nametemp[100];
4182 int occur = 0;
4183
4184 if (node == NULL)
4185 return (NULL);
4186
4187 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004188 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004189 if (buffer == NULL) {
4190 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004191 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004192 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004193 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004194 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004195 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004196 xmlFree(buffer);
4197 return (NULL);
4198 }
4199
4200 buffer[0] = 0;
4201 cur = node;
4202 do {
4203 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004204 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004205 occur = 0;
4206 if ((cur->type == XML_DOCUMENT_NODE) ||
4207 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4208 if (buffer[0] == '/')
4209 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004210 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004211 next = NULL;
4212 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004213 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004214 name = (const char *) cur->name;
4215 if (cur->ns) {
William M. Brack84d83e32003-12-23 03:45:17 +00004216 if (cur->ns->prefix != NULL)
William M. Brack13dfa872004-09-18 04:52:08 +00004217 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4218 (char *)cur->ns->prefix, (char *)cur->name);
William M. Brack84d83e32003-12-23 03:45:17 +00004219 else
William M. Brack13dfa872004-09-18 04:52:08 +00004220 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4221 (char *)cur->name);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004222 nametemp[sizeof(nametemp) - 1] = 0;
4223 name = nametemp;
4224 }
4225 next = cur->parent;
4226
4227 /*
4228 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004229 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004230 */
4231 tmp = cur->prev;
4232 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004233 if ((tmp->type == XML_ELEMENT_NODE) &&
4234 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004235 occur++;
4236 tmp = tmp->prev;
4237 }
4238 if (occur == 0) {
4239 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004240 while (tmp != NULL && occur == 0) {
4241 if ((tmp->type == XML_ELEMENT_NODE) &&
4242 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004243 occur++;
4244 tmp = tmp->next;
4245 }
4246 if (occur != 0)
4247 occur = 1;
4248 } else
4249 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004250 } else if (cur->type == XML_COMMENT_NODE) {
4251 sep = "/";
4252 name = "comment()";
4253 next = cur->parent;
4254
4255 /*
4256 * Thumbler index computation
4257 */
4258 tmp = cur->prev;
4259 while (tmp != NULL) {
4260 if (tmp->type == XML_COMMENT_NODE)
4261 occur++;
4262 tmp = tmp->prev;
4263 }
4264 if (occur == 0) {
4265 tmp = cur->next;
4266 while (tmp != NULL && occur == 0) {
4267 if (tmp->type == XML_COMMENT_NODE)
4268 occur++;
4269 tmp = tmp->next;
4270 }
4271 if (occur != 0)
4272 occur = 1;
4273 } else
4274 occur++;
4275 } else if ((cur->type == XML_TEXT_NODE) ||
4276 (cur->type == XML_CDATA_SECTION_NODE)) {
4277 sep = "/";
4278 name = "text()";
4279 next = cur->parent;
4280
4281 /*
4282 * Thumbler index computation
4283 */
4284 tmp = cur->prev;
4285 while (tmp != NULL) {
4286 if ((cur->type == XML_TEXT_NODE) ||
4287 (cur->type == XML_CDATA_SECTION_NODE))
4288 occur++;
4289 tmp = tmp->prev;
4290 }
4291 if (occur == 0) {
4292 tmp = cur->next;
4293 while (tmp != NULL && occur == 0) {
Daniel Veillard1f8658a2004-08-14 21:46:31 +00004294 if ((tmp->type == XML_TEXT_NODE) ||
4295 (tmp->type == XML_CDATA_SECTION_NODE))
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004296 occur++;
4297 tmp = tmp->next;
4298 }
4299 if (occur != 0)
4300 occur = 1;
4301 } else
4302 occur++;
4303 } else if (cur->type == XML_PI_NODE) {
4304 sep = "/";
4305 snprintf(nametemp, sizeof(nametemp) - 1,
William M. Brack13dfa872004-09-18 04:52:08 +00004306 "processing-instruction('%s')", (char *)cur->name);
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004307 nametemp[sizeof(nametemp) - 1] = 0;
4308 name = nametemp;
4309
4310 next = cur->parent;
4311
4312 /*
4313 * Thumbler index computation
4314 */
4315 tmp = cur->prev;
4316 while (tmp != NULL) {
4317 if ((tmp->type == XML_PI_NODE) &&
4318 (xmlStrEqual(cur->name, tmp->name)))
4319 occur++;
4320 tmp = tmp->prev;
4321 }
4322 if (occur == 0) {
4323 tmp = cur->next;
4324 while (tmp != NULL && occur == 0) {
4325 if ((tmp->type == XML_PI_NODE) &&
4326 (xmlStrEqual(cur->name, tmp->name)))
4327 occur++;
4328 tmp = tmp->next;
4329 }
4330 if (occur != 0)
4331 occur = 1;
4332 } else
4333 occur++;
4334
Daniel Veillard8faa7832001-11-26 15:58:08 +00004335 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004336 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004337 name = (const char *) (((xmlAttrPtr) cur)->name);
4338 next = ((xmlAttrPtr) cur)->parent;
4339 } else {
4340 next = cur->parent;
4341 }
4342
4343 /*
4344 * Make sure there is enough room
4345 */
4346 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4347 buf_len =
4348 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4349 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4350 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004351 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004352 xmlFree(buf);
4353 xmlFree(buffer);
4354 return (NULL);
4355 }
4356 buffer = temp;
4357 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4358 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004359 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004360 xmlFree(buf);
4361 xmlFree(buffer);
4362 return (NULL);
4363 }
4364 buf = temp;
4365 }
4366 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004367 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004368 sep, name, (char *) buffer);
4369 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004370 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004371 sep, name, occur, (char *) buffer);
William M. Brack13dfa872004-09-18 04:52:08 +00004372 snprintf((char *) buffer, buf_len, "%s", (char *)buf);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004373 cur = next;
4374 } while (cur != NULL);
4375 xmlFree(buf);
4376 return (buffer);
4377}
Daniel Veillard652327a2003-09-29 18:02:38 +00004378#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004379
4380/**
Owen Taylor3473f882001-02-23 17:55:21 +00004381 * xmlDocGetRootElement:
4382 * @doc: the document
4383 *
4384 * Get the root element of the document (doc->children is a list
4385 * containing possibly comments, PIs, etc ...).
4386 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004387 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004388 */
4389xmlNodePtr
4390xmlDocGetRootElement(xmlDocPtr doc) {
4391 xmlNodePtr ret;
4392
4393 if (doc == NULL) return(NULL);
4394 ret = doc->children;
4395 while (ret != NULL) {
4396 if (ret->type == XML_ELEMENT_NODE)
4397 return(ret);
4398 ret = ret->next;
4399 }
4400 return(ret);
4401}
4402
Daniel Veillard2156d432004-03-04 15:59:36 +00004403#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004404/**
4405 * xmlDocSetRootElement:
4406 * @doc: the document
4407 * @root: the new document root element
4408 *
4409 * Set the root element of the document (doc->children is a list
4410 * containing possibly comments, PIs, etc ...).
4411 *
4412 * Returns the old root element if any was found
4413 */
4414xmlNodePtr
4415xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4416 xmlNodePtr old = NULL;
4417
4418 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004419 if (root == NULL)
4420 return(NULL);
4421 xmlUnlinkNode(root);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00004422 xmlSetTreeDoc(root, doc);
Daniel Veillardc575b992002-02-08 13:28:40 +00004423 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004424 old = doc->children;
4425 while (old != NULL) {
4426 if (old->type == XML_ELEMENT_NODE)
4427 break;
4428 old = old->next;
4429 }
4430 if (old == NULL) {
4431 if (doc->children == NULL) {
4432 doc->children = root;
4433 doc->last = root;
4434 } else {
4435 xmlAddSibling(doc->children, root);
4436 }
4437 } else {
4438 xmlReplaceNode(old, root);
4439 }
4440 return(old);
4441}
Daniel Veillard2156d432004-03-04 15:59:36 +00004442#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004443
Daniel Veillard2156d432004-03-04 15:59:36 +00004444#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004445/**
4446 * xmlNodeSetLang:
4447 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004448 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004449 *
4450 * Set the language of a node, i.e. the values of the xml:lang
4451 * attribute.
4452 */
4453void
4454xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004455 xmlNsPtr ns;
4456
Owen Taylor3473f882001-02-23 17:55:21 +00004457 if (cur == NULL) return;
4458 switch(cur->type) {
4459 case XML_TEXT_NODE:
4460 case XML_CDATA_SECTION_NODE:
4461 case XML_COMMENT_NODE:
4462 case XML_DOCUMENT_NODE:
4463 case XML_DOCUMENT_TYPE_NODE:
4464 case XML_DOCUMENT_FRAG_NODE:
4465 case XML_NOTATION_NODE:
4466 case XML_HTML_DOCUMENT_NODE:
4467 case XML_DTD_NODE:
4468 case XML_ELEMENT_DECL:
4469 case XML_ATTRIBUTE_DECL:
4470 case XML_ENTITY_DECL:
4471 case XML_PI_NODE:
4472 case XML_ENTITY_REF_NODE:
4473 case XML_ENTITY_NODE:
4474 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004475#ifdef LIBXML_DOCB_ENABLED
4476 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004477#endif
4478 case XML_XINCLUDE_START:
4479 case XML_XINCLUDE_END:
4480 return;
4481 case XML_ELEMENT_NODE:
4482 case XML_ATTRIBUTE_NODE:
4483 break;
4484 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004485 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4486 if (ns == NULL)
4487 return;
4488 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004489}
Daniel Veillard652327a2003-09-29 18:02:38 +00004490#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004491
4492/**
4493 * xmlNodeGetLang:
4494 * @cur: the node being checked
4495 *
4496 * Searches the language of a node, i.e. the values of the xml:lang
4497 * attribute or the one carried by the nearest ancestor.
4498 *
4499 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004500 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004501 */
4502xmlChar *
4503xmlNodeGetLang(xmlNodePtr cur) {
4504 xmlChar *lang;
4505
4506 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004507 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004508 if (lang != NULL)
4509 return(lang);
4510 cur = cur->parent;
4511 }
4512 return(NULL);
4513}
4514
4515
Daniel Veillard652327a2003-09-29 18:02:38 +00004516#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004517/**
4518 * xmlNodeSetSpacePreserve:
4519 * @cur: the node being changed
4520 * @val: the xml:space value ("0": default, 1: "preserve")
4521 *
4522 * Set (or reset) the space preserving behaviour of a node, i.e. the
4523 * value of the xml:space attribute.
4524 */
4525void
4526xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004527 xmlNsPtr ns;
4528
Owen Taylor3473f882001-02-23 17:55:21 +00004529 if (cur == NULL) return;
4530 switch(cur->type) {
4531 case XML_TEXT_NODE:
4532 case XML_CDATA_SECTION_NODE:
4533 case XML_COMMENT_NODE:
4534 case XML_DOCUMENT_NODE:
4535 case XML_DOCUMENT_TYPE_NODE:
4536 case XML_DOCUMENT_FRAG_NODE:
4537 case XML_NOTATION_NODE:
4538 case XML_HTML_DOCUMENT_NODE:
4539 case XML_DTD_NODE:
4540 case XML_ELEMENT_DECL:
4541 case XML_ATTRIBUTE_DECL:
4542 case XML_ENTITY_DECL:
4543 case XML_PI_NODE:
4544 case XML_ENTITY_REF_NODE:
4545 case XML_ENTITY_NODE:
4546 case XML_NAMESPACE_DECL:
4547 case XML_XINCLUDE_START:
4548 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004549#ifdef LIBXML_DOCB_ENABLED
4550 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004551#endif
4552 return;
4553 case XML_ELEMENT_NODE:
4554 case XML_ATTRIBUTE_NODE:
4555 break;
4556 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004557 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4558 if (ns == NULL)
4559 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004560 switch (val) {
4561 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004562 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004563 break;
4564 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004565 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004566 break;
4567 }
4568}
Daniel Veillard652327a2003-09-29 18:02:38 +00004569#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004570
4571/**
4572 * xmlNodeGetSpacePreserve:
4573 * @cur: the node being checked
4574 *
4575 * Searches the space preserving behaviour of a node, i.e. the values
4576 * of the xml:space attribute or the one carried by the nearest
4577 * ancestor.
4578 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004579 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004580 */
4581int
4582xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4583 xmlChar *space;
4584
4585 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004586 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004587 if (space != NULL) {
4588 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4589 xmlFree(space);
4590 return(1);
4591 }
4592 if (xmlStrEqual(space, BAD_CAST "default")) {
4593 xmlFree(space);
4594 return(0);
4595 }
4596 xmlFree(space);
4597 }
4598 cur = cur->parent;
4599 }
4600 return(-1);
4601}
4602
Daniel Veillard652327a2003-09-29 18:02:38 +00004603#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004604/**
4605 * xmlNodeSetName:
4606 * @cur: the node being changed
4607 * @name: the new tag name
4608 *
4609 * Set (or reset) the name of a node.
4610 */
4611void
4612xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4613 if (cur == NULL) return;
4614 if (name == NULL) return;
4615 switch(cur->type) {
4616 case XML_TEXT_NODE:
4617 case XML_CDATA_SECTION_NODE:
4618 case XML_COMMENT_NODE:
4619 case XML_DOCUMENT_TYPE_NODE:
4620 case XML_DOCUMENT_FRAG_NODE:
4621 case XML_NOTATION_NODE:
4622 case XML_HTML_DOCUMENT_NODE:
4623 case XML_NAMESPACE_DECL:
4624 case XML_XINCLUDE_START:
4625 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004626#ifdef LIBXML_DOCB_ENABLED
4627 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004628#endif
4629 return;
4630 case XML_ELEMENT_NODE:
4631 case XML_ATTRIBUTE_NODE:
4632 case XML_PI_NODE:
4633 case XML_ENTITY_REF_NODE:
4634 case XML_ENTITY_NODE:
4635 case XML_DTD_NODE:
4636 case XML_DOCUMENT_NODE:
4637 case XML_ELEMENT_DECL:
4638 case XML_ATTRIBUTE_DECL:
4639 case XML_ENTITY_DECL:
4640 break;
4641 }
4642 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4643 cur->name = xmlStrdup(name);
4644}
Daniel Veillard2156d432004-03-04 15:59:36 +00004645#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004646
Daniel Veillard2156d432004-03-04 15:59:36 +00004647#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004648/**
4649 * xmlNodeSetBase:
4650 * @cur: the node being changed
4651 * @uri: the new base URI
4652 *
4653 * Set (or reset) the base URI of a node, i.e. the value of the
4654 * xml:base attribute.
4655 */
4656void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004657xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004658 xmlNsPtr ns;
4659
Owen Taylor3473f882001-02-23 17:55:21 +00004660 if (cur == NULL) return;
4661 switch(cur->type) {
4662 case XML_TEXT_NODE:
4663 case XML_CDATA_SECTION_NODE:
4664 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004665 case XML_DOCUMENT_TYPE_NODE:
4666 case XML_DOCUMENT_FRAG_NODE:
4667 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004668 case XML_DTD_NODE:
4669 case XML_ELEMENT_DECL:
4670 case XML_ATTRIBUTE_DECL:
4671 case XML_ENTITY_DECL:
4672 case XML_PI_NODE:
4673 case XML_ENTITY_REF_NODE:
4674 case XML_ENTITY_NODE:
4675 case XML_NAMESPACE_DECL:
4676 case XML_XINCLUDE_START:
4677 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004678 return;
4679 case XML_ELEMENT_NODE:
4680 case XML_ATTRIBUTE_NODE:
4681 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004682 case XML_DOCUMENT_NODE:
4683#ifdef LIBXML_DOCB_ENABLED
4684 case XML_DOCB_DOCUMENT_NODE:
4685#endif
4686 case XML_HTML_DOCUMENT_NODE: {
4687 xmlDocPtr doc = (xmlDocPtr) cur;
4688
4689 if (doc->URL != NULL)
4690 xmlFree((xmlChar *) doc->URL);
4691 if (uri == NULL)
4692 doc->URL = NULL;
4693 else
4694 doc->URL = xmlStrdup(uri);
4695 return;
4696 }
Owen Taylor3473f882001-02-23 17:55:21 +00004697 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004698
4699 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4700 if (ns == NULL)
4701 return;
4702 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004703}
Daniel Veillard652327a2003-09-29 18:02:38 +00004704#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004705
4706/**
Owen Taylor3473f882001-02-23 17:55:21 +00004707 * xmlNodeGetBase:
4708 * @doc: the document the node pertains to
4709 * @cur: the node being checked
4710 *
4711 * Searches for the BASE URL. The code should work on both XML
4712 * and HTML document even if base mechanisms are completely different.
4713 * It returns the base as defined in RFC 2396 sections
4714 * 5.1.1. Base URI within Document Content
4715 * and
4716 * 5.1.2. Base URI from the Encapsulating Entity
4717 * However it does not return the document base (5.1.3), use
4718 * xmlDocumentGetBase() for this
4719 *
4720 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004721 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004722 */
4723xmlChar *
4724xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004725 xmlChar *oldbase = NULL;
4726 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004727
4728 if ((cur == NULL) && (doc == NULL))
4729 return(NULL);
4730 if (doc == NULL) doc = cur->doc;
4731 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4732 cur = doc->children;
4733 while ((cur != NULL) && (cur->name != NULL)) {
4734 if (cur->type != XML_ELEMENT_NODE) {
4735 cur = cur->next;
4736 continue;
4737 }
4738 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4739 cur = cur->children;
4740 continue;
4741 }
4742 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4743 cur = cur->children;
4744 continue;
4745 }
4746 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4747 return(xmlGetProp(cur, BAD_CAST "href"));
4748 }
4749 cur = cur->next;
4750 }
4751 return(NULL);
4752 }
4753 while (cur != NULL) {
4754 if (cur->type == XML_ENTITY_DECL) {
4755 xmlEntityPtr ent = (xmlEntityPtr) cur;
4756 return(xmlStrdup(ent->URI));
4757 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004758 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004759 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004760 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004761 if (oldbase != NULL) {
4762 newbase = xmlBuildURI(oldbase, base);
4763 if (newbase != NULL) {
4764 xmlFree(oldbase);
4765 xmlFree(base);
4766 oldbase = newbase;
4767 } else {
4768 xmlFree(oldbase);
4769 xmlFree(base);
4770 return(NULL);
4771 }
4772 } else {
4773 oldbase = base;
4774 }
4775 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4776 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4777 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4778 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004779 }
4780 }
Owen Taylor3473f882001-02-23 17:55:21 +00004781 cur = cur->parent;
4782 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004783 if ((doc != NULL) && (doc->URL != NULL)) {
4784 if (oldbase == NULL)
4785 return(xmlStrdup(doc->URL));
4786 newbase = xmlBuildURI(oldbase, doc->URL);
4787 xmlFree(oldbase);
4788 return(newbase);
4789 }
4790 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004791}
4792
4793/**
Daniel Veillard78697292003-10-19 20:44:43 +00004794 * xmlNodeBufGetContent:
4795 * @buffer: a buffer
4796 * @cur: the node being read
4797 *
4798 * Read the value of a node @cur, this can be either the text carried
4799 * directly by this node if it's a TEXT node or the aggregate string
4800 * of the values carried by this node child's (TEXT and ENTITY_REF).
4801 * Entity references are substituted.
4802 * Fills up the buffer @buffer with this value
4803 *
4804 * Returns 0 in case of success and -1 in case of error.
4805 */
4806int
4807xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4808{
4809 if ((cur == NULL) || (buffer == NULL)) return(-1);
4810 switch (cur->type) {
4811 case XML_CDATA_SECTION_NODE:
4812 case XML_TEXT_NODE:
4813 xmlBufferCat(buffer, cur->content);
4814 break;
4815 case XML_DOCUMENT_FRAG_NODE:
4816 case XML_ELEMENT_NODE:{
4817 xmlNodePtr tmp = cur;
4818
4819 while (tmp != NULL) {
4820 switch (tmp->type) {
4821 case XML_CDATA_SECTION_NODE:
4822 case XML_TEXT_NODE:
4823 if (tmp->content != NULL)
4824 xmlBufferCat(buffer, tmp->content);
4825 break;
4826 case XML_ENTITY_REF_NODE:
4827 xmlNodeBufGetContent(buffer, tmp->children);
4828 break;
4829 default:
4830 break;
4831 }
4832 /*
4833 * Skip to next node
4834 */
4835 if (tmp->children != NULL) {
4836 if (tmp->children->type != XML_ENTITY_DECL) {
4837 tmp = tmp->children;
4838 continue;
4839 }
4840 }
4841 if (tmp == cur)
4842 break;
4843
4844 if (tmp->next != NULL) {
4845 tmp = tmp->next;
4846 continue;
4847 }
4848
4849 do {
4850 tmp = tmp->parent;
4851 if (tmp == NULL)
4852 break;
4853 if (tmp == cur) {
4854 tmp = NULL;
4855 break;
4856 }
4857 if (tmp->next != NULL) {
4858 tmp = tmp->next;
4859 break;
4860 }
4861 } while (tmp != NULL);
4862 }
4863 break;
4864 }
4865 case XML_ATTRIBUTE_NODE:{
4866 xmlAttrPtr attr = (xmlAttrPtr) cur;
4867 xmlNodePtr tmp = attr->children;
4868
4869 while (tmp != NULL) {
4870 if (tmp->type == XML_TEXT_NODE)
4871 xmlBufferCat(buffer, tmp->content);
4872 else
4873 xmlNodeBufGetContent(buffer, tmp);
4874 tmp = tmp->next;
4875 }
4876 break;
4877 }
4878 case XML_COMMENT_NODE:
4879 case XML_PI_NODE:
4880 xmlBufferCat(buffer, cur->content);
4881 break;
4882 case XML_ENTITY_REF_NODE:{
4883 xmlEntityPtr ent;
4884 xmlNodePtr tmp;
4885
4886 /* lookup entity declaration */
4887 ent = xmlGetDocEntity(cur->doc, cur->name);
4888 if (ent == NULL)
4889 return(-1);
4890
4891 /* an entity content can be any "well balanced chunk",
4892 * i.e. the result of the content [43] production:
4893 * http://www.w3.org/TR/REC-xml#NT-content
4894 * -> we iterate through child nodes and recursive call
4895 * xmlNodeGetContent() which handles all possible node types */
4896 tmp = ent->children;
4897 while (tmp) {
4898 xmlNodeBufGetContent(buffer, tmp);
4899 tmp = tmp->next;
4900 }
4901 break;
4902 }
4903 case XML_ENTITY_NODE:
4904 case XML_DOCUMENT_TYPE_NODE:
4905 case XML_NOTATION_NODE:
4906 case XML_DTD_NODE:
4907 case XML_XINCLUDE_START:
4908 case XML_XINCLUDE_END:
4909 break;
4910 case XML_DOCUMENT_NODE:
4911#ifdef LIBXML_DOCB_ENABLED
4912 case XML_DOCB_DOCUMENT_NODE:
4913#endif
4914 case XML_HTML_DOCUMENT_NODE:
4915 cur = cur->children;
4916 while (cur!= NULL) {
4917 if ((cur->type == XML_ELEMENT_NODE) ||
4918 (cur->type == XML_TEXT_NODE) ||
4919 (cur->type == XML_CDATA_SECTION_NODE)) {
4920 xmlNodeBufGetContent(buffer, cur);
4921 }
4922 cur = cur->next;
4923 }
4924 break;
4925 case XML_NAMESPACE_DECL:
4926 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
4927 break;
4928 case XML_ELEMENT_DECL:
4929 case XML_ATTRIBUTE_DECL:
4930 case XML_ENTITY_DECL:
4931 break;
4932 }
4933 return(0);
4934}
4935/**
Owen Taylor3473f882001-02-23 17:55:21 +00004936 * xmlNodeGetContent:
4937 * @cur: the node being read
4938 *
4939 * Read the value of a node, this can be either the text carried
4940 * directly by this node if it's a TEXT node or the aggregate string
4941 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004942 * Entity references are substituted.
4943 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004944 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004945 */
4946xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004947xmlNodeGetContent(xmlNodePtr cur)
4948{
4949 if (cur == NULL)
4950 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004951 switch (cur->type) {
4952 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004953 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00004954 xmlBufferPtr buffer;
4955 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004956
Daniel Veillard814a76d2003-01-23 18:24:20 +00004957 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004958 if (buffer == NULL)
4959 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00004960 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004961 ret = buffer->content;
4962 buffer->content = NULL;
4963 xmlBufferFree(buffer);
4964 return (ret);
4965 }
4966 case XML_ATTRIBUTE_NODE:{
4967 xmlAttrPtr attr = (xmlAttrPtr) cur;
4968
4969 if (attr->parent != NULL)
4970 return (xmlNodeListGetString
4971 (attr->parent->doc, attr->children, 1));
4972 else
4973 return (xmlNodeListGetString(NULL, attr->children, 1));
4974 break;
4975 }
Owen Taylor3473f882001-02-23 17:55:21 +00004976 case XML_COMMENT_NODE:
4977 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004978 if (cur->content != NULL)
4979 return (xmlStrdup(cur->content));
4980 return (NULL);
4981 case XML_ENTITY_REF_NODE:{
4982 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00004983 xmlBufferPtr buffer;
4984 xmlChar *ret;
4985
4986 /* lookup entity declaration */
4987 ent = xmlGetDocEntity(cur->doc, cur->name);
4988 if (ent == NULL)
4989 return (NULL);
4990
4991 buffer = xmlBufferCreate();
4992 if (buffer == NULL)
4993 return (NULL);
4994
Daniel Veillardc4696922003-10-19 21:47:14 +00004995 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004996
4997 ret = buffer->content;
4998 buffer->content = NULL;
4999 xmlBufferFree(buffer);
5000 return (ret);
5001 }
Owen Taylor3473f882001-02-23 17:55:21 +00005002 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005003 case XML_DOCUMENT_TYPE_NODE:
5004 case XML_NOTATION_NODE:
5005 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005006 case XML_XINCLUDE_START:
5007 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00005008 return (NULL);
5009 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005010#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005011 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005012#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005013 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00005014 xmlBufferPtr buffer;
5015 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005016
Daniel Veillardc4696922003-10-19 21:47:14 +00005017 buffer = xmlBufferCreate();
5018 if (buffer == NULL)
5019 return (NULL);
5020
5021 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5022
5023 ret = buffer->content;
5024 buffer->content = NULL;
5025 xmlBufferFree(buffer);
5026 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005027 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005028 case XML_NAMESPACE_DECL: {
5029 xmlChar *tmp;
5030
5031 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5032 return (tmp);
5033 }
Owen Taylor3473f882001-02-23 17:55:21 +00005034 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005035 /* TODO !!! */
5036 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005037 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005038 /* TODO !!! */
5039 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005040 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005041 /* TODO !!! */
5042 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005043 case XML_CDATA_SECTION_NODE:
5044 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005045 if (cur->content != NULL)
5046 return (xmlStrdup(cur->content));
5047 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005048 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005049 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005050}
Daniel Veillard652327a2003-09-29 18:02:38 +00005051
Owen Taylor3473f882001-02-23 17:55:21 +00005052/**
5053 * xmlNodeSetContent:
5054 * @cur: the node being modified
5055 * @content: the new value of the content
5056 *
5057 * Replace the content of a node.
5058 */
5059void
5060xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5061 if (cur == NULL) {
5062#ifdef DEBUG_TREE
5063 xmlGenericError(xmlGenericErrorContext,
5064 "xmlNodeSetContent : node == NULL\n");
5065#endif
5066 return;
5067 }
5068 switch (cur->type) {
5069 case XML_DOCUMENT_FRAG_NODE:
5070 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005071 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005072 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5073 cur->children = xmlStringGetNodeList(cur->doc, content);
5074 UPDATE_LAST_CHILD_AND_PARENT(cur)
5075 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005076 case XML_TEXT_NODE:
5077 case XML_CDATA_SECTION_NODE:
5078 case XML_ENTITY_REF_NODE:
5079 case XML_ENTITY_NODE:
5080 case XML_PI_NODE:
5081 case XML_COMMENT_NODE:
5082 if (cur->content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005083 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5084 xmlDictOwns(cur->doc->dict, cur->content)))
5085 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005086 }
5087 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5088 cur->last = cur->children = NULL;
5089 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005090 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005091 } else
5092 cur->content = NULL;
5093 break;
5094 case XML_DOCUMENT_NODE:
5095 case XML_HTML_DOCUMENT_NODE:
5096 case XML_DOCUMENT_TYPE_NODE:
5097 case XML_XINCLUDE_START:
5098 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005099#ifdef LIBXML_DOCB_ENABLED
5100 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005101#endif
5102 break;
5103 case XML_NOTATION_NODE:
5104 break;
5105 case XML_DTD_NODE:
5106 break;
5107 case XML_NAMESPACE_DECL:
5108 break;
5109 case XML_ELEMENT_DECL:
5110 /* TODO !!! */
5111 break;
5112 case XML_ATTRIBUTE_DECL:
5113 /* TODO !!! */
5114 break;
5115 case XML_ENTITY_DECL:
5116 /* TODO !!! */
5117 break;
5118 }
5119}
5120
Daniel Veillard652327a2003-09-29 18:02:38 +00005121#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005122/**
5123 * xmlNodeSetContentLen:
5124 * @cur: the node being modified
5125 * @content: the new value of the content
5126 * @len: the size of @content
5127 *
5128 * Replace the content of a node.
5129 */
5130void
5131xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5132 if (cur == NULL) {
5133#ifdef DEBUG_TREE
5134 xmlGenericError(xmlGenericErrorContext,
5135 "xmlNodeSetContentLen : node == NULL\n");
5136#endif
5137 return;
5138 }
5139 switch (cur->type) {
5140 case XML_DOCUMENT_FRAG_NODE:
5141 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005142 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005143 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5144 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5145 UPDATE_LAST_CHILD_AND_PARENT(cur)
5146 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005147 case XML_TEXT_NODE:
5148 case XML_CDATA_SECTION_NODE:
5149 case XML_ENTITY_REF_NODE:
5150 case XML_ENTITY_NODE:
5151 case XML_PI_NODE:
5152 case XML_COMMENT_NODE:
5153 case XML_NOTATION_NODE:
5154 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005155 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005156 }
5157 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5158 cur->children = cur->last = NULL;
5159 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005160 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005161 } else
5162 cur->content = NULL;
5163 break;
5164 case XML_DOCUMENT_NODE:
5165 case XML_DTD_NODE:
5166 case XML_HTML_DOCUMENT_NODE:
5167 case XML_DOCUMENT_TYPE_NODE:
5168 case XML_NAMESPACE_DECL:
5169 case XML_XINCLUDE_START:
5170 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005171#ifdef LIBXML_DOCB_ENABLED
5172 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005173#endif
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}
Daniel Veillard652327a2003-09-29 18:02:38 +00005186#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005187
5188/**
5189 * xmlNodeAddContentLen:
5190 * @cur: the node being modified
5191 * @content: extra content
5192 * @len: the size of @content
5193 *
5194 * Append the extra substring to the node content.
5195 */
5196void
5197xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5198 if (cur == NULL) {
5199#ifdef DEBUG_TREE
5200 xmlGenericError(xmlGenericErrorContext,
5201 "xmlNodeAddContentLen : node == NULL\n");
5202#endif
5203 return;
5204 }
5205 if (len <= 0) return;
5206 switch (cur->type) {
5207 case XML_DOCUMENT_FRAG_NODE:
5208 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005209 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005210
Daniel Veillard7db37732001-07-12 01:20:08 +00005211 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005212 newNode = xmlNewTextLen(content, len);
5213 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005214 tmp = xmlAddChild(cur, newNode);
5215 if (tmp != newNode)
5216 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005217 if ((last != NULL) && (last->next == newNode)) {
5218 xmlTextMerge(last, newNode);
5219 }
5220 }
5221 break;
5222 }
5223 case XML_ATTRIBUTE_NODE:
5224 break;
5225 case XML_TEXT_NODE:
5226 case XML_CDATA_SECTION_NODE:
5227 case XML_ENTITY_REF_NODE:
5228 case XML_ENTITY_NODE:
5229 case XML_PI_NODE:
5230 case XML_COMMENT_NODE:
5231 case XML_NOTATION_NODE:
5232 if (content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005233 if ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5234 xmlDictOwns(cur->doc->dict, cur->content)) {
5235 cur->content =
5236 xmlStrncatNew(cur->content, content, len);
5237 break;
5238 }
Owen Taylor3473f882001-02-23 17:55:21 +00005239 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005240 }
5241 case XML_DOCUMENT_NODE:
5242 case XML_DTD_NODE:
5243 case XML_HTML_DOCUMENT_NODE:
5244 case XML_DOCUMENT_TYPE_NODE:
5245 case XML_NAMESPACE_DECL:
5246 case XML_XINCLUDE_START:
5247 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005248#ifdef LIBXML_DOCB_ENABLED
5249 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005250#endif
5251 break;
5252 case XML_ELEMENT_DECL:
5253 case XML_ATTRIBUTE_DECL:
5254 case XML_ENTITY_DECL:
5255 break;
5256 }
5257}
5258
5259/**
5260 * xmlNodeAddContent:
5261 * @cur: the node being modified
5262 * @content: extra content
5263 *
5264 * Append the extra substring to the node content.
5265 */
5266void
5267xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5268 int len;
5269
5270 if (cur == NULL) {
5271#ifdef DEBUG_TREE
5272 xmlGenericError(xmlGenericErrorContext,
5273 "xmlNodeAddContent : node == NULL\n");
5274#endif
5275 return;
5276 }
5277 if (content == NULL) return;
5278 len = xmlStrlen(content);
5279 xmlNodeAddContentLen(cur, content, len);
5280}
5281
5282/**
5283 * xmlTextMerge:
5284 * @first: the first text node
5285 * @second: the second text node being merged
5286 *
5287 * Merge two text nodes into one
5288 * Returns the first text node augmented
5289 */
5290xmlNodePtr
5291xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5292 if (first == NULL) return(second);
5293 if (second == NULL) return(first);
5294 if (first->type != XML_TEXT_NODE) return(first);
5295 if (second->type != XML_TEXT_NODE) return(first);
5296 if (second->name != first->name)
5297 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005298 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005299 xmlUnlinkNode(second);
5300 xmlFreeNode(second);
5301 return(first);
5302}
5303
Daniel Veillard2156d432004-03-04 15:59:36 +00005304#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005305/**
5306 * xmlGetNsList:
5307 * @doc: the document
5308 * @node: the current node
5309 *
5310 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005311 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005312 * that need to be freed by the caller or NULL if no
5313 * namespace if defined
5314 */
5315xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005316xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5317{
Owen Taylor3473f882001-02-23 17:55:21 +00005318 xmlNsPtr cur;
5319 xmlNsPtr *ret = NULL;
5320 int nbns = 0;
5321 int maxns = 10;
5322 int i;
5323
5324 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005325 if (node->type == XML_ELEMENT_NODE) {
5326 cur = node->nsDef;
5327 while (cur != NULL) {
5328 if (ret == NULL) {
5329 ret =
5330 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5331 sizeof(xmlNsPtr));
5332 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005333 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005334 return (NULL);
5335 }
5336 ret[nbns] = NULL;
5337 }
5338 for (i = 0; i < nbns; i++) {
5339 if ((cur->prefix == ret[i]->prefix) ||
5340 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5341 break;
5342 }
5343 if (i >= nbns) {
5344 if (nbns >= maxns) {
5345 maxns *= 2;
5346 ret = (xmlNsPtr *) xmlRealloc(ret,
5347 (maxns +
5348 1) *
5349 sizeof(xmlNsPtr));
5350 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005351 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005352 return (NULL);
5353 }
5354 }
5355 ret[nbns++] = cur;
5356 ret[nbns] = NULL;
5357 }
Owen Taylor3473f882001-02-23 17:55:21 +00005358
Daniel Veillard77044732001-06-29 21:31:07 +00005359 cur = cur->next;
5360 }
5361 }
5362 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005363 }
Daniel Veillard77044732001-06-29 21:31:07 +00005364 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005365}
Daniel Veillard652327a2003-09-29 18:02:38 +00005366#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005367
5368/**
5369 * xmlSearchNs:
5370 * @doc: the document
5371 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005372 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005373 *
5374 * Search a Ns registered under a given name space for a document.
5375 * recurse on the parents until it finds the defined namespace
5376 * or return NULL otherwise.
5377 * @nameSpace can be NULL, this is a search for the default namespace.
5378 * We don't allow to cross entities boundaries. If you don't declare
5379 * the namespace within those you will be in troubles !!! A warning
5380 * is generated to cover this case.
5381 *
5382 * Returns the namespace pointer or NULL.
5383 */
5384xmlNsPtr
5385xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005386
Owen Taylor3473f882001-02-23 17:55:21 +00005387 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005388 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005389
5390 if (node == NULL) return(NULL);
5391 if ((nameSpace != NULL) &&
5392 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005393 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5394 /*
5395 * The XML-1.0 namespace is normally held on the root
5396 * element. In this case exceptionally create it on the
5397 * node element.
5398 */
5399 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5400 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005401 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005402 return(NULL);
5403 }
5404 memset(cur, 0, sizeof(xmlNs));
5405 cur->type = XML_LOCAL_NAMESPACE;
5406 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5407 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5408 cur->next = node->nsDef;
5409 node->nsDef = cur;
5410 return(cur);
5411 }
Owen Taylor3473f882001-02-23 17:55:21 +00005412 if (doc->oldNs == NULL) {
5413 /*
5414 * Allocate a new Namespace and fill the fields.
5415 */
5416 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5417 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005418 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005419 return(NULL);
5420 }
5421 memset(doc->oldNs, 0, sizeof(xmlNs));
5422 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5423
5424 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5425 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5426 }
5427 return(doc->oldNs);
5428 }
5429 while (node != NULL) {
5430 if ((node->type == XML_ENTITY_REF_NODE) ||
5431 (node->type == XML_ENTITY_NODE) ||
5432 (node->type == XML_ENTITY_DECL))
5433 return(NULL);
5434 if (node->type == XML_ELEMENT_NODE) {
5435 cur = node->nsDef;
5436 while (cur != NULL) {
5437 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5438 (cur->href != NULL))
5439 return(cur);
5440 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5441 (cur->href != NULL) &&
5442 (xmlStrEqual(cur->prefix, nameSpace)))
5443 return(cur);
5444 cur = cur->next;
5445 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005446 if (orig != node) {
5447 cur = node->ns;
5448 if (cur != NULL) {
5449 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5450 (cur->href != NULL))
5451 return(cur);
5452 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5453 (cur->href != NULL) &&
5454 (xmlStrEqual(cur->prefix, nameSpace)))
5455 return(cur);
5456 }
5457 }
Owen Taylor3473f882001-02-23 17:55:21 +00005458 }
5459 node = node->parent;
5460 }
5461 return(NULL);
5462}
5463
5464/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005465 * xmlNsInScope:
5466 * @doc: the document
5467 * @node: the current node
5468 * @ancestor: the ancestor carrying the namespace
5469 * @prefix: the namespace prefix
5470 *
5471 * Verify that the given namespace held on @ancestor is still in scope
5472 * on node.
5473 *
5474 * Returns 1 if true, 0 if false and -1 in case of error.
5475 */
5476static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005477xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5478 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005479{
5480 xmlNsPtr tst;
5481
5482 while ((node != NULL) && (node != ancestor)) {
5483 if ((node->type == XML_ENTITY_REF_NODE) ||
5484 (node->type == XML_ENTITY_NODE) ||
5485 (node->type == XML_ENTITY_DECL))
5486 return (-1);
5487 if (node->type == XML_ELEMENT_NODE) {
5488 tst = node->nsDef;
5489 while (tst != NULL) {
5490 if ((tst->prefix == NULL)
5491 && (prefix == NULL))
5492 return (0);
5493 if ((tst->prefix != NULL)
5494 && (prefix != NULL)
5495 && (xmlStrEqual(tst->prefix, prefix)))
5496 return (0);
5497 tst = tst->next;
5498 }
5499 }
5500 node = node->parent;
5501 }
5502 if (node != ancestor)
5503 return (-1);
5504 return (1);
5505}
5506
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005507/**
Owen Taylor3473f882001-02-23 17:55:21 +00005508 * xmlSearchNsByHref:
5509 * @doc: the document
5510 * @node: the current node
5511 * @href: the namespace value
5512 *
5513 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5514 * the defined namespace or return NULL otherwise.
5515 * Returns the namespace pointer or NULL.
5516 */
5517xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005518xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5519{
Owen Taylor3473f882001-02-23 17:55:21 +00005520 xmlNsPtr cur;
5521 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005522 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005523
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005524 if ((node == NULL) || (href == NULL))
5525 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005526 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005527 /*
5528 * Only the document can hold the XML spec namespace.
5529 */
5530 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5531 /*
5532 * The XML-1.0 namespace is normally held on the root
5533 * element. In this case exceptionally create it on the
5534 * node element.
5535 */
5536 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5537 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005538 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005539 return (NULL);
5540 }
5541 memset(cur, 0, sizeof(xmlNs));
5542 cur->type = XML_LOCAL_NAMESPACE;
5543 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5544 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5545 cur->next = node->nsDef;
5546 node->nsDef = cur;
5547 return (cur);
5548 }
5549 if (doc->oldNs == NULL) {
5550 /*
5551 * Allocate a new Namespace and fill the fields.
5552 */
5553 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5554 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005555 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005556 return (NULL);
5557 }
5558 memset(doc->oldNs, 0, sizeof(xmlNs));
5559 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005560
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005561 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5562 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5563 }
5564 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005565 }
Daniel Veillard62040be2004-05-17 03:17:26 +00005566 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00005567 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005568 if ((node->type == XML_ENTITY_REF_NODE) ||
5569 (node->type == XML_ENTITY_NODE) ||
5570 (node->type == XML_ENTITY_DECL))
5571 return (NULL);
5572 if (node->type == XML_ELEMENT_NODE) {
5573 cur = node->nsDef;
5574 while (cur != NULL) {
5575 if ((cur->href != NULL) && (href != NULL) &&
5576 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005577 if (((!is_attr) || (cur->prefix != NULL)) &&
5578 (xmlNsInScope(doc, orig, node, cur->href) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005579 return (cur);
5580 }
5581 cur = cur->next;
5582 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005583 if (orig != node) {
5584 cur = node->ns;
5585 if (cur != NULL) {
5586 if ((cur->href != NULL) && (href != NULL) &&
5587 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005588 if (((!is_attr) || (cur->prefix != NULL)) &&
5589 (xmlNsInScope(doc, orig, node, cur->href) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00005590 return (cur);
5591 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005592 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005593 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005594 }
5595 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005596 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005597 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005598}
5599
5600/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005601 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005602 * @doc: the document
5603 * @tree: a node expected to hold the new namespace
5604 * @ns: the original namespace
5605 *
5606 * This function tries to locate a namespace definition in a tree
5607 * ancestors, or create a new namespace definition node similar to
5608 * @ns trying to reuse the same prefix. However if the given prefix is
5609 * null (default namespace) or reused within the subtree defined by
5610 * @tree or on one of its ancestors then a new prefix is generated.
5611 * Returns the (new) namespace definition or NULL in case of error
5612 */
5613xmlNsPtr
5614xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5615 xmlNsPtr def;
5616 xmlChar prefix[50];
5617 int counter = 1;
5618
5619 if (tree == NULL) {
5620#ifdef DEBUG_TREE
5621 xmlGenericError(xmlGenericErrorContext,
5622 "xmlNewReconciliedNs : tree == NULL\n");
5623#endif
5624 return(NULL);
5625 }
5626 if (ns == NULL) {
5627#ifdef DEBUG_TREE
5628 xmlGenericError(xmlGenericErrorContext,
5629 "xmlNewReconciliedNs : ns == NULL\n");
5630#endif
5631 return(NULL);
5632 }
5633 /*
5634 * Search an existing namespace definition inherited.
5635 */
5636 def = xmlSearchNsByHref(doc, tree, ns->href);
5637 if (def != NULL)
5638 return(def);
5639
5640 /*
5641 * Find a close prefix which is not already in use.
5642 * Let's strip namespace prefixes longer than 20 chars !
5643 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005644 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005645 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005646 else
William M. Brack13dfa872004-09-18 04:52:08 +00005647 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005648
Owen Taylor3473f882001-02-23 17:55:21 +00005649 def = xmlSearchNs(doc, tree, prefix);
5650 while (def != NULL) {
5651 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005652 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005653 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005654 else
William M. Brack13dfa872004-09-18 04:52:08 +00005655 snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
5656 (char *)ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005657 def = xmlSearchNs(doc, tree, prefix);
5658 }
5659
5660 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005661 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005662 */
5663 def = xmlNewNs(tree, ns->href, prefix);
5664 return(def);
5665}
5666
Daniel Veillard652327a2003-09-29 18:02:38 +00005667#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005668/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005669 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005670 * @doc: the document
5671 * @tree: a node defining the subtree to reconciliate
5672 *
5673 * This function checks that all the namespaces declared within the given
5674 * tree are properly declared. This is needed for example after Copy or Cut
5675 * and then paste operations. The subtree may still hold pointers to
5676 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005677 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005678 * the new environment. If not possible the new namespaces are redeclared
5679 * on @tree at the top of the given subtree.
5680 * Returns the number of namespace declarations created or -1 in case of error.
5681 */
5682int
5683xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5684 xmlNsPtr *oldNs = NULL;
5685 xmlNsPtr *newNs = NULL;
5686 int sizeCache = 0;
5687 int nbCache = 0;
5688
5689 xmlNsPtr n;
5690 xmlNodePtr node = tree;
5691 xmlAttrPtr attr;
5692 int ret = 0, i;
5693
5694 while (node != NULL) {
5695 /*
5696 * Reconciliate the node namespace
5697 */
5698 if (node->ns != NULL) {
5699 /*
5700 * initialize the cache if needed
5701 */
5702 if (sizeCache == 0) {
5703 sizeCache = 10;
5704 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5705 sizeof(xmlNsPtr));
5706 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005707 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005708 return(-1);
5709 }
5710 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5711 sizeof(xmlNsPtr));
5712 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005713 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005714 xmlFree(oldNs);
5715 return(-1);
5716 }
5717 }
5718 for (i = 0;i < nbCache;i++) {
5719 if (oldNs[i] == node->ns) {
5720 node->ns = newNs[i];
5721 break;
5722 }
5723 }
5724 if (i == nbCache) {
5725 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005726 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005727 */
5728 n = xmlNewReconciliedNs(doc, tree, node->ns);
5729 if (n != NULL) { /* :-( what if else ??? */
5730 /*
5731 * check if we need to grow the cache buffers.
5732 */
5733 if (sizeCache <= nbCache) {
5734 sizeCache *= 2;
5735 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5736 sizeof(xmlNsPtr));
5737 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005738 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005739 xmlFree(newNs);
5740 return(-1);
5741 }
5742 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5743 sizeof(xmlNsPtr));
5744 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005745 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005746 xmlFree(oldNs);
5747 return(-1);
5748 }
5749 }
5750 newNs[nbCache] = n;
5751 oldNs[nbCache++] = node->ns;
5752 node->ns = n;
5753 }
5754 }
5755 }
5756 /*
5757 * now check for namespace hold by attributes on the node.
5758 */
5759 attr = node->properties;
5760 while (attr != NULL) {
5761 if (attr->ns != NULL) {
5762 /*
5763 * initialize the cache if needed
5764 */
5765 if (sizeCache == 0) {
5766 sizeCache = 10;
5767 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5768 sizeof(xmlNsPtr));
5769 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005770 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005771 return(-1);
5772 }
5773 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5774 sizeof(xmlNsPtr));
5775 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005776 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005777 xmlFree(oldNs);
5778 return(-1);
5779 }
5780 }
5781 for (i = 0;i < nbCache;i++) {
5782 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005783 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005784 break;
5785 }
5786 }
5787 if (i == nbCache) {
5788 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005789 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005790 */
5791 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5792 if (n != NULL) { /* :-( what if else ??? */
5793 /*
5794 * check if we need to grow the cache buffers.
5795 */
5796 if (sizeCache <= nbCache) {
5797 sizeCache *= 2;
5798 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5799 sizeof(xmlNsPtr));
5800 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005801 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005802 xmlFree(newNs);
5803 return(-1);
5804 }
5805 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5806 sizeof(xmlNsPtr));
5807 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005808 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005809 xmlFree(oldNs);
5810 return(-1);
5811 }
5812 }
5813 newNs[nbCache] = n;
5814 oldNs[nbCache++] = attr->ns;
5815 attr->ns = n;
5816 }
5817 }
5818 }
5819 attr = attr->next;
5820 }
5821
5822 /*
5823 * Browse the full subtree, deep first
5824 */
Daniel Veillardac996a12004-07-30 12:02:58 +00005825 if (node->children != NULL && node->type != XML_ENTITY_REF_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00005826 /* deep first */
5827 node = node->children;
5828 } else if ((node != tree) && (node->next != NULL)) {
5829 /* then siblings */
5830 node = node->next;
5831 } else if (node != tree) {
5832 /* go up to parents->next if needed */
5833 while (node != tree) {
5834 if (node->parent != NULL)
5835 node = node->parent;
5836 if ((node != tree) && (node->next != NULL)) {
5837 node = node->next;
5838 break;
5839 }
5840 if (node->parent == NULL) {
5841 node = NULL;
5842 break;
5843 }
5844 }
5845 /* exit condition */
5846 if (node == tree)
5847 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005848 } else
5849 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005850 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005851 if (oldNs != NULL)
5852 xmlFree(oldNs);
5853 if (newNs != NULL)
5854 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005855 return(ret);
5856}
Daniel Veillard652327a2003-09-29 18:02:38 +00005857#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005858
5859/**
5860 * xmlHasProp:
5861 * @node: the node
5862 * @name: the attribute name
5863 *
5864 * Search an attribute associated to a node
5865 * This function also looks in DTD attribute declaration for #FIXED or
5866 * default declaration values unless DTD use has been turned off.
5867 *
5868 * Returns the attribute or the attribute declaration or NULL if
5869 * neither was found.
5870 */
5871xmlAttrPtr
5872xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5873 xmlAttrPtr prop;
5874 xmlDocPtr doc;
5875
5876 if ((node == NULL) || (name == NULL)) return(NULL);
5877 /*
5878 * Check on the properties attached to the node
5879 */
5880 prop = node->properties;
5881 while (prop != NULL) {
5882 if (xmlStrEqual(prop->name, name)) {
5883 return(prop);
5884 }
5885 prop = prop->next;
5886 }
5887 if (!xmlCheckDTD) return(NULL);
5888
5889 /*
5890 * Check if there is a default declaration in the internal
5891 * or external subsets
5892 */
5893 doc = node->doc;
5894 if (doc != NULL) {
5895 xmlAttributePtr attrDecl;
5896 if (doc->intSubset != NULL) {
5897 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5898 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5899 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005900 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5901 /* return attribute declaration only if a default value is given
5902 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005903 return((xmlAttrPtr) attrDecl);
5904 }
5905 }
5906 return(NULL);
5907}
5908
5909/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005910 * xmlHasNsProp:
5911 * @node: the node
5912 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005913 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005914 *
5915 * Search for an attribute associated to a node
5916 * This attribute has to be anchored in the namespace specified.
5917 * This does the entity substitution.
5918 * This function looks in DTD attribute declaration for #FIXED or
5919 * default declaration values unless DTD use has been turned off.
William M. Brack2c228442004-10-03 04:10:00 +00005920 * Note that a namespace of NULL indicates to use the default namespace.
Daniel Veillarde95e2392001-06-06 10:46:28 +00005921 *
5922 * Returns the attribute or the attribute declaration or NULL
5923 * if neither was found.
5924 */
5925xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005926xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005927 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00005928#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005929 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00005930#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005931
5932 if (node == NULL)
5933 return(NULL);
5934
5935 prop = node->properties;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005936 while (prop != NULL) {
5937 /*
5938 * One need to have
5939 * - same attribute names
5940 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005941 */
William M. Brack2c228442004-10-03 04:10:00 +00005942 if (xmlStrEqual(prop->name, name)) {
5943 if (((prop->ns != NULL) &&
5944 (xmlStrEqual(prop->ns->href, nameSpace))) ||
5945 ((prop->ns == NULL) && (nameSpace == NULL))) {
5946 return(prop);
5947 }
Daniel Veillarde95e2392001-06-06 10:46:28 +00005948 }
5949 prop = prop->next;
5950 }
5951 if (!xmlCheckDTD) return(NULL);
5952
Daniel Veillard652327a2003-09-29 18:02:38 +00005953#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005954 /*
5955 * Check if there is a default declaration in the internal
5956 * or external subsets
5957 */
5958 doc = node->doc;
5959 if (doc != NULL) {
5960 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005961 xmlAttributePtr attrDecl = NULL;
5962 xmlNsPtr *nsList, *cur;
5963 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005964
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005965 nsList = xmlGetNsList(node->doc, node);
5966 if (nsList == NULL)
5967 return(NULL);
5968 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5969 ename = xmlStrdup(node->ns->prefix);
5970 ename = xmlStrcat(ename, BAD_CAST ":");
5971 ename = xmlStrcat(ename, node->name);
5972 } else {
5973 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005974 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005975 if (ename == NULL) {
5976 xmlFree(nsList);
5977 return(NULL);
5978 }
5979
William M. Brack2c228442004-10-03 04:10:00 +00005980 if (nameSpace == NULL) {
5981 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5982 name, NULL);
5983 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
5984 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5985 name, NULL);
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005986 }
William M. Brack2c228442004-10-03 04:10:00 +00005987 } else {
5988 cur = nsList;
5989 while (*cur != NULL) {
5990 if (xmlStrEqual((*cur)->href, nameSpace)) {
5991 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5992 name, (*cur)->prefix);
5993 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5994 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5995 name, (*cur)->prefix);
5996 }
5997 cur++;
5998 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005999 }
6000 xmlFree(nsList);
6001 xmlFree(ename);
6002 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006003 }
6004 }
Daniel Veillard652327a2003-09-29 18:02:38 +00006005#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00006006 return(NULL);
6007}
6008
6009/**
Owen Taylor3473f882001-02-23 17:55:21 +00006010 * xmlGetProp:
6011 * @node: the node
6012 * @name: the attribute name
6013 *
6014 * Search and get the value of an attribute associated to a node
6015 * This does the entity substitution.
6016 * This function looks in DTD attribute declaration for #FIXED or
6017 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00006018 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00006019 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6020 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00006021 *
6022 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006023 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006024 */
6025xmlChar *
6026xmlGetProp(xmlNodePtr node, const xmlChar *name) {
6027 xmlAttrPtr prop;
6028 xmlDocPtr doc;
6029
6030 if ((node == NULL) || (name == NULL)) return(NULL);
6031 /*
6032 * Check on the properties attached to the node
6033 */
6034 prop = node->properties;
6035 while (prop != NULL) {
6036 if (xmlStrEqual(prop->name, name)) {
6037 xmlChar *ret;
6038
6039 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6040 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6041 return(ret);
6042 }
6043 prop = prop->next;
6044 }
6045 if (!xmlCheckDTD) return(NULL);
6046
6047 /*
6048 * Check if there is a default declaration in the internal
6049 * or external subsets
6050 */
6051 doc = node->doc;
6052 if (doc != NULL) {
6053 xmlAttributePtr attrDecl;
6054 if (doc->intSubset != NULL) {
6055 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6056 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6057 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006058 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6059 /* return attribute declaration only if a default value is given
6060 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006061 return(xmlStrdup(attrDecl->defaultValue));
6062 }
6063 }
6064 return(NULL);
6065}
6066
6067/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006068 * xmlGetNoNsProp:
6069 * @node: the node
6070 * @name: the attribute name
6071 *
6072 * Search and get the value of an attribute associated to a node
6073 * This does the entity substitution.
6074 * This function looks in DTD attribute declaration for #FIXED or
6075 * default declaration values unless DTD use has been turned off.
6076 * This function is similar to xmlGetProp except it will accept only
6077 * an attribute in no namespace.
6078 *
6079 * Returns the attribute value or NULL if not found.
6080 * It's up to the caller to free the memory with xmlFree().
6081 */
6082xmlChar *
6083xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6084 xmlAttrPtr prop;
6085 xmlDocPtr doc;
6086
6087 if ((node == NULL) || (name == NULL)) return(NULL);
6088 /*
6089 * Check on the properties attached to the node
6090 */
6091 prop = node->properties;
6092 while (prop != NULL) {
6093 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6094 xmlChar *ret;
6095
6096 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6097 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6098 return(ret);
6099 }
6100 prop = prop->next;
6101 }
6102 if (!xmlCheckDTD) return(NULL);
6103
6104 /*
6105 * Check if there is a default declaration in the internal
6106 * or external subsets
6107 */
6108 doc = node->doc;
6109 if (doc != NULL) {
6110 xmlAttributePtr attrDecl;
6111 if (doc->intSubset != NULL) {
6112 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6113 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6114 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006115 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6116 /* return attribute declaration only if a default value is given
6117 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006118 return(xmlStrdup(attrDecl->defaultValue));
6119 }
6120 }
6121 return(NULL);
6122}
6123
6124/**
Owen Taylor3473f882001-02-23 17:55:21 +00006125 * xmlGetNsProp:
6126 * @node: the node
6127 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006128 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006129 *
6130 * Search and get the value of an attribute associated to a node
6131 * This attribute has to be anchored in the namespace specified.
6132 * This does the entity substitution.
6133 * This function looks in DTD attribute declaration for #FIXED or
6134 * default declaration values unless DTD use has been turned off.
6135 *
6136 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006137 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006138 */
6139xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006140xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006141 xmlAttrPtr prop;
6142 xmlDocPtr doc;
6143 xmlNsPtr ns;
6144
6145 if (node == NULL)
6146 return(NULL);
6147
6148 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006149 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006150 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006151 while (prop != NULL) {
6152 /*
6153 * One need to have
6154 * - same attribute names
6155 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006156 */
6157 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006158 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006159 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006160 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) {
Owen Taylor3473f882001-02-23 17:55:21 +00006176 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006177 xmlAttributePtr attrDecl;
6178
Owen Taylor3473f882001-02-23 17:55:21 +00006179 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6180 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6181 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6182
6183 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6184 /*
6185 * The DTD declaration only allows a prefix search
6186 */
6187 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006188 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006189 return(xmlStrdup(attrDecl->defaultValue));
6190 }
6191 }
6192 }
6193 return(NULL);
6194}
6195
Daniel Veillard2156d432004-03-04 15:59:36 +00006196#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6197/**
6198 * xmlUnsetProp:
6199 * @node: the node
6200 * @name: the attribute name
6201 *
6202 * Remove an attribute carried by a node.
6203 * Returns 0 if successful, -1 if not found
6204 */
6205int
6206xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
6207 xmlAttrPtr prop, prev = NULL;;
6208
6209 if ((node == NULL) || (name == NULL))
6210 return(-1);
6211 prop = node->properties;
6212 while (prop != NULL) {
6213 if ((xmlStrEqual(prop->name, name)) &&
6214 (prop->ns == NULL)) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006215 if (prev == NULL) {
Daniel Veillard2156d432004-03-04 15:59:36 +00006216 node->properties = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006217 if (prop->next != NULL)
6218 prop->next->prev = NULL;
6219 } else {
Daniel Veillard2156d432004-03-04 15:59:36 +00006220 prev->next = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006221 if (prop->next != NULL)
6222 prop->next->prev = NULL;
6223 }
6224 prop->next = NULL;
6225 prop->prev = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00006226 xmlFreeProp(prop);
6227 return(0);
6228 }
6229 prev = prop;
6230 prop = prop->next;
6231 }
6232 return(-1);
6233}
6234
6235/**
6236 * xmlUnsetNsProp:
6237 * @node: the node
6238 * @ns: the namespace definition
6239 * @name: the attribute name
6240 *
6241 * Remove an attribute carried by a node.
6242 * Returns 0 if successful, -1 if not found
6243 */
6244int
6245xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6246 xmlAttrPtr prop = node->properties, prev = NULL;;
6247
6248 if ((node == NULL) || (name == NULL))
6249 return(-1);
6250 if (ns == NULL)
6251 return(xmlUnsetProp(node, name));
6252 if (ns->href == NULL)
6253 return(-1);
6254 while (prop != NULL) {
6255 if ((xmlStrEqual(prop->name, name)) &&
6256 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006257 if (prev == NULL) {
Daniel Veillard2156d432004-03-04 15:59:36 +00006258 node->properties = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006259 if (prop->next != NULL)
6260 prop->next->prev = NULL;
6261 } else {
Daniel Veillard2156d432004-03-04 15:59:36 +00006262 prev->next = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006263 if (prop->next != NULL)
6264 prop->next->prev = NULL;
6265 }
6266 prop->next = NULL;
6267 prop->prev = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00006268 xmlFreeProp(prop);
6269 return(0);
6270 }
6271 prev = prop;
6272 prop = prop->next;
6273 }
6274 return(-1);
6275}
6276#endif
6277
6278#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006279/**
6280 * xmlSetProp:
6281 * @node: the node
6282 * @name: the attribute name
6283 * @value: the attribute value
6284 *
6285 * Set (or reset) an attribute carried by a node.
6286 * Returns the attribute pointer.
6287 */
6288xmlAttrPtr
6289xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006290 xmlAttrPtr prop;
6291 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006292
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006293 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006294 return(NULL);
6295 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006296 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006297 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006298 if ((xmlStrEqual(prop->name, name)) &&
6299 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006300 xmlNodePtr oldprop = prop->children;
6301
Owen Taylor3473f882001-02-23 17:55:21 +00006302 prop->children = NULL;
6303 prop->last = NULL;
6304 if (value != NULL) {
6305 xmlChar *buffer;
6306 xmlNodePtr tmp;
6307
6308 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6309 prop->children = xmlStringGetNodeList(node->doc, buffer);
6310 prop->last = NULL;
6311 prop->doc = doc;
6312 tmp = prop->children;
6313 while (tmp != NULL) {
6314 tmp->parent = (xmlNodePtr) prop;
6315 tmp->doc = doc;
6316 if (tmp->next == NULL)
6317 prop->last = tmp;
6318 tmp = tmp->next;
6319 }
6320 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006321 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006322 if (oldprop != NULL)
6323 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006324 return(prop);
6325 }
6326 prop = prop->next;
6327 }
6328 prop = xmlNewProp(node, name, value);
6329 return(prop);
6330}
6331
6332/**
6333 * xmlSetNsProp:
6334 * @node: the node
6335 * @ns: the namespace definition
6336 * @name: the attribute name
6337 * @value: the attribute value
6338 *
6339 * Set (or reset) an attribute carried by a node.
6340 * The ns structure must be in scope, this is not checked.
6341 *
6342 * Returns the attribute pointer.
6343 */
6344xmlAttrPtr
6345xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6346 const xmlChar *value) {
6347 xmlAttrPtr prop;
6348
6349 if ((node == NULL) || (name == NULL))
6350 return(NULL);
6351
6352 if (ns == NULL)
6353 return(xmlSetProp(node, name, value));
6354 if (ns->href == NULL)
6355 return(NULL);
6356 prop = node->properties;
6357
6358 while (prop != NULL) {
6359 /*
6360 * One need to have
6361 * - same attribute names
6362 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006363 */
6364 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006365 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006366 if (prop->children != NULL)
6367 xmlFreeNodeList(prop->children);
6368 prop->children = NULL;
6369 prop->last = NULL;
6370 prop->ns = ns;
6371 if (value != NULL) {
6372 xmlChar *buffer;
6373 xmlNodePtr tmp;
6374
6375 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6376 prop->children = xmlStringGetNodeList(node->doc, buffer);
6377 prop->last = NULL;
6378 tmp = prop->children;
6379 while (tmp != NULL) {
6380 tmp->parent = (xmlNodePtr) prop;
6381 if (tmp->next == NULL)
6382 prop->last = tmp;
6383 tmp = tmp->next;
6384 }
6385 xmlFree(buffer);
6386 }
6387 return(prop);
6388 }
6389 prop = prop->next;
6390 }
6391 prop = xmlNewNsProp(node, ns, name, value);
6392 return(prop);
6393}
6394
Daniel Veillard652327a2003-09-29 18:02:38 +00006395#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006396
6397/**
Owen Taylor3473f882001-02-23 17:55:21 +00006398 * xmlNodeIsText:
6399 * @node: the node
6400 *
6401 * Is this node a Text node ?
6402 * Returns 1 yes, 0 no
6403 */
6404int
6405xmlNodeIsText(xmlNodePtr node) {
6406 if (node == NULL) return(0);
6407
6408 if (node->type == XML_TEXT_NODE) return(1);
6409 return(0);
6410}
6411
6412/**
6413 * xmlIsBlankNode:
6414 * @node: the node
6415 *
6416 * Checks whether this node is an empty or whitespace only
6417 * (and possibly ignorable) text-node.
6418 *
6419 * Returns 1 yes, 0 no
6420 */
6421int
6422xmlIsBlankNode(xmlNodePtr node) {
6423 const xmlChar *cur;
6424 if (node == NULL) return(0);
6425
Daniel Veillard7db37732001-07-12 01:20:08 +00006426 if ((node->type != XML_TEXT_NODE) &&
6427 (node->type != XML_CDATA_SECTION_NODE))
6428 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006429 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006430 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006431 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006432 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006433 cur++;
6434 }
6435
6436 return(1);
6437}
6438
6439/**
6440 * xmlTextConcat:
6441 * @node: the node
6442 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006443 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006444 *
6445 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006446 *
6447 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006448 */
6449
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006450int
Owen Taylor3473f882001-02-23 17:55:21 +00006451xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006452 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006453
6454 if ((node->type != XML_TEXT_NODE) &&
6455 (node->type != XML_CDATA_SECTION_NODE)) {
6456#ifdef DEBUG_TREE
6457 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006458 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006459#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006460 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006461 }
William M. Brack7762bb12004-01-04 14:49:01 +00006462 /* need to check if content is currently in the dictionary */
6463 if ((node->doc != NULL) && (node->doc->dict != NULL) &&
6464 xmlDictOwns(node->doc->dict, node->content)) {
6465 node->content = xmlStrncatNew(node->content, content, len);
6466 } else {
6467 node->content = xmlStrncat(node->content, content, len);
6468 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006469 if (node->content == NULL)
6470 return(-1);
6471 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006472}
6473
6474/************************************************************************
6475 * *
6476 * Output : to a FILE or in memory *
6477 * *
6478 ************************************************************************/
6479
Owen Taylor3473f882001-02-23 17:55:21 +00006480/**
6481 * xmlBufferCreate:
6482 *
6483 * routine to create an XML buffer.
6484 * returns the new structure.
6485 */
6486xmlBufferPtr
6487xmlBufferCreate(void) {
6488 xmlBufferPtr ret;
6489
6490 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6491 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006492 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006493 return(NULL);
6494 }
6495 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006496 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006497 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006498 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006499 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006500 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006501 xmlFree(ret);
6502 return(NULL);
6503 }
6504 ret->content[0] = 0;
6505 return(ret);
6506}
6507
6508/**
6509 * xmlBufferCreateSize:
6510 * @size: initial size of buffer
6511 *
6512 * routine to create an XML buffer.
6513 * returns the new structure.
6514 */
6515xmlBufferPtr
6516xmlBufferCreateSize(size_t size) {
6517 xmlBufferPtr ret;
6518
6519 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6520 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006521 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006522 return(NULL);
6523 }
6524 ret->use = 0;
6525 ret->alloc = xmlBufferAllocScheme;
6526 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6527 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006528 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006529 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006530 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006531 xmlFree(ret);
6532 return(NULL);
6533 }
6534 ret->content[0] = 0;
6535 } else
6536 ret->content = NULL;
6537 return(ret);
6538}
6539
6540/**
Daniel Veillard53350552003-09-18 13:35:51 +00006541 * xmlBufferCreateStatic:
6542 * @mem: the memory area
6543 * @size: the size in byte
6544 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006545 * routine to create an XML buffer from an immutable memory area.
6546 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006547 * present until the end of the buffer lifetime.
6548 *
6549 * returns the new structure.
6550 */
6551xmlBufferPtr
6552xmlBufferCreateStatic(void *mem, size_t size) {
6553 xmlBufferPtr ret;
6554
6555 if ((mem == NULL) || (size == 0))
6556 return(NULL);
6557
6558 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6559 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006560 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006561 return(NULL);
6562 }
6563 ret->use = size;
6564 ret->size = size;
6565 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6566 ret->content = (xmlChar *) mem;
6567 return(ret);
6568}
6569
6570/**
Owen Taylor3473f882001-02-23 17:55:21 +00006571 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006572 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006573 * @scheme: allocation scheme to use
6574 *
6575 * Sets the allocation scheme for this buffer
6576 */
6577void
6578xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6579 xmlBufferAllocationScheme scheme) {
6580 if (buf == NULL) {
6581#ifdef DEBUG_BUFFER
6582 xmlGenericError(xmlGenericErrorContext,
6583 "xmlBufferSetAllocationScheme: buf == NULL\n");
6584#endif
6585 return;
6586 }
Daniel Veillard53350552003-09-18 13:35:51 +00006587 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006588
6589 buf->alloc = scheme;
6590}
6591
6592/**
6593 * xmlBufferFree:
6594 * @buf: the buffer to free
6595 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006596 * Frees an XML buffer. It frees both the content and the structure which
6597 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006598 */
6599void
6600xmlBufferFree(xmlBufferPtr buf) {
6601 if (buf == NULL) {
6602#ifdef DEBUG_BUFFER
6603 xmlGenericError(xmlGenericErrorContext,
6604 "xmlBufferFree: buf == NULL\n");
6605#endif
6606 return;
6607 }
Daniel Veillard53350552003-09-18 13:35:51 +00006608
6609 if ((buf->content != NULL) &&
6610 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006611 xmlFree(buf->content);
6612 }
Owen Taylor3473f882001-02-23 17:55:21 +00006613 xmlFree(buf);
6614}
6615
6616/**
6617 * xmlBufferEmpty:
6618 * @buf: the buffer
6619 *
6620 * empty a buffer.
6621 */
6622void
6623xmlBufferEmpty(xmlBufferPtr buf) {
6624 if (buf->content == NULL) return;
6625 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006626 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006627 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006628 } else {
6629 memset(buf->content, 0, buf->size);
6630 }
Owen Taylor3473f882001-02-23 17:55:21 +00006631}
6632
6633/**
6634 * xmlBufferShrink:
6635 * @buf: the buffer to dump
6636 * @len: the number of xmlChar to remove
6637 *
6638 * Remove the beginning of an XML buffer.
6639 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006640 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006641 */
6642int
6643xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6644 if (len == 0) return(0);
6645 if (len > buf->use) return(-1);
6646
6647 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006648 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6649 buf->content += len;
6650 } else {
6651 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6652 buf->content[buf->use] = 0;
6653 }
Owen Taylor3473f882001-02-23 17:55:21 +00006654 return(len);
6655}
6656
6657/**
6658 * xmlBufferGrow:
6659 * @buf: the buffer
6660 * @len: the minimum free size to allocate
6661 *
6662 * Grow the available space of an XML buffer.
6663 *
6664 * Returns the new available space or -1 in case of error
6665 */
6666int
6667xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6668 int size;
6669 xmlChar *newbuf;
6670
Daniel Veillard53350552003-09-18 13:35:51 +00006671 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006672 if (len + buf->use < buf->size) return(0);
6673
William M. Brack30fe43f2004-07-26 18:00:58 +00006674/*
6675 * Windows has a BIG problem on realloc timing, so we try to double
6676 * the buffer size (if that's enough) (bug 146697)
6677 */
6678#ifdef WIN32
6679 if (buf->size > len)
6680 size = buf->size * 2;
6681 else
6682 size = buf->use + len + 100;
6683#else
Owen Taylor3473f882001-02-23 17:55:21 +00006684 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00006685#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006686
6687 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006688 if (newbuf == NULL) {
6689 xmlTreeErrMemory("growing buffer");
6690 return(-1);
6691 }
Owen Taylor3473f882001-02-23 17:55:21 +00006692 buf->content = newbuf;
6693 buf->size = size;
6694 return(buf->size - buf->use);
6695}
6696
6697/**
6698 * xmlBufferDump:
6699 * @file: the file output
6700 * @buf: the buffer to dump
6701 *
6702 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006703 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006704 */
6705int
6706xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6707 int ret;
6708
6709 if (buf == NULL) {
6710#ifdef DEBUG_BUFFER
6711 xmlGenericError(xmlGenericErrorContext,
6712 "xmlBufferDump: buf == NULL\n");
6713#endif
6714 return(0);
6715 }
6716 if (buf->content == NULL) {
6717#ifdef DEBUG_BUFFER
6718 xmlGenericError(xmlGenericErrorContext,
6719 "xmlBufferDump: buf->content == NULL\n");
6720#endif
6721 return(0);
6722 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006723 if (file == NULL)
6724 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006725 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6726 return(ret);
6727}
6728
6729/**
6730 * xmlBufferContent:
6731 * @buf: the buffer
6732 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006733 * Function to extract the content of a buffer
6734 *
Owen Taylor3473f882001-02-23 17:55:21 +00006735 * Returns the internal content
6736 */
6737
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006738const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006739xmlBufferContent(const xmlBufferPtr buf)
6740{
6741 if(!buf)
6742 return NULL;
6743
6744 return buf->content;
6745}
6746
6747/**
6748 * xmlBufferLength:
6749 * @buf: the buffer
6750 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006751 * Function to get the length of a buffer
6752 *
Owen Taylor3473f882001-02-23 17:55:21 +00006753 * Returns the length of data in the internal content
6754 */
6755
6756int
6757xmlBufferLength(const xmlBufferPtr buf)
6758{
6759 if(!buf)
6760 return 0;
6761
6762 return buf->use;
6763}
6764
6765/**
6766 * xmlBufferResize:
6767 * @buf: the buffer to resize
6768 * @size: the desired size
6769 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006770 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006771 *
6772 * Returns 0 in case of problems, 1 otherwise
6773 */
6774int
6775xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6776{
6777 unsigned int newSize;
6778 xmlChar* rebuf = NULL;
6779
Daniel Veillard53350552003-09-18 13:35:51 +00006780 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6781
Owen Taylor3473f882001-02-23 17:55:21 +00006782 /* Don't resize if we don't have to */
6783 if (size < buf->size)
6784 return 1;
6785
6786 /* figure out new size */
6787 switch (buf->alloc){
6788 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillardbf629492004-04-20 22:20:59 +00006789 /*take care of empty case*/
6790 newSize = (buf->size ? buf->size*2 : size + 10);
Owen Taylor3473f882001-02-23 17:55:21 +00006791 while (size > newSize) newSize *= 2;
6792 break;
6793 case XML_BUFFER_ALLOC_EXACT:
6794 newSize = size+10;
6795 break;
6796 default:
6797 newSize = size+10;
6798 break;
6799 }
6800
6801 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006802 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006803 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006804 rebuf = (xmlChar *) xmlRealloc(buf->content,
6805 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006806 } else {
6807 /*
6808 * if we are reallocating a buffer far from being full, it's
6809 * better to make a new allocation and copy only the used range
6810 * and free the old one.
6811 */
6812 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6813 if (rebuf != NULL) {
6814 memcpy(rebuf, buf->content, buf->use);
6815 xmlFree(buf->content);
William M. Brack42331a92004-07-29 07:07:16 +00006816 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006817 }
6818 }
Owen Taylor3473f882001-02-23 17:55:21 +00006819 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006820 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006821 return 0;
6822 }
6823 buf->content = rebuf;
6824 buf->size = newSize;
6825
6826 return 1;
6827}
6828
6829/**
6830 * xmlBufferAdd:
6831 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006832 * @str: the #xmlChar string
6833 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006834 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006835 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006836 * str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006837 *
6838 * Returns 0 successful, a positive error code number otherwise
6839 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006840 */
William M. Bracka3215c72004-07-31 16:24:01 +00006841int
Owen Taylor3473f882001-02-23 17:55:21 +00006842xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6843 unsigned int needSize;
6844
6845 if (str == NULL) {
6846#ifdef DEBUG_BUFFER
6847 xmlGenericError(xmlGenericErrorContext,
6848 "xmlBufferAdd: str == NULL\n");
6849#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006850 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006851 }
William M. Bracka3215c72004-07-31 16:24:01 +00006852 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006853 if (len < -1) {
6854#ifdef DEBUG_BUFFER
6855 xmlGenericError(xmlGenericErrorContext,
6856 "xmlBufferAdd: len < 0\n");
6857#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006858 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006859 }
William M. Bracka3215c72004-07-31 16:24:01 +00006860 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006861
6862 if (len < 0)
6863 len = xmlStrlen(str);
6864
William M. Bracka3215c72004-07-31 16:24:01 +00006865 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006866
6867 needSize = buf->use + len + 2;
6868 if (needSize > buf->size){
6869 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006870 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006871 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006872 }
6873 }
6874
6875 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6876 buf->use += len;
6877 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006878 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006879}
6880
6881/**
6882 * xmlBufferAddHead:
6883 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006884 * @str: the #xmlChar string
6885 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006886 *
6887 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006888 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006889 *
6890 * Returns 0 successful, a positive error code number otherwise
6891 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006892 */
William M. Bracka3215c72004-07-31 16:24:01 +00006893int
Owen Taylor3473f882001-02-23 17:55:21 +00006894xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6895 unsigned int needSize;
6896
William M. Bracka3215c72004-07-31 16:24:01 +00006897 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006898 if (str == NULL) {
6899#ifdef DEBUG_BUFFER
6900 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006901 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006902#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006903 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006904 }
6905 if (len < -1) {
6906#ifdef DEBUG_BUFFER
6907 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006908 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006909#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006910 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006911 }
William M. Bracka3215c72004-07-31 16:24:01 +00006912 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006913
6914 if (len < 0)
6915 len = xmlStrlen(str);
6916
William M. Bracka3215c72004-07-31 16:24:01 +00006917 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006918
6919 needSize = buf->use + len + 2;
6920 if (needSize > buf->size){
6921 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006922 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006923 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006924 }
6925 }
6926
6927 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6928 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6929 buf->use += len;
6930 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006931 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006932}
6933
6934/**
6935 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00006936 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00006937 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006938 *
6939 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00006940 *
6941 * Returns 0 successful, a positive error code number otherwise
6942 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006943 */
William M. Bracka3215c72004-07-31 16:24:01 +00006944int
Owen Taylor3473f882001-02-23 17:55:21 +00006945xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
William M. Bracka3215c72004-07-31 16:24:01 +00006946 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
6947 if (str == NULL) return -1;
6948 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00006949}
6950
6951/**
6952 * xmlBufferCCat:
6953 * @buf: the buffer to dump
6954 * @str: the C char string
6955 *
6956 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00006957 *
6958 * Returns 0 successful, a positive error code number otherwise
6959 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006960 */
William M. Bracka3215c72004-07-31 16:24:01 +00006961int
Owen Taylor3473f882001-02-23 17:55:21 +00006962xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6963 const char *cur;
6964
William M. Bracka3215c72004-07-31 16:24:01 +00006965 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006966 if (str == NULL) {
6967#ifdef DEBUG_BUFFER
6968 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006969 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006970#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006971 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006972 }
6973 for (cur = str;*cur != 0;cur++) {
6974 if (buf->use + 10 >= buf->size) {
6975 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006976 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006977 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006978 }
6979 }
6980 buf->content[buf->use++] = *cur;
6981 }
6982 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006983 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006984}
6985
6986/**
6987 * xmlBufferWriteCHAR:
6988 * @buf: the XML buffer
6989 * @string: the string to add
6990 *
6991 * routine which manages and grows an output buffer. This one adds
6992 * xmlChars at the end of the buffer.
6993 */
6994void
Daniel Veillard53350552003-09-18 13:35:51 +00006995xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
6996 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006997 xmlBufferCat(buf, string);
6998}
6999
7000/**
7001 * xmlBufferWriteChar:
7002 * @buf: the XML buffer output
7003 * @string: the string to add
7004 *
7005 * routine which manage and grows an output buffer. This one add
7006 * C chars at the end of the array.
7007 */
7008void
7009xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillard53350552003-09-18 13:35:51 +00007010 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007011 xmlBufferCCat(buf, string);
7012}
7013
7014
7015/**
7016 * xmlBufferWriteQuotedString:
7017 * @buf: the XML buffer output
7018 * @string: the string to add
7019 *
7020 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00007021 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00007022 * quote or double-quotes internally
7023 */
7024void
7025xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00007026 const xmlChar *cur, *base;
Daniel Veillard53350552003-09-18 13:35:51 +00007027 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00007028 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00007029 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00007030#ifdef DEBUG_BUFFER
7031 xmlGenericError(xmlGenericErrorContext,
7032 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7033#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00007034 xmlBufferCCat(buf, "\"");
7035 base = cur = string;
7036 while(*cur != 0){
7037 if(*cur == '"'){
7038 if (base != cur)
7039 xmlBufferAdd(buf, base, cur - base);
7040 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7041 cur++;
7042 base = cur;
7043 }
7044 else {
7045 cur++;
7046 }
7047 }
7048 if (base != cur)
7049 xmlBufferAdd(buf, base, cur - base);
7050 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007051 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007052 else{
7053 xmlBufferCCat(buf, "\'");
7054 xmlBufferCat(buf, string);
7055 xmlBufferCCat(buf, "\'");
7056 }
Owen Taylor3473f882001-02-23 17:55:21 +00007057 } else {
7058 xmlBufferCCat(buf, "\"");
7059 xmlBufferCat(buf, string);
7060 xmlBufferCCat(buf, "\"");
7061 }
7062}
7063
7064
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007065/**
7066 * xmlGetDocCompressMode:
7067 * @doc: the document
7068 *
7069 * get the compression ratio for a document, ZLIB based
7070 * Returns 0 (uncompressed) to 9 (max compression)
7071 */
7072int
7073xmlGetDocCompressMode (xmlDocPtr doc) {
7074 if (doc == NULL) return(-1);
7075 return(doc->compression);
7076}
7077
7078/**
7079 * xmlSetDocCompressMode:
7080 * @doc: the document
7081 * @mode: the compression ratio
7082 *
7083 * set the compression ratio for a document, ZLIB based
7084 * Correct values: 0 (uncompressed) to 9 (max compression)
7085 */
7086void
7087xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7088 if (doc == NULL) return;
7089 if (mode < 0) doc->compression = 0;
7090 else if (mode > 9) doc->compression = 9;
7091 else doc->compression = mode;
7092}
7093
7094/**
7095 * xmlGetCompressMode:
7096 *
7097 * get the default compression mode used, ZLIB based.
7098 * Returns 0 (uncompressed) to 9 (max compression)
7099 */
7100int
7101xmlGetCompressMode(void)
7102{
7103 return (xmlCompressMode);
7104}
7105
7106/**
7107 * xmlSetCompressMode:
7108 * @mode: the compression ratio
7109 *
7110 * set the default compression mode used, ZLIB based
7111 * Correct values: 0 (uncompressed) to 9 (max compression)
7112 */
7113void
7114xmlSetCompressMode(int mode) {
7115 if (mode < 0) xmlCompressMode = 0;
7116 else if (mode > 9) xmlCompressMode = 9;
7117 else xmlCompressMode = mode;
7118}
7119