blob: 295066bc80ac63786133070635337d91c158ba8a [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 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001023 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001024 * indexes.
1025 */
1026 while (c != NULL) {
1027 next = c->next;
Daniel Veillardd72c7e32003-05-12 21:55:03 +00001028 if ((c->type == XML_COMMENT_NODE) || (c->type == XML_PI_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001029 xmlUnlinkNode(c);
1030 xmlFreeNode(c);
1031 }
1032 c = next;
1033 }
1034 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001035 DICT_FREE(cur->name)
1036 DICT_FREE(cur->SystemID)
1037 DICT_FREE(cur->ExternalID)
Owen Taylor3473f882001-02-23 17:55:21 +00001038 /* TODO !!! */
1039 if (cur->notations != NULL)
1040 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1041
1042 if (cur->elements != NULL)
1043 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1044 if (cur->attributes != NULL)
1045 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1046 if (cur->entities != NULL)
1047 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1048 if (cur->pentities != NULL)
1049 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1050
Owen Taylor3473f882001-02-23 17:55:21 +00001051 xmlFree(cur);
1052}
1053
1054/**
1055 * xmlNewDoc:
1056 * @version: xmlChar string giving the version of XML "1.0"
1057 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001058 * Creates a new XML document
1059 *
Owen Taylor3473f882001-02-23 17:55:21 +00001060 * Returns a new document
1061 */
1062xmlDocPtr
1063xmlNewDoc(const xmlChar *version) {
1064 xmlDocPtr cur;
1065
1066 if (version == NULL)
1067 version = (const xmlChar *) "1.0";
1068
1069 /*
1070 * Allocate a new document and fill the fields.
1071 */
1072 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1073 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001074 xmlTreeErrMemory("building doc");
Owen Taylor3473f882001-02-23 17:55:21 +00001075 return(NULL);
1076 }
1077 memset(cur, 0, sizeof(xmlDoc));
1078 cur->type = XML_DOCUMENT_NODE;
1079
1080 cur->version = xmlStrdup(version);
William M. Bracka3215c72004-07-31 16:24:01 +00001081 if (cur->version == NULL) {
1082 xmlTreeErrMemory("building doc");
1083 xmlFree(cur);
1084 return(NULL);
1085 }
Owen Taylor3473f882001-02-23 17:55:21 +00001086 cur->standalone = -1;
1087 cur->compression = -1; /* not initialized */
1088 cur->doc = cur;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001089 /*
1090 * The in memory encoding is always UTF8
1091 * This field will never change and would
1092 * be obsolete if not for binary compatibility.
1093 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001094 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001095
Daniel Veillarda880b122003-04-21 21:36:41 +00001096 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001097 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001098 return(cur);
1099}
1100
1101/**
1102 * xmlFreeDoc:
1103 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001104 *
1105 * Free up all the structures used by a document, tree included.
1106 */
1107void
1108xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001109 xmlDtdPtr extSubset, intSubset;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001110 xmlDictPtr dict = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001111
Owen Taylor3473f882001-02-23 17:55:21 +00001112 if (cur == NULL) {
1113#ifdef DEBUG_TREE
1114 xmlGenericError(xmlGenericErrorContext,
1115 "xmlFreeDoc : document == NULL\n");
1116#endif
1117 return;
1118 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001119 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001120
Daniel Veillarda880b122003-04-21 21:36:41 +00001121 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001122 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1123
Daniel Veillard76d66f42001-05-16 21:05:17 +00001124 /*
1125 * Do this before freeing the children list to avoid ID lookups
1126 */
1127 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1128 cur->ids = NULL;
1129 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1130 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001131 extSubset = cur->extSubset;
1132 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001133 if (intSubset == extSubset)
1134 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001135 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001136 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001137 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001138 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001139 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001140 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001141 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001142 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001143 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001144 }
1145
1146 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001147 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001148
1149 DICT_FREE(cur->version)
1150 DICT_FREE(cur->name)
1151 DICT_FREE(cur->encoding)
1152 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001153 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001154 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001155}
1156
1157/**
1158 * xmlStringLenGetNodeList:
1159 * @doc: the document
1160 * @value: the value of the text
1161 * @len: the length of the string value
1162 *
1163 * Parse the value string and build the node list associated. Should
1164 * produce a flat tree with only TEXTs and ENTITY_REFs.
1165 * Returns a pointer to the first child
1166 */
1167xmlNodePtr
1168xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1169 xmlNodePtr ret = NULL, last = NULL;
1170 xmlNodePtr node;
1171 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001172 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001173 const xmlChar *q;
1174 xmlEntityPtr ent;
1175
1176 if (value == NULL) return(NULL);
1177
1178 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001179 while ((cur < end) && (*cur != 0)) {
1180 if (cur[0] == '&') {
1181 int charval = 0;
1182 xmlChar tmp;
1183
Owen Taylor3473f882001-02-23 17:55:21 +00001184 /*
1185 * Save the current text.
1186 */
1187 if (cur != q) {
1188 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1189 xmlNodeAddContentLen(last, q, cur - q);
1190 } else {
1191 node = xmlNewDocTextLen(doc, q, cur - q);
1192 if (node == NULL) return(ret);
1193 if (last == NULL)
1194 last = ret = node;
1195 else {
1196 last->next = node;
1197 node->prev = last;
1198 last = node;
1199 }
1200 }
1201 }
Owen Taylor3473f882001-02-23 17:55:21 +00001202 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001203 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1204 cur += 3;
1205 if (cur < end)
1206 tmp = *cur;
1207 else
1208 tmp = 0;
1209 while (tmp != ';') { /* Non input consuming loop */
1210 if ((tmp >= '0') && (tmp <= '9'))
1211 charval = charval * 16 + (tmp - '0');
1212 else if ((tmp >= 'a') && (tmp <= 'f'))
1213 charval = charval * 16 + (tmp - 'a') + 10;
1214 else if ((tmp >= 'A') && (tmp <= 'F'))
1215 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001216 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001217 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1218 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001219 charval = 0;
1220 break;
1221 }
1222 cur++;
1223 if (cur < end)
1224 tmp = *cur;
1225 else
1226 tmp = 0;
1227 }
1228 if (tmp == ';')
1229 cur++;
1230 q = cur;
1231 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1232 cur += 2;
1233 if (cur < end)
1234 tmp = *cur;
1235 else
1236 tmp = 0;
1237 while (tmp != ';') { /* Non input consuming loops */
1238 if ((tmp >= '0') && (tmp <= '9'))
1239 charval = charval * 10 + (tmp - '0');
1240 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001241 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1242 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001243 charval = 0;
1244 break;
1245 }
1246 cur++;
1247 if (cur < end)
1248 tmp = *cur;
1249 else
1250 tmp = 0;
1251 }
1252 if (tmp == ';')
1253 cur++;
1254 q = cur;
1255 } else {
1256 /*
1257 * Read the entity string
1258 */
1259 cur++;
1260 q = cur;
1261 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1262 if ((cur >= end) || (*cur == 0)) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001263 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1264 (const char *) q);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001265 return(ret);
1266 }
1267 if (cur != q) {
1268 /*
1269 * Predefined entities don't generate nodes
1270 */
1271 val = xmlStrndup(q, cur - q);
1272 ent = xmlGetDocEntity(doc, val);
1273 if ((ent != NULL) &&
1274 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1275 if (last == NULL) {
1276 node = xmlNewDocText(doc, ent->content);
1277 last = ret = node;
1278 } else if (last->type != XML_TEXT_NODE) {
1279 node = xmlNewDocText(doc, ent->content);
1280 last = xmlAddNextSibling(last, node);
1281 } else
1282 xmlNodeAddContent(last, ent->content);
1283
1284 } else {
1285 /*
1286 * Create a new REFERENCE_REF node
1287 */
1288 node = xmlNewReference(doc, val);
1289 if (node == NULL) {
1290 if (val != NULL) xmlFree(val);
1291 return(ret);
1292 }
1293 else if ((ent != NULL) && (ent->children == NULL)) {
1294 xmlNodePtr temp;
1295
1296 ent->children = xmlStringGetNodeList(doc,
1297 (const xmlChar*)node->content);
1298 ent->owner = 1;
1299 temp = ent->children;
1300 while (temp) {
1301 temp->parent = (xmlNodePtr)ent;
1302 temp = temp->next;
1303 }
1304 }
1305 if (last == NULL) {
1306 last = ret = node;
1307 } else {
1308 last = xmlAddNextSibling(last, node);
1309 }
1310 }
1311 xmlFree(val);
1312 }
1313 cur++;
1314 q = cur;
1315 }
1316 if (charval != 0) {
1317 xmlChar buf[10];
1318 int l;
1319
1320 l = xmlCopyCharMultiByte(buf, charval);
1321 buf[l] = 0;
1322 node = xmlNewDocText(doc, buf);
1323 if (node != NULL) {
1324 if (last == NULL) {
1325 last = ret = node;
1326 } else {
1327 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001328 }
1329 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001330 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001331 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001332 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001333 cur++;
1334 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001335 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001336 /*
1337 * Handle the last piece of text.
1338 */
1339 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1340 xmlNodeAddContentLen(last, q, cur - q);
1341 } else {
1342 node = xmlNewDocTextLen(doc, q, cur - q);
1343 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001344 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001345 last = ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001346 } else {
1347 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001348 }
1349 }
1350 }
1351 return(ret);
1352}
1353
1354/**
1355 * xmlStringGetNodeList:
1356 * @doc: the document
1357 * @value: the value of the attribute
1358 *
1359 * Parse the value string and build the node list associated. Should
1360 * produce a flat tree with only TEXTs and ENTITY_REFs.
1361 * Returns a pointer to the first child
1362 */
1363xmlNodePtr
1364xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1365 xmlNodePtr ret = NULL, last = NULL;
1366 xmlNodePtr node;
1367 xmlChar *val;
1368 const xmlChar *cur = value;
1369 const xmlChar *q;
1370 xmlEntityPtr ent;
1371
1372 if (value == NULL) return(NULL);
1373
1374 q = cur;
1375 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001376 if (cur[0] == '&') {
1377 int charval = 0;
1378 xmlChar tmp;
1379
Owen Taylor3473f882001-02-23 17:55:21 +00001380 /*
1381 * Save the current text.
1382 */
1383 if (cur != q) {
1384 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1385 xmlNodeAddContentLen(last, q, cur - q);
1386 } else {
1387 node = xmlNewDocTextLen(doc, q, cur - q);
1388 if (node == NULL) return(ret);
1389 if (last == NULL)
1390 last = ret = node;
1391 else {
1392 last->next = node;
1393 node->prev = last;
1394 last = node;
1395 }
1396 }
1397 }
Owen Taylor3473f882001-02-23 17:55:21 +00001398 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001399 if ((cur[1] == '#') && (cur[2] == 'x')) {
1400 cur += 3;
1401 tmp = *cur;
1402 while (tmp != ';') { /* Non input consuming loop */
1403 if ((tmp >= '0') && (tmp <= '9'))
1404 charval = charval * 16 + (tmp - '0');
1405 else if ((tmp >= 'a') && (tmp <= 'f'))
1406 charval = charval * 16 + (tmp - 'a') + 10;
1407 else if ((tmp >= 'A') && (tmp <= 'F'))
1408 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001409 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001410 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1411 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001412 charval = 0;
1413 break;
1414 }
1415 cur++;
1416 tmp = *cur;
1417 }
1418 if (tmp == ';')
1419 cur++;
1420 q = cur;
1421 } else if (cur[1] == '#') {
1422 cur += 2;
1423 tmp = *cur;
1424 while (tmp != ';') { /* Non input consuming loops */
1425 if ((tmp >= '0') && (tmp <= '9'))
1426 charval = charval * 10 + (tmp - '0');
1427 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001428 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1429 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001430 charval = 0;
1431 break;
1432 }
1433 cur++;
1434 tmp = *cur;
1435 }
1436 if (tmp == ';')
1437 cur++;
1438 q = cur;
1439 } else {
1440 /*
1441 * Read the entity string
1442 */
1443 cur++;
1444 q = cur;
1445 while ((*cur != 0) && (*cur != ';')) cur++;
1446 if (*cur == 0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001447 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1448 (xmlNodePtr) doc, (const char *) q);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001449 return(ret);
1450 }
1451 if (cur != q) {
1452 /*
1453 * Predefined entities don't generate nodes
1454 */
1455 val = xmlStrndup(q, cur - q);
1456 ent = xmlGetDocEntity(doc, val);
1457 if ((ent != NULL) &&
1458 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1459 if (last == NULL) {
1460 node = xmlNewDocText(doc, ent->content);
1461 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001462 } else if (last->type != XML_TEXT_NODE) {
1463 node = xmlNewDocText(doc, ent->content);
1464 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001465 } else
1466 xmlNodeAddContent(last, ent->content);
1467
1468 } else {
1469 /*
1470 * Create a new REFERENCE_REF node
1471 */
1472 node = xmlNewReference(doc, val);
1473 if (node == NULL) {
1474 if (val != NULL) xmlFree(val);
1475 return(ret);
1476 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001477 else if ((ent != NULL) && (ent->children == NULL)) {
1478 xmlNodePtr temp;
1479
1480 ent->children = xmlStringGetNodeList(doc,
1481 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001482 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001483 temp = ent->children;
1484 while (temp) {
1485 temp->parent = (xmlNodePtr)ent;
1486 temp = temp->next;
1487 }
1488 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001489 if (last == NULL) {
1490 last = ret = node;
1491 } else {
1492 last = xmlAddNextSibling(last, node);
1493 }
1494 }
1495 xmlFree(val);
1496 }
1497 cur++;
1498 q = cur;
1499 }
1500 if (charval != 0) {
1501 xmlChar buf[10];
1502 int len;
1503
1504 len = xmlCopyCharMultiByte(buf, charval);
1505 buf[len] = 0;
1506 node = xmlNewDocText(doc, buf);
1507 if (node != NULL) {
1508 if (last == NULL) {
1509 last = ret = node;
1510 } else {
1511 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001512 }
1513 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001514
1515 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001516 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001517 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001518 cur++;
1519 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001520 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001521 /*
1522 * Handle the last piece of text.
1523 */
1524 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1525 xmlNodeAddContentLen(last, q, cur - q);
1526 } else {
1527 node = xmlNewDocTextLen(doc, q, cur - q);
1528 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001529 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001530 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001531 } else {
1532 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001533 }
1534 }
1535 }
1536 return(ret);
1537}
1538
1539/**
1540 * xmlNodeListGetString:
1541 * @doc: the document
1542 * @list: a Node list
1543 * @inLine: should we replace entity contents or show their external form
1544 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001545 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001546 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001547 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001548 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001549 */
1550xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001551xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1552{
Owen Taylor3473f882001-02-23 17:55:21 +00001553 xmlNodePtr node = list;
1554 xmlChar *ret = NULL;
1555 xmlEntityPtr ent;
1556
Daniel Veillard7646b182002-04-20 06:41:40 +00001557 if (list == NULL)
1558 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001559
1560 while (node != NULL) {
1561 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001562 (node->type == XML_CDATA_SECTION_NODE)) {
1563 if (inLine) {
1564 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001565 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001566 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001567
Daniel Veillard7646b182002-04-20 06:41:40 +00001568 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1569 if (buffer != NULL) {
1570 ret = xmlStrcat(ret, buffer);
1571 xmlFree(buffer);
1572 }
1573 }
1574 } else if (node->type == XML_ENTITY_REF_NODE) {
1575 if (inLine) {
1576 ent = xmlGetDocEntity(doc, node->name);
1577 if (ent != NULL) {
1578 xmlChar *buffer;
1579
1580 /* an entity content can be any "well balanced chunk",
1581 * i.e. the result of the content [43] production:
1582 * http://www.w3.org/TR/REC-xml#NT-content.
1583 * So it can contain text, CDATA section or nested
1584 * entity reference nodes (among others).
1585 * -> we recursive call xmlNodeListGetString()
1586 * which handles these types */
1587 buffer = xmlNodeListGetString(doc, ent->children, 1);
1588 if (buffer != NULL) {
1589 ret = xmlStrcat(ret, buffer);
1590 xmlFree(buffer);
1591 }
1592 } else {
1593 ret = xmlStrcat(ret, node->content);
1594 }
1595 } else {
1596 xmlChar buf[2];
1597
1598 buf[0] = '&';
1599 buf[1] = 0;
1600 ret = xmlStrncat(ret, buf, 1);
1601 ret = xmlStrcat(ret, node->name);
1602 buf[0] = ';';
1603 buf[1] = 0;
1604 ret = xmlStrncat(ret, buf, 1);
1605 }
1606 }
1607#if 0
1608 else {
1609 xmlGenericError(xmlGenericErrorContext,
1610 "xmlGetNodeListString : invalid node type %d\n",
1611 node->type);
1612 }
1613#endif
1614 node = node->next;
1615 }
1616 return (ret);
1617}
Daniel Veillard652327a2003-09-29 18:02:38 +00001618
1619#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001620/**
1621 * xmlNodeListGetRawString:
1622 * @doc: the document
1623 * @list: a Node list
1624 * @inLine: should we replace entity contents or show their external form
1625 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001626 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001627 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1628 * this function doesn't do any character encoding handling.
1629 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001630 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001631 */
1632xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001633xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1634{
Owen Taylor3473f882001-02-23 17:55:21 +00001635 xmlNodePtr node = list;
1636 xmlChar *ret = NULL;
1637 xmlEntityPtr ent;
1638
Daniel Veillard7646b182002-04-20 06:41:40 +00001639 if (list == NULL)
1640 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001641
1642 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001643 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001644 (node->type == XML_CDATA_SECTION_NODE)) {
1645 if (inLine) {
1646 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001647 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001648 xmlChar *buffer;
1649
1650 buffer = xmlEncodeSpecialChars(doc, node->content);
1651 if (buffer != NULL) {
1652 ret = xmlStrcat(ret, buffer);
1653 xmlFree(buffer);
1654 }
1655 }
1656 } else if (node->type == XML_ENTITY_REF_NODE) {
1657 if (inLine) {
1658 ent = xmlGetDocEntity(doc, node->name);
1659 if (ent != NULL) {
1660 xmlChar *buffer;
1661
1662 /* an entity content can be any "well balanced chunk",
1663 * i.e. the result of the content [43] production:
1664 * http://www.w3.org/TR/REC-xml#NT-content.
1665 * So it can contain text, CDATA section or nested
1666 * entity reference nodes (among others).
1667 * -> we recursive call xmlNodeListGetRawString()
1668 * which handles these types */
1669 buffer =
1670 xmlNodeListGetRawString(doc, ent->children, 1);
1671 if (buffer != NULL) {
1672 ret = xmlStrcat(ret, buffer);
1673 xmlFree(buffer);
1674 }
1675 } else {
1676 ret = xmlStrcat(ret, node->content);
1677 }
1678 } else {
1679 xmlChar buf[2];
1680
1681 buf[0] = '&';
1682 buf[1] = 0;
1683 ret = xmlStrncat(ret, buf, 1);
1684 ret = xmlStrcat(ret, node->name);
1685 buf[0] = ';';
1686 buf[1] = 0;
1687 ret = xmlStrncat(ret, buf, 1);
1688 }
1689 }
Owen Taylor3473f882001-02-23 17:55:21 +00001690#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001691 else {
1692 xmlGenericError(xmlGenericErrorContext,
1693 "xmlGetNodeListString : invalid node type %d\n",
1694 node->type);
1695 }
Owen Taylor3473f882001-02-23 17:55:21 +00001696#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001697 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001698 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001699 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001700}
Daniel Veillard652327a2003-09-29 18:02:38 +00001701#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001702
Daniel Veillard2156d432004-03-04 15:59:36 +00001703#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00001704/**
1705 * xmlNewProp:
1706 * @node: the holding node
1707 * @name: the name of the attribute
1708 * @value: the value of the attribute
1709 *
1710 * Create a new property carried by a node.
1711 * Returns a pointer to the attribute
1712 */
1713xmlAttrPtr
1714xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1715 xmlAttrPtr cur;
1716 xmlDocPtr doc = NULL;
1717
1718 if (name == NULL) {
1719#ifdef DEBUG_TREE
1720 xmlGenericError(xmlGenericErrorContext,
1721 "xmlNewProp : name == NULL\n");
1722#endif
1723 return(NULL);
1724 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001725 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1726 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001727
1728 /*
1729 * Allocate a new property and fill the fields.
1730 */
1731 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1732 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001733 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001734 return(NULL);
1735 }
1736 memset(cur, 0, sizeof(xmlAttr));
1737 cur->type = XML_ATTRIBUTE_NODE;
1738
1739 cur->parent = node;
1740 if (node != NULL) {
1741 doc = node->doc;
1742 cur->doc = doc;
1743 }
1744 cur->name = xmlStrdup(name);
1745 if (value != NULL) {
1746 xmlChar *buffer;
1747 xmlNodePtr tmp;
1748
1749 buffer = xmlEncodeEntitiesReentrant(doc, value);
1750 cur->children = xmlStringGetNodeList(doc, buffer);
1751 cur->last = NULL;
1752 tmp = cur->children;
1753 while (tmp != NULL) {
1754 tmp->parent = (xmlNodePtr) cur;
1755 tmp->doc = doc;
1756 if (tmp->next == NULL)
1757 cur->last = tmp;
1758 tmp = tmp->next;
1759 }
1760 xmlFree(buffer);
1761 }
1762
1763 /*
1764 * Add it at the end to preserve parsing order ...
1765 */
1766 if (node != NULL) {
1767 if (node->properties == NULL) {
1768 node->properties = cur;
1769 } else {
1770 xmlAttrPtr prev = node->properties;
1771
1772 while (prev->next != NULL) prev = prev->next;
1773 prev->next = cur;
1774 cur->prev = prev;
1775 }
1776 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001777
Daniel Veillarda880b122003-04-21 21:36:41 +00001778 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001779 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001780 return(cur);
1781}
Daniel Veillard652327a2003-09-29 18:02:38 +00001782#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001783
1784/**
1785 * xmlNewNsProp:
1786 * @node: the holding node
1787 * @ns: the namespace
1788 * @name: the name of the attribute
1789 * @value: the value of the attribute
1790 *
1791 * Create a new property tagged with a namespace and carried by a node.
1792 * Returns a pointer to the attribute
1793 */
1794xmlAttrPtr
1795xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1796 const xmlChar *value) {
1797 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001798 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001799
1800 if (name == NULL) {
1801#ifdef DEBUG_TREE
1802 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001803 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001804#endif
1805 return(NULL);
1806 }
1807
1808 /*
1809 * Allocate a new property and fill the fields.
1810 */
1811 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1812 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001813 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001814 return(NULL);
1815 }
1816 memset(cur, 0, sizeof(xmlAttr));
1817 cur->type = XML_ATTRIBUTE_NODE;
1818
1819 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001820 if (node != NULL) {
1821 doc = node->doc;
1822 cur->doc = doc;
1823 }
Owen Taylor3473f882001-02-23 17:55:21 +00001824 cur->ns = ns;
1825 cur->name = xmlStrdup(name);
1826 if (value != NULL) {
1827 xmlChar *buffer;
1828 xmlNodePtr tmp;
1829
Daniel Veillarda682b212001-06-07 19:59:42 +00001830 buffer = xmlEncodeEntitiesReentrant(doc, value);
1831 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001832 cur->last = NULL;
1833 tmp = cur->children;
1834 while (tmp != NULL) {
1835 tmp->parent = (xmlNodePtr) cur;
1836 if (tmp->next == NULL)
1837 cur->last = tmp;
1838 tmp = tmp->next;
1839 }
1840 xmlFree(buffer);
1841 }
1842
1843 /*
1844 * Add it at the end to preserve parsing order ...
1845 */
1846 if (node != NULL) {
1847 if (node->properties == NULL) {
1848 node->properties = cur;
1849 } else {
1850 xmlAttrPtr prev = node->properties;
1851
1852 while (prev->next != NULL) prev = prev->next;
1853 prev->next = cur;
1854 cur->prev = prev;
1855 }
1856 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001857
Daniel Veillarda880b122003-04-21 21:36:41 +00001858 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001859 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001860 return(cur);
1861}
1862
1863/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001864 * xmlNewNsPropEatName:
1865 * @node: the holding node
1866 * @ns: the namespace
1867 * @name: the name of the attribute
1868 * @value: the value of the attribute
1869 *
1870 * Create a new property tagged with a namespace and carried by a node.
1871 * Returns a pointer to the attribute
1872 */
1873xmlAttrPtr
1874xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1875 const xmlChar *value) {
1876 xmlAttrPtr cur;
1877 xmlDocPtr doc = NULL;
1878
1879 if (name == NULL) {
1880#ifdef DEBUG_TREE
1881 xmlGenericError(xmlGenericErrorContext,
1882 "xmlNewNsPropEatName : name == NULL\n");
1883#endif
1884 return(NULL);
1885 }
1886
1887 /*
1888 * Allocate a new property and fill the fields.
1889 */
1890 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1891 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001892 xmlTreeErrMemory("building attribute");
Daniel Veillard46de64e2002-05-29 08:21:33 +00001893 return(NULL);
1894 }
1895 memset(cur, 0, sizeof(xmlAttr));
1896 cur->type = XML_ATTRIBUTE_NODE;
1897
1898 cur->parent = node;
1899 if (node != NULL) {
1900 doc = node->doc;
1901 cur->doc = doc;
1902 }
1903 cur->ns = ns;
1904 cur->name = name;
1905 if (value != NULL) {
1906 xmlChar *buffer;
1907 xmlNodePtr tmp;
1908
1909 buffer = xmlEncodeEntitiesReentrant(doc, value);
1910 cur->children = xmlStringGetNodeList(doc, buffer);
1911 cur->last = NULL;
1912 tmp = cur->children;
1913 while (tmp != NULL) {
1914 tmp->parent = (xmlNodePtr) cur;
1915 if (tmp->next == NULL)
1916 cur->last = tmp;
1917 tmp = tmp->next;
1918 }
1919 xmlFree(buffer);
1920 }
1921
1922 /*
1923 * Add it at the end to preserve parsing order ...
1924 */
1925 if (node != NULL) {
1926 if (node->properties == NULL) {
1927 node->properties = cur;
1928 } else {
1929 xmlAttrPtr prev = node->properties;
1930
1931 while (prev->next != NULL) prev = prev->next;
1932 prev->next = cur;
1933 cur->prev = prev;
1934 }
1935 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001936
Daniel Veillarda880b122003-04-21 21:36:41 +00001937 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001938 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001939 return(cur);
1940}
1941
1942/**
Owen Taylor3473f882001-02-23 17:55:21 +00001943 * xmlNewDocProp:
1944 * @doc: the document
1945 * @name: the name of the attribute
1946 * @value: the value of the attribute
1947 *
1948 * Create a new property carried by a document.
1949 * Returns a pointer to the attribute
1950 */
1951xmlAttrPtr
1952xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1953 xmlAttrPtr cur;
1954
1955 if (name == NULL) {
1956#ifdef DEBUG_TREE
1957 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001958 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001959#endif
1960 return(NULL);
1961 }
1962
1963 /*
1964 * Allocate a new property and fill the fields.
1965 */
1966 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1967 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001968 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001969 return(NULL);
1970 }
1971 memset(cur, 0, sizeof(xmlAttr));
1972 cur->type = XML_ATTRIBUTE_NODE;
1973
1974 cur->name = xmlStrdup(name);
1975 cur->doc = doc;
1976 if (value != NULL) {
1977 xmlNodePtr tmp;
1978
1979 cur->children = xmlStringGetNodeList(doc, value);
1980 cur->last = NULL;
1981
1982 tmp = cur->children;
1983 while (tmp != NULL) {
1984 tmp->parent = (xmlNodePtr) cur;
1985 if (tmp->next == NULL)
1986 cur->last = tmp;
1987 tmp = tmp->next;
1988 }
1989 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001990
Daniel Veillarda880b122003-04-21 21:36:41 +00001991 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001992 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001993 return(cur);
1994}
1995
1996/**
1997 * xmlFreePropList:
1998 * @cur: the first property in the list
1999 *
2000 * Free a property and all its siblings, all the children are freed too.
2001 */
2002void
2003xmlFreePropList(xmlAttrPtr cur) {
2004 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002005 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002006 while (cur != NULL) {
2007 next = cur->next;
2008 xmlFreeProp(cur);
2009 cur = next;
2010 }
2011}
2012
2013/**
2014 * xmlFreeProp:
2015 * @cur: an attribute
2016 *
2017 * Free one attribute, all the content is freed too
2018 */
2019void
2020xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002021 xmlDictPtr dict = NULL;
2022 if (cur == NULL) return;
2023
2024 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002025
Daniel Veillarda880b122003-04-21 21:36:41 +00002026 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002027 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
2028
Owen Taylor3473f882001-02-23 17:55:21 +00002029 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00002030 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
2031 ((cur->parent->doc->intSubset != NULL) ||
2032 (cur->parent->doc->extSubset != NULL))) {
2033 if (xmlIsID(cur->parent->doc, cur->parent, cur))
2034 xmlRemoveID(cur->parent->doc, cur);
2035 }
Owen Taylor3473f882001-02-23 17:55:21 +00002036 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002037 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002038 xmlFree(cur);
2039}
2040
Daniel Veillard652327a2003-09-29 18:02:38 +00002041#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002042/**
2043 * xmlRemoveProp:
2044 * @cur: an attribute
2045 *
2046 * Unlink and free one attribute, all the content is freed too
2047 * Note this doesn't work for namespace definition attributes
2048 *
2049 * Returns 0 if success and -1 in case of error.
2050 */
2051int
2052xmlRemoveProp(xmlAttrPtr cur) {
2053 xmlAttrPtr tmp;
2054 if (cur == NULL) {
2055#ifdef DEBUG_TREE
2056 xmlGenericError(xmlGenericErrorContext,
2057 "xmlRemoveProp : cur == NULL\n");
2058#endif
2059 return(-1);
2060 }
2061 if (cur->parent == NULL) {
2062#ifdef DEBUG_TREE
2063 xmlGenericError(xmlGenericErrorContext,
2064 "xmlRemoveProp : cur->parent == NULL\n");
2065#endif
2066 return(-1);
2067 }
2068 tmp = cur->parent->properties;
2069 if (tmp == cur) {
2070 cur->parent->properties = cur->next;
2071 xmlFreeProp(cur);
2072 return(0);
2073 }
2074 while (tmp != NULL) {
2075 if (tmp->next == cur) {
2076 tmp->next = cur->next;
2077 if (tmp->next != NULL)
2078 tmp->next->prev = tmp;
2079 xmlFreeProp(cur);
2080 return(0);
2081 }
2082 tmp = tmp->next;
2083 }
2084#ifdef DEBUG_TREE
2085 xmlGenericError(xmlGenericErrorContext,
2086 "xmlRemoveProp : attribute not owned by its node\n");
2087#endif
2088 return(-1);
2089}
Daniel Veillard652327a2003-09-29 18:02:38 +00002090#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002091
2092/**
2093 * xmlNewPI:
2094 * @name: the processing instruction name
2095 * @content: the PI content
2096 *
2097 * Creation of a processing instruction element.
2098 * Returns a pointer to the new node object.
2099 */
2100xmlNodePtr
2101xmlNewPI(const xmlChar *name, const xmlChar *content) {
2102 xmlNodePtr cur;
2103
2104 if (name == NULL) {
2105#ifdef DEBUG_TREE
2106 xmlGenericError(xmlGenericErrorContext,
2107 "xmlNewPI : name == NULL\n");
2108#endif
2109 return(NULL);
2110 }
2111
2112 /*
2113 * Allocate a new node and fill the fields.
2114 */
2115 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2116 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002117 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002118 return(NULL);
2119 }
2120 memset(cur, 0, sizeof(xmlNode));
2121 cur->type = XML_PI_NODE;
2122
2123 cur->name = xmlStrdup(name);
2124 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002125 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002126 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002127
Daniel Veillarda880b122003-04-21 21:36:41 +00002128 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002129 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002130 return(cur);
2131}
2132
2133/**
2134 * xmlNewNode:
2135 * @ns: namespace if any
2136 * @name: the node name
2137 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002138 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002139 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002140 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2141 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002142 */
2143xmlNodePtr
2144xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2145 xmlNodePtr cur;
2146
2147 if (name == NULL) {
2148#ifdef DEBUG_TREE
2149 xmlGenericError(xmlGenericErrorContext,
2150 "xmlNewNode : name == NULL\n");
2151#endif
2152 return(NULL);
2153 }
2154
2155 /*
2156 * Allocate a new node and fill the fields.
2157 */
2158 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2159 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002160 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002161 return(NULL);
2162 }
2163 memset(cur, 0, sizeof(xmlNode));
2164 cur->type = XML_ELEMENT_NODE;
2165
2166 cur->name = xmlStrdup(name);
2167 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002168
Daniel Veillarda880b122003-04-21 21:36:41 +00002169 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002170 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002171 return(cur);
2172}
2173
2174/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002175 * xmlNewNodeEatName:
2176 * @ns: namespace if any
2177 * @name: the node name
2178 *
2179 * Creation of a new node element. @ns is optional (NULL).
2180 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002181 * Returns a pointer to the new node object, with pointer @name as
2182 * new node's name. Use xmlNewNode() if a copy of @name string is
2183 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002184 */
2185xmlNodePtr
2186xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2187 xmlNodePtr cur;
2188
2189 if (name == NULL) {
2190#ifdef DEBUG_TREE
2191 xmlGenericError(xmlGenericErrorContext,
2192 "xmlNewNode : name == NULL\n");
2193#endif
2194 return(NULL);
2195 }
2196
2197 /*
2198 * Allocate a new node and fill the fields.
2199 */
2200 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2201 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002202 xmlTreeErrMemory("building node");
Daniel Veillard46de64e2002-05-29 08:21:33 +00002203 return(NULL);
2204 }
2205 memset(cur, 0, sizeof(xmlNode));
2206 cur->type = XML_ELEMENT_NODE;
2207
2208 cur->name = name;
2209 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002210
Daniel Veillarda880b122003-04-21 21:36:41 +00002211 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002212 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002213 return(cur);
2214}
2215
2216/**
Owen Taylor3473f882001-02-23 17:55:21 +00002217 * xmlNewDocNode:
2218 * @doc: the document
2219 * @ns: namespace if any
2220 * @name: the node name
2221 * @content: the XML text content if any
2222 *
2223 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002224 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002225 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2226 * references, but XML special chars need to be escaped first by using
2227 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2228 * need entities support.
2229 *
2230 * Returns a pointer to the new node object.
2231 */
2232xmlNodePtr
2233xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2234 const xmlChar *name, const xmlChar *content) {
2235 xmlNodePtr cur;
2236
2237 cur = xmlNewNode(ns, name);
2238 if (cur != NULL) {
2239 cur->doc = doc;
2240 if (content != NULL) {
2241 cur->children = xmlStringGetNodeList(doc, content);
2242 UPDATE_LAST_CHILD_AND_PARENT(cur)
2243 }
2244 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002245
Owen Taylor3473f882001-02-23 17:55:21 +00002246 return(cur);
2247}
2248
Daniel Veillard46de64e2002-05-29 08:21:33 +00002249/**
2250 * xmlNewDocNodeEatName:
2251 * @doc: the document
2252 * @ns: namespace if any
2253 * @name: the node name
2254 * @content: the XML text content if any
2255 *
2256 * Creation of a new node element within a document. @ns and @content
2257 * are optional (NULL).
2258 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2259 * references, but XML special chars need to be escaped first by using
2260 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2261 * need entities support.
2262 *
2263 * Returns a pointer to the new node object.
2264 */
2265xmlNodePtr
2266xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2267 xmlChar *name, const xmlChar *content) {
2268 xmlNodePtr cur;
2269
2270 cur = xmlNewNodeEatName(ns, name);
2271 if (cur != NULL) {
2272 cur->doc = doc;
2273 if (content != NULL) {
2274 cur->children = xmlStringGetNodeList(doc, content);
2275 UPDATE_LAST_CHILD_AND_PARENT(cur)
2276 }
2277 }
2278 return(cur);
2279}
2280
Daniel Veillard652327a2003-09-29 18:02:38 +00002281#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002282/**
2283 * xmlNewDocRawNode:
2284 * @doc: the document
2285 * @ns: namespace if any
2286 * @name: the node name
2287 * @content: the text content if any
2288 *
2289 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002290 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002291 *
2292 * Returns a pointer to the new node object.
2293 */
2294xmlNodePtr
2295xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2296 const xmlChar *name, const xmlChar *content) {
2297 xmlNodePtr cur;
2298
2299 cur = xmlNewNode(ns, name);
2300 if (cur != NULL) {
2301 cur->doc = doc;
2302 if (content != NULL) {
2303 cur->children = xmlNewDocText(doc, content);
2304 UPDATE_LAST_CHILD_AND_PARENT(cur)
2305 }
2306 }
2307 return(cur);
2308}
2309
2310/**
2311 * xmlNewDocFragment:
2312 * @doc: the document owning the fragment
2313 *
2314 * Creation of a new Fragment node.
2315 * Returns a pointer to the new node object.
2316 */
2317xmlNodePtr
2318xmlNewDocFragment(xmlDocPtr doc) {
2319 xmlNodePtr cur;
2320
2321 /*
2322 * Allocate a new DocumentFragment node and fill the fields.
2323 */
2324 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2325 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002326 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002327 return(NULL);
2328 }
2329 memset(cur, 0, sizeof(xmlNode));
2330 cur->type = XML_DOCUMENT_FRAG_NODE;
2331
2332 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002333
Daniel Veillarda880b122003-04-21 21:36:41 +00002334 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002335 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002336 return(cur);
2337}
Daniel Veillard652327a2003-09-29 18:02:38 +00002338#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002339
2340/**
2341 * xmlNewText:
2342 * @content: the text content
2343 *
2344 * Creation of a new text node.
2345 * Returns a pointer to the new node object.
2346 */
2347xmlNodePtr
2348xmlNewText(const xmlChar *content) {
2349 xmlNodePtr cur;
2350
2351 /*
2352 * Allocate a new node and fill the fields.
2353 */
2354 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2355 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002356 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002357 return(NULL);
2358 }
2359 memset(cur, 0, sizeof(xmlNode));
2360 cur->type = XML_TEXT_NODE;
2361
2362 cur->name = xmlStringText;
2363 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002364 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002365 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002366
Daniel Veillarda880b122003-04-21 21:36:41 +00002367 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002368 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002369 return(cur);
2370}
2371
Daniel Veillard652327a2003-09-29 18:02:38 +00002372#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002373/**
2374 * xmlNewTextChild:
2375 * @parent: the parent node
2376 * @ns: a namespace if any
2377 * @name: the name of the child
2378 * @content: the text content of the child if any.
2379 *
2380 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002381 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2382 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002383 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002384 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2385 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2386 * reserved XML chars that might appear in @content, such as the ampersand,
2387 * greater-than or less-than signs, are automatically replaced by their XML
2388 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002389 *
2390 * Returns a pointer to the new node object.
2391 */
2392xmlNodePtr
2393xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2394 const xmlChar *name, const xmlChar *content) {
2395 xmlNodePtr cur, prev;
2396
2397 if (parent == NULL) {
2398#ifdef DEBUG_TREE
2399 xmlGenericError(xmlGenericErrorContext,
2400 "xmlNewTextChild : parent == NULL\n");
2401#endif
2402 return(NULL);
2403 }
2404
2405 if (name == NULL) {
2406#ifdef DEBUG_TREE
2407 xmlGenericError(xmlGenericErrorContext,
2408 "xmlNewTextChild : name == NULL\n");
2409#endif
2410 return(NULL);
2411 }
2412
2413 /*
2414 * Allocate a new node
2415 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002416 if (parent->type == XML_ELEMENT_NODE) {
2417 if (ns == NULL)
2418 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2419 else
2420 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2421 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2422 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2423 if (ns == NULL)
2424 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2425 else
2426 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2427 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2428 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2429 } else {
2430 return(NULL);
2431 }
Owen Taylor3473f882001-02-23 17:55:21 +00002432 if (cur == NULL) return(NULL);
2433
2434 /*
2435 * add the new element at the end of the children list.
2436 */
2437 cur->type = XML_ELEMENT_NODE;
2438 cur->parent = parent;
2439 cur->doc = parent->doc;
2440 if (parent->children == NULL) {
2441 parent->children = cur;
2442 parent->last = cur;
2443 } else {
2444 prev = parent->last;
2445 prev->next = cur;
2446 cur->prev = prev;
2447 parent->last = cur;
2448 }
2449
2450 return(cur);
2451}
Daniel Veillard652327a2003-09-29 18:02:38 +00002452#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002453
2454/**
2455 * xmlNewCharRef:
2456 * @doc: the document
2457 * @name: the char ref string, starting with # or "&# ... ;"
2458 *
2459 * Creation of a new character reference node.
2460 * Returns a pointer to the new node object.
2461 */
2462xmlNodePtr
2463xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2464 xmlNodePtr cur;
2465
2466 /*
2467 * Allocate a new node and fill the fields.
2468 */
2469 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2470 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002471 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002472 return(NULL);
2473 }
2474 memset(cur, 0, sizeof(xmlNode));
2475 cur->type = XML_ENTITY_REF_NODE;
2476
2477 cur->doc = doc;
2478 if (name[0] == '&') {
2479 int len;
2480 name++;
2481 len = xmlStrlen(name);
2482 if (name[len - 1] == ';')
2483 cur->name = xmlStrndup(name, len - 1);
2484 else
2485 cur->name = xmlStrndup(name, len);
2486 } else
2487 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002488
Daniel Veillarda880b122003-04-21 21:36:41 +00002489 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002490 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002491 return(cur);
2492}
2493
2494/**
2495 * xmlNewReference:
2496 * @doc: the document
2497 * @name: the reference name, or the reference string with & and ;
2498 *
2499 * Creation of a new reference node.
2500 * Returns a pointer to the new node object.
2501 */
2502xmlNodePtr
2503xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2504 xmlNodePtr cur;
2505 xmlEntityPtr ent;
2506
2507 /*
2508 * Allocate a new node and fill the fields.
2509 */
2510 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2511 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002512 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002513 return(NULL);
2514 }
2515 memset(cur, 0, sizeof(xmlNode));
2516 cur->type = XML_ENTITY_REF_NODE;
2517
2518 cur->doc = doc;
2519 if (name[0] == '&') {
2520 int len;
2521 name++;
2522 len = xmlStrlen(name);
2523 if (name[len - 1] == ';')
2524 cur->name = xmlStrndup(name, len - 1);
2525 else
2526 cur->name = xmlStrndup(name, len);
2527 } else
2528 cur->name = xmlStrdup(name);
2529
2530 ent = xmlGetDocEntity(doc, cur->name);
2531 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002532 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002533 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002534 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002535 * updated. Not sure if this is 100% correct.
2536 * -George
2537 */
2538 cur->children = (xmlNodePtr) ent;
2539 cur->last = (xmlNodePtr) ent;
2540 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002541
Daniel Veillarda880b122003-04-21 21:36:41 +00002542 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002543 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002544 return(cur);
2545}
2546
2547/**
2548 * xmlNewDocText:
2549 * @doc: the document
2550 * @content: the text content
2551 *
2552 * Creation of a new text node within a document.
2553 * Returns a pointer to the new node object.
2554 */
2555xmlNodePtr
2556xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2557 xmlNodePtr cur;
2558
2559 cur = xmlNewText(content);
2560 if (cur != NULL) cur->doc = doc;
2561 return(cur);
2562}
2563
2564/**
2565 * xmlNewTextLen:
2566 * @content: the text content
2567 * @len: the text len.
2568 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002569 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002570 * Returns a pointer to the new node object.
2571 */
2572xmlNodePtr
2573xmlNewTextLen(const xmlChar *content, int len) {
2574 xmlNodePtr cur;
2575
2576 /*
2577 * Allocate a new node and fill the fields.
2578 */
2579 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2580 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002581 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002582 return(NULL);
2583 }
2584 memset(cur, 0, sizeof(xmlNode));
2585 cur->type = XML_TEXT_NODE;
2586
2587 cur->name = xmlStringText;
2588 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002589 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002590 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002591
Daniel Veillarda880b122003-04-21 21:36:41 +00002592 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002593 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002594 return(cur);
2595}
2596
2597/**
2598 * xmlNewDocTextLen:
2599 * @doc: the document
2600 * @content: the text content
2601 * @len: the text len.
2602 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002603 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002604 * text node pertain to a given document.
2605 * Returns a pointer to the new node object.
2606 */
2607xmlNodePtr
2608xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2609 xmlNodePtr cur;
2610
2611 cur = xmlNewTextLen(content, len);
2612 if (cur != NULL) cur->doc = doc;
2613 return(cur);
2614}
2615
2616/**
2617 * xmlNewComment:
2618 * @content: the comment content
2619 *
2620 * Creation of a new node containing a comment.
2621 * Returns a pointer to the new node object.
2622 */
2623xmlNodePtr
2624xmlNewComment(const xmlChar *content) {
2625 xmlNodePtr cur;
2626
2627 /*
2628 * Allocate a new node and fill the fields.
2629 */
2630 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2631 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002632 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002633 return(NULL);
2634 }
2635 memset(cur, 0, sizeof(xmlNode));
2636 cur->type = XML_COMMENT_NODE;
2637
2638 cur->name = xmlStringComment;
2639 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002640 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002641 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002642
Daniel Veillarda880b122003-04-21 21:36:41 +00002643 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002644 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002645 return(cur);
2646}
2647
2648/**
2649 * xmlNewCDataBlock:
2650 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002651 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002652 * @len: the length of the block
2653 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002654 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002655 * Returns a pointer to the new node object.
2656 */
2657xmlNodePtr
2658xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2659 xmlNodePtr cur;
2660
2661 /*
2662 * Allocate a new node and fill the fields.
2663 */
2664 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2665 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002666 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002667 return(NULL);
2668 }
2669 memset(cur, 0, sizeof(xmlNode));
2670 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002671 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002672
2673 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002674 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002675 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002676
Daniel Veillarda880b122003-04-21 21:36:41 +00002677 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002678 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002679 return(cur);
2680}
2681
2682/**
2683 * xmlNewDocComment:
2684 * @doc: the document
2685 * @content: the comment content
2686 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002687 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002688 * Returns a pointer to the new node object.
2689 */
2690xmlNodePtr
2691xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2692 xmlNodePtr cur;
2693
2694 cur = xmlNewComment(content);
2695 if (cur != NULL) cur->doc = doc;
2696 return(cur);
2697}
2698
2699/**
2700 * xmlSetTreeDoc:
2701 * @tree: the top element
2702 * @doc: the document
2703 *
2704 * update all nodes under the tree to point to the right document
2705 */
2706void
2707xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002708 xmlAttrPtr prop;
2709
Owen Taylor3473f882001-02-23 17:55:21 +00002710 if (tree == NULL)
2711 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002712 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002713 if(tree->type == XML_ELEMENT_NODE) {
2714 prop = tree->properties;
2715 while (prop != NULL) {
2716 prop->doc = doc;
2717 xmlSetListDoc(prop->children, doc);
2718 prop = prop->next;
2719 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002720 }
Owen Taylor3473f882001-02-23 17:55:21 +00002721 if (tree->children != NULL)
2722 xmlSetListDoc(tree->children, doc);
2723 tree->doc = doc;
2724 }
2725}
2726
2727/**
2728 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002729 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002730 * @doc: the document
2731 *
2732 * update all nodes in the list to point to the right document
2733 */
2734void
2735xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2736 xmlNodePtr cur;
2737
2738 if (list == NULL)
2739 return;
2740 cur = list;
2741 while (cur != NULL) {
2742 if (cur->doc != doc)
2743 xmlSetTreeDoc(cur, doc);
2744 cur = cur->next;
2745 }
2746}
2747
Daniel Veillard2156d432004-03-04 15:59:36 +00002748#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002749/**
2750 * xmlNewChild:
2751 * @parent: the parent node
2752 * @ns: a namespace if any
2753 * @name: the name of the child
2754 * @content: the XML content of the child if any.
2755 *
2756 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002757 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2758 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002759 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002760 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2761 * references. XML special chars must be escaped first by using
2762 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002763 *
2764 * Returns a pointer to the new node object.
2765 */
2766xmlNodePtr
2767xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2768 const xmlChar *name, const xmlChar *content) {
2769 xmlNodePtr cur, prev;
2770
2771 if (parent == NULL) {
2772#ifdef DEBUG_TREE
2773 xmlGenericError(xmlGenericErrorContext,
2774 "xmlNewChild : parent == NULL\n");
2775#endif
2776 return(NULL);
2777 }
2778
2779 if (name == NULL) {
2780#ifdef DEBUG_TREE
2781 xmlGenericError(xmlGenericErrorContext,
2782 "xmlNewChild : name == NULL\n");
2783#endif
2784 return(NULL);
2785 }
2786
2787 /*
2788 * Allocate a new node
2789 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002790 if (parent->type == XML_ELEMENT_NODE) {
2791 if (ns == NULL)
2792 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2793 else
2794 cur = xmlNewDocNode(parent->doc, ns, name, content);
2795 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2796 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2797 if (ns == NULL)
2798 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2799 else
2800 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002801 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2802 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002803 } else {
2804 return(NULL);
2805 }
Owen Taylor3473f882001-02-23 17:55:21 +00002806 if (cur == NULL) return(NULL);
2807
2808 /*
2809 * add the new element at the end of the children list.
2810 */
2811 cur->type = XML_ELEMENT_NODE;
2812 cur->parent = parent;
2813 cur->doc = parent->doc;
2814 if (parent->children == NULL) {
2815 parent->children = cur;
2816 parent->last = cur;
2817 } else {
2818 prev = parent->last;
2819 prev->next = cur;
2820 cur->prev = prev;
2821 parent->last = cur;
2822 }
2823
2824 return(cur);
2825}
Daniel Veillard652327a2003-09-29 18:02:38 +00002826#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002827
2828/**
2829 * xmlAddNextSibling:
2830 * @cur: the child node
2831 * @elem: the new node
2832 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002833 * Add a new node @elem as the next sibling of @cur
2834 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002835 * first unlinked from its existing context.
2836 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002837 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2838 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002839 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002840 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002841 */
2842xmlNodePtr
2843xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2844 if (cur == NULL) {
2845#ifdef DEBUG_TREE
2846 xmlGenericError(xmlGenericErrorContext,
2847 "xmlAddNextSibling : cur == NULL\n");
2848#endif
2849 return(NULL);
2850 }
2851 if (elem == NULL) {
2852#ifdef DEBUG_TREE
2853 xmlGenericError(xmlGenericErrorContext,
2854 "xmlAddNextSibling : elem == NULL\n");
2855#endif
2856 return(NULL);
2857 }
2858
2859 xmlUnlinkNode(elem);
2860
2861 if (elem->type == XML_TEXT_NODE) {
2862 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002863 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002864 xmlFreeNode(elem);
2865 return(cur);
2866 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002867 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2868 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002869 xmlChar *tmp;
2870
2871 tmp = xmlStrdup(elem->content);
2872 tmp = xmlStrcat(tmp, cur->next->content);
2873 xmlNodeSetContent(cur->next, tmp);
2874 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002875 xmlFreeNode(elem);
2876 return(cur->next);
2877 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002878 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2879 /* check if an attribute with the same name exists */
2880 xmlAttrPtr attr;
2881
2882 if (elem->ns == NULL)
2883 attr = xmlHasProp(cur->parent, elem->name);
2884 else
2885 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2886 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2887 /* different instance, destroy it (attributes must be unique) */
2888 xmlFreeProp(attr);
2889 }
Owen Taylor3473f882001-02-23 17:55:21 +00002890 }
2891
2892 if (elem->doc != cur->doc) {
2893 xmlSetTreeDoc(elem, cur->doc);
2894 }
2895 elem->parent = cur->parent;
2896 elem->prev = cur;
2897 elem->next = cur->next;
2898 cur->next = elem;
2899 if (elem->next != NULL)
2900 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002901 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002902 elem->parent->last = elem;
2903 return(elem);
2904}
2905
Daniel Veillard2156d432004-03-04 15:59:36 +00002906#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002907/**
2908 * xmlAddPrevSibling:
2909 * @cur: the child node
2910 * @elem: the new node
2911 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002912 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002913 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002914 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002915 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002916 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2917 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002918 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002919 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002920 */
2921xmlNodePtr
2922xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2923 if (cur == NULL) {
2924#ifdef DEBUG_TREE
2925 xmlGenericError(xmlGenericErrorContext,
2926 "xmlAddPrevSibling : cur == NULL\n");
2927#endif
2928 return(NULL);
2929 }
2930 if (elem == NULL) {
2931#ifdef DEBUG_TREE
2932 xmlGenericError(xmlGenericErrorContext,
2933 "xmlAddPrevSibling : elem == NULL\n");
2934#endif
2935 return(NULL);
2936 }
2937
2938 xmlUnlinkNode(elem);
2939
2940 if (elem->type == XML_TEXT_NODE) {
2941 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002942 xmlChar *tmp;
2943
2944 tmp = xmlStrdup(elem->content);
2945 tmp = xmlStrcat(tmp, cur->content);
2946 xmlNodeSetContent(cur, tmp);
2947 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002948 xmlFreeNode(elem);
2949 return(cur);
2950 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002951 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2952 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002953 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002954 xmlFreeNode(elem);
2955 return(cur->prev);
2956 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002957 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2958 /* check if an attribute with the same name exists */
2959 xmlAttrPtr attr;
2960
2961 if (elem->ns == NULL)
2962 attr = xmlHasProp(cur->parent, elem->name);
2963 else
2964 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2965 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2966 /* different instance, destroy it (attributes must be unique) */
2967 xmlFreeProp(attr);
2968 }
Owen Taylor3473f882001-02-23 17:55:21 +00002969 }
2970
2971 if (elem->doc != cur->doc) {
2972 xmlSetTreeDoc(elem, cur->doc);
2973 }
2974 elem->parent = cur->parent;
2975 elem->next = cur;
2976 elem->prev = cur->prev;
2977 cur->prev = elem;
2978 if (elem->prev != NULL)
2979 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002980 if (elem->parent != NULL) {
2981 if (elem->type == XML_ATTRIBUTE_NODE) {
2982 if (elem->parent->properties == (xmlAttrPtr) cur) {
2983 elem->parent->properties = (xmlAttrPtr) elem;
2984 }
2985 } else {
2986 if (elem->parent->children == cur) {
2987 elem->parent->children = elem;
2988 }
2989 }
2990 }
Owen Taylor3473f882001-02-23 17:55:21 +00002991 return(elem);
2992}
Daniel Veillard652327a2003-09-29 18:02:38 +00002993#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002994
2995/**
2996 * xmlAddSibling:
2997 * @cur: the child node
2998 * @elem: the new node
2999 *
3000 * Add a new element @elem to the list of siblings of @cur
3001 * merging adjacent TEXT nodes (@elem may be freed)
3002 * If the new element was already inserted in a document it is
3003 * first unlinked from its existing context.
3004 *
3005 * Returns the new element or NULL in case of error.
3006 */
3007xmlNodePtr
3008xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
3009 xmlNodePtr parent;
3010
3011 if (cur == NULL) {
3012#ifdef DEBUG_TREE
3013 xmlGenericError(xmlGenericErrorContext,
3014 "xmlAddSibling : cur == NULL\n");
3015#endif
3016 return(NULL);
3017 }
3018
3019 if (elem == NULL) {
3020#ifdef DEBUG_TREE
3021 xmlGenericError(xmlGenericErrorContext,
3022 "xmlAddSibling : elem == NULL\n");
3023#endif
3024 return(NULL);
3025 }
3026
3027 /*
3028 * Constant time is we can rely on the ->parent->last to find
3029 * the last sibling.
3030 */
3031 if ((cur->parent != NULL) &&
3032 (cur->parent->children != NULL) &&
3033 (cur->parent->last != NULL) &&
3034 (cur->parent->last->next == NULL)) {
3035 cur = cur->parent->last;
3036 } else {
3037 while (cur->next != NULL) cur = cur->next;
3038 }
3039
3040 xmlUnlinkNode(elem);
3041
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003042 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3043 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003044 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003045 xmlFreeNode(elem);
3046 return(cur);
3047 }
3048
3049 if (elem->doc != cur->doc) {
3050 xmlSetTreeDoc(elem, cur->doc);
3051 }
3052 parent = cur->parent;
3053 elem->prev = cur;
3054 elem->next = NULL;
3055 elem->parent = parent;
3056 cur->next = elem;
3057 if (parent != NULL)
3058 parent->last = elem;
3059
3060 return(elem);
3061}
3062
3063/**
3064 * xmlAddChildList:
3065 * @parent: the parent node
3066 * @cur: the first node in the list
3067 *
3068 * Add a list of node at the end of the child list of the parent
3069 * merging adjacent TEXT nodes (@cur may be freed)
3070 *
3071 * Returns the last child or NULL in case of error.
3072 */
3073xmlNodePtr
3074xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3075 xmlNodePtr prev;
3076
3077 if (parent == NULL) {
3078#ifdef DEBUG_TREE
3079 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003080 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003081#endif
3082 return(NULL);
3083 }
3084
3085 if (cur == NULL) {
3086#ifdef DEBUG_TREE
3087 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003088 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003089#endif
3090 return(NULL);
3091 }
3092
3093 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3094 (cur->doc != parent->doc)) {
3095#ifdef DEBUG_TREE
3096 xmlGenericError(xmlGenericErrorContext,
3097 "Elements moved to a different document\n");
3098#endif
3099 }
3100
3101 /*
3102 * add the first element at the end of the children list.
3103 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003104
Owen Taylor3473f882001-02-23 17:55:21 +00003105 if (parent->children == NULL) {
3106 parent->children = cur;
3107 } else {
3108 /*
3109 * If cur and parent->last both are TEXT nodes, then merge them.
3110 */
3111 if ((cur->type == XML_TEXT_NODE) &&
3112 (parent->last->type == XML_TEXT_NODE) &&
3113 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003114 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003115 /*
3116 * if it's the only child, nothing more to be done.
3117 */
3118 if (cur->next == NULL) {
3119 xmlFreeNode(cur);
3120 return(parent->last);
3121 }
3122 prev = cur;
3123 cur = cur->next;
3124 xmlFreeNode(prev);
3125 }
3126 prev = parent->last;
3127 prev->next = cur;
3128 cur->prev = prev;
3129 }
3130 while (cur->next != NULL) {
3131 cur->parent = parent;
3132 if (cur->doc != parent->doc) {
3133 xmlSetTreeDoc(cur, parent->doc);
3134 }
3135 cur = cur->next;
3136 }
3137 cur->parent = parent;
3138 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3139 parent->last = cur;
3140
3141 return(cur);
3142}
3143
3144/**
3145 * xmlAddChild:
3146 * @parent: the parent node
3147 * @cur: the child node
3148 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003149 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003150 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003151 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3152 * If there is an attribute with equal name, it is first destroyed.
3153 *
Owen Taylor3473f882001-02-23 17:55:21 +00003154 * Returns the child or NULL in case of error.
3155 */
3156xmlNodePtr
3157xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3158 xmlNodePtr prev;
3159
3160 if (parent == NULL) {
3161#ifdef DEBUG_TREE
3162 xmlGenericError(xmlGenericErrorContext,
3163 "xmlAddChild : parent == NULL\n");
3164#endif
3165 return(NULL);
3166 }
3167
3168 if (cur == NULL) {
3169#ifdef DEBUG_TREE
3170 xmlGenericError(xmlGenericErrorContext,
3171 "xmlAddChild : child == NULL\n");
3172#endif
3173 return(NULL);
3174 }
3175
Owen Taylor3473f882001-02-23 17:55:21 +00003176 /*
3177 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003178 * cur is then freed.
3179 */
3180 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003181 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003182 (parent->content != NULL) &&
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003183 (parent->name == cur->name) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003184 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003185 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003186 xmlFreeNode(cur);
3187 return(parent);
3188 }
3189 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003190 (parent->last->name == cur->name) &&
3191 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003192 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003193 xmlFreeNode(cur);
3194 return(parent->last);
3195 }
3196 }
3197
3198 /*
3199 * add the new element at the end of the children list.
3200 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003201 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003202 cur->parent = parent;
3203 if (cur->doc != parent->doc) {
3204 xmlSetTreeDoc(cur, parent->doc);
3205 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003206 /* this check prevents a loop on tree-traversions if a developer
3207 * tries to add a node to its parent multiple times
3208 */
3209 if (prev == parent)
3210 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003211
3212 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003213 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003214 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003215 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003216 (parent->content != NULL) &&
3217 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003218 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003219 xmlFreeNode(cur);
3220 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003221 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003222 if (cur->type == XML_ATTRIBUTE_NODE) {
3223 if (parent->properties == NULL) {
3224 parent->properties = (xmlAttrPtr) cur;
3225 } else {
3226 /* check if an attribute with the same name exists */
3227 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003228
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003229 if (cur->ns == NULL)
3230 lastattr = xmlHasProp(parent, cur->name);
3231 else
3232 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3233 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3234 /* different instance, destroy it (attributes must be unique) */
3235 xmlFreeProp(lastattr);
3236 }
3237 /* find the end */
3238 lastattr = parent->properties;
3239 while (lastattr->next != NULL) {
3240 lastattr = lastattr->next;
3241 }
3242 lastattr->next = (xmlAttrPtr) cur;
3243 ((xmlAttrPtr) cur)->prev = lastattr;
3244 }
3245 } else {
3246 if (parent->children == NULL) {
3247 parent->children = cur;
3248 parent->last = cur;
3249 } else {
3250 prev = parent->last;
3251 prev->next = cur;
3252 cur->prev = prev;
3253 parent->last = cur;
3254 }
3255 }
Owen Taylor3473f882001-02-23 17:55:21 +00003256 return(cur);
3257}
3258
3259/**
3260 * xmlGetLastChild:
3261 * @parent: the parent node
3262 *
3263 * Search the last child of a node.
3264 * Returns the last child or NULL if none.
3265 */
3266xmlNodePtr
3267xmlGetLastChild(xmlNodePtr parent) {
3268 if (parent == NULL) {
3269#ifdef DEBUG_TREE
3270 xmlGenericError(xmlGenericErrorContext,
3271 "xmlGetLastChild : parent == NULL\n");
3272#endif
3273 return(NULL);
3274 }
3275 return(parent->last);
3276}
3277
3278/**
3279 * xmlFreeNodeList:
3280 * @cur: the first node in the list
3281 *
3282 * Free a node and all its siblings, this is a recursive behaviour, all
3283 * the children are freed too.
3284 */
3285void
3286xmlFreeNodeList(xmlNodePtr cur) {
3287 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003288 xmlDictPtr dict = NULL;
3289
3290 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003291 if (cur->type == XML_NAMESPACE_DECL) {
3292 xmlFreeNsList((xmlNsPtr) cur);
3293 return;
3294 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003295 if ((cur->type == XML_DOCUMENT_NODE) ||
3296#ifdef LIBXML_DOCB_ENABLED
3297 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003298#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003299 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003300 xmlFreeDoc((xmlDocPtr) cur);
3301 return;
3302 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003303 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003304 while (cur != NULL) {
3305 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003306 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003307
Daniel Veillarda880b122003-04-21 21:36:41 +00003308 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003309 xmlDeregisterNodeDefaultValue(cur);
3310
Daniel Veillard02141ea2001-04-30 11:46:40 +00003311 if ((cur->children != NULL) &&
3312 (cur->type != XML_ENTITY_REF_NODE))
3313 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003314 if (((cur->type == XML_ELEMENT_NODE) ||
3315 (cur->type == XML_XINCLUDE_START) ||
3316 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003317 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003318 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003319 if ((cur->type != XML_ELEMENT_NODE) &&
3320 (cur->type != XML_XINCLUDE_START) &&
3321 (cur->type != XML_XINCLUDE_END) &&
3322 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003323 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003324 }
3325 if (((cur->type == XML_ELEMENT_NODE) ||
3326 (cur->type == XML_XINCLUDE_START) ||
3327 (cur->type == XML_XINCLUDE_END)) &&
3328 (cur->nsDef != NULL))
3329 xmlFreeNsList(cur->nsDef);
3330
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003331 /*
3332 * When a node is a text node or a comment, it uses a global static
3333 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003334 * Otherwise the node name might come from the document's
3335 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003336 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003337 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003338 (cur->type != XML_TEXT_NODE) &&
3339 (cur->type != XML_COMMENT_NODE))
3340 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003341 xmlFree(cur);
3342 }
Owen Taylor3473f882001-02-23 17:55:21 +00003343 cur = next;
3344 }
3345}
3346
3347/**
3348 * xmlFreeNode:
3349 * @cur: the node
3350 *
3351 * Free a node, this is a recursive behaviour, all the children are freed too.
3352 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3353 */
3354void
3355xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003356 xmlDictPtr dict = NULL;
3357
3358 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003359
Daniel Veillard02141ea2001-04-30 11:46:40 +00003360 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003361 if (cur->type == XML_DTD_NODE) {
3362 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003363 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003364 }
3365 if (cur->type == XML_NAMESPACE_DECL) {
3366 xmlFreeNs((xmlNsPtr) cur);
3367 return;
3368 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003369 if (cur->type == XML_ATTRIBUTE_NODE) {
3370 xmlFreeProp((xmlAttrPtr) cur);
3371 return;
3372 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003373
Daniel Veillarda880b122003-04-21 21:36:41 +00003374 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003375 xmlDeregisterNodeDefaultValue(cur);
3376
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003377 if (cur->doc != NULL) dict = cur->doc->dict;
3378
Owen Taylor3473f882001-02-23 17:55:21 +00003379 if ((cur->children != NULL) &&
3380 (cur->type != XML_ENTITY_REF_NODE))
3381 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003382 if (((cur->type == XML_ELEMENT_NODE) ||
3383 (cur->type == XML_XINCLUDE_START) ||
3384 (cur->type == XML_XINCLUDE_END)) &&
3385 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003386 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003387 if ((cur->type != XML_ELEMENT_NODE) &&
3388 (cur->content != NULL) &&
3389 (cur->type != XML_ENTITY_REF_NODE) &&
3390 (cur->type != XML_XINCLUDE_END) &&
3391 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003392 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003393 }
3394
Daniel Veillardacd370f2001-06-09 17:17:51 +00003395 /*
3396 * When a node is a text node or a comment, it uses a global static
3397 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003398 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003399 */
Owen Taylor3473f882001-02-23 17:55:21 +00003400 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003401 (cur->type != XML_TEXT_NODE) &&
3402 (cur->type != XML_COMMENT_NODE))
3403 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003404
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003405 if (((cur->type == XML_ELEMENT_NODE) ||
3406 (cur->type == XML_XINCLUDE_START) ||
3407 (cur->type == XML_XINCLUDE_END)) &&
3408 (cur->nsDef != NULL))
3409 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003410 xmlFree(cur);
3411}
3412
3413/**
3414 * xmlUnlinkNode:
3415 * @cur: the node
3416 *
3417 * Unlink a node from it's current context, the node is not freed
3418 */
3419void
3420xmlUnlinkNode(xmlNodePtr cur) {
3421 if (cur == NULL) {
3422#ifdef DEBUG_TREE
3423 xmlGenericError(xmlGenericErrorContext,
3424 "xmlUnlinkNode : node == NULL\n");
3425#endif
3426 return;
3427 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003428 if (cur->type == XML_DTD_NODE) {
3429 xmlDocPtr doc;
3430 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003431 if (doc != NULL) {
3432 if (doc->intSubset == (xmlDtdPtr) cur)
3433 doc->intSubset = NULL;
3434 if (doc->extSubset == (xmlDtdPtr) cur)
3435 doc->extSubset = NULL;
3436 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003437 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003438 if (cur->parent != NULL) {
3439 xmlNodePtr parent;
3440 parent = cur->parent;
3441 if (cur->type == XML_ATTRIBUTE_NODE) {
3442 if (parent->properties == (xmlAttrPtr) cur)
3443 parent->properties = ((xmlAttrPtr) cur)->next;
3444 } else {
3445 if (parent->children == cur)
3446 parent->children = cur->next;
3447 if (parent->last == cur)
3448 parent->last = cur->prev;
3449 }
3450 cur->parent = NULL;
3451 }
Owen Taylor3473f882001-02-23 17:55:21 +00003452 if (cur->next != NULL)
3453 cur->next->prev = cur->prev;
3454 if (cur->prev != NULL)
3455 cur->prev->next = cur->next;
3456 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003457}
3458
Daniel Veillard2156d432004-03-04 15:59:36 +00003459#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003460/**
3461 * xmlReplaceNode:
3462 * @old: the old node
3463 * @cur: the node
3464 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003465 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003466 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003467 * first unlinked from its existing context.
3468 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003469 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003470 */
3471xmlNodePtr
3472xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3473 if (old == NULL) {
3474#ifdef DEBUG_TREE
3475 xmlGenericError(xmlGenericErrorContext,
3476 "xmlReplaceNode : old == NULL\n");
3477#endif
3478 return(NULL);
3479 }
3480 if (cur == NULL) {
3481 xmlUnlinkNode(old);
3482 return(old);
3483 }
3484 if (cur == old) {
3485 return(old);
3486 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003487 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3488#ifdef DEBUG_TREE
3489 xmlGenericError(xmlGenericErrorContext,
3490 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3491#endif
3492 return(old);
3493 }
3494 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3495#ifdef DEBUG_TREE
3496 xmlGenericError(xmlGenericErrorContext,
3497 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3498#endif
3499 return(old);
3500 }
Owen Taylor3473f882001-02-23 17:55:21 +00003501 xmlUnlinkNode(cur);
3502 cur->doc = old->doc;
3503 cur->parent = old->parent;
3504 cur->next = old->next;
3505 if (cur->next != NULL)
3506 cur->next->prev = cur;
3507 cur->prev = old->prev;
3508 if (cur->prev != NULL)
3509 cur->prev->next = cur;
3510 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003511 if (cur->type == XML_ATTRIBUTE_NODE) {
3512 if (cur->parent->properties == (xmlAttrPtr)old)
3513 cur->parent->properties = ((xmlAttrPtr) cur);
3514 } else {
3515 if (cur->parent->children == old)
3516 cur->parent->children = cur;
3517 if (cur->parent->last == old)
3518 cur->parent->last = cur;
3519 }
Owen Taylor3473f882001-02-23 17:55:21 +00003520 }
3521 old->next = old->prev = NULL;
3522 old->parent = NULL;
3523 return(old);
3524}
Daniel Veillard652327a2003-09-29 18:02:38 +00003525#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003526
3527/************************************************************************
3528 * *
3529 * Copy operations *
3530 * *
3531 ************************************************************************/
3532
3533/**
3534 * xmlCopyNamespace:
3535 * @cur: the namespace
3536 *
3537 * Do a copy of the namespace.
3538 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003539 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003540 */
3541xmlNsPtr
3542xmlCopyNamespace(xmlNsPtr cur) {
3543 xmlNsPtr ret;
3544
3545 if (cur == NULL) return(NULL);
3546 switch (cur->type) {
3547 case XML_LOCAL_NAMESPACE:
3548 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3549 break;
3550 default:
3551#ifdef DEBUG_TREE
3552 xmlGenericError(xmlGenericErrorContext,
3553 "xmlCopyNamespace: invalid type %d\n", cur->type);
3554#endif
3555 return(NULL);
3556 }
3557 return(ret);
3558}
3559
3560/**
3561 * xmlCopyNamespaceList:
3562 * @cur: the first namespace
3563 *
3564 * Do a copy of an namespace list.
3565 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003566 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003567 */
3568xmlNsPtr
3569xmlCopyNamespaceList(xmlNsPtr cur) {
3570 xmlNsPtr ret = NULL;
3571 xmlNsPtr p = NULL,q;
3572
3573 while (cur != NULL) {
3574 q = xmlCopyNamespace(cur);
3575 if (p == NULL) {
3576 ret = p = q;
3577 } else {
3578 p->next = q;
3579 p = q;
3580 }
3581 cur = cur->next;
3582 }
3583 return(ret);
3584}
3585
3586static xmlNodePtr
3587xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3588/**
3589 * xmlCopyProp:
3590 * @target: the element where the attribute will be grafted
3591 * @cur: the attribute
3592 *
3593 * Do a copy of the attribute.
3594 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003595 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003596 */
3597xmlAttrPtr
3598xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3599 xmlAttrPtr ret;
3600
3601 if (cur == NULL) return(NULL);
3602 if (target != NULL)
3603 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3604 else if (cur->parent != NULL)
3605 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3606 else if (cur->children != NULL)
3607 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3608 else
3609 ret = xmlNewDocProp(NULL, cur->name, NULL);
3610 if (ret == NULL) return(NULL);
3611 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003612
Owen Taylor3473f882001-02-23 17:55:21 +00003613 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003614 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003615
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003616 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3617 if (ns == NULL) {
3618 /*
3619 * Humm, we are copying an element whose namespace is defined
3620 * out of the new tree scope. Search it in the original tree
3621 * and add it at the top of the new tree
3622 */
3623 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3624 if (ns != NULL) {
3625 xmlNodePtr root = target;
3626 xmlNodePtr pred = NULL;
3627
3628 while (root->parent != NULL) {
3629 pred = root;
3630 root = root->parent;
3631 }
3632 if (root == (xmlNodePtr) target->doc) {
3633 /* correct possibly cycling above the document elt */
3634 root = pred;
3635 }
3636 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3637 }
3638 } else {
3639 /*
3640 * we have to find something appropriate here since
3641 * we cant be sure, that the namespce we found is identified
3642 * by the prefix
3643 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003644 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003645 /* this is the nice case */
3646 ret->ns = ns;
3647 } else {
3648 /*
3649 * we are in trouble: we need a new reconcilied namespace.
3650 * This is expensive
3651 */
3652 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3653 }
3654 }
3655
Owen Taylor3473f882001-02-23 17:55:21 +00003656 } else
3657 ret->ns = NULL;
3658
3659 if (cur->children != NULL) {
3660 xmlNodePtr tmp;
3661
3662 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3663 ret->last = NULL;
3664 tmp = ret->children;
3665 while (tmp != NULL) {
3666 /* tmp->parent = (xmlNodePtr)ret; */
3667 if (tmp->next == NULL)
3668 ret->last = tmp;
3669 tmp = tmp->next;
3670 }
3671 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003672 /*
3673 * Try to handle IDs
3674 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003675 if ((target!= NULL) && (cur!= NULL) &&
3676 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003677 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3678 if (xmlIsID(cur->doc, cur->parent, cur)) {
3679 xmlChar *id;
3680
3681 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3682 if (id != NULL) {
3683 xmlAddID(NULL, target->doc, id, ret);
3684 xmlFree(id);
3685 }
3686 }
3687 }
Owen Taylor3473f882001-02-23 17:55:21 +00003688 return(ret);
3689}
3690
3691/**
3692 * xmlCopyPropList:
3693 * @target: the element where the attributes will be grafted
3694 * @cur: the first attribute
3695 *
3696 * Do a copy of an attribute list.
3697 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003698 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003699 */
3700xmlAttrPtr
3701xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3702 xmlAttrPtr ret = NULL;
3703 xmlAttrPtr p = NULL,q;
3704
3705 while (cur != NULL) {
3706 q = xmlCopyProp(target, cur);
3707 if (p == NULL) {
3708 ret = p = q;
3709 } else {
3710 p->next = q;
3711 q->prev = p;
3712 p = q;
3713 }
3714 cur = cur->next;
3715 }
3716 return(ret);
3717}
3718
3719/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003720 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003721 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003722 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003723 * tricky reason: namespaces. Doing a direct copy of a node
3724 * say RPM:Copyright without changing the namespace pointer to
3725 * something else can produce stale links. One way to do it is
3726 * to keep a reference counter but this doesn't work as soon
3727 * as one move the element or the subtree out of the scope of
3728 * the existing namespace. The actual solution seems to add
3729 * a copy of the namespace at the top of the copied tree if
3730 * not available in the subtree.
3731 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00003732 * The argument "recursive" normally indicates a recursive copy
3733 * of the node with values 0 (no) and 1 (yes). For XInclude,
3734 * however, we allow a value of 2 to indicate copy properties and
3735 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00003736 */
3737
3738static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003739xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00003740 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003741 xmlNodePtr ret;
3742
3743 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003744 switch (node->type) {
3745 case XML_TEXT_NODE:
3746 case XML_CDATA_SECTION_NODE:
3747 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003748 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003749 case XML_ENTITY_REF_NODE:
3750 case XML_ENTITY_NODE:
3751 case XML_PI_NODE:
3752 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003753 case XML_XINCLUDE_START:
3754 case XML_XINCLUDE_END:
3755 break;
3756 case XML_ATTRIBUTE_NODE:
3757 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3758 case XML_NAMESPACE_DECL:
3759 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3760
Daniel Veillard39196eb2001-06-19 18:09:42 +00003761 case XML_DOCUMENT_NODE:
3762 case XML_HTML_DOCUMENT_NODE:
3763#ifdef LIBXML_DOCB_ENABLED
3764 case XML_DOCB_DOCUMENT_NODE:
3765#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003766#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00003767 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00003768#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003769 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003770 case XML_NOTATION_NODE:
3771 case XML_DTD_NODE:
3772 case XML_ELEMENT_DECL:
3773 case XML_ATTRIBUTE_DECL:
3774 case XML_ENTITY_DECL:
3775 return(NULL);
3776 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003777
Owen Taylor3473f882001-02-23 17:55:21 +00003778 /*
3779 * Allocate a new node and fill the fields.
3780 */
3781 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3782 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003783 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003784 return(NULL);
3785 }
3786 memset(ret, 0, sizeof(xmlNode));
3787 ret->type = node->type;
3788
3789 ret->doc = doc;
3790 ret->parent = parent;
3791 if (node->name == xmlStringText)
3792 ret->name = xmlStringText;
3793 else if (node->name == xmlStringTextNoenc)
3794 ret->name = xmlStringTextNoenc;
3795 else if (node->name == xmlStringComment)
3796 ret->name = xmlStringComment;
3797 else if (node->name != NULL)
3798 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003799 if ((node->type != XML_ELEMENT_NODE) &&
3800 (node->content != NULL) &&
3801 (node->type != XML_ENTITY_REF_NODE) &&
3802 (node->type != XML_XINCLUDE_END) &&
3803 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003804 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003805 }else{
3806 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003807 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003808 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003809 if (parent != NULL) {
3810 xmlNodePtr tmp;
3811
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003812 /*
3813 * this is a tricky part for the node register thing:
3814 * in case ret does get coalesced in xmlAddChild
3815 * the deregister-node callback is called; so we register ret now already
3816 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003817 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003818 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3819
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003820 tmp = xmlAddChild(parent, ret);
3821 /* node could have coalesced */
3822 if (tmp != ret)
3823 return(tmp);
3824 }
Owen Taylor3473f882001-02-23 17:55:21 +00003825
William M. Brack57e9e912004-03-09 16:19:02 +00003826 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003827 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003828 if (node->nsDef != NULL)
3829 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3830
3831 if (node->ns != NULL) {
3832 xmlNsPtr ns;
3833
3834 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3835 if (ns == NULL) {
3836 /*
3837 * Humm, we are copying an element whose namespace is defined
3838 * out of the new tree scope. Search it in the original tree
3839 * and add it at the top of the new tree
3840 */
3841 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3842 if (ns != NULL) {
3843 xmlNodePtr root = ret;
3844
3845 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003846 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003847 }
3848 } else {
3849 /*
3850 * reference the existing namespace definition in our own tree.
3851 */
3852 ret->ns = ns;
3853 }
3854 }
3855 if (node->properties != NULL)
3856 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003857 if (node->type == XML_ENTITY_REF_NODE) {
3858 if ((doc == NULL) || (node->doc != doc)) {
3859 /*
3860 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003861 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003862 * we cannot keep the reference. Try to find it in the
3863 * target document.
3864 */
3865 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3866 } else {
3867 ret->children = node->children;
3868 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003869 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00003870 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003871 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003872 UPDATE_LAST_CHILD_AND_PARENT(ret)
3873 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003874
3875out:
3876 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00003877 if ((parent == NULL) &&
3878 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003879 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003880 return(ret);
3881}
3882
3883static xmlNodePtr
3884xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3885 xmlNodePtr ret = NULL;
3886 xmlNodePtr p = NULL,q;
3887
3888 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003889#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003890 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003891 if (doc == NULL) {
3892 node = node->next;
3893 continue;
3894 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003895 if (doc->intSubset == NULL) {
3896 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3897 q->doc = doc;
3898 q->parent = parent;
3899 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003900 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003901 } else {
3902 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003903 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003904 }
3905 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003906#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003907 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003908 if (ret == NULL) {
3909 q->prev = NULL;
3910 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003911 } else if (p != q) {
3912 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003913 p->next = q;
3914 q->prev = p;
3915 p = q;
3916 }
3917 node = node->next;
3918 }
3919 return(ret);
3920}
3921
3922/**
3923 * xmlCopyNode:
3924 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00003925 * @extended: if 1 do a recursive copy (properties, namespaces and children
3926 * when applicable)
3927 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00003928 *
3929 * Do a copy of the node.
3930 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003931 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003932 */
3933xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003934xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003935 xmlNodePtr ret;
3936
William M. Brack57e9e912004-03-09 16:19:02 +00003937 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00003938 return(ret);
3939}
3940
3941/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003942 * xmlDocCopyNode:
3943 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003944 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00003945 * @extended: if 1 do a recursive copy (properties, namespaces and children
3946 * when applicable)
3947 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00003948 *
3949 * Do a copy of the node to a given document.
3950 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003951 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003952 */
3953xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003954xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003955 xmlNodePtr ret;
3956
William M. Brack57e9e912004-03-09 16:19:02 +00003957 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00003958 return(ret);
3959}
3960
3961/**
Owen Taylor3473f882001-02-23 17:55:21 +00003962 * xmlCopyNodeList:
3963 * @node: the first node in the list.
3964 *
3965 * Do a recursive copy of the node list.
3966 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003967 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003968 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003969xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003970 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3971 return(ret);
3972}
3973
Daniel Veillard2156d432004-03-04 15:59:36 +00003974#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003975/**
Owen Taylor3473f882001-02-23 17:55:21 +00003976 * xmlCopyDtd:
3977 * @dtd: the dtd
3978 *
3979 * Do a copy of the dtd.
3980 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003981 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003982 */
3983xmlDtdPtr
3984xmlCopyDtd(xmlDtdPtr dtd) {
3985 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003986 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003987
3988 if (dtd == NULL) return(NULL);
3989 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3990 if (ret == NULL) return(NULL);
3991 if (dtd->entities != NULL)
3992 ret->entities = (void *) xmlCopyEntitiesTable(
3993 (xmlEntitiesTablePtr) dtd->entities);
3994 if (dtd->notations != NULL)
3995 ret->notations = (void *) xmlCopyNotationTable(
3996 (xmlNotationTablePtr) dtd->notations);
3997 if (dtd->elements != NULL)
3998 ret->elements = (void *) xmlCopyElementTable(
3999 (xmlElementTablePtr) dtd->elements);
4000 if (dtd->attributes != NULL)
4001 ret->attributes = (void *) xmlCopyAttributeTable(
4002 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004003 if (dtd->pentities != NULL)
4004 ret->pentities = (void *) xmlCopyEntitiesTable(
4005 (xmlEntitiesTablePtr) dtd->pentities);
4006
4007 cur = dtd->children;
4008 while (cur != NULL) {
4009 q = NULL;
4010
4011 if (cur->type == XML_ENTITY_DECL) {
4012 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4013 switch (tmp->etype) {
4014 case XML_INTERNAL_GENERAL_ENTITY:
4015 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4016 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4017 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4018 break;
4019 case XML_INTERNAL_PARAMETER_ENTITY:
4020 case XML_EXTERNAL_PARAMETER_ENTITY:
4021 q = (xmlNodePtr)
4022 xmlGetParameterEntityFromDtd(ret, tmp->name);
4023 break;
4024 case XML_INTERNAL_PREDEFINED_ENTITY:
4025 break;
4026 }
4027 } else if (cur->type == XML_ELEMENT_DECL) {
4028 xmlElementPtr tmp = (xmlElementPtr) cur;
4029 q = (xmlNodePtr)
4030 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4031 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4032 xmlAttributePtr tmp = (xmlAttributePtr) cur;
4033 q = (xmlNodePtr)
4034 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4035 } else if (cur->type == XML_COMMENT_NODE) {
4036 q = xmlCopyNode(cur, 0);
4037 }
4038
4039 if (q == NULL) {
4040 cur = cur->next;
4041 continue;
4042 }
4043
4044 if (p == NULL)
4045 ret->children = q;
4046 else
4047 p->next = q;
4048
4049 q->prev = p;
4050 q->parent = (xmlNodePtr) ret;
4051 q->next = NULL;
4052 ret->last = q;
4053 p = q;
4054 cur = cur->next;
4055 }
4056
Owen Taylor3473f882001-02-23 17:55:21 +00004057 return(ret);
4058}
Daniel Veillard2156d432004-03-04 15:59:36 +00004059#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004060
Daniel Veillard2156d432004-03-04 15:59:36 +00004061#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004062/**
4063 * xmlCopyDoc:
4064 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004065 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004066 *
4067 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004068 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004069 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004070 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004071 */
4072xmlDocPtr
4073xmlCopyDoc(xmlDocPtr doc, int recursive) {
4074 xmlDocPtr ret;
4075
4076 if (doc == NULL) return(NULL);
4077 ret = xmlNewDoc(doc->version);
4078 if (ret == NULL) return(NULL);
4079 if (doc->name != NULL)
4080 ret->name = xmlMemStrdup(doc->name);
4081 if (doc->encoding != NULL)
4082 ret->encoding = xmlStrdup(doc->encoding);
4083 ret->charset = doc->charset;
4084 ret->compression = doc->compression;
4085 ret->standalone = doc->standalone;
4086 if (!recursive) return(ret);
4087
Daniel Veillardb33c2012001-04-25 12:59:04 +00004088 ret->last = NULL;
4089 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004090#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004091 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004092 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004093 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004094 ret->intSubset->parent = ret;
4095 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004096#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004097 if (doc->oldNs != NULL)
4098 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4099 if (doc->children != NULL) {
4100 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004101
4102 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4103 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004104 ret->last = NULL;
4105 tmp = ret->children;
4106 while (tmp != NULL) {
4107 if (tmp->next == NULL)
4108 ret->last = tmp;
4109 tmp = tmp->next;
4110 }
4111 }
4112 return(ret);
4113}
Daniel Veillard652327a2003-09-29 18:02:38 +00004114#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004115
4116/************************************************************************
4117 * *
4118 * Content access functions *
4119 * *
4120 ************************************************************************/
4121
4122/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004123 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004124 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004125 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004126 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004127 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004128 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004129 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004130 */
4131long
4132xmlGetLineNo(xmlNodePtr node)
4133{
4134 long result = -1;
4135
4136 if (!node)
4137 return result;
4138 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004139 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004140 else if ((node->prev != NULL) &&
4141 ((node->prev->type == XML_ELEMENT_NODE) ||
4142 (node->prev->type == XML_TEXT_NODE)))
4143 result = xmlGetLineNo(node->prev);
4144 else if ((node->parent != NULL) &&
4145 ((node->parent->type == XML_ELEMENT_NODE) ||
4146 (node->parent->type == XML_TEXT_NODE)))
4147 result = xmlGetLineNo(node->parent);
4148
4149 return result;
4150}
4151
Daniel Veillard2156d432004-03-04 15:59:36 +00004152#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004153/**
4154 * xmlGetNodePath:
4155 * @node: a node
4156 *
4157 * Build a structure based Path for the given node
4158 *
4159 * Returns the new path or NULL in case of error. The caller must free
4160 * the returned string
4161 */
4162xmlChar *
4163xmlGetNodePath(xmlNodePtr node)
4164{
4165 xmlNodePtr cur, tmp, next;
4166 xmlChar *buffer = NULL, *temp;
4167 size_t buf_len;
4168 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004169 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004170 const char *name;
4171 char nametemp[100];
4172 int occur = 0;
4173
4174 if (node == NULL)
4175 return (NULL);
4176
4177 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004178 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004179 if (buffer == NULL) {
4180 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004181 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004182 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004183 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004184 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004185 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004186 xmlFree(buffer);
4187 return (NULL);
4188 }
4189
4190 buffer[0] = 0;
4191 cur = node;
4192 do {
4193 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004194 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004195 occur = 0;
4196 if ((cur->type == XML_DOCUMENT_NODE) ||
4197 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4198 if (buffer[0] == '/')
4199 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004200 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004201 next = NULL;
4202 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004203 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004204 name = (const char *) cur->name;
4205 if (cur->ns) {
William M. Brack84d83e32003-12-23 03:45:17 +00004206 if (cur->ns->prefix != NULL)
4207 snprintf(nametemp, sizeof(nametemp) - 1,
Daniel Veillard8faa7832001-11-26 15:58:08 +00004208 "%s:%s", cur->ns->prefix, cur->name);
William M. Brack84d83e32003-12-23 03:45:17 +00004209 else
4210 snprintf(nametemp, sizeof(nametemp) - 1,
4211 "%s", cur->name);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004212 nametemp[sizeof(nametemp) - 1] = 0;
4213 name = nametemp;
4214 }
4215 next = cur->parent;
4216
4217 /*
4218 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004219 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004220 */
4221 tmp = cur->prev;
4222 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004223 if ((tmp->type == XML_ELEMENT_NODE) &&
4224 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004225 occur++;
4226 tmp = tmp->prev;
4227 }
4228 if (occur == 0) {
4229 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004230 while (tmp != NULL && occur == 0) {
4231 if ((tmp->type == XML_ELEMENT_NODE) &&
4232 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004233 occur++;
4234 tmp = tmp->next;
4235 }
4236 if (occur != 0)
4237 occur = 1;
4238 } else
4239 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004240 } else if (cur->type == XML_COMMENT_NODE) {
4241 sep = "/";
4242 name = "comment()";
4243 next = cur->parent;
4244
4245 /*
4246 * Thumbler index computation
4247 */
4248 tmp = cur->prev;
4249 while (tmp != NULL) {
4250 if (tmp->type == XML_COMMENT_NODE)
4251 occur++;
4252 tmp = tmp->prev;
4253 }
4254 if (occur == 0) {
4255 tmp = cur->next;
4256 while (tmp != NULL && occur == 0) {
4257 if (tmp->type == XML_COMMENT_NODE)
4258 occur++;
4259 tmp = tmp->next;
4260 }
4261 if (occur != 0)
4262 occur = 1;
4263 } else
4264 occur++;
4265 } else if ((cur->type == XML_TEXT_NODE) ||
4266 (cur->type == XML_CDATA_SECTION_NODE)) {
4267 sep = "/";
4268 name = "text()";
4269 next = cur->parent;
4270
4271 /*
4272 * Thumbler index computation
4273 */
4274 tmp = cur->prev;
4275 while (tmp != NULL) {
4276 if ((cur->type == XML_TEXT_NODE) ||
4277 (cur->type == XML_CDATA_SECTION_NODE))
4278 occur++;
4279 tmp = tmp->prev;
4280 }
4281 if (occur == 0) {
4282 tmp = cur->next;
4283 while (tmp != NULL && occur == 0) {
4284 if ((cur->type == XML_TEXT_NODE) ||
4285 (cur->type == XML_CDATA_SECTION_NODE))
4286 occur++;
4287 tmp = tmp->next;
4288 }
4289 if (occur != 0)
4290 occur = 1;
4291 } else
4292 occur++;
4293 } else if (cur->type == XML_PI_NODE) {
4294 sep = "/";
4295 snprintf(nametemp, sizeof(nametemp) - 1,
4296 "processing-instruction('%s')", cur->name);
4297 nametemp[sizeof(nametemp) - 1] = 0;
4298 name = nametemp;
4299
4300 next = cur->parent;
4301
4302 /*
4303 * Thumbler index computation
4304 */
4305 tmp = cur->prev;
4306 while (tmp != NULL) {
4307 if ((tmp->type == XML_PI_NODE) &&
4308 (xmlStrEqual(cur->name, tmp->name)))
4309 occur++;
4310 tmp = tmp->prev;
4311 }
4312 if (occur == 0) {
4313 tmp = cur->next;
4314 while (tmp != NULL && occur == 0) {
4315 if ((tmp->type == XML_PI_NODE) &&
4316 (xmlStrEqual(cur->name, tmp->name)))
4317 occur++;
4318 tmp = tmp->next;
4319 }
4320 if (occur != 0)
4321 occur = 1;
4322 } else
4323 occur++;
4324
Daniel Veillard8faa7832001-11-26 15:58:08 +00004325 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004326 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004327 name = (const char *) (((xmlAttrPtr) cur)->name);
4328 next = ((xmlAttrPtr) cur)->parent;
4329 } else {
4330 next = cur->parent;
4331 }
4332
4333 /*
4334 * Make sure there is enough room
4335 */
4336 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4337 buf_len =
4338 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4339 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4340 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004341 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004342 xmlFree(buf);
4343 xmlFree(buffer);
4344 return (NULL);
4345 }
4346 buffer = temp;
4347 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4348 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004349 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004350 xmlFree(buf);
4351 xmlFree(buffer);
4352 return (NULL);
4353 }
4354 buf = temp;
4355 }
4356 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004357 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004358 sep, name, (char *) buffer);
4359 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004360 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004361 sep, name, occur, (char *) buffer);
4362 snprintf((char *) buffer, buf_len, "%s", buf);
4363 cur = next;
4364 } while (cur != NULL);
4365 xmlFree(buf);
4366 return (buffer);
4367}
Daniel Veillard652327a2003-09-29 18:02:38 +00004368#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004369
4370/**
Owen Taylor3473f882001-02-23 17:55:21 +00004371 * xmlDocGetRootElement:
4372 * @doc: the document
4373 *
4374 * Get the root element of the document (doc->children is a list
4375 * containing possibly comments, PIs, etc ...).
4376 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004377 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004378 */
4379xmlNodePtr
4380xmlDocGetRootElement(xmlDocPtr doc) {
4381 xmlNodePtr ret;
4382
4383 if (doc == NULL) return(NULL);
4384 ret = doc->children;
4385 while (ret != NULL) {
4386 if (ret->type == XML_ELEMENT_NODE)
4387 return(ret);
4388 ret = ret->next;
4389 }
4390 return(ret);
4391}
4392
Daniel Veillard2156d432004-03-04 15:59:36 +00004393#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004394/**
4395 * xmlDocSetRootElement:
4396 * @doc: the document
4397 * @root: the new document root element
4398 *
4399 * Set the root element of the document (doc->children is a list
4400 * containing possibly comments, PIs, etc ...).
4401 *
4402 * Returns the old root element if any was found
4403 */
4404xmlNodePtr
4405xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4406 xmlNodePtr old = NULL;
4407
4408 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004409 if (root == NULL)
4410 return(NULL);
4411 xmlUnlinkNode(root);
4412 root->doc = doc;
4413 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004414 old = doc->children;
4415 while (old != NULL) {
4416 if (old->type == XML_ELEMENT_NODE)
4417 break;
4418 old = old->next;
4419 }
4420 if (old == NULL) {
4421 if (doc->children == NULL) {
4422 doc->children = root;
4423 doc->last = root;
4424 } else {
4425 xmlAddSibling(doc->children, root);
4426 }
4427 } else {
4428 xmlReplaceNode(old, root);
4429 }
4430 return(old);
4431}
Daniel Veillard2156d432004-03-04 15:59:36 +00004432#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004433
Daniel Veillard2156d432004-03-04 15:59:36 +00004434#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004435/**
4436 * xmlNodeSetLang:
4437 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004438 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004439 *
4440 * Set the language of a node, i.e. the values of the xml:lang
4441 * attribute.
4442 */
4443void
4444xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004445 xmlNsPtr ns;
4446
Owen Taylor3473f882001-02-23 17:55:21 +00004447 if (cur == NULL) return;
4448 switch(cur->type) {
4449 case XML_TEXT_NODE:
4450 case XML_CDATA_SECTION_NODE:
4451 case XML_COMMENT_NODE:
4452 case XML_DOCUMENT_NODE:
4453 case XML_DOCUMENT_TYPE_NODE:
4454 case XML_DOCUMENT_FRAG_NODE:
4455 case XML_NOTATION_NODE:
4456 case XML_HTML_DOCUMENT_NODE:
4457 case XML_DTD_NODE:
4458 case XML_ELEMENT_DECL:
4459 case XML_ATTRIBUTE_DECL:
4460 case XML_ENTITY_DECL:
4461 case XML_PI_NODE:
4462 case XML_ENTITY_REF_NODE:
4463 case XML_ENTITY_NODE:
4464 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004465#ifdef LIBXML_DOCB_ENABLED
4466 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004467#endif
4468 case XML_XINCLUDE_START:
4469 case XML_XINCLUDE_END:
4470 return;
4471 case XML_ELEMENT_NODE:
4472 case XML_ATTRIBUTE_NODE:
4473 break;
4474 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004475 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4476 if (ns == NULL)
4477 return;
4478 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004479}
Daniel Veillard652327a2003-09-29 18:02:38 +00004480#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004481
4482/**
4483 * xmlNodeGetLang:
4484 * @cur: the node being checked
4485 *
4486 * Searches the language of a node, i.e. the values of the xml:lang
4487 * attribute or the one carried by the nearest ancestor.
4488 *
4489 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004490 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004491 */
4492xmlChar *
4493xmlNodeGetLang(xmlNodePtr cur) {
4494 xmlChar *lang;
4495
4496 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004497 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004498 if (lang != NULL)
4499 return(lang);
4500 cur = cur->parent;
4501 }
4502 return(NULL);
4503}
4504
4505
Daniel Veillard652327a2003-09-29 18:02:38 +00004506#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004507/**
4508 * xmlNodeSetSpacePreserve:
4509 * @cur: the node being changed
4510 * @val: the xml:space value ("0": default, 1: "preserve")
4511 *
4512 * Set (or reset) the space preserving behaviour of a node, i.e. the
4513 * value of the xml:space attribute.
4514 */
4515void
4516xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004517 xmlNsPtr ns;
4518
Owen Taylor3473f882001-02-23 17:55:21 +00004519 if (cur == NULL) return;
4520 switch(cur->type) {
4521 case XML_TEXT_NODE:
4522 case XML_CDATA_SECTION_NODE:
4523 case XML_COMMENT_NODE:
4524 case XML_DOCUMENT_NODE:
4525 case XML_DOCUMENT_TYPE_NODE:
4526 case XML_DOCUMENT_FRAG_NODE:
4527 case XML_NOTATION_NODE:
4528 case XML_HTML_DOCUMENT_NODE:
4529 case XML_DTD_NODE:
4530 case XML_ELEMENT_DECL:
4531 case XML_ATTRIBUTE_DECL:
4532 case XML_ENTITY_DECL:
4533 case XML_PI_NODE:
4534 case XML_ENTITY_REF_NODE:
4535 case XML_ENTITY_NODE:
4536 case XML_NAMESPACE_DECL:
4537 case XML_XINCLUDE_START:
4538 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004539#ifdef LIBXML_DOCB_ENABLED
4540 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004541#endif
4542 return;
4543 case XML_ELEMENT_NODE:
4544 case XML_ATTRIBUTE_NODE:
4545 break;
4546 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004547 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4548 if (ns == NULL)
4549 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004550 switch (val) {
4551 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004552 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004553 break;
4554 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004555 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004556 break;
4557 }
4558}
Daniel Veillard652327a2003-09-29 18:02:38 +00004559#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004560
4561/**
4562 * xmlNodeGetSpacePreserve:
4563 * @cur: the node being checked
4564 *
4565 * Searches the space preserving behaviour of a node, i.e. the values
4566 * of the xml:space attribute or the one carried by the nearest
4567 * ancestor.
4568 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004569 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004570 */
4571int
4572xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4573 xmlChar *space;
4574
4575 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004576 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004577 if (space != NULL) {
4578 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4579 xmlFree(space);
4580 return(1);
4581 }
4582 if (xmlStrEqual(space, BAD_CAST "default")) {
4583 xmlFree(space);
4584 return(0);
4585 }
4586 xmlFree(space);
4587 }
4588 cur = cur->parent;
4589 }
4590 return(-1);
4591}
4592
Daniel Veillard652327a2003-09-29 18:02:38 +00004593#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004594/**
4595 * xmlNodeSetName:
4596 * @cur: the node being changed
4597 * @name: the new tag name
4598 *
4599 * Set (or reset) the name of a node.
4600 */
4601void
4602xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4603 if (cur == NULL) return;
4604 if (name == NULL) return;
4605 switch(cur->type) {
4606 case XML_TEXT_NODE:
4607 case XML_CDATA_SECTION_NODE:
4608 case XML_COMMENT_NODE:
4609 case XML_DOCUMENT_TYPE_NODE:
4610 case XML_DOCUMENT_FRAG_NODE:
4611 case XML_NOTATION_NODE:
4612 case XML_HTML_DOCUMENT_NODE:
4613 case XML_NAMESPACE_DECL:
4614 case XML_XINCLUDE_START:
4615 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004616#ifdef LIBXML_DOCB_ENABLED
4617 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004618#endif
4619 return;
4620 case XML_ELEMENT_NODE:
4621 case XML_ATTRIBUTE_NODE:
4622 case XML_PI_NODE:
4623 case XML_ENTITY_REF_NODE:
4624 case XML_ENTITY_NODE:
4625 case XML_DTD_NODE:
4626 case XML_DOCUMENT_NODE:
4627 case XML_ELEMENT_DECL:
4628 case XML_ATTRIBUTE_DECL:
4629 case XML_ENTITY_DECL:
4630 break;
4631 }
4632 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4633 cur->name = xmlStrdup(name);
4634}
Daniel Veillard2156d432004-03-04 15:59:36 +00004635#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004636
Daniel Veillard2156d432004-03-04 15:59:36 +00004637#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004638/**
4639 * xmlNodeSetBase:
4640 * @cur: the node being changed
4641 * @uri: the new base URI
4642 *
4643 * Set (or reset) the base URI of a node, i.e. the value of the
4644 * xml:base attribute.
4645 */
4646void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004647xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004648 xmlNsPtr ns;
4649
Owen Taylor3473f882001-02-23 17:55:21 +00004650 if (cur == NULL) return;
4651 switch(cur->type) {
4652 case XML_TEXT_NODE:
4653 case XML_CDATA_SECTION_NODE:
4654 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004655 case XML_DOCUMENT_TYPE_NODE:
4656 case XML_DOCUMENT_FRAG_NODE:
4657 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004658 case XML_DTD_NODE:
4659 case XML_ELEMENT_DECL:
4660 case XML_ATTRIBUTE_DECL:
4661 case XML_ENTITY_DECL:
4662 case XML_PI_NODE:
4663 case XML_ENTITY_REF_NODE:
4664 case XML_ENTITY_NODE:
4665 case XML_NAMESPACE_DECL:
4666 case XML_XINCLUDE_START:
4667 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004668 return;
4669 case XML_ELEMENT_NODE:
4670 case XML_ATTRIBUTE_NODE:
4671 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004672 case XML_DOCUMENT_NODE:
4673#ifdef LIBXML_DOCB_ENABLED
4674 case XML_DOCB_DOCUMENT_NODE:
4675#endif
4676 case XML_HTML_DOCUMENT_NODE: {
4677 xmlDocPtr doc = (xmlDocPtr) cur;
4678
4679 if (doc->URL != NULL)
4680 xmlFree((xmlChar *) doc->URL);
4681 if (uri == NULL)
4682 doc->URL = NULL;
4683 else
4684 doc->URL = xmlStrdup(uri);
4685 return;
4686 }
Owen Taylor3473f882001-02-23 17:55:21 +00004687 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004688
4689 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4690 if (ns == NULL)
4691 return;
4692 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004693}
Daniel Veillard652327a2003-09-29 18:02:38 +00004694#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004695
4696/**
Owen Taylor3473f882001-02-23 17:55:21 +00004697 * xmlNodeGetBase:
4698 * @doc: the document the node pertains to
4699 * @cur: the node being checked
4700 *
4701 * Searches for the BASE URL. The code should work on both XML
4702 * and HTML document even if base mechanisms are completely different.
4703 * It returns the base as defined in RFC 2396 sections
4704 * 5.1.1. Base URI within Document Content
4705 * and
4706 * 5.1.2. Base URI from the Encapsulating Entity
4707 * However it does not return the document base (5.1.3), use
4708 * xmlDocumentGetBase() for this
4709 *
4710 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004711 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004712 */
4713xmlChar *
4714xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004715 xmlChar *oldbase = NULL;
4716 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004717
4718 if ((cur == NULL) && (doc == NULL))
4719 return(NULL);
4720 if (doc == NULL) doc = cur->doc;
4721 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4722 cur = doc->children;
4723 while ((cur != NULL) && (cur->name != NULL)) {
4724 if (cur->type != XML_ELEMENT_NODE) {
4725 cur = cur->next;
4726 continue;
4727 }
4728 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4729 cur = cur->children;
4730 continue;
4731 }
4732 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4733 cur = cur->children;
4734 continue;
4735 }
4736 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4737 return(xmlGetProp(cur, BAD_CAST "href"));
4738 }
4739 cur = cur->next;
4740 }
4741 return(NULL);
4742 }
4743 while (cur != NULL) {
4744 if (cur->type == XML_ENTITY_DECL) {
4745 xmlEntityPtr ent = (xmlEntityPtr) cur;
4746 return(xmlStrdup(ent->URI));
4747 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004748 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004749 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004750 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004751 if (oldbase != NULL) {
4752 newbase = xmlBuildURI(oldbase, base);
4753 if (newbase != NULL) {
4754 xmlFree(oldbase);
4755 xmlFree(base);
4756 oldbase = newbase;
4757 } else {
4758 xmlFree(oldbase);
4759 xmlFree(base);
4760 return(NULL);
4761 }
4762 } else {
4763 oldbase = base;
4764 }
4765 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4766 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4767 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4768 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004769 }
4770 }
Owen Taylor3473f882001-02-23 17:55:21 +00004771 cur = cur->parent;
4772 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004773 if ((doc != NULL) && (doc->URL != NULL)) {
4774 if (oldbase == NULL)
4775 return(xmlStrdup(doc->URL));
4776 newbase = xmlBuildURI(oldbase, doc->URL);
4777 xmlFree(oldbase);
4778 return(newbase);
4779 }
4780 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004781}
4782
4783/**
Daniel Veillard78697292003-10-19 20:44:43 +00004784 * xmlNodeBufGetContent:
4785 * @buffer: a buffer
4786 * @cur: the node being read
4787 *
4788 * Read the value of a node @cur, this can be either the text carried
4789 * directly by this node if it's a TEXT node or the aggregate string
4790 * of the values carried by this node child's (TEXT and ENTITY_REF).
4791 * Entity references are substituted.
4792 * Fills up the buffer @buffer with this value
4793 *
4794 * Returns 0 in case of success and -1 in case of error.
4795 */
4796int
4797xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4798{
4799 if ((cur == NULL) || (buffer == NULL)) return(-1);
4800 switch (cur->type) {
4801 case XML_CDATA_SECTION_NODE:
4802 case XML_TEXT_NODE:
4803 xmlBufferCat(buffer, cur->content);
4804 break;
4805 case XML_DOCUMENT_FRAG_NODE:
4806 case XML_ELEMENT_NODE:{
4807 xmlNodePtr tmp = cur;
4808
4809 while (tmp != NULL) {
4810 switch (tmp->type) {
4811 case XML_CDATA_SECTION_NODE:
4812 case XML_TEXT_NODE:
4813 if (tmp->content != NULL)
4814 xmlBufferCat(buffer, tmp->content);
4815 break;
4816 case XML_ENTITY_REF_NODE:
4817 xmlNodeBufGetContent(buffer, tmp->children);
4818 break;
4819 default:
4820 break;
4821 }
4822 /*
4823 * Skip to next node
4824 */
4825 if (tmp->children != NULL) {
4826 if (tmp->children->type != XML_ENTITY_DECL) {
4827 tmp = tmp->children;
4828 continue;
4829 }
4830 }
4831 if (tmp == cur)
4832 break;
4833
4834 if (tmp->next != NULL) {
4835 tmp = tmp->next;
4836 continue;
4837 }
4838
4839 do {
4840 tmp = tmp->parent;
4841 if (tmp == NULL)
4842 break;
4843 if (tmp == cur) {
4844 tmp = NULL;
4845 break;
4846 }
4847 if (tmp->next != NULL) {
4848 tmp = tmp->next;
4849 break;
4850 }
4851 } while (tmp != NULL);
4852 }
4853 break;
4854 }
4855 case XML_ATTRIBUTE_NODE:{
4856 xmlAttrPtr attr = (xmlAttrPtr) cur;
4857 xmlNodePtr tmp = attr->children;
4858
4859 while (tmp != NULL) {
4860 if (tmp->type == XML_TEXT_NODE)
4861 xmlBufferCat(buffer, tmp->content);
4862 else
4863 xmlNodeBufGetContent(buffer, tmp);
4864 tmp = tmp->next;
4865 }
4866 break;
4867 }
4868 case XML_COMMENT_NODE:
4869 case XML_PI_NODE:
4870 xmlBufferCat(buffer, cur->content);
4871 break;
4872 case XML_ENTITY_REF_NODE:{
4873 xmlEntityPtr ent;
4874 xmlNodePtr tmp;
4875
4876 /* lookup entity declaration */
4877 ent = xmlGetDocEntity(cur->doc, cur->name);
4878 if (ent == NULL)
4879 return(-1);
4880
4881 /* an entity content can be any "well balanced chunk",
4882 * i.e. the result of the content [43] production:
4883 * http://www.w3.org/TR/REC-xml#NT-content
4884 * -> we iterate through child nodes and recursive call
4885 * xmlNodeGetContent() which handles all possible node types */
4886 tmp = ent->children;
4887 while (tmp) {
4888 xmlNodeBufGetContent(buffer, tmp);
4889 tmp = tmp->next;
4890 }
4891 break;
4892 }
4893 case XML_ENTITY_NODE:
4894 case XML_DOCUMENT_TYPE_NODE:
4895 case XML_NOTATION_NODE:
4896 case XML_DTD_NODE:
4897 case XML_XINCLUDE_START:
4898 case XML_XINCLUDE_END:
4899 break;
4900 case XML_DOCUMENT_NODE:
4901#ifdef LIBXML_DOCB_ENABLED
4902 case XML_DOCB_DOCUMENT_NODE:
4903#endif
4904 case XML_HTML_DOCUMENT_NODE:
4905 cur = cur->children;
4906 while (cur!= NULL) {
4907 if ((cur->type == XML_ELEMENT_NODE) ||
4908 (cur->type == XML_TEXT_NODE) ||
4909 (cur->type == XML_CDATA_SECTION_NODE)) {
4910 xmlNodeBufGetContent(buffer, cur);
4911 }
4912 cur = cur->next;
4913 }
4914 break;
4915 case XML_NAMESPACE_DECL:
4916 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
4917 break;
4918 case XML_ELEMENT_DECL:
4919 case XML_ATTRIBUTE_DECL:
4920 case XML_ENTITY_DECL:
4921 break;
4922 }
4923 return(0);
4924}
4925/**
Owen Taylor3473f882001-02-23 17:55:21 +00004926 * xmlNodeGetContent:
4927 * @cur: the node being read
4928 *
4929 * Read the value of a node, this can be either the text carried
4930 * directly by this node if it's a TEXT node or the aggregate string
4931 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004932 * Entity references are substituted.
4933 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004934 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004935 */
4936xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004937xmlNodeGetContent(xmlNodePtr cur)
4938{
4939 if (cur == NULL)
4940 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004941 switch (cur->type) {
4942 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004943 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00004944 xmlBufferPtr buffer;
4945 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004946
Daniel Veillard814a76d2003-01-23 18:24:20 +00004947 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004948 if (buffer == NULL)
4949 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00004950 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004951 ret = buffer->content;
4952 buffer->content = NULL;
4953 xmlBufferFree(buffer);
4954 return (ret);
4955 }
4956 case XML_ATTRIBUTE_NODE:{
4957 xmlAttrPtr attr = (xmlAttrPtr) cur;
4958
4959 if (attr->parent != NULL)
4960 return (xmlNodeListGetString
4961 (attr->parent->doc, attr->children, 1));
4962 else
4963 return (xmlNodeListGetString(NULL, attr->children, 1));
4964 break;
4965 }
Owen Taylor3473f882001-02-23 17:55:21 +00004966 case XML_COMMENT_NODE:
4967 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004968 if (cur->content != NULL)
4969 return (xmlStrdup(cur->content));
4970 return (NULL);
4971 case XML_ENTITY_REF_NODE:{
4972 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00004973 xmlBufferPtr buffer;
4974 xmlChar *ret;
4975
4976 /* lookup entity declaration */
4977 ent = xmlGetDocEntity(cur->doc, cur->name);
4978 if (ent == NULL)
4979 return (NULL);
4980
4981 buffer = xmlBufferCreate();
4982 if (buffer == NULL)
4983 return (NULL);
4984
Daniel Veillardc4696922003-10-19 21:47:14 +00004985 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004986
4987 ret = buffer->content;
4988 buffer->content = NULL;
4989 xmlBufferFree(buffer);
4990 return (ret);
4991 }
Owen Taylor3473f882001-02-23 17:55:21 +00004992 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004993 case XML_DOCUMENT_TYPE_NODE:
4994 case XML_NOTATION_NODE:
4995 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004996 case XML_XINCLUDE_START:
4997 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00004998 return (NULL);
4999 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005000#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005001 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005002#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005003 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00005004 xmlBufferPtr buffer;
5005 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005006
Daniel Veillardc4696922003-10-19 21:47:14 +00005007 buffer = xmlBufferCreate();
5008 if (buffer == NULL)
5009 return (NULL);
5010
5011 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5012
5013 ret = buffer->content;
5014 buffer->content = NULL;
5015 xmlBufferFree(buffer);
5016 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005017 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005018 case XML_NAMESPACE_DECL: {
5019 xmlChar *tmp;
5020
5021 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5022 return (tmp);
5023 }
Owen Taylor3473f882001-02-23 17:55:21 +00005024 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005025 /* TODO !!! */
5026 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005027 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005028 /* TODO !!! */
5029 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005030 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005031 /* TODO !!! */
5032 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005033 case XML_CDATA_SECTION_NODE:
5034 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005035 if (cur->content != NULL)
5036 return (xmlStrdup(cur->content));
5037 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005038 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005039 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005040}
Daniel Veillard652327a2003-09-29 18:02:38 +00005041
Owen Taylor3473f882001-02-23 17:55:21 +00005042/**
5043 * xmlNodeSetContent:
5044 * @cur: the node being modified
5045 * @content: the new value of the content
5046 *
5047 * Replace the content of a node.
5048 */
5049void
5050xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5051 if (cur == NULL) {
5052#ifdef DEBUG_TREE
5053 xmlGenericError(xmlGenericErrorContext,
5054 "xmlNodeSetContent : node == NULL\n");
5055#endif
5056 return;
5057 }
5058 switch (cur->type) {
5059 case XML_DOCUMENT_FRAG_NODE:
5060 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005061 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005062 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5063 cur->children = xmlStringGetNodeList(cur->doc, content);
5064 UPDATE_LAST_CHILD_AND_PARENT(cur)
5065 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005066 case XML_TEXT_NODE:
5067 case XML_CDATA_SECTION_NODE:
5068 case XML_ENTITY_REF_NODE:
5069 case XML_ENTITY_NODE:
5070 case XML_PI_NODE:
5071 case XML_COMMENT_NODE:
5072 if (cur->content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005073 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5074 xmlDictOwns(cur->doc->dict, cur->content)))
5075 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005076 }
5077 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5078 cur->last = cur->children = NULL;
5079 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005080 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005081 } else
5082 cur->content = NULL;
5083 break;
5084 case XML_DOCUMENT_NODE:
5085 case XML_HTML_DOCUMENT_NODE:
5086 case XML_DOCUMENT_TYPE_NODE:
5087 case XML_XINCLUDE_START:
5088 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005089#ifdef LIBXML_DOCB_ENABLED
5090 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005091#endif
5092 break;
5093 case XML_NOTATION_NODE:
5094 break;
5095 case XML_DTD_NODE:
5096 break;
5097 case XML_NAMESPACE_DECL:
5098 break;
5099 case XML_ELEMENT_DECL:
5100 /* TODO !!! */
5101 break;
5102 case XML_ATTRIBUTE_DECL:
5103 /* TODO !!! */
5104 break;
5105 case XML_ENTITY_DECL:
5106 /* TODO !!! */
5107 break;
5108 }
5109}
5110
Daniel Veillard652327a2003-09-29 18:02:38 +00005111#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005112/**
5113 * xmlNodeSetContentLen:
5114 * @cur: the node being modified
5115 * @content: the new value of the content
5116 * @len: the size of @content
5117 *
5118 * Replace the content of a node.
5119 */
5120void
5121xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5122 if (cur == NULL) {
5123#ifdef DEBUG_TREE
5124 xmlGenericError(xmlGenericErrorContext,
5125 "xmlNodeSetContentLen : node == NULL\n");
5126#endif
5127 return;
5128 }
5129 switch (cur->type) {
5130 case XML_DOCUMENT_FRAG_NODE:
5131 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005132 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005133 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5134 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5135 UPDATE_LAST_CHILD_AND_PARENT(cur)
5136 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005137 case XML_TEXT_NODE:
5138 case XML_CDATA_SECTION_NODE:
5139 case XML_ENTITY_REF_NODE:
5140 case XML_ENTITY_NODE:
5141 case XML_PI_NODE:
5142 case XML_COMMENT_NODE:
5143 case XML_NOTATION_NODE:
5144 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005145 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005146 }
5147 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5148 cur->children = cur->last = NULL;
5149 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005150 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005151 } else
5152 cur->content = NULL;
5153 break;
5154 case XML_DOCUMENT_NODE:
5155 case XML_DTD_NODE:
5156 case XML_HTML_DOCUMENT_NODE:
5157 case XML_DOCUMENT_TYPE_NODE:
5158 case XML_NAMESPACE_DECL:
5159 case XML_XINCLUDE_START:
5160 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005161#ifdef LIBXML_DOCB_ENABLED
5162 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005163#endif
5164 break;
5165 case XML_ELEMENT_DECL:
5166 /* TODO !!! */
5167 break;
5168 case XML_ATTRIBUTE_DECL:
5169 /* TODO !!! */
5170 break;
5171 case XML_ENTITY_DECL:
5172 /* TODO !!! */
5173 break;
5174 }
5175}
Daniel Veillard652327a2003-09-29 18:02:38 +00005176#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005177
5178/**
5179 * xmlNodeAddContentLen:
5180 * @cur: the node being modified
5181 * @content: extra content
5182 * @len: the size of @content
5183 *
5184 * Append the extra substring to the node content.
5185 */
5186void
5187xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5188 if (cur == NULL) {
5189#ifdef DEBUG_TREE
5190 xmlGenericError(xmlGenericErrorContext,
5191 "xmlNodeAddContentLen : node == NULL\n");
5192#endif
5193 return;
5194 }
5195 if (len <= 0) return;
5196 switch (cur->type) {
5197 case XML_DOCUMENT_FRAG_NODE:
5198 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005199 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005200
Daniel Veillard7db37732001-07-12 01:20:08 +00005201 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005202 newNode = xmlNewTextLen(content, len);
5203 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005204 tmp = xmlAddChild(cur, newNode);
5205 if (tmp != newNode)
5206 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005207 if ((last != NULL) && (last->next == newNode)) {
5208 xmlTextMerge(last, newNode);
5209 }
5210 }
5211 break;
5212 }
5213 case XML_ATTRIBUTE_NODE:
5214 break;
5215 case XML_TEXT_NODE:
5216 case XML_CDATA_SECTION_NODE:
5217 case XML_ENTITY_REF_NODE:
5218 case XML_ENTITY_NODE:
5219 case XML_PI_NODE:
5220 case XML_COMMENT_NODE:
5221 case XML_NOTATION_NODE:
5222 if (content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005223 if ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5224 xmlDictOwns(cur->doc->dict, cur->content)) {
5225 cur->content =
5226 xmlStrncatNew(cur->content, content, len);
5227 break;
5228 }
Owen Taylor3473f882001-02-23 17:55:21 +00005229 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005230 }
5231 case XML_DOCUMENT_NODE:
5232 case XML_DTD_NODE:
5233 case XML_HTML_DOCUMENT_NODE:
5234 case XML_DOCUMENT_TYPE_NODE:
5235 case XML_NAMESPACE_DECL:
5236 case XML_XINCLUDE_START:
5237 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005238#ifdef LIBXML_DOCB_ENABLED
5239 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005240#endif
5241 break;
5242 case XML_ELEMENT_DECL:
5243 case XML_ATTRIBUTE_DECL:
5244 case XML_ENTITY_DECL:
5245 break;
5246 }
5247}
5248
5249/**
5250 * xmlNodeAddContent:
5251 * @cur: the node being modified
5252 * @content: extra content
5253 *
5254 * Append the extra substring to the node content.
5255 */
5256void
5257xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5258 int len;
5259
5260 if (cur == NULL) {
5261#ifdef DEBUG_TREE
5262 xmlGenericError(xmlGenericErrorContext,
5263 "xmlNodeAddContent : node == NULL\n");
5264#endif
5265 return;
5266 }
5267 if (content == NULL) return;
5268 len = xmlStrlen(content);
5269 xmlNodeAddContentLen(cur, content, len);
5270}
5271
5272/**
5273 * xmlTextMerge:
5274 * @first: the first text node
5275 * @second: the second text node being merged
5276 *
5277 * Merge two text nodes into one
5278 * Returns the first text node augmented
5279 */
5280xmlNodePtr
5281xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5282 if (first == NULL) return(second);
5283 if (second == NULL) return(first);
5284 if (first->type != XML_TEXT_NODE) return(first);
5285 if (second->type != XML_TEXT_NODE) return(first);
5286 if (second->name != first->name)
5287 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005288 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005289 xmlUnlinkNode(second);
5290 xmlFreeNode(second);
5291 return(first);
5292}
5293
Daniel Veillard2156d432004-03-04 15:59:36 +00005294#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005295/**
5296 * xmlGetNsList:
5297 * @doc: the document
5298 * @node: the current node
5299 *
5300 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005301 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005302 * that need to be freed by the caller or NULL if no
5303 * namespace if defined
5304 */
5305xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005306xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5307{
Owen Taylor3473f882001-02-23 17:55:21 +00005308 xmlNsPtr cur;
5309 xmlNsPtr *ret = NULL;
5310 int nbns = 0;
5311 int maxns = 10;
5312 int i;
5313
5314 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005315 if (node->type == XML_ELEMENT_NODE) {
5316 cur = node->nsDef;
5317 while (cur != NULL) {
5318 if (ret == NULL) {
5319 ret =
5320 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5321 sizeof(xmlNsPtr));
5322 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005323 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005324 return (NULL);
5325 }
5326 ret[nbns] = NULL;
5327 }
5328 for (i = 0; i < nbns; i++) {
5329 if ((cur->prefix == ret[i]->prefix) ||
5330 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5331 break;
5332 }
5333 if (i >= nbns) {
5334 if (nbns >= maxns) {
5335 maxns *= 2;
5336 ret = (xmlNsPtr *) xmlRealloc(ret,
5337 (maxns +
5338 1) *
5339 sizeof(xmlNsPtr));
5340 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005341 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005342 return (NULL);
5343 }
5344 }
5345 ret[nbns++] = cur;
5346 ret[nbns] = NULL;
5347 }
Owen Taylor3473f882001-02-23 17:55:21 +00005348
Daniel Veillard77044732001-06-29 21:31:07 +00005349 cur = cur->next;
5350 }
5351 }
5352 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005353 }
Daniel Veillard77044732001-06-29 21:31:07 +00005354 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005355}
Daniel Veillard652327a2003-09-29 18:02:38 +00005356#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005357
5358/**
5359 * xmlSearchNs:
5360 * @doc: the document
5361 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005362 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005363 *
5364 * Search a Ns registered under a given name space for a document.
5365 * recurse on the parents until it finds the defined namespace
5366 * or return NULL otherwise.
5367 * @nameSpace can be NULL, this is a search for the default namespace.
5368 * We don't allow to cross entities boundaries. If you don't declare
5369 * the namespace within those you will be in troubles !!! A warning
5370 * is generated to cover this case.
5371 *
5372 * Returns the namespace pointer or NULL.
5373 */
5374xmlNsPtr
5375xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005376
Owen Taylor3473f882001-02-23 17:55:21 +00005377 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005378 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005379
5380 if (node == NULL) return(NULL);
5381 if ((nameSpace != NULL) &&
5382 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005383 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5384 /*
5385 * The XML-1.0 namespace is normally held on the root
5386 * element. In this case exceptionally create it on the
5387 * node element.
5388 */
5389 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5390 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005391 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005392 return(NULL);
5393 }
5394 memset(cur, 0, sizeof(xmlNs));
5395 cur->type = XML_LOCAL_NAMESPACE;
5396 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5397 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5398 cur->next = node->nsDef;
5399 node->nsDef = cur;
5400 return(cur);
5401 }
Owen Taylor3473f882001-02-23 17:55:21 +00005402 if (doc->oldNs == NULL) {
5403 /*
5404 * Allocate a new Namespace and fill the fields.
5405 */
5406 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5407 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005408 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005409 return(NULL);
5410 }
5411 memset(doc->oldNs, 0, sizeof(xmlNs));
5412 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5413
5414 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5415 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5416 }
5417 return(doc->oldNs);
5418 }
5419 while (node != NULL) {
5420 if ((node->type == XML_ENTITY_REF_NODE) ||
5421 (node->type == XML_ENTITY_NODE) ||
5422 (node->type == XML_ENTITY_DECL))
5423 return(NULL);
5424 if (node->type == XML_ELEMENT_NODE) {
5425 cur = node->nsDef;
5426 while (cur != NULL) {
5427 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5428 (cur->href != NULL))
5429 return(cur);
5430 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5431 (cur->href != NULL) &&
5432 (xmlStrEqual(cur->prefix, nameSpace)))
5433 return(cur);
5434 cur = cur->next;
5435 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005436 if (orig != node) {
5437 cur = node->ns;
5438 if (cur != NULL) {
5439 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5440 (cur->href != NULL))
5441 return(cur);
5442 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5443 (cur->href != NULL) &&
5444 (xmlStrEqual(cur->prefix, nameSpace)))
5445 return(cur);
5446 }
5447 }
Owen Taylor3473f882001-02-23 17:55:21 +00005448 }
5449 node = node->parent;
5450 }
5451 return(NULL);
5452}
5453
5454/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005455 * xmlNsInScope:
5456 * @doc: the document
5457 * @node: the current node
5458 * @ancestor: the ancestor carrying the namespace
5459 * @prefix: the namespace prefix
5460 *
5461 * Verify that the given namespace held on @ancestor is still in scope
5462 * on node.
5463 *
5464 * Returns 1 if true, 0 if false and -1 in case of error.
5465 */
5466static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005467xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5468 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005469{
5470 xmlNsPtr tst;
5471
5472 while ((node != NULL) && (node != ancestor)) {
5473 if ((node->type == XML_ENTITY_REF_NODE) ||
5474 (node->type == XML_ENTITY_NODE) ||
5475 (node->type == XML_ENTITY_DECL))
5476 return (-1);
5477 if (node->type == XML_ELEMENT_NODE) {
5478 tst = node->nsDef;
5479 while (tst != NULL) {
5480 if ((tst->prefix == NULL)
5481 && (prefix == NULL))
5482 return (0);
5483 if ((tst->prefix != NULL)
5484 && (prefix != NULL)
5485 && (xmlStrEqual(tst->prefix, prefix)))
5486 return (0);
5487 tst = tst->next;
5488 }
5489 }
5490 node = node->parent;
5491 }
5492 if (node != ancestor)
5493 return (-1);
5494 return (1);
5495}
5496
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005497/**
Owen Taylor3473f882001-02-23 17:55:21 +00005498 * xmlSearchNsByHref:
5499 * @doc: the document
5500 * @node: the current node
5501 * @href: the namespace value
5502 *
5503 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5504 * the defined namespace or return NULL otherwise.
5505 * Returns the namespace pointer or NULL.
5506 */
5507xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005508xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5509{
Owen Taylor3473f882001-02-23 17:55:21 +00005510 xmlNsPtr cur;
5511 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005512 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005513
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005514 if ((node == NULL) || (href == NULL))
5515 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005516 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005517 /*
5518 * Only the document can hold the XML spec namespace.
5519 */
5520 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5521 /*
5522 * The XML-1.0 namespace is normally held on the root
5523 * element. In this case exceptionally create it on the
5524 * node element.
5525 */
5526 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5527 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005528 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005529 return (NULL);
5530 }
5531 memset(cur, 0, sizeof(xmlNs));
5532 cur->type = XML_LOCAL_NAMESPACE;
5533 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5534 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5535 cur->next = node->nsDef;
5536 node->nsDef = cur;
5537 return (cur);
5538 }
5539 if (doc->oldNs == NULL) {
5540 /*
5541 * Allocate a new Namespace and fill the fields.
5542 */
5543 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5544 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005545 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005546 return (NULL);
5547 }
5548 memset(doc->oldNs, 0, sizeof(xmlNs));
5549 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005550
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005551 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5552 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5553 }
5554 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005555 }
Daniel Veillard62040be2004-05-17 03:17:26 +00005556 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00005557 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005558 if ((node->type == XML_ENTITY_REF_NODE) ||
5559 (node->type == XML_ENTITY_NODE) ||
5560 (node->type == XML_ENTITY_DECL))
5561 return (NULL);
5562 if (node->type == XML_ELEMENT_NODE) {
5563 cur = node->nsDef;
5564 while (cur != NULL) {
5565 if ((cur->href != NULL) && (href != NULL) &&
5566 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005567 if (((!is_attr) || (cur->prefix != NULL)) &&
5568 (xmlNsInScope(doc, orig, node, cur->href) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005569 return (cur);
5570 }
5571 cur = cur->next;
5572 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005573 if (orig != node) {
5574 cur = node->ns;
5575 if (cur != NULL) {
5576 if ((cur->href != NULL) && (href != NULL) &&
5577 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005578 if (((!is_attr) || (cur->prefix != NULL)) &&
5579 (xmlNsInScope(doc, orig, node, cur->href) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00005580 return (cur);
5581 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005582 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005583 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005584 }
5585 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005586 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005587 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005588}
5589
5590/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005591 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005592 * @doc: the document
5593 * @tree: a node expected to hold the new namespace
5594 * @ns: the original namespace
5595 *
5596 * This function tries to locate a namespace definition in a tree
5597 * ancestors, or create a new namespace definition node similar to
5598 * @ns trying to reuse the same prefix. However if the given prefix is
5599 * null (default namespace) or reused within the subtree defined by
5600 * @tree or on one of its ancestors then a new prefix is generated.
5601 * Returns the (new) namespace definition or NULL in case of error
5602 */
5603xmlNsPtr
5604xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5605 xmlNsPtr def;
5606 xmlChar prefix[50];
5607 int counter = 1;
5608
5609 if (tree == NULL) {
5610#ifdef DEBUG_TREE
5611 xmlGenericError(xmlGenericErrorContext,
5612 "xmlNewReconciliedNs : tree == NULL\n");
5613#endif
5614 return(NULL);
5615 }
5616 if (ns == NULL) {
5617#ifdef DEBUG_TREE
5618 xmlGenericError(xmlGenericErrorContext,
5619 "xmlNewReconciliedNs : ns == NULL\n");
5620#endif
5621 return(NULL);
5622 }
5623 /*
5624 * Search an existing namespace definition inherited.
5625 */
5626 def = xmlSearchNsByHref(doc, tree, ns->href);
5627 if (def != NULL)
5628 return(def);
5629
5630 /*
5631 * Find a close prefix which is not already in use.
5632 * Let's strip namespace prefixes longer than 20 chars !
5633 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005634 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005635 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005636 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005637 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005638
Owen Taylor3473f882001-02-23 17:55:21 +00005639 def = xmlSearchNs(doc, tree, prefix);
5640 while (def != NULL) {
5641 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005642 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005643 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005644 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005645 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005646 def = xmlSearchNs(doc, tree, prefix);
5647 }
5648
5649 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005650 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005651 */
5652 def = xmlNewNs(tree, ns->href, prefix);
5653 return(def);
5654}
5655
Daniel Veillard652327a2003-09-29 18:02:38 +00005656#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005657/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005658 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005659 * @doc: the document
5660 * @tree: a node defining the subtree to reconciliate
5661 *
5662 * This function checks that all the namespaces declared within the given
5663 * tree are properly declared. This is needed for example after Copy or Cut
5664 * and then paste operations. The subtree may still hold pointers to
5665 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005666 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005667 * the new environment. If not possible the new namespaces are redeclared
5668 * on @tree at the top of the given subtree.
5669 * Returns the number of namespace declarations created or -1 in case of error.
5670 */
5671int
5672xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5673 xmlNsPtr *oldNs = NULL;
5674 xmlNsPtr *newNs = NULL;
5675 int sizeCache = 0;
5676 int nbCache = 0;
5677
5678 xmlNsPtr n;
5679 xmlNodePtr node = tree;
5680 xmlAttrPtr attr;
5681 int ret = 0, i;
5682
5683 while (node != NULL) {
5684 /*
5685 * Reconciliate the node namespace
5686 */
5687 if (node->ns != NULL) {
5688 /*
5689 * initialize the cache if needed
5690 */
5691 if (sizeCache == 0) {
5692 sizeCache = 10;
5693 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5694 sizeof(xmlNsPtr));
5695 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005696 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005697 return(-1);
5698 }
5699 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5700 sizeof(xmlNsPtr));
5701 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005702 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005703 xmlFree(oldNs);
5704 return(-1);
5705 }
5706 }
5707 for (i = 0;i < nbCache;i++) {
5708 if (oldNs[i] == node->ns) {
5709 node->ns = newNs[i];
5710 break;
5711 }
5712 }
5713 if (i == nbCache) {
5714 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005715 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005716 */
5717 n = xmlNewReconciliedNs(doc, tree, node->ns);
5718 if (n != NULL) { /* :-( what if else ??? */
5719 /*
5720 * check if we need to grow the cache buffers.
5721 */
5722 if (sizeCache <= nbCache) {
5723 sizeCache *= 2;
5724 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5725 sizeof(xmlNsPtr));
5726 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005727 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005728 xmlFree(newNs);
5729 return(-1);
5730 }
5731 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5732 sizeof(xmlNsPtr));
5733 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005734 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005735 xmlFree(oldNs);
5736 return(-1);
5737 }
5738 }
5739 newNs[nbCache] = n;
5740 oldNs[nbCache++] = node->ns;
5741 node->ns = n;
5742 }
5743 }
5744 }
5745 /*
5746 * now check for namespace hold by attributes on the node.
5747 */
5748 attr = node->properties;
5749 while (attr != NULL) {
5750 if (attr->ns != NULL) {
5751 /*
5752 * initialize the cache if needed
5753 */
5754 if (sizeCache == 0) {
5755 sizeCache = 10;
5756 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5757 sizeof(xmlNsPtr));
5758 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005759 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005760 return(-1);
5761 }
5762 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5763 sizeof(xmlNsPtr));
5764 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005765 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005766 xmlFree(oldNs);
5767 return(-1);
5768 }
5769 }
5770 for (i = 0;i < nbCache;i++) {
5771 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005772 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005773 break;
5774 }
5775 }
5776 if (i == nbCache) {
5777 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005778 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005779 */
5780 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5781 if (n != NULL) { /* :-( what if else ??? */
5782 /*
5783 * check if we need to grow the cache buffers.
5784 */
5785 if (sizeCache <= nbCache) {
5786 sizeCache *= 2;
5787 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5788 sizeof(xmlNsPtr));
5789 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005790 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005791 xmlFree(newNs);
5792 return(-1);
5793 }
5794 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5795 sizeof(xmlNsPtr));
5796 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005797 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005798 xmlFree(oldNs);
5799 return(-1);
5800 }
5801 }
5802 newNs[nbCache] = n;
5803 oldNs[nbCache++] = attr->ns;
5804 attr->ns = n;
5805 }
5806 }
5807 }
5808 attr = attr->next;
5809 }
5810
5811 /*
5812 * Browse the full subtree, deep first
5813 */
Daniel Veillardac996a12004-07-30 12:02:58 +00005814 if (node->children != NULL && node->type != XML_ENTITY_REF_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00005815 /* deep first */
5816 node = node->children;
5817 } else if ((node != tree) && (node->next != NULL)) {
5818 /* then siblings */
5819 node = node->next;
5820 } else if (node != tree) {
5821 /* go up to parents->next if needed */
5822 while (node != tree) {
5823 if (node->parent != NULL)
5824 node = node->parent;
5825 if ((node != tree) && (node->next != NULL)) {
5826 node = node->next;
5827 break;
5828 }
5829 if (node->parent == NULL) {
5830 node = NULL;
5831 break;
5832 }
5833 }
5834 /* exit condition */
5835 if (node == tree)
5836 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005837 } else
5838 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005839 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005840 if (oldNs != NULL)
5841 xmlFree(oldNs);
5842 if (newNs != NULL)
5843 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005844 return(ret);
5845}
Daniel Veillard652327a2003-09-29 18:02:38 +00005846#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005847
5848/**
5849 * xmlHasProp:
5850 * @node: the node
5851 * @name: the attribute name
5852 *
5853 * Search an attribute associated to a node
5854 * This function also looks in DTD attribute declaration for #FIXED or
5855 * default declaration values unless DTD use has been turned off.
5856 *
5857 * Returns the attribute or the attribute declaration or NULL if
5858 * neither was found.
5859 */
5860xmlAttrPtr
5861xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5862 xmlAttrPtr prop;
5863 xmlDocPtr doc;
5864
5865 if ((node == NULL) || (name == NULL)) return(NULL);
5866 /*
5867 * Check on the properties attached to the node
5868 */
5869 prop = node->properties;
5870 while (prop != NULL) {
5871 if (xmlStrEqual(prop->name, name)) {
5872 return(prop);
5873 }
5874 prop = prop->next;
5875 }
5876 if (!xmlCheckDTD) return(NULL);
5877
5878 /*
5879 * Check if there is a default declaration in the internal
5880 * or external subsets
5881 */
5882 doc = node->doc;
5883 if (doc != NULL) {
5884 xmlAttributePtr attrDecl;
5885 if (doc->intSubset != NULL) {
5886 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5887 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5888 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005889 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5890 /* return attribute declaration only if a default value is given
5891 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005892 return((xmlAttrPtr) attrDecl);
5893 }
5894 }
5895 return(NULL);
5896}
5897
5898/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005899 * xmlHasNsProp:
5900 * @node: the node
5901 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005902 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005903 *
5904 * Search for an attribute associated to a node
5905 * This attribute has to be anchored in the namespace specified.
5906 * This does the entity substitution.
5907 * This function looks in DTD attribute declaration for #FIXED or
5908 * default declaration values unless DTD use has been turned off.
5909 *
5910 * Returns the attribute or the attribute declaration or NULL
5911 * if neither was found.
5912 */
5913xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005914xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005915 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00005916#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005917 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00005918#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005919
5920 if (node == NULL)
5921 return(NULL);
5922
5923 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005924 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005925 return(xmlHasProp(node, name));
5926 while (prop != NULL) {
5927 /*
5928 * One need to have
5929 * - same attribute names
5930 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005931 */
5932 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005933 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5934 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005935 }
5936 prop = prop->next;
5937 }
5938 if (!xmlCheckDTD) return(NULL);
5939
Daniel Veillard652327a2003-09-29 18:02:38 +00005940#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005941 /*
5942 * Check if there is a default declaration in the internal
5943 * or external subsets
5944 */
5945 doc = node->doc;
5946 if (doc != NULL) {
5947 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005948 xmlAttributePtr attrDecl = NULL;
5949 xmlNsPtr *nsList, *cur;
5950 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005951
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005952 nsList = xmlGetNsList(node->doc, node);
5953 if (nsList == NULL)
5954 return(NULL);
5955 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5956 ename = xmlStrdup(node->ns->prefix);
5957 ename = xmlStrcat(ename, BAD_CAST ":");
5958 ename = xmlStrcat(ename, node->name);
5959 } else {
5960 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005961 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005962 if (ename == NULL) {
5963 xmlFree(nsList);
5964 return(NULL);
5965 }
5966
5967 cur = nsList;
5968 while (*cur != NULL) {
5969 if (xmlStrEqual((*cur)->href, nameSpace)) {
5970 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5971 name, (*cur)->prefix);
5972 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5973 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5974 name, (*cur)->prefix);
5975 }
5976 cur++;
5977 }
5978 xmlFree(nsList);
5979 xmlFree(ename);
5980 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005981 }
5982 }
Daniel Veillard652327a2003-09-29 18:02:38 +00005983#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005984 return(NULL);
5985}
5986
5987/**
Owen Taylor3473f882001-02-23 17:55:21 +00005988 * xmlGetProp:
5989 * @node: the node
5990 * @name: the attribute name
5991 *
5992 * Search and get the value of an attribute associated to a node
5993 * This does the entity substitution.
5994 * This function looks in DTD attribute declaration for #FIXED or
5995 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00005996 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00005997 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5998 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005999 *
6000 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006001 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006002 */
6003xmlChar *
6004xmlGetProp(xmlNodePtr node, const xmlChar *name) {
6005 xmlAttrPtr prop;
6006 xmlDocPtr doc;
6007
6008 if ((node == NULL) || (name == NULL)) return(NULL);
6009 /*
6010 * Check on the properties attached to the node
6011 */
6012 prop = node->properties;
6013 while (prop != NULL) {
6014 if (xmlStrEqual(prop->name, name)) {
6015 xmlChar *ret;
6016
6017 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6018 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6019 return(ret);
6020 }
6021 prop = prop->next;
6022 }
6023 if (!xmlCheckDTD) return(NULL);
6024
6025 /*
6026 * Check if there is a default declaration in the internal
6027 * or external subsets
6028 */
6029 doc = node->doc;
6030 if (doc != NULL) {
6031 xmlAttributePtr attrDecl;
6032 if (doc->intSubset != NULL) {
6033 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6034 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6035 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006036 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6037 /* return attribute declaration only if a default value is given
6038 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006039 return(xmlStrdup(attrDecl->defaultValue));
6040 }
6041 }
6042 return(NULL);
6043}
6044
6045/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006046 * xmlGetNoNsProp:
6047 * @node: the node
6048 * @name: the attribute name
6049 *
6050 * Search and get the value of an attribute associated to a node
6051 * This does the entity substitution.
6052 * This function looks in DTD attribute declaration for #FIXED or
6053 * default declaration values unless DTD use has been turned off.
6054 * This function is similar to xmlGetProp except it will accept only
6055 * an attribute in no namespace.
6056 *
6057 * Returns the attribute value or NULL if not found.
6058 * It's up to the caller to free the memory with xmlFree().
6059 */
6060xmlChar *
6061xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6062 xmlAttrPtr prop;
6063 xmlDocPtr doc;
6064
6065 if ((node == NULL) || (name == NULL)) return(NULL);
6066 /*
6067 * Check on the properties attached to the node
6068 */
6069 prop = node->properties;
6070 while (prop != NULL) {
6071 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6072 xmlChar *ret;
6073
6074 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6075 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6076 return(ret);
6077 }
6078 prop = prop->next;
6079 }
6080 if (!xmlCheckDTD) return(NULL);
6081
6082 /*
6083 * Check if there is a default declaration in the internal
6084 * or external subsets
6085 */
6086 doc = node->doc;
6087 if (doc != NULL) {
6088 xmlAttributePtr attrDecl;
6089 if (doc->intSubset != NULL) {
6090 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6091 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6092 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006093 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6094 /* return attribute declaration only if a default value is given
6095 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006096 return(xmlStrdup(attrDecl->defaultValue));
6097 }
6098 }
6099 return(NULL);
6100}
6101
6102/**
Owen Taylor3473f882001-02-23 17:55:21 +00006103 * xmlGetNsProp:
6104 * @node: the node
6105 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006106 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006107 *
6108 * Search and get the value of an attribute associated to a node
6109 * This attribute has to be anchored in the namespace specified.
6110 * This does the entity substitution.
6111 * This function looks in DTD attribute declaration for #FIXED or
6112 * default declaration values unless DTD use has been turned off.
6113 *
6114 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006115 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006116 */
6117xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006118xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006119 xmlAttrPtr prop;
6120 xmlDocPtr doc;
6121 xmlNsPtr ns;
6122
6123 if (node == NULL)
6124 return(NULL);
6125
6126 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006127 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006128 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006129 while (prop != NULL) {
6130 /*
6131 * One need to have
6132 * - same attribute names
6133 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006134 */
6135 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006136 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006137 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006138 xmlChar *ret;
6139
6140 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6141 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6142 return(ret);
6143 }
6144 prop = prop->next;
6145 }
6146 if (!xmlCheckDTD) return(NULL);
6147
6148 /*
6149 * Check if there is a default declaration in the internal
6150 * or external subsets
6151 */
6152 doc = node->doc;
6153 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006154 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006155 xmlAttributePtr attrDecl;
6156
Owen Taylor3473f882001-02-23 17:55:21 +00006157 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6158 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6159 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6160
6161 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6162 /*
6163 * The DTD declaration only allows a prefix search
6164 */
6165 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006166 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006167 return(xmlStrdup(attrDecl->defaultValue));
6168 }
6169 }
6170 }
6171 return(NULL);
6172}
6173
Daniel Veillard2156d432004-03-04 15:59:36 +00006174#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6175/**
6176 * xmlUnsetProp:
6177 * @node: the node
6178 * @name: the attribute name
6179 *
6180 * Remove an attribute carried by a node.
6181 * Returns 0 if successful, -1 if not found
6182 */
6183int
6184xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
6185 xmlAttrPtr prop, prev = NULL;;
6186
6187 if ((node == NULL) || (name == NULL))
6188 return(-1);
6189 prop = node->properties;
6190 while (prop != NULL) {
6191 if ((xmlStrEqual(prop->name, name)) &&
6192 (prop->ns == NULL)) {
6193 if (prev == NULL)
6194 node->properties = prop->next;
6195 else
6196 prev->next = prop->next;
6197 xmlFreeProp(prop);
6198 return(0);
6199 }
6200 prev = prop;
6201 prop = prop->next;
6202 }
6203 return(-1);
6204}
6205
6206/**
6207 * xmlUnsetNsProp:
6208 * @node: the node
6209 * @ns: the namespace definition
6210 * @name: the attribute name
6211 *
6212 * Remove an attribute carried by a node.
6213 * Returns 0 if successful, -1 if not found
6214 */
6215int
6216xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6217 xmlAttrPtr prop = node->properties, prev = NULL;;
6218
6219 if ((node == NULL) || (name == NULL))
6220 return(-1);
6221 if (ns == NULL)
6222 return(xmlUnsetProp(node, name));
6223 if (ns->href == NULL)
6224 return(-1);
6225 while (prop != NULL) {
6226 if ((xmlStrEqual(prop->name, name)) &&
6227 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
6228 if (prev == NULL)
6229 node->properties = prop->next;
6230 else
6231 prev->next = prop->next;
6232 xmlFreeProp(prop);
6233 return(0);
6234 }
6235 prev = prop;
6236 prop = prop->next;
6237 }
6238 return(-1);
6239}
6240#endif
6241
6242#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006243/**
6244 * xmlSetProp:
6245 * @node: the node
6246 * @name: the attribute name
6247 * @value: the attribute value
6248 *
6249 * Set (or reset) an attribute carried by a node.
6250 * Returns the attribute pointer.
6251 */
6252xmlAttrPtr
6253xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006254 xmlAttrPtr prop;
6255 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006256
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006257 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006258 return(NULL);
6259 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006260 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006261 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006262 if ((xmlStrEqual(prop->name, name)) &&
6263 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006264 xmlNodePtr oldprop = prop->children;
6265
Owen Taylor3473f882001-02-23 17:55:21 +00006266 prop->children = NULL;
6267 prop->last = NULL;
6268 if (value != NULL) {
6269 xmlChar *buffer;
6270 xmlNodePtr tmp;
6271
6272 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6273 prop->children = xmlStringGetNodeList(node->doc, buffer);
6274 prop->last = NULL;
6275 prop->doc = doc;
6276 tmp = prop->children;
6277 while (tmp != NULL) {
6278 tmp->parent = (xmlNodePtr) prop;
6279 tmp->doc = doc;
6280 if (tmp->next == NULL)
6281 prop->last = tmp;
6282 tmp = tmp->next;
6283 }
6284 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006285 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006286 if (oldprop != NULL)
6287 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006288 return(prop);
6289 }
6290 prop = prop->next;
6291 }
6292 prop = xmlNewProp(node, name, value);
6293 return(prop);
6294}
6295
6296/**
6297 * xmlSetNsProp:
6298 * @node: the node
6299 * @ns: the namespace definition
6300 * @name: the attribute name
6301 * @value: the attribute value
6302 *
6303 * Set (or reset) an attribute carried by a node.
6304 * The ns structure must be in scope, this is not checked.
6305 *
6306 * Returns the attribute pointer.
6307 */
6308xmlAttrPtr
6309xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6310 const xmlChar *value) {
6311 xmlAttrPtr prop;
6312
6313 if ((node == NULL) || (name == NULL))
6314 return(NULL);
6315
6316 if (ns == NULL)
6317 return(xmlSetProp(node, name, value));
6318 if (ns->href == NULL)
6319 return(NULL);
6320 prop = node->properties;
6321
6322 while (prop != NULL) {
6323 /*
6324 * One need to have
6325 * - same attribute names
6326 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006327 */
6328 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006329 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006330 if (prop->children != NULL)
6331 xmlFreeNodeList(prop->children);
6332 prop->children = NULL;
6333 prop->last = NULL;
6334 prop->ns = ns;
6335 if (value != NULL) {
6336 xmlChar *buffer;
6337 xmlNodePtr tmp;
6338
6339 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6340 prop->children = xmlStringGetNodeList(node->doc, buffer);
6341 prop->last = NULL;
6342 tmp = prop->children;
6343 while (tmp != NULL) {
6344 tmp->parent = (xmlNodePtr) prop;
6345 if (tmp->next == NULL)
6346 prop->last = tmp;
6347 tmp = tmp->next;
6348 }
6349 xmlFree(buffer);
6350 }
6351 return(prop);
6352 }
6353 prop = prop->next;
6354 }
6355 prop = xmlNewNsProp(node, ns, name, value);
6356 return(prop);
6357}
6358
Daniel Veillard652327a2003-09-29 18:02:38 +00006359#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006360
6361/**
Owen Taylor3473f882001-02-23 17:55:21 +00006362 * xmlNodeIsText:
6363 * @node: the node
6364 *
6365 * Is this node a Text node ?
6366 * Returns 1 yes, 0 no
6367 */
6368int
6369xmlNodeIsText(xmlNodePtr node) {
6370 if (node == NULL) return(0);
6371
6372 if (node->type == XML_TEXT_NODE) return(1);
6373 return(0);
6374}
6375
6376/**
6377 * xmlIsBlankNode:
6378 * @node: the node
6379 *
6380 * Checks whether this node is an empty or whitespace only
6381 * (and possibly ignorable) text-node.
6382 *
6383 * Returns 1 yes, 0 no
6384 */
6385int
6386xmlIsBlankNode(xmlNodePtr node) {
6387 const xmlChar *cur;
6388 if (node == NULL) return(0);
6389
Daniel Veillard7db37732001-07-12 01:20:08 +00006390 if ((node->type != XML_TEXT_NODE) &&
6391 (node->type != XML_CDATA_SECTION_NODE))
6392 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006393 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006394 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006395 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006396 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006397 cur++;
6398 }
6399
6400 return(1);
6401}
6402
6403/**
6404 * xmlTextConcat:
6405 * @node: the node
6406 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006407 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006408 *
6409 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006410 *
6411 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006412 */
6413
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006414int
Owen Taylor3473f882001-02-23 17:55:21 +00006415xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006416 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006417
6418 if ((node->type != XML_TEXT_NODE) &&
6419 (node->type != XML_CDATA_SECTION_NODE)) {
6420#ifdef DEBUG_TREE
6421 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006422 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006423#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006424 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006425 }
William M. Brack7762bb12004-01-04 14:49:01 +00006426 /* need to check if content is currently in the dictionary */
6427 if ((node->doc != NULL) && (node->doc->dict != NULL) &&
6428 xmlDictOwns(node->doc->dict, node->content)) {
6429 node->content = xmlStrncatNew(node->content, content, len);
6430 } else {
6431 node->content = xmlStrncat(node->content, content, len);
6432 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006433 if (node->content == NULL)
6434 return(-1);
6435 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006436}
6437
6438/************************************************************************
6439 * *
6440 * Output : to a FILE or in memory *
6441 * *
6442 ************************************************************************/
6443
Owen Taylor3473f882001-02-23 17:55:21 +00006444/**
6445 * xmlBufferCreate:
6446 *
6447 * routine to create an XML buffer.
6448 * returns the new structure.
6449 */
6450xmlBufferPtr
6451xmlBufferCreate(void) {
6452 xmlBufferPtr ret;
6453
6454 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6455 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006456 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006457 return(NULL);
6458 }
6459 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006460 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006461 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006462 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006463 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006464 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006465 xmlFree(ret);
6466 return(NULL);
6467 }
6468 ret->content[0] = 0;
6469 return(ret);
6470}
6471
6472/**
6473 * xmlBufferCreateSize:
6474 * @size: initial size of buffer
6475 *
6476 * routine to create an XML buffer.
6477 * returns the new structure.
6478 */
6479xmlBufferPtr
6480xmlBufferCreateSize(size_t size) {
6481 xmlBufferPtr ret;
6482
6483 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6484 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006485 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006486 return(NULL);
6487 }
6488 ret->use = 0;
6489 ret->alloc = xmlBufferAllocScheme;
6490 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6491 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006492 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006493 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006494 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006495 xmlFree(ret);
6496 return(NULL);
6497 }
6498 ret->content[0] = 0;
6499 } else
6500 ret->content = NULL;
6501 return(ret);
6502}
6503
6504/**
Daniel Veillard53350552003-09-18 13:35:51 +00006505 * xmlBufferCreateStatic:
6506 * @mem: the memory area
6507 * @size: the size in byte
6508 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006509 * routine to create an XML buffer from an immutable memory area.
6510 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006511 * present until the end of the buffer lifetime.
6512 *
6513 * returns the new structure.
6514 */
6515xmlBufferPtr
6516xmlBufferCreateStatic(void *mem, size_t size) {
6517 xmlBufferPtr ret;
6518
6519 if ((mem == NULL) || (size == 0))
6520 return(NULL);
6521
6522 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6523 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006524 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006525 return(NULL);
6526 }
6527 ret->use = size;
6528 ret->size = size;
6529 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6530 ret->content = (xmlChar *) mem;
6531 return(ret);
6532}
6533
6534/**
Owen Taylor3473f882001-02-23 17:55:21 +00006535 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006536 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006537 * @scheme: allocation scheme to use
6538 *
6539 * Sets the allocation scheme for this buffer
6540 */
6541void
6542xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6543 xmlBufferAllocationScheme scheme) {
6544 if (buf == NULL) {
6545#ifdef DEBUG_BUFFER
6546 xmlGenericError(xmlGenericErrorContext,
6547 "xmlBufferSetAllocationScheme: buf == NULL\n");
6548#endif
6549 return;
6550 }
Daniel Veillard53350552003-09-18 13:35:51 +00006551 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006552
6553 buf->alloc = scheme;
6554}
6555
6556/**
6557 * xmlBufferFree:
6558 * @buf: the buffer to free
6559 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006560 * Frees an XML buffer. It frees both the content and the structure which
6561 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006562 */
6563void
6564xmlBufferFree(xmlBufferPtr buf) {
6565 if (buf == NULL) {
6566#ifdef DEBUG_BUFFER
6567 xmlGenericError(xmlGenericErrorContext,
6568 "xmlBufferFree: buf == NULL\n");
6569#endif
6570 return;
6571 }
Daniel Veillard53350552003-09-18 13:35:51 +00006572
6573 if ((buf->content != NULL) &&
6574 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006575 xmlFree(buf->content);
6576 }
Owen Taylor3473f882001-02-23 17:55:21 +00006577 xmlFree(buf);
6578}
6579
6580/**
6581 * xmlBufferEmpty:
6582 * @buf: the buffer
6583 *
6584 * empty a buffer.
6585 */
6586void
6587xmlBufferEmpty(xmlBufferPtr buf) {
6588 if (buf->content == NULL) return;
6589 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006590 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006591 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006592 } else {
6593 memset(buf->content, 0, buf->size);
6594 }
Owen Taylor3473f882001-02-23 17:55:21 +00006595}
6596
6597/**
6598 * xmlBufferShrink:
6599 * @buf: the buffer to dump
6600 * @len: the number of xmlChar to remove
6601 *
6602 * Remove the beginning of an XML buffer.
6603 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006604 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006605 */
6606int
6607xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6608 if (len == 0) return(0);
6609 if (len > buf->use) return(-1);
6610
6611 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006612 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6613 buf->content += len;
6614 } else {
6615 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6616 buf->content[buf->use] = 0;
6617 }
Owen Taylor3473f882001-02-23 17:55:21 +00006618 return(len);
6619}
6620
6621/**
6622 * xmlBufferGrow:
6623 * @buf: the buffer
6624 * @len: the minimum free size to allocate
6625 *
6626 * Grow the available space of an XML buffer.
6627 *
6628 * Returns the new available space or -1 in case of error
6629 */
6630int
6631xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6632 int size;
6633 xmlChar *newbuf;
6634
Daniel Veillard53350552003-09-18 13:35:51 +00006635 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006636 if (len + buf->use < buf->size) return(0);
6637
William M. Brack30fe43f2004-07-26 18:00:58 +00006638/*
6639 * Windows has a BIG problem on realloc timing, so we try to double
6640 * the buffer size (if that's enough) (bug 146697)
6641 */
6642#ifdef WIN32
6643 if (buf->size > len)
6644 size = buf->size * 2;
6645 else
6646 size = buf->use + len + 100;
6647#else
Owen Taylor3473f882001-02-23 17:55:21 +00006648 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00006649#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006650
6651 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006652 if (newbuf == NULL) {
6653 xmlTreeErrMemory("growing buffer");
6654 return(-1);
6655 }
Owen Taylor3473f882001-02-23 17:55:21 +00006656 buf->content = newbuf;
6657 buf->size = size;
6658 return(buf->size - buf->use);
6659}
6660
6661/**
6662 * xmlBufferDump:
6663 * @file: the file output
6664 * @buf: the buffer to dump
6665 *
6666 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006667 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006668 */
6669int
6670xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6671 int ret;
6672
6673 if (buf == NULL) {
6674#ifdef DEBUG_BUFFER
6675 xmlGenericError(xmlGenericErrorContext,
6676 "xmlBufferDump: buf == NULL\n");
6677#endif
6678 return(0);
6679 }
6680 if (buf->content == NULL) {
6681#ifdef DEBUG_BUFFER
6682 xmlGenericError(xmlGenericErrorContext,
6683 "xmlBufferDump: buf->content == NULL\n");
6684#endif
6685 return(0);
6686 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006687 if (file == NULL)
6688 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006689 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6690 return(ret);
6691}
6692
6693/**
6694 * xmlBufferContent:
6695 * @buf: the buffer
6696 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006697 * Function to extract the content of a buffer
6698 *
Owen Taylor3473f882001-02-23 17:55:21 +00006699 * Returns the internal content
6700 */
6701
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006702const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006703xmlBufferContent(const xmlBufferPtr buf)
6704{
6705 if(!buf)
6706 return NULL;
6707
6708 return buf->content;
6709}
6710
6711/**
6712 * xmlBufferLength:
6713 * @buf: the buffer
6714 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006715 * Function to get the length of a buffer
6716 *
Owen Taylor3473f882001-02-23 17:55:21 +00006717 * Returns the length of data in the internal content
6718 */
6719
6720int
6721xmlBufferLength(const xmlBufferPtr buf)
6722{
6723 if(!buf)
6724 return 0;
6725
6726 return buf->use;
6727}
6728
6729/**
6730 * xmlBufferResize:
6731 * @buf: the buffer to resize
6732 * @size: the desired size
6733 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006734 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006735 *
6736 * Returns 0 in case of problems, 1 otherwise
6737 */
6738int
6739xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6740{
6741 unsigned int newSize;
6742 xmlChar* rebuf = NULL;
6743
Daniel Veillard53350552003-09-18 13:35:51 +00006744 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6745
Owen Taylor3473f882001-02-23 17:55:21 +00006746 /* Don't resize if we don't have to */
6747 if (size < buf->size)
6748 return 1;
6749
6750 /* figure out new size */
6751 switch (buf->alloc){
6752 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillardbf629492004-04-20 22:20:59 +00006753 /*take care of empty case*/
6754 newSize = (buf->size ? buf->size*2 : size + 10);
Owen Taylor3473f882001-02-23 17:55:21 +00006755 while (size > newSize) newSize *= 2;
6756 break;
6757 case XML_BUFFER_ALLOC_EXACT:
6758 newSize = size+10;
6759 break;
6760 default:
6761 newSize = size+10;
6762 break;
6763 }
6764
6765 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006766 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006767 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006768 rebuf = (xmlChar *) xmlRealloc(buf->content,
6769 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006770 } else {
6771 /*
6772 * if we are reallocating a buffer far from being full, it's
6773 * better to make a new allocation and copy only the used range
6774 * and free the old one.
6775 */
6776 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6777 if (rebuf != NULL) {
6778 memcpy(rebuf, buf->content, buf->use);
6779 xmlFree(buf->content);
William M. Brack42331a92004-07-29 07:07:16 +00006780 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006781 }
6782 }
Owen Taylor3473f882001-02-23 17:55:21 +00006783 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006784 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006785 return 0;
6786 }
6787 buf->content = rebuf;
6788 buf->size = newSize;
6789
6790 return 1;
6791}
6792
6793/**
6794 * xmlBufferAdd:
6795 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006796 * @str: the #xmlChar string
6797 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006798 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006799 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006800 * str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006801 *
6802 * Returns 0 successful, a positive error code number otherwise
6803 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006804 */
William M. Bracka3215c72004-07-31 16:24:01 +00006805int
Owen Taylor3473f882001-02-23 17:55:21 +00006806xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6807 unsigned int needSize;
6808
6809 if (str == NULL) {
6810#ifdef DEBUG_BUFFER
6811 xmlGenericError(xmlGenericErrorContext,
6812 "xmlBufferAdd: str == NULL\n");
6813#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006814 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006815 }
William M. Bracka3215c72004-07-31 16:24:01 +00006816 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006817 if (len < -1) {
6818#ifdef DEBUG_BUFFER
6819 xmlGenericError(xmlGenericErrorContext,
6820 "xmlBufferAdd: len < 0\n");
6821#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006822 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006823 }
William M. Bracka3215c72004-07-31 16:24:01 +00006824 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006825
6826 if (len < 0)
6827 len = xmlStrlen(str);
6828
William M. Bracka3215c72004-07-31 16:24:01 +00006829 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006830
6831 needSize = buf->use + len + 2;
6832 if (needSize > buf->size){
6833 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006834 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006835 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006836 }
6837 }
6838
6839 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6840 buf->use += len;
6841 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006842 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006843}
6844
6845/**
6846 * xmlBufferAddHead:
6847 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006848 * @str: the #xmlChar string
6849 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006850 *
6851 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006852 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006853 *
6854 * Returns 0 successful, a positive error code number otherwise
6855 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006856 */
William M. Bracka3215c72004-07-31 16:24:01 +00006857int
Owen Taylor3473f882001-02-23 17:55:21 +00006858xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6859 unsigned int needSize;
6860
William M. Bracka3215c72004-07-31 16:24:01 +00006861 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006862 if (str == NULL) {
6863#ifdef DEBUG_BUFFER
6864 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006865 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006866#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006867 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006868 }
6869 if (len < -1) {
6870#ifdef DEBUG_BUFFER
6871 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006872 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006873#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006874 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006875 }
William M. Bracka3215c72004-07-31 16:24:01 +00006876 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006877
6878 if (len < 0)
6879 len = xmlStrlen(str);
6880
William M. Bracka3215c72004-07-31 16:24:01 +00006881 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006882
6883 needSize = buf->use + len + 2;
6884 if (needSize > buf->size){
6885 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006886 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006887 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006888 }
6889 }
6890
6891 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6892 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6893 buf->use += len;
6894 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006895 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006896}
6897
6898/**
6899 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00006900 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00006901 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006902 *
6903 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00006904 *
6905 * Returns 0 successful, a positive error code number otherwise
6906 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006907 */
William M. Bracka3215c72004-07-31 16:24:01 +00006908int
Owen Taylor3473f882001-02-23 17:55:21 +00006909xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
William M. Bracka3215c72004-07-31 16:24:01 +00006910 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
6911 if (str == NULL) return -1;
6912 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00006913}
6914
6915/**
6916 * xmlBufferCCat:
6917 * @buf: the buffer to dump
6918 * @str: the C char string
6919 *
6920 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00006921 *
6922 * Returns 0 successful, a positive error code number otherwise
6923 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006924 */
William M. Bracka3215c72004-07-31 16:24:01 +00006925int
Owen Taylor3473f882001-02-23 17:55:21 +00006926xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6927 const char *cur;
6928
William M. Bracka3215c72004-07-31 16:24:01 +00006929 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006930 if (str == NULL) {
6931#ifdef DEBUG_BUFFER
6932 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006933 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006934#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006935 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006936 }
6937 for (cur = str;*cur != 0;cur++) {
6938 if (buf->use + 10 >= buf->size) {
6939 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006940 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006941 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006942 }
6943 }
6944 buf->content[buf->use++] = *cur;
6945 }
6946 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006947 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006948}
6949
6950/**
6951 * xmlBufferWriteCHAR:
6952 * @buf: the XML buffer
6953 * @string: the string to add
6954 *
6955 * routine which manages and grows an output buffer. This one adds
6956 * xmlChars at the end of the buffer.
6957 */
6958void
Daniel Veillard53350552003-09-18 13:35:51 +00006959xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
6960 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006961 xmlBufferCat(buf, string);
6962}
6963
6964/**
6965 * xmlBufferWriteChar:
6966 * @buf: the XML buffer output
6967 * @string: the string to add
6968 *
6969 * routine which manage and grows an output buffer. This one add
6970 * C chars at the end of the array.
6971 */
6972void
6973xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillard53350552003-09-18 13:35:51 +00006974 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006975 xmlBufferCCat(buf, string);
6976}
6977
6978
6979/**
6980 * xmlBufferWriteQuotedString:
6981 * @buf: the XML buffer output
6982 * @string: the string to add
6983 *
6984 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006985 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006986 * quote or double-quotes internally
6987 */
6988void
6989xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00006990 const xmlChar *cur, *base;
Daniel Veillard53350552003-09-18 13:35:51 +00006991 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00006992 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00006993 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00006994#ifdef DEBUG_BUFFER
6995 xmlGenericError(xmlGenericErrorContext,
6996 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6997#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00006998 xmlBufferCCat(buf, "\"");
6999 base = cur = string;
7000 while(*cur != 0){
7001 if(*cur == '"'){
7002 if (base != cur)
7003 xmlBufferAdd(buf, base, cur - base);
7004 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7005 cur++;
7006 base = cur;
7007 }
7008 else {
7009 cur++;
7010 }
7011 }
7012 if (base != cur)
7013 xmlBufferAdd(buf, base, cur - base);
7014 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007015 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007016 else{
7017 xmlBufferCCat(buf, "\'");
7018 xmlBufferCat(buf, string);
7019 xmlBufferCCat(buf, "\'");
7020 }
Owen Taylor3473f882001-02-23 17:55:21 +00007021 } else {
7022 xmlBufferCCat(buf, "\"");
7023 xmlBufferCat(buf, string);
7024 xmlBufferCCat(buf, "\"");
7025 }
7026}
7027
7028
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007029/**
7030 * xmlGetDocCompressMode:
7031 * @doc: the document
7032 *
7033 * get the compression ratio for a document, ZLIB based
7034 * Returns 0 (uncompressed) to 9 (max compression)
7035 */
7036int
7037xmlGetDocCompressMode (xmlDocPtr doc) {
7038 if (doc == NULL) return(-1);
7039 return(doc->compression);
7040}
7041
7042/**
7043 * xmlSetDocCompressMode:
7044 * @doc: the document
7045 * @mode: the compression ratio
7046 *
7047 * set the compression ratio for a document, ZLIB based
7048 * Correct values: 0 (uncompressed) to 9 (max compression)
7049 */
7050void
7051xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7052 if (doc == NULL) return;
7053 if (mode < 0) doc->compression = 0;
7054 else if (mode > 9) doc->compression = 9;
7055 else doc->compression = mode;
7056}
7057
7058/**
7059 * xmlGetCompressMode:
7060 *
7061 * get the default compression mode used, ZLIB based.
7062 * Returns 0 (uncompressed) to 9 (max compression)
7063 */
7064int
7065xmlGetCompressMode(void)
7066{
7067 return (xmlCompressMode);
7068}
7069
7070/**
7071 * xmlSetCompressMode:
7072 * @mode: the compression ratio
7073 *
7074 * set the default compression mode used, ZLIB based
7075 * Correct values: 0 (uncompressed) to 9 (max compression)
7076 */
7077void
7078xmlSetCompressMode(int mode) {
7079 if (mode < 0) xmlCompressMode = 0;
7080 else if (mode > 9) xmlCompressMode = 9;
7081 else xmlCompressMode = mode;
7082}
7083