blob: cbf0664a0a43c4d2ab29624c98a6540fb18e78e5 [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 Veillarde96a2a42003-09-24 21:23:56 +00001122 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001123
Daniel Veillarda880b122003-04-21 21:36:41 +00001124 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001125 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1126
Daniel Veillard76d66f42001-05-16 21:05:17 +00001127 /*
1128 * Do this before freeing the children list to avoid ID lookups
1129 */
1130 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1131 cur->ids = NULL;
1132 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1133 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001134 extSubset = cur->extSubset;
1135 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001136 if (intSubset == extSubset)
1137 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001138 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001139 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001140 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001141 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001142 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001143 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001144 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001145 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001146 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001147 }
1148
1149 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001150 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001151
1152 DICT_FREE(cur->version)
1153 DICT_FREE(cur->name)
1154 DICT_FREE(cur->encoding)
1155 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001156 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001157 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001158}
1159
1160/**
1161 * xmlStringLenGetNodeList:
1162 * @doc: the document
1163 * @value: the value of the text
1164 * @len: the length of the string value
1165 *
1166 * Parse the value string and build the node list associated. Should
1167 * produce a flat tree with only TEXTs and ENTITY_REFs.
1168 * Returns a pointer to the first child
1169 */
1170xmlNodePtr
1171xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1172 xmlNodePtr ret = NULL, last = NULL;
1173 xmlNodePtr node;
1174 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001175 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001176 const xmlChar *q;
1177 xmlEntityPtr ent;
1178
1179 if (value == NULL) return(NULL);
1180
1181 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001182 while ((cur < end) && (*cur != 0)) {
1183 if (cur[0] == '&') {
1184 int charval = 0;
1185 xmlChar tmp;
1186
Owen Taylor3473f882001-02-23 17:55:21 +00001187 /*
1188 * Save the current text.
1189 */
1190 if (cur != q) {
1191 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1192 xmlNodeAddContentLen(last, q, cur - q);
1193 } else {
1194 node = xmlNewDocTextLen(doc, q, cur - q);
1195 if (node == NULL) return(ret);
1196 if (last == NULL)
1197 last = ret = node;
1198 else {
1199 last->next = node;
1200 node->prev = last;
1201 last = node;
1202 }
1203 }
1204 }
Owen Taylor3473f882001-02-23 17:55:21 +00001205 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001206 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1207 cur += 3;
1208 if (cur < end)
1209 tmp = *cur;
1210 else
1211 tmp = 0;
1212 while (tmp != ';') { /* Non input consuming loop */
1213 if ((tmp >= '0') && (tmp <= '9'))
1214 charval = charval * 16 + (tmp - '0');
1215 else if ((tmp >= 'a') && (tmp <= 'f'))
1216 charval = charval * 16 + (tmp - 'a') + 10;
1217 else if ((tmp >= 'A') && (tmp <= 'F'))
1218 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001219 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001220 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1221 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001222 charval = 0;
1223 break;
1224 }
1225 cur++;
1226 if (cur < end)
1227 tmp = *cur;
1228 else
1229 tmp = 0;
1230 }
1231 if (tmp == ';')
1232 cur++;
1233 q = cur;
1234 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1235 cur += 2;
1236 if (cur < end)
1237 tmp = *cur;
1238 else
1239 tmp = 0;
1240 while (tmp != ';') { /* Non input consuming loops */
1241 if ((tmp >= '0') && (tmp <= '9'))
1242 charval = charval * 10 + (tmp - '0');
1243 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001244 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1245 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001246 charval = 0;
1247 break;
1248 }
1249 cur++;
1250 if (cur < end)
1251 tmp = *cur;
1252 else
1253 tmp = 0;
1254 }
1255 if (tmp == ';')
1256 cur++;
1257 q = cur;
1258 } else {
1259 /*
1260 * Read the entity string
1261 */
1262 cur++;
1263 q = cur;
1264 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1265 if ((cur >= end) || (*cur == 0)) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001266 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1267 (const char *) q);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001268 return(ret);
1269 }
1270 if (cur != q) {
1271 /*
1272 * Predefined entities don't generate nodes
1273 */
1274 val = xmlStrndup(q, cur - q);
1275 ent = xmlGetDocEntity(doc, val);
1276 if ((ent != NULL) &&
1277 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1278 if (last == NULL) {
1279 node = xmlNewDocText(doc, ent->content);
1280 last = ret = node;
1281 } else if (last->type != XML_TEXT_NODE) {
1282 node = xmlNewDocText(doc, ent->content);
1283 last = xmlAddNextSibling(last, node);
1284 } else
1285 xmlNodeAddContent(last, ent->content);
1286
1287 } else {
1288 /*
1289 * Create a new REFERENCE_REF node
1290 */
1291 node = xmlNewReference(doc, val);
1292 if (node == NULL) {
1293 if (val != NULL) xmlFree(val);
1294 return(ret);
1295 }
1296 else if ((ent != NULL) && (ent->children == NULL)) {
1297 xmlNodePtr temp;
1298
1299 ent->children = xmlStringGetNodeList(doc,
1300 (const xmlChar*)node->content);
1301 ent->owner = 1;
1302 temp = ent->children;
1303 while (temp) {
1304 temp->parent = (xmlNodePtr)ent;
1305 temp = temp->next;
1306 }
1307 }
1308 if (last == NULL) {
1309 last = ret = node;
1310 } else {
1311 last = xmlAddNextSibling(last, node);
1312 }
1313 }
1314 xmlFree(val);
1315 }
1316 cur++;
1317 q = cur;
1318 }
1319 if (charval != 0) {
1320 xmlChar buf[10];
1321 int l;
1322
1323 l = xmlCopyCharMultiByte(buf, charval);
1324 buf[l] = 0;
1325 node = xmlNewDocText(doc, buf);
1326 if (node != NULL) {
1327 if (last == NULL) {
1328 last = ret = node;
1329 } else {
1330 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001331 }
1332 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001333 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001334 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001335 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001336 cur++;
1337 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001338 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001339 /*
1340 * Handle the last piece of text.
1341 */
1342 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1343 xmlNodeAddContentLen(last, q, cur - q);
1344 } else {
1345 node = xmlNewDocTextLen(doc, q, cur - q);
1346 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001347 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001348 last = ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001349 } else {
1350 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001351 }
1352 }
1353 }
1354 return(ret);
1355}
1356
1357/**
1358 * xmlStringGetNodeList:
1359 * @doc: the document
1360 * @value: the value of the attribute
1361 *
1362 * Parse the value string and build the node list associated. Should
1363 * produce a flat tree with only TEXTs and ENTITY_REFs.
1364 * Returns a pointer to the first child
1365 */
1366xmlNodePtr
1367xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1368 xmlNodePtr ret = NULL, last = NULL;
1369 xmlNodePtr node;
1370 xmlChar *val;
1371 const xmlChar *cur = value;
1372 const xmlChar *q;
1373 xmlEntityPtr ent;
1374
1375 if (value == NULL) return(NULL);
1376
1377 q = cur;
1378 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001379 if (cur[0] == '&') {
1380 int charval = 0;
1381 xmlChar tmp;
1382
Owen Taylor3473f882001-02-23 17:55:21 +00001383 /*
1384 * Save the current text.
1385 */
1386 if (cur != q) {
1387 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1388 xmlNodeAddContentLen(last, q, cur - q);
1389 } else {
1390 node = xmlNewDocTextLen(doc, q, cur - q);
1391 if (node == NULL) return(ret);
1392 if (last == NULL)
1393 last = ret = node;
1394 else {
1395 last->next = node;
1396 node->prev = last;
1397 last = node;
1398 }
1399 }
1400 }
Owen Taylor3473f882001-02-23 17:55:21 +00001401 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001402 if ((cur[1] == '#') && (cur[2] == 'x')) {
1403 cur += 3;
1404 tmp = *cur;
1405 while (tmp != ';') { /* Non input consuming loop */
1406 if ((tmp >= '0') && (tmp <= '9'))
1407 charval = charval * 16 + (tmp - '0');
1408 else if ((tmp >= 'a') && (tmp <= 'f'))
1409 charval = charval * 16 + (tmp - 'a') + 10;
1410 else if ((tmp >= 'A') && (tmp <= 'F'))
1411 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001412 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001413 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1414 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001415 charval = 0;
1416 break;
1417 }
1418 cur++;
1419 tmp = *cur;
1420 }
1421 if (tmp == ';')
1422 cur++;
1423 q = cur;
1424 } else if (cur[1] == '#') {
1425 cur += 2;
1426 tmp = *cur;
1427 while (tmp != ';') { /* Non input consuming loops */
1428 if ((tmp >= '0') && (tmp <= '9'))
1429 charval = charval * 10 + (tmp - '0');
1430 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001431 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1432 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001433 charval = 0;
1434 break;
1435 }
1436 cur++;
1437 tmp = *cur;
1438 }
1439 if (tmp == ';')
1440 cur++;
1441 q = cur;
1442 } else {
1443 /*
1444 * Read the entity string
1445 */
1446 cur++;
1447 q = cur;
1448 while ((*cur != 0) && (*cur != ';')) cur++;
1449 if (*cur == 0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001450 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1451 (xmlNodePtr) doc, (const char *) q);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001452 return(ret);
1453 }
1454 if (cur != q) {
1455 /*
1456 * Predefined entities don't generate nodes
1457 */
1458 val = xmlStrndup(q, cur - q);
1459 ent = xmlGetDocEntity(doc, val);
1460 if ((ent != NULL) &&
1461 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1462 if (last == NULL) {
1463 node = xmlNewDocText(doc, ent->content);
1464 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001465 } else if (last->type != XML_TEXT_NODE) {
1466 node = xmlNewDocText(doc, ent->content);
1467 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001468 } else
1469 xmlNodeAddContent(last, ent->content);
1470
1471 } else {
1472 /*
1473 * Create a new REFERENCE_REF node
1474 */
1475 node = xmlNewReference(doc, val);
1476 if (node == NULL) {
1477 if (val != NULL) xmlFree(val);
1478 return(ret);
1479 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001480 else if ((ent != NULL) && (ent->children == NULL)) {
1481 xmlNodePtr temp;
1482
1483 ent->children = xmlStringGetNodeList(doc,
1484 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001485 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001486 temp = ent->children;
1487 while (temp) {
1488 temp->parent = (xmlNodePtr)ent;
1489 temp = temp->next;
1490 }
1491 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001492 if (last == NULL) {
1493 last = ret = node;
1494 } else {
1495 last = xmlAddNextSibling(last, node);
1496 }
1497 }
1498 xmlFree(val);
1499 }
1500 cur++;
1501 q = cur;
1502 }
1503 if (charval != 0) {
1504 xmlChar buf[10];
1505 int len;
1506
1507 len = xmlCopyCharMultiByte(buf, charval);
1508 buf[len] = 0;
1509 node = xmlNewDocText(doc, buf);
1510 if (node != NULL) {
1511 if (last == NULL) {
1512 last = ret = node;
1513 } else {
1514 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001515 }
1516 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001517
1518 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001519 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001520 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001521 cur++;
1522 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001523 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001524 /*
1525 * Handle the last piece of text.
1526 */
1527 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1528 xmlNodeAddContentLen(last, q, cur - q);
1529 } else {
1530 node = xmlNewDocTextLen(doc, q, cur - q);
1531 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001532 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001533 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001534 } else {
1535 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001536 }
1537 }
1538 }
1539 return(ret);
1540}
1541
1542/**
1543 * xmlNodeListGetString:
1544 * @doc: the document
1545 * @list: a Node list
1546 * @inLine: should we replace entity contents or show their external form
1547 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001548 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001549 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001550 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001551 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001552 */
1553xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001554xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1555{
Owen Taylor3473f882001-02-23 17:55:21 +00001556 xmlNodePtr node = list;
1557 xmlChar *ret = NULL;
1558 xmlEntityPtr ent;
1559
Daniel Veillard7646b182002-04-20 06:41:40 +00001560 if (list == NULL)
1561 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001562
1563 while (node != NULL) {
1564 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001565 (node->type == XML_CDATA_SECTION_NODE)) {
1566 if (inLine) {
1567 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001568 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001569 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001570
Daniel Veillard7646b182002-04-20 06:41:40 +00001571 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1572 if (buffer != NULL) {
1573 ret = xmlStrcat(ret, buffer);
1574 xmlFree(buffer);
1575 }
1576 }
1577 } else if (node->type == XML_ENTITY_REF_NODE) {
1578 if (inLine) {
1579 ent = xmlGetDocEntity(doc, node->name);
1580 if (ent != NULL) {
1581 xmlChar *buffer;
1582
1583 /* an entity content can be any "well balanced chunk",
1584 * i.e. the result of the content [43] production:
1585 * http://www.w3.org/TR/REC-xml#NT-content.
1586 * So it can contain text, CDATA section or nested
1587 * entity reference nodes (among others).
1588 * -> we recursive call xmlNodeListGetString()
1589 * which handles these types */
1590 buffer = xmlNodeListGetString(doc, ent->children, 1);
1591 if (buffer != NULL) {
1592 ret = xmlStrcat(ret, buffer);
1593 xmlFree(buffer);
1594 }
1595 } else {
1596 ret = xmlStrcat(ret, node->content);
1597 }
1598 } else {
1599 xmlChar buf[2];
1600
1601 buf[0] = '&';
1602 buf[1] = 0;
1603 ret = xmlStrncat(ret, buf, 1);
1604 ret = xmlStrcat(ret, node->name);
1605 buf[0] = ';';
1606 buf[1] = 0;
1607 ret = xmlStrncat(ret, buf, 1);
1608 }
1609 }
1610#if 0
1611 else {
1612 xmlGenericError(xmlGenericErrorContext,
1613 "xmlGetNodeListString : invalid node type %d\n",
1614 node->type);
1615 }
1616#endif
1617 node = node->next;
1618 }
1619 return (ret);
1620}
Daniel Veillard652327a2003-09-29 18:02:38 +00001621
1622#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001623/**
1624 * xmlNodeListGetRawString:
1625 * @doc: the document
1626 * @list: a Node list
1627 * @inLine: should we replace entity contents or show their external form
1628 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001629 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001630 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1631 * this function doesn't do any character encoding handling.
1632 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001633 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001634 */
1635xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001636xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1637{
Owen Taylor3473f882001-02-23 17:55:21 +00001638 xmlNodePtr node = list;
1639 xmlChar *ret = NULL;
1640 xmlEntityPtr ent;
1641
Daniel Veillard7646b182002-04-20 06:41:40 +00001642 if (list == NULL)
1643 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001644
1645 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001646 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001647 (node->type == XML_CDATA_SECTION_NODE)) {
1648 if (inLine) {
1649 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001650 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001651 xmlChar *buffer;
1652
1653 buffer = xmlEncodeSpecialChars(doc, node->content);
1654 if (buffer != NULL) {
1655 ret = xmlStrcat(ret, buffer);
1656 xmlFree(buffer);
1657 }
1658 }
1659 } else if (node->type == XML_ENTITY_REF_NODE) {
1660 if (inLine) {
1661 ent = xmlGetDocEntity(doc, node->name);
1662 if (ent != NULL) {
1663 xmlChar *buffer;
1664
1665 /* an entity content can be any "well balanced chunk",
1666 * i.e. the result of the content [43] production:
1667 * http://www.w3.org/TR/REC-xml#NT-content.
1668 * So it can contain text, CDATA section or nested
1669 * entity reference nodes (among others).
1670 * -> we recursive call xmlNodeListGetRawString()
1671 * which handles these types */
1672 buffer =
1673 xmlNodeListGetRawString(doc, ent->children, 1);
1674 if (buffer != NULL) {
1675 ret = xmlStrcat(ret, buffer);
1676 xmlFree(buffer);
1677 }
1678 } else {
1679 ret = xmlStrcat(ret, node->content);
1680 }
1681 } else {
1682 xmlChar buf[2];
1683
1684 buf[0] = '&';
1685 buf[1] = 0;
1686 ret = xmlStrncat(ret, buf, 1);
1687 ret = xmlStrcat(ret, node->name);
1688 buf[0] = ';';
1689 buf[1] = 0;
1690 ret = xmlStrncat(ret, buf, 1);
1691 }
1692 }
Owen Taylor3473f882001-02-23 17:55:21 +00001693#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001694 else {
1695 xmlGenericError(xmlGenericErrorContext,
1696 "xmlGetNodeListString : invalid node type %d\n",
1697 node->type);
1698 }
Owen Taylor3473f882001-02-23 17:55:21 +00001699#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001700 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001701 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001702 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001703}
Daniel Veillard652327a2003-09-29 18:02:38 +00001704#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001705
Daniel Veillard2156d432004-03-04 15:59:36 +00001706#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00001707/**
1708 * xmlNewProp:
1709 * @node: the holding node
1710 * @name: the name of the attribute
1711 * @value: the value of the attribute
1712 *
1713 * Create a new property carried by a node.
1714 * Returns a pointer to the attribute
1715 */
1716xmlAttrPtr
1717xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1718 xmlAttrPtr cur;
1719 xmlDocPtr doc = NULL;
1720
1721 if (name == NULL) {
1722#ifdef DEBUG_TREE
1723 xmlGenericError(xmlGenericErrorContext,
1724 "xmlNewProp : name == NULL\n");
1725#endif
1726 return(NULL);
1727 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001728 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1729 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001730
1731 /*
1732 * Allocate a new property and fill the fields.
1733 */
1734 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1735 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001736 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001737 return(NULL);
1738 }
1739 memset(cur, 0, sizeof(xmlAttr));
1740 cur->type = XML_ATTRIBUTE_NODE;
1741
1742 cur->parent = node;
1743 if (node != NULL) {
1744 doc = node->doc;
1745 cur->doc = doc;
1746 }
1747 cur->name = xmlStrdup(name);
1748 if (value != NULL) {
1749 xmlChar *buffer;
1750 xmlNodePtr tmp;
1751
1752 buffer = xmlEncodeEntitiesReentrant(doc, value);
1753 cur->children = xmlStringGetNodeList(doc, buffer);
1754 cur->last = NULL;
1755 tmp = cur->children;
1756 while (tmp != NULL) {
1757 tmp->parent = (xmlNodePtr) cur;
1758 tmp->doc = doc;
1759 if (tmp->next == NULL)
1760 cur->last = tmp;
1761 tmp = tmp->next;
1762 }
1763 xmlFree(buffer);
1764 }
1765
1766 /*
1767 * Add it at the end to preserve parsing order ...
1768 */
1769 if (node != NULL) {
1770 if (node->properties == NULL) {
1771 node->properties = cur;
1772 } else {
1773 xmlAttrPtr prev = node->properties;
1774
1775 while (prev->next != NULL) prev = prev->next;
1776 prev->next = cur;
1777 cur->prev = prev;
1778 }
1779 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001780
Daniel Veillarda880b122003-04-21 21:36:41 +00001781 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001782 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001783 return(cur);
1784}
Daniel Veillard652327a2003-09-29 18:02:38 +00001785#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001786
1787/**
1788 * xmlNewNsProp:
1789 * @node: the holding node
1790 * @ns: the namespace
1791 * @name: the name of the attribute
1792 * @value: the value of the attribute
1793 *
1794 * Create a new property tagged with a namespace and carried by a node.
1795 * Returns a pointer to the attribute
1796 */
1797xmlAttrPtr
1798xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1799 const xmlChar *value) {
1800 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001801 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001802
1803 if (name == NULL) {
1804#ifdef DEBUG_TREE
1805 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001806 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001807#endif
1808 return(NULL);
1809 }
1810
1811 /*
1812 * Allocate a new property and fill the fields.
1813 */
1814 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1815 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001816 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001817 return(NULL);
1818 }
1819 memset(cur, 0, sizeof(xmlAttr));
1820 cur->type = XML_ATTRIBUTE_NODE;
1821
1822 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001823 if (node != NULL) {
1824 doc = node->doc;
1825 cur->doc = doc;
1826 }
Owen Taylor3473f882001-02-23 17:55:21 +00001827 cur->ns = ns;
1828 cur->name = xmlStrdup(name);
1829 if (value != NULL) {
1830 xmlChar *buffer;
1831 xmlNodePtr tmp;
1832
Daniel Veillarda682b212001-06-07 19:59:42 +00001833 buffer = xmlEncodeEntitiesReentrant(doc, value);
1834 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001835 cur->last = NULL;
1836 tmp = cur->children;
1837 while (tmp != NULL) {
1838 tmp->parent = (xmlNodePtr) cur;
1839 if (tmp->next == NULL)
1840 cur->last = tmp;
1841 tmp = tmp->next;
1842 }
1843 xmlFree(buffer);
1844 }
1845
1846 /*
1847 * Add it at the end to preserve parsing order ...
1848 */
1849 if (node != NULL) {
1850 if (node->properties == NULL) {
1851 node->properties = cur;
1852 } else {
1853 xmlAttrPtr prev = node->properties;
1854
1855 while (prev->next != NULL) prev = prev->next;
1856 prev->next = cur;
1857 cur->prev = prev;
1858 }
1859 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001860
Daniel Veillarda880b122003-04-21 21:36:41 +00001861 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001862 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001863 return(cur);
1864}
1865
1866/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001867 * xmlNewNsPropEatName:
1868 * @node: the holding node
1869 * @ns: the namespace
1870 * @name: the name of the attribute
1871 * @value: the value of the attribute
1872 *
1873 * Create a new property tagged with a namespace and carried by a node.
1874 * Returns a pointer to the attribute
1875 */
1876xmlAttrPtr
1877xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1878 const xmlChar *value) {
1879 xmlAttrPtr cur;
1880 xmlDocPtr doc = NULL;
1881
1882 if (name == NULL) {
1883#ifdef DEBUG_TREE
1884 xmlGenericError(xmlGenericErrorContext,
1885 "xmlNewNsPropEatName : name == NULL\n");
1886#endif
1887 return(NULL);
1888 }
1889
1890 /*
1891 * Allocate a new property and fill the fields.
1892 */
1893 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1894 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001895 xmlTreeErrMemory("building attribute");
Daniel Veillard46de64e2002-05-29 08:21:33 +00001896 return(NULL);
1897 }
1898 memset(cur, 0, sizeof(xmlAttr));
1899 cur->type = XML_ATTRIBUTE_NODE;
1900
1901 cur->parent = node;
1902 if (node != NULL) {
1903 doc = node->doc;
1904 cur->doc = doc;
1905 }
1906 cur->ns = ns;
1907 cur->name = name;
1908 if (value != NULL) {
1909 xmlChar *buffer;
1910 xmlNodePtr tmp;
1911
1912 buffer = xmlEncodeEntitiesReentrant(doc, value);
1913 cur->children = xmlStringGetNodeList(doc, buffer);
1914 cur->last = NULL;
1915 tmp = cur->children;
1916 while (tmp != NULL) {
1917 tmp->parent = (xmlNodePtr) cur;
1918 if (tmp->next == NULL)
1919 cur->last = tmp;
1920 tmp = tmp->next;
1921 }
1922 xmlFree(buffer);
1923 }
1924
1925 /*
1926 * Add it at the end to preserve parsing order ...
1927 */
1928 if (node != NULL) {
1929 if (node->properties == NULL) {
1930 node->properties = cur;
1931 } else {
1932 xmlAttrPtr prev = node->properties;
1933
1934 while (prev->next != NULL) prev = prev->next;
1935 prev->next = cur;
1936 cur->prev = prev;
1937 }
1938 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001939
Daniel Veillarda880b122003-04-21 21:36:41 +00001940 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001941 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001942 return(cur);
1943}
1944
1945/**
Owen Taylor3473f882001-02-23 17:55:21 +00001946 * xmlNewDocProp:
1947 * @doc: the document
1948 * @name: the name of the attribute
1949 * @value: the value of the attribute
1950 *
1951 * Create a new property carried by a document.
1952 * Returns a pointer to the attribute
1953 */
1954xmlAttrPtr
1955xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1956 xmlAttrPtr cur;
1957
1958 if (name == NULL) {
1959#ifdef DEBUG_TREE
1960 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001961 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001962#endif
1963 return(NULL);
1964 }
1965
1966 /*
1967 * Allocate a new property and fill the fields.
1968 */
1969 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1970 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001971 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001972 return(NULL);
1973 }
1974 memset(cur, 0, sizeof(xmlAttr));
1975 cur->type = XML_ATTRIBUTE_NODE;
1976
1977 cur->name = xmlStrdup(name);
1978 cur->doc = doc;
1979 if (value != NULL) {
1980 xmlNodePtr tmp;
1981
1982 cur->children = xmlStringGetNodeList(doc, value);
1983 cur->last = NULL;
1984
1985 tmp = cur->children;
1986 while (tmp != NULL) {
1987 tmp->parent = (xmlNodePtr) cur;
1988 if (tmp->next == NULL)
1989 cur->last = tmp;
1990 tmp = tmp->next;
1991 }
1992 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001993
Daniel Veillarda880b122003-04-21 21:36:41 +00001994 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001995 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001996 return(cur);
1997}
1998
1999/**
2000 * xmlFreePropList:
2001 * @cur: the first property in the list
2002 *
2003 * Free a property and all its siblings, all the children are freed too.
2004 */
2005void
2006xmlFreePropList(xmlAttrPtr cur) {
2007 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002008 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002009 while (cur != NULL) {
2010 next = cur->next;
2011 xmlFreeProp(cur);
2012 cur = next;
2013 }
2014}
2015
2016/**
2017 * xmlFreeProp:
2018 * @cur: an attribute
2019 *
2020 * Free one attribute, all the content is freed too
2021 */
2022void
2023xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002024 xmlDictPtr dict = NULL;
2025 if (cur == NULL) return;
2026
2027 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002028
Daniel Veillarda880b122003-04-21 21:36:41 +00002029 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002030 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
2031
Owen Taylor3473f882001-02-23 17:55:21 +00002032 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00002033 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
2034 ((cur->parent->doc->intSubset != NULL) ||
2035 (cur->parent->doc->extSubset != NULL))) {
2036 if (xmlIsID(cur->parent->doc, cur->parent, cur))
2037 xmlRemoveID(cur->parent->doc, cur);
2038 }
Owen Taylor3473f882001-02-23 17:55:21 +00002039 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002040 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002041 xmlFree(cur);
2042}
2043
Daniel Veillard652327a2003-09-29 18:02:38 +00002044#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002045/**
2046 * xmlRemoveProp:
2047 * @cur: an attribute
2048 *
2049 * Unlink and free one attribute, all the content is freed too
2050 * Note this doesn't work for namespace definition attributes
2051 *
2052 * Returns 0 if success and -1 in case of error.
2053 */
2054int
2055xmlRemoveProp(xmlAttrPtr cur) {
2056 xmlAttrPtr tmp;
2057 if (cur == NULL) {
2058#ifdef DEBUG_TREE
2059 xmlGenericError(xmlGenericErrorContext,
2060 "xmlRemoveProp : cur == NULL\n");
2061#endif
2062 return(-1);
2063 }
2064 if (cur->parent == NULL) {
2065#ifdef DEBUG_TREE
2066 xmlGenericError(xmlGenericErrorContext,
2067 "xmlRemoveProp : cur->parent == NULL\n");
2068#endif
2069 return(-1);
2070 }
2071 tmp = cur->parent->properties;
2072 if (tmp == cur) {
2073 cur->parent->properties = cur->next;
2074 xmlFreeProp(cur);
2075 return(0);
2076 }
2077 while (tmp != NULL) {
2078 if (tmp->next == cur) {
2079 tmp->next = cur->next;
2080 if (tmp->next != NULL)
2081 tmp->next->prev = tmp;
2082 xmlFreeProp(cur);
2083 return(0);
2084 }
2085 tmp = tmp->next;
2086 }
2087#ifdef DEBUG_TREE
2088 xmlGenericError(xmlGenericErrorContext,
2089 "xmlRemoveProp : attribute not owned by its node\n");
2090#endif
2091 return(-1);
2092}
Daniel Veillard652327a2003-09-29 18:02:38 +00002093#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002094
2095/**
2096 * xmlNewPI:
2097 * @name: the processing instruction name
2098 * @content: the PI content
2099 *
2100 * Creation of a processing instruction element.
2101 * Returns a pointer to the new node object.
2102 */
2103xmlNodePtr
2104xmlNewPI(const xmlChar *name, const xmlChar *content) {
2105 xmlNodePtr cur;
2106
2107 if (name == NULL) {
2108#ifdef DEBUG_TREE
2109 xmlGenericError(xmlGenericErrorContext,
2110 "xmlNewPI : name == NULL\n");
2111#endif
2112 return(NULL);
2113 }
2114
2115 /*
2116 * Allocate a new node and fill the fields.
2117 */
2118 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2119 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002120 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002121 return(NULL);
2122 }
2123 memset(cur, 0, sizeof(xmlNode));
2124 cur->type = XML_PI_NODE;
2125
2126 cur->name = xmlStrdup(name);
2127 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002128 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002129 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002130
Daniel Veillarda880b122003-04-21 21:36:41 +00002131 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002132 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002133 return(cur);
2134}
2135
2136/**
2137 * xmlNewNode:
2138 * @ns: namespace if any
2139 * @name: the node name
2140 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002141 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002142 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002143 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2144 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002145 */
2146xmlNodePtr
2147xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2148 xmlNodePtr cur;
2149
2150 if (name == NULL) {
2151#ifdef DEBUG_TREE
2152 xmlGenericError(xmlGenericErrorContext,
2153 "xmlNewNode : name == NULL\n");
2154#endif
2155 return(NULL);
2156 }
2157
2158 /*
2159 * Allocate a new node and fill the fields.
2160 */
2161 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2162 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002163 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002164 return(NULL);
2165 }
2166 memset(cur, 0, sizeof(xmlNode));
2167 cur->type = XML_ELEMENT_NODE;
2168
2169 cur->name = xmlStrdup(name);
2170 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002171
Daniel Veillarda880b122003-04-21 21:36:41 +00002172 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002173 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002174 return(cur);
2175}
2176
2177/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002178 * xmlNewNodeEatName:
2179 * @ns: namespace if any
2180 * @name: the node name
2181 *
2182 * Creation of a new node element. @ns is optional (NULL).
2183 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002184 * Returns a pointer to the new node object, with pointer @name as
2185 * new node's name. Use xmlNewNode() if a copy of @name string is
2186 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002187 */
2188xmlNodePtr
2189xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2190 xmlNodePtr cur;
2191
2192 if (name == NULL) {
2193#ifdef DEBUG_TREE
2194 xmlGenericError(xmlGenericErrorContext,
2195 "xmlNewNode : name == NULL\n");
2196#endif
2197 return(NULL);
2198 }
2199
2200 /*
2201 * Allocate a new node and fill the fields.
2202 */
2203 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2204 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002205 xmlTreeErrMemory("building node");
Daniel Veillard46de64e2002-05-29 08:21:33 +00002206 return(NULL);
2207 }
2208 memset(cur, 0, sizeof(xmlNode));
2209 cur->type = XML_ELEMENT_NODE;
2210
2211 cur->name = name;
2212 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002213
Daniel Veillarda880b122003-04-21 21:36:41 +00002214 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002215 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002216 return(cur);
2217}
2218
2219/**
Owen Taylor3473f882001-02-23 17:55:21 +00002220 * xmlNewDocNode:
2221 * @doc: the document
2222 * @ns: namespace if any
2223 * @name: the node name
2224 * @content: the XML text content if any
2225 *
2226 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002227 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002228 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2229 * references, but XML special chars need to be escaped first by using
2230 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2231 * need entities support.
2232 *
2233 * Returns a pointer to the new node object.
2234 */
2235xmlNodePtr
2236xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2237 const xmlChar *name, const xmlChar *content) {
2238 xmlNodePtr cur;
2239
2240 cur = xmlNewNode(ns, name);
2241 if (cur != NULL) {
2242 cur->doc = doc;
2243 if (content != NULL) {
2244 cur->children = xmlStringGetNodeList(doc, content);
2245 UPDATE_LAST_CHILD_AND_PARENT(cur)
2246 }
2247 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002248
Owen Taylor3473f882001-02-23 17:55:21 +00002249 return(cur);
2250}
2251
Daniel Veillard46de64e2002-05-29 08:21:33 +00002252/**
2253 * xmlNewDocNodeEatName:
2254 * @doc: the document
2255 * @ns: namespace if any
2256 * @name: the node name
2257 * @content: the XML text content if any
2258 *
2259 * Creation of a new node element within a document. @ns and @content
2260 * are optional (NULL).
2261 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2262 * references, but XML special chars need to be escaped first by using
2263 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2264 * need entities support.
2265 *
2266 * Returns a pointer to the new node object.
2267 */
2268xmlNodePtr
2269xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2270 xmlChar *name, const xmlChar *content) {
2271 xmlNodePtr cur;
2272
2273 cur = xmlNewNodeEatName(ns, name);
2274 if (cur != NULL) {
2275 cur->doc = doc;
2276 if (content != NULL) {
2277 cur->children = xmlStringGetNodeList(doc, content);
2278 UPDATE_LAST_CHILD_AND_PARENT(cur)
2279 }
2280 }
2281 return(cur);
2282}
2283
Daniel Veillard652327a2003-09-29 18:02:38 +00002284#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002285/**
2286 * xmlNewDocRawNode:
2287 * @doc: the document
2288 * @ns: namespace if any
2289 * @name: the node name
2290 * @content: the text content if any
2291 *
2292 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002293 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002294 *
2295 * Returns a pointer to the new node object.
2296 */
2297xmlNodePtr
2298xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2299 const xmlChar *name, const xmlChar *content) {
2300 xmlNodePtr cur;
2301
2302 cur = xmlNewNode(ns, name);
2303 if (cur != NULL) {
2304 cur->doc = doc;
2305 if (content != NULL) {
2306 cur->children = xmlNewDocText(doc, content);
2307 UPDATE_LAST_CHILD_AND_PARENT(cur)
2308 }
2309 }
2310 return(cur);
2311}
2312
2313/**
2314 * xmlNewDocFragment:
2315 * @doc: the document owning the fragment
2316 *
2317 * Creation of a new Fragment node.
2318 * Returns a pointer to the new node object.
2319 */
2320xmlNodePtr
2321xmlNewDocFragment(xmlDocPtr doc) {
2322 xmlNodePtr cur;
2323
2324 /*
2325 * Allocate a new DocumentFragment node and fill the fields.
2326 */
2327 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2328 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002329 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002330 return(NULL);
2331 }
2332 memset(cur, 0, sizeof(xmlNode));
2333 cur->type = XML_DOCUMENT_FRAG_NODE;
2334
2335 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002336
Daniel Veillarda880b122003-04-21 21:36:41 +00002337 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002338 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002339 return(cur);
2340}
Daniel Veillard652327a2003-09-29 18:02:38 +00002341#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002342
2343/**
2344 * xmlNewText:
2345 * @content: the text content
2346 *
2347 * Creation of a new text node.
2348 * Returns a pointer to the new node object.
2349 */
2350xmlNodePtr
2351xmlNewText(const xmlChar *content) {
2352 xmlNodePtr cur;
2353
2354 /*
2355 * Allocate a new node and fill the fields.
2356 */
2357 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2358 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002359 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002360 return(NULL);
2361 }
2362 memset(cur, 0, sizeof(xmlNode));
2363 cur->type = XML_TEXT_NODE;
2364
2365 cur->name = xmlStringText;
2366 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002367 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002368 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002369
Daniel Veillarda880b122003-04-21 21:36:41 +00002370 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002371 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002372 return(cur);
2373}
2374
Daniel Veillard652327a2003-09-29 18:02:38 +00002375#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002376/**
2377 * xmlNewTextChild:
2378 * @parent: the parent node
2379 * @ns: a namespace if any
2380 * @name: the name of the child
2381 * @content: the text content of the child if any.
2382 *
2383 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002384 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2385 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002386 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002387 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2388 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2389 * reserved XML chars that might appear in @content, such as the ampersand,
2390 * greater-than or less-than signs, are automatically replaced by their XML
2391 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002392 *
2393 * Returns a pointer to the new node object.
2394 */
2395xmlNodePtr
2396xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2397 const xmlChar *name, const xmlChar *content) {
2398 xmlNodePtr cur, prev;
2399
2400 if (parent == NULL) {
2401#ifdef DEBUG_TREE
2402 xmlGenericError(xmlGenericErrorContext,
2403 "xmlNewTextChild : parent == NULL\n");
2404#endif
2405 return(NULL);
2406 }
2407
2408 if (name == NULL) {
2409#ifdef DEBUG_TREE
2410 xmlGenericError(xmlGenericErrorContext,
2411 "xmlNewTextChild : name == NULL\n");
2412#endif
2413 return(NULL);
2414 }
2415
2416 /*
2417 * Allocate a new node
2418 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002419 if (parent->type == XML_ELEMENT_NODE) {
2420 if (ns == NULL)
2421 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2422 else
2423 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2424 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2425 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2426 if (ns == NULL)
2427 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2428 else
2429 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2430 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2431 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2432 } else {
2433 return(NULL);
2434 }
Owen Taylor3473f882001-02-23 17:55:21 +00002435 if (cur == NULL) return(NULL);
2436
2437 /*
2438 * add the new element at the end of the children list.
2439 */
2440 cur->type = XML_ELEMENT_NODE;
2441 cur->parent = parent;
2442 cur->doc = parent->doc;
2443 if (parent->children == NULL) {
2444 parent->children = cur;
2445 parent->last = cur;
2446 } else {
2447 prev = parent->last;
2448 prev->next = cur;
2449 cur->prev = prev;
2450 parent->last = cur;
2451 }
2452
2453 return(cur);
2454}
Daniel Veillard652327a2003-09-29 18:02:38 +00002455#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002456
2457/**
2458 * xmlNewCharRef:
2459 * @doc: the document
2460 * @name: the char ref string, starting with # or "&# ... ;"
2461 *
2462 * Creation of a new character reference node.
2463 * Returns a pointer to the new node object.
2464 */
2465xmlNodePtr
2466xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2467 xmlNodePtr cur;
2468
2469 /*
2470 * Allocate a new node and fill the fields.
2471 */
2472 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2473 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002474 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002475 return(NULL);
2476 }
2477 memset(cur, 0, sizeof(xmlNode));
2478 cur->type = XML_ENTITY_REF_NODE;
2479
2480 cur->doc = doc;
2481 if (name[0] == '&') {
2482 int len;
2483 name++;
2484 len = xmlStrlen(name);
2485 if (name[len - 1] == ';')
2486 cur->name = xmlStrndup(name, len - 1);
2487 else
2488 cur->name = xmlStrndup(name, len);
2489 } else
2490 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002491
Daniel Veillarda880b122003-04-21 21:36:41 +00002492 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002493 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002494 return(cur);
2495}
2496
2497/**
2498 * xmlNewReference:
2499 * @doc: the document
2500 * @name: the reference name, or the reference string with & and ;
2501 *
2502 * Creation of a new reference node.
2503 * Returns a pointer to the new node object.
2504 */
2505xmlNodePtr
2506xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2507 xmlNodePtr cur;
2508 xmlEntityPtr ent;
2509
2510 /*
2511 * Allocate a new node and fill the fields.
2512 */
2513 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2514 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002515 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002516 return(NULL);
2517 }
2518 memset(cur, 0, sizeof(xmlNode));
2519 cur->type = XML_ENTITY_REF_NODE;
2520
2521 cur->doc = doc;
2522 if (name[0] == '&') {
2523 int len;
2524 name++;
2525 len = xmlStrlen(name);
2526 if (name[len - 1] == ';')
2527 cur->name = xmlStrndup(name, len - 1);
2528 else
2529 cur->name = xmlStrndup(name, len);
2530 } else
2531 cur->name = xmlStrdup(name);
2532
2533 ent = xmlGetDocEntity(doc, cur->name);
2534 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002535 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002536 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002537 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002538 * updated. Not sure if this is 100% correct.
2539 * -George
2540 */
2541 cur->children = (xmlNodePtr) ent;
2542 cur->last = (xmlNodePtr) ent;
2543 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002544
Daniel Veillarda880b122003-04-21 21:36:41 +00002545 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002546 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002547 return(cur);
2548}
2549
2550/**
2551 * xmlNewDocText:
2552 * @doc: the document
2553 * @content: the text content
2554 *
2555 * Creation of a new text node within a document.
2556 * Returns a pointer to the new node object.
2557 */
2558xmlNodePtr
2559xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2560 xmlNodePtr cur;
2561
2562 cur = xmlNewText(content);
2563 if (cur != NULL) cur->doc = doc;
2564 return(cur);
2565}
2566
2567/**
2568 * xmlNewTextLen:
2569 * @content: the text content
2570 * @len: the text len.
2571 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002572 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002573 * Returns a pointer to the new node object.
2574 */
2575xmlNodePtr
2576xmlNewTextLen(const xmlChar *content, int len) {
2577 xmlNodePtr cur;
2578
2579 /*
2580 * Allocate a new node and fill the fields.
2581 */
2582 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2583 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002584 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002585 return(NULL);
2586 }
2587 memset(cur, 0, sizeof(xmlNode));
2588 cur->type = XML_TEXT_NODE;
2589
2590 cur->name = xmlStringText;
2591 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002592 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002593 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002594
Daniel Veillarda880b122003-04-21 21:36:41 +00002595 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002596 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002597 return(cur);
2598}
2599
2600/**
2601 * xmlNewDocTextLen:
2602 * @doc: the document
2603 * @content: the text content
2604 * @len: the text len.
2605 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002606 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002607 * text node pertain to a given document.
2608 * Returns a pointer to the new node object.
2609 */
2610xmlNodePtr
2611xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2612 xmlNodePtr cur;
2613
2614 cur = xmlNewTextLen(content, len);
2615 if (cur != NULL) cur->doc = doc;
2616 return(cur);
2617}
2618
2619/**
2620 * xmlNewComment:
2621 * @content: the comment content
2622 *
2623 * Creation of a new node containing a comment.
2624 * Returns a pointer to the new node object.
2625 */
2626xmlNodePtr
2627xmlNewComment(const xmlChar *content) {
2628 xmlNodePtr cur;
2629
2630 /*
2631 * Allocate a new node and fill the fields.
2632 */
2633 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2634 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002635 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002636 return(NULL);
2637 }
2638 memset(cur, 0, sizeof(xmlNode));
2639 cur->type = XML_COMMENT_NODE;
2640
2641 cur->name = xmlStringComment;
2642 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002643 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002644 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002645
Daniel Veillarda880b122003-04-21 21:36:41 +00002646 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002647 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002648 return(cur);
2649}
2650
2651/**
2652 * xmlNewCDataBlock:
2653 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002654 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002655 * @len: the length of the block
2656 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002657 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002658 * Returns a pointer to the new node object.
2659 */
2660xmlNodePtr
2661xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2662 xmlNodePtr cur;
2663
2664 /*
2665 * Allocate a new node and fill the fields.
2666 */
2667 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2668 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002669 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002670 return(NULL);
2671 }
2672 memset(cur, 0, sizeof(xmlNode));
2673 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002674 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002675
2676 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002677 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002678 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002679
Daniel Veillarda880b122003-04-21 21:36:41 +00002680 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002681 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002682 return(cur);
2683}
2684
2685/**
2686 * xmlNewDocComment:
2687 * @doc: the document
2688 * @content: the comment content
2689 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002690 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002691 * Returns a pointer to the new node object.
2692 */
2693xmlNodePtr
2694xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2695 xmlNodePtr cur;
2696
2697 cur = xmlNewComment(content);
2698 if (cur != NULL) cur->doc = doc;
2699 return(cur);
2700}
2701
2702/**
2703 * xmlSetTreeDoc:
2704 * @tree: the top element
2705 * @doc: the document
2706 *
2707 * update all nodes under the tree to point to the right document
2708 */
2709void
2710xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002711 xmlAttrPtr prop;
2712
Owen Taylor3473f882001-02-23 17:55:21 +00002713 if (tree == NULL)
2714 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002715 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002716 if(tree->type == XML_ELEMENT_NODE) {
2717 prop = tree->properties;
2718 while (prop != NULL) {
2719 prop->doc = doc;
2720 xmlSetListDoc(prop->children, doc);
2721 prop = prop->next;
2722 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002723 }
Owen Taylor3473f882001-02-23 17:55:21 +00002724 if (tree->children != NULL)
2725 xmlSetListDoc(tree->children, doc);
2726 tree->doc = doc;
2727 }
2728}
2729
2730/**
2731 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002732 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002733 * @doc: the document
2734 *
2735 * update all nodes in the list to point to the right document
2736 */
2737void
2738xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2739 xmlNodePtr cur;
2740
2741 if (list == NULL)
2742 return;
2743 cur = list;
2744 while (cur != NULL) {
2745 if (cur->doc != doc)
2746 xmlSetTreeDoc(cur, doc);
2747 cur = cur->next;
2748 }
2749}
2750
Daniel Veillard2156d432004-03-04 15:59:36 +00002751#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002752/**
2753 * xmlNewChild:
2754 * @parent: the parent node
2755 * @ns: a namespace if any
2756 * @name: the name of the child
2757 * @content: the XML content of the child if any.
2758 *
2759 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002760 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2761 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002762 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002763 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2764 * references. XML special chars must be escaped first by using
2765 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002766 *
2767 * Returns a pointer to the new node object.
2768 */
2769xmlNodePtr
2770xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2771 const xmlChar *name, const xmlChar *content) {
2772 xmlNodePtr cur, prev;
2773
2774 if (parent == NULL) {
2775#ifdef DEBUG_TREE
2776 xmlGenericError(xmlGenericErrorContext,
2777 "xmlNewChild : parent == NULL\n");
2778#endif
2779 return(NULL);
2780 }
2781
2782 if (name == NULL) {
2783#ifdef DEBUG_TREE
2784 xmlGenericError(xmlGenericErrorContext,
2785 "xmlNewChild : name == NULL\n");
2786#endif
2787 return(NULL);
2788 }
2789
2790 /*
2791 * Allocate a new node
2792 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002793 if (parent->type == XML_ELEMENT_NODE) {
2794 if (ns == NULL)
2795 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2796 else
2797 cur = xmlNewDocNode(parent->doc, ns, name, content);
2798 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2799 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2800 if (ns == NULL)
2801 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2802 else
2803 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002804 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2805 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002806 } else {
2807 return(NULL);
2808 }
Owen Taylor3473f882001-02-23 17:55:21 +00002809 if (cur == NULL) return(NULL);
2810
2811 /*
2812 * add the new element at the end of the children list.
2813 */
2814 cur->type = XML_ELEMENT_NODE;
2815 cur->parent = parent;
2816 cur->doc = parent->doc;
2817 if (parent->children == NULL) {
2818 parent->children = cur;
2819 parent->last = cur;
2820 } else {
2821 prev = parent->last;
2822 prev->next = cur;
2823 cur->prev = prev;
2824 parent->last = cur;
2825 }
2826
2827 return(cur);
2828}
Daniel Veillard652327a2003-09-29 18:02:38 +00002829#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002830
2831/**
2832 * xmlAddNextSibling:
2833 * @cur: the child node
2834 * @elem: the new node
2835 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002836 * Add a new node @elem as the next sibling of @cur
2837 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002838 * first unlinked from its existing context.
2839 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002840 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2841 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002842 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002843 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002844 */
2845xmlNodePtr
2846xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2847 if (cur == NULL) {
2848#ifdef DEBUG_TREE
2849 xmlGenericError(xmlGenericErrorContext,
2850 "xmlAddNextSibling : cur == NULL\n");
2851#endif
2852 return(NULL);
2853 }
2854 if (elem == NULL) {
2855#ifdef DEBUG_TREE
2856 xmlGenericError(xmlGenericErrorContext,
2857 "xmlAddNextSibling : elem == NULL\n");
2858#endif
2859 return(NULL);
2860 }
2861
2862 xmlUnlinkNode(elem);
2863
2864 if (elem->type == XML_TEXT_NODE) {
2865 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002866 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002867 xmlFreeNode(elem);
2868 return(cur);
2869 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002870 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2871 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002872 xmlChar *tmp;
2873
2874 tmp = xmlStrdup(elem->content);
2875 tmp = xmlStrcat(tmp, cur->next->content);
2876 xmlNodeSetContent(cur->next, tmp);
2877 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002878 xmlFreeNode(elem);
2879 return(cur->next);
2880 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002881 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2882 /* check if an attribute with the same name exists */
2883 xmlAttrPtr attr;
2884
2885 if (elem->ns == NULL)
2886 attr = xmlHasProp(cur->parent, elem->name);
2887 else
2888 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2889 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2890 /* different instance, destroy it (attributes must be unique) */
2891 xmlFreeProp(attr);
2892 }
Owen Taylor3473f882001-02-23 17:55:21 +00002893 }
2894
2895 if (elem->doc != cur->doc) {
2896 xmlSetTreeDoc(elem, cur->doc);
2897 }
2898 elem->parent = cur->parent;
2899 elem->prev = cur;
2900 elem->next = cur->next;
2901 cur->next = elem;
2902 if (elem->next != NULL)
2903 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002904 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002905 elem->parent->last = elem;
2906 return(elem);
2907}
2908
Daniel Veillard2156d432004-03-04 15:59:36 +00002909#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002910/**
2911 * xmlAddPrevSibling:
2912 * @cur: the child node
2913 * @elem: the new node
2914 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002915 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002916 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002917 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002918 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002919 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2920 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002921 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002922 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002923 */
2924xmlNodePtr
2925xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2926 if (cur == NULL) {
2927#ifdef DEBUG_TREE
2928 xmlGenericError(xmlGenericErrorContext,
2929 "xmlAddPrevSibling : cur == NULL\n");
2930#endif
2931 return(NULL);
2932 }
2933 if (elem == NULL) {
2934#ifdef DEBUG_TREE
2935 xmlGenericError(xmlGenericErrorContext,
2936 "xmlAddPrevSibling : elem == NULL\n");
2937#endif
2938 return(NULL);
2939 }
2940
2941 xmlUnlinkNode(elem);
2942
2943 if (elem->type == XML_TEXT_NODE) {
2944 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002945 xmlChar *tmp;
2946
2947 tmp = xmlStrdup(elem->content);
2948 tmp = xmlStrcat(tmp, cur->content);
2949 xmlNodeSetContent(cur, tmp);
2950 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002951 xmlFreeNode(elem);
2952 return(cur);
2953 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002954 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2955 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002956 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002957 xmlFreeNode(elem);
2958 return(cur->prev);
2959 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002960 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2961 /* check if an attribute with the same name exists */
2962 xmlAttrPtr attr;
2963
2964 if (elem->ns == NULL)
2965 attr = xmlHasProp(cur->parent, elem->name);
2966 else
2967 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2968 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2969 /* different instance, destroy it (attributes must be unique) */
2970 xmlFreeProp(attr);
2971 }
Owen Taylor3473f882001-02-23 17:55:21 +00002972 }
2973
2974 if (elem->doc != cur->doc) {
2975 xmlSetTreeDoc(elem, cur->doc);
2976 }
2977 elem->parent = cur->parent;
2978 elem->next = cur;
2979 elem->prev = cur->prev;
2980 cur->prev = elem;
2981 if (elem->prev != NULL)
2982 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002983 if (elem->parent != NULL) {
2984 if (elem->type == XML_ATTRIBUTE_NODE) {
2985 if (elem->parent->properties == (xmlAttrPtr) cur) {
2986 elem->parent->properties = (xmlAttrPtr) elem;
2987 }
2988 } else {
2989 if (elem->parent->children == cur) {
2990 elem->parent->children = elem;
2991 }
2992 }
2993 }
Owen Taylor3473f882001-02-23 17:55:21 +00002994 return(elem);
2995}
Daniel Veillard652327a2003-09-29 18:02:38 +00002996#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002997
2998/**
2999 * xmlAddSibling:
3000 * @cur: the child node
3001 * @elem: the new node
3002 *
3003 * Add a new element @elem to the list of siblings of @cur
3004 * merging adjacent TEXT nodes (@elem may be freed)
3005 * If the new element was already inserted in a document it is
3006 * first unlinked from its existing context.
3007 *
3008 * Returns the new element or NULL in case of error.
3009 */
3010xmlNodePtr
3011xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
3012 xmlNodePtr parent;
3013
3014 if (cur == NULL) {
3015#ifdef DEBUG_TREE
3016 xmlGenericError(xmlGenericErrorContext,
3017 "xmlAddSibling : cur == NULL\n");
3018#endif
3019 return(NULL);
3020 }
3021
3022 if (elem == NULL) {
3023#ifdef DEBUG_TREE
3024 xmlGenericError(xmlGenericErrorContext,
3025 "xmlAddSibling : elem == NULL\n");
3026#endif
3027 return(NULL);
3028 }
3029
3030 /*
3031 * Constant time is we can rely on the ->parent->last to find
3032 * the last sibling.
3033 */
3034 if ((cur->parent != NULL) &&
3035 (cur->parent->children != NULL) &&
3036 (cur->parent->last != NULL) &&
3037 (cur->parent->last->next == NULL)) {
3038 cur = cur->parent->last;
3039 } else {
3040 while (cur->next != NULL) cur = cur->next;
3041 }
3042
3043 xmlUnlinkNode(elem);
3044
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003045 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3046 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003047 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003048 xmlFreeNode(elem);
3049 return(cur);
3050 }
3051
3052 if (elem->doc != cur->doc) {
3053 xmlSetTreeDoc(elem, cur->doc);
3054 }
3055 parent = cur->parent;
3056 elem->prev = cur;
3057 elem->next = NULL;
3058 elem->parent = parent;
3059 cur->next = elem;
3060 if (parent != NULL)
3061 parent->last = elem;
3062
3063 return(elem);
3064}
3065
3066/**
3067 * xmlAddChildList:
3068 * @parent: the parent node
3069 * @cur: the first node in the list
3070 *
3071 * Add a list of node at the end of the child list of the parent
3072 * merging adjacent TEXT nodes (@cur may be freed)
3073 *
3074 * Returns the last child or NULL in case of error.
3075 */
3076xmlNodePtr
3077xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3078 xmlNodePtr prev;
3079
3080 if (parent == NULL) {
3081#ifdef DEBUG_TREE
3082 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003083 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003084#endif
3085 return(NULL);
3086 }
3087
3088 if (cur == NULL) {
3089#ifdef DEBUG_TREE
3090 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003091 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003092#endif
3093 return(NULL);
3094 }
3095
3096 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3097 (cur->doc != parent->doc)) {
3098#ifdef DEBUG_TREE
3099 xmlGenericError(xmlGenericErrorContext,
3100 "Elements moved to a different document\n");
3101#endif
3102 }
3103
3104 /*
3105 * add the first element at the end of the children list.
3106 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003107
Owen Taylor3473f882001-02-23 17:55:21 +00003108 if (parent->children == NULL) {
3109 parent->children = cur;
3110 } else {
3111 /*
3112 * If cur and parent->last both are TEXT nodes, then merge them.
3113 */
3114 if ((cur->type == XML_TEXT_NODE) &&
3115 (parent->last->type == XML_TEXT_NODE) &&
3116 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003117 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003118 /*
3119 * if it's the only child, nothing more to be done.
3120 */
3121 if (cur->next == NULL) {
3122 xmlFreeNode(cur);
3123 return(parent->last);
3124 }
3125 prev = cur;
3126 cur = cur->next;
3127 xmlFreeNode(prev);
3128 }
3129 prev = parent->last;
3130 prev->next = cur;
3131 cur->prev = prev;
3132 }
3133 while (cur->next != NULL) {
3134 cur->parent = parent;
3135 if (cur->doc != parent->doc) {
3136 xmlSetTreeDoc(cur, parent->doc);
3137 }
3138 cur = cur->next;
3139 }
3140 cur->parent = parent;
3141 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3142 parent->last = cur;
3143
3144 return(cur);
3145}
3146
3147/**
3148 * xmlAddChild:
3149 * @parent: the parent node
3150 * @cur: the child node
3151 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003152 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003153 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003154 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3155 * If there is an attribute with equal name, it is first destroyed.
3156 *
Owen Taylor3473f882001-02-23 17:55:21 +00003157 * Returns the child or NULL in case of error.
3158 */
3159xmlNodePtr
3160xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3161 xmlNodePtr prev;
3162
3163 if (parent == NULL) {
3164#ifdef DEBUG_TREE
3165 xmlGenericError(xmlGenericErrorContext,
3166 "xmlAddChild : parent == NULL\n");
3167#endif
3168 return(NULL);
3169 }
3170
3171 if (cur == NULL) {
3172#ifdef DEBUG_TREE
3173 xmlGenericError(xmlGenericErrorContext,
3174 "xmlAddChild : child == NULL\n");
3175#endif
3176 return(NULL);
3177 }
3178
Owen Taylor3473f882001-02-23 17:55:21 +00003179 /*
3180 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003181 * cur is then freed.
3182 */
3183 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003184 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003185 (parent->content != NULL) &&
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003186 (parent->name == cur->name) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003187 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003188 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003189 xmlFreeNode(cur);
3190 return(parent);
3191 }
3192 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003193 (parent->last->name == cur->name) &&
3194 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003195 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003196 xmlFreeNode(cur);
3197 return(parent->last);
3198 }
3199 }
3200
3201 /*
3202 * add the new element at the end of the children list.
3203 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003204 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003205 cur->parent = parent;
3206 if (cur->doc != parent->doc) {
3207 xmlSetTreeDoc(cur, parent->doc);
3208 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003209 /* this check prevents a loop on tree-traversions if a developer
3210 * tries to add a node to its parent multiple times
3211 */
3212 if (prev == parent)
3213 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003214
3215 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003216 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003217 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003218 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003219 (parent->content != NULL) &&
3220 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003221 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003222 xmlFreeNode(cur);
3223 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003224 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003225 if (cur->type == XML_ATTRIBUTE_NODE) {
3226 if (parent->properties == NULL) {
3227 parent->properties = (xmlAttrPtr) cur;
3228 } else {
3229 /* check if an attribute with the same name exists */
3230 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003231
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003232 if (cur->ns == NULL)
3233 lastattr = xmlHasProp(parent, cur->name);
3234 else
3235 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3236 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3237 /* different instance, destroy it (attributes must be unique) */
3238 xmlFreeProp(lastattr);
3239 }
3240 /* find the end */
3241 lastattr = parent->properties;
3242 while (lastattr->next != NULL) {
3243 lastattr = lastattr->next;
3244 }
3245 lastattr->next = (xmlAttrPtr) cur;
3246 ((xmlAttrPtr) cur)->prev = lastattr;
3247 }
3248 } else {
3249 if (parent->children == NULL) {
3250 parent->children = cur;
3251 parent->last = cur;
3252 } else {
3253 prev = parent->last;
3254 prev->next = cur;
3255 cur->prev = prev;
3256 parent->last = cur;
3257 }
3258 }
Owen Taylor3473f882001-02-23 17:55:21 +00003259 return(cur);
3260}
3261
3262/**
3263 * xmlGetLastChild:
3264 * @parent: the parent node
3265 *
3266 * Search the last child of a node.
3267 * Returns the last child or NULL if none.
3268 */
3269xmlNodePtr
3270xmlGetLastChild(xmlNodePtr parent) {
3271 if (parent == NULL) {
3272#ifdef DEBUG_TREE
3273 xmlGenericError(xmlGenericErrorContext,
3274 "xmlGetLastChild : parent == NULL\n");
3275#endif
3276 return(NULL);
3277 }
3278 return(parent->last);
3279}
3280
3281/**
3282 * xmlFreeNodeList:
3283 * @cur: the first node in the list
3284 *
3285 * Free a node and all its siblings, this is a recursive behaviour, all
3286 * the children are freed too.
3287 */
3288void
3289xmlFreeNodeList(xmlNodePtr cur) {
3290 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003291 xmlDictPtr dict = NULL;
3292
3293 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003294 if (cur->type == XML_NAMESPACE_DECL) {
3295 xmlFreeNsList((xmlNsPtr) cur);
3296 return;
3297 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003298 if ((cur->type == XML_DOCUMENT_NODE) ||
3299#ifdef LIBXML_DOCB_ENABLED
3300 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003301#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003302 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003303 xmlFreeDoc((xmlDocPtr) cur);
3304 return;
3305 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003306 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003307 while (cur != NULL) {
3308 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003309 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003310
Daniel Veillarda880b122003-04-21 21:36:41 +00003311 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003312 xmlDeregisterNodeDefaultValue(cur);
3313
Daniel Veillard02141ea2001-04-30 11:46:40 +00003314 if ((cur->children != NULL) &&
3315 (cur->type != XML_ENTITY_REF_NODE))
3316 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003317 if (((cur->type == XML_ELEMENT_NODE) ||
3318 (cur->type == XML_XINCLUDE_START) ||
3319 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003320 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003321 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003322 if ((cur->type != XML_ELEMENT_NODE) &&
3323 (cur->type != XML_XINCLUDE_START) &&
3324 (cur->type != XML_XINCLUDE_END) &&
3325 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003326 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003327 }
3328 if (((cur->type == XML_ELEMENT_NODE) ||
3329 (cur->type == XML_XINCLUDE_START) ||
3330 (cur->type == XML_XINCLUDE_END)) &&
3331 (cur->nsDef != NULL))
3332 xmlFreeNsList(cur->nsDef);
3333
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003334 /*
3335 * When a node is a text node or a comment, it uses a global static
3336 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003337 * Otherwise the node name might come from the document's
3338 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003339 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003340 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003341 (cur->type != XML_TEXT_NODE) &&
3342 (cur->type != XML_COMMENT_NODE))
3343 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003344 xmlFree(cur);
3345 }
Owen Taylor3473f882001-02-23 17:55:21 +00003346 cur = next;
3347 }
3348}
3349
3350/**
3351 * xmlFreeNode:
3352 * @cur: the node
3353 *
3354 * Free a node, this is a recursive behaviour, all the children are freed too.
3355 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3356 */
3357void
3358xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003359 xmlDictPtr dict = NULL;
3360
3361 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003362
Daniel Veillard02141ea2001-04-30 11:46:40 +00003363 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003364 if (cur->type == XML_DTD_NODE) {
3365 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003366 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003367 }
3368 if (cur->type == XML_NAMESPACE_DECL) {
3369 xmlFreeNs((xmlNsPtr) cur);
3370 return;
3371 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003372 if (cur->type == XML_ATTRIBUTE_NODE) {
3373 xmlFreeProp((xmlAttrPtr) cur);
3374 return;
3375 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003376
Daniel Veillarda880b122003-04-21 21:36:41 +00003377 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003378 xmlDeregisterNodeDefaultValue(cur);
3379
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003380 if (cur->doc != NULL) dict = cur->doc->dict;
3381
Owen Taylor3473f882001-02-23 17:55:21 +00003382 if ((cur->children != NULL) &&
3383 (cur->type != XML_ENTITY_REF_NODE))
3384 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003385 if (((cur->type == XML_ELEMENT_NODE) ||
3386 (cur->type == XML_XINCLUDE_START) ||
3387 (cur->type == XML_XINCLUDE_END)) &&
3388 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003389 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003390 if ((cur->type != XML_ELEMENT_NODE) &&
3391 (cur->content != NULL) &&
3392 (cur->type != XML_ENTITY_REF_NODE) &&
3393 (cur->type != XML_XINCLUDE_END) &&
3394 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003395 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003396 }
3397
Daniel Veillardacd370f2001-06-09 17:17:51 +00003398 /*
3399 * When a node is a text node or a comment, it uses a global static
3400 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003401 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003402 */
Owen Taylor3473f882001-02-23 17:55:21 +00003403 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003404 (cur->type != XML_TEXT_NODE) &&
3405 (cur->type != XML_COMMENT_NODE))
3406 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003407
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003408 if (((cur->type == XML_ELEMENT_NODE) ||
3409 (cur->type == XML_XINCLUDE_START) ||
3410 (cur->type == XML_XINCLUDE_END)) &&
3411 (cur->nsDef != NULL))
3412 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003413 xmlFree(cur);
3414}
3415
3416/**
3417 * xmlUnlinkNode:
3418 * @cur: the node
3419 *
3420 * Unlink a node from it's current context, the node is not freed
3421 */
3422void
3423xmlUnlinkNode(xmlNodePtr cur) {
3424 if (cur == NULL) {
3425#ifdef DEBUG_TREE
3426 xmlGenericError(xmlGenericErrorContext,
3427 "xmlUnlinkNode : node == NULL\n");
3428#endif
3429 return;
3430 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003431 if (cur->type == XML_DTD_NODE) {
3432 xmlDocPtr doc;
3433 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003434 if (doc != NULL) {
3435 if (doc->intSubset == (xmlDtdPtr) cur)
3436 doc->intSubset = NULL;
3437 if (doc->extSubset == (xmlDtdPtr) cur)
3438 doc->extSubset = NULL;
3439 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003440 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003441 if (cur->parent != NULL) {
3442 xmlNodePtr parent;
3443 parent = cur->parent;
3444 if (cur->type == XML_ATTRIBUTE_NODE) {
3445 if (parent->properties == (xmlAttrPtr) cur)
3446 parent->properties = ((xmlAttrPtr) cur)->next;
3447 } else {
3448 if (parent->children == cur)
3449 parent->children = cur->next;
3450 if (parent->last == cur)
3451 parent->last = cur->prev;
3452 }
3453 cur->parent = NULL;
3454 }
Owen Taylor3473f882001-02-23 17:55:21 +00003455 if (cur->next != NULL)
3456 cur->next->prev = cur->prev;
3457 if (cur->prev != NULL)
3458 cur->prev->next = cur->next;
3459 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003460}
3461
Daniel Veillard2156d432004-03-04 15:59:36 +00003462#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003463/**
3464 * xmlReplaceNode:
3465 * @old: the old node
3466 * @cur: the node
3467 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003468 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003469 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003470 * first unlinked from its existing context.
3471 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003472 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003473 */
3474xmlNodePtr
3475xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3476 if (old == NULL) {
3477#ifdef DEBUG_TREE
3478 xmlGenericError(xmlGenericErrorContext,
3479 "xmlReplaceNode : old == NULL\n");
3480#endif
3481 return(NULL);
3482 }
3483 if (cur == NULL) {
3484 xmlUnlinkNode(old);
3485 return(old);
3486 }
3487 if (cur == old) {
3488 return(old);
3489 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003490 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3491#ifdef DEBUG_TREE
3492 xmlGenericError(xmlGenericErrorContext,
3493 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3494#endif
3495 return(old);
3496 }
3497 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3498#ifdef DEBUG_TREE
3499 xmlGenericError(xmlGenericErrorContext,
3500 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3501#endif
3502 return(old);
3503 }
Owen Taylor3473f882001-02-23 17:55:21 +00003504 xmlUnlinkNode(cur);
3505 cur->doc = old->doc;
3506 cur->parent = old->parent;
3507 cur->next = old->next;
3508 if (cur->next != NULL)
3509 cur->next->prev = cur;
3510 cur->prev = old->prev;
3511 if (cur->prev != NULL)
3512 cur->prev->next = cur;
3513 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003514 if (cur->type == XML_ATTRIBUTE_NODE) {
3515 if (cur->parent->properties == (xmlAttrPtr)old)
3516 cur->parent->properties = ((xmlAttrPtr) cur);
3517 } else {
3518 if (cur->parent->children == old)
3519 cur->parent->children = cur;
3520 if (cur->parent->last == old)
3521 cur->parent->last = cur;
3522 }
Owen Taylor3473f882001-02-23 17:55:21 +00003523 }
3524 old->next = old->prev = NULL;
3525 old->parent = NULL;
3526 return(old);
3527}
Daniel Veillard652327a2003-09-29 18:02:38 +00003528#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003529
3530/************************************************************************
3531 * *
3532 * Copy operations *
3533 * *
3534 ************************************************************************/
3535
3536/**
3537 * xmlCopyNamespace:
3538 * @cur: the namespace
3539 *
3540 * Do a copy of the namespace.
3541 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003542 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003543 */
3544xmlNsPtr
3545xmlCopyNamespace(xmlNsPtr cur) {
3546 xmlNsPtr ret;
3547
3548 if (cur == NULL) return(NULL);
3549 switch (cur->type) {
3550 case XML_LOCAL_NAMESPACE:
3551 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3552 break;
3553 default:
3554#ifdef DEBUG_TREE
3555 xmlGenericError(xmlGenericErrorContext,
3556 "xmlCopyNamespace: invalid type %d\n", cur->type);
3557#endif
3558 return(NULL);
3559 }
3560 return(ret);
3561}
3562
3563/**
3564 * xmlCopyNamespaceList:
3565 * @cur: the first namespace
3566 *
3567 * Do a copy of an namespace list.
3568 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003569 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003570 */
3571xmlNsPtr
3572xmlCopyNamespaceList(xmlNsPtr cur) {
3573 xmlNsPtr ret = NULL;
3574 xmlNsPtr p = NULL,q;
3575
3576 while (cur != NULL) {
3577 q = xmlCopyNamespace(cur);
3578 if (p == NULL) {
3579 ret = p = q;
3580 } else {
3581 p->next = q;
3582 p = q;
3583 }
3584 cur = cur->next;
3585 }
3586 return(ret);
3587}
3588
3589static xmlNodePtr
3590xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3591/**
3592 * xmlCopyProp:
3593 * @target: the element where the attribute will be grafted
3594 * @cur: the attribute
3595 *
3596 * Do a copy of the attribute.
3597 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003598 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003599 */
3600xmlAttrPtr
3601xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3602 xmlAttrPtr ret;
3603
3604 if (cur == NULL) return(NULL);
3605 if (target != NULL)
3606 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3607 else if (cur->parent != NULL)
3608 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3609 else if (cur->children != NULL)
3610 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3611 else
3612 ret = xmlNewDocProp(NULL, cur->name, NULL);
3613 if (ret == NULL) return(NULL);
3614 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003615
Owen Taylor3473f882001-02-23 17:55:21 +00003616 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003617 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003618
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003619 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3620 if (ns == NULL) {
3621 /*
3622 * Humm, we are copying an element whose namespace is defined
3623 * out of the new tree scope. Search it in the original tree
3624 * and add it at the top of the new tree
3625 */
3626 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3627 if (ns != NULL) {
3628 xmlNodePtr root = target;
3629 xmlNodePtr pred = NULL;
3630
3631 while (root->parent != NULL) {
3632 pred = root;
3633 root = root->parent;
3634 }
3635 if (root == (xmlNodePtr) target->doc) {
3636 /* correct possibly cycling above the document elt */
3637 root = pred;
3638 }
3639 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3640 }
3641 } else {
3642 /*
3643 * we have to find something appropriate here since
3644 * we cant be sure, that the namespce we found is identified
3645 * by the prefix
3646 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003647 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003648 /* this is the nice case */
3649 ret->ns = ns;
3650 } else {
3651 /*
3652 * we are in trouble: we need a new reconcilied namespace.
3653 * This is expensive
3654 */
3655 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3656 }
3657 }
3658
Owen Taylor3473f882001-02-23 17:55:21 +00003659 } else
3660 ret->ns = NULL;
3661
3662 if (cur->children != NULL) {
3663 xmlNodePtr tmp;
3664
3665 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3666 ret->last = NULL;
3667 tmp = ret->children;
3668 while (tmp != NULL) {
3669 /* tmp->parent = (xmlNodePtr)ret; */
3670 if (tmp->next == NULL)
3671 ret->last = tmp;
3672 tmp = tmp->next;
3673 }
3674 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003675 /*
3676 * Try to handle IDs
3677 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003678 if ((target!= NULL) && (cur!= NULL) &&
3679 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003680 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3681 if (xmlIsID(cur->doc, cur->parent, cur)) {
3682 xmlChar *id;
3683
3684 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3685 if (id != NULL) {
3686 xmlAddID(NULL, target->doc, id, ret);
3687 xmlFree(id);
3688 }
3689 }
3690 }
Owen Taylor3473f882001-02-23 17:55:21 +00003691 return(ret);
3692}
3693
3694/**
3695 * xmlCopyPropList:
3696 * @target: the element where the attributes will be grafted
3697 * @cur: the first attribute
3698 *
3699 * Do a copy of an attribute list.
3700 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003701 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003702 */
3703xmlAttrPtr
3704xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3705 xmlAttrPtr ret = NULL;
3706 xmlAttrPtr p = NULL,q;
3707
3708 while (cur != NULL) {
3709 q = xmlCopyProp(target, cur);
3710 if (p == NULL) {
3711 ret = p = q;
3712 } else {
3713 p->next = q;
3714 q->prev = p;
3715 p = q;
3716 }
3717 cur = cur->next;
3718 }
3719 return(ret);
3720}
3721
3722/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003723 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003724 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003725 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003726 * tricky reason: namespaces. Doing a direct copy of a node
3727 * say RPM:Copyright without changing the namespace pointer to
3728 * something else can produce stale links. One way to do it is
3729 * to keep a reference counter but this doesn't work as soon
3730 * as one move the element or the subtree out of the scope of
3731 * the existing namespace. The actual solution seems to add
3732 * a copy of the namespace at the top of the copied tree if
3733 * not available in the subtree.
3734 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00003735 * The argument "recursive" normally indicates a recursive copy
3736 * of the node with values 0 (no) and 1 (yes). For XInclude,
3737 * however, we allow a value of 2 to indicate copy properties and
3738 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00003739 */
3740
3741static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003742xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00003743 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003744 xmlNodePtr ret;
3745
3746 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003747 switch (node->type) {
3748 case XML_TEXT_NODE:
3749 case XML_CDATA_SECTION_NODE:
3750 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003751 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003752 case XML_ENTITY_REF_NODE:
3753 case XML_ENTITY_NODE:
3754 case XML_PI_NODE:
3755 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003756 case XML_XINCLUDE_START:
3757 case XML_XINCLUDE_END:
3758 break;
3759 case XML_ATTRIBUTE_NODE:
3760 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3761 case XML_NAMESPACE_DECL:
3762 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3763
Daniel Veillard39196eb2001-06-19 18:09:42 +00003764 case XML_DOCUMENT_NODE:
3765 case XML_HTML_DOCUMENT_NODE:
3766#ifdef LIBXML_DOCB_ENABLED
3767 case XML_DOCB_DOCUMENT_NODE:
3768#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003769#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00003770 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00003771#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003772 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003773 case XML_NOTATION_NODE:
3774 case XML_DTD_NODE:
3775 case XML_ELEMENT_DECL:
3776 case XML_ATTRIBUTE_DECL:
3777 case XML_ENTITY_DECL:
3778 return(NULL);
3779 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003780
Owen Taylor3473f882001-02-23 17:55:21 +00003781 /*
3782 * Allocate a new node and fill the fields.
3783 */
3784 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3785 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003786 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003787 return(NULL);
3788 }
3789 memset(ret, 0, sizeof(xmlNode));
3790 ret->type = node->type;
3791
3792 ret->doc = doc;
3793 ret->parent = parent;
3794 if (node->name == xmlStringText)
3795 ret->name = xmlStringText;
3796 else if (node->name == xmlStringTextNoenc)
3797 ret->name = xmlStringTextNoenc;
3798 else if (node->name == xmlStringComment)
3799 ret->name = xmlStringComment;
3800 else if (node->name != NULL)
3801 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003802 if ((node->type != XML_ELEMENT_NODE) &&
3803 (node->content != NULL) &&
3804 (node->type != XML_ENTITY_REF_NODE) &&
3805 (node->type != XML_XINCLUDE_END) &&
3806 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003807 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003808 }else{
3809 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003810 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003811 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003812 if (parent != NULL) {
3813 xmlNodePtr tmp;
3814
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003815 /*
3816 * this is a tricky part for the node register thing:
3817 * in case ret does get coalesced in xmlAddChild
3818 * the deregister-node callback is called; so we register ret now already
3819 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003820 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003821 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3822
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003823 tmp = xmlAddChild(parent, ret);
3824 /* node could have coalesced */
3825 if (tmp != ret)
3826 return(tmp);
3827 }
Owen Taylor3473f882001-02-23 17:55:21 +00003828
William M. Brack57e9e912004-03-09 16:19:02 +00003829 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003830 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003831 if (node->nsDef != NULL)
3832 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3833
3834 if (node->ns != NULL) {
3835 xmlNsPtr ns;
3836
3837 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3838 if (ns == NULL) {
3839 /*
3840 * Humm, we are copying an element whose namespace is defined
3841 * out of the new tree scope. Search it in the original tree
3842 * and add it at the top of the new tree
3843 */
3844 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3845 if (ns != NULL) {
3846 xmlNodePtr root = ret;
3847
3848 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003849 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003850 }
3851 } else {
3852 /*
3853 * reference the existing namespace definition in our own tree.
3854 */
3855 ret->ns = ns;
3856 }
3857 }
3858 if (node->properties != NULL)
3859 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003860 if (node->type == XML_ENTITY_REF_NODE) {
3861 if ((doc == NULL) || (node->doc != doc)) {
3862 /*
3863 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003864 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003865 * we cannot keep the reference. Try to find it in the
3866 * target document.
3867 */
3868 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3869 } else {
3870 ret->children = node->children;
3871 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003872 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00003873 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003874 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003875 UPDATE_LAST_CHILD_AND_PARENT(ret)
3876 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003877
3878out:
3879 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00003880 if ((parent == NULL) &&
3881 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003882 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003883 return(ret);
3884}
3885
3886static xmlNodePtr
3887xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3888 xmlNodePtr ret = NULL;
3889 xmlNodePtr p = NULL,q;
3890
3891 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003892#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003893 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003894 if (doc == NULL) {
3895 node = node->next;
3896 continue;
3897 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003898 if (doc->intSubset == NULL) {
3899 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3900 q->doc = doc;
3901 q->parent = parent;
3902 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003903 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003904 } else {
3905 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003906 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003907 }
3908 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003909#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003910 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003911 if (ret == NULL) {
3912 q->prev = NULL;
3913 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003914 } else if (p != q) {
3915 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003916 p->next = q;
3917 q->prev = p;
3918 p = q;
3919 }
3920 node = node->next;
3921 }
3922 return(ret);
3923}
3924
3925/**
3926 * xmlCopyNode:
3927 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00003928 * @extended: if 1 do a recursive copy (properties, namespaces and children
3929 * when applicable)
3930 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00003931 *
3932 * Do a copy of the node.
3933 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003934 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003935 */
3936xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003937xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003938 xmlNodePtr ret;
3939
William M. Brack57e9e912004-03-09 16:19:02 +00003940 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00003941 return(ret);
3942}
3943
3944/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003945 * xmlDocCopyNode:
3946 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003947 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00003948 * @extended: if 1 do a recursive copy (properties, namespaces and children
3949 * when applicable)
3950 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00003951 *
3952 * Do a copy of the node to a given document.
3953 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003954 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003955 */
3956xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003957xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003958 xmlNodePtr ret;
3959
William M. Brack57e9e912004-03-09 16:19:02 +00003960 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00003961 return(ret);
3962}
3963
3964/**
Owen Taylor3473f882001-02-23 17:55:21 +00003965 * xmlCopyNodeList:
3966 * @node: the first node in the list.
3967 *
3968 * Do a recursive copy of the node list.
3969 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003970 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003971 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003972xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003973 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3974 return(ret);
3975}
3976
Daniel Veillard2156d432004-03-04 15:59:36 +00003977#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003978/**
Owen Taylor3473f882001-02-23 17:55:21 +00003979 * xmlCopyDtd:
3980 * @dtd: the dtd
3981 *
3982 * Do a copy of the dtd.
3983 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003984 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003985 */
3986xmlDtdPtr
3987xmlCopyDtd(xmlDtdPtr dtd) {
3988 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003989 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003990
3991 if (dtd == NULL) return(NULL);
3992 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3993 if (ret == NULL) return(NULL);
3994 if (dtd->entities != NULL)
3995 ret->entities = (void *) xmlCopyEntitiesTable(
3996 (xmlEntitiesTablePtr) dtd->entities);
3997 if (dtd->notations != NULL)
3998 ret->notations = (void *) xmlCopyNotationTable(
3999 (xmlNotationTablePtr) dtd->notations);
4000 if (dtd->elements != NULL)
4001 ret->elements = (void *) xmlCopyElementTable(
4002 (xmlElementTablePtr) dtd->elements);
4003 if (dtd->attributes != NULL)
4004 ret->attributes = (void *) xmlCopyAttributeTable(
4005 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004006 if (dtd->pentities != NULL)
4007 ret->pentities = (void *) xmlCopyEntitiesTable(
4008 (xmlEntitiesTablePtr) dtd->pentities);
4009
4010 cur = dtd->children;
4011 while (cur != NULL) {
4012 q = NULL;
4013
4014 if (cur->type == XML_ENTITY_DECL) {
4015 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4016 switch (tmp->etype) {
4017 case XML_INTERNAL_GENERAL_ENTITY:
4018 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4019 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4020 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4021 break;
4022 case XML_INTERNAL_PARAMETER_ENTITY:
4023 case XML_EXTERNAL_PARAMETER_ENTITY:
4024 q = (xmlNodePtr)
4025 xmlGetParameterEntityFromDtd(ret, tmp->name);
4026 break;
4027 case XML_INTERNAL_PREDEFINED_ENTITY:
4028 break;
4029 }
4030 } else if (cur->type == XML_ELEMENT_DECL) {
4031 xmlElementPtr tmp = (xmlElementPtr) cur;
4032 q = (xmlNodePtr)
4033 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4034 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4035 xmlAttributePtr tmp = (xmlAttributePtr) cur;
4036 q = (xmlNodePtr)
4037 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4038 } else if (cur->type == XML_COMMENT_NODE) {
4039 q = xmlCopyNode(cur, 0);
4040 }
4041
4042 if (q == NULL) {
4043 cur = cur->next;
4044 continue;
4045 }
4046
4047 if (p == NULL)
4048 ret->children = q;
4049 else
4050 p->next = q;
4051
4052 q->prev = p;
4053 q->parent = (xmlNodePtr) ret;
4054 q->next = NULL;
4055 ret->last = q;
4056 p = q;
4057 cur = cur->next;
4058 }
4059
Owen Taylor3473f882001-02-23 17:55:21 +00004060 return(ret);
4061}
Daniel Veillard2156d432004-03-04 15:59:36 +00004062#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004063
Daniel Veillard2156d432004-03-04 15:59:36 +00004064#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004065/**
4066 * xmlCopyDoc:
4067 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004068 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004069 *
4070 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004071 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004072 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004073 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004074 */
4075xmlDocPtr
4076xmlCopyDoc(xmlDocPtr doc, int recursive) {
4077 xmlDocPtr ret;
4078
4079 if (doc == NULL) return(NULL);
4080 ret = xmlNewDoc(doc->version);
4081 if (ret == NULL) return(NULL);
4082 if (doc->name != NULL)
4083 ret->name = xmlMemStrdup(doc->name);
4084 if (doc->encoding != NULL)
4085 ret->encoding = xmlStrdup(doc->encoding);
4086 ret->charset = doc->charset;
4087 ret->compression = doc->compression;
4088 ret->standalone = doc->standalone;
4089 if (!recursive) return(ret);
4090
Daniel Veillardb33c2012001-04-25 12:59:04 +00004091 ret->last = NULL;
4092 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004093#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004094 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004095 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004096 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004097 ret->intSubset->parent = ret;
4098 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004099#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004100 if (doc->oldNs != NULL)
4101 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4102 if (doc->children != NULL) {
4103 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004104
4105 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4106 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004107 ret->last = NULL;
4108 tmp = ret->children;
4109 while (tmp != NULL) {
4110 if (tmp->next == NULL)
4111 ret->last = tmp;
4112 tmp = tmp->next;
4113 }
4114 }
4115 return(ret);
4116}
Daniel Veillard652327a2003-09-29 18:02:38 +00004117#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004118
4119/************************************************************************
4120 * *
4121 * Content access functions *
4122 * *
4123 ************************************************************************/
4124
4125/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004126 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004127 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004128 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004129 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004130 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004131 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004132 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004133 */
4134long
4135xmlGetLineNo(xmlNodePtr node)
4136{
4137 long result = -1;
4138
4139 if (!node)
4140 return result;
4141 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004142 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004143 else if ((node->prev != NULL) &&
4144 ((node->prev->type == XML_ELEMENT_NODE) ||
4145 (node->prev->type == XML_TEXT_NODE)))
4146 result = xmlGetLineNo(node->prev);
4147 else if ((node->parent != NULL) &&
4148 ((node->parent->type == XML_ELEMENT_NODE) ||
4149 (node->parent->type == XML_TEXT_NODE)))
4150 result = xmlGetLineNo(node->parent);
4151
4152 return result;
4153}
4154
Daniel Veillard2156d432004-03-04 15:59:36 +00004155#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004156/**
4157 * xmlGetNodePath:
4158 * @node: a node
4159 *
4160 * Build a structure based Path for the given node
4161 *
4162 * Returns the new path or NULL in case of error. The caller must free
4163 * the returned string
4164 */
4165xmlChar *
4166xmlGetNodePath(xmlNodePtr node)
4167{
4168 xmlNodePtr cur, tmp, next;
4169 xmlChar *buffer = NULL, *temp;
4170 size_t buf_len;
4171 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004172 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004173 const char *name;
4174 char nametemp[100];
4175 int occur = 0;
4176
4177 if (node == NULL)
4178 return (NULL);
4179
4180 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004181 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004182 if (buffer == NULL) {
4183 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004184 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004185 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004186 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004187 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004188 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004189 xmlFree(buffer);
4190 return (NULL);
4191 }
4192
4193 buffer[0] = 0;
4194 cur = node;
4195 do {
4196 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004197 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004198 occur = 0;
4199 if ((cur->type == XML_DOCUMENT_NODE) ||
4200 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4201 if (buffer[0] == '/')
4202 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004203 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004204 next = NULL;
4205 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004206 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004207 name = (const char *) cur->name;
4208 if (cur->ns) {
William M. Brack84d83e32003-12-23 03:45:17 +00004209 if (cur->ns->prefix != NULL)
4210 snprintf(nametemp, sizeof(nametemp) - 1,
Daniel Veillard8faa7832001-11-26 15:58:08 +00004211 "%s:%s", cur->ns->prefix, cur->name);
William M. Brack84d83e32003-12-23 03:45:17 +00004212 else
4213 snprintf(nametemp, sizeof(nametemp) - 1,
4214 "%s", cur->name);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004215 nametemp[sizeof(nametemp) - 1] = 0;
4216 name = nametemp;
4217 }
4218 next = cur->parent;
4219
4220 /*
4221 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004222 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004223 */
4224 tmp = cur->prev;
4225 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004226 if ((tmp->type == XML_ELEMENT_NODE) &&
4227 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004228 occur++;
4229 tmp = tmp->prev;
4230 }
4231 if (occur == 0) {
4232 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004233 while (tmp != NULL && occur == 0) {
4234 if ((tmp->type == XML_ELEMENT_NODE) &&
4235 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004236 occur++;
4237 tmp = tmp->next;
4238 }
4239 if (occur != 0)
4240 occur = 1;
4241 } else
4242 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004243 } else if (cur->type == XML_COMMENT_NODE) {
4244 sep = "/";
4245 name = "comment()";
4246 next = cur->parent;
4247
4248 /*
4249 * Thumbler index computation
4250 */
4251 tmp = cur->prev;
4252 while (tmp != NULL) {
4253 if (tmp->type == XML_COMMENT_NODE)
4254 occur++;
4255 tmp = tmp->prev;
4256 }
4257 if (occur == 0) {
4258 tmp = cur->next;
4259 while (tmp != NULL && occur == 0) {
4260 if (tmp->type == XML_COMMENT_NODE)
4261 occur++;
4262 tmp = tmp->next;
4263 }
4264 if (occur != 0)
4265 occur = 1;
4266 } else
4267 occur++;
4268 } else if ((cur->type == XML_TEXT_NODE) ||
4269 (cur->type == XML_CDATA_SECTION_NODE)) {
4270 sep = "/";
4271 name = "text()";
4272 next = cur->parent;
4273
4274 /*
4275 * Thumbler index computation
4276 */
4277 tmp = cur->prev;
4278 while (tmp != NULL) {
4279 if ((cur->type == XML_TEXT_NODE) ||
4280 (cur->type == XML_CDATA_SECTION_NODE))
4281 occur++;
4282 tmp = tmp->prev;
4283 }
4284 if (occur == 0) {
4285 tmp = cur->next;
4286 while (tmp != NULL && occur == 0) {
4287 if ((cur->type == XML_TEXT_NODE) ||
4288 (cur->type == XML_CDATA_SECTION_NODE))
4289 occur++;
4290 tmp = tmp->next;
4291 }
4292 if (occur != 0)
4293 occur = 1;
4294 } else
4295 occur++;
4296 } else if (cur->type == XML_PI_NODE) {
4297 sep = "/";
4298 snprintf(nametemp, sizeof(nametemp) - 1,
4299 "processing-instruction('%s')", cur->name);
4300 nametemp[sizeof(nametemp) - 1] = 0;
4301 name = nametemp;
4302
4303 next = cur->parent;
4304
4305 /*
4306 * Thumbler index computation
4307 */
4308 tmp = cur->prev;
4309 while (tmp != NULL) {
4310 if ((tmp->type == XML_PI_NODE) &&
4311 (xmlStrEqual(cur->name, tmp->name)))
4312 occur++;
4313 tmp = tmp->prev;
4314 }
4315 if (occur == 0) {
4316 tmp = cur->next;
4317 while (tmp != NULL && occur == 0) {
4318 if ((tmp->type == XML_PI_NODE) &&
4319 (xmlStrEqual(cur->name, tmp->name)))
4320 occur++;
4321 tmp = tmp->next;
4322 }
4323 if (occur != 0)
4324 occur = 1;
4325 } else
4326 occur++;
4327
Daniel Veillard8faa7832001-11-26 15:58:08 +00004328 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004329 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004330 name = (const char *) (((xmlAttrPtr) cur)->name);
4331 next = ((xmlAttrPtr) cur)->parent;
4332 } else {
4333 next = cur->parent;
4334 }
4335
4336 /*
4337 * Make sure there is enough room
4338 */
4339 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4340 buf_len =
4341 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4342 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4343 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004344 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004345 xmlFree(buf);
4346 xmlFree(buffer);
4347 return (NULL);
4348 }
4349 buffer = temp;
4350 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4351 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004352 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004353 xmlFree(buf);
4354 xmlFree(buffer);
4355 return (NULL);
4356 }
4357 buf = temp;
4358 }
4359 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004360 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004361 sep, name, (char *) buffer);
4362 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004363 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004364 sep, name, occur, (char *) buffer);
4365 snprintf((char *) buffer, buf_len, "%s", buf);
4366 cur = next;
4367 } while (cur != NULL);
4368 xmlFree(buf);
4369 return (buffer);
4370}
Daniel Veillard652327a2003-09-29 18:02:38 +00004371#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004372
4373/**
Owen Taylor3473f882001-02-23 17:55:21 +00004374 * xmlDocGetRootElement:
4375 * @doc: the document
4376 *
4377 * Get the root element of the document (doc->children is a list
4378 * containing possibly comments, PIs, etc ...).
4379 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004380 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004381 */
4382xmlNodePtr
4383xmlDocGetRootElement(xmlDocPtr doc) {
4384 xmlNodePtr ret;
4385
4386 if (doc == NULL) return(NULL);
4387 ret = doc->children;
4388 while (ret != NULL) {
4389 if (ret->type == XML_ELEMENT_NODE)
4390 return(ret);
4391 ret = ret->next;
4392 }
4393 return(ret);
4394}
4395
Daniel Veillard2156d432004-03-04 15:59:36 +00004396#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004397/**
4398 * xmlDocSetRootElement:
4399 * @doc: the document
4400 * @root: the new document root element
4401 *
4402 * Set the root element of the document (doc->children is a list
4403 * containing possibly comments, PIs, etc ...).
4404 *
4405 * Returns the old root element if any was found
4406 */
4407xmlNodePtr
4408xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4409 xmlNodePtr old = NULL;
4410
4411 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004412 if (root == NULL)
4413 return(NULL);
4414 xmlUnlinkNode(root);
4415 root->doc = doc;
4416 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004417 old = doc->children;
4418 while (old != NULL) {
4419 if (old->type == XML_ELEMENT_NODE)
4420 break;
4421 old = old->next;
4422 }
4423 if (old == NULL) {
4424 if (doc->children == NULL) {
4425 doc->children = root;
4426 doc->last = root;
4427 } else {
4428 xmlAddSibling(doc->children, root);
4429 }
4430 } else {
4431 xmlReplaceNode(old, root);
4432 }
4433 return(old);
4434}
Daniel Veillard2156d432004-03-04 15:59:36 +00004435#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004436
Daniel Veillard2156d432004-03-04 15:59:36 +00004437#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004438/**
4439 * xmlNodeSetLang:
4440 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004441 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004442 *
4443 * Set the language of a node, i.e. the values of the xml:lang
4444 * attribute.
4445 */
4446void
4447xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004448 xmlNsPtr ns;
4449
Owen Taylor3473f882001-02-23 17:55:21 +00004450 if (cur == NULL) return;
4451 switch(cur->type) {
4452 case XML_TEXT_NODE:
4453 case XML_CDATA_SECTION_NODE:
4454 case XML_COMMENT_NODE:
4455 case XML_DOCUMENT_NODE:
4456 case XML_DOCUMENT_TYPE_NODE:
4457 case XML_DOCUMENT_FRAG_NODE:
4458 case XML_NOTATION_NODE:
4459 case XML_HTML_DOCUMENT_NODE:
4460 case XML_DTD_NODE:
4461 case XML_ELEMENT_DECL:
4462 case XML_ATTRIBUTE_DECL:
4463 case XML_ENTITY_DECL:
4464 case XML_PI_NODE:
4465 case XML_ENTITY_REF_NODE:
4466 case XML_ENTITY_NODE:
4467 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004468#ifdef LIBXML_DOCB_ENABLED
4469 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004470#endif
4471 case XML_XINCLUDE_START:
4472 case XML_XINCLUDE_END:
4473 return;
4474 case XML_ELEMENT_NODE:
4475 case XML_ATTRIBUTE_NODE:
4476 break;
4477 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004478 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4479 if (ns == NULL)
4480 return;
4481 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004482}
Daniel Veillard652327a2003-09-29 18:02:38 +00004483#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004484
4485/**
4486 * xmlNodeGetLang:
4487 * @cur: the node being checked
4488 *
4489 * Searches the language of a node, i.e. the values of the xml:lang
4490 * attribute or the one carried by the nearest ancestor.
4491 *
4492 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004493 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004494 */
4495xmlChar *
4496xmlNodeGetLang(xmlNodePtr cur) {
4497 xmlChar *lang;
4498
4499 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004500 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004501 if (lang != NULL)
4502 return(lang);
4503 cur = cur->parent;
4504 }
4505 return(NULL);
4506}
4507
4508
Daniel Veillard652327a2003-09-29 18:02:38 +00004509#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004510/**
4511 * xmlNodeSetSpacePreserve:
4512 * @cur: the node being changed
4513 * @val: the xml:space value ("0": default, 1: "preserve")
4514 *
4515 * Set (or reset) the space preserving behaviour of a node, i.e. the
4516 * value of the xml:space attribute.
4517 */
4518void
4519xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004520 xmlNsPtr ns;
4521
Owen Taylor3473f882001-02-23 17:55:21 +00004522 if (cur == NULL) return;
4523 switch(cur->type) {
4524 case XML_TEXT_NODE:
4525 case XML_CDATA_SECTION_NODE:
4526 case XML_COMMENT_NODE:
4527 case XML_DOCUMENT_NODE:
4528 case XML_DOCUMENT_TYPE_NODE:
4529 case XML_DOCUMENT_FRAG_NODE:
4530 case XML_NOTATION_NODE:
4531 case XML_HTML_DOCUMENT_NODE:
4532 case XML_DTD_NODE:
4533 case XML_ELEMENT_DECL:
4534 case XML_ATTRIBUTE_DECL:
4535 case XML_ENTITY_DECL:
4536 case XML_PI_NODE:
4537 case XML_ENTITY_REF_NODE:
4538 case XML_ENTITY_NODE:
4539 case XML_NAMESPACE_DECL:
4540 case XML_XINCLUDE_START:
4541 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004542#ifdef LIBXML_DOCB_ENABLED
4543 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004544#endif
4545 return;
4546 case XML_ELEMENT_NODE:
4547 case XML_ATTRIBUTE_NODE:
4548 break;
4549 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004550 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4551 if (ns == NULL)
4552 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004553 switch (val) {
4554 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004555 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004556 break;
4557 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004558 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004559 break;
4560 }
4561}
Daniel Veillard652327a2003-09-29 18:02:38 +00004562#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004563
4564/**
4565 * xmlNodeGetSpacePreserve:
4566 * @cur: the node being checked
4567 *
4568 * Searches the space preserving behaviour of a node, i.e. the values
4569 * of the xml:space attribute or the one carried by the nearest
4570 * ancestor.
4571 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004572 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004573 */
4574int
4575xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4576 xmlChar *space;
4577
4578 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004579 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004580 if (space != NULL) {
4581 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4582 xmlFree(space);
4583 return(1);
4584 }
4585 if (xmlStrEqual(space, BAD_CAST "default")) {
4586 xmlFree(space);
4587 return(0);
4588 }
4589 xmlFree(space);
4590 }
4591 cur = cur->parent;
4592 }
4593 return(-1);
4594}
4595
Daniel Veillard652327a2003-09-29 18:02:38 +00004596#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004597/**
4598 * xmlNodeSetName:
4599 * @cur: the node being changed
4600 * @name: the new tag name
4601 *
4602 * Set (or reset) the name of a node.
4603 */
4604void
4605xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4606 if (cur == NULL) return;
4607 if (name == NULL) return;
4608 switch(cur->type) {
4609 case XML_TEXT_NODE:
4610 case XML_CDATA_SECTION_NODE:
4611 case XML_COMMENT_NODE:
4612 case XML_DOCUMENT_TYPE_NODE:
4613 case XML_DOCUMENT_FRAG_NODE:
4614 case XML_NOTATION_NODE:
4615 case XML_HTML_DOCUMENT_NODE:
4616 case XML_NAMESPACE_DECL:
4617 case XML_XINCLUDE_START:
4618 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004619#ifdef LIBXML_DOCB_ENABLED
4620 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004621#endif
4622 return;
4623 case XML_ELEMENT_NODE:
4624 case XML_ATTRIBUTE_NODE:
4625 case XML_PI_NODE:
4626 case XML_ENTITY_REF_NODE:
4627 case XML_ENTITY_NODE:
4628 case XML_DTD_NODE:
4629 case XML_DOCUMENT_NODE:
4630 case XML_ELEMENT_DECL:
4631 case XML_ATTRIBUTE_DECL:
4632 case XML_ENTITY_DECL:
4633 break;
4634 }
4635 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4636 cur->name = xmlStrdup(name);
4637}
Daniel Veillard2156d432004-03-04 15:59:36 +00004638#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004639
Daniel Veillard2156d432004-03-04 15:59:36 +00004640#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004641/**
4642 * xmlNodeSetBase:
4643 * @cur: the node being changed
4644 * @uri: the new base URI
4645 *
4646 * Set (or reset) the base URI of a node, i.e. the value of the
4647 * xml:base attribute.
4648 */
4649void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004650xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004651 xmlNsPtr ns;
4652
Owen Taylor3473f882001-02-23 17:55:21 +00004653 if (cur == NULL) return;
4654 switch(cur->type) {
4655 case XML_TEXT_NODE:
4656 case XML_CDATA_SECTION_NODE:
4657 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004658 case XML_DOCUMENT_TYPE_NODE:
4659 case XML_DOCUMENT_FRAG_NODE:
4660 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004661 case XML_DTD_NODE:
4662 case XML_ELEMENT_DECL:
4663 case XML_ATTRIBUTE_DECL:
4664 case XML_ENTITY_DECL:
4665 case XML_PI_NODE:
4666 case XML_ENTITY_REF_NODE:
4667 case XML_ENTITY_NODE:
4668 case XML_NAMESPACE_DECL:
4669 case XML_XINCLUDE_START:
4670 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004671 return;
4672 case XML_ELEMENT_NODE:
4673 case XML_ATTRIBUTE_NODE:
4674 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004675 case XML_DOCUMENT_NODE:
4676#ifdef LIBXML_DOCB_ENABLED
4677 case XML_DOCB_DOCUMENT_NODE:
4678#endif
4679 case XML_HTML_DOCUMENT_NODE: {
4680 xmlDocPtr doc = (xmlDocPtr) cur;
4681
4682 if (doc->URL != NULL)
4683 xmlFree((xmlChar *) doc->URL);
4684 if (uri == NULL)
4685 doc->URL = NULL;
4686 else
4687 doc->URL = xmlStrdup(uri);
4688 return;
4689 }
Owen Taylor3473f882001-02-23 17:55:21 +00004690 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004691
4692 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4693 if (ns == NULL)
4694 return;
4695 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004696}
Daniel Veillard652327a2003-09-29 18:02:38 +00004697#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004698
4699/**
Owen Taylor3473f882001-02-23 17:55:21 +00004700 * xmlNodeGetBase:
4701 * @doc: the document the node pertains to
4702 * @cur: the node being checked
4703 *
4704 * Searches for the BASE URL. The code should work on both XML
4705 * and HTML document even if base mechanisms are completely different.
4706 * It returns the base as defined in RFC 2396 sections
4707 * 5.1.1. Base URI within Document Content
4708 * and
4709 * 5.1.2. Base URI from the Encapsulating Entity
4710 * However it does not return the document base (5.1.3), use
4711 * xmlDocumentGetBase() for this
4712 *
4713 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004714 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004715 */
4716xmlChar *
4717xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004718 xmlChar *oldbase = NULL;
4719 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004720
4721 if ((cur == NULL) && (doc == NULL))
4722 return(NULL);
4723 if (doc == NULL) doc = cur->doc;
4724 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4725 cur = doc->children;
4726 while ((cur != NULL) && (cur->name != NULL)) {
4727 if (cur->type != XML_ELEMENT_NODE) {
4728 cur = cur->next;
4729 continue;
4730 }
4731 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4732 cur = cur->children;
4733 continue;
4734 }
4735 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4736 cur = cur->children;
4737 continue;
4738 }
4739 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4740 return(xmlGetProp(cur, BAD_CAST "href"));
4741 }
4742 cur = cur->next;
4743 }
4744 return(NULL);
4745 }
4746 while (cur != NULL) {
4747 if (cur->type == XML_ENTITY_DECL) {
4748 xmlEntityPtr ent = (xmlEntityPtr) cur;
4749 return(xmlStrdup(ent->URI));
4750 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004751 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004752 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004753 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004754 if (oldbase != NULL) {
4755 newbase = xmlBuildURI(oldbase, base);
4756 if (newbase != NULL) {
4757 xmlFree(oldbase);
4758 xmlFree(base);
4759 oldbase = newbase;
4760 } else {
4761 xmlFree(oldbase);
4762 xmlFree(base);
4763 return(NULL);
4764 }
4765 } else {
4766 oldbase = base;
4767 }
4768 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4769 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4770 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4771 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004772 }
4773 }
Owen Taylor3473f882001-02-23 17:55:21 +00004774 cur = cur->parent;
4775 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004776 if ((doc != NULL) && (doc->URL != NULL)) {
4777 if (oldbase == NULL)
4778 return(xmlStrdup(doc->URL));
4779 newbase = xmlBuildURI(oldbase, doc->URL);
4780 xmlFree(oldbase);
4781 return(newbase);
4782 }
4783 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004784}
4785
4786/**
Daniel Veillard78697292003-10-19 20:44:43 +00004787 * xmlNodeBufGetContent:
4788 * @buffer: a buffer
4789 * @cur: the node being read
4790 *
4791 * Read the value of a node @cur, this can be either the text carried
4792 * directly by this node if it's a TEXT node or the aggregate string
4793 * of the values carried by this node child's (TEXT and ENTITY_REF).
4794 * Entity references are substituted.
4795 * Fills up the buffer @buffer with this value
4796 *
4797 * Returns 0 in case of success and -1 in case of error.
4798 */
4799int
4800xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4801{
4802 if ((cur == NULL) || (buffer == NULL)) return(-1);
4803 switch (cur->type) {
4804 case XML_CDATA_SECTION_NODE:
4805 case XML_TEXT_NODE:
4806 xmlBufferCat(buffer, cur->content);
4807 break;
4808 case XML_DOCUMENT_FRAG_NODE:
4809 case XML_ELEMENT_NODE:{
4810 xmlNodePtr tmp = cur;
4811
4812 while (tmp != NULL) {
4813 switch (tmp->type) {
4814 case XML_CDATA_SECTION_NODE:
4815 case XML_TEXT_NODE:
4816 if (tmp->content != NULL)
4817 xmlBufferCat(buffer, tmp->content);
4818 break;
4819 case XML_ENTITY_REF_NODE:
4820 xmlNodeBufGetContent(buffer, tmp->children);
4821 break;
4822 default:
4823 break;
4824 }
4825 /*
4826 * Skip to next node
4827 */
4828 if (tmp->children != NULL) {
4829 if (tmp->children->type != XML_ENTITY_DECL) {
4830 tmp = tmp->children;
4831 continue;
4832 }
4833 }
4834 if (tmp == cur)
4835 break;
4836
4837 if (tmp->next != NULL) {
4838 tmp = tmp->next;
4839 continue;
4840 }
4841
4842 do {
4843 tmp = tmp->parent;
4844 if (tmp == NULL)
4845 break;
4846 if (tmp == cur) {
4847 tmp = NULL;
4848 break;
4849 }
4850 if (tmp->next != NULL) {
4851 tmp = tmp->next;
4852 break;
4853 }
4854 } while (tmp != NULL);
4855 }
4856 break;
4857 }
4858 case XML_ATTRIBUTE_NODE:{
4859 xmlAttrPtr attr = (xmlAttrPtr) cur;
4860 xmlNodePtr tmp = attr->children;
4861
4862 while (tmp != NULL) {
4863 if (tmp->type == XML_TEXT_NODE)
4864 xmlBufferCat(buffer, tmp->content);
4865 else
4866 xmlNodeBufGetContent(buffer, tmp);
4867 tmp = tmp->next;
4868 }
4869 break;
4870 }
4871 case XML_COMMENT_NODE:
4872 case XML_PI_NODE:
4873 xmlBufferCat(buffer, cur->content);
4874 break;
4875 case XML_ENTITY_REF_NODE:{
4876 xmlEntityPtr ent;
4877 xmlNodePtr tmp;
4878
4879 /* lookup entity declaration */
4880 ent = xmlGetDocEntity(cur->doc, cur->name);
4881 if (ent == NULL)
4882 return(-1);
4883
4884 /* an entity content can be any "well balanced chunk",
4885 * i.e. the result of the content [43] production:
4886 * http://www.w3.org/TR/REC-xml#NT-content
4887 * -> we iterate through child nodes and recursive call
4888 * xmlNodeGetContent() which handles all possible node types */
4889 tmp = ent->children;
4890 while (tmp) {
4891 xmlNodeBufGetContent(buffer, tmp);
4892 tmp = tmp->next;
4893 }
4894 break;
4895 }
4896 case XML_ENTITY_NODE:
4897 case XML_DOCUMENT_TYPE_NODE:
4898 case XML_NOTATION_NODE:
4899 case XML_DTD_NODE:
4900 case XML_XINCLUDE_START:
4901 case XML_XINCLUDE_END:
4902 break;
4903 case XML_DOCUMENT_NODE:
4904#ifdef LIBXML_DOCB_ENABLED
4905 case XML_DOCB_DOCUMENT_NODE:
4906#endif
4907 case XML_HTML_DOCUMENT_NODE:
4908 cur = cur->children;
4909 while (cur!= NULL) {
4910 if ((cur->type == XML_ELEMENT_NODE) ||
4911 (cur->type == XML_TEXT_NODE) ||
4912 (cur->type == XML_CDATA_SECTION_NODE)) {
4913 xmlNodeBufGetContent(buffer, cur);
4914 }
4915 cur = cur->next;
4916 }
4917 break;
4918 case XML_NAMESPACE_DECL:
4919 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
4920 break;
4921 case XML_ELEMENT_DECL:
4922 case XML_ATTRIBUTE_DECL:
4923 case XML_ENTITY_DECL:
4924 break;
4925 }
4926 return(0);
4927}
4928/**
Owen Taylor3473f882001-02-23 17:55:21 +00004929 * xmlNodeGetContent:
4930 * @cur: the node being read
4931 *
4932 * Read the value of a node, this can be either the text carried
4933 * directly by this node if it's a TEXT node or the aggregate string
4934 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004935 * Entity references are substituted.
4936 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004937 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004938 */
4939xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004940xmlNodeGetContent(xmlNodePtr cur)
4941{
4942 if (cur == NULL)
4943 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004944 switch (cur->type) {
4945 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004946 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00004947 xmlBufferPtr buffer;
4948 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004949
Daniel Veillard814a76d2003-01-23 18:24:20 +00004950 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004951 if (buffer == NULL)
4952 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00004953 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004954 ret = buffer->content;
4955 buffer->content = NULL;
4956 xmlBufferFree(buffer);
4957 return (ret);
4958 }
4959 case XML_ATTRIBUTE_NODE:{
4960 xmlAttrPtr attr = (xmlAttrPtr) cur;
4961
4962 if (attr->parent != NULL)
4963 return (xmlNodeListGetString
4964 (attr->parent->doc, attr->children, 1));
4965 else
4966 return (xmlNodeListGetString(NULL, attr->children, 1));
4967 break;
4968 }
Owen Taylor3473f882001-02-23 17:55:21 +00004969 case XML_COMMENT_NODE:
4970 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004971 if (cur->content != NULL)
4972 return (xmlStrdup(cur->content));
4973 return (NULL);
4974 case XML_ENTITY_REF_NODE:{
4975 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00004976 xmlBufferPtr buffer;
4977 xmlChar *ret;
4978
4979 /* lookup entity declaration */
4980 ent = xmlGetDocEntity(cur->doc, cur->name);
4981 if (ent == NULL)
4982 return (NULL);
4983
4984 buffer = xmlBufferCreate();
4985 if (buffer == NULL)
4986 return (NULL);
4987
Daniel Veillardc4696922003-10-19 21:47:14 +00004988 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004989
4990 ret = buffer->content;
4991 buffer->content = NULL;
4992 xmlBufferFree(buffer);
4993 return (ret);
4994 }
Owen Taylor3473f882001-02-23 17:55:21 +00004995 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004996 case XML_DOCUMENT_TYPE_NODE:
4997 case XML_NOTATION_NODE:
4998 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004999 case XML_XINCLUDE_START:
5000 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00005001 return (NULL);
5002 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005003#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005004 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005005#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005006 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00005007 xmlBufferPtr buffer;
5008 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005009
Daniel Veillardc4696922003-10-19 21:47:14 +00005010 buffer = xmlBufferCreate();
5011 if (buffer == NULL)
5012 return (NULL);
5013
5014 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5015
5016 ret = buffer->content;
5017 buffer->content = NULL;
5018 xmlBufferFree(buffer);
5019 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005020 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005021 case XML_NAMESPACE_DECL: {
5022 xmlChar *tmp;
5023
5024 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5025 return (tmp);
5026 }
Owen Taylor3473f882001-02-23 17:55:21 +00005027 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005028 /* TODO !!! */
5029 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005030 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005031 /* TODO !!! */
5032 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005033 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005034 /* TODO !!! */
5035 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005036 case XML_CDATA_SECTION_NODE:
5037 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005038 if (cur->content != NULL)
5039 return (xmlStrdup(cur->content));
5040 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005041 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005042 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005043}
Daniel Veillard652327a2003-09-29 18:02:38 +00005044
Owen Taylor3473f882001-02-23 17:55:21 +00005045/**
5046 * xmlNodeSetContent:
5047 * @cur: the node being modified
5048 * @content: the new value of the content
5049 *
5050 * Replace the content of a node.
5051 */
5052void
5053xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5054 if (cur == NULL) {
5055#ifdef DEBUG_TREE
5056 xmlGenericError(xmlGenericErrorContext,
5057 "xmlNodeSetContent : node == NULL\n");
5058#endif
5059 return;
5060 }
5061 switch (cur->type) {
5062 case XML_DOCUMENT_FRAG_NODE:
5063 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005064 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005065 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5066 cur->children = xmlStringGetNodeList(cur->doc, content);
5067 UPDATE_LAST_CHILD_AND_PARENT(cur)
5068 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005069 case XML_TEXT_NODE:
5070 case XML_CDATA_SECTION_NODE:
5071 case XML_ENTITY_REF_NODE:
5072 case XML_ENTITY_NODE:
5073 case XML_PI_NODE:
5074 case XML_COMMENT_NODE:
5075 if (cur->content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005076 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5077 xmlDictOwns(cur->doc->dict, cur->content)))
5078 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005079 }
5080 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5081 cur->last = cur->children = NULL;
5082 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005083 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005084 } else
5085 cur->content = NULL;
5086 break;
5087 case XML_DOCUMENT_NODE:
5088 case XML_HTML_DOCUMENT_NODE:
5089 case XML_DOCUMENT_TYPE_NODE:
5090 case XML_XINCLUDE_START:
5091 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005092#ifdef LIBXML_DOCB_ENABLED
5093 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005094#endif
5095 break;
5096 case XML_NOTATION_NODE:
5097 break;
5098 case XML_DTD_NODE:
5099 break;
5100 case XML_NAMESPACE_DECL:
5101 break;
5102 case XML_ELEMENT_DECL:
5103 /* TODO !!! */
5104 break;
5105 case XML_ATTRIBUTE_DECL:
5106 /* TODO !!! */
5107 break;
5108 case XML_ENTITY_DECL:
5109 /* TODO !!! */
5110 break;
5111 }
5112}
5113
Daniel Veillard652327a2003-09-29 18:02:38 +00005114#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005115/**
5116 * xmlNodeSetContentLen:
5117 * @cur: the node being modified
5118 * @content: the new value of the content
5119 * @len: the size of @content
5120 *
5121 * Replace the content of a node.
5122 */
5123void
5124xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5125 if (cur == NULL) {
5126#ifdef DEBUG_TREE
5127 xmlGenericError(xmlGenericErrorContext,
5128 "xmlNodeSetContentLen : node == NULL\n");
5129#endif
5130 return;
5131 }
5132 switch (cur->type) {
5133 case XML_DOCUMENT_FRAG_NODE:
5134 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005135 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005136 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5137 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5138 UPDATE_LAST_CHILD_AND_PARENT(cur)
5139 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005140 case XML_TEXT_NODE:
5141 case XML_CDATA_SECTION_NODE:
5142 case XML_ENTITY_REF_NODE:
5143 case XML_ENTITY_NODE:
5144 case XML_PI_NODE:
5145 case XML_COMMENT_NODE:
5146 case XML_NOTATION_NODE:
5147 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005148 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005149 }
5150 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5151 cur->children = cur->last = NULL;
5152 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005153 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005154 } else
5155 cur->content = NULL;
5156 break;
5157 case XML_DOCUMENT_NODE:
5158 case XML_DTD_NODE:
5159 case XML_HTML_DOCUMENT_NODE:
5160 case XML_DOCUMENT_TYPE_NODE:
5161 case XML_NAMESPACE_DECL:
5162 case XML_XINCLUDE_START:
5163 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005164#ifdef LIBXML_DOCB_ENABLED
5165 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005166#endif
5167 break;
5168 case XML_ELEMENT_DECL:
5169 /* TODO !!! */
5170 break;
5171 case XML_ATTRIBUTE_DECL:
5172 /* TODO !!! */
5173 break;
5174 case XML_ENTITY_DECL:
5175 /* TODO !!! */
5176 break;
5177 }
5178}
Daniel Veillard652327a2003-09-29 18:02:38 +00005179#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005180
5181/**
5182 * xmlNodeAddContentLen:
5183 * @cur: the node being modified
5184 * @content: extra content
5185 * @len: the size of @content
5186 *
5187 * Append the extra substring to the node content.
5188 */
5189void
5190xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5191 if (cur == NULL) {
5192#ifdef DEBUG_TREE
5193 xmlGenericError(xmlGenericErrorContext,
5194 "xmlNodeAddContentLen : node == NULL\n");
5195#endif
5196 return;
5197 }
5198 if (len <= 0) return;
5199 switch (cur->type) {
5200 case XML_DOCUMENT_FRAG_NODE:
5201 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005202 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005203
Daniel Veillard7db37732001-07-12 01:20:08 +00005204 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005205 newNode = xmlNewTextLen(content, len);
5206 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005207 tmp = xmlAddChild(cur, newNode);
5208 if (tmp != newNode)
5209 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005210 if ((last != NULL) && (last->next == newNode)) {
5211 xmlTextMerge(last, newNode);
5212 }
5213 }
5214 break;
5215 }
5216 case XML_ATTRIBUTE_NODE:
5217 break;
5218 case XML_TEXT_NODE:
5219 case XML_CDATA_SECTION_NODE:
5220 case XML_ENTITY_REF_NODE:
5221 case XML_ENTITY_NODE:
5222 case XML_PI_NODE:
5223 case XML_COMMENT_NODE:
5224 case XML_NOTATION_NODE:
5225 if (content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005226 if ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5227 xmlDictOwns(cur->doc->dict, cur->content)) {
5228 cur->content =
5229 xmlStrncatNew(cur->content, content, len);
5230 break;
5231 }
Owen Taylor3473f882001-02-23 17:55:21 +00005232 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005233 }
5234 case XML_DOCUMENT_NODE:
5235 case XML_DTD_NODE:
5236 case XML_HTML_DOCUMENT_NODE:
5237 case XML_DOCUMENT_TYPE_NODE:
5238 case XML_NAMESPACE_DECL:
5239 case XML_XINCLUDE_START:
5240 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005241#ifdef LIBXML_DOCB_ENABLED
5242 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005243#endif
5244 break;
5245 case XML_ELEMENT_DECL:
5246 case XML_ATTRIBUTE_DECL:
5247 case XML_ENTITY_DECL:
5248 break;
5249 }
5250}
5251
5252/**
5253 * xmlNodeAddContent:
5254 * @cur: the node being modified
5255 * @content: extra content
5256 *
5257 * Append the extra substring to the node content.
5258 */
5259void
5260xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5261 int len;
5262
5263 if (cur == NULL) {
5264#ifdef DEBUG_TREE
5265 xmlGenericError(xmlGenericErrorContext,
5266 "xmlNodeAddContent : node == NULL\n");
5267#endif
5268 return;
5269 }
5270 if (content == NULL) return;
5271 len = xmlStrlen(content);
5272 xmlNodeAddContentLen(cur, content, len);
5273}
5274
5275/**
5276 * xmlTextMerge:
5277 * @first: the first text node
5278 * @second: the second text node being merged
5279 *
5280 * Merge two text nodes into one
5281 * Returns the first text node augmented
5282 */
5283xmlNodePtr
5284xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5285 if (first == NULL) return(second);
5286 if (second == NULL) return(first);
5287 if (first->type != XML_TEXT_NODE) return(first);
5288 if (second->type != XML_TEXT_NODE) return(first);
5289 if (second->name != first->name)
5290 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005291 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005292 xmlUnlinkNode(second);
5293 xmlFreeNode(second);
5294 return(first);
5295}
5296
Daniel Veillard2156d432004-03-04 15:59:36 +00005297#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005298/**
5299 * xmlGetNsList:
5300 * @doc: the document
5301 * @node: the current node
5302 *
5303 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005304 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005305 * that need to be freed by the caller or NULL if no
5306 * namespace if defined
5307 */
5308xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005309xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5310{
Owen Taylor3473f882001-02-23 17:55:21 +00005311 xmlNsPtr cur;
5312 xmlNsPtr *ret = NULL;
5313 int nbns = 0;
5314 int maxns = 10;
5315 int i;
5316
5317 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005318 if (node->type == XML_ELEMENT_NODE) {
5319 cur = node->nsDef;
5320 while (cur != NULL) {
5321 if (ret == NULL) {
5322 ret =
5323 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5324 sizeof(xmlNsPtr));
5325 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005326 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005327 return (NULL);
5328 }
5329 ret[nbns] = NULL;
5330 }
5331 for (i = 0; i < nbns; i++) {
5332 if ((cur->prefix == ret[i]->prefix) ||
5333 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5334 break;
5335 }
5336 if (i >= nbns) {
5337 if (nbns >= maxns) {
5338 maxns *= 2;
5339 ret = (xmlNsPtr *) xmlRealloc(ret,
5340 (maxns +
5341 1) *
5342 sizeof(xmlNsPtr));
5343 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005344 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005345 return (NULL);
5346 }
5347 }
5348 ret[nbns++] = cur;
5349 ret[nbns] = NULL;
5350 }
Owen Taylor3473f882001-02-23 17:55:21 +00005351
Daniel Veillard77044732001-06-29 21:31:07 +00005352 cur = cur->next;
5353 }
5354 }
5355 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005356 }
Daniel Veillard77044732001-06-29 21:31:07 +00005357 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005358}
Daniel Veillard652327a2003-09-29 18:02:38 +00005359#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005360
5361/**
5362 * xmlSearchNs:
5363 * @doc: the document
5364 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005365 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005366 *
5367 * Search a Ns registered under a given name space for a document.
5368 * recurse on the parents until it finds the defined namespace
5369 * or return NULL otherwise.
5370 * @nameSpace can be NULL, this is a search for the default namespace.
5371 * We don't allow to cross entities boundaries. If you don't declare
5372 * the namespace within those you will be in troubles !!! A warning
5373 * is generated to cover this case.
5374 *
5375 * Returns the namespace pointer or NULL.
5376 */
5377xmlNsPtr
5378xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005379
Owen Taylor3473f882001-02-23 17:55:21 +00005380 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005381 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005382
5383 if (node == NULL) return(NULL);
5384 if ((nameSpace != NULL) &&
5385 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005386 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5387 /*
5388 * The XML-1.0 namespace is normally held on the root
5389 * element. In this case exceptionally create it on the
5390 * node element.
5391 */
5392 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5393 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005394 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005395 return(NULL);
5396 }
5397 memset(cur, 0, sizeof(xmlNs));
5398 cur->type = XML_LOCAL_NAMESPACE;
5399 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5400 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5401 cur->next = node->nsDef;
5402 node->nsDef = cur;
5403 return(cur);
5404 }
Owen Taylor3473f882001-02-23 17:55:21 +00005405 if (doc->oldNs == NULL) {
5406 /*
5407 * Allocate a new Namespace and fill the fields.
5408 */
5409 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5410 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005411 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005412 return(NULL);
5413 }
5414 memset(doc->oldNs, 0, sizeof(xmlNs));
5415 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5416
5417 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5418 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5419 }
5420 return(doc->oldNs);
5421 }
5422 while (node != NULL) {
5423 if ((node->type == XML_ENTITY_REF_NODE) ||
5424 (node->type == XML_ENTITY_NODE) ||
5425 (node->type == XML_ENTITY_DECL))
5426 return(NULL);
5427 if (node->type == XML_ELEMENT_NODE) {
5428 cur = node->nsDef;
5429 while (cur != NULL) {
5430 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5431 (cur->href != NULL))
5432 return(cur);
5433 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5434 (cur->href != NULL) &&
5435 (xmlStrEqual(cur->prefix, nameSpace)))
5436 return(cur);
5437 cur = cur->next;
5438 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005439 if (orig != node) {
5440 cur = node->ns;
5441 if (cur != NULL) {
5442 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5443 (cur->href != NULL))
5444 return(cur);
5445 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5446 (cur->href != NULL) &&
5447 (xmlStrEqual(cur->prefix, nameSpace)))
5448 return(cur);
5449 }
5450 }
Owen Taylor3473f882001-02-23 17:55:21 +00005451 }
5452 node = node->parent;
5453 }
5454 return(NULL);
5455}
5456
5457/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005458 * xmlNsInScope:
5459 * @doc: the document
5460 * @node: the current node
5461 * @ancestor: the ancestor carrying the namespace
5462 * @prefix: the namespace prefix
5463 *
5464 * Verify that the given namespace held on @ancestor is still in scope
5465 * on node.
5466 *
5467 * Returns 1 if true, 0 if false and -1 in case of error.
5468 */
5469static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005470xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5471 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005472{
5473 xmlNsPtr tst;
5474
5475 while ((node != NULL) && (node != ancestor)) {
5476 if ((node->type == XML_ENTITY_REF_NODE) ||
5477 (node->type == XML_ENTITY_NODE) ||
5478 (node->type == XML_ENTITY_DECL))
5479 return (-1);
5480 if (node->type == XML_ELEMENT_NODE) {
5481 tst = node->nsDef;
5482 while (tst != NULL) {
5483 if ((tst->prefix == NULL)
5484 && (prefix == NULL))
5485 return (0);
5486 if ((tst->prefix != NULL)
5487 && (prefix != NULL)
5488 && (xmlStrEqual(tst->prefix, prefix)))
5489 return (0);
5490 tst = tst->next;
5491 }
5492 }
5493 node = node->parent;
5494 }
5495 if (node != ancestor)
5496 return (-1);
5497 return (1);
5498}
5499
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005500/**
Owen Taylor3473f882001-02-23 17:55:21 +00005501 * xmlSearchNsByHref:
5502 * @doc: the document
5503 * @node: the current node
5504 * @href: the namespace value
5505 *
5506 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5507 * the defined namespace or return NULL otherwise.
5508 * Returns the namespace pointer or NULL.
5509 */
5510xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005511xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5512{
Owen Taylor3473f882001-02-23 17:55:21 +00005513 xmlNsPtr cur;
5514 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005515 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005516
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005517 if ((node == NULL) || (href == NULL))
5518 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005519 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005520 /*
5521 * Only the document can hold the XML spec namespace.
5522 */
5523 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5524 /*
5525 * The XML-1.0 namespace is normally held on the root
5526 * element. In this case exceptionally create it on the
5527 * node element.
5528 */
5529 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5530 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005531 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005532 return (NULL);
5533 }
5534 memset(cur, 0, sizeof(xmlNs));
5535 cur->type = XML_LOCAL_NAMESPACE;
5536 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5537 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5538 cur->next = node->nsDef;
5539 node->nsDef = cur;
5540 return (cur);
5541 }
5542 if (doc->oldNs == NULL) {
5543 /*
5544 * Allocate a new Namespace and fill the fields.
5545 */
5546 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5547 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005548 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005549 return (NULL);
5550 }
5551 memset(doc->oldNs, 0, sizeof(xmlNs));
5552 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005553
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005554 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5555 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5556 }
5557 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005558 }
Daniel Veillard62040be2004-05-17 03:17:26 +00005559 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00005560 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005561 if ((node->type == XML_ENTITY_REF_NODE) ||
5562 (node->type == XML_ENTITY_NODE) ||
5563 (node->type == XML_ENTITY_DECL))
5564 return (NULL);
5565 if (node->type == XML_ELEMENT_NODE) {
5566 cur = node->nsDef;
5567 while (cur != NULL) {
5568 if ((cur->href != NULL) && (href != NULL) &&
5569 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005570 if (((!is_attr) || (cur->prefix != NULL)) &&
5571 (xmlNsInScope(doc, orig, node, cur->href) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005572 return (cur);
5573 }
5574 cur = cur->next;
5575 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005576 if (orig != node) {
5577 cur = node->ns;
5578 if (cur != NULL) {
5579 if ((cur->href != NULL) && (href != NULL) &&
5580 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005581 if (((!is_attr) || (cur->prefix != NULL)) &&
5582 (xmlNsInScope(doc, orig, node, cur->href) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00005583 return (cur);
5584 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005585 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005586 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005587 }
5588 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005589 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005590 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005591}
5592
5593/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005594 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005595 * @doc: the document
5596 * @tree: a node expected to hold the new namespace
5597 * @ns: the original namespace
5598 *
5599 * This function tries to locate a namespace definition in a tree
5600 * ancestors, or create a new namespace definition node similar to
5601 * @ns trying to reuse the same prefix. However if the given prefix is
5602 * null (default namespace) or reused within the subtree defined by
5603 * @tree or on one of its ancestors then a new prefix is generated.
5604 * Returns the (new) namespace definition or NULL in case of error
5605 */
5606xmlNsPtr
5607xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5608 xmlNsPtr def;
5609 xmlChar prefix[50];
5610 int counter = 1;
5611
5612 if (tree == NULL) {
5613#ifdef DEBUG_TREE
5614 xmlGenericError(xmlGenericErrorContext,
5615 "xmlNewReconciliedNs : tree == NULL\n");
5616#endif
5617 return(NULL);
5618 }
5619 if (ns == NULL) {
5620#ifdef DEBUG_TREE
5621 xmlGenericError(xmlGenericErrorContext,
5622 "xmlNewReconciliedNs : ns == NULL\n");
5623#endif
5624 return(NULL);
5625 }
5626 /*
5627 * Search an existing namespace definition inherited.
5628 */
5629 def = xmlSearchNsByHref(doc, tree, ns->href);
5630 if (def != NULL)
5631 return(def);
5632
5633 /*
5634 * Find a close prefix which is not already in use.
5635 * Let's strip namespace prefixes longer than 20 chars !
5636 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005637 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005638 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005639 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005640 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005641
Owen Taylor3473f882001-02-23 17:55:21 +00005642 def = xmlSearchNs(doc, tree, prefix);
5643 while (def != NULL) {
5644 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005645 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005646 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005647 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005648 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005649 def = xmlSearchNs(doc, tree, prefix);
5650 }
5651
5652 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005653 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005654 */
5655 def = xmlNewNs(tree, ns->href, prefix);
5656 return(def);
5657}
5658
Daniel Veillard652327a2003-09-29 18:02:38 +00005659#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005660/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005661 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005662 * @doc: the document
5663 * @tree: a node defining the subtree to reconciliate
5664 *
5665 * This function checks that all the namespaces declared within the given
5666 * tree are properly declared. This is needed for example after Copy or Cut
5667 * and then paste operations. The subtree may still hold pointers to
5668 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005669 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005670 * the new environment. If not possible the new namespaces are redeclared
5671 * on @tree at the top of the given subtree.
5672 * Returns the number of namespace declarations created or -1 in case of error.
5673 */
5674int
5675xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5676 xmlNsPtr *oldNs = NULL;
5677 xmlNsPtr *newNs = NULL;
5678 int sizeCache = 0;
5679 int nbCache = 0;
5680
5681 xmlNsPtr n;
5682 xmlNodePtr node = tree;
5683 xmlAttrPtr attr;
5684 int ret = 0, i;
5685
5686 while (node != NULL) {
5687 /*
5688 * Reconciliate the node namespace
5689 */
5690 if (node->ns != NULL) {
5691 /*
5692 * initialize the cache if needed
5693 */
5694 if (sizeCache == 0) {
5695 sizeCache = 10;
5696 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5697 sizeof(xmlNsPtr));
5698 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005699 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005700 return(-1);
5701 }
5702 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5703 sizeof(xmlNsPtr));
5704 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005705 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005706 xmlFree(oldNs);
5707 return(-1);
5708 }
5709 }
5710 for (i = 0;i < nbCache;i++) {
5711 if (oldNs[i] == node->ns) {
5712 node->ns = newNs[i];
5713 break;
5714 }
5715 }
5716 if (i == nbCache) {
5717 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005718 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005719 */
5720 n = xmlNewReconciliedNs(doc, tree, node->ns);
5721 if (n != NULL) { /* :-( what if else ??? */
5722 /*
5723 * check if we need to grow the cache buffers.
5724 */
5725 if (sizeCache <= nbCache) {
5726 sizeCache *= 2;
5727 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5728 sizeof(xmlNsPtr));
5729 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005730 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005731 xmlFree(newNs);
5732 return(-1);
5733 }
5734 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5735 sizeof(xmlNsPtr));
5736 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005737 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005738 xmlFree(oldNs);
5739 return(-1);
5740 }
5741 }
5742 newNs[nbCache] = n;
5743 oldNs[nbCache++] = node->ns;
5744 node->ns = n;
5745 }
5746 }
5747 }
5748 /*
5749 * now check for namespace hold by attributes on the node.
5750 */
5751 attr = node->properties;
5752 while (attr != NULL) {
5753 if (attr->ns != NULL) {
5754 /*
5755 * initialize the cache if needed
5756 */
5757 if (sizeCache == 0) {
5758 sizeCache = 10;
5759 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5760 sizeof(xmlNsPtr));
5761 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005762 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005763 return(-1);
5764 }
5765 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5766 sizeof(xmlNsPtr));
5767 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005768 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005769 xmlFree(oldNs);
5770 return(-1);
5771 }
5772 }
5773 for (i = 0;i < nbCache;i++) {
5774 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005775 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005776 break;
5777 }
5778 }
5779 if (i == nbCache) {
5780 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005781 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005782 */
5783 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5784 if (n != NULL) { /* :-( what if else ??? */
5785 /*
5786 * check if we need to grow the cache buffers.
5787 */
5788 if (sizeCache <= nbCache) {
5789 sizeCache *= 2;
5790 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5791 sizeof(xmlNsPtr));
5792 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005793 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005794 xmlFree(newNs);
5795 return(-1);
5796 }
5797 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5798 sizeof(xmlNsPtr));
5799 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005800 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005801 xmlFree(oldNs);
5802 return(-1);
5803 }
5804 }
5805 newNs[nbCache] = n;
5806 oldNs[nbCache++] = attr->ns;
5807 attr->ns = n;
5808 }
5809 }
5810 }
5811 attr = attr->next;
5812 }
5813
5814 /*
5815 * Browse the full subtree, deep first
5816 */
Daniel Veillardac996a12004-07-30 12:02:58 +00005817 if (node->children != NULL && node->type != XML_ENTITY_REF_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00005818 /* deep first */
5819 node = node->children;
5820 } else if ((node != tree) && (node->next != NULL)) {
5821 /* then siblings */
5822 node = node->next;
5823 } else if (node != tree) {
5824 /* go up to parents->next if needed */
5825 while (node != tree) {
5826 if (node->parent != NULL)
5827 node = node->parent;
5828 if ((node != tree) && (node->next != NULL)) {
5829 node = node->next;
5830 break;
5831 }
5832 if (node->parent == NULL) {
5833 node = NULL;
5834 break;
5835 }
5836 }
5837 /* exit condition */
5838 if (node == tree)
5839 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005840 } else
5841 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005842 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005843 if (oldNs != NULL)
5844 xmlFree(oldNs);
5845 if (newNs != NULL)
5846 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005847 return(ret);
5848}
Daniel Veillard652327a2003-09-29 18:02:38 +00005849#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005850
5851/**
5852 * xmlHasProp:
5853 * @node: the node
5854 * @name: the attribute name
5855 *
5856 * Search an attribute associated to a node
5857 * This function also looks in DTD attribute declaration for #FIXED or
5858 * default declaration values unless DTD use has been turned off.
5859 *
5860 * Returns the attribute or the attribute declaration or NULL if
5861 * neither was found.
5862 */
5863xmlAttrPtr
5864xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5865 xmlAttrPtr prop;
5866 xmlDocPtr doc;
5867
5868 if ((node == NULL) || (name == NULL)) return(NULL);
5869 /*
5870 * Check on the properties attached to the node
5871 */
5872 prop = node->properties;
5873 while (prop != NULL) {
5874 if (xmlStrEqual(prop->name, name)) {
5875 return(prop);
5876 }
5877 prop = prop->next;
5878 }
5879 if (!xmlCheckDTD) return(NULL);
5880
5881 /*
5882 * Check if there is a default declaration in the internal
5883 * or external subsets
5884 */
5885 doc = node->doc;
5886 if (doc != NULL) {
5887 xmlAttributePtr attrDecl;
5888 if (doc->intSubset != NULL) {
5889 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5890 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5891 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005892 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5893 /* return attribute declaration only if a default value is given
5894 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005895 return((xmlAttrPtr) attrDecl);
5896 }
5897 }
5898 return(NULL);
5899}
5900
5901/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005902 * xmlHasNsProp:
5903 * @node: the node
5904 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005905 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005906 *
5907 * Search for an attribute associated to a node
5908 * This attribute has to be anchored in the namespace specified.
5909 * This does the entity substitution.
5910 * This function looks in DTD attribute declaration for #FIXED or
5911 * default declaration values unless DTD use has been turned off.
5912 *
5913 * Returns the attribute or the attribute declaration or NULL
5914 * if neither was found.
5915 */
5916xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005917xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005918 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00005919#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005920 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00005921#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005922
5923 if (node == NULL)
5924 return(NULL);
5925
5926 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005927 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005928 return(xmlHasProp(node, name));
5929 while (prop != NULL) {
5930 /*
5931 * One need to have
5932 * - same attribute names
5933 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005934 */
5935 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005936 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5937 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005938 }
5939 prop = prop->next;
5940 }
5941 if (!xmlCheckDTD) return(NULL);
5942
Daniel Veillard652327a2003-09-29 18:02:38 +00005943#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005944 /*
5945 * Check if there is a default declaration in the internal
5946 * or external subsets
5947 */
5948 doc = node->doc;
5949 if (doc != NULL) {
5950 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005951 xmlAttributePtr attrDecl = NULL;
5952 xmlNsPtr *nsList, *cur;
5953 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005954
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005955 nsList = xmlGetNsList(node->doc, node);
5956 if (nsList == NULL)
5957 return(NULL);
5958 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5959 ename = xmlStrdup(node->ns->prefix);
5960 ename = xmlStrcat(ename, BAD_CAST ":");
5961 ename = xmlStrcat(ename, node->name);
5962 } else {
5963 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005964 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005965 if (ename == NULL) {
5966 xmlFree(nsList);
5967 return(NULL);
5968 }
5969
5970 cur = nsList;
5971 while (*cur != NULL) {
5972 if (xmlStrEqual((*cur)->href, nameSpace)) {
5973 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5974 name, (*cur)->prefix);
5975 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5976 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5977 name, (*cur)->prefix);
5978 }
5979 cur++;
5980 }
5981 xmlFree(nsList);
5982 xmlFree(ename);
5983 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005984 }
5985 }
Daniel Veillard652327a2003-09-29 18:02:38 +00005986#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005987 return(NULL);
5988}
5989
5990/**
Owen Taylor3473f882001-02-23 17:55:21 +00005991 * xmlGetProp:
5992 * @node: the node
5993 * @name: the attribute name
5994 *
5995 * Search and get the value of an attribute associated to a node
5996 * This does the entity substitution.
5997 * This function looks in DTD attribute declaration for #FIXED or
5998 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00005999 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00006000 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6001 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00006002 *
6003 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006004 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006005 */
6006xmlChar *
6007xmlGetProp(xmlNodePtr node, const xmlChar *name) {
6008 xmlAttrPtr prop;
6009 xmlDocPtr doc;
6010
6011 if ((node == NULL) || (name == NULL)) return(NULL);
6012 /*
6013 * Check on the properties attached to the node
6014 */
6015 prop = node->properties;
6016 while (prop != NULL) {
6017 if (xmlStrEqual(prop->name, name)) {
6018 xmlChar *ret;
6019
6020 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6021 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6022 return(ret);
6023 }
6024 prop = prop->next;
6025 }
6026 if (!xmlCheckDTD) return(NULL);
6027
6028 /*
6029 * Check if there is a default declaration in the internal
6030 * or external subsets
6031 */
6032 doc = node->doc;
6033 if (doc != NULL) {
6034 xmlAttributePtr attrDecl;
6035 if (doc->intSubset != NULL) {
6036 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6037 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6038 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006039 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6040 /* return attribute declaration only if a default value is given
6041 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006042 return(xmlStrdup(attrDecl->defaultValue));
6043 }
6044 }
6045 return(NULL);
6046}
6047
6048/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006049 * xmlGetNoNsProp:
6050 * @node: the node
6051 * @name: the attribute name
6052 *
6053 * Search and get the value of an attribute associated to a node
6054 * This does the entity substitution.
6055 * This function looks in DTD attribute declaration for #FIXED or
6056 * default declaration values unless DTD use has been turned off.
6057 * This function is similar to xmlGetProp except it will accept only
6058 * an attribute in no namespace.
6059 *
6060 * Returns the attribute value or NULL if not found.
6061 * It's up to the caller to free the memory with xmlFree().
6062 */
6063xmlChar *
6064xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6065 xmlAttrPtr prop;
6066 xmlDocPtr doc;
6067
6068 if ((node == NULL) || (name == NULL)) return(NULL);
6069 /*
6070 * Check on the properties attached to the node
6071 */
6072 prop = node->properties;
6073 while (prop != NULL) {
6074 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6075 xmlChar *ret;
6076
6077 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6078 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6079 return(ret);
6080 }
6081 prop = prop->next;
6082 }
6083 if (!xmlCheckDTD) return(NULL);
6084
6085 /*
6086 * Check if there is a default declaration in the internal
6087 * or external subsets
6088 */
6089 doc = node->doc;
6090 if (doc != NULL) {
6091 xmlAttributePtr attrDecl;
6092 if (doc->intSubset != NULL) {
6093 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6094 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6095 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006096 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6097 /* return attribute declaration only if a default value is given
6098 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006099 return(xmlStrdup(attrDecl->defaultValue));
6100 }
6101 }
6102 return(NULL);
6103}
6104
6105/**
Owen Taylor3473f882001-02-23 17:55:21 +00006106 * xmlGetNsProp:
6107 * @node: the node
6108 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006109 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006110 *
6111 * Search and get the value of an attribute associated to a node
6112 * This attribute has to be anchored in the namespace specified.
6113 * This does the entity substitution.
6114 * This function looks in DTD attribute declaration for #FIXED or
6115 * default declaration values unless DTD use has been turned off.
6116 *
6117 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006118 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006119 */
6120xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006121xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006122 xmlAttrPtr prop;
6123 xmlDocPtr doc;
6124 xmlNsPtr ns;
6125
6126 if (node == NULL)
6127 return(NULL);
6128
6129 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006130 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006131 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006132 while (prop != NULL) {
6133 /*
6134 * One need to have
6135 * - same attribute names
6136 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006137 */
6138 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006139 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006140 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006141 xmlChar *ret;
6142
6143 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6144 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6145 return(ret);
6146 }
6147 prop = prop->next;
6148 }
6149 if (!xmlCheckDTD) return(NULL);
6150
6151 /*
6152 * Check if there is a default declaration in the internal
6153 * or external subsets
6154 */
6155 doc = node->doc;
6156 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006157 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006158 xmlAttributePtr attrDecl;
6159
Owen Taylor3473f882001-02-23 17:55:21 +00006160 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6161 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6162 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6163
6164 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6165 /*
6166 * The DTD declaration only allows a prefix search
6167 */
6168 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006169 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006170 return(xmlStrdup(attrDecl->defaultValue));
6171 }
6172 }
6173 }
6174 return(NULL);
6175}
6176
Daniel Veillard2156d432004-03-04 15:59:36 +00006177#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6178/**
6179 * xmlUnsetProp:
6180 * @node: the node
6181 * @name: the attribute name
6182 *
6183 * Remove an attribute carried by a node.
6184 * Returns 0 if successful, -1 if not found
6185 */
6186int
6187xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
6188 xmlAttrPtr prop, prev = NULL;;
6189
6190 if ((node == NULL) || (name == NULL))
6191 return(-1);
6192 prop = node->properties;
6193 while (prop != NULL) {
6194 if ((xmlStrEqual(prop->name, name)) &&
6195 (prop->ns == NULL)) {
6196 if (prev == NULL)
6197 node->properties = prop->next;
6198 else
6199 prev->next = prop->next;
6200 xmlFreeProp(prop);
6201 return(0);
6202 }
6203 prev = prop;
6204 prop = prop->next;
6205 }
6206 return(-1);
6207}
6208
6209/**
6210 * xmlUnsetNsProp:
6211 * @node: the node
6212 * @ns: the namespace definition
6213 * @name: the attribute name
6214 *
6215 * Remove an attribute carried by a node.
6216 * Returns 0 if successful, -1 if not found
6217 */
6218int
6219xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6220 xmlAttrPtr prop = node->properties, prev = NULL;;
6221
6222 if ((node == NULL) || (name == NULL))
6223 return(-1);
6224 if (ns == NULL)
6225 return(xmlUnsetProp(node, name));
6226 if (ns->href == NULL)
6227 return(-1);
6228 while (prop != NULL) {
6229 if ((xmlStrEqual(prop->name, name)) &&
6230 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
6231 if (prev == NULL)
6232 node->properties = prop->next;
6233 else
6234 prev->next = prop->next;
6235 xmlFreeProp(prop);
6236 return(0);
6237 }
6238 prev = prop;
6239 prop = prop->next;
6240 }
6241 return(-1);
6242}
6243#endif
6244
6245#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006246/**
6247 * xmlSetProp:
6248 * @node: the node
6249 * @name: the attribute name
6250 * @value: the attribute value
6251 *
6252 * Set (or reset) an attribute carried by a node.
6253 * Returns the attribute pointer.
6254 */
6255xmlAttrPtr
6256xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006257 xmlAttrPtr prop;
6258 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006259
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006260 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006261 return(NULL);
6262 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006263 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006264 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006265 if ((xmlStrEqual(prop->name, name)) &&
6266 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006267 xmlNodePtr oldprop = prop->children;
6268
Owen Taylor3473f882001-02-23 17:55:21 +00006269 prop->children = NULL;
6270 prop->last = NULL;
6271 if (value != NULL) {
6272 xmlChar *buffer;
6273 xmlNodePtr tmp;
6274
6275 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6276 prop->children = xmlStringGetNodeList(node->doc, buffer);
6277 prop->last = NULL;
6278 prop->doc = doc;
6279 tmp = prop->children;
6280 while (tmp != NULL) {
6281 tmp->parent = (xmlNodePtr) prop;
6282 tmp->doc = doc;
6283 if (tmp->next == NULL)
6284 prop->last = tmp;
6285 tmp = tmp->next;
6286 }
6287 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006288 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006289 if (oldprop != NULL)
6290 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006291 return(prop);
6292 }
6293 prop = prop->next;
6294 }
6295 prop = xmlNewProp(node, name, value);
6296 return(prop);
6297}
6298
6299/**
6300 * xmlSetNsProp:
6301 * @node: the node
6302 * @ns: the namespace definition
6303 * @name: the attribute name
6304 * @value: the attribute value
6305 *
6306 * Set (or reset) an attribute carried by a node.
6307 * The ns structure must be in scope, this is not checked.
6308 *
6309 * Returns the attribute pointer.
6310 */
6311xmlAttrPtr
6312xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6313 const xmlChar *value) {
6314 xmlAttrPtr prop;
6315
6316 if ((node == NULL) || (name == NULL))
6317 return(NULL);
6318
6319 if (ns == NULL)
6320 return(xmlSetProp(node, name, value));
6321 if (ns->href == NULL)
6322 return(NULL);
6323 prop = node->properties;
6324
6325 while (prop != NULL) {
6326 /*
6327 * One need to have
6328 * - same attribute names
6329 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006330 */
6331 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006332 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006333 if (prop->children != NULL)
6334 xmlFreeNodeList(prop->children);
6335 prop->children = NULL;
6336 prop->last = NULL;
6337 prop->ns = ns;
6338 if (value != NULL) {
6339 xmlChar *buffer;
6340 xmlNodePtr tmp;
6341
6342 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6343 prop->children = xmlStringGetNodeList(node->doc, buffer);
6344 prop->last = NULL;
6345 tmp = prop->children;
6346 while (tmp != NULL) {
6347 tmp->parent = (xmlNodePtr) prop;
6348 if (tmp->next == NULL)
6349 prop->last = tmp;
6350 tmp = tmp->next;
6351 }
6352 xmlFree(buffer);
6353 }
6354 return(prop);
6355 }
6356 prop = prop->next;
6357 }
6358 prop = xmlNewNsProp(node, ns, name, value);
6359 return(prop);
6360}
6361
Daniel Veillard652327a2003-09-29 18:02:38 +00006362#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006363
6364/**
Owen Taylor3473f882001-02-23 17:55:21 +00006365 * xmlNodeIsText:
6366 * @node: the node
6367 *
6368 * Is this node a Text node ?
6369 * Returns 1 yes, 0 no
6370 */
6371int
6372xmlNodeIsText(xmlNodePtr node) {
6373 if (node == NULL) return(0);
6374
6375 if (node->type == XML_TEXT_NODE) return(1);
6376 return(0);
6377}
6378
6379/**
6380 * xmlIsBlankNode:
6381 * @node: the node
6382 *
6383 * Checks whether this node is an empty or whitespace only
6384 * (and possibly ignorable) text-node.
6385 *
6386 * Returns 1 yes, 0 no
6387 */
6388int
6389xmlIsBlankNode(xmlNodePtr node) {
6390 const xmlChar *cur;
6391 if (node == NULL) return(0);
6392
Daniel Veillard7db37732001-07-12 01:20:08 +00006393 if ((node->type != XML_TEXT_NODE) &&
6394 (node->type != XML_CDATA_SECTION_NODE))
6395 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006396 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006397 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006398 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006399 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006400 cur++;
6401 }
6402
6403 return(1);
6404}
6405
6406/**
6407 * xmlTextConcat:
6408 * @node: the node
6409 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006410 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006411 *
6412 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006413 *
6414 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006415 */
6416
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006417int
Owen Taylor3473f882001-02-23 17:55:21 +00006418xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006419 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006420
6421 if ((node->type != XML_TEXT_NODE) &&
6422 (node->type != XML_CDATA_SECTION_NODE)) {
6423#ifdef DEBUG_TREE
6424 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006425 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006426#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006427 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006428 }
William M. Brack7762bb12004-01-04 14:49:01 +00006429 /* need to check if content is currently in the dictionary */
6430 if ((node->doc != NULL) && (node->doc->dict != NULL) &&
6431 xmlDictOwns(node->doc->dict, node->content)) {
6432 node->content = xmlStrncatNew(node->content, content, len);
6433 } else {
6434 node->content = xmlStrncat(node->content, content, len);
6435 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006436 if (node->content == NULL)
6437 return(-1);
6438 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006439}
6440
6441/************************************************************************
6442 * *
6443 * Output : to a FILE or in memory *
6444 * *
6445 ************************************************************************/
6446
Owen Taylor3473f882001-02-23 17:55:21 +00006447/**
6448 * xmlBufferCreate:
6449 *
6450 * routine to create an XML buffer.
6451 * returns the new structure.
6452 */
6453xmlBufferPtr
6454xmlBufferCreate(void) {
6455 xmlBufferPtr ret;
6456
6457 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6458 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006459 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006460 return(NULL);
6461 }
6462 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006463 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006464 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006465 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006466 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006467 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006468 xmlFree(ret);
6469 return(NULL);
6470 }
6471 ret->content[0] = 0;
6472 return(ret);
6473}
6474
6475/**
6476 * xmlBufferCreateSize:
6477 * @size: initial size of buffer
6478 *
6479 * routine to create an XML buffer.
6480 * returns the new structure.
6481 */
6482xmlBufferPtr
6483xmlBufferCreateSize(size_t size) {
6484 xmlBufferPtr ret;
6485
6486 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6487 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006488 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006489 return(NULL);
6490 }
6491 ret->use = 0;
6492 ret->alloc = xmlBufferAllocScheme;
6493 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6494 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006495 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006496 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006497 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006498 xmlFree(ret);
6499 return(NULL);
6500 }
6501 ret->content[0] = 0;
6502 } else
6503 ret->content = NULL;
6504 return(ret);
6505}
6506
6507/**
Daniel Veillard53350552003-09-18 13:35:51 +00006508 * xmlBufferCreateStatic:
6509 * @mem: the memory area
6510 * @size: the size in byte
6511 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006512 * routine to create an XML buffer from an immutable memory area.
6513 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006514 * present until the end of the buffer lifetime.
6515 *
6516 * returns the new structure.
6517 */
6518xmlBufferPtr
6519xmlBufferCreateStatic(void *mem, size_t size) {
6520 xmlBufferPtr ret;
6521
6522 if ((mem == NULL) || (size == 0))
6523 return(NULL);
6524
6525 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6526 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006527 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006528 return(NULL);
6529 }
6530 ret->use = size;
6531 ret->size = size;
6532 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6533 ret->content = (xmlChar *) mem;
6534 return(ret);
6535}
6536
6537/**
Owen Taylor3473f882001-02-23 17:55:21 +00006538 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006539 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006540 * @scheme: allocation scheme to use
6541 *
6542 * Sets the allocation scheme for this buffer
6543 */
6544void
6545xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6546 xmlBufferAllocationScheme scheme) {
6547 if (buf == NULL) {
6548#ifdef DEBUG_BUFFER
6549 xmlGenericError(xmlGenericErrorContext,
6550 "xmlBufferSetAllocationScheme: buf == NULL\n");
6551#endif
6552 return;
6553 }
Daniel Veillard53350552003-09-18 13:35:51 +00006554 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006555
6556 buf->alloc = scheme;
6557}
6558
6559/**
6560 * xmlBufferFree:
6561 * @buf: the buffer to free
6562 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006563 * Frees an XML buffer. It frees both the content and the structure which
6564 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006565 */
6566void
6567xmlBufferFree(xmlBufferPtr buf) {
6568 if (buf == NULL) {
6569#ifdef DEBUG_BUFFER
6570 xmlGenericError(xmlGenericErrorContext,
6571 "xmlBufferFree: buf == NULL\n");
6572#endif
6573 return;
6574 }
Daniel Veillard53350552003-09-18 13:35:51 +00006575
6576 if ((buf->content != NULL) &&
6577 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006578 xmlFree(buf->content);
6579 }
Owen Taylor3473f882001-02-23 17:55:21 +00006580 xmlFree(buf);
6581}
6582
6583/**
6584 * xmlBufferEmpty:
6585 * @buf: the buffer
6586 *
6587 * empty a buffer.
6588 */
6589void
6590xmlBufferEmpty(xmlBufferPtr buf) {
6591 if (buf->content == NULL) return;
6592 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006593 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006594 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006595 } else {
6596 memset(buf->content, 0, buf->size);
6597 }
Owen Taylor3473f882001-02-23 17:55:21 +00006598}
6599
6600/**
6601 * xmlBufferShrink:
6602 * @buf: the buffer to dump
6603 * @len: the number of xmlChar to remove
6604 *
6605 * Remove the beginning of an XML buffer.
6606 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006607 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006608 */
6609int
6610xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6611 if (len == 0) return(0);
6612 if (len > buf->use) return(-1);
6613
6614 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006615 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6616 buf->content += len;
6617 } else {
6618 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6619 buf->content[buf->use] = 0;
6620 }
Owen Taylor3473f882001-02-23 17:55:21 +00006621 return(len);
6622}
6623
6624/**
6625 * xmlBufferGrow:
6626 * @buf: the buffer
6627 * @len: the minimum free size to allocate
6628 *
6629 * Grow the available space of an XML buffer.
6630 *
6631 * Returns the new available space or -1 in case of error
6632 */
6633int
6634xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6635 int size;
6636 xmlChar *newbuf;
6637
Daniel Veillard53350552003-09-18 13:35:51 +00006638 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006639 if (len + buf->use < buf->size) return(0);
6640
William M. Brack30fe43f2004-07-26 18:00:58 +00006641/*
6642 * Windows has a BIG problem on realloc timing, so we try to double
6643 * the buffer size (if that's enough) (bug 146697)
6644 */
6645#ifdef WIN32
6646 if (buf->size > len)
6647 size = buf->size * 2;
6648 else
6649 size = buf->use + len + 100;
6650#else
Owen Taylor3473f882001-02-23 17:55:21 +00006651 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00006652#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006653
6654 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006655 if (newbuf == NULL) {
6656 xmlTreeErrMemory("growing buffer");
6657 return(-1);
6658 }
Owen Taylor3473f882001-02-23 17:55:21 +00006659 buf->content = newbuf;
6660 buf->size = size;
6661 return(buf->size - buf->use);
6662}
6663
6664/**
6665 * xmlBufferDump:
6666 * @file: the file output
6667 * @buf: the buffer to dump
6668 *
6669 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006670 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006671 */
6672int
6673xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6674 int ret;
6675
6676 if (buf == NULL) {
6677#ifdef DEBUG_BUFFER
6678 xmlGenericError(xmlGenericErrorContext,
6679 "xmlBufferDump: buf == NULL\n");
6680#endif
6681 return(0);
6682 }
6683 if (buf->content == NULL) {
6684#ifdef DEBUG_BUFFER
6685 xmlGenericError(xmlGenericErrorContext,
6686 "xmlBufferDump: buf->content == NULL\n");
6687#endif
6688 return(0);
6689 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006690 if (file == NULL)
6691 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006692 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6693 return(ret);
6694}
6695
6696/**
6697 * xmlBufferContent:
6698 * @buf: the buffer
6699 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006700 * Function to extract the content of a buffer
6701 *
Owen Taylor3473f882001-02-23 17:55:21 +00006702 * Returns the internal content
6703 */
6704
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006705const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006706xmlBufferContent(const xmlBufferPtr buf)
6707{
6708 if(!buf)
6709 return NULL;
6710
6711 return buf->content;
6712}
6713
6714/**
6715 * xmlBufferLength:
6716 * @buf: the buffer
6717 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006718 * Function to get the length of a buffer
6719 *
Owen Taylor3473f882001-02-23 17:55:21 +00006720 * Returns the length of data in the internal content
6721 */
6722
6723int
6724xmlBufferLength(const xmlBufferPtr buf)
6725{
6726 if(!buf)
6727 return 0;
6728
6729 return buf->use;
6730}
6731
6732/**
6733 * xmlBufferResize:
6734 * @buf: the buffer to resize
6735 * @size: the desired size
6736 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006737 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006738 *
6739 * Returns 0 in case of problems, 1 otherwise
6740 */
6741int
6742xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6743{
6744 unsigned int newSize;
6745 xmlChar* rebuf = NULL;
6746
Daniel Veillard53350552003-09-18 13:35:51 +00006747 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6748
Owen Taylor3473f882001-02-23 17:55:21 +00006749 /* Don't resize if we don't have to */
6750 if (size < buf->size)
6751 return 1;
6752
6753 /* figure out new size */
6754 switch (buf->alloc){
6755 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillardbf629492004-04-20 22:20:59 +00006756 /*take care of empty case*/
6757 newSize = (buf->size ? buf->size*2 : size + 10);
Owen Taylor3473f882001-02-23 17:55:21 +00006758 while (size > newSize) newSize *= 2;
6759 break;
6760 case XML_BUFFER_ALLOC_EXACT:
6761 newSize = size+10;
6762 break;
6763 default:
6764 newSize = size+10;
6765 break;
6766 }
6767
6768 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006769 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006770 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006771 rebuf = (xmlChar *) xmlRealloc(buf->content,
6772 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006773 } else {
6774 /*
6775 * if we are reallocating a buffer far from being full, it's
6776 * better to make a new allocation and copy only the used range
6777 * and free the old one.
6778 */
6779 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6780 if (rebuf != NULL) {
6781 memcpy(rebuf, buf->content, buf->use);
6782 xmlFree(buf->content);
William M. Brack42331a92004-07-29 07:07:16 +00006783 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006784 }
6785 }
Owen Taylor3473f882001-02-23 17:55:21 +00006786 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006787 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006788 return 0;
6789 }
6790 buf->content = rebuf;
6791 buf->size = newSize;
6792
6793 return 1;
6794}
6795
6796/**
6797 * xmlBufferAdd:
6798 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006799 * @str: the #xmlChar string
6800 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006801 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006802 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006803 * str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006804 *
6805 * Returns 0 successful, a positive error code number otherwise
6806 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006807 */
William M. Bracka3215c72004-07-31 16:24:01 +00006808int
Owen Taylor3473f882001-02-23 17:55:21 +00006809xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6810 unsigned int needSize;
6811
6812 if (str == NULL) {
6813#ifdef DEBUG_BUFFER
6814 xmlGenericError(xmlGenericErrorContext,
6815 "xmlBufferAdd: str == NULL\n");
6816#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006817 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006818 }
William M. Bracka3215c72004-07-31 16:24:01 +00006819 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006820 if (len < -1) {
6821#ifdef DEBUG_BUFFER
6822 xmlGenericError(xmlGenericErrorContext,
6823 "xmlBufferAdd: len < 0\n");
6824#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006825 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006826 }
William M. Bracka3215c72004-07-31 16:24:01 +00006827 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006828
6829 if (len < 0)
6830 len = xmlStrlen(str);
6831
William M. Bracka3215c72004-07-31 16:24:01 +00006832 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006833
6834 needSize = buf->use + len + 2;
6835 if (needSize > buf->size){
6836 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006837 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006838 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006839 }
6840 }
6841
6842 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6843 buf->use += len;
6844 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006845 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006846}
6847
6848/**
6849 * xmlBufferAddHead:
6850 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006851 * @str: the #xmlChar string
6852 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006853 *
6854 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006855 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006856 *
6857 * Returns 0 successful, a positive error code number otherwise
6858 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006859 */
William M. Bracka3215c72004-07-31 16:24:01 +00006860int
Owen Taylor3473f882001-02-23 17:55:21 +00006861xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6862 unsigned int needSize;
6863
William M. Bracka3215c72004-07-31 16:24:01 +00006864 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006865 if (str == NULL) {
6866#ifdef DEBUG_BUFFER
6867 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006868 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006869#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006870 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006871 }
6872 if (len < -1) {
6873#ifdef DEBUG_BUFFER
6874 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006875 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006876#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006877 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006878 }
William M. Bracka3215c72004-07-31 16:24:01 +00006879 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006880
6881 if (len < 0)
6882 len = xmlStrlen(str);
6883
William M. Bracka3215c72004-07-31 16:24:01 +00006884 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006885
6886 needSize = buf->use + len + 2;
6887 if (needSize > buf->size){
6888 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006889 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006890 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006891 }
6892 }
6893
6894 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6895 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6896 buf->use += len;
6897 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006898 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006899}
6900
6901/**
6902 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00006903 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00006904 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006905 *
6906 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00006907 *
6908 * Returns 0 successful, a positive error code number otherwise
6909 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006910 */
William M. Bracka3215c72004-07-31 16:24:01 +00006911int
Owen Taylor3473f882001-02-23 17:55:21 +00006912xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
William M. Bracka3215c72004-07-31 16:24:01 +00006913 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
6914 if (str == NULL) return -1;
6915 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00006916}
6917
6918/**
6919 * xmlBufferCCat:
6920 * @buf: the buffer to dump
6921 * @str: the C char string
6922 *
6923 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00006924 *
6925 * Returns 0 successful, a positive error code number otherwise
6926 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006927 */
William M. Bracka3215c72004-07-31 16:24:01 +00006928int
Owen Taylor3473f882001-02-23 17:55:21 +00006929xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6930 const char *cur;
6931
William M. Bracka3215c72004-07-31 16:24:01 +00006932 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006933 if (str == NULL) {
6934#ifdef DEBUG_BUFFER
6935 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006936 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006937#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006938 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006939 }
6940 for (cur = str;*cur != 0;cur++) {
6941 if (buf->use + 10 >= buf->size) {
6942 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006943 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006944 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006945 }
6946 }
6947 buf->content[buf->use++] = *cur;
6948 }
6949 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006950 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006951}
6952
6953/**
6954 * xmlBufferWriteCHAR:
6955 * @buf: the XML buffer
6956 * @string: the string to add
6957 *
6958 * routine which manages and grows an output buffer. This one adds
6959 * xmlChars at the end of the buffer.
6960 */
6961void
Daniel Veillard53350552003-09-18 13:35:51 +00006962xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
6963 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006964 xmlBufferCat(buf, string);
6965}
6966
6967/**
6968 * xmlBufferWriteChar:
6969 * @buf: the XML buffer output
6970 * @string: the string to add
6971 *
6972 * routine which manage and grows an output buffer. This one add
6973 * C chars at the end of the array.
6974 */
6975void
6976xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillard53350552003-09-18 13:35:51 +00006977 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006978 xmlBufferCCat(buf, string);
6979}
6980
6981
6982/**
6983 * xmlBufferWriteQuotedString:
6984 * @buf: the XML buffer output
6985 * @string: the string to add
6986 *
6987 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006988 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006989 * quote or double-quotes internally
6990 */
6991void
6992xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00006993 const xmlChar *cur, *base;
Daniel Veillard53350552003-09-18 13:35:51 +00006994 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00006995 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00006996 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00006997#ifdef DEBUG_BUFFER
6998 xmlGenericError(xmlGenericErrorContext,
6999 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7000#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00007001 xmlBufferCCat(buf, "\"");
7002 base = cur = string;
7003 while(*cur != 0){
7004 if(*cur == '"'){
7005 if (base != cur)
7006 xmlBufferAdd(buf, base, cur - base);
7007 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7008 cur++;
7009 base = cur;
7010 }
7011 else {
7012 cur++;
7013 }
7014 }
7015 if (base != cur)
7016 xmlBufferAdd(buf, base, cur - base);
7017 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007018 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007019 else{
7020 xmlBufferCCat(buf, "\'");
7021 xmlBufferCat(buf, string);
7022 xmlBufferCCat(buf, "\'");
7023 }
Owen Taylor3473f882001-02-23 17:55:21 +00007024 } else {
7025 xmlBufferCCat(buf, "\"");
7026 xmlBufferCat(buf, string);
7027 xmlBufferCCat(buf, "\"");
7028 }
7029}
7030
7031
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007032/**
7033 * xmlGetDocCompressMode:
7034 * @doc: the document
7035 *
7036 * get the compression ratio for a document, ZLIB based
7037 * Returns 0 (uncompressed) to 9 (max compression)
7038 */
7039int
7040xmlGetDocCompressMode (xmlDocPtr doc) {
7041 if (doc == NULL) return(-1);
7042 return(doc->compression);
7043}
7044
7045/**
7046 * xmlSetDocCompressMode:
7047 * @doc: the document
7048 * @mode: the compression ratio
7049 *
7050 * set the compression ratio for a document, ZLIB based
7051 * Correct values: 0 (uncompressed) to 9 (max compression)
7052 */
7053void
7054xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7055 if (doc == NULL) return;
7056 if (mode < 0) doc->compression = 0;
7057 else if (mode > 9) doc->compression = 9;
7058 else doc->compression = mode;
7059}
7060
7061/**
7062 * xmlGetCompressMode:
7063 *
7064 * get the default compression mode used, ZLIB based.
7065 * Returns 0 (uncompressed) to 9 (max compression)
7066 */
7067int
7068xmlGetCompressMode(void)
7069{
7070 return (xmlCompressMode);
7071}
7072
7073/**
7074 * xmlSetCompressMode:
7075 * @mode: the compression ratio
7076 *
7077 * set the default compression mode used, ZLIB based
7078 * Correct values: 0 (uncompressed) to 9 (max compression)
7079 */
7080void
7081xmlSetCompressMode(int mode) {
7082 if (mode < 0) xmlCompressMode = 0;
7083 else if (mode > 9) xmlCompressMode = 9;
7084 else xmlCompressMode = mode;
7085}
7086