blob: 6c2e2cbd4f029604b6eb071221ea622de249f27c [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
Daniel Veillardd5c2f922002-11-21 14:10:52 +00004 * References:
5 * XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
6 *
Owen Taylor3473f882001-02-23 17:55:21 +00007 * See Copyright for the status of this software.
8 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00009 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000010 *
Owen Taylor3473f882001-02-23 17:55:21 +000011 */
12
Daniel Veillard34ce8be2002-03-18 19:37:11 +000013#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000014#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000015
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24#ifdef HAVE_ZLIB_H
25#include <zlib.h>
26#endif
27
28#include <libxml/xmlmemory.h>
29#include <libxml/tree.h>
30#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000031#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000032#include <libxml/entities.h>
33#include <libxml/valid.h>
34#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000035#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000036#include <libxml/globals.h>
Daniel Veillardd5c2f922002-11-21 14:10:52 +000037#ifdef LIBXML_HTML_ENABLED
38#include <libxml/HTMLtree.h>
39#endif
Owen Taylor3473f882001-02-23 17:55:21 +000040
Daniel Veillarda880b122003-04-21 21:36:41 +000041int __xmlRegisterCallbacks = 0;
42
Daniel Veillard56a4cb82001-03-24 17:00:36 +000043xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
44
45/************************************************************************
46 * *
Daniel Veillard18ec16e2003-10-07 23:16:40 +000047 * Tree memory error handler *
48 * *
49 ************************************************************************/
50/**
51 * xmlTreeErrMemory:
52 * @extra: extra informations
53 *
54 * Handle an out of memory condition
55 */
56static void
57xmlTreeErrMemory(const char *extra)
58{
59 __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
60}
61
62/**
63 * xmlTreeErr:
64 * @code: the error number
65 * @extra: extra informations
66 *
67 * Handle an out of memory condition
68 */
69static void
70xmlTreeErr(int code, xmlNodePtr node, const char *extra)
71{
72 const char *msg = NULL;
73
74 switch(code) {
75 case XML_TREE_INVALID_HEX:
Daniel Veillardac996a12004-07-30 12:02:58 +000076 msg = "invalid hexadecimal character value\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000077 break;
78 case XML_TREE_INVALID_DEC:
Daniel Veillardac996a12004-07-30 12:02:58 +000079 msg = "invalid decimal character value\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000080 break;
81 case XML_TREE_UNTERMINATED_ENTITY:
Daniel Veillardac996a12004-07-30 12:02:58 +000082 msg = "unterminated entity reference %15s\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000083 break;
84 default:
Daniel Veillardac996a12004-07-30 12:02:58 +000085 msg = "unexpected error number\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000086 }
87 __xmlSimpleError(XML_FROM_TREE, code, node, msg, extra);
88}
89
90/************************************************************************
91 * *
Daniel Veillard56a4cb82001-03-24 17:00:36 +000092 * A few static variables and macros *
93 * *
94 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000095/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000096const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000097/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000098const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000099 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +0000100/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +0000101const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
102
Owen Taylor3473f882001-02-23 17:55:21 +0000103static int xmlCompressMode = 0;
104static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000105
Owen Taylor3473f882001-02-23 17:55:21 +0000106#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
107 xmlNodePtr ulccur = (n)->children; \
108 if (ulccur == NULL) { \
109 (n)->last = NULL; \
110 } else { \
111 while (ulccur->next != NULL) { \
112 ulccur->parent = (n); \
113 ulccur = ulccur->next; \
114 } \
115 ulccur->parent = (n); \
116 (n)->last = ulccur; \
117}}
118
119/* #define DEBUG_BUFFER */
120/* #define DEBUG_TREE */
121
122/************************************************************************
123 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000124 * Functions to move to entities.c once the *
125 * API freeze is smoothen and they can be made public. *
126 * *
127 ************************************************************************/
128#include <libxml/hash.h>
129
Daniel Veillard652327a2003-09-29 18:02:38 +0000130#ifdef LIBXML_TREE_ENABLED
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000131/**
132 * xmlGetEntityFromDtd:
133 * @dtd: A pointer to the DTD to search
134 * @name: The entity name
135 *
136 * Do an entity lookup in the DTD entity hash table and
137 * return the corresponding entity, if found.
138 *
139 * Returns A pointer to the entity structure or NULL if not found.
140 */
141static xmlEntityPtr
142xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
143 xmlEntitiesTablePtr table;
144
145 if((dtd != NULL) && (dtd->entities != NULL)) {
146 table = (xmlEntitiesTablePtr) dtd->entities;
147 return((xmlEntityPtr) xmlHashLookup(table, name));
148 /* return(xmlGetEntityFromTable(table, name)); */
149 }
150 return(NULL);
151}
152/**
153 * xmlGetParameterEntityFromDtd:
154 * @dtd: A pointer to the DTD to search
155 * @name: The entity name
156 *
157 * Do an entity lookup in the DTD pararmeter entity hash table and
158 * return the corresponding entity, if found.
159 *
160 * Returns A pointer to the entity structure or NULL if not found.
161 */
162static xmlEntityPtr
163xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
164 xmlEntitiesTablePtr table;
165
166 if ((dtd != NULL) && (dtd->pentities != NULL)) {
167 table = (xmlEntitiesTablePtr) dtd->pentities;
168 return((xmlEntityPtr) xmlHashLookup(table, name));
169 /* return(xmlGetEntityFromTable(table, name)); */
170 }
171 return(NULL);
172}
Daniel Veillard652327a2003-09-29 18:02:38 +0000173#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000174
175/************************************************************************
176 * *
Daniel Veillardc00cda82003-04-07 10:22:39 +0000177 * QName handling helper *
178 * *
179 ************************************************************************/
180
181/**
182 * xmlBuildQName:
183 * @ncname: the Name
184 * @prefix: the prefix
185 * @memory: preallocated memory
186 * @len: preallocated memory length
187 *
188 * Builds the QName @prefix:@ncname in @memory if there is enough space
189 * and prefix is not NULL nor empty, otherwise allocate a new string.
190 * If prefix is NULL or empty it returns ncname.
191 *
192 * Returns the new string which must be freed by the caller if different from
193 * @memory and @ncname or NULL in case of error
194 */
195xmlChar *
196xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
197 xmlChar *memory, int len) {
198 int lenn, lenp;
199 xmlChar *ret;
200
Daniel Veillard3b7840c2003-09-11 23:42:01 +0000201 if (ncname == NULL) return(NULL);
202 if (prefix == NULL) return((xmlChar *) ncname);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000203
204 lenn = strlen((char *) ncname);
205 lenp = strlen((char *) prefix);
206
207 if ((memory == NULL) || (len < lenn + lenp + 2)) {
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000208 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000209 if (ret == NULL) {
210 xmlTreeErrMemory("building QName");
211 return(NULL);
212 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000213 } else {
214 ret = memory;
215 }
216 memcpy(&ret[0], prefix, lenp);
217 ret[lenp] = ':';
218 memcpy(&ret[lenp + 1], ncname, lenn);
219 ret[lenn + lenp + 1] = 0;
220 return(ret);
221}
222
223/**
224 * xmlSplitQName2:
225 * @name: the full QName
226 * @prefix: a xmlChar **
227 *
228 * parse an XML qualified name string
229 *
230 * [NS 5] QName ::= (Prefix ':')? LocalPart
231 *
232 * [NS 6] Prefix ::= NCName
233 *
234 * [NS 7] LocalPart ::= NCName
235 *
236 * Returns NULL if not a QName, otherwise the local part, and prefix
237 * is updated to get the Prefix if any.
238 */
239
240xmlChar *
241xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
242 int len = 0;
243 xmlChar *ret = NULL;
244
245 *prefix = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000246 if (name == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000247
248#ifndef XML_XML_NAMESPACE
249 /* xml: prefix is not really a namespace */
250 if ((name[0] == 'x') && (name[1] == 'm') &&
251 (name[2] == 'l') && (name[3] == ':'))
252 return(NULL);
253#endif
254
255 /* nasty but valid */
256 if (name[0] == ':')
257 return(NULL);
258
259 /*
260 * we are not trying to validate but just to cut, and yes it will
261 * work even if this is as set of UTF-8 encoded chars
262 */
263 while ((name[len] != 0) && (name[len] != ':'))
264 len++;
265
266 if (name[len] == 0)
267 return(NULL);
268
269 *prefix = xmlStrndup(name, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000270 if (*prefix == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000271 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000272 return(NULL);
273 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000274 ret = xmlStrdup(&name[len + 1]);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000275 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000276 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000277 if (*prefix != NULL) {
278 xmlFree(*prefix);
279 *prefix = NULL;
280 }
281 return(NULL);
282 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000283
284 return(ret);
285}
286
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000287/**
288 * xmlSplitQName3:
289 * @name: the full QName
290 * @len: an int *
291 *
292 * parse an XML qualified name string,i
293 *
294 * returns NULL if it is not a Qualified Name, otherwise, update len
295 * with the lenght in byte of the prefix and return a pointer
296 */
297
298const xmlChar *
299xmlSplitQName3(const xmlChar *name, int *len) {
300 int l = 0;
301
302 if (name == NULL) return(NULL);
303 if (len == NULL) return(NULL);
304
305 /* nasty but valid */
306 if (name[0] == ':')
307 return(NULL);
308
309 /*
310 * we are not trying to validate but just to cut, and yes it will
311 * work even if this is as set of UTF-8 encoded chars
312 */
313 while ((name[l] != 0) && (name[l] != ':'))
314 l++;
315
316 if (name[l] == 0)
317 return(NULL);
318
319 *len = l;
320
321 return(&name[l+1]);
322}
323
Daniel Veillardc00cda82003-04-07 10:22:39 +0000324/************************************************************************
325 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000326 * Check Name, NCName and QName strings *
327 * *
328 ************************************************************************/
329
330#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
331
Daniel Veillard2156d432004-03-04 15:59:36 +0000332#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000333/**
334 * xmlValidateNCName:
335 * @value: the value to check
336 * @space: allow spaces in front and end of the string
337 *
338 * Check that a value conforms to the lexical space of NCName
339 *
340 * Returns 0 if this validates, a positive error code number otherwise
341 * and -1 in case of internal or API error.
342 */
343int
344xmlValidateNCName(const xmlChar *value, int space) {
345 const xmlChar *cur = value;
346 int c,l;
347
348 /*
349 * First quick algorithm for ASCII range
350 */
351 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000352 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000353 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
354 (*cur == '_'))
355 cur++;
356 else
357 goto try_complex;
358 while (((*cur >= 'a') && (*cur <= 'z')) ||
359 ((*cur >= 'A') && (*cur <= 'Z')) ||
360 ((*cur >= '0') && (*cur <= '9')) ||
361 (*cur == '_') || (*cur == '-') || (*cur == '.'))
362 cur++;
363 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000364 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000365 if (*cur == 0)
366 return(0);
367
368try_complex:
369 /*
370 * Second check for chars outside the ASCII range
371 */
372 cur = value;
373 c = CUR_SCHAR(cur, l);
374 if (space) {
375 while (IS_BLANK(c)) {
376 cur += l;
377 c = CUR_SCHAR(cur, l);
378 }
379 }
William M. Brack871611b2003-10-18 04:53:14 +0000380 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000381 return(1);
382 cur += l;
383 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000384 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
385 (c == '-') || (c == '_') || IS_COMBINING(c) ||
386 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000387 cur += l;
388 c = CUR_SCHAR(cur, l);
389 }
390 if (space) {
391 while (IS_BLANK(c)) {
392 cur += l;
393 c = CUR_SCHAR(cur, l);
394 }
395 }
396 if (c != 0)
397 return(1);
398
399 return(0);
400}
Daniel Veillard2156d432004-03-04 15:59:36 +0000401#endif
Daniel Veillardd2298792003-02-14 16:54:11 +0000402
Daniel Veillard2156d432004-03-04 15:59:36 +0000403#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000404/**
405 * xmlValidateQName:
406 * @value: the value to check
407 * @space: allow spaces in front and end of the string
408 *
409 * Check that a value conforms to the lexical space of QName
410 *
411 * Returns 0 if this validates, a positive error code number otherwise
412 * and -1 in case of internal or API error.
413 */
414int
415xmlValidateQName(const xmlChar *value, int space) {
416 const xmlChar *cur = value;
417 int c,l;
418
419 /*
420 * First quick algorithm for ASCII range
421 */
422 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000423 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000424 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
425 (*cur == '_'))
426 cur++;
427 else
428 goto try_complex;
429 while (((*cur >= 'a') && (*cur <= 'z')) ||
430 ((*cur >= 'A') && (*cur <= 'Z')) ||
431 ((*cur >= '0') && (*cur <= '9')) ||
432 (*cur == '_') || (*cur == '-') || (*cur == '.'))
433 cur++;
434 if (*cur == ':') {
435 cur++;
436 if (((*cur >= 'a') && (*cur <= 'z')) ||
437 ((*cur >= 'A') && (*cur <= 'Z')) ||
438 (*cur == '_'))
439 cur++;
440 else
441 goto try_complex;
442 while (((*cur >= 'a') && (*cur <= 'z')) ||
443 ((*cur >= 'A') && (*cur <= 'Z')) ||
444 ((*cur >= '0') && (*cur <= '9')) ||
445 (*cur == '_') || (*cur == '-') || (*cur == '.'))
446 cur++;
447 }
448 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000449 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000450 if (*cur == 0)
451 return(0);
452
453try_complex:
454 /*
455 * Second check for chars outside the ASCII range
456 */
457 cur = value;
458 c = CUR_SCHAR(cur, l);
459 if (space) {
460 while (IS_BLANK(c)) {
461 cur += l;
462 c = CUR_SCHAR(cur, l);
463 }
464 }
William M. Brack871611b2003-10-18 04:53:14 +0000465 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000466 return(1);
467 cur += l;
468 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000469 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
470 (c == '-') || (c == '_') || IS_COMBINING(c) ||
471 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000472 cur += l;
473 c = CUR_SCHAR(cur, l);
474 }
475 if (c == ':') {
476 cur += l;
477 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000478 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000479 return(1);
480 cur += l;
481 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000482 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
483 (c == '-') || (c == '_') || IS_COMBINING(c) ||
484 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000485 cur += l;
486 c = CUR_SCHAR(cur, l);
487 }
488 }
489 if (space) {
490 while (IS_BLANK(c)) {
491 cur += l;
492 c = CUR_SCHAR(cur, l);
493 }
494 }
495 if (c != 0)
496 return(1);
497 return(0);
498}
499
500/**
501 * xmlValidateName:
502 * @value: the value to check
503 * @space: allow spaces in front and end of the string
504 *
505 * Check that a value conforms to the lexical space of Name
506 *
507 * Returns 0 if this validates, a positive error code number otherwise
508 * and -1 in case of internal or API error.
509 */
510int
511xmlValidateName(const xmlChar *value, int space) {
512 const xmlChar *cur = value;
513 int c,l;
514
515 /*
516 * First quick algorithm for ASCII range
517 */
518 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000519 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000520 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
521 (*cur == '_') || (*cur == ':'))
522 cur++;
523 else
524 goto try_complex;
525 while (((*cur >= 'a') && (*cur <= 'z')) ||
526 ((*cur >= 'A') && (*cur <= 'Z')) ||
527 ((*cur >= '0') && (*cur <= '9')) ||
528 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
529 cur++;
530 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000531 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000532 if (*cur == 0)
533 return(0);
534
535try_complex:
536 /*
537 * Second check for chars outside the ASCII range
538 */
539 cur = value;
540 c = CUR_SCHAR(cur, l);
541 if (space) {
542 while (IS_BLANK(c)) {
543 cur += l;
544 c = CUR_SCHAR(cur, l);
545 }
546 }
William M. Brack871611b2003-10-18 04:53:14 +0000547 if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000548 return(1);
549 cur += l;
550 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000551 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
552 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000553 cur += l;
554 c = CUR_SCHAR(cur, l);
555 }
556 if (space) {
557 while (IS_BLANK(c)) {
558 cur += l;
559 c = CUR_SCHAR(cur, l);
560 }
561 }
562 if (c != 0)
563 return(1);
564 return(0);
565}
566
Daniel Veillardd4310742003-02-18 21:12:46 +0000567/**
568 * xmlValidateNMToken:
569 * @value: the value to check
570 * @space: allow spaces in front and end of the string
571 *
572 * Check that a value conforms to the lexical space of NMToken
573 *
574 * Returns 0 if this validates, a positive error code number otherwise
575 * and -1 in case of internal or API error.
576 */
577int
578xmlValidateNMToken(const xmlChar *value, int space) {
579 const xmlChar *cur = value;
580 int c,l;
581
582 /*
583 * First quick algorithm for ASCII range
584 */
585 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000586 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000587 if (((*cur >= 'a') && (*cur <= 'z')) ||
588 ((*cur >= 'A') && (*cur <= 'Z')) ||
589 ((*cur >= '0') && (*cur <= '9')) ||
590 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
591 cur++;
592 else
593 goto try_complex;
594 while (((*cur >= 'a') && (*cur <= 'z')) ||
595 ((*cur >= 'A') && (*cur <= 'Z')) ||
596 ((*cur >= '0') && (*cur <= '9')) ||
597 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
598 cur++;
599 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000600 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000601 if (*cur == 0)
602 return(0);
603
604try_complex:
605 /*
606 * Second check for chars outside the ASCII range
607 */
608 cur = value;
609 c = CUR_SCHAR(cur, l);
610 if (space) {
611 while (IS_BLANK(c)) {
612 cur += l;
613 c = CUR_SCHAR(cur, l);
614 }
615 }
William M. Brack871611b2003-10-18 04:53:14 +0000616 if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
617 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
Daniel Veillardd4310742003-02-18 21:12:46 +0000618 return(1);
619 cur += l;
620 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000621 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
622 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd4310742003-02-18 21:12:46 +0000623 cur += l;
624 c = CUR_SCHAR(cur, l);
625 }
626 if (space) {
627 while (IS_BLANK(c)) {
628 cur += l;
629 c = CUR_SCHAR(cur, l);
630 }
631 }
632 if (c != 0)
633 return(1);
634 return(0);
635}
Daniel Veillard652327a2003-09-29 18:02:38 +0000636#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardd4310742003-02-18 21:12:46 +0000637
Daniel Veillardd2298792003-02-14 16:54:11 +0000638/************************************************************************
639 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000640 * Allocation and deallocation of basic structures *
641 * *
642 ************************************************************************/
643
644/**
645 * xmlSetBufferAllocationScheme:
646 * @scheme: allocation method to use
647 *
648 * Set the buffer allocation method. Types are
649 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
650 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
651 * improves performance
652 */
653void
654xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
655 xmlBufferAllocScheme = scheme;
656}
657
658/**
659 * xmlGetBufferAllocationScheme:
660 *
661 * Types are
662 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
663 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
664 * improves performance
665 *
666 * Returns the current allocation scheme
667 */
668xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000669xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000670 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000671}
672
673/**
674 * xmlNewNs:
675 * @node: the element carrying the namespace
676 * @href: the URI associated
677 * @prefix: the prefix for the namespace
678 *
679 * Creation of a new Namespace. This function will refuse to create
680 * a namespace with a similar prefix than an existing one present on this
681 * node.
682 * We use href==NULL in the case of an element creation where the namespace
683 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000684 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000685 */
686xmlNsPtr
687xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
688 xmlNsPtr cur;
689
690 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
691 return(NULL);
692
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000693 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
694 return(NULL);
695
Owen Taylor3473f882001-02-23 17:55:21 +0000696 /*
697 * Allocate a new Namespace and fill the fields.
698 */
699 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
700 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000701 xmlTreeErrMemory("building namespace");
Owen Taylor3473f882001-02-23 17:55:21 +0000702 return(NULL);
703 }
704 memset(cur, 0, sizeof(xmlNs));
705 cur->type = XML_LOCAL_NAMESPACE;
706
707 if (href != NULL)
708 cur->href = xmlStrdup(href);
709 if (prefix != NULL)
710 cur->prefix = xmlStrdup(prefix);
711
712 /*
713 * Add it at the end to preserve parsing order ...
714 * and checks for existing use of the prefix
715 */
716 if (node != NULL) {
717 if (node->nsDef == NULL) {
718 node->nsDef = cur;
719 } else {
720 xmlNsPtr prev = node->nsDef;
721
722 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
723 (xmlStrEqual(prev->prefix, cur->prefix))) {
724 xmlFreeNs(cur);
725 return(NULL);
726 }
727 while (prev->next != NULL) {
728 prev = prev->next;
729 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
730 (xmlStrEqual(prev->prefix, cur->prefix))) {
731 xmlFreeNs(cur);
732 return(NULL);
733 }
734 }
735 prev->next = cur;
736 }
737 }
738 return(cur);
739}
740
741/**
742 * xmlSetNs:
743 * @node: a node in the document
744 * @ns: a namespace pointer
745 *
746 * Associate a namespace to a node, a posteriori.
747 */
748void
749xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
750 if (node == NULL) {
751#ifdef DEBUG_TREE
752 xmlGenericError(xmlGenericErrorContext,
753 "xmlSetNs: node == NULL\n");
754#endif
755 return;
756 }
757 node->ns = ns;
758}
759
760/**
761 * xmlFreeNs:
762 * @cur: the namespace pointer
763 *
764 * Free up the structures associated to a namespace
765 */
766void
767xmlFreeNs(xmlNsPtr cur) {
768 if (cur == NULL) {
769#ifdef DEBUG_TREE
770 xmlGenericError(xmlGenericErrorContext,
771 "xmlFreeNs : ns == NULL\n");
772#endif
773 return;
774 }
775 if (cur->href != NULL) xmlFree((char *) cur->href);
776 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000777 xmlFree(cur);
778}
779
780/**
781 * xmlFreeNsList:
782 * @cur: the first namespace pointer
783 *
784 * Free up all the structures associated to the chained namespaces.
785 */
786void
787xmlFreeNsList(xmlNsPtr cur) {
788 xmlNsPtr next;
789 if (cur == NULL) {
790#ifdef DEBUG_TREE
791 xmlGenericError(xmlGenericErrorContext,
792 "xmlFreeNsList : ns == NULL\n");
793#endif
794 return;
795 }
796 while (cur != NULL) {
797 next = cur->next;
798 xmlFreeNs(cur);
799 cur = next;
800 }
801}
802
803/**
804 * xmlNewDtd:
805 * @doc: the document pointer
806 * @name: the DTD name
807 * @ExternalID: the external ID
808 * @SystemID: the system ID
809 *
810 * Creation of a new DTD for the external subset. To create an
811 * internal subset, use xmlCreateIntSubset().
812 *
813 * Returns a pointer to the new DTD structure
814 */
815xmlDtdPtr
816xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
817 const xmlChar *ExternalID, const xmlChar *SystemID) {
818 xmlDtdPtr cur;
819
820 if ((doc != NULL) && (doc->extSubset != NULL)) {
821#ifdef DEBUG_TREE
822 xmlGenericError(xmlGenericErrorContext,
823 "xmlNewDtd(%s): document %s already have a DTD %s\n",
824 /* !!! */ (char *) name, doc->name,
825 /* !!! */ (char *)doc->extSubset->name);
826#endif
827 return(NULL);
828 }
829
830 /*
831 * Allocate a new DTD and fill the fields.
832 */
833 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
834 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000835 xmlTreeErrMemory("building DTD");
Owen Taylor3473f882001-02-23 17:55:21 +0000836 return(NULL);
837 }
838 memset(cur, 0 , sizeof(xmlDtd));
839 cur->type = XML_DTD_NODE;
840
841 if (name != NULL)
842 cur->name = xmlStrdup(name);
843 if (ExternalID != NULL)
844 cur->ExternalID = xmlStrdup(ExternalID);
845 if (SystemID != NULL)
846 cur->SystemID = xmlStrdup(SystemID);
847 if (doc != NULL)
848 doc->extSubset = cur;
849 cur->doc = doc;
850
Daniel Veillarda880b122003-04-21 21:36:41 +0000851 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000852 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000853 return(cur);
854}
855
856/**
857 * xmlGetIntSubset:
858 * @doc: the document pointer
859 *
860 * Get the internal subset of a document
861 * Returns a pointer to the DTD structure or NULL if not found
862 */
863
864xmlDtdPtr
865xmlGetIntSubset(xmlDocPtr doc) {
866 xmlNodePtr cur;
867
868 if (doc == NULL)
869 return(NULL);
870 cur = doc->children;
871 while (cur != NULL) {
872 if (cur->type == XML_DTD_NODE)
873 return((xmlDtdPtr) cur);
874 cur = cur->next;
875 }
876 return((xmlDtdPtr) doc->intSubset);
877}
878
879/**
880 * xmlCreateIntSubset:
881 * @doc: the document pointer
882 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000883 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000884 * @SystemID: the system ID
885 *
886 * Create the internal subset of a document
887 * Returns a pointer to the new DTD structure
888 */
889xmlDtdPtr
890xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
891 const xmlChar *ExternalID, const xmlChar *SystemID) {
892 xmlDtdPtr cur;
893
894 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
895#ifdef DEBUG_TREE
896 xmlGenericError(xmlGenericErrorContext,
897
898 "xmlCreateIntSubset(): document %s already have an internal subset\n",
899 doc->name);
900#endif
901 return(NULL);
902 }
903
904 /*
905 * Allocate a new DTD and fill the fields.
906 */
907 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
908 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000909 xmlTreeErrMemory("building internal subset");
Owen Taylor3473f882001-02-23 17:55:21 +0000910 return(NULL);
911 }
912 memset(cur, 0, sizeof(xmlDtd));
913 cur->type = XML_DTD_NODE;
914
William M. Bracka3215c72004-07-31 16:24:01 +0000915 if (name != NULL) {
916 cur->name = xmlStrdup(name);
917 if (cur->name == NULL) {
918 xmlTreeErrMemory("building internal subset");
919 xmlFree(cur);
920 return(NULL);
921 }
922 }
923 if (ExternalID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000924 cur->ExternalID = xmlStrdup(ExternalID);
William M. Bracka3215c72004-07-31 16:24:01 +0000925 if (cur->ExternalID == NULL) {
926 xmlTreeErrMemory("building internal subset");
927 if (cur->name != NULL)
928 xmlFree((char *)cur->name);
929 xmlFree(cur);
930 return(NULL);
931 }
932 }
933 if (SystemID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000934 cur->SystemID = xmlStrdup(SystemID);
William M. Bracka3215c72004-07-31 16:24:01 +0000935 if (cur->SystemID == NULL) {
936 xmlTreeErrMemory("building internal subset");
937 if (cur->name != NULL)
938 xmlFree((char *)cur->name);
939 if (cur->ExternalID != NULL)
940 xmlFree((char *)cur->ExternalID);
941 xmlFree(cur);
942 return(NULL);
943 }
944 }
Owen Taylor3473f882001-02-23 17:55:21 +0000945 if (doc != NULL) {
946 doc->intSubset = cur;
947 cur->parent = doc;
948 cur->doc = doc;
949 if (doc->children == NULL) {
950 doc->children = (xmlNodePtr) cur;
951 doc->last = (xmlNodePtr) cur;
952 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000953 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000954 xmlNodePtr prev;
955
Owen Taylor3473f882001-02-23 17:55:21 +0000956 prev = doc->children;
957 prev->prev = (xmlNodePtr) cur;
958 cur->next = prev;
959 doc->children = (xmlNodePtr) cur;
960 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000961 xmlNodePtr next;
962
963 next = doc->children;
964 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
965 next = next->next;
966 if (next == NULL) {
967 cur->prev = doc->last;
968 cur->prev->next = (xmlNodePtr) cur;
969 cur->next = NULL;
970 doc->last = (xmlNodePtr) cur;
971 } else {
972 cur->next = next;
973 cur->prev = next->prev;
974 if (cur->prev == NULL)
975 doc->children = (xmlNodePtr) cur;
976 else
977 cur->prev->next = (xmlNodePtr) cur;
978 next->prev = (xmlNodePtr) cur;
979 }
Owen Taylor3473f882001-02-23 17:55:21 +0000980 }
981 }
982 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000983
Daniel Veillarda880b122003-04-21 21:36:41 +0000984 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000985 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000986 return(cur);
987}
988
989/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000990 * DICT_FREE:
991 * @str: a string
992 *
993 * Free a string if it is not owned by the "dict" dictionnary in the
994 * current scope
995 */
996#define DICT_FREE(str) \
997 if ((str) && ((!dict) || \
998 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
999 xmlFree((char *)(str));
1000
1001/**
Owen Taylor3473f882001-02-23 17:55:21 +00001002 * xmlFreeDtd:
1003 * @cur: the DTD structure to free up
1004 *
1005 * Free a DTD structure.
1006 */
1007void
1008xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001009 xmlDictPtr dict = NULL;
1010
Owen Taylor3473f882001-02-23 17:55:21 +00001011 if (cur == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001012 return;
1013 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001014 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001015
Daniel Veillarda880b122003-04-21 21:36:41 +00001016 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001017 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1018
Owen Taylor3473f882001-02-23 17:55:21 +00001019 if (cur->children != NULL) {
1020 xmlNodePtr next, c = cur->children;
1021
1022 /*
William M. Brack18a04f22004-08-03 16:42:37 +00001023 * Cleanup all nodes which are not part of the specific lists
1024 * of notations, elements, attributes and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00001025 */
1026 while (c != NULL) {
1027 next = c->next;
William M. Brack18a04f22004-08-03 16:42:37 +00001028 if ((c->type != XML_NOTATION_NODE) &&
1029 (c->type != XML_ELEMENT_DECL) &&
1030 (c->type != XML_ATTRIBUTE_DECL) &&
1031 (c->type != XML_ENTITY_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001032 xmlUnlinkNode(c);
1033 xmlFreeNode(c);
1034 }
1035 c = next;
1036 }
1037 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001038 DICT_FREE(cur->name)
1039 DICT_FREE(cur->SystemID)
1040 DICT_FREE(cur->ExternalID)
Owen Taylor3473f882001-02-23 17:55:21 +00001041 /* TODO !!! */
1042 if (cur->notations != NULL)
1043 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1044
1045 if (cur->elements != NULL)
1046 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1047 if (cur->attributes != NULL)
1048 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1049 if (cur->entities != NULL)
1050 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1051 if (cur->pentities != NULL)
1052 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1053
Owen Taylor3473f882001-02-23 17:55:21 +00001054 xmlFree(cur);
1055}
1056
1057/**
1058 * xmlNewDoc:
1059 * @version: xmlChar string giving the version of XML "1.0"
1060 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001061 * Creates a new XML document
1062 *
Owen Taylor3473f882001-02-23 17:55:21 +00001063 * Returns a new document
1064 */
1065xmlDocPtr
1066xmlNewDoc(const xmlChar *version) {
1067 xmlDocPtr cur;
1068
1069 if (version == NULL)
1070 version = (const xmlChar *) "1.0";
1071
1072 /*
1073 * Allocate a new document and fill the fields.
1074 */
1075 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1076 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001077 xmlTreeErrMemory("building doc");
Owen Taylor3473f882001-02-23 17:55:21 +00001078 return(NULL);
1079 }
1080 memset(cur, 0, sizeof(xmlDoc));
1081 cur->type = XML_DOCUMENT_NODE;
1082
1083 cur->version = xmlStrdup(version);
William M. Bracka3215c72004-07-31 16:24:01 +00001084 if (cur->version == NULL) {
1085 xmlTreeErrMemory("building doc");
1086 xmlFree(cur);
1087 return(NULL);
1088 }
Owen Taylor3473f882001-02-23 17:55:21 +00001089 cur->standalone = -1;
1090 cur->compression = -1; /* not initialized */
1091 cur->doc = cur;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001092 /*
1093 * The in memory encoding is always UTF8
1094 * This field will never change and would
1095 * be obsolete if not for binary compatibility.
1096 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001097 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001098
Daniel Veillarda880b122003-04-21 21:36:41 +00001099 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001100 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001101 return(cur);
1102}
1103
1104/**
1105 * xmlFreeDoc:
1106 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001107 *
1108 * Free up all the structures used by a document, tree included.
1109 */
1110void
1111xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001112 xmlDtdPtr extSubset, intSubset;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001113 xmlDictPtr dict = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001114
Owen Taylor3473f882001-02-23 17:55:21 +00001115 if (cur == NULL) {
1116#ifdef DEBUG_TREE
1117 xmlGenericError(xmlGenericErrorContext,
1118 "xmlFreeDoc : document == NULL\n");
1119#endif
1120 return;
1121 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001122 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001123
Daniel Veillarda880b122003-04-21 21:36:41 +00001124 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001125 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1126
Daniel Veillard76d66f42001-05-16 21:05:17 +00001127 /*
1128 * Do this before freeing the children list to avoid ID lookups
1129 */
1130 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1131 cur->ids = NULL;
1132 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1133 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001134 extSubset = cur->extSubset;
1135 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001136 if (intSubset == extSubset)
1137 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001138 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001139 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001140 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001141 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001142 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001143 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001144 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001145 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001146 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001147 }
1148
1149 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001150 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001151
1152 DICT_FREE(cur->version)
1153 DICT_FREE(cur->name)
1154 DICT_FREE(cur->encoding)
1155 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001156 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001157 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001158}
1159
1160/**
1161 * xmlStringLenGetNodeList:
1162 * @doc: the document
1163 * @value: the value of the text
1164 * @len: the length of the string value
1165 *
1166 * Parse the value string and build the node list associated. Should
1167 * produce a flat tree with only TEXTs and ENTITY_REFs.
1168 * Returns a pointer to the first child
1169 */
1170xmlNodePtr
1171xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1172 xmlNodePtr ret = NULL, last = NULL;
1173 xmlNodePtr node;
1174 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001175 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001176 const xmlChar *q;
1177 xmlEntityPtr ent;
1178
1179 if (value == NULL) return(NULL);
1180
1181 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001182 while ((cur < end) && (*cur != 0)) {
1183 if (cur[0] == '&') {
1184 int charval = 0;
1185 xmlChar tmp;
1186
Owen Taylor3473f882001-02-23 17:55:21 +00001187 /*
1188 * Save the current text.
1189 */
1190 if (cur != q) {
1191 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1192 xmlNodeAddContentLen(last, q, cur - q);
1193 } else {
1194 node = xmlNewDocTextLen(doc, q, cur - q);
1195 if (node == NULL) return(ret);
1196 if (last == NULL)
1197 last = ret = node;
1198 else {
1199 last->next = node;
1200 node->prev = last;
1201 last = node;
1202 }
1203 }
1204 }
Owen Taylor3473f882001-02-23 17:55:21 +00001205 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001206 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1207 cur += 3;
1208 if (cur < end)
1209 tmp = *cur;
1210 else
1211 tmp = 0;
1212 while (tmp != ';') { /* Non input consuming loop */
1213 if ((tmp >= '0') && (tmp <= '9'))
1214 charval = charval * 16 + (tmp - '0');
1215 else if ((tmp >= 'a') && (tmp <= 'f'))
1216 charval = charval * 16 + (tmp - 'a') + 10;
1217 else if ((tmp >= 'A') && (tmp <= 'F'))
1218 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001219 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001220 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1221 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001222 charval = 0;
1223 break;
1224 }
1225 cur++;
1226 if (cur < end)
1227 tmp = *cur;
1228 else
1229 tmp = 0;
1230 }
1231 if (tmp == ';')
1232 cur++;
1233 q = cur;
1234 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1235 cur += 2;
1236 if (cur < end)
1237 tmp = *cur;
1238 else
1239 tmp = 0;
1240 while (tmp != ';') { /* Non input consuming loops */
1241 if ((tmp >= '0') && (tmp <= '9'))
1242 charval = charval * 10 + (tmp - '0');
1243 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001244 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1245 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001246 charval = 0;
1247 break;
1248 }
1249 cur++;
1250 if (cur < end)
1251 tmp = *cur;
1252 else
1253 tmp = 0;
1254 }
1255 if (tmp == ';')
1256 cur++;
1257 q = cur;
1258 } else {
1259 /*
1260 * Read the entity string
1261 */
1262 cur++;
1263 q = cur;
1264 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1265 if ((cur >= end) || (*cur == 0)) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001266 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1267 (const char *) q);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001268 return(ret);
1269 }
1270 if (cur != q) {
1271 /*
1272 * Predefined entities don't generate nodes
1273 */
1274 val = xmlStrndup(q, cur - q);
1275 ent = xmlGetDocEntity(doc, val);
1276 if ((ent != NULL) &&
1277 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1278 if (last == NULL) {
1279 node = xmlNewDocText(doc, ent->content);
1280 last = ret = node;
1281 } else if (last->type != XML_TEXT_NODE) {
1282 node = xmlNewDocText(doc, ent->content);
1283 last = xmlAddNextSibling(last, node);
1284 } else
1285 xmlNodeAddContent(last, ent->content);
1286
1287 } else {
1288 /*
1289 * Create a new REFERENCE_REF node
1290 */
1291 node = xmlNewReference(doc, val);
1292 if (node == NULL) {
1293 if (val != NULL) xmlFree(val);
1294 return(ret);
1295 }
1296 else if ((ent != NULL) && (ent->children == NULL)) {
1297 xmlNodePtr temp;
1298
1299 ent->children = xmlStringGetNodeList(doc,
1300 (const xmlChar*)node->content);
1301 ent->owner = 1;
1302 temp = ent->children;
1303 while (temp) {
1304 temp->parent = (xmlNodePtr)ent;
1305 temp = temp->next;
1306 }
1307 }
1308 if (last == NULL) {
1309 last = ret = node;
1310 } else {
1311 last = xmlAddNextSibling(last, node);
1312 }
1313 }
1314 xmlFree(val);
1315 }
1316 cur++;
1317 q = cur;
1318 }
1319 if (charval != 0) {
1320 xmlChar buf[10];
1321 int l;
1322
1323 l = xmlCopyCharMultiByte(buf, charval);
1324 buf[l] = 0;
1325 node = xmlNewDocText(doc, buf);
1326 if (node != NULL) {
1327 if (last == NULL) {
1328 last = ret = node;
1329 } else {
1330 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001331 }
1332 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001333 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001334 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001335 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001336 cur++;
1337 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001338 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001339 /*
1340 * Handle the last piece of text.
1341 */
1342 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1343 xmlNodeAddContentLen(last, q, cur - q);
1344 } else {
1345 node = xmlNewDocTextLen(doc, q, cur - q);
1346 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001347 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001348 last = ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001349 } else {
1350 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001351 }
1352 }
1353 }
1354 return(ret);
1355}
1356
1357/**
1358 * xmlStringGetNodeList:
1359 * @doc: the document
1360 * @value: the value of the attribute
1361 *
1362 * Parse the value string and build the node list associated. Should
1363 * produce a flat tree with only TEXTs and ENTITY_REFs.
1364 * Returns a pointer to the first child
1365 */
1366xmlNodePtr
1367xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1368 xmlNodePtr ret = NULL, last = NULL;
1369 xmlNodePtr node;
1370 xmlChar *val;
1371 const xmlChar *cur = value;
1372 const xmlChar *q;
1373 xmlEntityPtr ent;
1374
1375 if (value == NULL) return(NULL);
1376
1377 q = cur;
1378 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001379 if (cur[0] == '&') {
1380 int charval = 0;
1381 xmlChar tmp;
1382
Owen Taylor3473f882001-02-23 17:55:21 +00001383 /*
1384 * Save the current text.
1385 */
1386 if (cur != q) {
1387 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1388 xmlNodeAddContentLen(last, q, cur - q);
1389 } else {
1390 node = xmlNewDocTextLen(doc, q, cur - q);
1391 if (node == NULL) return(ret);
1392 if (last == NULL)
1393 last = ret = node;
1394 else {
1395 last->next = node;
1396 node->prev = last;
1397 last = node;
1398 }
1399 }
1400 }
Owen Taylor3473f882001-02-23 17:55:21 +00001401 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001402 if ((cur[1] == '#') && (cur[2] == 'x')) {
1403 cur += 3;
1404 tmp = *cur;
1405 while (tmp != ';') { /* Non input consuming loop */
1406 if ((tmp >= '0') && (tmp <= '9'))
1407 charval = charval * 16 + (tmp - '0');
1408 else if ((tmp >= 'a') && (tmp <= 'f'))
1409 charval = charval * 16 + (tmp - 'a') + 10;
1410 else if ((tmp >= 'A') && (tmp <= 'F'))
1411 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001412 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001413 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1414 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001415 charval = 0;
1416 break;
1417 }
1418 cur++;
1419 tmp = *cur;
1420 }
1421 if (tmp == ';')
1422 cur++;
1423 q = cur;
1424 } else if (cur[1] == '#') {
1425 cur += 2;
1426 tmp = *cur;
1427 while (tmp != ';') { /* Non input consuming loops */
1428 if ((tmp >= '0') && (tmp <= '9'))
1429 charval = charval * 10 + (tmp - '0');
1430 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001431 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1432 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001433 charval = 0;
1434 break;
1435 }
1436 cur++;
1437 tmp = *cur;
1438 }
1439 if (tmp == ';')
1440 cur++;
1441 q = cur;
1442 } else {
1443 /*
1444 * Read the entity string
1445 */
1446 cur++;
1447 q = cur;
1448 while ((*cur != 0) && (*cur != ';')) cur++;
1449 if (*cur == 0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001450 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1451 (xmlNodePtr) doc, (const char *) q);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001452 return(ret);
1453 }
1454 if (cur != q) {
1455 /*
1456 * Predefined entities don't generate nodes
1457 */
1458 val = xmlStrndup(q, cur - q);
1459 ent = xmlGetDocEntity(doc, val);
1460 if ((ent != NULL) &&
1461 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1462 if (last == NULL) {
1463 node = xmlNewDocText(doc, ent->content);
1464 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001465 } else if (last->type != XML_TEXT_NODE) {
1466 node = xmlNewDocText(doc, ent->content);
1467 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001468 } else
1469 xmlNodeAddContent(last, ent->content);
1470
1471 } else {
1472 /*
1473 * Create a new REFERENCE_REF node
1474 */
1475 node = xmlNewReference(doc, val);
1476 if (node == NULL) {
1477 if (val != NULL) xmlFree(val);
1478 return(ret);
1479 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001480 else if ((ent != NULL) && (ent->children == NULL)) {
1481 xmlNodePtr temp;
1482
1483 ent->children = xmlStringGetNodeList(doc,
1484 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001485 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001486 temp = ent->children;
1487 while (temp) {
1488 temp->parent = (xmlNodePtr)ent;
1489 temp = temp->next;
1490 }
1491 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001492 if (last == NULL) {
1493 last = ret = node;
1494 } else {
1495 last = xmlAddNextSibling(last, node);
1496 }
1497 }
1498 xmlFree(val);
1499 }
1500 cur++;
1501 q = cur;
1502 }
1503 if (charval != 0) {
1504 xmlChar buf[10];
1505 int len;
1506
1507 len = xmlCopyCharMultiByte(buf, charval);
1508 buf[len] = 0;
1509 node = xmlNewDocText(doc, buf);
1510 if (node != NULL) {
1511 if (last == NULL) {
1512 last = ret = node;
1513 } else {
1514 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001515 }
1516 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001517
1518 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001519 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001520 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001521 cur++;
1522 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001523 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001524 /*
1525 * Handle the last piece of text.
1526 */
1527 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1528 xmlNodeAddContentLen(last, q, cur - q);
1529 } else {
1530 node = xmlNewDocTextLen(doc, q, cur - q);
1531 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001532 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001533 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001534 } else {
1535 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001536 }
1537 }
1538 }
1539 return(ret);
1540}
1541
1542/**
1543 * xmlNodeListGetString:
1544 * @doc: the document
1545 * @list: a Node list
1546 * @inLine: should we replace entity contents or show their external form
1547 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001548 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001549 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001550 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001551 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001552 */
1553xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001554xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1555{
Owen Taylor3473f882001-02-23 17:55:21 +00001556 xmlNodePtr node = list;
1557 xmlChar *ret = NULL;
1558 xmlEntityPtr ent;
1559
Daniel Veillard7646b182002-04-20 06:41:40 +00001560 if (list == NULL)
1561 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001562
1563 while (node != NULL) {
1564 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001565 (node->type == XML_CDATA_SECTION_NODE)) {
1566 if (inLine) {
1567 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001568 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001569 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001570
Daniel Veillard7646b182002-04-20 06:41:40 +00001571 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1572 if (buffer != NULL) {
1573 ret = xmlStrcat(ret, buffer);
1574 xmlFree(buffer);
1575 }
1576 }
1577 } else if (node->type == XML_ENTITY_REF_NODE) {
1578 if (inLine) {
1579 ent = xmlGetDocEntity(doc, node->name);
1580 if (ent != NULL) {
1581 xmlChar *buffer;
1582
1583 /* an entity content can be any "well balanced chunk",
1584 * i.e. the result of the content [43] production:
1585 * http://www.w3.org/TR/REC-xml#NT-content.
1586 * So it can contain text, CDATA section or nested
1587 * entity reference nodes (among others).
1588 * -> we recursive call xmlNodeListGetString()
1589 * which handles these types */
1590 buffer = xmlNodeListGetString(doc, ent->children, 1);
1591 if (buffer != NULL) {
1592 ret = xmlStrcat(ret, buffer);
1593 xmlFree(buffer);
1594 }
1595 } else {
1596 ret = xmlStrcat(ret, node->content);
1597 }
1598 } else {
1599 xmlChar buf[2];
1600
1601 buf[0] = '&';
1602 buf[1] = 0;
1603 ret = xmlStrncat(ret, buf, 1);
1604 ret = xmlStrcat(ret, node->name);
1605 buf[0] = ';';
1606 buf[1] = 0;
1607 ret = xmlStrncat(ret, buf, 1);
1608 }
1609 }
1610#if 0
1611 else {
1612 xmlGenericError(xmlGenericErrorContext,
1613 "xmlGetNodeListString : invalid node type %d\n",
1614 node->type);
1615 }
1616#endif
1617 node = node->next;
1618 }
1619 return (ret);
1620}
Daniel Veillard652327a2003-09-29 18:02:38 +00001621
1622#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001623/**
1624 * xmlNodeListGetRawString:
1625 * @doc: the document
1626 * @list: a Node list
1627 * @inLine: should we replace entity contents or show their external form
1628 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001629 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001630 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1631 * this function doesn't do any character encoding handling.
1632 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001633 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001634 */
1635xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001636xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1637{
Owen Taylor3473f882001-02-23 17:55:21 +00001638 xmlNodePtr node = list;
1639 xmlChar *ret = NULL;
1640 xmlEntityPtr ent;
1641
Daniel Veillard7646b182002-04-20 06:41:40 +00001642 if (list == NULL)
1643 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001644
1645 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001646 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001647 (node->type == XML_CDATA_SECTION_NODE)) {
1648 if (inLine) {
1649 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001650 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001651 xmlChar *buffer;
1652
1653 buffer = xmlEncodeSpecialChars(doc, node->content);
1654 if (buffer != NULL) {
1655 ret = xmlStrcat(ret, buffer);
1656 xmlFree(buffer);
1657 }
1658 }
1659 } else if (node->type == XML_ENTITY_REF_NODE) {
1660 if (inLine) {
1661 ent = xmlGetDocEntity(doc, node->name);
1662 if (ent != NULL) {
1663 xmlChar *buffer;
1664
1665 /* an entity content can be any "well balanced chunk",
1666 * i.e. the result of the content [43] production:
1667 * http://www.w3.org/TR/REC-xml#NT-content.
1668 * So it can contain text, CDATA section or nested
1669 * entity reference nodes (among others).
1670 * -> we recursive call xmlNodeListGetRawString()
1671 * which handles these types */
1672 buffer =
1673 xmlNodeListGetRawString(doc, ent->children, 1);
1674 if (buffer != NULL) {
1675 ret = xmlStrcat(ret, buffer);
1676 xmlFree(buffer);
1677 }
1678 } else {
1679 ret = xmlStrcat(ret, node->content);
1680 }
1681 } else {
1682 xmlChar buf[2];
1683
1684 buf[0] = '&';
1685 buf[1] = 0;
1686 ret = xmlStrncat(ret, buf, 1);
1687 ret = xmlStrcat(ret, node->name);
1688 buf[0] = ';';
1689 buf[1] = 0;
1690 ret = xmlStrncat(ret, buf, 1);
1691 }
1692 }
Owen Taylor3473f882001-02-23 17:55:21 +00001693#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001694 else {
1695 xmlGenericError(xmlGenericErrorContext,
1696 "xmlGetNodeListString : invalid node type %d\n",
1697 node->type);
1698 }
Owen Taylor3473f882001-02-23 17:55:21 +00001699#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001700 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001701 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001702 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001703}
Daniel Veillard652327a2003-09-29 18:02:38 +00001704#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001705
Daniel Veillard2156d432004-03-04 15:59:36 +00001706#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00001707/**
1708 * xmlNewProp:
1709 * @node: the holding node
1710 * @name: the name of the attribute
1711 * @value: the value of the attribute
1712 *
1713 * Create a new property carried by a node.
1714 * Returns a pointer to the attribute
1715 */
1716xmlAttrPtr
1717xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1718 xmlAttrPtr cur;
1719 xmlDocPtr doc = NULL;
1720
1721 if (name == NULL) {
1722#ifdef DEBUG_TREE
1723 xmlGenericError(xmlGenericErrorContext,
1724 "xmlNewProp : name == NULL\n");
1725#endif
1726 return(NULL);
1727 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001728 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1729 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001730
1731 /*
1732 * Allocate a new property and fill the fields.
1733 */
1734 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1735 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001736 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001737 return(NULL);
1738 }
1739 memset(cur, 0, sizeof(xmlAttr));
1740 cur->type = XML_ATTRIBUTE_NODE;
1741
1742 cur->parent = node;
1743 if (node != NULL) {
1744 doc = node->doc;
1745 cur->doc = doc;
1746 }
1747 cur->name = xmlStrdup(name);
1748 if (value != NULL) {
1749 xmlChar *buffer;
1750 xmlNodePtr tmp;
1751
1752 buffer = xmlEncodeEntitiesReentrant(doc, value);
1753 cur->children = xmlStringGetNodeList(doc, buffer);
1754 cur->last = NULL;
1755 tmp = cur->children;
1756 while (tmp != NULL) {
1757 tmp->parent = (xmlNodePtr) cur;
1758 tmp->doc = doc;
1759 if (tmp->next == NULL)
1760 cur->last = tmp;
1761 tmp = tmp->next;
1762 }
1763 xmlFree(buffer);
1764 }
1765
1766 /*
1767 * Add it at the end to preserve parsing order ...
1768 */
1769 if (node != NULL) {
1770 if (node->properties == NULL) {
1771 node->properties = cur;
1772 } else {
1773 xmlAttrPtr prev = node->properties;
1774
1775 while (prev->next != NULL) prev = prev->next;
1776 prev->next = cur;
1777 cur->prev = prev;
1778 }
1779 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001780
Daniel Veillarda880b122003-04-21 21:36:41 +00001781 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001782 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001783 return(cur);
1784}
Daniel Veillard652327a2003-09-29 18:02:38 +00001785#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001786
1787/**
1788 * xmlNewNsProp:
1789 * @node: the holding node
1790 * @ns: the namespace
1791 * @name: the name of the attribute
1792 * @value: the value of the attribute
1793 *
1794 * Create a new property tagged with a namespace and carried by a node.
1795 * Returns a pointer to the attribute
1796 */
1797xmlAttrPtr
1798xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1799 const xmlChar *value) {
1800 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001801 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001802
1803 if (name == NULL) {
1804#ifdef DEBUG_TREE
1805 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001806 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001807#endif
1808 return(NULL);
1809 }
1810
1811 /*
1812 * Allocate a new property and fill the fields.
1813 */
1814 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1815 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001816 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001817 return(NULL);
1818 }
1819 memset(cur, 0, sizeof(xmlAttr));
1820 cur->type = XML_ATTRIBUTE_NODE;
1821
1822 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001823 if (node != NULL) {
1824 doc = node->doc;
1825 cur->doc = doc;
1826 }
Owen Taylor3473f882001-02-23 17:55:21 +00001827 cur->ns = ns;
1828 cur->name = xmlStrdup(name);
1829 if (value != NULL) {
1830 xmlChar *buffer;
1831 xmlNodePtr tmp;
1832
Daniel Veillarda682b212001-06-07 19:59:42 +00001833 buffer = xmlEncodeEntitiesReentrant(doc, value);
1834 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001835 cur->last = NULL;
1836 tmp = cur->children;
1837 while (tmp != NULL) {
1838 tmp->parent = (xmlNodePtr) cur;
1839 if (tmp->next == NULL)
1840 cur->last = tmp;
1841 tmp = tmp->next;
1842 }
1843 xmlFree(buffer);
1844 }
1845
1846 /*
1847 * Add it at the end to preserve parsing order ...
1848 */
1849 if (node != NULL) {
1850 if (node->properties == NULL) {
1851 node->properties = cur;
1852 } else {
1853 xmlAttrPtr prev = node->properties;
1854
1855 while (prev->next != NULL) prev = prev->next;
1856 prev->next = cur;
1857 cur->prev = prev;
1858 }
1859 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001860
Daniel Veillarda880b122003-04-21 21:36:41 +00001861 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001862 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001863 return(cur);
1864}
1865
1866/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001867 * xmlNewNsPropEatName:
1868 * @node: the holding node
1869 * @ns: the namespace
1870 * @name: the name of the attribute
1871 * @value: the value of the attribute
1872 *
1873 * Create a new property tagged with a namespace and carried by a node.
1874 * Returns a pointer to the attribute
1875 */
1876xmlAttrPtr
1877xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1878 const xmlChar *value) {
1879 xmlAttrPtr cur;
1880 xmlDocPtr doc = NULL;
1881
1882 if (name == NULL) {
1883#ifdef DEBUG_TREE
1884 xmlGenericError(xmlGenericErrorContext,
1885 "xmlNewNsPropEatName : name == NULL\n");
1886#endif
1887 return(NULL);
1888 }
1889
1890 /*
1891 * Allocate a new property and fill the fields.
1892 */
1893 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1894 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001895 xmlTreeErrMemory("building attribute");
Daniel Veillard46de64e2002-05-29 08:21:33 +00001896 return(NULL);
1897 }
1898 memset(cur, 0, sizeof(xmlAttr));
1899 cur->type = XML_ATTRIBUTE_NODE;
1900
1901 cur->parent = node;
1902 if (node != NULL) {
1903 doc = node->doc;
1904 cur->doc = doc;
1905 }
1906 cur->ns = ns;
1907 cur->name = name;
1908 if (value != NULL) {
1909 xmlChar *buffer;
1910 xmlNodePtr tmp;
1911
1912 buffer = xmlEncodeEntitiesReentrant(doc, value);
1913 cur->children = xmlStringGetNodeList(doc, buffer);
1914 cur->last = NULL;
1915 tmp = cur->children;
1916 while (tmp != NULL) {
1917 tmp->parent = (xmlNodePtr) cur;
1918 if (tmp->next == NULL)
1919 cur->last = tmp;
1920 tmp = tmp->next;
1921 }
1922 xmlFree(buffer);
1923 }
1924
1925 /*
1926 * Add it at the end to preserve parsing order ...
1927 */
1928 if (node != NULL) {
1929 if (node->properties == NULL) {
1930 node->properties = cur;
1931 } else {
1932 xmlAttrPtr prev = node->properties;
1933
1934 while (prev->next != NULL) prev = prev->next;
1935 prev->next = cur;
1936 cur->prev = prev;
1937 }
1938 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001939
Daniel Veillarda880b122003-04-21 21:36:41 +00001940 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001941 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001942 return(cur);
1943}
1944
1945/**
Owen Taylor3473f882001-02-23 17:55:21 +00001946 * xmlNewDocProp:
1947 * @doc: the document
1948 * @name: the name of the attribute
1949 * @value: the value of the attribute
1950 *
1951 * Create a new property carried by a document.
1952 * Returns a pointer to the attribute
1953 */
1954xmlAttrPtr
1955xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1956 xmlAttrPtr cur;
1957
1958 if (name == NULL) {
1959#ifdef DEBUG_TREE
1960 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001961 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001962#endif
1963 return(NULL);
1964 }
1965
1966 /*
1967 * Allocate a new property and fill the fields.
1968 */
1969 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1970 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001971 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001972 return(NULL);
1973 }
1974 memset(cur, 0, sizeof(xmlAttr));
1975 cur->type = XML_ATTRIBUTE_NODE;
1976
1977 cur->name = xmlStrdup(name);
1978 cur->doc = doc;
1979 if (value != NULL) {
1980 xmlNodePtr tmp;
1981
1982 cur->children = xmlStringGetNodeList(doc, value);
1983 cur->last = NULL;
1984
1985 tmp = cur->children;
1986 while (tmp != NULL) {
1987 tmp->parent = (xmlNodePtr) cur;
1988 if (tmp->next == NULL)
1989 cur->last = tmp;
1990 tmp = tmp->next;
1991 }
1992 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001993
Daniel Veillarda880b122003-04-21 21:36:41 +00001994 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001995 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001996 return(cur);
1997}
1998
1999/**
2000 * xmlFreePropList:
2001 * @cur: the first property in the list
2002 *
2003 * Free a property and all its siblings, all the children are freed too.
2004 */
2005void
2006xmlFreePropList(xmlAttrPtr cur) {
2007 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002008 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002009 while (cur != NULL) {
2010 next = cur->next;
2011 xmlFreeProp(cur);
2012 cur = next;
2013 }
2014}
2015
2016/**
2017 * xmlFreeProp:
2018 * @cur: an attribute
2019 *
2020 * Free one attribute, all the content is freed too
2021 */
2022void
2023xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002024 xmlDictPtr dict = NULL;
2025 if (cur == NULL) return;
2026
2027 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002028
Daniel Veillarda880b122003-04-21 21:36:41 +00002029 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002030 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
2031
Owen Taylor3473f882001-02-23 17:55:21 +00002032 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00002033 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
2034 ((cur->parent->doc->intSubset != NULL) ||
2035 (cur->parent->doc->extSubset != NULL))) {
2036 if (xmlIsID(cur->parent->doc, cur->parent, cur))
2037 xmlRemoveID(cur->parent->doc, cur);
2038 }
Owen Taylor3473f882001-02-23 17:55:21 +00002039 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002040 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002041 xmlFree(cur);
2042}
2043
Daniel Veillard652327a2003-09-29 18:02:38 +00002044#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002045/**
2046 * xmlRemoveProp:
2047 * @cur: an attribute
2048 *
2049 * Unlink and free one attribute, all the content is freed too
2050 * Note this doesn't work for namespace definition attributes
2051 *
2052 * Returns 0 if success and -1 in case of error.
2053 */
2054int
2055xmlRemoveProp(xmlAttrPtr cur) {
2056 xmlAttrPtr tmp;
2057 if (cur == NULL) {
2058#ifdef DEBUG_TREE
2059 xmlGenericError(xmlGenericErrorContext,
2060 "xmlRemoveProp : cur == NULL\n");
2061#endif
2062 return(-1);
2063 }
2064 if (cur->parent == NULL) {
2065#ifdef DEBUG_TREE
2066 xmlGenericError(xmlGenericErrorContext,
2067 "xmlRemoveProp : cur->parent == NULL\n");
2068#endif
2069 return(-1);
2070 }
2071 tmp = cur->parent->properties;
2072 if (tmp == cur) {
2073 cur->parent->properties = cur->next;
2074 xmlFreeProp(cur);
2075 return(0);
2076 }
2077 while (tmp != NULL) {
2078 if (tmp->next == cur) {
2079 tmp->next = cur->next;
2080 if (tmp->next != NULL)
2081 tmp->next->prev = tmp;
2082 xmlFreeProp(cur);
2083 return(0);
2084 }
2085 tmp = tmp->next;
2086 }
2087#ifdef DEBUG_TREE
2088 xmlGenericError(xmlGenericErrorContext,
2089 "xmlRemoveProp : attribute not owned by its node\n");
2090#endif
2091 return(-1);
2092}
Daniel Veillard652327a2003-09-29 18:02:38 +00002093#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002094
2095/**
2096 * xmlNewPI:
2097 * @name: the processing instruction name
2098 * @content: the PI content
2099 *
2100 * Creation of a processing instruction element.
2101 * Returns a pointer to the new node object.
2102 */
2103xmlNodePtr
2104xmlNewPI(const xmlChar *name, const xmlChar *content) {
2105 xmlNodePtr cur;
2106
2107 if (name == NULL) {
2108#ifdef DEBUG_TREE
2109 xmlGenericError(xmlGenericErrorContext,
2110 "xmlNewPI : name == NULL\n");
2111#endif
2112 return(NULL);
2113 }
2114
2115 /*
2116 * Allocate a new node and fill the fields.
2117 */
2118 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2119 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002120 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002121 return(NULL);
2122 }
2123 memset(cur, 0, sizeof(xmlNode));
2124 cur->type = XML_PI_NODE;
2125
2126 cur->name = xmlStrdup(name);
2127 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002128 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002129 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002130
Daniel Veillarda880b122003-04-21 21:36:41 +00002131 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002132 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002133 return(cur);
2134}
2135
2136/**
2137 * xmlNewNode:
2138 * @ns: namespace if any
2139 * @name: the node name
2140 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002141 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002142 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002143 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2144 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002145 */
2146xmlNodePtr
2147xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2148 xmlNodePtr cur;
2149
2150 if (name == NULL) {
2151#ifdef DEBUG_TREE
2152 xmlGenericError(xmlGenericErrorContext,
2153 "xmlNewNode : name == NULL\n");
2154#endif
2155 return(NULL);
2156 }
2157
2158 /*
2159 * Allocate a new node and fill the fields.
2160 */
2161 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2162 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002163 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002164 return(NULL);
2165 }
2166 memset(cur, 0, sizeof(xmlNode));
2167 cur->type = XML_ELEMENT_NODE;
2168
2169 cur->name = xmlStrdup(name);
2170 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002171
Daniel Veillarda880b122003-04-21 21:36:41 +00002172 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002173 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002174 return(cur);
2175}
2176
2177/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002178 * xmlNewNodeEatName:
2179 * @ns: namespace if any
2180 * @name: the node name
2181 *
2182 * Creation of a new node element. @ns is optional (NULL).
2183 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002184 * Returns a pointer to the new node object, with pointer @name as
2185 * new node's name. Use xmlNewNode() if a copy of @name string is
2186 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002187 */
2188xmlNodePtr
2189xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2190 xmlNodePtr cur;
2191
2192 if (name == NULL) {
2193#ifdef DEBUG_TREE
2194 xmlGenericError(xmlGenericErrorContext,
2195 "xmlNewNode : name == NULL\n");
2196#endif
2197 return(NULL);
2198 }
2199
2200 /*
2201 * Allocate a new node and fill the fields.
2202 */
2203 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2204 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002205 xmlTreeErrMemory("building node");
Daniel Veillard46de64e2002-05-29 08:21:33 +00002206 return(NULL);
2207 }
2208 memset(cur, 0, sizeof(xmlNode));
2209 cur->type = XML_ELEMENT_NODE;
2210
2211 cur->name = name;
2212 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002213
Daniel Veillarda880b122003-04-21 21:36:41 +00002214 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002215 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002216 return(cur);
2217}
2218
2219/**
Owen Taylor3473f882001-02-23 17:55:21 +00002220 * xmlNewDocNode:
2221 * @doc: the document
2222 * @ns: namespace if any
2223 * @name: the node name
2224 * @content: the XML text content if any
2225 *
2226 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002227 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002228 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2229 * references, but XML special chars need to be escaped first by using
2230 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2231 * need entities support.
2232 *
2233 * Returns a pointer to the new node object.
2234 */
2235xmlNodePtr
2236xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2237 const xmlChar *name, const xmlChar *content) {
2238 xmlNodePtr cur;
2239
2240 cur = xmlNewNode(ns, name);
2241 if (cur != NULL) {
2242 cur->doc = doc;
2243 if (content != NULL) {
2244 cur->children = xmlStringGetNodeList(doc, content);
2245 UPDATE_LAST_CHILD_AND_PARENT(cur)
2246 }
2247 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002248
Owen Taylor3473f882001-02-23 17:55:21 +00002249 return(cur);
2250}
2251
Daniel Veillard46de64e2002-05-29 08:21:33 +00002252/**
2253 * xmlNewDocNodeEatName:
2254 * @doc: the document
2255 * @ns: namespace if any
2256 * @name: the node name
2257 * @content: the XML text content if any
2258 *
2259 * Creation of a new node element within a document. @ns and @content
2260 * are optional (NULL).
2261 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2262 * references, but XML special chars need to be escaped first by using
2263 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2264 * need entities support.
2265 *
2266 * Returns a pointer to the new node object.
2267 */
2268xmlNodePtr
2269xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2270 xmlChar *name, const xmlChar *content) {
2271 xmlNodePtr cur;
2272
2273 cur = xmlNewNodeEatName(ns, name);
2274 if (cur != NULL) {
2275 cur->doc = doc;
2276 if (content != NULL) {
2277 cur->children = xmlStringGetNodeList(doc, content);
2278 UPDATE_LAST_CHILD_AND_PARENT(cur)
2279 }
2280 }
2281 return(cur);
2282}
2283
Daniel Veillard652327a2003-09-29 18:02:38 +00002284#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002285/**
2286 * xmlNewDocRawNode:
2287 * @doc: the document
2288 * @ns: namespace if any
2289 * @name: the node name
2290 * @content: the text content if any
2291 *
2292 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002293 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002294 *
2295 * Returns a pointer to the new node object.
2296 */
2297xmlNodePtr
2298xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2299 const xmlChar *name, const xmlChar *content) {
2300 xmlNodePtr cur;
2301
2302 cur = xmlNewNode(ns, name);
2303 if (cur != NULL) {
2304 cur->doc = doc;
2305 if (content != NULL) {
2306 cur->children = xmlNewDocText(doc, content);
2307 UPDATE_LAST_CHILD_AND_PARENT(cur)
2308 }
2309 }
2310 return(cur);
2311}
2312
2313/**
2314 * xmlNewDocFragment:
2315 * @doc: the document owning the fragment
2316 *
2317 * Creation of a new Fragment node.
2318 * Returns a pointer to the new node object.
2319 */
2320xmlNodePtr
2321xmlNewDocFragment(xmlDocPtr doc) {
2322 xmlNodePtr cur;
2323
2324 /*
2325 * Allocate a new DocumentFragment node and fill the fields.
2326 */
2327 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2328 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002329 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002330 return(NULL);
2331 }
2332 memset(cur, 0, sizeof(xmlNode));
2333 cur->type = XML_DOCUMENT_FRAG_NODE;
2334
2335 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002336
Daniel Veillarda880b122003-04-21 21:36:41 +00002337 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002338 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002339 return(cur);
2340}
Daniel Veillard652327a2003-09-29 18:02:38 +00002341#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002342
2343/**
2344 * xmlNewText:
2345 * @content: the text content
2346 *
2347 * Creation of a new text node.
2348 * Returns a pointer to the new node object.
2349 */
2350xmlNodePtr
2351xmlNewText(const xmlChar *content) {
2352 xmlNodePtr cur;
2353
2354 /*
2355 * Allocate a new node and fill the fields.
2356 */
2357 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2358 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002359 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002360 return(NULL);
2361 }
2362 memset(cur, 0, sizeof(xmlNode));
2363 cur->type = XML_TEXT_NODE;
2364
2365 cur->name = xmlStringText;
2366 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002367 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002368 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002369
Daniel Veillarda880b122003-04-21 21:36:41 +00002370 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002371 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002372 return(cur);
2373}
2374
Daniel Veillard652327a2003-09-29 18:02:38 +00002375#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002376/**
2377 * xmlNewTextChild:
2378 * @parent: the parent node
2379 * @ns: a namespace if any
2380 * @name: the name of the child
2381 * @content: the text content of the child if any.
2382 *
2383 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002384 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2385 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002386 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002387 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2388 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2389 * reserved XML chars that might appear in @content, such as the ampersand,
2390 * greater-than or less-than signs, are automatically replaced by their XML
2391 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002392 *
2393 * Returns a pointer to the new node object.
2394 */
2395xmlNodePtr
2396xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2397 const xmlChar *name, const xmlChar *content) {
2398 xmlNodePtr cur, prev;
2399
2400 if (parent == NULL) {
2401#ifdef DEBUG_TREE
2402 xmlGenericError(xmlGenericErrorContext,
2403 "xmlNewTextChild : parent == NULL\n");
2404#endif
2405 return(NULL);
2406 }
2407
2408 if (name == NULL) {
2409#ifdef DEBUG_TREE
2410 xmlGenericError(xmlGenericErrorContext,
2411 "xmlNewTextChild : name == NULL\n");
2412#endif
2413 return(NULL);
2414 }
2415
2416 /*
2417 * Allocate a new node
2418 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002419 if (parent->type == XML_ELEMENT_NODE) {
2420 if (ns == NULL)
2421 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2422 else
2423 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2424 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2425 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2426 if (ns == NULL)
2427 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2428 else
2429 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2430 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2431 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2432 } else {
2433 return(NULL);
2434 }
Owen Taylor3473f882001-02-23 17:55:21 +00002435 if (cur == NULL) return(NULL);
2436
2437 /*
2438 * add the new element at the end of the children list.
2439 */
2440 cur->type = XML_ELEMENT_NODE;
2441 cur->parent = parent;
2442 cur->doc = parent->doc;
2443 if (parent->children == NULL) {
2444 parent->children = cur;
2445 parent->last = cur;
2446 } else {
2447 prev = parent->last;
2448 prev->next = cur;
2449 cur->prev = prev;
2450 parent->last = cur;
2451 }
2452
2453 return(cur);
2454}
Daniel Veillard652327a2003-09-29 18:02:38 +00002455#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002456
2457/**
2458 * xmlNewCharRef:
2459 * @doc: the document
2460 * @name: the char ref string, starting with # or "&# ... ;"
2461 *
2462 * Creation of a new character reference node.
2463 * Returns a pointer to the new node object.
2464 */
2465xmlNodePtr
2466xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2467 xmlNodePtr cur;
2468
2469 /*
2470 * Allocate a new node and fill the fields.
2471 */
2472 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2473 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002474 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002475 return(NULL);
2476 }
2477 memset(cur, 0, sizeof(xmlNode));
2478 cur->type = XML_ENTITY_REF_NODE;
2479
2480 cur->doc = doc;
2481 if (name[0] == '&') {
2482 int len;
2483 name++;
2484 len = xmlStrlen(name);
2485 if (name[len - 1] == ';')
2486 cur->name = xmlStrndup(name, len - 1);
2487 else
2488 cur->name = xmlStrndup(name, len);
2489 } else
2490 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002491
Daniel Veillarda880b122003-04-21 21:36:41 +00002492 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002493 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002494 return(cur);
2495}
2496
2497/**
2498 * xmlNewReference:
2499 * @doc: the document
2500 * @name: the reference name, or the reference string with & and ;
2501 *
2502 * Creation of a new reference node.
2503 * Returns a pointer to the new node object.
2504 */
2505xmlNodePtr
2506xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2507 xmlNodePtr cur;
2508 xmlEntityPtr ent;
2509
2510 /*
2511 * Allocate a new node and fill the fields.
2512 */
2513 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2514 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002515 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002516 return(NULL);
2517 }
2518 memset(cur, 0, sizeof(xmlNode));
2519 cur->type = XML_ENTITY_REF_NODE;
2520
2521 cur->doc = doc;
2522 if (name[0] == '&') {
2523 int len;
2524 name++;
2525 len = xmlStrlen(name);
2526 if (name[len - 1] == ';')
2527 cur->name = xmlStrndup(name, len - 1);
2528 else
2529 cur->name = xmlStrndup(name, len);
2530 } else
2531 cur->name = xmlStrdup(name);
2532
2533 ent = xmlGetDocEntity(doc, cur->name);
2534 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002535 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002536 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002537 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002538 * updated. Not sure if this is 100% correct.
2539 * -George
2540 */
2541 cur->children = (xmlNodePtr) ent;
2542 cur->last = (xmlNodePtr) ent;
2543 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002544
Daniel Veillarda880b122003-04-21 21:36:41 +00002545 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002546 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002547 return(cur);
2548}
2549
2550/**
2551 * xmlNewDocText:
2552 * @doc: the document
2553 * @content: the text content
2554 *
2555 * Creation of a new text node within a document.
2556 * Returns a pointer to the new node object.
2557 */
2558xmlNodePtr
2559xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2560 xmlNodePtr cur;
2561
2562 cur = xmlNewText(content);
2563 if (cur != NULL) cur->doc = doc;
2564 return(cur);
2565}
2566
2567/**
2568 * xmlNewTextLen:
2569 * @content: the text content
2570 * @len: the text len.
2571 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002572 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002573 * Returns a pointer to the new node object.
2574 */
2575xmlNodePtr
2576xmlNewTextLen(const xmlChar *content, int len) {
2577 xmlNodePtr cur;
2578
2579 /*
2580 * Allocate a new node and fill the fields.
2581 */
2582 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2583 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002584 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002585 return(NULL);
2586 }
2587 memset(cur, 0, sizeof(xmlNode));
2588 cur->type = XML_TEXT_NODE;
2589
2590 cur->name = xmlStringText;
2591 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002592 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002593 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002594
Daniel Veillarda880b122003-04-21 21:36:41 +00002595 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002596 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002597 return(cur);
2598}
2599
2600/**
2601 * xmlNewDocTextLen:
2602 * @doc: the document
2603 * @content: the text content
2604 * @len: the text len.
2605 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002606 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002607 * text node pertain to a given document.
2608 * Returns a pointer to the new node object.
2609 */
2610xmlNodePtr
2611xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2612 xmlNodePtr cur;
2613
2614 cur = xmlNewTextLen(content, len);
2615 if (cur != NULL) cur->doc = doc;
2616 return(cur);
2617}
2618
2619/**
2620 * xmlNewComment:
2621 * @content: the comment content
2622 *
2623 * Creation of a new node containing a comment.
2624 * Returns a pointer to the new node object.
2625 */
2626xmlNodePtr
2627xmlNewComment(const xmlChar *content) {
2628 xmlNodePtr cur;
2629
2630 /*
2631 * Allocate a new node and fill the fields.
2632 */
2633 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2634 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002635 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002636 return(NULL);
2637 }
2638 memset(cur, 0, sizeof(xmlNode));
2639 cur->type = XML_COMMENT_NODE;
2640
2641 cur->name = xmlStringComment;
2642 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002643 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002644 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002645
Daniel Veillarda880b122003-04-21 21:36:41 +00002646 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002647 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002648 return(cur);
2649}
2650
2651/**
2652 * xmlNewCDataBlock:
2653 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002654 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002655 * @len: the length of the block
2656 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002657 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002658 * Returns a pointer to the new node object.
2659 */
2660xmlNodePtr
2661xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2662 xmlNodePtr cur;
2663
2664 /*
2665 * Allocate a new node and fill the fields.
2666 */
2667 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2668 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002669 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002670 return(NULL);
2671 }
2672 memset(cur, 0, sizeof(xmlNode));
2673 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002674 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002675
2676 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002677 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002678 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002679
Daniel Veillarda880b122003-04-21 21:36:41 +00002680 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002681 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002682 return(cur);
2683}
2684
2685/**
2686 * xmlNewDocComment:
2687 * @doc: the document
2688 * @content: the comment content
2689 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002690 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002691 * Returns a pointer to the new node object.
2692 */
2693xmlNodePtr
2694xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2695 xmlNodePtr cur;
2696
2697 cur = xmlNewComment(content);
2698 if (cur != NULL) cur->doc = doc;
2699 return(cur);
2700}
2701
2702/**
2703 * xmlSetTreeDoc:
2704 * @tree: the top element
2705 * @doc: the document
2706 *
2707 * update all nodes under the tree to point to the right document
2708 */
2709void
2710xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002711 xmlAttrPtr prop;
2712
Owen Taylor3473f882001-02-23 17:55:21 +00002713 if (tree == NULL)
2714 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002715 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002716 if(tree->type == XML_ELEMENT_NODE) {
2717 prop = tree->properties;
2718 while (prop != NULL) {
2719 prop->doc = doc;
2720 xmlSetListDoc(prop->children, doc);
2721 prop = prop->next;
2722 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002723 }
Owen Taylor3473f882001-02-23 17:55:21 +00002724 if (tree->children != NULL)
2725 xmlSetListDoc(tree->children, doc);
2726 tree->doc = doc;
2727 }
2728}
2729
2730/**
2731 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002732 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002733 * @doc: the document
2734 *
2735 * update all nodes in the list to point to the right document
2736 */
2737void
2738xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2739 xmlNodePtr cur;
2740
2741 if (list == NULL)
2742 return;
2743 cur = list;
2744 while (cur != NULL) {
2745 if (cur->doc != doc)
2746 xmlSetTreeDoc(cur, doc);
2747 cur = cur->next;
2748 }
2749}
2750
Daniel Veillard2156d432004-03-04 15:59:36 +00002751#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002752/**
2753 * xmlNewChild:
2754 * @parent: the parent node
2755 * @ns: a namespace if any
2756 * @name: the name of the child
2757 * @content: the XML content of the child if any.
2758 *
2759 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002760 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2761 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002762 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002763 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2764 * references. XML special chars must be escaped first by using
2765 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002766 *
2767 * Returns a pointer to the new node object.
2768 */
2769xmlNodePtr
2770xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2771 const xmlChar *name, const xmlChar *content) {
2772 xmlNodePtr cur, prev;
2773
2774 if (parent == NULL) {
2775#ifdef DEBUG_TREE
2776 xmlGenericError(xmlGenericErrorContext,
2777 "xmlNewChild : parent == NULL\n");
2778#endif
2779 return(NULL);
2780 }
2781
2782 if (name == NULL) {
2783#ifdef DEBUG_TREE
2784 xmlGenericError(xmlGenericErrorContext,
2785 "xmlNewChild : name == NULL\n");
2786#endif
2787 return(NULL);
2788 }
2789
2790 /*
2791 * Allocate a new node
2792 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002793 if (parent->type == XML_ELEMENT_NODE) {
2794 if (ns == NULL)
2795 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2796 else
2797 cur = xmlNewDocNode(parent->doc, ns, name, content);
2798 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2799 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2800 if (ns == NULL)
2801 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2802 else
2803 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002804 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2805 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002806 } else {
2807 return(NULL);
2808 }
Owen Taylor3473f882001-02-23 17:55:21 +00002809 if (cur == NULL) return(NULL);
2810
2811 /*
2812 * add the new element at the end of the children list.
2813 */
2814 cur->type = XML_ELEMENT_NODE;
2815 cur->parent = parent;
2816 cur->doc = parent->doc;
2817 if (parent->children == NULL) {
2818 parent->children = cur;
2819 parent->last = cur;
2820 } else {
2821 prev = parent->last;
2822 prev->next = cur;
2823 cur->prev = prev;
2824 parent->last = cur;
2825 }
2826
2827 return(cur);
2828}
Daniel Veillard652327a2003-09-29 18:02:38 +00002829#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002830
2831/**
2832 * xmlAddNextSibling:
2833 * @cur: the child node
2834 * @elem: the new node
2835 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002836 * Add a new node @elem as the next sibling of @cur
2837 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002838 * first unlinked from its existing context.
2839 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002840 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2841 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002842 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002843 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002844 */
2845xmlNodePtr
2846xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2847 if (cur == NULL) {
2848#ifdef DEBUG_TREE
2849 xmlGenericError(xmlGenericErrorContext,
2850 "xmlAddNextSibling : cur == NULL\n");
2851#endif
2852 return(NULL);
2853 }
2854 if (elem == NULL) {
2855#ifdef DEBUG_TREE
2856 xmlGenericError(xmlGenericErrorContext,
2857 "xmlAddNextSibling : elem == NULL\n");
2858#endif
2859 return(NULL);
2860 }
2861
2862 xmlUnlinkNode(elem);
2863
2864 if (elem->type == XML_TEXT_NODE) {
2865 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002866 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002867 xmlFreeNode(elem);
2868 return(cur);
2869 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002870 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2871 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002872 xmlChar *tmp;
2873
2874 tmp = xmlStrdup(elem->content);
2875 tmp = xmlStrcat(tmp, cur->next->content);
2876 xmlNodeSetContent(cur->next, tmp);
2877 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002878 xmlFreeNode(elem);
2879 return(cur->next);
2880 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002881 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2882 /* check if an attribute with the same name exists */
2883 xmlAttrPtr attr;
2884
2885 if (elem->ns == NULL)
2886 attr = xmlHasProp(cur->parent, elem->name);
2887 else
2888 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2889 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2890 /* different instance, destroy it (attributes must be unique) */
2891 xmlFreeProp(attr);
2892 }
Owen Taylor3473f882001-02-23 17:55:21 +00002893 }
2894
2895 if (elem->doc != cur->doc) {
2896 xmlSetTreeDoc(elem, cur->doc);
2897 }
2898 elem->parent = cur->parent;
2899 elem->prev = cur;
2900 elem->next = cur->next;
2901 cur->next = elem;
2902 if (elem->next != NULL)
2903 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002904 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002905 elem->parent->last = elem;
2906 return(elem);
2907}
2908
Daniel Veillard2156d432004-03-04 15:59:36 +00002909#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002910/**
2911 * xmlAddPrevSibling:
2912 * @cur: the child node
2913 * @elem: the new node
2914 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002915 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002916 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002917 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002918 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002919 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2920 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002921 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002922 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002923 */
2924xmlNodePtr
2925xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2926 if (cur == NULL) {
2927#ifdef DEBUG_TREE
2928 xmlGenericError(xmlGenericErrorContext,
2929 "xmlAddPrevSibling : cur == NULL\n");
2930#endif
2931 return(NULL);
2932 }
2933 if (elem == NULL) {
2934#ifdef DEBUG_TREE
2935 xmlGenericError(xmlGenericErrorContext,
2936 "xmlAddPrevSibling : elem == NULL\n");
2937#endif
2938 return(NULL);
2939 }
2940
2941 xmlUnlinkNode(elem);
2942
2943 if (elem->type == XML_TEXT_NODE) {
2944 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002945 xmlChar *tmp;
2946
2947 tmp = xmlStrdup(elem->content);
2948 tmp = xmlStrcat(tmp, cur->content);
2949 xmlNodeSetContent(cur, tmp);
2950 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002951 xmlFreeNode(elem);
2952 return(cur);
2953 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002954 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2955 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002956 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002957 xmlFreeNode(elem);
2958 return(cur->prev);
2959 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002960 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2961 /* check if an attribute with the same name exists */
2962 xmlAttrPtr attr;
2963
2964 if (elem->ns == NULL)
2965 attr = xmlHasProp(cur->parent, elem->name);
2966 else
2967 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2968 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2969 /* different instance, destroy it (attributes must be unique) */
2970 xmlFreeProp(attr);
2971 }
Owen Taylor3473f882001-02-23 17:55:21 +00002972 }
2973
2974 if (elem->doc != cur->doc) {
2975 xmlSetTreeDoc(elem, cur->doc);
2976 }
2977 elem->parent = cur->parent;
2978 elem->next = cur;
2979 elem->prev = cur->prev;
2980 cur->prev = elem;
2981 if (elem->prev != NULL)
2982 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002983 if (elem->parent != NULL) {
2984 if (elem->type == XML_ATTRIBUTE_NODE) {
2985 if (elem->parent->properties == (xmlAttrPtr) cur) {
2986 elem->parent->properties = (xmlAttrPtr) elem;
2987 }
2988 } else {
2989 if (elem->parent->children == cur) {
2990 elem->parent->children = elem;
2991 }
2992 }
2993 }
Owen Taylor3473f882001-02-23 17:55:21 +00002994 return(elem);
2995}
Daniel Veillard652327a2003-09-29 18:02:38 +00002996#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002997
2998/**
2999 * xmlAddSibling:
3000 * @cur: the child node
3001 * @elem: the new node
3002 *
3003 * Add a new element @elem to the list of siblings of @cur
3004 * merging adjacent TEXT nodes (@elem may be freed)
3005 * If the new element was already inserted in a document it is
3006 * first unlinked from its existing context.
3007 *
3008 * Returns the new element or NULL in case of error.
3009 */
3010xmlNodePtr
3011xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
3012 xmlNodePtr parent;
3013
3014 if (cur == NULL) {
3015#ifdef DEBUG_TREE
3016 xmlGenericError(xmlGenericErrorContext,
3017 "xmlAddSibling : cur == NULL\n");
3018#endif
3019 return(NULL);
3020 }
3021
3022 if (elem == NULL) {
3023#ifdef DEBUG_TREE
3024 xmlGenericError(xmlGenericErrorContext,
3025 "xmlAddSibling : elem == NULL\n");
3026#endif
3027 return(NULL);
3028 }
3029
3030 /*
3031 * Constant time is we can rely on the ->parent->last to find
3032 * the last sibling.
3033 */
3034 if ((cur->parent != NULL) &&
3035 (cur->parent->children != NULL) &&
3036 (cur->parent->last != NULL) &&
3037 (cur->parent->last->next == NULL)) {
3038 cur = cur->parent->last;
3039 } else {
3040 while (cur->next != NULL) cur = cur->next;
3041 }
3042
3043 xmlUnlinkNode(elem);
3044
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003045 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3046 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003047 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003048 xmlFreeNode(elem);
3049 return(cur);
3050 }
3051
3052 if (elem->doc != cur->doc) {
3053 xmlSetTreeDoc(elem, cur->doc);
3054 }
3055 parent = cur->parent;
3056 elem->prev = cur;
3057 elem->next = NULL;
3058 elem->parent = parent;
3059 cur->next = elem;
3060 if (parent != NULL)
3061 parent->last = elem;
3062
3063 return(elem);
3064}
3065
3066/**
3067 * xmlAddChildList:
3068 * @parent: the parent node
3069 * @cur: the first node in the list
3070 *
3071 * Add a list of node at the end of the child list of the parent
3072 * merging adjacent TEXT nodes (@cur may be freed)
3073 *
3074 * Returns the last child or NULL in case of error.
3075 */
3076xmlNodePtr
3077xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3078 xmlNodePtr prev;
3079
3080 if (parent == NULL) {
3081#ifdef DEBUG_TREE
3082 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003083 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003084#endif
3085 return(NULL);
3086 }
3087
3088 if (cur == NULL) {
3089#ifdef DEBUG_TREE
3090 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003091 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003092#endif
3093 return(NULL);
3094 }
3095
3096 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3097 (cur->doc != parent->doc)) {
3098#ifdef DEBUG_TREE
3099 xmlGenericError(xmlGenericErrorContext,
3100 "Elements moved to a different document\n");
3101#endif
3102 }
3103
3104 /*
3105 * add the first element at the end of the children list.
3106 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003107
Owen Taylor3473f882001-02-23 17:55:21 +00003108 if (parent->children == NULL) {
3109 parent->children = cur;
3110 } else {
3111 /*
3112 * If cur and parent->last both are TEXT nodes, then merge them.
3113 */
3114 if ((cur->type == XML_TEXT_NODE) &&
3115 (parent->last->type == XML_TEXT_NODE) &&
3116 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003117 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003118 /*
3119 * if it's the only child, nothing more to be done.
3120 */
3121 if (cur->next == NULL) {
3122 xmlFreeNode(cur);
3123 return(parent->last);
3124 }
3125 prev = cur;
3126 cur = cur->next;
3127 xmlFreeNode(prev);
3128 }
3129 prev = parent->last;
3130 prev->next = cur;
3131 cur->prev = prev;
3132 }
3133 while (cur->next != NULL) {
3134 cur->parent = parent;
3135 if (cur->doc != parent->doc) {
3136 xmlSetTreeDoc(cur, parent->doc);
3137 }
3138 cur = cur->next;
3139 }
3140 cur->parent = parent;
3141 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3142 parent->last = cur;
3143
3144 return(cur);
3145}
3146
3147/**
3148 * xmlAddChild:
3149 * @parent: the parent node
3150 * @cur: the child node
3151 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003152 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003153 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003154 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3155 * If there is an attribute with equal name, it is first destroyed.
3156 *
Owen Taylor3473f882001-02-23 17:55:21 +00003157 * Returns the child or NULL in case of error.
3158 */
3159xmlNodePtr
3160xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3161 xmlNodePtr prev;
3162
3163 if (parent == NULL) {
3164#ifdef DEBUG_TREE
3165 xmlGenericError(xmlGenericErrorContext,
3166 "xmlAddChild : parent == NULL\n");
3167#endif
3168 return(NULL);
3169 }
3170
3171 if (cur == NULL) {
3172#ifdef DEBUG_TREE
3173 xmlGenericError(xmlGenericErrorContext,
3174 "xmlAddChild : child == NULL\n");
3175#endif
3176 return(NULL);
3177 }
3178
Owen Taylor3473f882001-02-23 17:55:21 +00003179 /*
3180 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003181 * cur is then freed.
3182 */
3183 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003184 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003185 (parent->content != NULL) &&
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003186 (parent->name == cur->name) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003187 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003188 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003189 xmlFreeNode(cur);
3190 return(parent);
3191 }
3192 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003193 (parent->last->name == cur->name) &&
3194 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003195 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003196 xmlFreeNode(cur);
3197 return(parent->last);
3198 }
3199 }
3200
3201 /*
3202 * add the new element at the end of the children list.
3203 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003204 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003205 cur->parent = parent;
3206 if (cur->doc != parent->doc) {
3207 xmlSetTreeDoc(cur, parent->doc);
3208 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003209 /* this check prevents a loop on tree-traversions if a developer
3210 * tries to add a node to its parent multiple times
3211 */
3212 if (prev == parent)
3213 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003214
3215 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003216 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003217 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003218 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003219 (parent->content != NULL) &&
3220 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003221 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003222 xmlFreeNode(cur);
3223 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003224 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003225 if (cur->type == XML_ATTRIBUTE_NODE) {
3226 if (parent->properties == NULL) {
3227 parent->properties = (xmlAttrPtr) cur;
3228 } else {
3229 /* check if an attribute with the same name exists */
3230 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003231
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003232 if (cur->ns == NULL)
3233 lastattr = xmlHasProp(parent, cur->name);
3234 else
3235 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3236 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3237 /* different instance, destroy it (attributes must be unique) */
3238 xmlFreeProp(lastattr);
3239 }
3240 /* find the end */
3241 lastattr = parent->properties;
3242 while (lastattr->next != NULL) {
3243 lastattr = lastattr->next;
3244 }
3245 lastattr->next = (xmlAttrPtr) cur;
3246 ((xmlAttrPtr) cur)->prev = lastattr;
3247 }
3248 } else {
3249 if (parent->children == NULL) {
3250 parent->children = cur;
3251 parent->last = cur;
3252 } else {
3253 prev = parent->last;
3254 prev->next = cur;
3255 cur->prev = prev;
3256 parent->last = cur;
3257 }
3258 }
Owen Taylor3473f882001-02-23 17:55:21 +00003259 return(cur);
3260}
3261
3262/**
3263 * xmlGetLastChild:
3264 * @parent: the parent node
3265 *
3266 * Search the last child of a node.
3267 * Returns the last child or NULL if none.
3268 */
3269xmlNodePtr
3270xmlGetLastChild(xmlNodePtr parent) {
3271 if (parent == NULL) {
3272#ifdef DEBUG_TREE
3273 xmlGenericError(xmlGenericErrorContext,
3274 "xmlGetLastChild : parent == NULL\n");
3275#endif
3276 return(NULL);
3277 }
3278 return(parent->last);
3279}
3280
3281/**
3282 * xmlFreeNodeList:
3283 * @cur: the first node in the list
3284 *
3285 * Free a node and all its siblings, this is a recursive behaviour, all
3286 * the children are freed too.
3287 */
3288void
3289xmlFreeNodeList(xmlNodePtr cur) {
3290 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003291 xmlDictPtr dict = NULL;
3292
3293 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003294 if (cur->type == XML_NAMESPACE_DECL) {
3295 xmlFreeNsList((xmlNsPtr) cur);
3296 return;
3297 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003298 if ((cur->type == XML_DOCUMENT_NODE) ||
3299#ifdef LIBXML_DOCB_ENABLED
3300 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003301#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003302 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003303 xmlFreeDoc((xmlDocPtr) cur);
3304 return;
3305 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003306 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003307 while (cur != NULL) {
3308 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003309 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003310
Daniel Veillarda880b122003-04-21 21:36:41 +00003311 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003312 xmlDeregisterNodeDefaultValue(cur);
3313
Daniel Veillard02141ea2001-04-30 11:46:40 +00003314 if ((cur->children != NULL) &&
3315 (cur->type != XML_ENTITY_REF_NODE))
3316 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003317 if (((cur->type == XML_ELEMENT_NODE) ||
3318 (cur->type == XML_XINCLUDE_START) ||
3319 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003320 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003321 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003322 if ((cur->type != XML_ELEMENT_NODE) &&
3323 (cur->type != XML_XINCLUDE_START) &&
3324 (cur->type != XML_XINCLUDE_END) &&
3325 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003326 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003327 }
3328 if (((cur->type == XML_ELEMENT_NODE) ||
3329 (cur->type == XML_XINCLUDE_START) ||
3330 (cur->type == XML_XINCLUDE_END)) &&
3331 (cur->nsDef != NULL))
3332 xmlFreeNsList(cur->nsDef);
3333
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003334 /*
3335 * When a node is a text node or a comment, it uses a global static
3336 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003337 * Otherwise the node name might come from the document's
3338 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003339 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003340 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003341 (cur->type != XML_TEXT_NODE) &&
3342 (cur->type != XML_COMMENT_NODE))
3343 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003344 xmlFree(cur);
3345 }
Owen Taylor3473f882001-02-23 17:55:21 +00003346 cur = next;
3347 }
3348}
3349
3350/**
3351 * xmlFreeNode:
3352 * @cur: the node
3353 *
3354 * Free a node, this is a recursive behaviour, all the children are freed too.
3355 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3356 */
3357void
3358xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003359 xmlDictPtr dict = NULL;
3360
3361 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003362
Daniel Veillard02141ea2001-04-30 11:46:40 +00003363 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003364 if (cur->type == XML_DTD_NODE) {
3365 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003366 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003367 }
3368 if (cur->type == XML_NAMESPACE_DECL) {
3369 xmlFreeNs((xmlNsPtr) cur);
3370 return;
3371 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003372 if (cur->type == XML_ATTRIBUTE_NODE) {
3373 xmlFreeProp((xmlAttrPtr) cur);
3374 return;
3375 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003376
Daniel Veillarda880b122003-04-21 21:36:41 +00003377 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003378 xmlDeregisterNodeDefaultValue(cur);
3379
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003380 if (cur->doc != NULL) dict = cur->doc->dict;
3381
Owen Taylor3473f882001-02-23 17:55:21 +00003382 if ((cur->children != NULL) &&
3383 (cur->type != XML_ENTITY_REF_NODE))
3384 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003385 if (((cur->type == XML_ELEMENT_NODE) ||
3386 (cur->type == XML_XINCLUDE_START) ||
3387 (cur->type == XML_XINCLUDE_END)) &&
3388 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003389 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003390 if ((cur->type != XML_ELEMENT_NODE) &&
3391 (cur->content != NULL) &&
3392 (cur->type != XML_ENTITY_REF_NODE) &&
3393 (cur->type != XML_XINCLUDE_END) &&
3394 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003395 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003396 }
3397
Daniel Veillardacd370f2001-06-09 17:17:51 +00003398 /*
3399 * When a node is a text node or a comment, it uses a global static
3400 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003401 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003402 */
Owen Taylor3473f882001-02-23 17:55:21 +00003403 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003404 (cur->type != XML_TEXT_NODE) &&
3405 (cur->type != XML_COMMENT_NODE))
3406 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003407
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003408 if (((cur->type == XML_ELEMENT_NODE) ||
3409 (cur->type == XML_XINCLUDE_START) ||
3410 (cur->type == XML_XINCLUDE_END)) &&
3411 (cur->nsDef != NULL))
3412 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003413 xmlFree(cur);
3414}
3415
3416/**
3417 * xmlUnlinkNode:
3418 * @cur: the node
3419 *
3420 * Unlink a node from it's current context, the node is not freed
3421 */
3422void
3423xmlUnlinkNode(xmlNodePtr cur) {
3424 if (cur == NULL) {
3425#ifdef DEBUG_TREE
3426 xmlGenericError(xmlGenericErrorContext,
3427 "xmlUnlinkNode : node == NULL\n");
3428#endif
3429 return;
3430 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003431 if (cur->type == XML_DTD_NODE) {
3432 xmlDocPtr doc;
3433 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003434 if (doc != NULL) {
3435 if (doc->intSubset == (xmlDtdPtr) cur)
3436 doc->intSubset = NULL;
3437 if (doc->extSubset == (xmlDtdPtr) cur)
3438 doc->extSubset = NULL;
3439 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003440 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003441 if (cur->parent != NULL) {
3442 xmlNodePtr parent;
3443 parent = cur->parent;
3444 if (cur->type == XML_ATTRIBUTE_NODE) {
3445 if (parent->properties == (xmlAttrPtr) cur)
3446 parent->properties = ((xmlAttrPtr) cur)->next;
3447 } else {
3448 if (parent->children == cur)
3449 parent->children = cur->next;
3450 if (parent->last == cur)
3451 parent->last = cur->prev;
3452 }
3453 cur->parent = NULL;
3454 }
Owen Taylor3473f882001-02-23 17:55:21 +00003455 if (cur->next != NULL)
3456 cur->next->prev = cur->prev;
3457 if (cur->prev != NULL)
3458 cur->prev->next = cur->next;
3459 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003460}
3461
Daniel Veillard2156d432004-03-04 15:59:36 +00003462#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003463/**
3464 * xmlReplaceNode:
3465 * @old: the old node
3466 * @cur: the node
3467 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003468 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003469 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003470 * first unlinked from its existing context.
3471 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003472 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003473 */
3474xmlNodePtr
3475xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3476 if (old == NULL) {
3477#ifdef DEBUG_TREE
3478 xmlGenericError(xmlGenericErrorContext,
3479 "xmlReplaceNode : old == NULL\n");
3480#endif
3481 return(NULL);
3482 }
3483 if (cur == NULL) {
3484 xmlUnlinkNode(old);
3485 return(old);
3486 }
3487 if (cur == old) {
3488 return(old);
3489 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003490 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3491#ifdef DEBUG_TREE
3492 xmlGenericError(xmlGenericErrorContext,
3493 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3494#endif
3495 return(old);
3496 }
3497 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3498#ifdef DEBUG_TREE
3499 xmlGenericError(xmlGenericErrorContext,
3500 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3501#endif
3502 return(old);
3503 }
Owen Taylor3473f882001-02-23 17:55:21 +00003504 xmlUnlinkNode(cur);
3505 cur->doc = old->doc;
3506 cur->parent = old->parent;
3507 cur->next = old->next;
3508 if (cur->next != NULL)
3509 cur->next->prev = cur;
3510 cur->prev = old->prev;
3511 if (cur->prev != NULL)
3512 cur->prev->next = cur;
3513 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003514 if (cur->type == XML_ATTRIBUTE_NODE) {
3515 if (cur->parent->properties == (xmlAttrPtr)old)
3516 cur->parent->properties = ((xmlAttrPtr) cur);
3517 } else {
3518 if (cur->parent->children == old)
3519 cur->parent->children = cur;
3520 if (cur->parent->last == old)
3521 cur->parent->last = cur;
3522 }
Owen Taylor3473f882001-02-23 17:55:21 +00003523 }
3524 old->next = old->prev = NULL;
3525 old->parent = NULL;
3526 return(old);
3527}
Daniel Veillard652327a2003-09-29 18:02:38 +00003528#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003529
3530/************************************************************************
3531 * *
3532 * Copy operations *
3533 * *
3534 ************************************************************************/
3535
3536/**
3537 * xmlCopyNamespace:
3538 * @cur: the namespace
3539 *
3540 * Do a copy of the namespace.
3541 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003542 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003543 */
3544xmlNsPtr
3545xmlCopyNamespace(xmlNsPtr cur) {
3546 xmlNsPtr ret;
3547
3548 if (cur == NULL) return(NULL);
3549 switch (cur->type) {
3550 case XML_LOCAL_NAMESPACE:
3551 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3552 break;
3553 default:
3554#ifdef DEBUG_TREE
3555 xmlGenericError(xmlGenericErrorContext,
3556 "xmlCopyNamespace: invalid type %d\n", cur->type);
3557#endif
3558 return(NULL);
3559 }
3560 return(ret);
3561}
3562
3563/**
3564 * xmlCopyNamespaceList:
3565 * @cur: the first namespace
3566 *
3567 * Do a copy of an namespace list.
3568 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003569 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003570 */
3571xmlNsPtr
3572xmlCopyNamespaceList(xmlNsPtr cur) {
3573 xmlNsPtr ret = NULL;
3574 xmlNsPtr p = NULL,q;
3575
3576 while (cur != NULL) {
3577 q = xmlCopyNamespace(cur);
3578 if (p == NULL) {
3579 ret = p = q;
3580 } else {
3581 p->next = q;
3582 p = q;
3583 }
3584 cur = cur->next;
3585 }
3586 return(ret);
3587}
3588
3589static xmlNodePtr
3590xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3591/**
3592 * xmlCopyProp:
3593 * @target: the element where the attribute will be grafted
3594 * @cur: the attribute
3595 *
3596 * Do a copy of the attribute.
3597 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003598 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003599 */
3600xmlAttrPtr
3601xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3602 xmlAttrPtr ret;
3603
3604 if (cur == NULL) return(NULL);
3605 if (target != NULL)
3606 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3607 else if (cur->parent != NULL)
3608 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3609 else if (cur->children != NULL)
3610 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3611 else
3612 ret = xmlNewDocProp(NULL, cur->name, NULL);
3613 if (ret == NULL) return(NULL);
3614 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003615
Owen Taylor3473f882001-02-23 17:55:21 +00003616 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003617 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003618
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003619 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3620 if (ns == NULL) {
3621 /*
3622 * Humm, we are copying an element whose namespace is defined
3623 * out of the new tree scope. Search it in the original tree
3624 * and add it at the top of the new tree
3625 */
3626 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3627 if (ns != NULL) {
3628 xmlNodePtr root = target;
3629 xmlNodePtr pred = NULL;
3630
3631 while (root->parent != NULL) {
3632 pred = root;
3633 root = root->parent;
3634 }
3635 if (root == (xmlNodePtr) target->doc) {
3636 /* correct possibly cycling above the document elt */
3637 root = pred;
3638 }
3639 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3640 }
3641 } else {
3642 /*
3643 * we have to find something appropriate here since
3644 * we cant be sure, that the namespce we found is identified
3645 * by the prefix
3646 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003647 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003648 /* this is the nice case */
3649 ret->ns = ns;
3650 } else {
3651 /*
3652 * we are in trouble: we need a new reconcilied namespace.
3653 * This is expensive
3654 */
3655 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3656 }
3657 }
3658
Owen Taylor3473f882001-02-23 17:55:21 +00003659 } else
3660 ret->ns = NULL;
3661
3662 if (cur->children != NULL) {
3663 xmlNodePtr tmp;
3664
3665 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3666 ret->last = NULL;
3667 tmp = ret->children;
3668 while (tmp != NULL) {
3669 /* tmp->parent = (xmlNodePtr)ret; */
3670 if (tmp->next == NULL)
3671 ret->last = tmp;
3672 tmp = tmp->next;
3673 }
3674 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003675 /*
3676 * Try to handle IDs
3677 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003678 if ((target!= NULL) && (cur!= NULL) &&
3679 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003680 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3681 if (xmlIsID(cur->doc, cur->parent, cur)) {
3682 xmlChar *id;
3683
3684 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3685 if (id != NULL) {
3686 xmlAddID(NULL, target->doc, id, ret);
3687 xmlFree(id);
3688 }
3689 }
3690 }
Owen Taylor3473f882001-02-23 17:55:21 +00003691 return(ret);
3692}
3693
3694/**
3695 * xmlCopyPropList:
3696 * @target: the element where the attributes will be grafted
3697 * @cur: the first attribute
3698 *
3699 * Do a copy of an attribute list.
3700 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003701 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003702 */
3703xmlAttrPtr
3704xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3705 xmlAttrPtr ret = NULL;
3706 xmlAttrPtr p = NULL,q;
3707
3708 while (cur != NULL) {
3709 q = xmlCopyProp(target, cur);
William M. Brack13dfa872004-09-18 04:52:08 +00003710 if (q == NULL)
3711 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003712 if (p == NULL) {
3713 ret = p = q;
3714 } else {
3715 p->next = q;
3716 q->prev = p;
3717 p = q;
3718 }
3719 cur = cur->next;
3720 }
3721 return(ret);
3722}
3723
3724/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003725 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003726 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003727 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003728 * tricky reason: namespaces. Doing a direct copy of a node
3729 * say RPM:Copyright without changing the namespace pointer to
3730 * something else can produce stale links. One way to do it is
3731 * to keep a reference counter but this doesn't work as soon
3732 * as one move the element or the subtree out of the scope of
3733 * the existing namespace. The actual solution seems to add
3734 * a copy of the namespace at the top of the copied tree if
3735 * not available in the subtree.
3736 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00003737 * The argument "recursive" normally indicates a recursive copy
3738 * of the node with values 0 (no) and 1 (yes). For XInclude,
3739 * however, we allow a value of 2 to indicate copy properties and
3740 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00003741 */
3742
3743static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003744xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00003745 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003746 xmlNodePtr ret;
3747
3748 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003749 switch (node->type) {
3750 case XML_TEXT_NODE:
3751 case XML_CDATA_SECTION_NODE:
3752 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003753 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003754 case XML_ENTITY_REF_NODE:
3755 case XML_ENTITY_NODE:
3756 case XML_PI_NODE:
3757 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003758 case XML_XINCLUDE_START:
3759 case XML_XINCLUDE_END:
3760 break;
3761 case XML_ATTRIBUTE_NODE:
3762 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3763 case XML_NAMESPACE_DECL:
3764 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3765
Daniel Veillard39196eb2001-06-19 18:09:42 +00003766 case XML_DOCUMENT_NODE:
3767 case XML_HTML_DOCUMENT_NODE:
3768#ifdef LIBXML_DOCB_ENABLED
3769 case XML_DOCB_DOCUMENT_NODE:
3770#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003771#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00003772 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00003773#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003774 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003775 case XML_NOTATION_NODE:
3776 case XML_DTD_NODE:
3777 case XML_ELEMENT_DECL:
3778 case XML_ATTRIBUTE_DECL:
3779 case XML_ENTITY_DECL:
3780 return(NULL);
3781 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003782
Owen Taylor3473f882001-02-23 17:55:21 +00003783 /*
3784 * Allocate a new node and fill the fields.
3785 */
3786 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3787 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003788 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003789 return(NULL);
3790 }
3791 memset(ret, 0, sizeof(xmlNode));
3792 ret->type = node->type;
3793
3794 ret->doc = doc;
3795 ret->parent = parent;
3796 if (node->name == xmlStringText)
3797 ret->name = xmlStringText;
3798 else if (node->name == xmlStringTextNoenc)
3799 ret->name = xmlStringTextNoenc;
3800 else if (node->name == xmlStringComment)
3801 ret->name = xmlStringComment;
3802 else if (node->name != NULL)
3803 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003804 if ((node->type != XML_ELEMENT_NODE) &&
3805 (node->content != NULL) &&
3806 (node->type != XML_ENTITY_REF_NODE) &&
3807 (node->type != XML_XINCLUDE_END) &&
3808 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003809 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003810 }else{
3811 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003812 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003813 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003814 if (parent != NULL) {
3815 xmlNodePtr tmp;
3816
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003817 /*
3818 * this is a tricky part for the node register thing:
3819 * in case ret does get coalesced in xmlAddChild
3820 * the deregister-node callback is called; so we register ret now already
3821 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003822 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003823 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3824
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003825 tmp = xmlAddChild(parent, ret);
3826 /* node could have coalesced */
3827 if (tmp != ret)
3828 return(tmp);
3829 }
Owen Taylor3473f882001-02-23 17:55:21 +00003830
William M. Brack57e9e912004-03-09 16:19:02 +00003831 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003832 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003833 if (node->nsDef != NULL)
3834 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3835
3836 if (node->ns != NULL) {
3837 xmlNsPtr ns;
3838
3839 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3840 if (ns == NULL) {
3841 /*
3842 * Humm, we are copying an element whose namespace is defined
3843 * out of the new tree scope. Search it in the original tree
3844 * and add it at the top of the new tree
3845 */
3846 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3847 if (ns != NULL) {
3848 xmlNodePtr root = ret;
3849
3850 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003851 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003852 }
3853 } else {
3854 /*
3855 * reference the existing namespace definition in our own tree.
3856 */
3857 ret->ns = ns;
3858 }
3859 }
3860 if (node->properties != NULL)
3861 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003862 if (node->type == XML_ENTITY_REF_NODE) {
3863 if ((doc == NULL) || (node->doc != doc)) {
3864 /*
3865 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003866 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003867 * we cannot keep the reference. Try to find it in the
3868 * target document.
3869 */
3870 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3871 } else {
3872 ret->children = node->children;
3873 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003874 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00003875 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003876 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003877 UPDATE_LAST_CHILD_AND_PARENT(ret)
3878 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003879
3880out:
3881 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00003882 if ((parent == NULL) &&
3883 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003884 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003885 return(ret);
3886}
3887
3888static xmlNodePtr
3889xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3890 xmlNodePtr ret = NULL;
3891 xmlNodePtr p = NULL,q;
3892
3893 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003894#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003895 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003896 if (doc == NULL) {
3897 node = node->next;
3898 continue;
3899 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003900 if (doc->intSubset == NULL) {
3901 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3902 q->doc = doc;
3903 q->parent = parent;
3904 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003905 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003906 } else {
3907 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003908 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003909 }
3910 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003911#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003912 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003913 if (ret == NULL) {
3914 q->prev = NULL;
3915 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003916 } else if (p != q) {
3917 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003918 p->next = q;
3919 q->prev = p;
3920 p = q;
3921 }
3922 node = node->next;
3923 }
3924 return(ret);
3925}
3926
3927/**
3928 * xmlCopyNode:
3929 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00003930 * @extended: if 1 do a recursive copy (properties, namespaces and children
3931 * when applicable)
3932 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00003933 *
3934 * Do a copy of the node.
3935 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003936 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003937 */
3938xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003939xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003940 xmlNodePtr ret;
3941
William M. Brack57e9e912004-03-09 16:19:02 +00003942 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00003943 return(ret);
3944}
3945
3946/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003947 * xmlDocCopyNode:
3948 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003949 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00003950 * @extended: if 1 do a recursive copy (properties, namespaces and children
3951 * when applicable)
3952 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00003953 *
3954 * Do a copy of the node to a given document.
3955 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003956 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003957 */
3958xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003959xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003960 xmlNodePtr ret;
3961
William M. Brack57e9e912004-03-09 16:19:02 +00003962 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00003963 return(ret);
3964}
3965
3966/**
Owen Taylor3473f882001-02-23 17:55:21 +00003967 * xmlCopyNodeList:
3968 * @node: the first node in the list.
3969 *
3970 * Do a recursive copy of the node list.
3971 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003972 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003973 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003974xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003975 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3976 return(ret);
3977}
3978
Daniel Veillard2156d432004-03-04 15:59:36 +00003979#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003980/**
Owen Taylor3473f882001-02-23 17:55:21 +00003981 * xmlCopyDtd:
3982 * @dtd: the dtd
3983 *
3984 * Do a copy of the dtd.
3985 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003986 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003987 */
3988xmlDtdPtr
3989xmlCopyDtd(xmlDtdPtr dtd) {
3990 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003991 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003992
3993 if (dtd == NULL) return(NULL);
3994 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3995 if (ret == NULL) return(NULL);
3996 if (dtd->entities != NULL)
3997 ret->entities = (void *) xmlCopyEntitiesTable(
3998 (xmlEntitiesTablePtr) dtd->entities);
3999 if (dtd->notations != NULL)
4000 ret->notations = (void *) xmlCopyNotationTable(
4001 (xmlNotationTablePtr) dtd->notations);
4002 if (dtd->elements != NULL)
4003 ret->elements = (void *) xmlCopyElementTable(
4004 (xmlElementTablePtr) dtd->elements);
4005 if (dtd->attributes != NULL)
4006 ret->attributes = (void *) xmlCopyAttributeTable(
4007 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004008 if (dtd->pentities != NULL)
4009 ret->pentities = (void *) xmlCopyEntitiesTable(
4010 (xmlEntitiesTablePtr) dtd->pentities);
4011
4012 cur = dtd->children;
4013 while (cur != NULL) {
4014 q = NULL;
4015
4016 if (cur->type == XML_ENTITY_DECL) {
4017 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4018 switch (tmp->etype) {
4019 case XML_INTERNAL_GENERAL_ENTITY:
4020 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4021 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4022 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4023 break;
4024 case XML_INTERNAL_PARAMETER_ENTITY:
4025 case XML_EXTERNAL_PARAMETER_ENTITY:
4026 q = (xmlNodePtr)
4027 xmlGetParameterEntityFromDtd(ret, tmp->name);
4028 break;
4029 case XML_INTERNAL_PREDEFINED_ENTITY:
4030 break;
4031 }
4032 } else if (cur->type == XML_ELEMENT_DECL) {
4033 xmlElementPtr tmp = (xmlElementPtr) cur;
4034 q = (xmlNodePtr)
4035 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4036 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4037 xmlAttributePtr tmp = (xmlAttributePtr) cur;
4038 q = (xmlNodePtr)
4039 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4040 } else if (cur->type == XML_COMMENT_NODE) {
4041 q = xmlCopyNode(cur, 0);
4042 }
4043
4044 if (q == NULL) {
4045 cur = cur->next;
4046 continue;
4047 }
4048
4049 if (p == NULL)
4050 ret->children = q;
4051 else
4052 p->next = q;
4053
4054 q->prev = p;
4055 q->parent = (xmlNodePtr) ret;
4056 q->next = NULL;
4057 ret->last = q;
4058 p = q;
4059 cur = cur->next;
4060 }
4061
Owen Taylor3473f882001-02-23 17:55:21 +00004062 return(ret);
4063}
Daniel Veillard2156d432004-03-04 15:59:36 +00004064#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004065
Daniel Veillard2156d432004-03-04 15:59:36 +00004066#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004067/**
4068 * xmlCopyDoc:
4069 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004070 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004071 *
4072 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004073 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004074 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004075 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004076 */
4077xmlDocPtr
4078xmlCopyDoc(xmlDocPtr doc, int recursive) {
4079 xmlDocPtr ret;
4080
4081 if (doc == NULL) return(NULL);
4082 ret = xmlNewDoc(doc->version);
4083 if (ret == NULL) return(NULL);
4084 if (doc->name != NULL)
4085 ret->name = xmlMemStrdup(doc->name);
4086 if (doc->encoding != NULL)
4087 ret->encoding = xmlStrdup(doc->encoding);
4088 ret->charset = doc->charset;
4089 ret->compression = doc->compression;
4090 ret->standalone = doc->standalone;
4091 if (!recursive) return(ret);
4092
Daniel Veillardb33c2012001-04-25 12:59:04 +00004093 ret->last = NULL;
4094 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004095#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004096 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004097 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004098 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004099 ret->intSubset->parent = ret;
4100 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004101#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004102 if (doc->oldNs != NULL)
4103 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4104 if (doc->children != NULL) {
4105 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004106
4107 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4108 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004109 ret->last = NULL;
4110 tmp = ret->children;
4111 while (tmp != NULL) {
4112 if (tmp->next == NULL)
4113 ret->last = tmp;
4114 tmp = tmp->next;
4115 }
4116 }
4117 return(ret);
4118}
Daniel Veillard652327a2003-09-29 18:02:38 +00004119#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004120
4121/************************************************************************
4122 * *
4123 * Content access functions *
4124 * *
4125 ************************************************************************/
4126
4127/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004128 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004129 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004130 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004131 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004132 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004133 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004134 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004135 */
4136long
4137xmlGetLineNo(xmlNodePtr node)
4138{
4139 long result = -1;
4140
4141 if (!node)
4142 return result;
4143 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004144 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004145 else if ((node->prev != NULL) &&
4146 ((node->prev->type == XML_ELEMENT_NODE) ||
4147 (node->prev->type == XML_TEXT_NODE)))
4148 result = xmlGetLineNo(node->prev);
4149 else if ((node->parent != NULL) &&
4150 ((node->parent->type == XML_ELEMENT_NODE) ||
4151 (node->parent->type == XML_TEXT_NODE)))
4152 result = xmlGetLineNo(node->parent);
4153
4154 return result;
4155}
4156
Daniel Veillard2156d432004-03-04 15:59:36 +00004157#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004158/**
4159 * xmlGetNodePath:
4160 * @node: a node
4161 *
4162 * Build a structure based Path for the given node
4163 *
4164 * Returns the new path or NULL in case of error. The caller must free
4165 * the returned string
4166 */
4167xmlChar *
4168xmlGetNodePath(xmlNodePtr node)
4169{
4170 xmlNodePtr cur, tmp, next;
4171 xmlChar *buffer = NULL, *temp;
4172 size_t buf_len;
4173 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004174 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004175 const char *name;
4176 char nametemp[100];
4177 int occur = 0;
4178
4179 if (node == NULL)
4180 return (NULL);
4181
4182 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004183 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004184 if (buffer == NULL) {
4185 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004186 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004187 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004188 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004189 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004190 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004191 xmlFree(buffer);
4192 return (NULL);
4193 }
4194
4195 buffer[0] = 0;
4196 cur = node;
4197 do {
4198 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004199 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004200 occur = 0;
4201 if ((cur->type == XML_DOCUMENT_NODE) ||
4202 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4203 if (buffer[0] == '/')
4204 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004205 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004206 next = NULL;
4207 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004208 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004209 name = (const char *) cur->name;
4210 if (cur->ns) {
William M. Brack84d83e32003-12-23 03:45:17 +00004211 if (cur->ns->prefix != NULL)
William M. Brack13dfa872004-09-18 04:52:08 +00004212 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4213 (char *)cur->ns->prefix, (char *)cur->name);
William M. Brack84d83e32003-12-23 03:45:17 +00004214 else
William M. Brack13dfa872004-09-18 04:52:08 +00004215 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4216 (char *)cur->name);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004217 nametemp[sizeof(nametemp) - 1] = 0;
4218 name = nametemp;
4219 }
4220 next = cur->parent;
4221
4222 /*
4223 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004224 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004225 */
4226 tmp = cur->prev;
4227 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004228 if ((tmp->type == XML_ELEMENT_NODE) &&
4229 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004230 occur++;
4231 tmp = tmp->prev;
4232 }
4233 if (occur == 0) {
4234 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004235 while (tmp != NULL && occur == 0) {
4236 if ((tmp->type == XML_ELEMENT_NODE) &&
4237 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004238 occur++;
4239 tmp = tmp->next;
4240 }
4241 if (occur != 0)
4242 occur = 1;
4243 } else
4244 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004245 } else if (cur->type == XML_COMMENT_NODE) {
4246 sep = "/";
4247 name = "comment()";
4248 next = cur->parent;
4249
4250 /*
4251 * Thumbler index computation
4252 */
4253 tmp = cur->prev;
4254 while (tmp != NULL) {
4255 if (tmp->type == XML_COMMENT_NODE)
4256 occur++;
4257 tmp = tmp->prev;
4258 }
4259 if (occur == 0) {
4260 tmp = cur->next;
4261 while (tmp != NULL && occur == 0) {
4262 if (tmp->type == XML_COMMENT_NODE)
4263 occur++;
4264 tmp = tmp->next;
4265 }
4266 if (occur != 0)
4267 occur = 1;
4268 } else
4269 occur++;
4270 } else if ((cur->type == XML_TEXT_NODE) ||
4271 (cur->type == XML_CDATA_SECTION_NODE)) {
4272 sep = "/";
4273 name = "text()";
4274 next = cur->parent;
4275
4276 /*
4277 * Thumbler index computation
4278 */
4279 tmp = cur->prev;
4280 while (tmp != NULL) {
4281 if ((cur->type == XML_TEXT_NODE) ||
4282 (cur->type == XML_CDATA_SECTION_NODE))
4283 occur++;
4284 tmp = tmp->prev;
4285 }
4286 if (occur == 0) {
4287 tmp = cur->next;
4288 while (tmp != NULL && occur == 0) {
Daniel Veillard1f8658a2004-08-14 21:46:31 +00004289 if ((tmp->type == XML_TEXT_NODE) ||
4290 (tmp->type == XML_CDATA_SECTION_NODE))
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004291 occur++;
4292 tmp = tmp->next;
4293 }
4294 if (occur != 0)
4295 occur = 1;
4296 } else
4297 occur++;
4298 } else if (cur->type == XML_PI_NODE) {
4299 sep = "/";
4300 snprintf(nametemp, sizeof(nametemp) - 1,
William M. Brack13dfa872004-09-18 04:52:08 +00004301 "processing-instruction('%s')", (char *)cur->name);
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004302 nametemp[sizeof(nametemp) - 1] = 0;
4303 name = nametemp;
4304
4305 next = cur->parent;
4306
4307 /*
4308 * Thumbler index computation
4309 */
4310 tmp = cur->prev;
4311 while (tmp != NULL) {
4312 if ((tmp->type == XML_PI_NODE) &&
4313 (xmlStrEqual(cur->name, tmp->name)))
4314 occur++;
4315 tmp = tmp->prev;
4316 }
4317 if (occur == 0) {
4318 tmp = cur->next;
4319 while (tmp != NULL && occur == 0) {
4320 if ((tmp->type == XML_PI_NODE) &&
4321 (xmlStrEqual(cur->name, tmp->name)))
4322 occur++;
4323 tmp = tmp->next;
4324 }
4325 if (occur != 0)
4326 occur = 1;
4327 } else
4328 occur++;
4329
Daniel Veillard8faa7832001-11-26 15:58:08 +00004330 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004331 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004332 name = (const char *) (((xmlAttrPtr) cur)->name);
4333 next = ((xmlAttrPtr) cur)->parent;
4334 } else {
4335 next = cur->parent;
4336 }
4337
4338 /*
4339 * Make sure there is enough room
4340 */
4341 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4342 buf_len =
4343 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4344 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4345 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004346 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004347 xmlFree(buf);
4348 xmlFree(buffer);
4349 return (NULL);
4350 }
4351 buffer = temp;
4352 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4353 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004354 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004355 xmlFree(buf);
4356 xmlFree(buffer);
4357 return (NULL);
4358 }
4359 buf = temp;
4360 }
4361 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004362 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004363 sep, name, (char *) buffer);
4364 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004365 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004366 sep, name, occur, (char *) buffer);
William M. Brack13dfa872004-09-18 04:52:08 +00004367 snprintf((char *) buffer, buf_len, "%s", (char *)buf);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004368 cur = next;
4369 } while (cur != NULL);
4370 xmlFree(buf);
4371 return (buffer);
4372}
Daniel Veillard652327a2003-09-29 18:02:38 +00004373#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004374
4375/**
Owen Taylor3473f882001-02-23 17:55:21 +00004376 * xmlDocGetRootElement:
4377 * @doc: the document
4378 *
4379 * Get the root element of the document (doc->children is a list
4380 * containing possibly comments, PIs, etc ...).
4381 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004382 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004383 */
4384xmlNodePtr
4385xmlDocGetRootElement(xmlDocPtr doc) {
4386 xmlNodePtr ret;
4387
4388 if (doc == NULL) return(NULL);
4389 ret = doc->children;
4390 while (ret != NULL) {
4391 if (ret->type == XML_ELEMENT_NODE)
4392 return(ret);
4393 ret = ret->next;
4394 }
4395 return(ret);
4396}
4397
Daniel Veillard2156d432004-03-04 15:59:36 +00004398#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004399/**
4400 * xmlDocSetRootElement:
4401 * @doc: the document
4402 * @root: the new document root element
4403 *
4404 * Set the root element of the document (doc->children is a list
4405 * containing possibly comments, PIs, etc ...).
4406 *
4407 * Returns the old root element if any was found
4408 */
4409xmlNodePtr
4410xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4411 xmlNodePtr old = NULL;
4412
4413 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004414 if (root == NULL)
4415 return(NULL);
4416 xmlUnlinkNode(root);
4417 root->doc = doc;
4418 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004419 old = doc->children;
4420 while (old != NULL) {
4421 if (old->type == XML_ELEMENT_NODE)
4422 break;
4423 old = old->next;
4424 }
4425 if (old == NULL) {
4426 if (doc->children == NULL) {
4427 doc->children = root;
4428 doc->last = root;
4429 } else {
4430 xmlAddSibling(doc->children, root);
4431 }
4432 } else {
4433 xmlReplaceNode(old, root);
4434 }
4435 return(old);
4436}
Daniel Veillard2156d432004-03-04 15:59:36 +00004437#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004438
Daniel Veillard2156d432004-03-04 15:59:36 +00004439#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004440/**
4441 * xmlNodeSetLang:
4442 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004443 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004444 *
4445 * Set the language of a node, i.e. the values of the xml:lang
4446 * attribute.
4447 */
4448void
4449xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004450 xmlNsPtr ns;
4451
Owen Taylor3473f882001-02-23 17:55:21 +00004452 if (cur == NULL) return;
4453 switch(cur->type) {
4454 case XML_TEXT_NODE:
4455 case XML_CDATA_SECTION_NODE:
4456 case XML_COMMENT_NODE:
4457 case XML_DOCUMENT_NODE:
4458 case XML_DOCUMENT_TYPE_NODE:
4459 case XML_DOCUMENT_FRAG_NODE:
4460 case XML_NOTATION_NODE:
4461 case XML_HTML_DOCUMENT_NODE:
4462 case XML_DTD_NODE:
4463 case XML_ELEMENT_DECL:
4464 case XML_ATTRIBUTE_DECL:
4465 case XML_ENTITY_DECL:
4466 case XML_PI_NODE:
4467 case XML_ENTITY_REF_NODE:
4468 case XML_ENTITY_NODE:
4469 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004470#ifdef LIBXML_DOCB_ENABLED
4471 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004472#endif
4473 case XML_XINCLUDE_START:
4474 case XML_XINCLUDE_END:
4475 return;
4476 case XML_ELEMENT_NODE:
4477 case XML_ATTRIBUTE_NODE:
4478 break;
4479 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004480 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4481 if (ns == NULL)
4482 return;
4483 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004484}
Daniel Veillard652327a2003-09-29 18:02:38 +00004485#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004486
4487/**
4488 * xmlNodeGetLang:
4489 * @cur: the node being checked
4490 *
4491 * Searches the language of a node, i.e. the values of the xml:lang
4492 * attribute or the one carried by the nearest ancestor.
4493 *
4494 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004495 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004496 */
4497xmlChar *
4498xmlNodeGetLang(xmlNodePtr cur) {
4499 xmlChar *lang;
4500
4501 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004502 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004503 if (lang != NULL)
4504 return(lang);
4505 cur = cur->parent;
4506 }
4507 return(NULL);
4508}
4509
4510
Daniel Veillard652327a2003-09-29 18:02:38 +00004511#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004512/**
4513 * xmlNodeSetSpacePreserve:
4514 * @cur: the node being changed
4515 * @val: the xml:space value ("0": default, 1: "preserve")
4516 *
4517 * Set (or reset) the space preserving behaviour of a node, i.e. the
4518 * value of the xml:space attribute.
4519 */
4520void
4521xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004522 xmlNsPtr ns;
4523
Owen Taylor3473f882001-02-23 17:55:21 +00004524 if (cur == NULL) return;
4525 switch(cur->type) {
4526 case XML_TEXT_NODE:
4527 case XML_CDATA_SECTION_NODE:
4528 case XML_COMMENT_NODE:
4529 case XML_DOCUMENT_NODE:
4530 case XML_DOCUMENT_TYPE_NODE:
4531 case XML_DOCUMENT_FRAG_NODE:
4532 case XML_NOTATION_NODE:
4533 case XML_HTML_DOCUMENT_NODE:
4534 case XML_DTD_NODE:
4535 case XML_ELEMENT_DECL:
4536 case XML_ATTRIBUTE_DECL:
4537 case XML_ENTITY_DECL:
4538 case XML_PI_NODE:
4539 case XML_ENTITY_REF_NODE:
4540 case XML_ENTITY_NODE:
4541 case XML_NAMESPACE_DECL:
4542 case XML_XINCLUDE_START:
4543 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004544#ifdef LIBXML_DOCB_ENABLED
4545 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004546#endif
4547 return;
4548 case XML_ELEMENT_NODE:
4549 case XML_ATTRIBUTE_NODE:
4550 break;
4551 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004552 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4553 if (ns == NULL)
4554 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004555 switch (val) {
4556 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004557 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004558 break;
4559 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004560 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004561 break;
4562 }
4563}
Daniel Veillard652327a2003-09-29 18:02:38 +00004564#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004565
4566/**
4567 * xmlNodeGetSpacePreserve:
4568 * @cur: the node being checked
4569 *
4570 * Searches the space preserving behaviour of a node, i.e. the values
4571 * of the xml:space attribute or the one carried by the nearest
4572 * ancestor.
4573 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004574 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004575 */
4576int
4577xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4578 xmlChar *space;
4579
4580 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004581 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004582 if (space != NULL) {
4583 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4584 xmlFree(space);
4585 return(1);
4586 }
4587 if (xmlStrEqual(space, BAD_CAST "default")) {
4588 xmlFree(space);
4589 return(0);
4590 }
4591 xmlFree(space);
4592 }
4593 cur = cur->parent;
4594 }
4595 return(-1);
4596}
4597
Daniel Veillard652327a2003-09-29 18:02:38 +00004598#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004599/**
4600 * xmlNodeSetName:
4601 * @cur: the node being changed
4602 * @name: the new tag name
4603 *
4604 * Set (or reset) the name of a node.
4605 */
4606void
4607xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4608 if (cur == NULL) return;
4609 if (name == NULL) return;
4610 switch(cur->type) {
4611 case XML_TEXT_NODE:
4612 case XML_CDATA_SECTION_NODE:
4613 case XML_COMMENT_NODE:
4614 case XML_DOCUMENT_TYPE_NODE:
4615 case XML_DOCUMENT_FRAG_NODE:
4616 case XML_NOTATION_NODE:
4617 case XML_HTML_DOCUMENT_NODE:
4618 case XML_NAMESPACE_DECL:
4619 case XML_XINCLUDE_START:
4620 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004621#ifdef LIBXML_DOCB_ENABLED
4622 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004623#endif
4624 return;
4625 case XML_ELEMENT_NODE:
4626 case XML_ATTRIBUTE_NODE:
4627 case XML_PI_NODE:
4628 case XML_ENTITY_REF_NODE:
4629 case XML_ENTITY_NODE:
4630 case XML_DTD_NODE:
4631 case XML_DOCUMENT_NODE:
4632 case XML_ELEMENT_DECL:
4633 case XML_ATTRIBUTE_DECL:
4634 case XML_ENTITY_DECL:
4635 break;
4636 }
4637 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4638 cur->name = xmlStrdup(name);
4639}
Daniel Veillard2156d432004-03-04 15:59:36 +00004640#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004641
Daniel Veillard2156d432004-03-04 15:59:36 +00004642#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004643/**
4644 * xmlNodeSetBase:
4645 * @cur: the node being changed
4646 * @uri: the new base URI
4647 *
4648 * Set (or reset) the base URI of a node, i.e. the value of the
4649 * xml:base attribute.
4650 */
4651void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004652xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004653 xmlNsPtr ns;
4654
Owen Taylor3473f882001-02-23 17:55:21 +00004655 if (cur == NULL) return;
4656 switch(cur->type) {
4657 case XML_TEXT_NODE:
4658 case XML_CDATA_SECTION_NODE:
4659 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004660 case XML_DOCUMENT_TYPE_NODE:
4661 case XML_DOCUMENT_FRAG_NODE:
4662 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004663 case XML_DTD_NODE:
4664 case XML_ELEMENT_DECL:
4665 case XML_ATTRIBUTE_DECL:
4666 case XML_ENTITY_DECL:
4667 case XML_PI_NODE:
4668 case XML_ENTITY_REF_NODE:
4669 case XML_ENTITY_NODE:
4670 case XML_NAMESPACE_DECL:
4671 case XML_XINCLUDE_START:
4672 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004673 return;
4674 case XML_ELEMENT_NODE:
4675 case XML_ATTRIBUTE_NODE:
4676 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004677 case XML_DOCUMENT_NODE:
4678#ifdef LIBXML_DOCB_ENABLED
4679 case XML_DOCB_DOCUMENT_NODE:
4680#endif
4681 case XML_HTML_DOCUMENT_NODE: {
4682 xmlDocPtr doc = (xmlDocPtr) cur;
4683
4684 if (doc->URL != NULL)
4685 xmlFree((xmlChar *) doc->URL);
4686 if (uri == NULL)
4687 doc->URL = NULL;
4688 else
4689 doc->URL = xmlStrdup(uri);
4690 return;
4691 }
Owen Taylor3473f882001-02-23 17:55:21 +00004692 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004693
4694 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4695 if (ns == NULL)
4696 return;
4697 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004698}
Daniel Veillard652327a2003-09-29 18:02:38 +00004699#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004700
4701/**
Owen Taylor3473f882001-02-23 17:55:21 +00004702 * xmlNodeGetBase:
4703 * @doc: the document the node pertains to
4704 * @cur: the node being checked
4705 *
4706 * Searches for the BASE URL. The code should work on both XML
4707 * and HTML document even if base mechanisms are completely different.
4708 * It returns the base as defined in RFC 2396 sections
4709 * 5.1.1. Base URI within Document Content
4710 * and
4711 * 5.1.2. Base URI from the Encapsulating Entity
4712 * However it does not return the document base (5.1.3), use
4713 * xmlDocumentGetBase() for this
4714 *
4715 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004716 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004717 */
4718xmlChar *
4719xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004720 xmlChar *oldbase = NULL;
4721 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004722
4723 if ((cur == NULL) && (doc == NULL))
4724 return(NULL);
4725 if (doc == NULL) doc = cur->doc;
4726 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4727 cur = doc->children;
4728 while ((cur != NULL) && (cur->name != NULL)) {
4729 if (cur->type != XML_ELEMENT_NODE) {
4730 cur = cur->next;
4731 continue;
4732 }
4733 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4734 cur = cur->children;
4735 continue;
4736 }
4737 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4738 cur = cur->children;
4739 continue;
4740 }
4741 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4742 return(xmlGetProp(cur, BAD_CAST "href"));
4743 }
4744 cur = cur->next;
4745 }
4746 return(NULL);
4747 }
4748 while (cur != NULL) {
4749 if (cur->type == XML_ENTITY_DECL) {
4750 xmlEntityPtr ent = (xmlEntityPtr) cur;
4751 return(xmlStrdup(ent->URI));
4752 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004753 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004754 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004755 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004756 if (oldbase != NULL) {
4757 newbase = xmlBuildURI(oldbase, base);
4758 if (newbase != NULL) {
4759 xmlFree(oldbase);
4760 xmlFree(base);
4761 oldbase = newbase;
4762 } else {
4763 xmlFree(oldbase);
4764 xmlFree(base);
4765 return(NULL);
4766 }
4767 } else {
4768 oldbase = base;
4769 }
4770 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4771 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4772 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4773 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004774 }
4775 }
Owen Taylor3473f882001-02-23 17:55:21 +00004776 cur = cur->parent;
4777 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004778 if ((doc != NULL) && (doc->URL != NULL)) {
4779 if (oldbase == NULL)
4780 return(xmlStrdup(doc->URL));
4781 newbase = xmlBuildURI(oldbase, doc->URL);
4782 xmlFree(oldbase);
4783 return(newbase);
4784 }
4785 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004786}
4787
4788/**
Daniel Veillard78697292003-10-19 20:44:43 +00004789 * xmlNodeBufGetContent:
4790 * @buffer: a buffer
4791 * @cur: the node being read
4792 *
4793 * Read the value of a node @cur, this can be either the text carried
4794 * directly by this node if it's a TEXT node or the aggregate string
4795 * of the values carried by this node child's (TEXT and ENTITY_REF).
4796 * Entity references are substituted.
4797 * Fills up the buffer @buffer with this value
4798 *
4799 * Returns 0 in case of success and -1 in case of error.
4800 */
4801int
4802xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4803{
4804 if ((cur == NULL) || (buffer == NULL)) return(-1);
4805 switch (cur->type) {
4806 case XML_CDATA_SECTION_NODE:
4807 case XML_TEXT_NODE:
4808 xmlBufferCat(buffer, cur->content);
4809 break;
4810 case XML_DOCUMENT_FRAG_NODE:
4811 case XML_ELEMENT_NODE:{
4812 xmlNodePtr tmp = cur;
4813
4814 while (tmp != NULL) {
4815 switch (tmp->type) {
4816 case XML_CDATA_SECTION_NODE:
4817 case XML_TEXT_NODE:
4818 if (tmp->content != NULL)
4819 xmlBufferCat(buffer, tmp->content);
4820 break;
4821 case XML_ENTITY_REF_NODE:
4822 xmlNodeBufGetContent(buffer, tmp->children);
4823 break;
4824 default:
4825 break;
4826 }
4827 /*
4828 * Skip to next node
4829 */
4830 if (tmp->children != NULL) {
4831 if (tmp->children->type != XML_ENTITY_DECL) {
4832 tmp = tmp->children;
4833 continue;
4834 }
4835 }
4836 if (tmp == cur)
4837 break;
4838
4839 if (tmp->next != NULL) {
4840 tmp = tmp->next;
4841 continue;
4842 }
4843
4844 do {
4845 tmp = tmp->parent;
4846 if (tmp == NULL)
4847 break;
4848 if (tmp == cur) {
4849 tmp = NULL;
4850 break;
4851 }
4852 if (tmp->next != NULL) {
4853 tmp = tmp->next;
4854 break;
4855 }
4856 } while (tmp != NULL);
4857 }
4858 break;
4859 }
4860 case XML_ATTRIBUTE_NODE:{
4861 xmlAttrPtr attr = (xmlAttrPtr) cur;
4862 xmlNodePtr tmp = attr->children;
4863
4864 while (tmp != NULL) {
4865 if (tmp->type == XML_TEXT_NODE)
4866 xmlBufferCat(buffer, tmp->content);
4867 else
4868 xmlNodeBufGetContent(buffer, tmp);
4869 tmp = tmp->next;
4870 }
4871 break;
4872 }
4873 case XML_COMMENT_NODE:
4874 case XML_PI_NODE:
4875 xmlBufferCat(buffer, cur->content);
4876 break;
4877 case XML_ENTITY_REF_NODE:{
4878 xmlEntityPtr ent;
4879 xmlNodePtr tmp;
4880
4881 /* lookup entity declaration */
4882 ent = xmlGetDocEntity(cur->doc, cur->name);
4883 if (ent == NULL)
4884 return(-1);
4885
4886 /* an entity content can be any "well balanced chunk",
4887 * i.e. the result of the content [43] production:
4888 * http://www.w3.org/TR/REC-xml#NT-content
4889 * -> we iterate through child nodes and recursive call
4890 * xmlNodeGetContent() which handles all possible node types */
4891 tmp = ent->children;
4892 while (tmp) {
4893 xmlNodeBufGetContent(buffer, tmp);
4894 tmp = tmp->next;
4895 }
4896 break;
4897 }
4898 case XML_ENTITY_NODE:
4899 case XML_DOCUMENT_TYPE_NODE:
4900 case XML_NOTATION_NODE:
4901 case XML_DTD_NODE:
4902 case XML_XINCLUDE_START:
4903 case XML_XINCLUDE_END:
4904 break;
4905 case XML_DOCUMENT_NODE:
4906#ifdef LIBXML_DOCB_ENABLED
4907 case XML_DOCB_DOCUMENT_NODE:
4908#endif
4909 case XML_HTML_DOCUMENT_NODE:
4910 cur = cur->children;
4911 while (cur!= NULL) {
4912 if ((cur->type == XML_ELEMENT_NODE) ||
4913 (cur->type == XML_TEXT_NODE) ||
4914 (cur->type == XML_CDATA_SECTION_NODE)) {
4915 xmlNodeBufGetContent(buffer, cur);
4916 }
4917 cur = cur->next;
4918 }
4919 break;
4920 case XML_NAMESPACE_DECL:
4921 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
4922 break;
4923 case XML_ELEMENT_DECL:
4924 case XML_ATTRIBUTE_DECL:
4925 case XML_ENTITY_DECL:
4926 break;
4927 }
4928 return(0);
4929}
4930/**
Owen Taylor3473f882001-02-23 17:55:21 +00004931 * xmlNodeGetContent:
4932 * @cur: the node being read
4933 *
4934 * Read the value of a node, this can be either the text carried
4935 * directly by this node if it's a TEXT node or the aggregate string
4936 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004937 * Entity references are substituted.
4938 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004939 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004940 */
4941xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004942xmlNodeGetContent(xmlNodePtr cur)
4943{
4944 if (cur == NULL)
4945 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004946 switch (cur->type) {
4947 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004948 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00004949 xmlBufferPtr buffer;
4950 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004951
Daniel Veillard814a76d2003-01-23 18:24:20 +00004952 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004953 if (buffer == NULL)
4954 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00004955 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004956 ret = buffer->content;
4957 buffer->content = NULL;
4958 xmlBufferFree(buffer);
4959 return (ret);
4960 }
4961 case XML_ATTRIBUTE_NODE:{
4962 xmlAttrPtr attr = (xmlAttrPtr) cur;
4963
4964 if (attr->parent != NULL)
4965 return (xmlNodeListGetString
4966 (attr->parent->doc, attr->children, 1));
4967 else
4968 return (xmlNodeListGetString(NULL, attr->children, 1));
4969 break;
4970 }
Owen Taylor3473f882001-02-23 17:55:21 +00004971 case XML_COMMENT_NODE:
4972 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004973 if (cur->content != NULL)
4974 return (xmlStrdup(cur->content));
4975 return (NULL);
4976 case XML_ENTITY_REF_NODE:{
4977 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00004978 xmlBufferPtr buffer;
4979 xmlChar *ret;
4980
4981 /* lookup entity declaration */
4982 ent = xmlGetDocEntity(cur->doc, cur->name);
4983 if (ent == NULL)
4984 return (NULL);
4985
4986 buffer = xmlBufferCreate();
4987 if (buffer == NULL)
4988 return (NULL);
4989
Daniel Veillardc4696922003-10-19 21:47:14 +00004990 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004991
4992 ret = buffer->content;
4993 buffer->content = NULL;
4994 xmlBufferFree(buffer);
4995 return (ret);
4996 }
Owen Taylor3473f882001-02-23 17:55:21 +00004997 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004998 case XML_DOCUMENT_TYPE_NODE:
4999 case XML_NOTATION_NODE:
5000 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005001 case XML_XINCLUDE_START:
5002 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00005003 return (NULL);
5004 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005005#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005006 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005007#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005008 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00005009 xmlBufferPtr buffer;
5010 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005011
Daniel Veillardc4696922003-10-19 21:47:14 +00005012 buffer = xmlBufferCreate();
5013 if (buffer == NULL)
5014 return (NULL);
5015
5016 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5017
5018 ret = buffer->content;
5019 buffer->content = NULL;
5020 xmlBufferFree(buffer);
5021 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005022 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005023 case XML_NAMESPACE_DECL: {
5024 xmlChar *tmp;
5025
5026 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5027 return (tmp);
5028 }
Owen Taylor3473f882001-02-23 17:55:21 +00005029 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005030 /* TODO !!! */
5031 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005032 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005033 /* TODO !!! */
5034 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005035 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005036 /* TODO !!! */
5037 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005038 case XML_CDATA_SECTION_NODE:
5039 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005040 if (cur->content != NULL)
5041 return (xmlStrdup(cur->content));
5042 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005043 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005044 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005045}
Daniel Veillard652327a2003-09-29 18:02:38 +00005046
Owen Taylor3473f882001-02-23 17:55:21 +00005047/**
5048 * xmlNodeSetContent:
5049 * @cur: the node being modified
5050 * @content: the new value of the content
5051 *
5052 * Replace the content of a node.
5053 */
5054void
5055xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5056 if (cur == NULL) {
5057#ifdef DEBUG_TREE
5058 xmlGenericError(xmlGenericErrorContext,
5059 "xmlNodeSetContent : node == NULL\n");
5060#endif
5061 return;
5062 }
5063 switch (cur->type) {
5064 case XML_DOCUMENT_FRAG_NODE:
5065 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005066 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005067 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5068 cur->children = xmlStringGetNodeList(cur->doc, content);
5069 UPDATE_LAST_CHILD_AND_PARENT(cur)
5070 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005071 case XML_TEXT_NODE:
5072 case XML_CDATA_SECTION_NODE:
5073 case XML_ENTITY_REF_NODE:
5074 case XML_ENTITY_NODE:
5075 case XML_PI_NODE:
5076 case XML_COMMENT_NODE:
5077 if (cur->content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005078 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5079 xmlDictOwns(cur->doc->dict, cur->content)))
5080 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005081 }
5082 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5083 cur->last = cur->children = NULL;
5084 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005085 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005086 } else
5087 cur->content = NULL;
5088 break;
5089 case XML_DOCUMENT_NODE:
5090 case XML_HTML_DOCUMENT_NODE:
5091 case XML_DOCUMENT_TYPE_NODE:
5092 case XML_XINCLUDE_START:
5093 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005094#ifdef LIBXML_DOCB_ENABLED
5095 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005096#endif
5097 break;
5098 case XML_NOTATION_NODE:
5099 break;
5100 case XML_DTD_NODE:
5101 break;
5102 case XML_NAMESPACE_DECL:
5103 break;
5104 case XML_ELEMENT_DECL:
5105 /* TODO !!! */
5106 break;
5107 case XML_ATTRIBUTE_DECL:
5108 /* TODO !!! */
5109 break;
5110 case XML_ENTITY_DECL:
5111 /* TODO !!! */
5112 break;
5113 }
5114}
5115
Daniel Veillard652327a2003-09-29 18:02:38 +00005116#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005117/**
5118 * xmlNodeSetContentLen:
5119 * @cur: the node being modified
5120 * @content: the new value of the content
5121 * @len: the size of @content
5122 *
5123 * Replace the content of a node.
5124 */
5125void
5126xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5127 if (cur == NULL) {
5128#ifdef DEBUG_TREE
5129 xmlGenericError(xmlGenericErrorContext,
5130 "xmlNodeSetContentLen : node == NULL\n");
5131#endif
5132 return;
5133 }
5134 switch (cur->type) {
5135 case XML_DOCUMENT_FRAG_NODE:
5136 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005137 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005138 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5139 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5140 UPDATE_LAST_CHILD_AND_PARENT(cur)
5141 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005142 case XML_TEXT_NODE:
5143 case XML_CDATA_SECTION_NODE:
5144 case XML_ENTITY_REF_NODE:
5145 case XML_ENTITY_NODE:
5146 case XML_PI_NODE:
5147 case XML_COMMENT_NODE:
5148 case XML_NOTATION_NODE:
5149 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005150 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005151 }
5152 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5153 cur->children = cur->last = NULL;
5154 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005155 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005156 } else
5157 cur->content = NULL;
5158 break;
5159 case XML_DOCUMENT_NODE:
5160 case XML_DTD_NODE:
5161 case XML_HTML_DOCUMENT_NODE:
5162 case XML_DOCUMENT_TYPE_NODE:
5163 case XML_NAMESPACE_DECL:
5164 case XML_XINCLUDE_START:
5165 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005166#ifdef LIBXML_DOCB_ENABLED
5167 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005168#endif
5169 break;
5170 case XML_ELEMENT_DECL:
5171 /* TODO !!! */
5172 break;
5173 case XML_ATTRIBUTE_DECL:
5174 /* TODO !!! */
5175 break;
5176 case XML_ENTITY_DECL:
5177 /* TODO !!! */
5178 break;
5179 }
5180}
Daniel Veillard652327a2003-09-29 18:02:38 +00005181#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005182
5183/**
5184 * xmlNodeAddContentLen:
5185 * @cur: the node being modified
5186 * @content: extra content
5187 * @len: the size of @content
5188 *
5189 * Append the extra substring to the node content.
5190 */
5191void
5192xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5193 if (cur == NULL) {
5194#ifdef DEBUG_TREE
5195 xmlGenericError(xmlGenericErrorContext,
5196 "xmlNodeAddContentLen : node == NULL\n");
5197#endif
5198 return;
5199 }
5200 if (len <= 0) return;
5201 switch (cur->type) {
5202 case XML_DOCUMENT_FRAG_NODE:
5203 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005204 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005205
Daniel Veillard7db37732001-07-12 01:20:08 +00005206 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005207 newNode = xmlNewTextLen(content, len);
5208 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005209 tmp = xmlAddChild(cur, newNode);
5210 if (tmp != newNode)
5211 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005212 if ((last != NULL) && (last->next == newNode)) {
5213 xmlTextMerge(last, newNode);
5214 }
5215 }
5216 break;
5217 }
5218 case XML_ATTRIBUTE_NODE:
5219 break;
5220 case XML_TEXT_NODE:
5221 case XML_CDATA_SECTION_NODE:
5222 case XML_ENTITY_REF_NODE:
5223 case XML_ENTITY_NODE:
5224 case XML_PI_NODE:
5225 case XML_COMMENT_NODE:
5226 case XML_NOTATION_NODE:
5227 if (content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005228 if ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5229 xmlDictOwns(cur->doc->dict, cur->content)) {
5230 cur->content =
5231 xmlStrncatNew(cur->content, content, len);
5232 break;
5233 }
Owen Taylor3473f882001-02-23 17:55:21 +00005234 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005235 }
5236 case XML_DOCUMENT_NODE:
5237 case XML_DTD_NODE:
5238 case XML_HTML_DOCUMENT_NODE:
5239 case XML_DOCUMENT_TYPE_NODE:
5240 case XML_NAMESPACE_DECL:
5241 case XML_XINCLUDE_START:
5242 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005243#ifdef LIBXML_DOCB_ENABLED
5244 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005245#endif
5246 break;
5247 case XML_ELEMENT_DECL:
5248 case XML_ATTRIBUTE_DECL:
5249 case XML_ENTITY_DECL:
5250 break;
5251 }
5252}
5253
5254/**
5255 * xmlNodeAddContent:
5256 * @cur: the node being modified
5257 * @content: extra content
5258 *
5259 * Append the extra substring to the node content.
5260 */
5261void
5262xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5263 int len;
5264
5265 if (cur == NULL) {
5266#ifdef DEBUG_TREE
5267 xmlGenericError(xmlGenericErrorContext,
5268 "xmlNodeAddContent : node == NULL\n");
5269#endif
5270 return;
5271 }
5272 if (content == NULL) return;
5273 len = xmlStrlen(content);
5274 xmlNodeAddContentLen(cur, content, len);
5275}
5276
5277/**
5278 * xmlTextMerge:
5279 * @first: the first text node
5280 * @second: the second text node being merged
5281 *
5282 * Merge two text nodes into one
5283 * Returns the first text node augmented
5284 */
5285xmlNodePtr
5286xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5287 if (first == NULL) return(second);
5288 if (second == NULL) return(first);
5289 if (first->type != XML_TEXT_NODE) return(first);
5290 if (second->type != XML_TEXT_NODE) return(first);
5291 if (second->name != first->name)
5292 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005293 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005294 xmlUnlinkNode(second);
5295 xmlFreeNode(second);
5296 return(first);
5297}
5298
Daniel Veillard2156d432004-03-04 15:59:36 +00005299#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005300/**
5301 * xmlGetNsList:
5302 * @doc: the document
5303 * @node: the current node
5304 *
5305 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005306 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005307 * that need to be freed by the caller or NULL if no
5308 * namespace if defined
5309 */
5310xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005311xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5312{
Owen Taylor3473f882001-02-23 17:55:21 +00005313 xmlNsPtr cur;
5314 xmlNsPtr *ret = NULL;
5315 int nbns = 0;
5316 int maxns = 10;
5317 int i;
5318
5319 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005320 if (node->type == XML_ELEMENT_NODE) {
5321 cur = node->nsDef;
5322 while (cur != NULL) {
5323 if (ret == NULL) {
5324 ret =
5325 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5326 sizeof(xmlNsPtr));
5327 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005328 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005329 return (NULL);
5330 }
5331 ret[nbns] = NULL;
5332 }
5333 for (i = 0; i < nbns; i++) {
5334 if ((cur->prefix == ret[i]->prefix) ||
5335 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5336 break;
5337 }
5338 if (i >= nbns) {
5339 if (nbns >= maxns) {
5340 maxns *= 2;
5341 ret = (xmlNsPtr *) xmlRealloc(ret,
5342 (maxns +
5343 1) *
5344 sizeof(xmlNsPtr));
5345 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005346 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005347 return (NULL);
5348 }
5349 }
5350 ret[nbns++] = cur;
5351 ret[nbns] = NULL;
5352 }
Owen Taylor3473f882001-02-23 17:55:21 +00005353
Daniel Veillard77044732001-06-29 21:31:07 +00005354 cur = cur->next;
5355 }
5356 }
5357 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005358 }
Daniel Veillard77044732001-06-29 21:31:07 +00005359 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005360}
Daniel Veillard652327a2003-09-29 18:02:38 +00005361#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005362
5363/**
5364 * xmlSearchNs:
5365 * @doc: the document
5366 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005367 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005368 *
5369 * Search a Ns registered under a given name space for a document.
5370 * recurse on the parents until it finds the defined namespace
5371 * or return NULL otherwise.
5372 * @nameSpace can be NULL, this is a search for the default namespace.
5373 * We don't allow to cross entities boundaries. If you don't declare
5374 * the namespace within those you will be in troubles !!! A warning
5375 * is generated to cover this case.
5376 *
5377 * Returns the namespace pointer or NULL.
5378 */
5379xmlNsPtr
5380xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005381
Owen Taylor3473f882001-02-23 17:55:21 +00005382 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005383 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005384
5385 if (node == NULL) return(NULL);
5386 if ((nameSpace != NULL) &&
5387 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005388 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5389 /*
5390 * The XML-1.0 namespace is normally held on the root
5391 * element. In this case exceptionally create it on the
5392 * node element.
5393 */
5394 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5395 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005396 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005397 return(NULL);
5398 }
5399 memset(cur, 0, sizeof(xmlNs));
5400 cur->type = XML_LOCAL_NAMESPACE;
5401 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5402 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5403 cur->next = node->nsDef;
5404 node->nsDef = cur;
5405 return(cur);
5406 }
Owen Taylor3473f882001-02-23 17:55:21 +00005407 if (doc->oldNs == NULL) {
5408 /*
5409 * Allocate a new Namespace and fill the fields.
5410 */
5411 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5412 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005413 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005414 return(NULL);
5415 }
5416 memset(doc->oldNs, 0, sizeof(xmlNs));
5417 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5418
5419 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5420 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5421 }
5422 return(doc->oldNs);
5423 }
5424 while (node != NULL) {
5425 if ((node->type == XML_ENTITY_REF_NODE) ||
5426 (node->type == XML_ENTITY_NODE) ||
5427 (node->type == XML_ENTITY_DECL))
5428 return(NULL);
5429 if (node->type == XML_ELEMENT_NODE) {
5430 cur = node->nsDef;
5431 while (cur != NULL) {
5432 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5433 (cur->href != NULL))
5434 return(cur);
5435 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5436 (cur->href != NULL) &&
5437 (xmlStrEqual(cur->prefix, nameSpace)))
5438 return(cur);
5439 cur = cur->next;
5440 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005441 if (orig != node) {
5442 cur = node->ns;
5443 if (cur != NULL) {
5444 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5445 (cur->href != NULL))
5446 return(cur);
5447 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5448 (cur->href != NULL) &&
5449 (xmlStrEqual(cur->prefix, nameSpace)))
5450 return(cur);
5451 }
5452 }
Owen Taylor3473f882001-02-23 17:55:21 +00005453 }
5454 node = node->parent;
5455 }
5456 return(NULL);
5457}
5458
5459/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005460 * xmlNsInScope:
5461 * @doc: the document
5462 * @node: the current node
5463 * @ancestor: the ancestor carrying the namespace
5464 * @prefix: the namespace prefix
5465 *
5466 * Verify that the given namespace held on @ancestor is still in scope
5467 * on node.
5468 *
5469 * Returns 1 if true, 0 if false and -1 in case of error.
5470 */
5471static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005472xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5473 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005474{
5475 xmlNsPtr tst;
5476
5477 while ((node != NULL) && (node != ancestor)) {
5478 if ((node->type == XML_ENTITY_REF_NODE) ||
5479 (node->type == XML_ENTITY_NODE) ||
5480 (node->type == XML_ENTITY_DECL))
5481 return (-1);
5482 if (node->type == XML_ELEMENT_NODE) {
5483 tst = node->nsDef;
5484 while (tst != NULL) {
5485 if ((tst->prefix == NULL)
5486 && (prefix == NULL))
5487 return (0);
5488 if ((tst->prefix != NULL)
5489 && (prefix != NULL)
5490 && (xmlStrEqual(tst->prefix, prefix)))
5491 return (0);
5492 tst = tst->next;
5493 }
5494 }
5495 node = node->parent;
5496 }
5497 if (node != ancestor)
5498 return (-1);
5499 return (1);
5500}
5501
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005502/**
Owen Taylor3473f882001-02-23 17:55:21 +00005503 * xmlSearchNsByHref:
5504 * @doc: the document
5505 * @node: the current node
5506 * @href: the namespace value
5507 *
5508 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5509 * the defined namespace or return NULL otherwise.
5510 * Returns the namespace pointer or NULL.
5511 */
5512xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005513xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5514{
Owen Taylor3473f882001-02-23 17:55:21 +00005515 xmlNsPtr cur;
5516 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005517 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005518
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005519 if ((node == NULL) || (href == NULL))
5520 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005521 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005522 /*
5523 * Only the document can hold the XML spec namespace.
5524 */
5525 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5526 /*
5527 * The XML-1.0 namespace is normally held on the root
5528 * element. In this case exceptionally create it on the
5529 * node element.
5530 */
5531 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5532 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005533 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005534 return (NULL);
5535 }
5536 memset(cur, 0, sizeof(xmlNs));
5537 cur->type = XML_LOCAL_NAMESPACE;
5538 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5539 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5540 cur->next = node->nsDef;
5541 node->nsDef = cur;
5542 return (cur);
5543 }
5544 if (doc->oldNs == NULL) {
5545 /*
5546 * Allocate a new Namespace and fill the fields.
5547 */
5548 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5549 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005550 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005551 return (NULL);
5552 }
5553 memset(doc->oldNs, 0, sizeof(xmlNs));
5554 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005555
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005556 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5557 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5558 }
5559 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005560 }
Daniel Veillard62040be2004-05-17 03:17:26 +00005561 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00005562 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005563 if ((node->type == XML_ENTITY_REF_NODE) ||
5564 (node->type == XML_ENTITY_NODE) ||
5565 (node->type == XML_ENTITY_DECL))
5566 return (NULL);
5567 if (node->type == XML_ELEMENT_NODE) {
5568 cur = node->nsDef;
5569 while (cur != NULL) {
5570 if ((cur->href != NULL) && (href != NULL) &&
5571 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005572 if (((!is_attr) || (cur->prefix != NULL)) &&
5573 (xmlNsInScope(doc, orig, node, cur->href) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005574 return (cur);
5575 }
5576 cur = cur->next;
5577 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005578 if (orig != node) {
5579 cur = node->ns;
5580 if (cur != NULL) {
5581 if ((cur->href != NULL) && (href != NULL) &&
5582 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005583 if (((!is_attr) || (cur->prefix != NULL)) &&
5584 (xmlNsInScope(doc, orig, node, cur->href) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00005585 return (cur);
5586 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005587 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005588 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005589 }
5590 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005591 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005592 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005593}
5594
5595/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005596 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005597 * @doc: the document
5598 * @tree: a node expected to hold the new namespace
5599 * @ns: the original namespace
5600 *
5601 * This function tries to locate a namespace definition in a tree
5602 * ancestors, or create a new namespace definition node similar to
5603 * @ns trying to reuse the same prefix. However if the given prefix is
5604 * null (default namespace) or reused within the subtree defined by
5605 * @tree or on one of its ancestors then a new prefix is generated.
5606 * Returns the (new) namespace definition or NULL in case of error
5607 */
5608xmlNsPtr
5609xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5610 xmlNsPtr def;
5611 xmlChar prefix[50];
5612 int counter = 1;
5613
5614 if (tree == NULL) {
5615#ifdef DEBUG_TREE
5616 xmlGenericError(xmlGenericErrorContext,
5617 "xmlNewReconciliedNs : tree == NULL\n");
5618#endif
5619 return(NULL);
5620 }
5621 if (ns == NULL) {
5622#ifdef DEBUG_TREE
5623 xmlGenericError(xmlGenericErrorContext,
5624 "xmlNewReconciliedNs : ns == NULL\n");
5625#endif
5626 return(NULL);
5627 }
5628 /*
5629 * Search an existing namespace definition inherited.
5630 */
5631 def = xmlSearchNsByHref(doc, tree, ns->href);
5632 if (def != NULL)
5633 return(def);
5634
5635 /*
5636 * Find a close prefix which is not already in use.
5637 * Let's strip namespace prefixes longer than 20 chars !
5638 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005639 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005640 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005641 else
William M. Brack13dfa872004-09-18 04:52:08 +00005642 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005643
Owen Taylor3473f882001-02-23 17:55:21 +00005644 def = xmlSearchNs(doc, tree, prefix);
5645 while (def != NULL) {
5646 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005647 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005648 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005649 else
William M. Brack13dfa872004-09-18 04:52:08 +00005650 snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
5651 (char *)ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005652 def = xmlSearchNs(doc, tree, prefix);
5653 }
5654
5655 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005656 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005657 */
5658 def = xmlNewNs(tree, ns->href, prefix);
5659 return(def);
5660}
5661
Daniel Veillard652327a2003-09-29 18:02:38 +00005662#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005663/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005664 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005665 * @doc: the document
5666 * @tree: a node defining the subtree to reconciliate
5667 *
5668 * This function checks that all the namespaces declared within the given
5669 * tree are properly declared. This is needed for example after Copy or Cut
5670 * and then paste operations. The subtree may still hold pointers to
5671 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005672 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005673 * the new environment. If not possible the new namespaces are redeclared
5674 * on @tree at the top of the given subtree.
5675 * Returns the number of namespace declarations created or -1 in case of error.
5676 */
5677int
5678xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5679 xmlNsPtr *oldNs = NULL;
5680 xmlNsPtr *newNs = NULL;
5681 int sizeCache = 0;
5682 int nbCache = 0;
5683
5684 xmlNsPtr n;
5685 xmlNodePtr node = tree;
5686 xmlAttrPtr attr;
5687 int ret = 0, i;
5688
5689 while (node != NULL) {
5690 /*
5691 * Reconciliate the node namespace
5692 */
5693 if (node->ns != NULL) {
5694 /*
5695 * initialize the cache if needed
5696 */
5697 if (sizeCache == 0) {
5698 sizeCache = 10;
5699 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5700 sizeof(xmlNsPtr));
5701 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005702 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005703 return(-1);
5704 }
5705 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5706 sizeof(xmlNsPtr));
5707 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005708 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005709 xmlFree(oldNs);
5710 return(-1);
5711 }
5712 }
5713 for (i = 0;i < nbCache;i++) {
5714 if (oldNs[i] == node->ns) {
5715 node->ns = newNs[i];
5716 break;
5717 }
5718 }
5719 if (i == nbCache) {
5720 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005721 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005722 */
5723 n = xmlNewReconciliedNs(doc, tree, node->ns);
5724 if (n != NULL) { /* :-( what if else ??? */
5725 /*
5726 * check if we need to grow the cache buffers.
5727 */
5728 if (sizeCache <= nbCache) {
5729 sizeCache *= 2;
5730 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5731 sizeof(xmlNsPtr));
5732 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005733 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005734 xmlFree(newNs);
5735 return(-1);
5736 }
5737 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5738 sizeof(xmlNsPtr));
5739 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005740 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005741 xmlFree(oldNs);
5742 return(-1);
5743 }
5744 }
5745 newNs[nbCache] = n;
5746 oldNs[nbCache++] = node->ns;
5747 node->ns = n;
5748 }
5749 }
5750 }
5751 /*
5752 * now check for namespace hold by attributes on the node.
5753 */
5754 attr = node->properties;
5755 while (attr != NULL) {
5756 if (attr->ns != NULL) {
5757 /*
5758 * initialize the cache if needed
5759 */
5760 if (sizeCache == 0) {
5761 sizeCache = 10;
5762 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5763 sizeof(xmlNsPtr));
5764 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005765 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005766 return(-1);
5767 }
5768 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5769 sizeof(xmlNsPtr));
5770 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005771 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005772 xmlFree(oldNs);
5773 return(-1);
5774 }
5775 }
5776 for (i = 0;i < nbCache;i++) {
5777 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005778 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005779 break;
5780 }
5781 }
5782 if (i == nbCache) {
5783 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005784 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005785 */
5786 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5787 if (n != NULL) { /* :-( what if else ??? */
5788 /*
5789 * check if we need to grow the cache buffers.
5790 */
5791 if (sizeCache <= nbCache) {
5792 sizeCache *= 2;
5793 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5794 sizeof(xmlNsPtr));
5795 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005796 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005797 xmlFree(newNs);
5798 return(-1);
5799 }
5800 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5801 sizeof(xmlNsPtr));
5802 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005803 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005804 xmlFree(oldNs);
5805 return(-1);
5806 }
5807 }
5808 newNs[nbCache] = n;
5809 oldNs[nbCache++] = attr->ns;
5810 attr->ns = n;
5811 }
5812 }
5813 }
5814 attr = attr->next;
5815 }
5816
5817 /*
5818 * Browse the full subtree, deep first
5819 */
Daniel Veillardac996a12004-07-30 12:02:58 +00005820 if (node->children != NULL && node->type != XML_ENTITY_REF_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00005821 /* deep first */
5822 node = node->children;
5823 } else if ((node != tree) && (node->next != NULL)) {
5824 /* then siblings */
5825 node = node->next;
5826 } else if (node != tree) {
5827 /* go up to parents->next if needed */
5828 while (node != tree) {
5829 if (node->parent != NULL)
5830 node = node->parent;
5831 if ((node != tree) && (node->next != NULL)) {
5832 node = node->next;
5833 break;
5834 }
5835 if (node->parent == NULL) {
5836 node = NULL;
5837 break;
5838 }
5839 }
5840 /* exit condition */
5841 if (node == tree)
5842 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005843 } else
5844 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005845 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005846 if (oldNs != NULL)
5847 xmlFree(oldNs);
5848 if (newNs != NULL)
5849 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005850 return(ret);
5851}
Daniel Veillard652327a2003-09-29 18:02:38 +00005852#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005853
5854/**
5855 * xmlHasProp:
5856 * @node: the node
5857 * @name: the attribute name
5858 *
5859 * Search an attribute associated to a node
5860 * This function also looks in DTD attribute declaration for #FIXED or
5861 * default declaration values unless DTD use has been turned off.
5862 *
5863 * Returns the attribute or the attribute declaration or NULL if
5864 * neither was found.
5865 */
5866xmlAttrPtr
5867xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5868 xmlAttrPtr prop;
5869 xmlDocPtr doc;
5870
5871 if ((node == NULL) || (name == NULL)) return(NULL);
5872 /*
5873 * Check on the properties attached to the node
5874 */
5875 prop = node->properties;
5876 while (prop != NULL) {
5877 if (xmlStrEqual(prop->name, name)) {
5878 return(prop);
5879 }
5880 prop = prop->next;
5881 }
5882 if (!xmlCheckDTD) return(NULL);
5883
5884 /*
5885 * Check if there is a default declaration in the internal
5886 * or external subsets
5887 */
5888 doc = node->doc;
5889 if (doc != NULL) {
5890 xmlAttributePtr attrDecl;
5891 if (doc->intSubset != NULL) {
5892 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5893 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5894 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005895 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5896 /* return attribute declaration only if a default value is given
5897 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005898 return((xmlAttrPtr) attrDecl);
5899 }
5900 }
5901 return(NULL);
5902}
5903
5904/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005905 * xmlHasNsProp:
5906 * @node: the node
5907 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005908 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005909 *
5910 * Search for an attribute associated to a node
5911 * This attribute has to be anchored in the namespace specified.
5912 * This does the entity substitution.
5913 * This function looks in DTD attribute declaration for #FIXED or
5914 * default declaration values unless DTD use has been turned off.
5915 *
5916 * Returns the attribute or the attribute declaration or NULL
5917 * if neither was found.
5918 */
5919xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005920xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005921 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00005922#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005923 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00005924#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005925
5926 if (node == NULL)
5927 return(NULL);
5928
5929 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005930 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005931 return(xmlHasProp(node, name));
5932 while (prop != NULL) {
5933 /*
5934 * One need to have
5935 * - same attribute names
5936 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005937 */
5938 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005939 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5940 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005941 }
5942 prop = prop->next;
5943 }
5944 if (!xmlCheckDTD) return(NULL);
5945
Daniel Veillard652327a2003-09-29 18:02:38 +00005946#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005947 /*
5948 * Check if there is a default declaration in the internal
5949 * or external subsets
5950 */
5951 doc = node->doc;
5952 if (doc != NULL) {
5953 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005954 xmlAttributePtr attrDecl = NULL;
5955 xmlNsPtr *nsList, *cur;
5956 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005957
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005958 nsList = xmlGetNsList(node->doc, node);
5959 if (nsList == NULL)
5960 return(NULL);
5961 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5962 ename = xmlStrdup(node->ns->prefix);
5963 ename = xmlStrcat(ename, BAD_CAST ":");
5964 ename = xmlStrcat(ename, node->name);
5965 } else {
5966 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005967 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005968 if (ename == NULL) {
5969 xmlFree(nsList);
5970 return(NULL);
5971 }
5972
5973 cur = nsList;
5974 while (*cur != NULL) {
5975 if (xmlStrEqual((*cur)->href, nameSpace)) {
5976 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5977 name, (*cur)->prefix);
5978 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5979 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5980 name, (*cur)->prefix);
5981 }
5982 cur++;
5983 }
5984 xmlFree(nsList);
5985 xmlFree(ename);
5986 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005987 }
5988 }
Daniel Veillard652327a2003-09-29 18:02:38 +00005989#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005990 return(NULL);
5991}
5992
5993/**
Owen Taylor3473f882001-02-23 17:55:21 +00005994 * xmlGetProp:
5995 * @node: the node
5996 * @name: the attribute name
5997 *
5998 * Search and get the value of an attribute associated to a node
5999 * This does the entity substitution.
6000 * This function looks in DTD attribute declaration for #FIXED or
6001 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00006002 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00006003 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6004 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00006005 *
6006 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006007 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006008 */
6009xmlChar *
6010xmlGetProp(xmlNodePtr node, const xmlChar *name) {
6011 xmlAttrPtr prop;
6012 xmlDocPtr doc;
6013
6014 if ((node == NULL) || (name == NULL)) return(NULL);
6015 /*
6016 * Check on the properties attached to the node
6017 */
6018 prop = node->properties;
6019 while (prop != NULL) {
6020 if (xmlStrEqual(prop->name, name)) {
6021 xmlChar *ret;
6022
6023 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6024 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6025 return(ret);
6026 }
6027 prop = prop->next;
6028 }
6029 if (!xmlCheckDTD) return(NULL);
6030
6031 /*
6032 * Check if there is a default declaration in the internal
6033 * or external subsets
6034 */
6035 doc = node->doc;
6036 if (doc != NULL) {
6037 xmlAttributePtr attrDecl;
6038 if (doc->intSubset != NULL) {
6039 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6040 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6041 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006042 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6043 /* return attribute declaration only if a default value is given
6044 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006045 return(xmlStrdup(attrDecl->defaultValue));
6046 }
6047 }
6048 return(NULL);
6049}
6050
6051/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006052 * xmlGetNoNsProp:
6053 * @node: the node
6054 * @name: the attribute name
6055 *
6056 * Search and get the value of an attribute associated to a node
6057 * This does the entity substitution.
6058 * This function looks in DTD attribute declaration for #FIXED or
6059 * default declaration values unless DTD use has been turned off.
6060 * This function is similar to xmlGetProp except it will accept only
6061 * an attribute in no namespace.
6062 *
6063 * Returns the attribute value or NULL if not found.
6064 * It's up to the caller to free the memory with xmlFree().
6065 */
6066xmlChar *
6067xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6068 xmlAttrPtr prop;
6069 xmlDocPtr doc;
6070
6071 if ((node == NULL) || (name == NULL)) return(NULL);
6072 /*
6073 * Check on the properties attached to the node
6074 */
6075 prop = node->properties;
6076 while (prop != NULL) {
6077 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6078 xmlChar *ret;
6079
6080 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6081 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6082 return(ret);
6083 }
6084 prop = prop->next;
6085 }
6086 if (!xmlCheckDTD) return(NULL);
6087
6088 /*
6089 * Check if there is a default declaration in the internal
6090 * or external subsets
6091 */
6092 doc = node->doc;
6093 if (doc != NULL) {
6094 xmlAttributePtr attrDecl;
6095 if (doc->intSubset != NULL) {
6096 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6097 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6098 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006099 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6100 /* return attribute declaration only if a default value is given
6101 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006102 return(xmlStrdup(attrDecl->defaultValue));
6103 }
6104 }
6105 return(NULL);
6106}
6107
6108/**
Owen Taylor3473f882001-02-23 17:55:21 +00006109 * xmlGetNsProp:
6110 * @node: the node
6111 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006112 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006113 *
6114 * Search and get the value of an attribute associated to a node
6115 * This attribute has to be anchored in the namespace specified.
6116 * This does the entity substitution.
6117 * This function looks in DTD attribute declaration for #FIXED or
6118 * default declaration values unless DTD use has been turned off.
6119 *
6120 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006121 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006122 */
6123xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006124xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006125 xmlAttrPtr prop;
6126 xmlDocPtr doc;
6127 xmlNsPtr ns;
6128
6129 if (node == NULL)
6130 return(NULL);
6131
6132 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006133 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006134 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006135 while (prop != NULL) {
6136 /*
6137 * One need to have
6138 * - same attribute names
6139 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006140 */
6141 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006142 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006143 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006144 xmlChar *ret;
6145
6146 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6147 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6148 return(ret);
6149 }
6150 prop = prop->next;
6151 }
6152 if (!xmlCheckDTD) return(NULL);
6153
6154 /*
6155 * Check if there is a default declaration in the internal
6156 * or external subsets
6157 */
6158 doc = node->doc;
6159 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006160 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006161 xmlAttributePtr attrDecl;
6162
Owen Taylor3473f882001-02-23 17:55:21 +00006163 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6164 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6165 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6166
6167 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6168 /*
6169 * The DTD declaration only allows a prefix search
6170 */
6171 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006172 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006173 return(xmlStrdup(attrDecl->defaultValue));
6174 }
6175 }
6176 }
6177 return(NULL);
6178}
6179
Daniel Veillard2156d432004-03-04 15:59:36 +00006180#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6181/**
6182 * xmlUnsetProp:
6183 * @node: the node
6184 * @name: the attribute name
6185 *
6186 * Remove an attribute carried by a node.
6187 * Returns 0 if successful, -1 if not found
6188 */
6189int
6190xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
6191 xmlAttrPtr prop, prev = NULL;;
6192
6193 if ((node == NULL) || (name == NULL))
6194 return(-1);
6195 prop = node->properties;
6196 while (prop != NULL) {
6197 if ((xmlStrEqual(prop->name, name)) &&
6198 (prop->ns == NULL)) {
6199 if (prev == NULL)
6200 node->properties = prop->next;
6201 else
6202 prev->next = prop->next;
6203 xmlFreeProp(prop);
6204 return(0);
6205 }
6206 prev = prop;
6207 prop = prop->next;
6208 }
6209 return(-1);
6210}
6211
6212/**
6213 * xmlUnsetNsProp:
6214 * @node: the node
6215 * @ns: the namespace definition
6216 * @name: the attribute name
6217 *
6218 * Remove an attribute carried by a node.
6219 * Returns 0 if successful, -1 if not found
6220 */
6221int
6222xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6223 xmlAttrPtr prop = node->properties, prev = NULL;;
6224
6225 if ((node == NULL) || (name == NULL))
6226 return(-1);
6227 if (ns == NULL)
6228 return(xmlUnsetProp(node, name));
6229 if (ns->href == NULL)
6230 return(-1);
6231 while (prop != NULL) {
6232 if ((xmlStrEqual(prop->name, name)) &&
6233 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
6234 if (prev == NULL)
6235 node->properties = prop->next;
6236 else
6237 prev->next = prop->next;
6238 xmlFreeProp(prop);
6239 return(0);
6240 }
6241 prev = prop;
6242 prop = prop->next;
6243 }
6244 return(-1);
6245}
6246#endif
6247
6248#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006249/**
6250 * xmlSetProp:
6251 * @node: the node
6252 * @name: the attribute name
6253 * @value: the attribute value
6254 *
6255 * Set (or reset) an attribute carried by a node.
6256 * Returns the attribute pointer.
6257 */
6258xmlAttrPtr
6259xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006260 xmlAttrPtr prop;
6261 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006262
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006263 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006264 return(NULL);
6265 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006266 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006267 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006268 if ((xmlStrEqual(prop->name, name)) &&
6269 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006270 xmlNodePtr oldprop = prop->children;
6271
Owen Taylor3473f882001-02-23 17:55:21 +00006272 prop->children = NULL;
6273 prop->last = NULL;
6274 if (value != NULL) {
6275 xmlChar *buffer;
6276 xmlNodePtr tmp;
6277
6278 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6279 prop->children = xmlStringGetNodeList(node->doc, buffer);
6280 prop->last = NULL;
6281 prop->doc = doc;
6282 tmp = prop->children;
6283 while (tmp != NULL) {
6284 tmp->parent = (xmlNodePtr) prop;
6285 tmp->doc = doc;
6286 if (tmp->next == NULL)
6287 prop->last = tmp;
6288 tmp = tmp->next;
6289 }
6290 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006291 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006292 if (oldprop != NULL)
6293 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006294 return(prop);
6295 }
6296 prop = prop->next;
6297 }
6298 prop = xmlNewProp(node, name, value);
6299 return(prop);
6300}
6301
6302/**
6303 * xmlSetNsProp:
6304 * @node: the node
6305 * @ns: the namespace definition
6306 * @name: the attribute name
6307 * @value: the attribute value
6308 *
6309 * Set (or reset) an attribute carried by a node.
6310 * The ns structure must be in scope, this is not checked.
6311 *
6312 * Returns the attribute pointer.
6313 */
6314xmlAttrPtr
6315xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6316 const xmlChar *value) {
6317 xmlAttrPtr prop;
6318
6319 if ((node == NULL) || (name == NULL))
6320 return(NULL);
6321
6322 if (ns == NULL)
6323 return(xmlSetProp(node, name, value));
6324 if (ns->href == NULL)
6325 return(NULL);
6326 prop = node->properties;
6327
6328 while (prop != NULL) {
6329 /*
6330 * One need to have
6331 * - same attribute names
6332 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006333 */
6334 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006335 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006336 if (prop->children != NULL)
6337 xmlFreeNodeList(prop->children);
6338 prop->children = NULL;
6339 prop->last = NULL;
6340 prop->ns = ns;
6341 if (value != NULL) {
6342 xmlChar *buffer;
6343 xmlNodePtr tmp;
6344
6345 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6346 prop->children = xmlStringGetNodeList(node->doc, buffer);
6347 prop->last = NULL;
6348 tmp = prop->children;
6349 while (tmp != NULL) {
6350 tmp->parent = (xmlNodePtr) prop;
6351 if (tmp->next == NULL)
6352 prop->last = tmp;
6353 tmp = tmp->next;
6354 }
6355 xmlFree(buffer);
6356 }
6357 return(prop);
6358 }
6359 prop = prop->next;
6360 }
6361 prop = xmlNewNsProp(node, ns, name, value);
6362 return(prop);
6363}
6364
Daniel Veillard652327a2003-09-29 18:02:38 +00006365#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006366
6367/**
Owen Taylor3473f882001-02-23 17:55:21 +00006368 * xmlNodeIsText:
6369 * @node: the node
6370 *
6371 * Is this node a Text node ?
6372 * Returns 1 yes, 0 no
6373 */
6374int
6375xmlNodeIsText(xmlNodePtr node) {
6376 if (node == NULL) return(0);
6377
6378 if (node->type == XML_TEXT_NODE) return(1);
6379 return(0);
6380}
6381
6382/**
6383 * xmlIsBlankNode:
6384 * @node: the node
6385 *
6386 * Checks whether this node is an empty or whitespace only
6387 * (and possibly ignorable) text-node.
6388 *
6389 * Returns 1 yes, 0 no
6390 */
6391int
6392xmlIsBlankNode(xmlNodePtr node) {
6393 const xmlChar *cur;
6394 if (node == NULL) return(0);
6395
Daniel Veillard7db37732001-07-12 01:20:08 +00006396 if ((node->type != XML_TEXT_NODE) &&
6397 (node->type != XML_CDATA_SECTION_NODE))
6398 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006399 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006400 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006401 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006402 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006403 cur++;
6404 }
6405
6406 return(1);
6407}
6408
6409/**
6410 * xmlTextConcat:
6411 * @node: the node
6412 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006413 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006414 *
6415 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006416 *
6417 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006418 */
6419
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006420int
Owen Taylor3473f882001-02-23 17:55:21 +00006421xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006422 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006423
6424 if ((node->type != XML_TEXT_NODE) &&
6425 (node->type != XML_CDATA_SECTION_NODE)) {
6426#ifdef DEBUG_TREE
6427 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006428 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006429#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006430 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006431 }
William M. Brack7762bb12004-01-04 14:49:01 +00006432 /* need to check if content is currently in the dictionary */
6433 if ((node->doc != NULL) && (node->doc->dict != NULL) &&
6434 xmlDictOwns(node->doc->dict, node->content)) {
6435 node->content = xmlStrncatNew(node->content, content, len);
6436 } else {
6437 node->content = xmlStrncat(node->content, content, len);
6438 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006439 if (node->content == NULL)
6440 return(-1);
6441 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006442}
6443
6444/************************************************************************
6445 * *
6446 * Output : to a FILE or in memory *
6447 * *
6448 ************************************************************************/
6449
Owen Taylor3473f882001-02-23 17:55:21 +00006450/**
6451 * xmlBufferCreate:
6452 *
6453 * routine to create an XML buffer.
6454 * returns the new structure.
6455 */
6456xmlBufferPtr
6457xmlBufferCreate(void) {
6458 xmlBufferPtr ret;
6459
6460 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6461 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006462 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006463 return(NULL);
6464 }
6465 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006466 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006467 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006468 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006469 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006470 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006471 xmlFree(ret);
6472 return(NULL);
6473 }
6474 ret->content[0] = 0;
6475 return(ret);
6476}
6477
6478/**
6479 * xmlBufferCreateSize:
6480 * @size: initial size of buffer
6481 *
6482 * routine to create an XML buffer.
6483 * returns the new structure.
6484 */
6485xmlBufferPtr
6486xmlBufferCreateSize(size_t size) {
6487 xmlBufferPtr ret;
6488
6489 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6490 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006491 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006492 return(NULL);
6493 }
6494 ret->use = 0;
6495 ret->alloc = xmlBufferAllocScheme;
6496 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6497 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006498 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006499 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006500 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006501 xmlFree(ret);
6502 return(NULL);
6503 }
6504 ret->content[0] = 0;
6505 } else
6506 ret->content = NULL;
6507 return(ret);
6508}
6509
6510/**
Daniel Veillard53350552003-09-18 13:35:51 +00006511 * xmlBufferCreateStatic:
6512 * @mem: the memory area
6513 * @size: the size in byte
6514 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006515 * routine to create an XML buffer from an immutable memory area.
6516 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006517 * present until the end of the buffer lifetime.
6518 *
6519 * returns the new structure.
6520 */
6521xmlBufferPtr
6522xmlBufferCreateStatic(void *mem, size_t size) {
6523 xmlBufferPtr ret;
6524
6525 if ((mem == NULL) || (size == 0))
6526 return(NULL);
6527
6528 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6529 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006530 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006531 return(NULL);
6532 }
6533 ret->use = size;
6534 ret->size = size;
6535 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6536 ret->content = (xmlChar *) mem;
6537 return(ret);
6538}
6539
6540/**
Owen Taylor3473f882001-02-23 17:55:21 +00006541 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006542 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006543 * @scheme: allocation scheme to use
6544 *
6545 * Sets the allocation scheme for this buffer
6546 */
6547void
6548xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6549 xmlBufferAllocationScheme scheme) {
6550 if (buf == NULL) {
6551#ifdef DEBUG_BUFFER
6552 xmlGenericError(xmlGenericErrorContext,
6553 "xmlBufferSetAllocationScheme: buf == NULL\n");
6554#endif
6555 return;
6556 }
Daniel Veillard53350552003-09-18 13:35:51 +00006557 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006558
6559 buf->alloc = scheme;
6560}
6561
6562/**
6563 * xmlBufferFree:
6564 * @buf: the buffer to free
6565 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006566 * Frees an XML buffer. It frees both the content and the structure which
6567 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006568 */
6569void
6570xmlBufferFree(xmlBufferPtr buf) {
6571 if (buf == NULL) {
6572#ifdef DEBUG_BUFFER
6573 xmlGenericError(xmlGenericErrorContext,
6574 "xmlBufferFree: buf == NULL\n");
6575#endif
6576 return;
6577 }
Daniel Veillard53350552003-09-18 13:35:51 +00006578
6579 if ((buf->content != NULL) &&
6580 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006581 xmlFree(buf->content);
6582 }
Owen Taylor3473f882001-02-23 17:55:21 +00006583 xmlFree(buf);
6584}
6585
6586/**
6587 * xmlBufferEmpty:
6588 * @buf: the buffer
6589 *
6590 * empty a buffer.
6591 */
6592void
6593xmlBufferEmpty(xmlBufferPtr buf) {
6594 if (buf->content == NULL) return;
6595 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006596 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006597 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006598 } else {
6599 memset(buf->content, 0, buf->size);
6600 }
Owen Taylor3473f882001-02-23 17:55:21 +00006601}
6602
6603/**
6604 * xmlBufferShrink:
6605 * @buf: the buffer to dump
6606 * @len: the number of xmlChar to remove
6607 *
6608 * Remove the beginning of an XML buffer.
6609 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006610 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006611 */
6612int
6613xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6614 if (len == 0) return(0);
6615 if (len > buf->use) return(-1);
6616
6617 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006618 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6619 buf->content += len;
6620 } else {
6621 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6622 buf->content[buf->use] = 0;
6623 }
Owen Taylor3473f882001-02-23 17:55:21 +00006624 return(len);
6625}
6626
6627/**
6628 * xmlBufferGrow:
6629 * @buf: the buffer
6630 * @len: the minimum free size to allocate
6631 *
6632 * Grow the available space of an XML buffer.
6633 *
6634 * Returns the new available space or -1 in case of error
6635 */
6636int
6637xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6638 int size;
6639 xmlChar *newbuf;
6640
Daniel Veillard53350552003-09-18 13:35:51 +00006641 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006642 if (len + buf->use < buf->size) return(0);
6643
William M. Brack30fe43f2004-07-26 18:00:58 +00006644/*
6645 * Windows has a BIG problem on realloc timing, so we try to double
6646 * the buffer size (if that's enough) (bug 146697)
6647 */
6648#ifdef WIN32
6649 if (buf->size > len)
6650 size = buf->size * 2;
6651 else
6652 size = buf->use + len + 100;
6653#else
Owen Taylor3473f882001-02-23 17:55:21 +00006654 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00006655#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006656
6657 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006658 if (newbuf == NULL) {
6659 xmlTreeErrMemory("growing buffer");
6660 return(-1);
6661 }
Owen Taylor3473f882001-02-23 17:55:21 +00006662 buf->content = newbuf;
6663 buf->size = size;
6664 return(buf->size - buf->use);
6665}
6666
6667/**
6668 * xmlBufferDump:
6669 * @file: the file output
6670 * @buf: the buffer to dump
6671 *
6672 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006673 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006674 */
6675int
6676xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6677 int ret;
6678
6679 if (buf == NULL) {
6680#ifdef DEBUG_BUFFER
6681 xmlGenericError(xmlGenericErrorContext,
6682 "xmlBufferDump: buf == NULL\n");
6683#endif
6684 return(0);
6685 }
6686 if (buf->content == NULL) {
6687#ifdef DEBUG_BUFFER
6688 xmlGenericError(xmlGenericErrorContext,
6689 "xmlBufferDump: buf->content == NULL\n");
6690#endif
6691 return(0);
6692 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006693 if (file == NULL)
6694 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006695 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6696 return(ret);
6697}
6698
6699/**
6700 * xmlBufferContent:
6701 * @buf: the buffer
6702 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006703 * Function to extract the content of a buffer
6704 *
Owen Taylor3473f882001-02-23 17:55:21 +00006705 * Returns the internal content
6706 */
6707
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006708const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006709xmlBufferContent(const xmlBufferPtr buf)
6710{
6711 if(!buf)
6712 return NULL;
6713
6714 return buf->content;
6715}
6716
6717/**
6718 * xmlBufferLength:
6719 * @buf: the buffer
6720 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006721 * Function to get the length of a buffer
6722 *
Owen Taylor3473f882001-02-23 17:55:21 +00006723 * Returns the length of data in the internal content
6724 */
6725
6726int
6727xmlBufferLength(const xmlBufferPtr buf)
6728{
6729 if(!buf)
6730 return 0;
6731
6732 return buf->use;
6733}
6734
6735/**
6736 * xmlBufferResize:
6737 * @buf: the buffer to resize
6738 * @size: the desired size
6739 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006740 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006741 *
6742 * Returns 0 in case of problems, 1 otherwise
6743 */
6744int
6745xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6746{
6747 unsigned int newSize;
6748 xmlChar* rebuf = NULL;
6749
Daniel Veillard53350552003-09-18 13:35:51 +00006750 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6751
Owen Taylor3473f882001-02-23 17:55:21 +00006752 /* Don't resize if we don't have to */
6753 if (size < buf->size)
6754 return 1;
6755
6756 /* figure out new size */
6757 switch (buf->alloc){
6758 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillardbf629492004-04-20 22:20:59 +00006759 /*take care of empty case*/
6760 newSize = (buf->size ? buf->size*2 : size + 10);
Owen Taylor3473f882001-02-23 17:55:21 +00006761 while (size > newSize) newSize *= 2;
6762 break;
6763 case XML_BUFFER_ALLOC_EXACT:
6764 newSize = size+10;
6765 break;
6766 default:
6767 newSize = size+10;
6768 break;
6769 }
6770
6771 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006772 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006773 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006774 rebuf = (xmlChar *) xmlRealloc(buf->content,
6775 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006776 } else {
6777 /*
6778 * if we are reallocating a buffer far from being full, it's
6779 * better to make a new allocation and copy only the used range
6780 * and free the old one.
6781 */
6782 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6783 if (rebuf != NULL) {
6784 memcpy(rebuf, buf->content, buf->use);
6785 xmlFree(buf->content);
William M. Brack42331a92004-07-29 07:07:16 +00006786 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006787 }
6788 }
Owen Taylor3473f882001-02-23 17:55:21 +00006789 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006790 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006791 return 0;
6792 }
6793 buf->content = rebuf;
6794 buf->size = newSize;
6795
6796 return 1;
6797}
6798
6799/**
6800 * xmlBufferAdd:
6801 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006802 * @str: the #xmlChar string
6803 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006804 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006805 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006806 * str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006807 *
6808 * Returns 0 successful, a positive error code number otherwise
6809 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006810 */
William M. Bracka3215c72004-07-31 16:24:01 +00006811int
Owen Taylor3473f882001-02-23 17:55:21 +00006812xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6813 unsigned int needSize;
6814
6815 if (str == NULL) {
6816#ifdef DEBUG_BUFFER
6817 xmlGenericError(xmlGenericErrorContext,
6818 "xmlBufferAdd: str == NULL\n");
6819#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006820 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006821 }
William M. Bracka3215c72004-07-31 16:24:01 +00006822 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006823 if (len < -1) {
6824#ifdef DEBUG_BUFFER
6825 xmlGenericError(xmlGenericErrorContext,
6826 "xmlBufferAdd: len < 0\n");
6827#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006828 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006829 }
William M. Bracka3215c72004-07-31 16:24:01 +00006830 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006831
6832 if (len < 0)
6833 len = xmlStrlen(str);
6834
William M. Bracka3215c72004-07-31 16:24:01 +00006835 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006836
6837 needSize = buf->use + len + 2;
6838 if (needSize > buf->size){
6839 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006840 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006841 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006842 }
6843 }
6844
6845 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6846 buf->use += len;
6847 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006848 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006849}
6850
6851/**
6852 * xmlBufferAddHead:
6853 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006854 * @str: the #xmlChar string
6855 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006856 *
6857 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006858 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006859 *
6860 * Returns 0 successful, a positive error code number otherwise
6861 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006862 */
William M. Bracka3215c72004-07-31 16:24:01 +00006863int
Owen Taylor3473f882001-02-23 17:55:21 +00006864xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6865 unsigned int needSize;
6866
William M. Bracka3215c72004-07-31 16:24:01 +00006867 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006868 if (str == NULL) {
6869#ifdef DEBUG_BUFFER
6870 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006871 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006872#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006873 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006874 }
6875 if (len < -1) {
6876#ifdef DEBUG_BUFFER
6877 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006878 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006879#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006880 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006881 }
William M. Bracka3215c72004-07-31 16:24:01 +00006882 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006883
6884 if (len < 0)
6885 len = xmlStrlen(str);
6886
William M. Bracka3215c72004-07-31 16:24:01 +00006887 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006888
6889 needSize = buf->use + len + 2;
6890 if (needSize > buf->size){
6891 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006892 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006893 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006894 }
6895 }
6896
6897 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6898 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6899 buf->use += len;
6900 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006901 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006902}
6903
6904/**
6905 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00006906 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00006907 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006908 *
6909 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00006910 *
6911 * Returns 0 successful, a positive error code number otherwise
6912 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006913 */
William M. Bracka3215c72004-07-31 16:24:01 +00006914int
Owen Taylor3473f882001-02-23 17:55:21 +00006915xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
William M. Bracka3215c72004-07-31 16:24:01 +00006916 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
6917 if (str == NULL) return -1;
6918 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00006919}
6920
6921/**
6922 * xmlBufferCCat:
6923 * @buf: the buffer to dump
6924 * @str: the C char string
6925 *
6926 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00006927 *
6928 * Returns 0 successful, a positive error code number otherwise
6929 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006930 */
William M. Bracka3215c72004-07-31 16:24:01 +00006931int
Owen Taylor3473f882001-02-23 17:55:21 +00006932xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6933 const char *cur;
6934
William M. Bracka3215c72004-07-31 16:24:01 +00006935 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006936 if (str == NULL) {
6937#ifdef DEBUG_BUFFER
6938 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006939 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006940#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006941 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006942 }
6943 for (cur = str;*cur != 0;cur++) {
6944 if (buf->use + 10 >= buf->size) {
6945 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006946 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006947 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006948 }
6949 }
6950 buf->content[buf->use++] = *cur;
6951 }
6952 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006953 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006954}
6955
6956/**
6957 * xmlBufferWriteCHAR:
6958 * @buf: the XML buffer
6959 * @string: the string to add
6960 *
6961 * routine which manages and grows an output buffer. This one adds
6962 * xmlChars at the end of the buffer.
6963 */
6964void
Daniel Veillard53350552003-09-18 13:35:51 +00006965xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
6966 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006967 xmlBufferCat(buf, string);
6968}
6969
6970/**
6971 * xmlBufferWriteChar:
6972 * @buf: the XML buffer output
6973 * @string: the string to add
6974 *
6975 * routine which manage and grows an output buffer. This one add
6976 * C chars at the end of the array.
6977 */
6978void
6979xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillard53350552003-09-18 13:35:51 +00006980 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006981 xmlBufferCCat(buf, string);
6982}
6983
6984
6985/**
6986 * xmlBufferWriteQuotedString:
6987 * @buf: the XML buffer output
6988 * @string: the string to add
6989 *
6990 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006991 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006992 * quote or double-quotes internally
6993 */
6994void
6995xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00006996 const xmlChar *cur, *base;
Daniel Veillard53350552003-09-18 13:35:51 +00006997 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00006998 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00006999 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00007000#ifdef DEBUG_BUFFER
7001 xmlGenericError(xmlGenericErrorContext,
7002 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7003#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00007004 xmlBufferCCat(buf, "\"");
7005 base = cur = string;
7006 while(*cur != 0){
7007 if(*cur == '"'){
7008 if (base != cur)
7009 xmlBufferAdd(buf, base, cur - base);
7010 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7011 cur++;
7012 base = cur;
7013 }
7014 else {
7015 cur++;
7016 }
7017 }
7018 if (base != cur)
7019 xmlBufferAdd(buf, base, cur - base);
7020 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007021 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007022 else{
7023 xmlBufferCCat(buf, "\'");
7024 xmlBufferCat(buf, string);
7025 xmlBufferCCat(buf, "\'");
7026 }
Owen Taylor3473f882001-02-23 17:55:21 +00007027 } else {
7028 xmlBufferCCat(buf, "\"");
7029 xmlBufferCat(buf, string);
7030 xmlBufferCCat(buf, "\"");
7031 }
7032}
7033
7034
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007035/**
7036 * xmlGetDocCompressMode:
7037 * @doc: the document
7038 *
7039 * get the compression ratio for a document, ZLIB based
7040 * Returns 0 (uncompressed) to 9 (max compression)
7041 */
7042int
7043xmlGetDocCompressMode (xmlDocPtr doc) {
7044 if (doc == NULL) return(-1);
7045 return(doc->compression);
7046}
7047
7048/**
7049 * xmlSetDocCompressMode:
7050 * @doc: the document
7051 * @mode: the compression ratio
7052 *
7053 * set the compression ratio for a document, ZLIB based
7054 * Correct values: 0 (uncompressed) to 9 (max compression)
7055 */
7056void
7057xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7058 if (doc == NULL) return;
7059 if (mode < 0) doc->compression = 0;
7060 else if (mode > 9) doc->compression = 9;
7061 else doc->compression = mode;
7062}
7063
7064/**
7065 * xmlGetCompressMode:
7066 *
7067 * get the default compression mode used, ZLIB based.
7068 * Returns 0 (uncompressed) to 9 (max compression)
7069 */
7070int
7071xmlGetCompressMode(void)
7072{
7073 return (xmlCompressMode);
7074}
7075
7076/**
7077 * xmlSetCompressMode:
7078 * @mode: the compression ratio
7079 *
7080 * set the default compression mode used, ZLIB based
7081 * Correct values: 0 (uncompressed) to 9 (max compression)
7082 */
7083void
7084xmlSetCompressMode(int mode) {
7085 if (mode < 0) xmlCompressMode = 0;
7086 else if (mode > 9) xmlCompressMode = 9;
7087 else xmlCompressMode = mode;
7088}
7089