blob: 42795b5292a7ebb95a4a3d3ebbd81554b723c291 [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
William M. Brack1d8c9b22004-12-25 10:14:57 +000040#ifdef LIBXML_DEBUG_ENABLED
41#include <libxml/debugXML.h>
42#endif
Owen Taylor3473f882001-02-23 17:55:21 +000043
Daniel Veillarda880b122003-04-21 21:36:41 +000044int __xmlRegisterCallbacks = 0;
45
Daniel Veillard56a4cb82001-03-24 17:00:36 +000046xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
47
48/************************************************************************
49 * *
Daniel Veillard18ec16e2003-10-07 23:16:40 +000050 * Tree memory error handler *
51 * *
52 ************************************************************************/
53/**
54 * xmlTreeErrMemory:
55 * @extra: extra informations
56 *
57 * Handle an out of memory condition
58 */
59static void
60xmlTreeErrMemory(const char *extra)
61{
62 __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
63}
64
65/**
66 * xmlTreeErr:
67 * @code: the error number
68 * @extra: extra informations
69 *
70 * Handle an out of memory condition
71 */
72static void
73xmlTreeErr(int code, xmlNodePtr node, const char *extra)
74{
75 const char *msg = NULL;
76
77 switch(code) {
78 case XML_TREE_INVALID_HEX:
Daniel Veillardac996a12004-07-30 12:02:58 +000079 msg = "invalid hexadecimal character value\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000080 break;
81 case XML_TREE_INVALID_DEC:
Daniel Veillardac996a12004-07-30 12:02:58 +000082 msg = "invalid decimal character value\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000083 break;
84 case XML_TREE_UNTERMINATED_ENTITY:
Daniel Veillardac996a12004-07-30 12:02:58 +000085 msg = "unterminated entity reference %15s\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000086 break;
87 default:
Daniel Veillardac996a12004-07-30 12:02:58 +000088 msg = "unexpected error number\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000089 }
90 __xmlSimpleError(XML_FROM_TREE, code, node, msg, extra);
91}
92
93/************************************************************************
94 * *
Daniel Veillard56a4cb82001-03-24 17:00:36 +000095 * A few static variables and macros *
96 * *
97 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000098/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000099const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +0000100/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +0000101const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +0000102 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +0000103/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +0000104const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
105
Owen Taylor3473f882001-02-23 17:55:21 +0000106static int xmlCompressMode = 0;
107static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000108
Owen Taylor3473f882001-02-23 17:55:21 +0000109#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
110 xmlNodePtr ulccur = (n)->children; \
111 if (ulccur == NULL) { \
112 (n)->last = NULL; \
113 } else { \
114 while (ulccur->next != NULL) { \
115 ulccur->parent = (n); \
116 ulccur = ulccur->next; \
117 } \
118 ulccur->parent = (n); \
119 (n)->last = ulccur; \
120}}
121
122/* #define DEBUG_BUFFER */
123/* #define DEBUG_TREE */
124
125/************************************************************************
126 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000127 * Functions to move to entities.c once the *
128 * API freeze is smoothen and they can be made public. *
129 * *
130 ************************************************************************/
131#include <libxml/hash.h>
132
Daniel Veillard652327a2003-09-29 18:02:38 +0000133#ifdef LIBXML_TREE_ENABLED
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000134/**
135 * xmlGetEntityFromDtd:
136 * @dtd: A pointer to the DTD to search
137 * @name: The entity name
138 *
139 * Do an entity lookup in the DTD entity hash table and
140 * return the corresponding entity, if found.
141 *
142 * Returns A pointer to the entity structure or NULL if not found.
143 */
144static xmlEntityPtr
145xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
146 xmlEntitiesTablePtr table;
147
148 if((dtd != NULL) && (dtd->entities != NULL)) {
149 table = (xmlEntitiesTablePtr) dtd->entities;
150 return((xmlEntityPtr) xmlHashLookup(table, name));
151 /* return(xmlGetEntityFromTable(table, name)); */
152 }
153 return(NULL);
154}
155/**
156 * xmlGetParameterEntityFromDtd:
157 * @dtd: A pointer to the DTD to search
158 * @name: The entity name
159 *
160 * Do an entity lookup in the DTD pararmeter entity hash table and
161 * return the corresponding entity, if found.
162 *
163 * Returns A pointer to the entity structure or NULL if not found.
164 */
165static xmlEntityPtr
166xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
167 xmlEntitiesTablePtr table;
168
169 if ((dtd != NULL) && (dtd->pentities != NULL)) {
170 table = (xmlEntitiesTablePtr) dtd->pentities;
171 return((xmlEntityPtr) xmlHashLookup(table, name));
172 /* return(xmlGetEntityFromTable(table, name)); */
173 }
174 return(NULL);
175}
Daniel Veillard652327a2003-09-29 18:02:38 +0000176#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000177
178/************************************************************************
179 * *
Daniel Veillardc00cda82003-04-07 10:22:39 +0000180 * QName handling helper *
181 * *
182 ************************************************************************/
183
184/**
185 * xmlBuildQName:
186 * @ncname: the Name
187 * @prefix: the prefix
188 * @memory: preallocated memory
189 * @len: preallocated memory length
190 *
191 * Builds the QName @prefix:@ncname in @memory if there is enough space
192 * and prefix is not NULL nor empty, otherwise allocate a new string.
193 * If prefix is NULL or empty it returns ncname.
194 *
195 * Returns the new string which must be freed by the caller if different from
196 * @memory and @ncname or NULL in case of error
197 */
198xmlChar *
199xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
200 xmlChar *memory, int len) {
201 int lenn, lenp;
202 xmlChar *ret;
203
Daniel Veillard3b7840c2003-09-11 23:42:01 +0000204 if (ncname == NULL) return(NULL);
205 if (prefix == NULL) return((xmlChar *) ncname);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000206
207 lenn = strlen((char *) ncname);
208 lenp = strlen((char *) prefix);
209
210 if ((memory == NULL) || (len < lenn + lenp + 2)) {
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000211 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000212 if (ret == NULL) {
213 xmlTreeErrMemory("building QName");
214 return(NULL);
215 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000216 } else {
217 ret = memory;
218 }
219 memcpy(&ret[0], prefix, lenp);
220 ret[lenp] = ':';
221 memcpy(&ret[lenp + 1], ncname, lenn);
222 ret[lenn + lenp + 1] = 0;
223 return(ret);
224}
225
226/**
227 * xmlSplitQName2:
228 * @name: the full QName
229 * @prefix: a xmlChar **
230 *
231 * parse an XML qualified name string
232 *
233 * [NS 5] QName ::= (Prefix ':')? LocalPart
234 *
235 * [NS 6] Prefix ::= NCName
236 *
237 * [NS 7] LocalPart ::= NCName
238 *
239 * Returns NULL if not a QName, otherwise the local part, and prefix
240 * is updated to get the Prefix if any.
241 */
242
243xmlChar *
244xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
245 int len = 0;
246 xmlChar *ret = NULL;
247
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000248 if (prefix == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000249 *prefix = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000250 if (name == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000251
252#ifndef XML_XML_NAMESPACE
253 /* xml: prefix is not really a namespace */
254 if ((name[0] == 'x') && (name[1] == 'm') &&
255 (name[2] == 'l') && (name[3] == ':'))
256 return(NULL);
257#endif
258
259 /* nasty but valid */
260 if (name[0] == ':')
261 return(NULL);
262
263 /*
264 * we are not trying to validate but just to cut, and yes it will
265 * work even if this is as set of UTF-8 encoded chars
266 */
267 while ((name[len] != 0) && (name[len] != ':'))
268 len++;
269
270 if (name[len] == 0)
271 return(NULL);
272
273 *prefix = xmlStrndup(name, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000274 if (*prefix == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000275 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000276 return(NULL);
277 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000278 ret = xmlStrdup(&name[len + 1]);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000279 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000280 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000281 if (*prefix != NULL) {
282 xmlFree(*prefix);
283 *prefix = NULL;
284 }
285 return(NULL);
286 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000287
288 return(ret);
289}
290
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000291/**
292 * xmlSplitQName3:
293 * @name: the full QName
294 * @len: an int *
295 *
296 * parse an XML qualified name string,i
297 *
298 * returns NULL if it is not a Qualified Name, otherwise, update len
299 * with the lenght in byte of the prefix and return a pointer
300 */
301
302const xmlChar *
303xmlSplitQName3(const xmlChar *name, int *len) {
304 int l = 0;
305
306 if (name == NULL) return(NULL);
307 if (len == NULL) return(NULL);
308
309 /* nasty but valid */
310 if (name[0] == ':')
311 return(NULL);
312
313 /*
314 * we are not trying to validate but just to cut, and yes it will
315 * work even if this is as set of UTF-8 encoded chars
316 */
317 while ((name[l] != 0) && (name[l] != ':'))
318 l++;
319
320 if (name[l] == 0)
321 return(NULL);
322
323 *len = l;
324
325 return(&name[l+1]);
326}
327
Daniel Veillardc00cda82003-04-07 10:22:39 +0000328/************************************************************************
329 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000330 * Check Name, NCName and QName strings *
331 * *
332 ************************************************************************/
333
334#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
335
Daniel Veillard03a53c32004-10-26 16:06:51 +0000336#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000337/**
338 * xmlValidateNCName:
339 * @value: the value to check
340 * @space: allow spaces in front and end of the string
341 *
342 * Check that a value conforms to the lexical space of NCName
343 *
344 * Returns 0 if this validates, a positive error code number otherwise
345 * and -1 in case of internal or API error.
346 */
347int
348xmlValidateNCName(const xmlChar *value, int space) {
349 const xmlChar *cur = value;
350 int c,l;
351
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000352 if (value == NULL)
353 return(-1);
354
Daniel Veillardd2298792003-02-14 16:54:11 +0000355 /*
356 * First quick algorithm for ASCII range
357 */
358 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000359 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000360 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
361 (*cur == '_'))
362 cur++;
363 else
364 goto try_complex;
365 while (((*cur >= 'a') && (*cur <= 'z')) ||
366 ((*cur >= 'A') && (*cur <= 'Z')) ||
367 ((*cur >= '0') && (*cur <= '9')) ||
368 (*cur == '_') || (*cur == '-') || (*cur == '.'))
369 cur++;
370 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000371 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000372 if (*cur == 0)
373 return(0);
374
375try_complex:
376 /*
377 * Second check for chars outside the ASCII range
378 */
379 cur = value;
380 c = CUR_SCHAR(cur, l);
381 if (space) {
382 while (IS_BLANK(c)) {
383 cur += l;
384 c = CUR_SCHAR(cur, l);
385 }
386 }
William M. Brack871611b2003-10-18 04:53:14 +0000387 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000388 return(1);
389 cur += l;
390 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000391 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
392 (c == '-') || (c == '_') || IS_COMBINING(c) ||
393 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000394 cur += l;
395 c = CUR_SCHAR(cur, l);
396 }
397 if (space) {
398 while (IS_BLANK(c)) {
399 cur += l;
400 c = CUR_SCHAR(cur, l);
401 }
402 }
403 if (c != 0)
404 return(1);
405
406 return(0);
407}
Daniel Veillard2156d432004-03-04 15:59:36 +0000408#endif
Daniel Veillardd2298792003-02-14 16:54:11 +0000409
Daniel Veillard2156d432004-03-04 15:59:36 +0000410#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000411/**
412 * xmlValidateQName:
413 * @value: the value to check
414 * @space: allow spaces in front and end of the string
415 *
416 * Check that a value conforms to the lexical space of QName
417 *
418 * Returns 0 if this validates, a positive error code number otherwise
419 * and -1 in case of internal or API error.
420 */
421int
422xmlValidateQName(const xmlChar *value, int space) {
423 const xmlChar *cur = value;
424 int c,l;
425
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000426 if (value == NULL)
427 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +0000428 /*
429 * First quick algorithm for ASCII range
430 */
431 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000432 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000433 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
434 (*cur == '_'))
435 cur++;
436 else
437 goto try_complex;
438 while (((*cur >= 'a') && (*cur <= 'z')) ||
439 ((*cur >= 'A') && (*cur <= 'Z')) ||
440 ((*cur >= '0') && (*cur <= '9')) ||
441 (*cur == '_') || (*cur == '-') || (*cur == '.'))
442 cur++;
443 if (*cur == ':') {
444 cur++;
445 if (((*cur >= 'a') && (*cur <= 'z')) ||
446 ((*cur >= 'A') && (*cur <= 'Z')) ||
447 (*cur == '_'))
448 cur++;
449 else
450 goto try_complex;
451 while (((*cur >= 'a') && (*cur <= 'z')) ||
452 ((*cur >= 'A') && (*cur <= 'Z')) ||
453 ((*cur >= '0') && (*cur <= '9')) ||
454 (*cur == '_') || (*cur == '-') || (*cur == '.'))
455 cur++;
456 }
457 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000458 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000459 if (*cur == 0)
460 return(0);
461
462try_complex:
463 /*
464 * Second check for chars outside the ASCII range
465 */
466 cur = value;
467 c = CUR_SCHAR(cur, l);
468 if (space) {
469 while (IS_BLANK(c)) {
470 cur += l;
471 c = CUR_SCHAR(cur, l);
472 }
473 }
William M. Brack871611b2003-10-18 04:53:14 +0000474 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000475 return(1);
476 cur += l;
477 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000478 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
479 (c == '-') || (c == '_') || IS_COMBINING(c) ||
480 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000481 cur += l;
482 c = CUR_SCHAR(cur, l);
483 }
484 if (c == ':') {
485 cur += l;
486 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000487 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000488 return(1);
489 cur += l;
490 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000491 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
492 (c == '-') || (c == '_') || IS_COMBINING(c) ||
493 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000494 cur += l;
495 c = CUR_SCHAR(cur, l);
496 }
497 }
498 if (space) {
499 while (IS_BLANK(c)) {
500 cur += l;
501 c = CUR_SCHAR(cur, l);
502 }
503 }
504 if (c != 0)
505 return(1);
506 return(0);
507}
508
509/**
510 * xmlValidateName:
511 * @value: the value to check
512 * @space: allow spaces in front and end of the string
513 *
514 * Check that a value conforms to the lexical space of Name
515 *
516 * Returns 0 if this validates, a positive error code number otherwise
517 * and -1 in case of internal or API error.
518 */
519int
520xmlValidateName(const xmlChar *value, int space) {
521 const xmlChar *cur = value;
522 int c,l;
523
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000524 if (value == NULL)
525 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +0000526 /*
527 * First quick algorithm for ASCII range
528 */
529 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000530 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000531 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
532 (*cur == '_') || (*cur == ':'))
533 cur++;
534 else
535 goto try_complex;
536 while (((*cur >= 'a') && (*cur <= 'z')) ||
537 ((*cur >= 'A') && (*cur <= 'Z')) ||
538 ((*cur >= '0') && (*cur <= '9')) ||
539 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
540 cur++;
541 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000542 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000543 if (*cur == 0)
544 return(0);
545
546try_complex:
547 /*
548 * Second check for chars outside the ASCII range
549 */
550 cur = value;
551 c = CUR_SCHAR(cur, l);
552 if (space) {
553 while (IS_BLANK(c)) {
554 cur += l;
555 c = CUR_SCHAR(cur, l);
556 }
557 }
William M. Brack871611b2003-10-18 04:53:14 +0000558 if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000559 return(1);
560 cur += l;
561 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000562 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
563 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000564 cur += l;
565 c = CUR_SCHAR(cur, l);
566 }
567 if (space) {
568 while (IS_BLANK(c)) {
569 cur += l;
570 c = CUR_SCHAR(cur, l);
571 }
572 }
573 if (c != 0)
574 return(1);
575 return(0);
576}
577
Daniel Veillardd4310742003-02-18 21:12:46 +0000578/**
579 * xmlValidateNMToken:
580 * @value: the value to check
581 * @space: allow spaces in front and end of the string
582 *
583 * Check that a value conforms to the lexical space of NMToken
584 *
585 * Returns 0 if this validates, a positive error code number otherwise
586 * and -1 in case of internal or API error.
587 */
588int
589xmlValidateNMToken(const xmlChar *value, int space) {
590 const xmlChar *cur = value;
591 int c,l;
592
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000593 if (value == NULL)
594 return(-1);
Daniel Veillardd4310742003-02-18 21:12:46 +0000595 /*
596 * First quick algorithm for ASCII range
597 */
598 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000599 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000600 if (((*cur >= 'a') && (*cur <= 'z')) ||
601 ((*cur >= 'A') && (*cur <= 'Z')) ||
602 ((*cur >= '0') && (*cur <= '9')) ||
603 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
604 cur++;
605 else
606 goto try_complex;
607 while (((*cur >= 'a') && (*cur <= 'z')) ||
608 ((*cur >= 'A') && (*cur <= 'Z')) ||
609 ((*cur >= '0') && (*cur <= '9')) ||
610 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
611 cur++;
612 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000613 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000614 if (*cur == 0)
615 return(0);
616
617try_complex:
618 /*
619 * Second check for chars outside the ASCII range
620 */
621 cur = value;
622 c = CUR_SCHAR(cur, l);
623 if (space) {
624 while (IS_BLANK(c)) {
625 cur += l;
626 c = CUR_SCHAR(cur, l);
627 }
628 }
William M. Brack871611b2003-10-18 04:53:14 +0000629 if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
630 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
Daniel Veillardd4310742003-02-18 21:12:46 +0000631 return(1);
632 cur += l;
633 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000634 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
635 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd4310742003-02-18 21:12:46 +0000636 cur += l;
637 c = CUR_SCHAR(cur, l);
638 }
639 if (space) {
640 while (IS_BLANK(c)) {
641 cur += l;
642 c = CUR_SCHAR(cur, l);
643 }
644 }
645 if (c != 0)
646 return(1);
647 return(0);
648}
Daniel Veillard652327a2003-09-29 18:02:38 +0000649#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardd4310742003-02-18 21:12:46 +0000650
Daniel Veillardd2298792003-02-14 16:54:11 +0000651/************************************************************************
652 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000653 * Allocation and deallocation of basic structures *
654 * *
655 ************************************************************************/
656
657/**
658 * xmlSetBufferAllocationScheme:
659 * @scheme: allocation method to use
660 *
661 * Set the buffer allocation method. 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 */
666void
667xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
668 xmlBufferAllocScheme = scheme;
669}
670
671/**
672 * xmlGetBufferAllocationScheme:
673 *
674 * Types are
675 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
676 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
677 * improves performance
678 *
679 * Returns the current allocation scheme
680 */
681xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000682xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000683 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000684}
685
686/**
687 * xmlNewNs:
688 * @node: the element carrying the namespace
689 * @href: the URI associated
690 * @prefix: the prefix for the namespace
691 *
692 * Creation of a new Namespace. This function will refuse to create
693 * a namespace with a similar prefix than an existing one present on this
694 * node.
695 * We use href==NULL in the case of an element creation where the namespace
696 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000697 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000698 */
699xmlNsPtr
700xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
701 xmlNsPtr cur;
702
703 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
704 return(NULL);
705
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000706 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
707 return(NULL);
708
Owen Taylor3473f882001-02-23 17:55:21 +0000709 /*
710 * Allocate a new Namespace and fill the fields.
711 */
712 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
713 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000714 xmlTreeErrMemory("building namespace");
Owen Taylor3473f882001-02-23 17:55:21 +0000715 return(NULL);
716 }
717 memset(cur, 0, sizeof(xmlNs));
718 cur->type = XML_LOCAL_NAMESPACE;
719
720 if (href != NULL)
721 cur->href = xmlStrdup(href);
722 if (prefix != NULL)
723 cur->prefix = xmlStrdup(prefix);
724
725 /*
726 * Add it at the end to preserve parsing order ...
727 * and checks for existing use of the prefix
728 */
729 if (node != NULL) {
730 if (node->nsDef == NULL) {
731 node->nsDef = cur;
732 } else {
733 xmlNsPtr prev = node->nsDef;
734
735 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
736 (xmlStrEqual(prev->prefix, cur->prefix))) {
737 xmlFreeNs(cur);
738 return(NULL);
739 }
740 while (prev->next != NULL) {
741 prev = prev->next;
742 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
743 (xmlStrEqual(prev->prefix, cur->prefix))) {
744 xmlFreeNs(cur);
745 return(NULL);
746 }
747 }
748 prev->next = cur;
749 }
750 }
751 return(cur);
752}
753
754/**
755 * xmlSetNs:
756 * @node: a node in the document
757 * @ns: a namespace pointer
758 *
759 * Associate a namespace to a node, a posteriori.
760 */
761void
762xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
763 if (node == NULL) {
764#ifdef DEBUG_TREE
765 xmlGenericError(xmlGenericErrorContext,
766 "xmlSetNs: node == NULL\n");
767#endif
768 return;
769 }
770 node->ns = ns;
771}
772
773/**
774 * xmlFreeNs:
775 * @cur: the namespace pointer
776 *
777 * Free up the structures associated to a namespace
778 */
779void
780xmlFreeNs(xmlNsPtr cur) {
781 if (cur == NULL) {
782#ifdef DEBUG_TREE
783 xmlGenericError(xmlGenericErrorContext,
784 "xmlFreeNs : ns == NULL\n");
785#endif
786 return;
787 }
788 if (cur->href != NULL) xmlFree((char *) cur->href);
789 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000790 xmlFree(cur);
791}
792
793/**
794 * xmlFreeNsList:
795 * @cur: the first namespace pointer
796 *
797 * Free up all the structures associated to the chained namespaces.
798 */
799void
800xmlFreeNsList(xmlNsPtr cur) {
801 xmlNsPtr next;
802 if (cur == NULL) {
803#ifdef DEBUG_TREE
804 xmlGenericError(xmlGenericErrorContext,
805 "xmlFreeNsList : ns == NULL\n");
806#endif
807 return;
808 }
809 while (cur != NULL) {
810 next = cur->next;
811 xmlFreeNs(cur);
812 cur = next;
813 }
814}
815
816/**
817 * xmlNewDtd:
818 * @doc: the document pointer
819 * @name: the DTD name
820 * @ExternalID: the external ID
821 * @SystemID: the system ID
822 *
823 * Creation of a new DTD for the external subset. To create an
824 * internal subset, use xmlCreateIntSubset().
825 *
826 * Returns a pointer to the new DTD structure
827 */
828xmlDtdPtr
829xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
830 const xmlChar *ExternalID, const xmlChar *SystemID) {
831 xmlDtdPtr cur;
832
833 if ((doc != NULL) && (doc->extSubset != NULL)) {
834#ifdef DEBUG_TREE
835 xmlGenericError(xmlGenericErrorContext,
836 "xmlNewDtd(%s): document %s already have a DTD %s\n",
837 /* !!! */ (char *) name, doc->name,
838 /* !!! */ (char *)doc->extSubset->name);
839#endif
840 return(NULL);
841 }
842
843 /*
844 * Allocate a new DTD and fill the fields.
845 */
846 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
847 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000848 xmlTreeErrMemory("building DTD");
Owen Taylor3473f882001-02-23 17:55:21 +0000849 return(NULL);
850 }
851 memset(cur, 0 , sizeof(xmlDtd));
852 cur->type = XML_DTD_NODE;
853
854 if (name != NULL)
855 cur->name = xmlStrdup(name);
856 if (ExternalID != NULL)
857 cur->ExternalID = xmlStrdup(ExternalID);
858 if (SystemID != NULL)
859 cur->SystemID = xmlStrdup(SystemID);
860 if (doc != NULL)
861 doc->extSubset = cur;
862 cur->doc = doc;
863
Daniel Veillarda880b122003-04-21 21:36:41 +0000864 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000865 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000866 return(cur);
867}
868
869/**
870 * xmlGetIntSubset:
871 * @doc: the document pointer
872 *
873 * Get the internal subset of a document
874 * Returns a pointer to the DTD structure or NULL if not found
875 */
876
877xmlDtdPtr
878xmlGetIntSubset(xmlDocPtr doc) {
879 xmlNodePtr cur;
880
881 if (doc == NULL)
882 return(NULL);
883 cur = doc->children;
884 while (cur != NULL) {
885 if (cur->type == XML_DTD_NODE)
886 return((xmlDtdPtr) cur);
887 cur = cur->next;
888 }
889 return((xmlDtdPtr) doc->intSubset);
890}
891
892/**
893 * xmlCreateIntSubset:
894 * @doc: the document pointer
895 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000896 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000897 * @SystemID: the system ID
898 *
899 * Create the internal subset of a document
900 * Returns a pointer to the new DTD structure
901 */
902xmlDtdPtr
903xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
904 const xmlChar *ExternalID, const xmlChar *SystemID) {
905 xmlDtdPtr cur;
906
907 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
908#ifdef DEBUG_TREE
909 xmlGenericError(xmlGenericErrorContext,
910
911 "xmlCreateIntSubset(): document %s already have an internal subset\n",
912 doc->name);
913#endif
914 return(NULL);
915 }
916
917 /*
918 * Allocate a new DTD and fill the fields.
919 */
920 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
921 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000922 xmlTreeErrMemory("building internal subset");
Owen Taylor3473f882001-02-23 17:55:21 +0000923 return(NULL);
924 }
925 memset(cur, 0, sizeof(xmlDtd));
926 cur->type = XML_DTD_NODE;
927
William M. Bracka3215c72004-07-31 16:24:01 +0000928 if (name != NULL) {
929 cur->name = xmlStrdup(name);
930 if (cur->name == NULL) {
931 xmlTreeErrMemory("building internal subset");
932 xmlFree(cur);
933 return(NULL);
934 }
935 }
936 if (ExternalID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000937 cur->ExternalID = xmlStrdup(ExternalID);
William M. Bracka3215c72004-07-31 16:24:01 +0000938 if (cur->ExternalID == NULL) {
939 xmlTreeErrMemory("building internal subset");
940 if (cur->name != NULL)
941 xmlFree((char *)cur->name);
942 xmlFree(cur);
943 return(NULL);
944 }
945 }
946 if (SystemID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000947 cur->SystemID = xmlStrdup(SystemID);
William M. Bracka3215c72004-07-31 16:24:01 +0000948 if (cur->SystemID == NULL) {
949 xmlTreeErrMemory("building internal subset");
950 if (cur->name != NULL)
951 xmlFree((char *)cur->name);
952 if (cur->ExternalID != NULL)
953 xmlFree((char *)cur->ExternalID);
954 xmlFree(cur);
955 return(NULL);
956 }
957 }
Owen Taylor3473f882001-02-23 17:55:21 +0000958 if (doc != NULL) {
959 doc->intSubset = cur;
960 cur->parent = doc;
961 cur->doc = doc;
962 if (doc->children == NULL) {
963 doc->children = (xmlNodePtr) cur;
964 doc->last = (xmlNodePtr) cur;
965 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000966 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000967 xmlNodePtr prev;
968
Owen Taylor3473f882001-02-23 17:55:21 +0000969 prev = doc->children;
970 prev->prev = (xmlNodePtr) cur;
971 cur->next = prev;
972 doc->children = (xmlNodePtr) cur;
973 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000974 xmlNodePtr next;
975
976 next = doc->children;
977 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
978 next = next->next;
979 if (next == NULL) {
980 cur->prev = doc->last;
981 cur->prev->next = (xmlNodePtr) cur;
982 cur->next = NULL;
983 doc->last = (xmlNodePtr) cur;
984 } else {
985 cur->next = next;
986 cur->prev = next->prev;
987 if (cur->prev == NULL)
988 doc->children = (xmlNodePtr) cur;
989 else
990 cur->prev->next = (xmlNodePtr) cur;
991 next->prev = (xmlNodePtr) cur;
992 }
Owen Taylor3473f882001-02-23 17:55:21 +0000993 }
994 }
995 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000996
Daniel Veillarda880b122003-04-21 21:36:41 +0000997 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000998 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000999 return(cur);
1000}
1001
1002/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001003 * DICT_FREE:
1004 * @str: a string
1005 *
1006 * Free a string if it is not owned by the "dict" dictionnary in the
1007 * current scope
1008 */
1009#define DICT_FREE(str) \
1010 if ((str) && ((!dict) || \
1011 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
1012 xmlFree((char *)(str));
1013
1014/**
Owen Taylor3473f882001-02-23 17:55:21 +00001015 * xmlFreeDtd:
1016 * @cur: the DTD structure to free up
1017 *
1018 * Free a DTD structure.
1019 */
1020void
1021xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001022 xmlDictPtr dict = NULL;
1023
Owen Taylor3473f882001-02-23 17:55:21 +00001024 if (cur == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001025 return;
1026 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001027 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001028
Daniel Veillarda880b122003-04-21 21:36:41 +00001029 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001030 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1031
Owen Taylor3473f882001-02-23 17:55:21 +00001032 if (cur->children != NULL) {
1033 xmlNodePtr next, c = cur->children;
1034
1035 /*
William M. Brack18a04f22004-08-03 16:42:37 +00001036 * Cleanup all nodes which are not part of the specific lists
1037 * of notations, elements, attributes and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00001038 */
1039 while (c != NULL) {
1040 next = c->next;
William M. Brack18a04f22004-08-03 16:42:37 +00001041 if ((c->type != XML_NOTATION_NODE) &&
1042 (c->type != XML_ELEMENT_DECL) &&
1043 (c->type != XML_ATTRIBUTE_DECL) &&
1044 (c->type != XML_ENTITY_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001045 xmlUnlinkNode(c);
1046 xmlFreeNode(c);
1047 }
1048 c = next;
1049 }
1050 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001051 DICT_FREE(cur->name)
1052 DICT_FREE(cur->SystemID)
1053 DICT_FREE(cur->ExternalID)
Owen Taylor3473f882001-02-23 17:55:21 +00001054 /* TODO !!! */
1055 if (cur->notations != NULL)
1056 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1057
1058 if (cur->elements != NULL)
1059 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1060 if (cur->attributes != NULL)
1061 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1062 if (cur->entities != NULL)
1063 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1064 if (cur->pentities != NULL)
1065 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1066
Owen Taylor3473f882001-02-23 17:55:21 +00001067 xmlFree(cur);
1068}
1069
1070/**
1071 * xmlNewDoc:
1072 * @version: xmlChar string giving the version of XML "1.0"
1073 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001074 * Creates a new XML document
1075 *
Owen Taylor3473f882001-02-23 17:55:21 +00001076 * Returns a new document
1077 */
1078xmlDocPtr
1079xmlNewDoc(const xmlChar *version) {
1080 xmlDocPtr cur;
1081
1082 if (version == NULL)
1083 version = (const xmlChar *) "1.0";
1084
1085 /*
1086 * Allocate a new document and fill the fields.
1087 */
1088 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1089 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001090 xmlTreeErrMemory("building doc");
Owen Taylor3473f882001-02-23 17:55:21 +00001091 return(NULL);
1092 }
1093 memset(cur, 0, sizeof(xmlDoc));
1094 cur->type = XML_DOCUMENT_NODE;
1095
1096 cur->version = xmlStrdup(version);
William M. Bracka3215c72004-07-31 16:24:01 +00001097 if (cur->version == NULL) {
1098 xmlTreeErrMemory("building doc");
1099 xmlFree(cur);
1100 return(NULL);
1101 }
Owen Taylor3473f882001-02-23 17:55:21 +00001102 cur->standalone = -1;
1103 cur->compression = -1; /* not initialized */
1104 cur->doc = cur;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001105 /*
1106 * The in memory encoding is always UTF8
1107 * This field will never change and would
1108 * be obsolete if not for binary compatibility.
1109 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001110 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001111
Daniel Veillarda880b122003-04-21 21:36:41 +00001112 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001113 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001114 return(cur);
1115}
1116
1117/**
1118 * xmlFreeDoc:
1119 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001120 *
1121 * Free up all the structures used by a document, tree included.
1122 */
1123void
1124xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001125 xmlDtdPtr extSubset, intSubset;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001126 xmlDictPtr dict = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001127
Owen Taylor3473f882001-02-23 17:55:21 +00001128 if (cur == NULL) {
1129#ifdef DEBUG_TREE
1130 xmlGenericError(xmlGenericErrorContext,
1131 "xmlFreeDoc : document == NULL\n");
1132#endif
1133 return;
1134 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001135#ifdef LIBXML_DEBUG_RUNTIME
1136 xmlDebugCheckDocument(stderr, cur);
1137#endif
1138
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001139 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001140
Daniel Veillarda880b122003-04-21 21:36:41 +00001141 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001142 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1143
Daniel Veillard76d66f42001-05-16 21:05:17 +00001144 /*
1145 * Do this before freeing the children list to avoid ID lookups
1146 */
1147 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1148 cur->ids = NULL;
1149 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1150 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001151 extSubset = cur->extSubset;
1152 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001153 if (intSubset == extSubset)
1154 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001155 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001156 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001157 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001158 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001159 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001160 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001161 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001162 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001163 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001164 }
1165
1166 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001167 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001168
1169 DICT_FREE(cur->version)
1170 DICT_FREE(cur->name)
1171 DICT_FREE(cur->encoding)
1172 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001173 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001174 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001175}
1176
1177/**
1178 * xmlStringLenGetNodeList:
1179 * @doc: the document
1180 * @value: the value of the text
1181 * @len: the length of the string value
1182 *
1183 * Parse the value string and build the node list associated. Should
1184 * produce a flat tree with only TEXTs and ENTITY_REFs.
1185 * Returns a pointer to the first child
1186 */
1187xmlNodePtr
1188xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1189 xmlNodePtr ret = NULL, last = NULL;
1190 xmlNodePtr node;
1191 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001192 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001193 const xmlChar *q;
1194 xmlEntityPtr ent;
1195
1196 if (value == NULL) return(NULL);
1197
1198 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001199 while ((cur < end) && (*cur != 0)) {
1200 if (cur[0] == '&') {
1201 int charval = 0;
1202 xmlChar tmp;
1203
Owen Taylor3473f882001-02-23 17:55:21 +00001204 /*
1205 * Save the current text.
1206 */
1207 if (cur != q) {
1208 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1209 xmlNodeAddContentLen(last, q, cur - q);
1210 } else {
1211 node = xmlNewDocTextLen(doc, q, cur - q);
1212 if (node == NULL) return(ret);
1213 if (last == NULL)
1214 last = ret = node;
1215 else {
1216 last->next = node;
1217 node->prev = last;
1218 last = node;
1219 }
1220 }
1221 }
Owen Taylor3473f882001-02-23 17:55:21 +00001222 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001223 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1224 cur += 3;
1225 if (cur < end)
1226 tmp = *cur;
1227 else
1228 tmp = 0;
1229 while (tmp != ';') { /* Non input consuming loop */
1230 if ((tmp >= '0') && (tmp <= '9'))
1231 charval = charval * 16 + (tmp - '0');
1232 else if ((tmp >= 'a') && (tmp <= 'f'))
1233 charval = charval * 16 + (tmp - 'a') + 10;
1234 else if ((tmp >= 'A') && (tmp <= 'F'))
1235 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001236 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001237 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1238 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001239 charval = 0;
1240 break;
1241 }
1242 cur++;
1243 if (cur < end)
1244 tmp = *cur;
1245 else
1246 tmp = 0;
1247 }
1248 if (tmp == ';')
1249 cur++;
1250 q = cur;
1251 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1252 cur += 2;
1253 if (cur < end)
1254 tmp = *cur;
1255 else
1256 tmp = 0;
1257 while (tmp != ';') { /* Non input consuming loops */
1258 if ((tmp >= '0') && (tmp <= '9'))
1259 charval = charval * 10 + (tmp - '0');
1260 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001261 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1262 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001263 charval = 0;
1264 break;
1265 }
1266 cur++;
1267 if (cur < end)
1268 tmp = *cur;
1269 else
1270 tmp = 0;
1271 }
1272 if (tmp == ';')
1273 cur++;
1274 q = cur;
1275 } else {
1276 /*
1277 * Read the entity string
1278 */
1279 cur++;
1280 q = cur;
1281 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1282 if ((cur >= end) || (*cur == 0)) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001283 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1284 (const char *) q);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001285 return(ret);
1286 }
1287 if (cur != q) {
1288 /*
1289 * Predefined entities don't generate nodes
1290 */
1291 val = xmlStrndup(q, cur - q);
1292 ent = xmlGetDocEntity(doc, val);
1293 if ((ent != NULL) &&
1294 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1295 if (last == NULL) {
1296 node = xmlNewDocText(doc, ent->content);
1297 last = ret = node;
1298 } else if (last->type != XML_TEXT_NODE) {
1299 node = xmlNewDocText(doc, ent->content);
1300 last = xmlAddNextSibling(last, node);
1301 } else
1302 xmlNodeAddContent(last, ent->content);
1303
1304 } else {
1305 /*
1306 * Create a new REFERENCE_REF node
1307 */
1308 node = xmlNewReference(doc, val);
1309 if (node == NULL) {
1310 if (val != NULL) xmlFree(val);
1311 return(ret);
1312 }
1313 else if ((ent != NULL) && (ent->children == NULL)) {
1314 xmlNodePtr temp;
1315
1316 ent->children = xmlStringGetNodeList(doc,
1317 (const xmlChar*)node->content);
1318 ent->owner = 1;
1319 temp = ent->children;
1320 while (temp) {
1321 temp->parent = (xmlNodePtr)ent;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001322 ent->last = temp;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001323 temp = temp->next;
1324 }
1325 }
1326 if (last == NULL) {
1327 last = ret = node;
1328 } else {
1329 last = xmlAddNextSibling(last, node);
1330 }
1331 }
1332 xmlFree(val);
1333 }
1334 cur++;
1335 q = cur;
1336 }
1337 if (charval != 0) {
1338 xmlChar buf[10];
1339 int l;
1340
1341 l = xmlCopyCharMultiByte(buf, charval);
1342 buf[l] = 0;
1343 node = xmlNewDocText(doc, buf);
1344 if (node != NULL) {
1345 if (last == NULL) {
1346 last = ret = node;
1347 } else {
1348 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001349 }
1350 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001351 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001352 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001353 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001354 cur++;
1355 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001356 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001357 /*
1358 * Handle the last piece of text.
1359 */
1360 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1361 xmlNodeAddContentLen(last, q, cur - q);
1362 } else {
1363 node = xmlNewDocTextLen(doc, q, cur - q);
1364 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001365 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001366 last = ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001367 } else {
1368 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001369 }
1370 }
1371 }
1372 return(ret);
1373}
1374
1375/**
1376 * xmlStringGetNodeList:
1377 * @doc: the document
1378 * @value: the value of the attribute
1379 *
1380 * Parse the value string and build the node list associated. Should
1381 * produce a flat tree with only TEXTs and ENTITY_REFs.
1382 * Returns a pointer to the first child
1383 */
1384xmlNodePtr
1385xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1386 xmlNodePtr ret = NULL, last = NULL;
1387 xmlNodePtr node;
1388 xmlChar *val;
1389 const xmlChar *cur = value;
1390 const xmlChar *q;
1391 xmlEntityPtr ent;
1392
1393 if (value == NULL) return(NULL);
1394
1395 q = cur;
1396 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001397 if (cur[0] == '&') {
1398 int charval = 0;
1399 xmlChar tmp;
1400
Owen Taylor3473f882001-02-23 17:55:21 +00001401 /*
1402 * Save the current text.
1403 */
1404 if (cur != q) {
1405 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1406 xmlNodeAddContentLen(last, q, cur - q);
1407 } else {
1408 node = xmlNewDocTextLen(doc, q, cur - q);
1409 if (node == NULL) return(ret);
1410 if (last == NULL)
1411 last = ret = node;
1412 else {
1413 last->next = node;
1414 node->prev = last;
1415 last = node;
1416 }
1417 }
1418 }
Owen Taylor3473f882001-02-23 17:55:21 +00001419 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001420 if ((cur[1] == '#') && (cur[2] == 'x')) {
1421 cur += 3;
1422 tmp = *cur;
1423 while (tmp != ';') { /* Non input consuming loop */
1424 if ((tmp >= '0') && (tmp <= '9'))
1425 charval = charval * 16 + (tmp - '0');
1426 else if ((tmp >= 'a') && (tmp <= 'f'))
1427 charval = charval * 16 + (tmp - 'a') + 10;
1428 else if ((tmp >= 'A') && (tmp <= 'F'))
1429 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001430 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001431 xmlTreeErr(XML_TREE_INVALID_HEX, (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 if (cur[1] == '#') {
1443 cur += 2;
1444 tmp = *cur;
1445 while (tmp != ';') { /* Non input consuming loops */
1446 if ((tmp >= '0') && (tmp <= '9'))
1447 charval = charval * 10 + (tmp - '0');
1448 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001449 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1450 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001451 charval = 0;
1452 break;
1453 }
1454 cur++;
1455 tmp = *cur;
1456 }
1457 if (tmp == ';')
1458 cur++;
1459 q = cur;
1460 } else {
1461 /*
1462 * Read the entity string
1463 */
1464 cur++;
1465 q = cur;
1466 while ((*cur != 0) && (*cur != ';')) cur++;
1467 if (*cur == 0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001468 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1469 (xmlNodePtr) doc, (const char *) q);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001470 return(ret);
1471 }
1472 if (cur != q) {
1473 /*
1474 * Predefined entities don't generate nodes
1475 */
1476 val = xmlStrndup(q, cur - q);
1477 ent = xmlGetDocEntity(doc, val);
1478 if ((ent != NULL) &&
1479 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1480 if (last == NULL) {
1481 node = xmlNewDocText(doc, ent->content);
1482 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001483 } else if (last->type != XML_TEXT_NODE) {
1484 node = xmlNewDocText(doc, ent->content);
1485 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001486 } else
1487 xmlNodeAddContent(last, ent->content);
1488
1489 } else {
1490 /*
1491 * Create a new REFERENCE_REF node
1492 */
1493 node = xmlNewReference(doc, val);
1494 if (node == NULL) {
1495 if (val != NULL) xmlFree(val);
1496 return(ret);
1497 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001498 else if ((ent != NULL) && (ent->children == NULL)) {
1499 xmlNodePtr temp;
1500
1501 ent->children = xmlStringGetNodeList(doc,
1502 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001503 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001504 temp = ent->children;
1505 while (temp) {
1506 temp->parent = (xmlNodePtr)ent;
1507 temp = temp->next;
1508 }
1509 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001510 if (last == NULL) {
1511 last = ret = node;
1512 } else {
1513 last = xmlAddNextSibling(last, node);
1514 }
1515 }
1516 xmlFree(val);
1517 }
1518 cur++;
1519 q = cur;
1520 }
1521 if (charval != 0) {
1522 xmlChar buf[10];
1523 int len;
1524
1525 len = xmlCopyCharMultiByte(buf, charval);
1526 buf[len] = 0;
1527 node = xmlNewDocText(doc, buf);
1528 if (node != NULL) {
1529 if (last == NULL) {
1530 last = ret = node;
1531 } else {
1532 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001533 }
1534 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001535
1536 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001537 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001538 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001539 cur++;
1540 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001541 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001542 /*
1543 * Handle the last piece of text.
1544 */
1545 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1546 xmlNodeAddContentLen(last, q, cur - q);
1547 } else {
1548 node = xmlNewDocTextLen(doc, q, cur - q);
1549 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001550 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001551 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001552 } else {
1553 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001554 }
1555 }
1556 }
1557 return(ret);
1558}
1559
1560/**
1561 * xmlNodeListGetString:
1562 * @doc: the document
1563 * @list: a Node list
1564 * @inLine: should we replace entity contents or show their external form
1565 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001566 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001567 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001568 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001569 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001570 */
1571xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001572xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1573{
Owen Taylor3473f882001-02-23 17:55:21 +00001574 xmlNodePtr node = list;
1575 xmlChar *ret = NULL;
1576 xmlEntityPtr ent;
1577
Daniel Veillard7646b182002-04-20 06:41:40 +00001578 if (list == NULL)
1579 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001580
1581 while (node != NULL) {
1582 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001583 (node->type == XML_CDATA_SECTION_NODE)) {
1584 if (inLine) {
1585 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001586 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001587 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001588
Daniel Veillard7646b182002-04-20 06:41:40 +00001589 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1590 if (buffer != NULL) {
1591 ret = xmlStrcat(ret, buffer);
1592 xmlFree(buffer);
1593 }
1594 }
1595 } else if (node->type == XML_ENTITY_REF_NODE) {
1596 if (inLine) {
1597 ent = xmlGetDocEntity(doc, node->name);
1598 if (ent != NULL) {
1599 xmlChar *buffer;
1600
1601 /* an entity content can be any "well balanced chunk",
1602 * i.e. the result of the content [43] production:
1603 * http://www.w3.org/TR/REC-xml#NT-content.
1604 * So it can contain text, CDATA section or nested
1605 * entity reference nodes (among others).
1606 * -> we recursive call xmlNodeListGetString()
1607 * which handles these types */
1608 buffer = xmlNodeListGetString(doc, ent->children, 1);
1609 if (buffer != NULL) {
1610 ret = xmlStrcat(ret, buffer);
1611 xmlFree(buffer);
1612 }
1613 } else {
1614 ret = xmlStrcat(ret, node->content);
1615 }
1616 } else {
1617 xmlChar buf[2];
1618
1619 buf[0] = '&';
1620 buf[1] = 0;
1621 ret = xmlStrncat(ret, buf, 1);
1622 ret = xmlStrcat(ret, node->name);
1623 buf[0] = ';';
1624 buf[1] = 0;
1625 ret = xmlStrncat(ret, buf, 1);
1626 }
1627 }
1628#if 0
1629 else {
1630 xmlGenericError(xmlGenericErrorContext,
1631 "xmlGetNodeListString : invalid node type %d\n",
1632 node->type);
1633 }
1634#endif
1635 node = node->next;
1636 }
1637 return (ret);
1638}
Daniel Veillard652327a2003-09-29 18:02:38 +00001639
1640#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001641/**
1642 * xmlNodeListGetRawString:
1643 * @doc: the document
1644 * @list: a Node list
1645 * @inLine: should we replace entity contents or show their external form
1646 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001647 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001648 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1649 * this function doesn't do any character encoding handling.
1650 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001651 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001652 */
1653xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001654xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1655{
Owen Taylor3473f882001-02-23 17:55:21 +00001656 xmlNodePtr node = list;
1657 xmlChar *ret = NULL;
1658 xmlEntityPtr ent;
1659
Daniel Veillard7646b182002-04-20 06:41:40 +00001660 if (list == NULL)
1661 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001662
1663 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001664 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001665 (node->type == XML_CDATA_SECTION_NODE)) {
1666 if (inLine) {
1667 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001668 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001669 xmlChar *buffer;
1670
1671 buffer = xmlEncodeSpecialChars(doc, node->content);
1672 if (buffer != NULL) {
1673 ret = xmlStrcat(ret, buffer);
1674 xmlFree(buffer);
1675 }
1676 }
1677 } else if (node->type == XML_ENTITY_REF_NODE) {
1678 if (inLine) {
1679 ent = xmlGetDocEntity(doc, node->name);
1680 if (ent != NULL) {
1681 xmlChar *buffer;
1682
1683 /* an entity content can be any "well balanced chunk",
1684 * i.e. the result of the content [43] production:
1685 * http://www.w3.org/TR/REC-xml#NT-content.
1686 * So it can contain text, CDATA section or nested
1687 * entity reference nodes (among others).
1688 * -> we recursive call xmlNodeListGetRawString()
1689 * which handles these types */
1690 buffer =
1691 xmlNodeListGetRawString(doc, ent->children, 1);
1692 if (buffer != NULL) {
1693 ret = xmlStrcat(ret, buffer);
1694 xmlFree(buffer);
1695 }
1696 } else {
1697 ret = xmlStrcat(ret, node->content);
1698 }
1699 } else {
1700 xmlChar buf[2];
1701
1702 buf[0] = '&';
1703 buf[1] = 0;
1704 ret = xmlStrncat(ret, buf, 1);
1705 ret = xmlStrcat(ret, node->name);
1706 buf[0] = ';';
1707 buf[1] = 0;
1708 ret = xmlStrncat(ret, buf, 1);
1709 }
1710 }
Owen Taylor3473f882001-02-23 17:55:21 +00001711#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001712 else {
1713 xmlGenericError(xmlGenericErrorContext,
1714 "xmlGetNodeListString : invalid node type %d\n",
1715 node->type);
1716 }
Owen Taylor3473f882001-02-23 17:55:21 +00001717#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001718 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001719 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001720 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001721}
Daniel Veillard652327a2003-09-29 18:02:38 +00001722#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001723
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001724static xmlAttrPtr xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns,
1725 const xmlChar *name, const xmlChar *value, int eatname) {
Owen Taylor3473f882001-02-23 17:55:21 +00001726 xmlAttrPtr cur;
1727 xmlDocPtr doc = NULL;
1728
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001729 if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) {
1730 if (eatname == 1)
1731 xmlFree((xmlChar *) name);
1732 return(NULL);
1733 }
Owen Taylor3473f882001-02-23 17:55:21 +00001734
1735 /*
1736 * Allocate a new property and fill the fields.
1737 */
1738 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1739 if (cur == NULL) {
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001740 if (eatname == 1)
1741 xmlFree((xmlChar *) name);
1742 xmlTreeErrMemory("building attribute");
1743 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001744 }
1745 memset(cur, 0, sizeof(xmlAttr));
1746 cur->type = XML_ATTRIBUTE_NODE;
1747
1748 cur->parent = node;
1749 if (node != NULL) {
1750 doc = node->doc;
1751 cur->doc = doc;
1752 }
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001753 cur->ns = ns;
1754
1755 if (eatname == 0) {
1756 if ((doc != NULL) && (doc->dict != NULL))
1757 cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
1758 else
1759 cur->name = xmlStrdup(name);
1760 } else
1761 cur->name = name;
1762
Owen Taylor3473f882001-02-23 17:55:21 +00001763 if (value != NULL) {
1764 xmlChar *buffer;
1765 xmlNodePtr tmp;
1766
1767 buffer = xmlEncodeEntitiesReentrant(doc, value);
1768 cur->children = xmlStringGetNodeList(doc, buffer);
1769 cur->last = NULL;
1770 tmp = cur->children;
1771 while (tmp != NULL) {
1772 tmp->parent = (xmlNodePtr) cur;
Owen Taylor3473f882001-02-23 17:55:21 +00001773 if (tmp->next == NULL)
1774 cur->last = tmp;
1775 tmp = tmp->next;
1776 }
1777 xmlFree(buffer);
1778 }
1779
1780 /*
1781 * Add it at the end to preserve parsing order ...
1782 */
1783 if (node != NULL) {
1784 if (node->properties == NULL) {
1785 node->properties = cur;
1786 } else {
1787 xmlAttrPtr prev = node->properties;
1788
1789 while (prev->next != NULL) prev = prev->next;
1790 prev->next = cur;
1791 cur->prev = prev;
1792 }
1793 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001794
Daniel Veillarda880b122003-04-21 21:36:41 +00001795 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001796 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001797 return(cur);
1798}
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001799
1800#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
1801 defined(LIBXML_SCHEMAS_ENABLED)
1802/**
1803 * xmlNewProp:
1804 * @node: the holding node
1805 * @name: the name of the attribute
1806 * @value: the value of the attribute
1807 *
1808 * Create a new property carried by a node.
1809 * Returns a pointer to the attribute
1810 */
1811xmlAttrPtr
1812xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1813
1814 if (name == NULL) {
1815#ifdef DEBUG_TREE
1816 xmlGenericError(xmlGenericErrorContext,
1817 "xmlNewProp : name == NULL\n");
1818#endif
1819 return(NULL);
1820 }
1821
1822 return xmlNewPropInternal(node, NULL, name, value, 0);
1823}
Daniel Veillard652327a2003-09-29 18:02:38 +00001824#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001825
1826/**
1827 * xmlNewNsProp:
1828 * @node: the holding node
1829 * @ns: the namespace
1830 * @name: the name of the attribute
1831 * @value: the value of the attribute
1832 *
1833 * Create a new property tagged with a namespace and carried by a node.
1834 * Returns a pointer to the attribute
1835 */
1836xmlAttrPtr
1837xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1838 const xmlChar *value) {
Owen Taylor3473f882001-02-23 17:55:21 +00001839
1840 if (name == NULL) {
1841#ifdef DEBUG_TREE
1842 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001843 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001844#endif
1845 return(NULL);
1846 }
1847
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001848 return xmlNewPropInternal(node, ns, name, value, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001849}
1850
1851/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001852 * xmlNewNsPropEatName:
1853 * @node: the holding node
1854 * @ns: the namespace
1855 * @name: the name of the attribute
1856 * @value: the value of the attribute
1857 *
1858 * Create a new property tagged with a namespace and carried by a node.
1859 * Returns a pointer to the attribute
1860 */
1861xmlAttrPtr
1862xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1863 const xmlChar *value) {
Daniel Veillard46de64e2002-05-29 08:21:33 +00001864
1865 if (name == NULL) {
1866#ifdef DEBUG_TREE
1867 xmlGenericError(xmlGenericErrorContext,
1868 "xmlNewNsPropEatName : name == NULL\n");
1869#endif
1870 return(NULL);
1871 }
1872
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001873 return xmlNewPropInternal(node, ns, name, value, 1);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001874}
1875
1876/**
Owen Taylor3473f882001-02-23 17:55:21 +00001877 * xmlNewDocProp:
1878 * @doc: the document
1879 * @name: the name of the attribute
1880 * @value: the value of the attribute
1881 *
1882 * Create a new property carried by a document.
1883 * Returns a pointer to the attribute
1884 */
1885xmlAttrPtr
1886xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1887 xmlAttrPtr cur;
1888
1889 if (name == NULL) {
1890#ifdef DEBUG_TREE
1891 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001892 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001893#endif
1894 return(NULL);
1895 }
1896
1897 /*
1898 * Allocate a new property and fill the fields.
1899 */
1900 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1901 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001902 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001903 return(NULL);
1904 }
1905 memset(cur, 0, sizeof(xmlAttr));
1906 cur->type = XML_ATTRIBUTE_NODE;
1907
Daniel Veillard03a53c32004-10-26 16:06:51 +00001908 if ((doc != NULL) && (doc->dict != NULL))
1909 cur->name = xmlDictLookup(doc->dict, name, -1);
1910 else
1911 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00001912 cur->doc = doc;
1913 if (value != NULL) {
1914 xmlNodePtr tmp;
1915
1916 cur->children = xmlStringGetNodeList(doc, value);
1917 cur->last = NULL;
1918
1919 tmp = cur->children;
1920 while (tmp != NULL) {
1921 tmp->parent = (xmlNodePtr) cur;
1922 if (tmp->next == NULL)
1923 cur->last = tmp;
1924 tmp = tmp->next;
1925 }
1926 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001927
Daniel Veillarda880b122003-04-21 21:36:41 +00001928 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001929 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001930 return(cur);
1931}
1932
1933/**
1934 * xmlFreePropList:
1935 * @cur: the first property in the list
1936 *
1937 * Free a property and all its siblings, all the children are freed too.
1938 */
1939void
1940xmlFreePropList(xmlAttrPtr cur) {
1941 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001942 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001943 while (cur != NULL) {
1944 next = cur->next;
1945 xmlFreeProp(cur);
1946 cur = next;
1947 }
1948}
1949
1950/**
1951 * xmlFreeProp:
1952 * @cur: an attribute
1953 *
1954 * Free one attribute, all the content is freed too
1955 */
1956void
1957xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001958 xmlDictPtr dict = NULL;
1959 if (cur == NULL) return;
1960
1961 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001962
Daniel Veillarda880b122003-04-21 21:36:41 +00001963 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001964 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1965
Owen Taylor3473f882001-02-23 17:55:21 +00001966 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001967 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1968 ((cur->parent->doc->intSubset != NULL) ||
1969 (cur->parent->doc->extSubset != NULL))) {
1970 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1971 xmlRemoveID(cur->parent->doc, cur);
1972 }
Owen Taylor3473f882001-02-23 17:55:21 +00001973 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001974 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00001975 xmlFree(cur);
1976}
1977
Daniel Veillard652327a2003-09-29 18:02:38 +00001978#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001979/**
1980 * xmlRemoveProp:
1981 * @cur: an attribute
1982 *
1983 * Unlink and free one attribute, all the content is freed too
1984 * Note this doesn't work for namespace definition attributes
1985 *
1986 * Returns 0 if success and -1 in case of error.
1987 */
1988int
1989xmlRemoveProp(xmlAttrPtr cur) {
1990 xmlAttrPtr tmp;
1991 if (cur == NULL) {
1992#ifdef DEBUG_TREE
1993 xmlGenericError(xmlGenericErrorContext,
1994 "xmlRemoveProp : cur == NULL\n");
1995#endif
1996 return(-1);
1997 }
1998 if (cur->parent == NULL) {
1999#ifdef DEBUG_TREE
2000 xmlGenericError(xmlGenericErrorContext,
2001 "xmlRemoveProp : cur->parent == NULL\n");
2002#endif
2003 return(-1);
2004 }
2005 tmp = cur->parent->properties;
2006 if (tmp == cur) {
2007 cur->parent->properties = cur->next;
2008 xmlFreeProp(cur);
2009 return(0);
2010 }
2011 while (tmp != NULL) {
2012 if (tmp->next == cur) {
2013 tmp->next = cur->next;
2014 if (tmp->next != NULL)
2015 tmp->next->prev = tmp;
2016 xmlFreeProp(cur);
2017 return(0);
2018 }
2019 tmp = tmp->next;
2020 }
2021#ifdef DEBUG_TREE
2022 xmlGenericError(xmlGenericErrorContext,
2023 "xmlRemoveProp : attribute not owned by its node\n");
2024#endif
2025 return(-1);
2026}
Daniel Veillard652327a2003-09-29 18:02:38 +00002027#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002028
2029/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002030 * xmlNewDocPI:
2031 * @doc: the target document
Owen Taylor3473f882001-02-23 17:55:21 +00002032 * @name: the processing instruction name
2033 * @content: the PI content
2034 *
2035 * Creation of a processing instruction element.
2036 * Returns a pointer to the new node object.
2037 */
2038xmlNodePtr
Daniel Veillard03a53c32004-10-26 16:06:51 +00002039xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
Owen Taylor3473f882001-02-23 17:55:21 +00002040 xmlNodePtr cur;
2041
2042 if (name == NULL) {
2043#ifdef DEBUG_TREE
2044 xmlGenericError(xmlGenericErrorContext,
2045 "xmlNewPI : name == NULL\n");
2046#endif
2047 return(NULL);
2048 }
2049
2050 /*
2051 * Allocate a new node and fill the fields.
2052 */
2053 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2054 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002055 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002056 return(NULL);
2057 }
2058 memset(cur, 0, sizeof(xmlNode));
2059 cur->type = XML_PI_NODE;
2060
Daniel Veillard03a53c32004-10-26 16:06:51 +00002061 if ((doc != NULL) && (doc->dict != NULL))
2062 cur->name = xmlDictLookup(doc->dict, name, -1);
2063 else
2064 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00002065 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002066 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002067 }
Daniel Veillarda03e3652004-11-02 18:45:30 +00002068 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002069
Daniel Veillarda880b122003-04-21 21:36:41 +00002070 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002071 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002072 return(cur);
2073}
2074
2075/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002076 * xmlNewPI:
2077 * @name: the processing instruction name
2078 * @content: the PI content
2079 *
2080 * Creation of a processing instruction element.
2081 * Use xmlDocNewPI preferably to get string interning
2082 *
2083 * Returns a pointer to the new node object.
2084 */
2085xmlNodePtr
2086xmlNewPI(const xmlChar *name, const xmlChar *content) {
2087 return(xmlNewDocPI(NULL, name, content));
2088}
2089
2090/**
Owen Taylor3473f882001-02-23 17:55:21 +00002091 * xmlNewNode:
2092 * @ns: namespace if any
2093 * @name: the node name
2094 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002095 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002096 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002097 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2098 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002099 */
2100xmlNodePtr
2101xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2102 xmlNodePtr cur;
2103
2104 if (name == NULL) {
2105#ifdef DEBUG_TREE
2106 xmlGenericError(xmlGenericErrorContext,
2107 "xmlNewNode : name == NULL\n");
2108#endif
2109 return(NULL);
2110 }
2111
2112 /*
2113 * Allocate a new node and fill the fields.
2114 */
2115 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2116 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002117 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002118 return(NULL);
2119 }
2120 memset(cur, 0, sizeof(xmlNode));
2121 cur->type = XML_ELEMENT_NODE;
2122
2123 cur->name = xmlStrdup(name);
2124 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002125
Daniel Veillarda880b122003-04-21 21:36:41 +00002126 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002127 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002128 return(cur);
2129}
2130
2131/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002132 * xmlNewNodeEatName:
2133 * @ns: namespace if any
2134 * @name: the node name
2135 *
2136 * Creation of a new node element. @ns is optional (NULL).
2137 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002138 * Returns a pointer to the new node object, with pointer @name as
2139 * new node's name. Use xmlNewNode() if a copy of @name string is
2140 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002141 */
2142xmlNodePtr
2143xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2144 xmlNodePtr cur;
2145
2146 if (name == NULL) {
2147#ifdef DEBUG_TREE
2148 xmlGenericError(xmlGenericErrorContext,
2149 "xmlNewNode : name == NULL\n");
2150#endif
2151 return(NULL);
2152 }
2153
2154 /*
2155 * Allocate a new node and fill the fields.
2156 */
2157 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2158 if (cur == NULL) {
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00002159 xmlFree(name);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002160 xmlTreeErrMemory("building node");
Daniel Veillard46de64e2002-05-29 08:21:33 +00002161 return(NULL);
2162 }
2163 memset(cur, 0, sizeof(xmlNode));
2164 cur->type = XML_ELEMENT_NODE;
2165
2166 cur->name = name;
2167 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002168
Daniel Veillarda880b122003-04-21 21:36:41 +00002169 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002170 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002171 return(cur);
2172}
2173
2174/**
Owen Taylor3473f882001-02-23 17:55:21 +00002175 * xmlNewDocNode:
2176 * @doc: the document
2177 * @ns: namespace if any
2178 * @name: the node name
2179 * @content: the XML text content if any
2180 *
2181 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002182 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002183 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2184 * references, but XML special chars need to be escaped first by using
2185 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2186 * need entities support.
2187 *
2188 * Returns a pointer to the new node object.
2189 */
2190xmlNodePtr
2191xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2192 const xmlChar *name, const xmlChar *content) {
2193 xmlNodePtr cur;
2194
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002195 if ((doc != NULL) && (doc->dict != NULL))
Daniel Veillard03a53c32004-10-26 16:06:51 +00002196 cur = xmlNewNodeEatName(ns, (xmlChar *)
2197 xmlDictLookup(doc->dict, name, -1));
2198 else
2199 cur = xmlNewNode(ns, name);
Owen Taylor3473f882001-02-23 17:55:21 +00002200 if (cur != NULL) {
2201 cur->doc = doc;
2202 if (content != NULL) {
2203 cur->children = xmlStringGetNodeList(doc, content);
2204 UPDATE_LAST_CHILD_AND_PARENT(cur)
2205 }
2206 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002207
Owen Taylor3473f882001-02-23 17:55:21 +00002208 return(cur);
2209}
2210
Daniel Veillard46de64e2002-05-29 08:21:33 +00002211/**
2212 * xmlNewDocNodeEatName:
2213 * @doc: the document
2214 * @ns: namespace if any
2215 * @name: the node name
2216 * @content: the XML text content if any
2217 *
2218 * Creation of a new node element within a document. @ns and @content
2219 * are optional (NULL).
2220 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2221 * references, but XML special chars need to be escaped first by using
2222 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2223 * need entities support.
2224 *
2225 * Returns a pointer to the new node object.
2226 */
2227xmlNodePtr
2228xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2229 xmlChar *name, const xmlChar *content) {
2230 xmlNodePtr cur;
2231
2232 cur = xmlNewNodeEatName(ns, name);
2233 if (cur != NULL) {
2234 cur->doc = doc;
2235 if (content != NULL) {
2236 cur->children = xmlStringGetNodeList(doc, content);
2237 UPDATE_LAST_CHILD_AND_PARENT(cur)
2238 }
2239 }
2240 return(cur);
2241}
2242
Daniel Veillard652327a2003-09-29 18:02:38 +00002243#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002244/**
2245 * xmlNewDocRawNode:
2246 * @doc: the document
2247 * @ns: namespace if any
2248 * @name: the node name
2249 * @content: the text content if any
2250 *
2251 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002252 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002253 *
2254 * Returns a pointer to the new node object.
2255 */
2256xmlNodePtr
2257xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2258 const xmlChar *name, const xmlChar *content) {
2259 xmlNodePtr cur;
2260
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002261 cur = xmlNewDocNode(doc, ns, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002262 if (cur != NULL) {
2263 cur->doc = doc;
2264 if (content != NULL) {
2265 cur->children = xmlNewDocText(doc, content);
2266 UPDATE_LAST_CHILD_AND_PARENT(cur)
2267 }
2268 }
2269 return(cur);
2270}
2271
2272/**
2273 * xmlNewDocFragment:
2274 * @doc: the document owning the fragment
2275 *
2276 * Creation of a new Fragment node.
2277 * Returns a pointer to the new node object.
2278 */
2279xmlNodePtr
2280xmlNewDocFragment(xmlDocPtr doc) {
2281 xmlNodePtr cur;
2282
2283 /*
2284 * Allocate a new DocumentFragment node and fill the fields.
2285 */
2286 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2287 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002288 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002289 return(NULL);
2290 }
2291 memset(cur, 0, sizeof(xmlNode));
2292 cur->type = XML_DOCUMENT_FRAG_NODE;
2293
2294 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002295
Daniel Veillarda880b122003-04-21 21:36:41 +00002296 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002297 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002298 return(cur);
2299}
Daniel Veillard652327a2003-09-29 18:02:38 +00002300#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002301
2302/**
2303 * xmlNewText:
2304 * @content: the text content
2305 *
2306 * Creation of a new text node.
2307 * Returns a pointer to the new node object.
2308 */
2309xmlNodePtr
2310xmlNewText(const xmlChar *content) {
2311 xmlNodePtr cur;
2312
2313 /*
2314 * Allocate a new node and fill the fields.
2315 */
2316 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2317 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002318 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002319 return(NULL);
2320 }
2321 memset(cur, 0, sizeof(xmlNode));
2322 cur->type = XML_TEXT_NODE;
2323
2324 cur->name = xmlStringText;
2325 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002326 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002327 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002328
Daniel Veillarda880b122003-04-21 21:36:41 +00002329 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002330 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002331 return(cur);
2332}
2333
Daniel Veillard652327a2003-09-29 18:02:38 +00002334#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002335/**
2336 * xmlNewTextChild:
2337 * @parent: the parent node
2338 * @ns: a namespace if any
2339 * @name: the name of the child
2340 * @content: the text content of the child if any.
2341 *
2342 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002343 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2344 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002345 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002346 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2347 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2348 * reserved XML chars that might appear in @content, such as the ampersand,
2349 * greater-than or less-than signs, are automatically replaced by their XML
2350 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002351 *
2352 * Returns a pointer to the new node object.
2353 */
2354xmlNodePtr
2355xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2356 const xmlChar *name, const xmlChar *content) {
2357 xmlNodePtr cur, prev;
2358
2359 if (parent == NULL) {
2360#ifdef DEBUG_TREE
2361 xmlGenericError(xmlGenericErrorContext,
2362 "xmlNewTextChild : parent == NULL\n");
2363#endif
2364 return(NULL);
2365 }
2366
2367 if (name == NULL) {
2368#ifdef DEBUG_TREE
2369 xmlGenericError(xmlGenericErrorContext,
2370 "xmlNewTextChild : name == NULL\n");
2371#endif
2372 return(NULL);
2373 }
2374
2375 /*
2376 * Allocate a new node
2377 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002378 if (parent->type == XML_ELEMENT_NODE) {
2379 if (ns == NULL)
2380 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2381 else
2382 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2383 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2384 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2385 if (ns == NULL)
2386 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2387 else
2388 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2389 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2390 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2391 } else {
2392 return(NULL);
2393 }
Owen Taylor3473f882001-02-23 17:55:21 +00002394 if (cur == NULL) return(NULL);
2395
2396 /*
2397 * add the new element at the end of the children list.
2398 */
2399 cur->type = XML_ELEMENT_NODE;
2400 cur->parent = parent;
2401 cur->doc = parent->doc;
2402 if (parent->children == NULL) {
2403 parent->children = cur;
2404 parent->last = cur;
2405 } else {
2406 prev = parent->last;
2407 prev->next = cur;
2408 cur->prev = prev;
2409 parent->last = cur;
2410 }
2411
2412 return(cur);
2413}
Daniel Veillard652327a2003-09-29 18:02:38 +00002414#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002415
2416/**
2417 * xmlNewCharRef:
2418 * @doc: the document
2419 * @name: the char ref string, starting with # or "&# ... ;"
2420 *
2421 * Creation of a new character reference node.
2422 * Returns a pointer to the new node object.
2423 */
2424xmlNodePtr
2425xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2426 xmlNodePtr cur;
2427
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002428 if (name == NULL)
2429 return(NULL);
2430
Owen Taylor3473f882001-02-23 17:55:21 +00002431 /*
2432 * Allocate a new node and fill the fields.
2433 */
2434 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2435 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002436 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002437 return(NULL);
2438 }
2439 memset(cur, 0, sizeof(xmlNode));
2440 cur->type = XML_ENTITY_REF_NODE;
2441
2442 cur->doc = doc;
2443 if (name[0] == '&') {
2444 int len;
2445 name++;
2446 len = xmlStrlen(name);
2447 if (name[len - 1] == ';')
2448 cur->name = xmlStrndup(name, len - 1);
2449 else
2450 cur->name = xmlStrndup(name, len);
2451 } else
2452 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002453
Daniel Veillarda880b122003-04-21 21:36:41 +00002454 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002455 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002456 return(cur);
2457}
2458
2459/**
2460 * xmlNewReference:
2461 * @doc: the document
2462 * @name: the reference name, or the reference string with & and ;
2463 *
2464 * Creation of a new reference node.
2465 * Returns a pointer to the new node object.
2466 */
2467xmlNodePtr
2468xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2469 xmlNodePtr cur;
2470 xmlEntityPtr ent;
2471
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002472 if (name == NULL)
2473 return(NULL);
2474
Owen Taylor3473f882001-02-23 17:55:21 +00002475 /*
2476 * Allocate a new node and fill the fields.
2477 */
2478 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2479 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002480 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002481 return(NULL);
2482 }
2483 memset(cur, 0, sizeof(xmlNode));
2484 cur->type = XML_ENTITY_REF_NODE;
2485
2486 cur->doc = doc;
2487 if (name[0] == '&') {
2488 int len;
2489 name++;
2490 len = xmlStrlen(name);
2491 if (name[len - 1] == ';')
2492 cur->name = xmlStrndup(name, len - 1);
2493 else
2494 cur->name = xmlStrndup(name, len);
2495 } else
2496 cur->name = xmlStrdup(name);
2497
2498 ent = xmlGetDocEntity(doc, cur->name);
2499 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002500 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002501 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002502 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002503 * updated. Not sure if this is 100% correct.
2504 * -George
2505 */
2506 cur->children = (xmlNodePtr) ent;
2507 cur->last = (xmlNodePtr) ent;
2508 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002509
Daniel Veillarda880b122003-04-21 21:36:41 +00002510 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002511 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002512 return(cur);
2513}
2514
2515/**
2516 * xmlNewDocText:
2517 * @doc: the document
2518 * @content: the text content
2519 *
2520 * Creation of a new text node within a document.
2521 * Returns a pointer to the new node object.
2522 */
2523xmlNodePtr
2524xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2525 xmlNodePtr cur;
2526
2527 cur = xmlNewText(content);
2528 if (cur != NULL) cur->doc = doc;
2529 return(cur);
2530}
2531
2532/**
2533 * xmlNewTextLen:
2534 * @content: the text content
2535 * @len: the text len.
2536 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002537 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002538 * Returns a pointer to the new node object.
2539 */
2540xmlNodePtr
2541xmlNewTextLen(const xmlChar *content, int len) {
2542 xmlNodePtr cur;
2543
2544 /*
2545 * Allocate a new node and fill the fields.
2546 */
2547 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2548 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002549 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002550 return(NULL);
2551 }
2552 memset(cur, 0, sizeof(xmlNode));
2553 cur->type = XML_TEXT_NODE;
2554
2555 cur->name = xmlStringText;
2556 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002557 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002558 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002559
Daniel Veillarda880b122003-04-21 21:36:41 +00002560 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002561 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002562 return(cur);
2563}
2564
2565/**
2566 * xmlNewDocTextLen:
2567 * @doc: the document
2568 * @content: the text content
2569 * @len: the text len.
2570 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002571 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002572 * text node pertain to a given document.
2573 * Returns a pointer to the new node object.
2574 */
2575xmlNodePtr
2576xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2577 xmlNodePtr cur;
2578
2579 cur = xmlNewTextLen(content, len);
2580 if (cur != NULL) cur->doc = doc;
2581 return(cur);
2582}
2583
2584/**
2585 * xmlNewComment:
2586 * @content: the comment content
2587 *
2588 * Creation of a new node containing a comment.
2589 * Returns a pointer to the new node object.
2590 */
2591xmlNodePtr
2592xmlNewComment(const xmlChar *content) {
2593 xmlNodePtr cur;
2594
2595 /*
2596 * Allocate a new node and fill the fields.
2597 */
2598 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2599 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002600 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002601 return(NULL);
2602 }
2603 memset(cur, 0, sizeof(xmlNode));
2604 cur->type = XML_COMMENT_NODE;
2605
2606 cur->name = xmlStringComment;
2607 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002608 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002609 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002610
Daniel Veillarda880b122003-04-21 21:36:41 +00002611 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002612 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002613 return(cur);
2614}
2615
2616/**
2617 * xmlNewCDataBlock:
2618 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002619 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002620 * @len: the length of the block
2621 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002622 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002623 * Returns a pointer to the new node object.
2624 */
2625xmlNodePtr
2626xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2627 xmlNodePtr cur;
2628
2629 /*
2630 * Allocate a new node and fill the fields.
2631 */
2632 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2633 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002634 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002635 return(NULL);
2636 }
2637 memset(cur, 0, sizeof(xmlNode));
2638 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002639 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002640
2641 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002642 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002643 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002644
Daniel Veillarda880b122003-04-21 21:36:41 +00002645 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002646 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002647 return(cur);
2648}
2649
2650/**
2651 * xmlNewDocComment:
2652 * @doc: the document
2653 * @content: the comment content
2654 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002655 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002656 * Returns a pointer to the new node object.
2657 */
2658xmlNodePtr
2659xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2660 xmlNodePtr cur;
2661
2662 cur = xmlNewComment(content);
2663 if (cur != NULL) cur->doc = doc;
2664 return(cur);
2665}
2666
2667/**
2668 * xmlSetTreeDoc:
2669 * @tree: the top element
2670 * @doc: the document
2671 *
2672 * update all nodes under the tree to point to the right document
2673 */
2674void
2675xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002676 xmlAttrPtr prop;
2677
Owen Taylor3473f882001-02-23 17:55:21 +00002678 if (tree == NULL)
2679 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002680 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002681 if(tree->type == XML_ELEMENT_NODE) {
2682 prop = tree->properties;
2683 while (prop != NULL) {
2684 prop->doc = doc;
2685 xmlSetListDoc(prop->children, doc);
2686 prop = prop->next;
2687 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002688 }
Owen Taylor3473f882001-02-23 17:55:21 +00002689 if (tree->children != NULL)
2690 xmlSetListDoc(tree->children, doc);
2691 tree->doc = doc;
2692 }
2693}
2694
2695/**
2696 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002697 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002698 * @doc: the document
2699 *
2700 * update all nodes in the list to point to the right document
2701 */
2702void
2703xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2704 xmlNodePtr cur;
2705
2706 if (list == NULL)
2707 return;
2708 cur = list;
2709 while (cur != NULL) {
2710 if (cur->doc != doc)
2711 xmlSetTreeDoc(cur, doc);
2712 cur = cur->next;
2713 }
2714}
2715
Daniel Veillard2156d432004-03-04 15:59:36 +00002716#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002717/**
2718 * xmlNewChild:
2719 * @parent: the parent node
2720 * @ns: a namespace if any
2721 * @name: the name of the child
2722 * @content: the XML content of the child if any.
2723 *
2724 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002725 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2726 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002727 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002728 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2729 * references. XML special chars must be escaped first by using
2730 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002731 *
2732 * Returns a pointer to the new node object.
2733 */
2734xmlNodePtr
2735xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2736 const xmlChar *name, const xmlChar *content) {
2737 xmlNodePtr cur, prev;
2738
2739 if (parent == NULL) {
2740#ifdef DEBUG_TREE
2741 xmlGenericError(xmlGenericErrorContext,
2742 "xmlNewChild : parent == NULL\n");
2743#endif
2744 return(NULL);
2745 }
2746
2747 if (name == NULL) {
2748#ifdef DEBUG_TREE
2749 xmlGenericError(xmlGenericErrorContext,
2750 "xmlNewChild : name == NULL\n");
2751#endif
2752 return(NULL);
2753 }
2754
2755 /*
2756 * Allocate a new node
2757 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002758 if (parent->type == XML_ELEMENT_NODE) {
2759 if (ns == NULL)
2760 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2761 else
2762 cur = xmlNewDocNode(parent->doc, ns, name, content);
2763 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2764 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2765 if (ns == NULL)
2766 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2767 else
2768 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002769 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2770 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002771 } else {
2772 return(NULL);
2773 }
Owen Taylor3473f882001-02-23 17:55:21 +00002774 if (cur == NULL) return(NULL);
2775
2776 /*
2777 * add the new element at the end of the children list.
2778 */
2779 cur->type = XML_ELEMENT_NODE;
2780 cur->parent = parent;
2781 cur->doc = parent->doc;
2782 if (parent->children == NULL) {
2783 parent->children = cur;
2784 parent->last = cur;
2785 } else {
2786 prev = parent->last;
2787 prev->next = cur;
2788 cur->prev = prev;
2789 parent->last = cur;
2790 }
2791
2792 return(cur);
2793}
Daniel Veillard652327a2003-09-29 18:02:38 +00002794#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002795
2796/**
2797 * xmlAddNextSibling:
2798 * @cur: the child node
2799 * @elem: the new node
2800 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002801 * Add a new node @elem as the next sibling of @cur
2802 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002803 * first unlinked from its existing context.
2804 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002805 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2806 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002807 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002808 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002809 */
2810xmlNodePtr
2811xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2812 if (cur == NULL) {
2813#ifdef DEBUG_TREE
2814 xmlGenericError(xmlGenericErrorContext,
2815 "xmlAddNextSibling : cur == NULL\n");
2816#endif
2817 return(NULL);
2818 }
2819 if (elem == NULL) {
2820#ifdef DEBUG_TREE
2821 xmlGenericError(xmlGenericErrorContext,
2822 "xmlAddNextSibling : elem == NULL\n");
2823#endif
2824 return(NULL);
2825 }
2826
2827 xmlUnlinkNode(elem);
2828
2829 if (elem->type == XML_TEXT_NODE) {
2830 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002831 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002832 xmlFreeNode(elem);
2833 return(cur);
2834 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002835 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2836 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002837 xmlChar *tmp;
2838
2839 tmp = xmlStrdup(elem->content);
2840 tmp = xmlStrcat(tmp, cur->next->content);
2841 xmlNodeSetContent(cur->next, tmp);
2842 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002843 xmlFreeNode(elem);
2844 return(cur->next);
2845 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002846 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2847 /* check if an attribute with the same name exists */
2848 xmlAttrPtr attr;
2849
2850 if (elem->ns == NULL)
2851 attr = xmlHasProp(cur->parent, elem->name);
2852 else
2853 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2854 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2855 /* different instance, destroy it (attributes must be unique) */
2856 xmlFreeProp(attr);
2857 }
Owen Taylor3473f882001-02-23 17:55:21 +00002858 }
2859
2860 if (elem->doc != cur->doc) {
2861 xmlSetTreeDoc(elem, cur->doc);
2862 }
2863 elem->parent = cur->parent;
2864 elem->prev = cur;
2865 elem->next = cur->next;
2866 cur->next = elem;
2867 if (elem->next != NULL)
2868 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002869 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002870 elem->parent->last = elem;
2871 return(elem);
2872}
2873
William M. Brack21e4ef22005-01-02 09:53:13 +00002874#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
2875 defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002876/**
2877 * xmlAddPrevSibling:
2878 * @cur: the child node
2879 * @elem: the new node
2880 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002881 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002882 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002883 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002884 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002885 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2886 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002887 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002888 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002889 */
2890xmlNodePtr
2891xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2892 if (cur == NULL) {
2893#ifdef DEBUG_TREE
2894 xmlGenericError(xmlGenericErrorContext,
2895 "xmlAddPrevSibling : cur == NULL\n");
2896#endif
2897 return(NULL);
2898 }
2899 if (elem == NULL) {
2900#ifdef DEBUG_TREE
2901 xmlGenericError(xmlGenericErrorContext,
2902 "xmlAddPrevSibling : elem == NULL\n");
2903#endif
2904 return(NULL);
2905 }
2906
2907 xmlUnlinkNode(elem);
2908
2909 if (elem->type == XML_TEXT_NODE) {
2910 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002911 xmlChar *tmp;
2912
2913 tmp = xmlStrdup(elem->content);
2914 tmp = xmlStrcat(tmp, cur->content);
2915 xmlNodeSetContent(cur, tmp);
2916 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002917 xmlFreeNode(elem);
2918 return(cur);
2919 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002920 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2921 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002922 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002923 xmlFreeNode(elem);
2924 return(cur->prev);
2925 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002926 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2927 /* check if an attribute with the same name exists */
2928 xmlAttrPtr attr;
2929
2930 if (elem->ns == NULL)
2931 attr = xmlHasProp(cur->parent, elem->name);
2932 else
2933 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2934 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2935 /* different instance, destroy it (attributes must be unique) */
2936 xmlFreeProp(attr);
2937 }
Owen Taylor3473f882001-02-23 17:55:21 +00002938 }
2939
2940 if (elem->doc != cur->doc) {
2941 xmlSetTreeDoc(elem, cur->doc);
2942 }
2943 elem->parent = cur->parent;
2944 elem->next = cur;
2945 elem->prev = cur->prev;
2946 cur->prev = elem;
2947 if (elem->prev != NULL)
2948 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002949 if (elem->parent != NULL) {
2950 if (elem->type == XML_ATTRIBUTE_NODE) {
2951 if (elem->parent->properties == (xmlAttrPtr) cur) {
2952 elem->parent->properties = (xmlAttrPtr) elem;
2953 }
2954 } else {
2955 if (elem->parent->children == cur) {
2956 elem->parent->children = elem;
2957 }
2958 }
2959 }
Owen Taylor3473f882001-02-23 17:55:21 +00002960 return(elem);
2961}
Daniel Veillard652327a2003-09-29 18:02:38 +00002962#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002963
2964/**
2965 * xmlAddSibling:
2966 * @cur: the child node
2967 * @elem: the new node
2968 *
2969 * Add a new element @elem to the list of siblings of @cur
2970 * merging adjacent TEXT nodes (@elem may be freed)
2971 * If the new element was already inserted in a document it is
2972 * first unlinked from its existing context.
2973 *
2974 * Returns the new element or NULL in case of error.
2975 */
2976xmlNodePtr
2977xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2978 xmlNodePtr parent;
2979
2980 if (cur == NULL) {
2981#ifdef DEBUG_TREE
2982 xmlGenericError(xmlGenericErrorContext,
2983 "xmlAddSibling : cur == NULL\n");
2984#endif
2985 return(NULL);
2986 }
2987
2988 if (elem == NULL) {
2989#ifdef DEBUG_TREE
2990 xmlGenericError(xmlGenericErrorContext,
2991 "xmlAddSibling : elem == NULL\n");
2992#endif
2993 return(NULL);
2994 }
2995
2996 /*
2997 * Constant time is we can rely on the ->parent->last to find
2998 * the last sibling.
2999 */
3000 if ((cur->parent != NULL) &&
3001 (cur->parent->children != NULL) &&
3002 (cur->parent->last != NULL) &&
3003 (cur->parent->last->next == NULL)) {
3004 cur = cur->parent->last;
3005 } else {
3006 while (cur->next != NULL) cur = cur->next;
3007 }
3008
3009 xmlUnlinkNode(elem);
3010
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003011 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3012 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003013 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003014 xmlFreeNode(elem);
3015 return(cur);
3016 }
3017
3018 if (elem->doc != cur->doc) {
3019 xmlSetTreeDoc(elem, cur->doc);
3020 }
3021 parent = cur->parent;
3022 elem->prev = cur;
3023 elem->next = NULL;
3024 elem->parent = parent;
3025 cur->next = elem;
3026 if (parent != NULL)
3027 parent->last = elem;
3028
3029 return(elem);
3030}
3031
3032/**
3033 * xmlAddChildList:
3034 * @parent: the parent node
3035 * @cur: the first node in the list
3036 *
3037 * Add a list of node at the end of the child list of the parent
3038 * merging adjacent TEXT nodes (@cur may be freed)
3039 *
3040 * Returns the last child or NULL in case of error.
3041 */
3042xmlNodePtr
3043xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3044 xmlNodePtr prev;
3045
3046 if (parent == NULL) {
3047#ifdef DEBUG_TREE
3048 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003049 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003050#endif
3051 return(NULL);
3052 }
3053
3054 if (cur == NULL) {
3055#ifdef DEBUG_TREE
3056 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003057 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003058#endif
3059 return(NULL);
3060 }
3061
3062 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3063 (cur->doc != parent->doc)) {
3064#ifdef DEBUG_TREE
3065 xmlGenericError(xmlGenericErrorContext,
3066 "Elements moved to a different document\n");
3067#endif
3068 }
3069
3070 /*
3071 * add the first element at the end of the children list.
3072 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003073
Owen Taylor3473f882001-02-23 17:55:21 +00003074 if (parent->children == NULL) {
3075 parent->children = cur;
3076 } else {
3077 /*
3078 * If cur and parent->last both are TEXT nodes, then merge them.
3079 */
3080 if ((cur->type == XML_TEXT_NODE) &&
3081 (parent->last->type == XML_TEXT_NODE) &&
3082 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003083 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003084 /*
3085 * if it's the only child, nothing more to be done.
3086 */
3087 if (cur->next == NULL) {
3088 xmlFreeNode(cur);
3089 return(parent->last);
3090 }
3091 prev = cur;
3092 cur = cur->next;
3093 xmlFreeNode(prev);
3094 }
3095 prev = parent->last;
3096 prev->next = cur;
3097 cur->prev = prev;
3098 }
3099 while (cur->next != NULL) {
3100 cur->parent = parent;
3101 if (cur->doc != parent->doc) {
3102 xmlSetTreeDoc(cur, parent->doc);
3103 }
3104 cur = cur->next;
3105 }
3106 cur->parent = parent;
3107 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3108 parent->last = cur;
3109
3110 return(cur);
3111}
3112
3113/**
3114 * xmlAddChild:
3115 * @parent: the parent node
3116 * @cur: the child node
3117 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003118 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003119 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003120 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3121 * If there is an attribute with equal name, it is first destroyed.
3122 *
Owen Taylor3473f882001-02-23 17:55:21 +00003123 * Returns the child or NULL in case of error.
3124 */
3125xmlNodePtr
3126xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3127 xmlNodePtr prev;
3128
3129 if (parent == NULL) {
3130#ifdef DEBUG_TREE
3131 xmlGenericError(xmlGenericErrorContext,
3132 "xmlAddChild : parent == NULL\n");
3133#endif
3134 return(NULL);
3135 }
3136
3137 if (cur == NULL) {
3138#ifdef DEBUG_TREE
3139 xmlGenericError(xmlGenericErrorContext,
3140 "xmlAddChild : child == NULL\n");
3141#endif
3142 return(NULL);
3143 }
3144
Owen Taylor3473f882001-02-23 17:55:21 +00003145 /*
3146 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003147 * cur is then freed.
3148 */
3149 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003150 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003151 (parent->content != NULL) &&
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003152 (parent->name == cur->name) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003153 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003154 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003155 xmlFreeNode(cur);
3156 return(parent);
3157 }
3158 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003159 (parent->last->name == cur->name) &&
3160 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003161 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003162 xmlFreeNode(cur);
3163 return(parent->last);
3164 }
3165 }
3166
3167 /*
3168 * add the new element at the end of the children list.
3169 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003170 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003171 cur->parent = parent;
3172 if (cur->doc != parent->doc) {
3173 xmlSetTreeDoc(cur, parent->doc);
3174 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003175 /* this check prevents a loop on tree-traversions if a developer
3176 * tries to add a node to its parent multiple times
3177 */
3178 if (prev == parent)
3179 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003180
3181 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003182 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003183 */
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) &&
3186 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003187 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003188 xmlFreeNode(cur);
3189 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003190 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003191 if (cur->type == XML_ATTRIBUTE_NODE) {
3192 if (parent->properties == NULL) {
3193 parent->properties = (xmlAttrPtr) cur;
3194 } else {
3195 /* check if an attribute with the same name exists */
3196 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003197
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003198 if (cur->ns == NULL)
3199 lastattr = xmlHasProp(parent, cur->name);
3200 else
3201 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3202 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3203 /* different instance, destroy it (attributes must be unique) */
3204 xmlFreeProp(lastattr);
3205 }
3206 /* find the end */
3207 lastattr = parent->properties;
3208 while (lastattr->next != NULL) {
3209 lastattr = lastattr->next;
3210 }
3211 lastattr->next = (xmlAttrPtr) cur;
3212 ((xmlAttrPtr) cur)->prev = lastattr;
3213 }
3214 } else {
3215 if (parent->children == NULL) {
3216 parent->children = cur;
3217 parent->last = cur;
3218 } else {
3219 prev = parent->last;
3220 prev->next = cur;
3221 cur->prev = prev;
3222 parent->last = cur;
3223 }
3224 }
Owen Taylor3473f882001-02-23 17:55:21 +00003225 return(cur);
3226}
3227
3228/**
3229 * xmlGetLastChild:
3230 * @parent: the parent node
3231 *
3232 * Search the last child of a node.
3233 * Returns the last child or NULL if none.
3234 */
3235xmlNodePtr
3236xmlGetLastChild(xmlNodePtr parent) {
3237 if (parent == NULL) {
3238#ifdef DEBUG_TREE
3239 xmlGenericError(xmlGenericErrorContext,
3240 "xmlGetLastChild : parent == NULL\n");
3241#endif
3242 return(NULL);
3243 }
3244 return(parent->last);
3245}
3246
3247/**
3248 * xmlFreeNodeList:
3249 * @cur: the first node in the list
3250 *
3251 * Free a node and all its siblings, this is a recursive behaviour, all
3252 * the children are freed too.
3253 */
3254void
3255xmlFreeNodeList(xmlNodePtr cur) {
3256 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003257 xmlDictPtr dict = NULL;
3258
3259 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003260 if (cur->type == XML_NAMESPACE_DECL) {
3261 xmlFreeNsList((xmlNsPtr) cur);
3262 return;
3263 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003264 if ((cur->type == XML_DOCUMENT_NODE) ||
3265#ifdef LIBXML_DOCB_ENABLED
3266 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003267#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003268 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003269 xmlFreeDoc((xmlDocPtr) cur);
3270 return;
3271 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003272 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003273 while (cur != NULL) {
3274 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003275 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003276
Daniel Veillarda880b122003-04-21 21:36:41 +00003277 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003278 xmlDeregisterNodeDefaultValue(cur);
3279
Daniel Veillard02141ea2001-04-30 11:46:40 +00003280 if ((cur->children != NULL) &&
3281 (cur->type != XML_ENTITY_REF_NODE))
3282 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003283 if (((cur->type == XML_ELEMENT_NODE) ||
3284 (cur->type == XML_XINCLUDE_START) ||
3285 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003286 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003287 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003288 if ((cur->type != XML_ELEMENT_NODE) &&
3289 (cur->type != XML_XINCLUDE_START) &&
3290 (cur->type != XML_XINCLUDE_END) &&
3291 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003292 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003293 }
3294 if (((cur->type == XML_ELEMENT_NODE) ||
3295 (cur->type == XML_XINCLUDE_START) ||
3296 (cur->type == XML_XINCLUDE_END)) &&
3297 (cur->nsDef != NULL))
3298 xmlFreeNsList(cur->nsDef);
3299
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003300 /*
3301 * When a node is a text node or a comment, it uses a global static
3302 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003303 * Otherwise the node name might come from the document's
3304 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003305 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003306 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003307 (cur->type != XML_TEXT_NODE) &&
3308 (cur->type != XML_COMMENT_NODE))
3309 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003310 xmlFree(cur);
3311 }
Owen Taylor3473f882001-02-23 17:55:21 +00003312 cur = next;
3313 }
3314}
3315
3316/**
3317 * xmlFreeNode:
3318 * @cur: the node
3319 *
3320 * Free a node, this is a recursive behaviour, all the children are freed too.
3321 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3322 */
3323void
3324xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003325 xmlDictPtr dict = NULL;
3326
3327 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003328
Daniel Veillard02141ea2001-04-30 11:46:40 +00003329 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003330 if (cur->type == XML_DTD_NODE) {
3331 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003332 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003333 }
3334 if (cur->type == XML_NAMESPACE_DECL) {
3335 xmlFreeNs((xmlNsPtr) cur);
3336 return;
3337 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003338 if (cur->type == XML_ATTRIBUTE_NODE) {
3339 xmlFreeProp((xmlAttrPtr) cur);
3340 return;
3341 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003342
Daniel Veillarda880b122003-04-21 21:36:41 +00003343 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003344 xmlDeregisterNodeDefaultValue(cur);
3345
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003346 if (cur->doc != NULL) dict = cur->doc->dict;
3347
Owen Taylor3473f882001-02-23 17:55:21 +00003348 if ((cur->children != NULL) &&
3349 (cur->type != XML_ENTITY_REF_NODE))
3350 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003351 if (((cur->type == XML_ELEMENT_NODE) ||
3352 (cur->type == XML_XINCLUDE_START) ||
3353 (cur->type == XML_XINCLUDE_END)) &&
3354 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003355 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003356 if ((cur->type != XML_ELEMENT_NODE) &&
3357 (cur->content != NULL) &&
3358 (cur->type != XML_ENTITY_REF_NODE) &&
3359 (cur->type != XML_XINCLUDE_END) &&
3360 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003361 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003362 }
3363
Daniel Veillardacd370f2001-06-09 17:17:51 +00003364 /*
3365 * When a node is a text node or a comment, it uses a global static
3366 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003367 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003368 */
Owen Taylor3473f882001-02-23 17:55:21 +00003369 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003370 (cur->type != XML_TEXT_NODE) &&
3371 (cur->type != XML_COMMENT_NODE))
3372 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003373
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003374 if (((cur->type == XML_ELEMENT_NODE) ||
3375 (cur->type == XML_XINCLUDE_START) ||
3376 (cur->type == XML_XINCLUDE_END)) &&
3377 (cur->nsDef != NULL))
3378 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003379 xmlFree(cur);
3380}
3381
3382/**
3383 * xmlUnlinkNode:
3384 * @cur: the node
3385 *
3386 * Unlink a node from it's current context, the node is not freed
3387 */
3388void
3389xmlUnlinkNode(xmlNodePtr cur) {
3390 if (cur == NULL) {
3391#ifdef DEBUG_TREE
3392 xmlGenericError(xmlGenericErrorContext,
3393 "xmlUnlinkNode : node == NULL\n");
3394#endif
3395 return;
3396 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003397 if (cur->type == XML_DTD_NODE) {
3398 xmlDocPtr doc;
3399 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003400 if (doc != NULL) {
3401 if (doc->intSubset == (xmlDtdPtr) cur)
3402 doc->intSubset = NULL;
3403 if (doc->extSubset == (xmlDtdPtr) cur)
3404 doc->extSubset = NULL;
3405 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003406 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003407 if (cur->parent != NULL) {
3408 xmlNodePtr parent;
3409 parent = cur->parent;
3410 if (cur->type == XML_ATTRIBUTE_NODE) {
3411 if (parent->properties == (xmlAttrPtr) cur)
3412 parent->properties = ((xmlAttrPtr) cur)->next;
3413 } else {
3414 if (parent->children == cur)
3415 parent->children = cur->next;
3416 if (parent->last == cur)
3417 parent->last = cur->prev;
3418 }
3419 cur->parent = NULL;
3420 }
Owen Taylor3473f882001-02-23 17:55:21 +00003421 if (cur->next != NULL)
3422 cur->next->prev = cur->prev;
3423 if (cur->prev != NULL)
3424 cur->prev->next = cur->next;
3425 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003426}
3427
Daniel Veillard2156d432004-03-04 15:59:36 +00003428#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003429/**
3430 * xmlReplaceNode:
3431 * @old: the old node
3432 * @cur: the node
3433 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003434 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003435 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003436 * first unlinked from its existing context.
3437 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003438 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003439 */
3440xmlNodePtr
3441xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00003442 if (old == cur) return(NULL);
Daniel Veillarda03e3652004-11-02 18:45:30 +00003443 if ((old == NULL) || (old->parent == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003444#ifdef DEBUG_TREE
3445 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda03e3652004-11-02 18:45:30 +00003446 "xmlReplaceNode : old == NULL or without parent\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003447#endif
3448 return(NULL);
3449 }
3450 if (cur == NULL) {
3451 xmlUnlinkNode(old);
3452 return(old);
3453 }
3454 if (cur == old) {
3455 return(old);
3456 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003457 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3458#ifdef DEBUG_TREE
3459 xmlGenericError(xmlGenericErrorContext,
3460 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3461#endif
3462 return(old);
3463 }
3464 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3465#ifdef DEBUG_TREE
3466 xmlGenericError(xmlGenericErrorContext,
3467 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3468#endif
3469 return(old);
3470 }
Owen Taylor3473f882001-02-23 17:55:21 +00003471 xmlUnlinkNode(cur);
3472 cur->doc = old->doc;
3473 cur->parent = old->parent;
3474 cur->next = old->next;
3475 if (cur->next != NULL)
3476 cur->next->prev = cur;
3477 cur->prev = old->prev;
3478 if (cur->prev != NULL)
3479 cur->prev->next = cur;
3480 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003481 if (cur->type == XML_ATTRIBUTE_NODE) {
3482 if (cur->parent->properties == (xmlAttrPtr)old)
3483 cur->parent->properties = ((xmlAttrPtr) cur);
3484 } else {
3485 if (cur->parent->children == old)
3486 cur->parent->children = cur;
3487 if (cur->parent->last == old)
3488 cur->parent->last = cur;
3489 }
Owen Taylor3473f882001-02-23 17:55:21 +00003490 }
3491 old->next = old->prev = NULL;
3492 old->parent = NULL;
3493 return(old);
3494}
Daniel Veillard652327a2003-09-29 18:02:38 +00003495#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003496
3497/************************************************************************
3498 * *
3499 * Copy operations *
3500 * *
3501 ************************************************************************/
3502
3503/**
3504 * xmlCopyNamespace:
3505 * @cur: the namespace
3506 *
3507 * Do a copy of the namespace.
3508 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003509 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003510 */
3511xmlNsPtr
3512xmlCopyNamespace(xmlNsPtr cur) {
3513 xmlNsPtr ret;
3514
3515 if (cur == NULL) return(NULL);
3516 switch (cur->type) {
3517 case XML_LOCAL_NAMESPACE:
3518 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3519 break;
3520 default:
3521#ifdef DEBUG_TREE
3522 xmlGenericError(xmlGenericErrorContext,
3523 "xmlCopyNamespace: invalid type %d\n", cur->type);
3524#endif
3525 return(NULL);
3526 }
3527 return(ret);
3528}
3529
3530/**
3531 * xmlCopyNamespaceList:
3532 * @cur: the first namespace
3533 *
3534 * Do a copy of an namespace list.
3535 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003536 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003537 */
3538xmlNsPtr
3539xmlCopyNamespaceList(xmlNsPtr cur) {
3540 xmlNsPtr ret = NULL;
3541 xmlNsPtr p = NULL,q;
3542
3543 while (cur != NULL) {
3544 q = xmlCopyNamespace(cur);
3545 if (p == NULL) {
3546 ret = p = q;
3547 } else {
3548 p->next = q;
3549 p = q;
3550 }
3551 cur = cur->next;
3552 }
3553 return(ret);
3554}
3555
3556static xmlNodePtr
3557xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3558/**
3559 * xmlCopyProp:
3560 * @target: the element where the attribute will be grafted
3561 * @cur: the attribute
3562 *
3563 * Do a copy of the attribute.
3564 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003565 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003566 */
3567xmlAttrPtr
3568xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3569 xmlAttrPtr ret;
3570
3571 if (cur == NULL) return(NULL);
3572 if (target != NULL)
3573 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3574 else if (cur->parent != NULL)
3575 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3576 else if (cur->children != NULL)
3577 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3578 else
3579 ret = xmlNewDocProp(NULL, cur->name, NULL);
3580 if (ret == NULL) return(NULL);
3581 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003582
Owen Taylor3473f882001-02-23 17:55:21 +00003583 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003584 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003585
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003586 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3587 if (ns == NULL) {
3588 /*
3589 * Humm, we are copying an element whose namespace is defined
3590 * out of the new tree scope. Search it in the original tree
3591 * and add it at the top of the new tree
3592 */
3593 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3594 if (ns != NULL) {
3595 xmlNodePtr root = target;
3596 xmlNodePtr pred = NULL;
3597
3598 while (root->parent != NULL) {
3599 pred = root;
3600 root = root->parent;
3601 }
3602 if (root == (xmlNodePtr) target->doc) {
3603 /* correct possibly cycling above the document elt */
3604 root = pred;
3605 }
3606 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3607 }
3608 } else {
3609 /*
3610 * we have to find something appropriate here since
3611 * we cant be sure, that the namespce we found is identified
3612 * by the prefix
3613 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003614 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003615 /* this is the nice case */
3616 ret->ns = ns;
3617 } else {
3618 /*
3619 * we are in trouble: we need a new reconcilied namespace.
3620 * This is expensive
3621 */
3622 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3623 }
3624 }
3625
Owen Taylor3473f882001-02-23 17:55:21 +00003626 } else
3627 ret->ns = NULL;
3628
3629 if (cur->children != NULL) {
3630 xmlNodePtr tmp;
3631
3632 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3633 ret->last = NULL;
3634 tmp = ret->children;
3635 while (tmp != NULL) {
3636 /* tmp->parent = (xmlNodePtr)ret; */
3637 if (tmp->next == NULL)
3638 ret->last = tmp;
3639 tmp = tmp->next;
3640 }
3641 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003642 /*
3643 * Try to handle IDs
3644 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003645 if ((target!= NULL) && (cur!= NULL) &&
3646 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003647 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3648 if (xmlIsID(cur->doc, cur->parent, cur)) {
3649 xmlChar *id;
3650
3651 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3652 if (id != NULL) {
3653 xmlAddID(NULL, target->doc, id, ret);
3654 xmlFree(id);
3655 }
3656 }
3657 }
Owen Taylor3473f882001-02-23 17:55:21 +00003658 return(ret);
3659}
3660
3661/**
3662 * xmlCopyPropList:
3663 * @target: the element where the attributes will be grafted
3664 * @cur: the first attribute
3665 *
3666 * Do a copy of an attribute list.
3667 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003668 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003669 */
3670xmlAttrPtr
3671xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3672 xmlAttrPtr ret = NULL;
3673 xmlAttrPtr p = NULL,q;
3674
3675 while (cur != NULL) {
3676 q = xmlCopyProp(target, cur);
William M. Brack13dfa872004-09-18 04:52:08 +00003677 if (q == NULL)
3678 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003679 if (p == NULL) {
3680 ret = p = q;
3681 } else {
3682 p->next = q;
3683 q->prev = p;
3684 p = q;
3685 }
3686 cur = cur->next;
3687 }
3688 return(ret);
3689}
3690
3691/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003692 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003693 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003694 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003695 * tricky reason: namespaces. Doing a direct copy of a node
3696 * say RPM:Copyright without changing the namespace pointer to
3697 * something else can produce stale links. One way to do it is
3698 * to keep a reference counter but this doesn't work as soon
3699 * as one move the element or the subtree out of the scope of
3700 * the existing namespace. The actual solution seems to add
3701 * a copy of the namespace at the top of the copied tree if
3702 * not available in the subtree.
3703 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00003704 * The argument "recursive" normally indicates a recursive copy
3705 * of the node with values 0 (no) and 1 (yes). For XInclude,
3706 * however, we allow a value of 2 to indicate copy properties and
3707 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00003708 */
3709
3710static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003711xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00003712 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003713 xmlNodePtr ret;
3714
3715 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003716 switch (node->type) {
3717 case XML_TEXT_NODE:
3718 case XML_CDATA_SECTION_NODE:
3719 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003720 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003721 case XML_ENTITY_REF_NODE:
3722 case XML_ENTITY_NODE:
3723 case XML_PI_NODE:
3724 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003725 case XML_XINCLUDE_START:
3726 case XML_XINCLUDE_END:
3727 break;
3728 case XML_ATTRIBUTE_NODE:
3729 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3730 case XML_NAMESPACE_DECL:
3731 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3732
Daniel Veillard39196eb2001-06-19 18:09:42 +00003733 case XML_DOCUMENT_NODE:
3734 case XML_HTML_DOCUMENT_NODE:
3735#ifdef LIBXML_DOCB_ENABLED
3736 case XML_DOCB_DOCUMENT_NODE:
3737#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003738#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00003739 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00003740#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003741 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003742 case XML_NOTATION_NODE:
3743 case XML_DTD_NODE:
3744 case XML_ELEMENT_DECL:
3745 case XML_ATTRIBUTE_DECL:
3746 case XML_ENTITY_DECL:
3747 return(NULL);
3748 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003749
Owen Taylor3473f882001-02-23 17:55:21 +00003750 /*
3751 * Allocate a new node and fill the fields.
3752 */
3753 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3754 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003755 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003756 return(NULL);
3757 }
3758 memset(ret, 0, sizeof(xmlNode));
3759 ret->type = node->type;
3760
3761 ret->doc = doc;
3762 ret->parent = parent;
3763 if (node->name == xmlStringText)
3764 ret->name = xmlStringText;
3765 else if (node->name == xmlStringTextNoenc)
3766 ret->name = xmlStringTextNoenc;
3767 else if (node->name == xmlStringComment)
3768 ret->name = xmlStringComment;
Daniel Veillard03a53c32004-10-26 16:06:51 +00003769 else if (node->name != NULL) {
3770 if ((doc != NULL) && (doc->dict != NULL))
3771 ret->name = xmlDictLookup(doc->dict, node->name, -1);
3772 else
3773 ret->name = xmlStrdup(node->name);
3774 }
Daniel Veillard7db37732001-07-12 01:20:08 +00003775 if ((node->type != XML_ELEMENT_NODE) &&
3776 (node->content != NULL) &&
3777 (node->type != XML_ENTITY_REF_NODE) &&
3778 (node->type != XML_XINCLUDE_END) &&
3779 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003780 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003781 }else{
3782 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003783 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003784 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003785 if (parent != NULL) {
3786 xmlNodePtr tmp;
3787
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003788 /*
3789 * this is a tricky part for the node register thing:
3790 * in case ret does get coalesced in xmlAddChild
3791 * the deregister-node callback is called; so we register ret now already
3792 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003793 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003794 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3795
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003796 tmp = xmlAddChild(parent, ret);
3797 /* node could have coalesced */
3798 if (tmp != ret)
3799 return(tmp);
3800 }
Owen Taylor3473f882001-02-23 17:55:21 +00003801
William M. Brack57e9e912004-03-09 16:19:02 +00003802 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003803 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003804 if (node->nsDef != NULL)
3805 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3806
3807 if (node->ns != NULL) {
3808 xmlNsPtr ns;
3809
3810 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3811 if (ns == NULL) {
3812 /*
3813 * Humm, we are copying an element whose namespace is defined
3814 * out of the new tree scope. Search it in the original tree
3815 * and add it at the top of the new tree
3816 */
3817 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3818 if (ns != NULL) {
3819 xmlNodePtr root = ret;
3820
3821 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003822 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003823 }
3824 } else {
3825 /*
3826 * reference the existing namespace definition in our own tree.
3827 */
3828 ret->ns = ns;
3829 }
3830 }
3831 if (node->properties != NULL)
3832 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003833 if (node->type == XML_ENTITY_REF_NODE) {
3834 if ((doc == NULL) || (node->doc != doc)) {
3835 /*
3836 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003837 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003838 * we cannot keep the reference. Try to find it in the
3839 * target document.
3840 */
3841 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3842 } else {
3843 ret->children = node->children;
3844 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003845 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00003846 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003847 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003848 UPDATE_LAST_CHILD_AND_PARENT(ret)
3849 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003850
3851out:
3852 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00003853 if ((parent == NULL) &&
3854 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003855 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003856 return(ret);
3857}
3858
3859static xmlNodePtr
3860xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3861 xmlNodePtr ret = NULL;
3862 xmlNodePtr p = NULL,q;
3863
3864 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003865#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003866 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003867 if (doc == NULL) {
3868 node = node->next;
3869 continue;
3870 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003871 if (doc->intSubset == NULL) {
3872 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3873 q->doc = doc;
3874 q->parent = parent;
3875 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003876 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003877 } else {
3878 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003879 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003880 }
3881 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003882#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003883 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003884 if (ret == NULL) {
3885 q->prev = NULL;
3886 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003887 } else if (p != q) {
3888 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003889 p->next = q;
3890 q->prev = p;
3891 p = q;
3892 }
3893 node = node->next;
3894 }
3895 return(ret);
3896}
3897
3898/**
3899 * xmlCopyNode:
3900 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00003901 * @extended: if 1 do a recursive copy (properties, namespaces and children
3902 * when applicable)
3903 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00003904 *
3905 * Do a copy of the node.
3906 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003907 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003908 */
3909xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003910xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003911 xmlNodePtr ret;
3912
William M. Brack57e9e912004-03-09 16:19:02 +00003913 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00003914 return(ret);
3915}
3916
3917/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003918 * xmlDocCopyNode:
3919 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003920 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00003921 * @extended: if 1 do a recursive copy (properties, namespaces and children
3922 * when applicable)
3923 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00003924 *
3925 * Do a copy of the node to a given document.
3926 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003927 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003928 */
3929xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003930xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003931 xmlNodePtr ret;
3932
William M. Brack57e9e912004-03-09 16:19:02 +00003933 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00003934 return(ret);
3935}
3936
3937/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00003938 * xmlDocCopyNodeList:
3939 * @doc: the target document
3940 * @node: the first node in the list.
3941 *
3942 * Do a recursive copy of the node list.
3943 *
3944 * Returns: a new #xmlNodePtr, or NULL in case of error.
3945 */
3946xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) {
3947 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
3948 return(ret);
3949}
3950
3951/**
Owen Taylor3473f882001-02-23 17:55:21 +00003952 * xmlCopyNodeList:
3953 * @node: the first node in the list.
3954 *
3955 * Do a recursive copy of the node list.
Daniel Veillard03a53c32004-10-26 16:06:51 +00003956 * Use xmlDocCopyNodeList() if possible to ensure string interning.
Owen Taylor3473f882001-02-23 17:55:21 +00003957 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003958 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003959 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003960xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003961 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3962 return(ret);
3963}
3964
Daniel Veillard2156d432004-03-04 15:59:36 +00003965#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003966/**
Owen Taylor3473f882001-02-23 17:55:21 +00003967 * xmlCopyDtd:
3968 * @dtd: the dtd
3969 *
3970 * Do a copy of the dtd.
3971 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003972 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003973 */
3974xmlDtdPtr
3975xmlCopyDtd(xmlDtdPtr dtd) {
3976 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003977 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003978
3979 if (dtd == NULL) return(NULL);
3980 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3981 if (ret == NULL) return(NULL);
3982 if (dtd->entities != NULL)
3983 ret->entities = (void *) xmlCopyEntitiesTable(
3984 (xmlEntitiesTablePtr) dtd->entities);
3985 if (dtd->notations != NULL)
3986 ret->notations = (void *) xmlCopyNotationTable(
3987 (xmlNotationTablePtr) dtd->notations);
3988 if (dtd->elements != NULL)
3989 ret->elements = (void *) xmlCopyElementTable(
3990 (xmlElementTablePtr) dtd->elements);
3991 if (dtd->attributes != NULL)
3992 ret->attributes = (void *) xmlCopyAttributeTable(
3993 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003994 if (dtd->pentities != NULL)
3995 ret->pentities = (void *) xmlCopyEntitiesTable(
3996 (xmlEntitiesTablePtr) dtd->pentities);
3997
3998 cur = dtd->children;
3999 while (cur != NULL) {
4000 q = NULL;
4001
4002 if (cur->type == XML_ENTITY_DECL) {
4003 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4004 switch (tmp->etype) {
4005 case XML_INTERNAL_GENERAL_ENTITY:
4006 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4007 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4008 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4009 break;
4010 case XML_INTERNAL_PARAMETER_ENTITY:
4011 case XML_EXTERNAL_PARAMETER_ENTITY:
4012 q = (xmlNodePtr)
4013 xmlGetParameterEntityFromDtd(ret, tmp->name);
4014 break;
4015 case XML_INTERNAL_PREDEFINED_ENTITY:
4016 break;
4017 }
4018 } else if (cur->type == XML_ELEMENT_DECL) {
4019 xmlElementPtr tmp = (xmlElementPtr) cur;
4020 q = (xmlNodePtr)
4021 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4022 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4023 xmlAttributePtr tmp = (xmlAttributePtr) cur;
4024 q = (xmlNodePtr)
4025 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4026 } else if (cur->type == XML_COMMENT_NODE) {
4027 q = xmlCopyNode(cur, 0);
4028 }
4029
4030 if (q == NULL) {
4031 cur = cur->next;
4032 continue;
4033 }
4034
4035 if (p == NULL)
4036 ret->children = q;
4037 else
4038 p->next = q;
4039
4040 q->prev = p;
4041 q->parent = (xmlNodePtr) ret;
4042 q->next = NULL;
4043 ret->last = q;
4044 p = q;
4045 cur = cur->next;
4046 }
4047
Owen Taylor3473f882001-02-23 17:55:21 +00004048 return(ret);
4049}
Daniel Veillard2156d432004-03-04 15:59:36 +00004050#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004051
Daniel Veillard2156d432004-03-04 15:59:36 +00004052#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004053/**
4054 * xmlCopyDoc:
4055 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004056 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004057 *
4058 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004059 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004060 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004061 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004062 */
4063xmlDocPtr
4064xmlCopyDoc(xmlDocPtr doc, int recursive) {
4065 xmlDocPtr ret;
4066
4067 if (doc == NULL) return(NULL);
4068 ret = xmlNewDoc(doc->version);
4069 if (ret == NULL) return(NULL);
4070 if (doc->name != NULL)
4071 ret->name = xmlMemStrdup(doc->name);
4072 if (doc->encoding != NULL)
4073 ret->encoding = xmlStrdup(doc->encoding);
Daniel Veillardf59507d2005-01-27 17:26:49 +00004074 if (doc->URL != NULL)
4075 ret->URL = xmlStrdup(doc->URL);
Owen Taylor3473f882001-02-23 17:55:21 +00004076 ret->charset = doc->charset;
4077 ret->compression = doc->compression;
4078 ret->standalone = doc->standalone;
4079 if (!recursive) return(ret);
4080
Daniel Veillardb33c2012001-04-25 12:59:04 +00004081 ret->last = NULL;
4082 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004083#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004084 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004085 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004086 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004087 ret->intSubset->parent = ret;
4088 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004089#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004090 if (doc->oldNs != NULL)
4091 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4092 if (doc->children != NULL) {
4093 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004094
4095 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4096 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004097 ret->last = NULL;
4098 tmp = ret->children;
4099 while (tmp != NULL) {
4100 if (tmp->next == NULL)
4101 ret->last = tmp;
4102 tmp = tmp->next;
4103 }
4104 }
4105 return(ret);
4106}
Daniel Veillard652327a2003-09-29 18:02:38 +00004107#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004108
4109/************************************************************************
4110 * *
4111 * Content access functions *
4112 * *
4113 ************************************************************************/
4114
4115/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004116 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004117 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004118 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004119 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004120 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004121 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004122 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004123 */
4124long
4125xmlGetLineNo(xmlNodePtr node)
4126{
4127 long result = -1;
4128
4129 if (!node)
4130 return result;
4131 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004132 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004133 else if ((node->prev != NULL) &&
4134 ((node->prev->type == XML_ELEMENT_NODE) ||
4135 (node->prev->type == XML_TEXT_NODE)))
4136 result = xmlGetLineNo(node->prev);
4137 else if ((node->parent != NULL) &&
4138 ((node->parent->type == XML_ELEMENT_NODE) ||
4139 (node->parent->type == XML_TEXT_NODE)))
4140 result = xmlGetLineNo(node->parent);
4141
4142 return result;
4143}
4144
Daniel Veillard2156d432004-03-04 15:59:36 +00004145#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004146/**
4147 * xmlGetNodePath:
4148 * @node: a node
4149 *
4150 * Build a structure based Path for the given node
4151 *
4152 * Returns the new path or NULL in case of error. The caller must free
4153 * the returned string
4154 */
4155xmlChar *
4156xmlGetNodePath(xmlNodePtr node)
4157{
4158 xmlNodePtr cur, tmp, next;
4159 xmlChar *buffer = NULL, *temp;
4160 size_t buf_len;
4161 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004162 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004163 const char *name;
4164 char nametemp[100];
4165 int occur = 0;
4166
4167 if (node == NULL)
4168 return (NULL);
4169
4170 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004171 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004172 if (buffer == NULL) {
4173 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004174 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004175 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004176 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004177 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004178 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004179 xmlFree(buffer);
4180 return (NULL);
4181 }
4182
4183 buffer[0] = 0;
4184 cur = node;
4185 do {
4186 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004187 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004188 occur = 0;
4189 if ((cur->type == XML_DOCUMENT_NODE) ||
4190 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4191 if (buffer[0] == '/')
4192 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004193 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004194 next = NULL;
4195 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004196 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004197 name = (const char *) cur->name;
4198 if (cur->ns) {
William M. Brack84d83e32003-12-23 03:45:17 +00004199 if (cur->ns->prefix != NULL)
William M. Brack13dfa872004-09-18 04:52:08 +00004200 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4201 (char *)cur->ns->prefix, (char *)cur->name);
William M. Brack84d83e32003-12-23 03:45:17 +00004202 else
William M. Brack13dfa872004-09-18 04:52:08 +00004203 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4204 (char *)cur->name);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004205 nametemp[sizeof(nametemp) - 1] = 0;
4206 name = nametemp;
4207 }
4208 next = cur->parent;
4209
4210 /*
4211 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004212 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004213 */
4214 tmp = cur->prev;
4215 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004216 if ((tmp->type == XML_ELEMENT_NODE) &&
Daniel Veillard0996a162005-02-05 14:00:10 +00004217 (xmlStrEqual(cur->name, tmp->name)) &&
4218 ((tmp->ns == cur->ns) ||
4219 ((tmp->ns != NULL) && (cur->ns != NULL) &&
4220 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004221 occur++;
4222 tmp = tmp->prev;
4223 }
4224 if (occur == 0) {
4225 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004226 while (tmp != NULL && occur == 0) {
4227 if ((tmp->type == XML_ELEMENT_NODE) &&
Daniel Veillard0996a162005-02-05 14:00:10 +00004228 (xmlStrEqual(cur->name, tmp->name)) &&
4229 ((tmp->ns == cur->ns) ||
4230 ((tmp->ns != NULL) && (cur->ns != NULL) &&
4231 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004232 occur++;
4233 tmp = tmp->next;
4234 }
4235 if (occur != 0)
4236 occur = 1;
4237 } else
4238 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004239 } else if (cur->type == XML_COMMENT_NODE) {
4240 sep = "/";
4241 name = "comment()";
4242 next = cur->parent;
4243
4244 /*
4245 * Thumbler index computation
4246 */
4247 tmp = cur->prev;
4248 while (tmp != NULL) {
4249 if (tmp->type == XML_COMMENT_NODE)
4250 occur++;
4251 tmp = tmp->prev;
4252 }
4253 if (occur == 0) {
4254 tmp = cur->next;
4255 while (tmp != NULL && occur == 0) {
4256 if (tmp->type == XML_COMMENT_NODE)
4257 occur++;
4258 tmp = tmp->next;
4259 }
4260 if (occur != 0)
4261 occur = 1;
4262 } else
4263 occur++;
4264 } else if ((cur->type == XML_TEXT_NODE) ||
4265 (cur->type == XML_CDATA_SECTION_NODE)) {
4266 sep = "/";
4267 name = "text()";
4268 next = cur->parent;
4269
4270 /*
4271 * Thumbler index computation
4272 */
4273 tmp = cur->prev;
4274 while (tmp != NULL) {
4275 if ((cur->type == XML_TEXT_NODE) ||
4276 (cur->type == XML_CDATA_SECTION_NODE))
4277 occur++;
4278 tmp = tmp->prev;
4279 }
4280 if (occur == 0) {
4281 tmp = cur->next;
4282 while (tmp != NULL && occur == 0) {
Daniel Veillard1f8658a2004-08-14 21:46:31 +00004283 if ((tmp->type == XML_TEXT_NODE) ||
4284 (tmp->type == XML_CDATA_SECTION_NODE))
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004285 occur++;
4286 tmp = tmp->next;
4287 }
4288 if (occur != 0)
4289 occur = 1;
4290 } else
4291 occur++;
4292 } else if (cur->type == XML_PI_NODE) {
4293 sep = "/";
4294 snprintf(nametemp, sizeof(nametemp) - 1,
William M. Brack13dfa872004-09-18 04:52:08 +00004295 "processing-instruction('%s')", (char *)cur->name);
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004296 nametemp[sizeof(nametemp) - 1] = 0;
4297 name = nametemp;
4298
4299 next = cur->parent;
4300
4301 /*
4302 * Thumbler index computation
4303 */
4304 tmp = cur->prev;
4305 while (tmp != NULL) {
4306 if ((tmp->type == XML_PI_NODE) &&
4307 (xmlStrEqual(cur->name, tmp->name)))
4308 occur++;
4309 tmp = tmp->prev;
4310 }
4311 if (occur == 0) {
4312 tmp = cur->next;
4313 while (tmp != NULL && occur == 0) {
4314 if ((tmp->type == XML_PI_NODE) &&
4315 (xmlStrEqual(cur->name, tmp->name)))
4316 occur++;
4317 tmp = tmp->next;
4318 }
4319 if (occur != 0)
4320 occur = 1;
4321 } else
4322 occur++;
4323
Daniel Veillard8faa7832001-11-26 15:58:08 +00004324 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004325 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004326 name = (const char *) (((xmlAttrPtr) cur)->name);
4327 next = ((xmlAttrPtr) cur)->parent;
4328 } else {
4329 next = cur->parent;
4330 }
4331
4332 /*
4333 * Make sure there is enough room
4334 */
4335 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4336 buf_len =
4337 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4338 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4339 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004340 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004341 xmlFree(buf);
4342 xmlFree(buffer);
4343 return (NULL);
4344 }
4345 buffer = temp;
4346 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4347 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004348 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004349 xmlFree(buf);
4350 xmlFree(buffer);
4351 return (NULL);
4352 }
4353 buf = temp;
4354 }
4355 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004356 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004357 sep, name, (char *) buffer);
4358 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004359 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004360 sep, name, occur, (char *) buffer);
William M. Brack13dfa872004-09-18 04:52:08 +00004361 snprintf((char *) buffer, buf_len, "%s", (char *)buf);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004362 cur = next;
4363 } while (cur != NULL);
4364 xmlFree(buf);
4365 return (buffer);
4366}
Daniel Veillard652327a2003-09-29 18:02:38 +00004367#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004368
4369/**
Owen Taylor3473f882001-02-23 17:55:21 +00004370 * xmlDocGetRootElement:
4371 * @doc: the document
4372 *
4373 * Get the root element of the document (doc->children is a list
4374 * containing possibly comments, PIs, etc ...).
4375 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004376 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004377 */
4378xmlNodePtr
4379xmlDocGetRootElement(xmlDocPtr doc) {
4380 xmlNodePtr ret;
4381
4382 if (doc == NULL) return(NULL);
4383 ret = doc->children;
4384 while (ret != NULL) {
4385 if (ret->type == XML_ELEMENT_NODE)
4386 return(ret);
4387 ret = ret->next;
4388 }
4389 return(ret);
4390}
4391
Daniel Veillard2156d432004-03-04 15:59:36 +00004392#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004393/**
4394 * xmlDocSetRootElement:
4395 * @doc: the document
4396 * @root: the new document root element
4397 *
4398 * Set the root element of the document (doc->children is a list
4399 * containing possibly comments, PIs, etc ...).
4400 *
4401 * Returns the old root element if any was found
4402 */
4403xmlNodePtr
4404xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4405 xmlNodePtr old = NULL;
4406
4407 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004408 if (root == NULL)
4409 return(NULL);
4410 xmlUnlinkNode(root);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00004411 xmlSetTreeDoc(root, doc);
Daniel Veillardc575b992002-02-08 13:28:40 +00004412 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004413 old = doc->children;
4414 while (old != NULL) {
4415 if (old->type == XML_ELEMENT_NODE)
4416 break;
4417 old = old->next;
4418 }
4419 if (old == NULL) {
4420 if (doc->children == NULL) {
4421 doc->children = root;
4422 doc->last = root;
4423 } else {
4424 xmlAddSibling(doc->children, root);
4425 }
4426 } else {
4427 xmlReplaceNode(old, root);
4428 }
4429 return(old);
4430}
Daniel Veillard2156d432004-03-04 15:59:36 +00004431#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004432
Daniel Veillard2156d432004-03-04 15:59:36 +00004433#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004434/**
4435 * xmlNodeSetLang:
4436 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004437 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004438 *
4439 * Set the language of a node, i.e. the values of the xml:lang
4440 * attribute.
4441 */
4442void
4443xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004444 xmlNsPtr ns;
4445
Owen Taylor3473f882001-02-23 17:55:21 +00004446 if (cur == NULL) return;
4447 switch(cur->type) {
4448 case XML_TEXT_NODE:
4449 case XML_CDATA_SECTION_NODE:
4450 case XML_COMMENT_NODE:
4451 case XML_DOCUMENT_NODE:
4452 case XML_DOCUMENT_TYPE_NODE:
4453 case XML_DOCUMENT_FRAG_NODE:
4454 case XML_NOTATION_NODE:
4455 case XML_HTML_DOCUMENT_NODE:
4456 case XML_DTD_NODE:
4457 case XML_ELEMENT_DECL:
4458 case XML_ATTRIBUTE_DECL:
4459 case XML_ENTITY_DECL:
4460 case XML_PI_NODE:
4461 case XML_ENTITY_REF_NODE:
4462 case XML_ENTITY_NODE:
4463 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004464#ifdef LIBXML_DOCB_ENABLED
4465 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004466#endif
4467 case XML_XINCLUDE_START:
4468 case XML_XINCLUDE_END:
4469 return;
4470 case XML_ELEMENT_NODE:
4471 case XML_ATTRIBUTE_NODE:
4472 break;
4473 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004474 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4475 if (ns == NULL)
4476 return;
4477 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004478}
Daniel Veillard652327a2003-09-29 18:02:38 +00004479#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004480
4481/**
4482 * xmlNodeGetLang:
4483 * @cur: the node being checked
4484 *
4485 * Searches the language of a node, i.e. the values of the xml:lang
4486 * attribute or the one carried by the nearest ancestor.
4487 *
4488 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004489 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004490 */
4491xmlChar *
4492xmlNodeGetLang(xmlNodePtr cur) {
4493 xmlChar *lang;
4494
4495 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004496 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004497 if (lang != NULL)
4498 return(lang);
4499 cur = cur->parent;
4500 }
4501 return(NULL);
4502}
4503
4504
Daniel Veillard652327a2003-09-29 18:02:38 +00004505#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004506/**
4507 * xmlNodeSetSpacePreserve:
4508 * @cur: the node being changed
4509 * @val: the xml:space value ("0": default, 1: "preserve")
4510 *
4511 * Set (or reset) the space preserving behaviour of a node, i.e. the
4512 * value of the xml:space attribute.
4513 */
4514void
4515xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004516 xmlNsPtr ns;
4517
Owen Taylor3473f882001-02-23 17:55:21 +00004518 if (cur == NULL) return;
4519 switch(cur->type) {
4520 case XML_TEXT_NODE:
4521 case XML_CDATA_SECTION_NODE:
4522 case XML_COMMENT_NODE:
4523 case XML_DOCUMENT_NODE:
4524 case XML_DOCUMENT_TYPE_NODE:
4525 case XML_DOCUMENT_FRAG_NODE:
4526 case XML_NOTATION_NODE:
4527 case XML_HTML_DOCUMENT_NODE:
4528 case XML_DTD_NODE:
4529 case XML_ELEMENT_DECL:
4530 case XML_ATTRIBUTE_DECL:
4531 case XML_ENTITY_DECL:
4532 case XML_PI_NODE:
4533 case XML_ENTITY_REF_NODE:
4534 case XML_ENTITY_NODE:
4535 case XML_NAMESPACE_DECL:
4536 case XML_XINCLUDE_START:
4537 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004538#ifdef LIBXML_DOCB_ENABLED
4539 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004540#endif
4541 return;
4542 case XML_ELEMENT_NODE:
4543 case XML_ATTRIBUTE_NODE:
4544 break;
4545 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004546 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4547 if (ns == NULL)
4548 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004549 switch (val) {
4550 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004551 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004552 break;
4553 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004554 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004555 break;
4556 }
4557}
Daniel Veillard652327a2003-09-29 18:02:38 +00004558#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004559
4560/**
4561 * xmlNodeGetSpacePreserve:
4562 * @cur: the node being checked
4563 *
4564 * Searches the space preserving behaviour of a node, i.e. the values
4565 * of the xml:space attribute or the one carried by the nearest
4566 * ancestor.
4567 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004568 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004569 */
4570int
4571xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4572 xmlChar *space;
4573
4574 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004575 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004576 if (space != NULL) {
4577 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4578 xmlFree(space);
4579 return(1);
4580 }
4581 if (xmlStrEqual(space, BAD_CAST "default")) {
4582 xmlFree(space);
4583 return(0);
4584 }
4585 xmlFree(space);
4586 }
4587 cur = cur->parent;
4588 }
4589 return(-1);
4590}
4591
Daniel Veillard652327a2003-09-29 18:02:38 +00004592#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004593/**
4594 * xmlNodeSetName:
4595 * @cur: the node being changed
4596 * @name: the new tag name
4597 *
4598 * Set (or reset) the name of a node.
4599 */
4600void
4601xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00004602 xmlDocPtr doc;
4603 xmlDictPtr dict;
4604
Owen Taylor3473f882001-02-23 17:55:21 +00004605 if (cur == NULL) return;
4606 if (name == NULL) return;
4607 switch(cur->type) {
4608 case XML_TEXT_NODE:
4609 case XML_CDATA_SECTION_NODE:
4610 case XML_COMMENT_NODE:
4611 case XML_DOCUMENT_TYPE_NODE:
4612 case XML_DOCUMENT_FRAG_NODE:
4613 case XML_NOTATION_NODE:
4614 case XML_HTML_DOCUMENT_NODE:
4615 case XML_NAMESPACE_DECL:
4616 case XML_XINCLUDE_START:
4617 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004618#ifdef LIBXML_DOCB_ENABLED
4619 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004620#endif
4621 return;
4622 case XML_ELEMENT_NODE:
4623 case XML_ATTRIBUTE_NODE:
4624 case XML_PI_NODE:
4625 case XML_ENTITY_REF_NODE:
4626 case XML_ENTITY_NODE:
4627 case XML_DTD_NODE:
4628 case XML_DOCUMENT_NODE:
4629 case XML_ELEMENT_DECL:
4630 case XML_ATTRIBUTE_DECL:
4631 case XML_ENTITY_DECL:
4632 break;
4633 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00004634 doc = cur->doc;
4635 if (doc != NULL)
4636 dict = doc->dict;
4637 else
4638 dict = NULL;
4639 if (dict != NULL) {
4640 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
4641 xmlFree((xmlChar *) cur->name);
4642 cur->name = xmlDictLookup(dict, name, -1);
4643 } else {
4644 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4645 cur->name = xmlStrdup(name);
4646 }
Owen Taylor3473f882001-02-23 17:55:21 +00004647}
Daniel Veillard2156d432004-03-04 15:59:36 +00004648#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004649
Daniel Veillard2156d432004-03-04 15:59:36 +00004650#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004651/**
4652 * xmlNodeSetBase:
4653 * @cur: the node being changed
4654 * @uri: the new base URI
4655 *
4656 * Set (or reset) the base URI of a node, i.e. the value of the
4657 * xml:base attribute.
4658 */
4659void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004660xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004661 xmlNsPtr ns;
4662
Owen Taylor3473f882001-02-23 17:55:21 +00004663 if (cur == NULL) return;
4664 switch(cur->type) {
4665 case XML_TEXT_NODE:
4666 case XML_CDATA_SECTION_NODE:
4667 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004668 case XML_DOCUMENT_TYPE_NODE:
4669 case XML_DOCUMENT_FRAG_NODE:
4670 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004671 case XML_DTD_NODE:
4672 case XML_ELEMENT_DECL:
4673 case XML_ATTRIBUTE_DECL:
4674 case XML_ENTITY_DECL:
4675 case XML_PI_NODE:
4676 case XML_ENTITY_REF_NODE:
4677 case XML_ENTITY_NODE:
4678 case XML_NAMESPACE_DECL:
4679 case XML_XINCLUDE_START:
4680 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004681 return;
4682 case XML_ELEMENT_NODE:
4683 case XML_ATTRIBUTE_NODE:
4684 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004685 case XML_DOCUMENT_NODE:
4686#ifdef LIBXML_DOCB_ENABLED
4687 case XML_DOCB_DOCUMENT_NODE:
4688#endif
4689 case XML_HTML_DOCUMENT_NODE: {
4690 xmlDocPtr doc = (xmlDocPtr) cur;
4691
4692 if (doc->URL != NULL)
4693 xmlFree((xmlChar *) doc->URL);
4694 if (uri == NULL)
4695 doc->URL = NULL;
4696 else
4697 doc->URL = xmlStrdup(uri);
4698 return;
4699 }
Owen Taylor3473f882001-02-23 17:55:21 +00004700 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004701
4702 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4703 if (ns == NULL)
4704 return;
4705 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004706}
Daniel Veillard652327a2003-09-29 18:02:38 +00004707#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004708
4709/**
Owen Taylor3473f882001-02-23 17:55:21 +00004710 * xmlNodeGetBase:
4711 * @doc: the document the node pertains to
4712 * @cur: the node being checked
4713 *
4714 * Searches for the BASE URL. The code should work on both XML
4715 * and HTML document even if base mechanisms are completely different.
4716 * It returns the base as defined in RFC 2396 sections
4717 * 5.1.1. Base URI within Document Content
4718 * and
4719 * 5.1.2. Base URI from the Encapsulating Entity
4720 * However it does not return the document base (5.1.3), use
4721 * xmlDocumentGetBase() for this
4722 *
4723 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004724 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004725 */
4726xmlChar *
4727xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004728 xmlChar *oldbase = NULL;
4729 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004730
4731 if ((cur == NULL) && (doc == NULL))
4732 return(NULL);
4733 if (doc == NULL) doc = cur->doc;
4734 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4735 cur = doc->children;
4736 while ((cur != NULL) && (cur->name != NULL)) {
4737 if (cur->type != XML_ELEMENT_NODE) {
4738 cur = cur->next;
4739 continue;
4740 }
4741 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4742 cur = cur->children;
4743 continue;
4744 }
4745 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4746 cur = cur->children;
4747 continue;
4748 }
4749 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4750 return(xmlGetProp(cur, BAD_CAST "href"));
4751 }
4752 cur = cur->next;
4753 }
4754 return(NULL);
4755 }
4756 while (cur != NULL) {
4757 if (cur->type == XML_ENTITY_DECL) {
4758 xmlEntityPtr ent = (xmlEntityPtr) cur;
4759 return(xmlStrdup(ent->URI));
4760 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004761 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004762 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004763 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004764 if (oldbase != NULL) {
4765 newbase = xmlBuildURI(oldbase, base);
4766 if (newbase != NULL) {
4767 xmlFree(oldbase);
4768 xmlFree(base);
4769 oldbase = newbase;
4770 } else {
4771 xmlFree(oldbase);
4772 xmlFree(base);
4773 return(NULL);
4774 }
4775 } else {
4776 oldbase = base;
4777 }
4778 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4779 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4780 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4781 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004782 }
4783 }
Owen Taylor3473f882001-02-23 17:55:21 +00004784 cur = cur->parent;
4785 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004786 if ((doc != NULL) && (doc->URL != NULL)) {
4787 if (oldbase == NULL)
4788 return(xmlStrdup(doc->URL));
4789 newbase = xmlBuildURI(oldbase, doc->URL);
4790 xmlFree(oldbase);
4791 return(newbase);
4792 }
4793 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004794}
4795
4796/**
Daniel Veillard78697292003-10-19 20:44:43 +00004797 * xmlNodeBufGetContent:
4798 * @buffer: a buffer
4799 * @cur: the node being read
4800 *
4801 * Read the value of a node @cur, this can be either the text carried
4802 * directly by this node if it's a TEXT node or the aggregate string
4803 * of the values carried by this node child's (TEXT and ENTITY_REF).
4804 * Entity references are substituted.
4805 * Fills up the buffer @buffer with this value
4806 *
4807 * Returns 0 in case of success and -1 in case of error.
4808 */
4809int
4810xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4811{
4812 if ((cur == NULL) || (buffer == NULL)) return(-1);
4813 switch (cur->type) {
4814 case XML_CDATA_SECTION_NODE:
4815 case XML_TEXT_NODE:
4816 xmlBufferCat(buffer, cur->content);
4817 break;
4818 case XML_DOCUMENT_FRAG_NODE:
4819 case XML_ELEMENT_NODE:{
4820 xmlNodePtr tmp = cur;
4821
4822 while (tmp != NULL) {
4823 switch (tmp->type) {
4824 case XML_CDATA_SECTION_NODE:
4825 case XML_TEXT_NODE:
4826 if (tmp->content != NULL)
4827 xmlBufferCat(buffer, tmp->content);
4828 break;
4829 case XML_ENTITY_REF_NODE:
4830 xmlNodeBufGetContent(buffer, tmp->children);
4831 break;
4832 default:
4833 break;
4834 }
4835 /*
4836 * Skip to next node
4837 */
4838 if (tmp->children != NULL) {
4839 if (tmp->children->type != XML_ENTITY_DECL) {
4840 tmp = tmp->children;
4841 continue;
4842 }
4843 }
4844 if (tmp == cur)
4845 break;
4846
4847 if (tmp->next != NULL) {
4848 tmp = tmp->next;
4849 continue;
4850 }
4851
4852 do {
4853 tmp = tmp->parent;
4854 if (tmp == NULL)
4855 break;
4856 if (tmp == cur) {
4857 tmp = NULL;
4858 break;
4859 }
4860 if (tmp->next != NULL) {
4861 tmp = tmp->next;
4862 break;
4863 }
4864 } while (tmp != NULL);
4865 }
4866 break;
4867 }
4868 case XML_ATTRIBUTE_NODE:{
4869 xmlAttrPtr attr = (xmlAttrPtr) cur;
4870 xmlNodePtr tmp = attr->children;
4871
4872 while (tmp != NULL) {
4873 if (tmp->type == XML_TEXT_NODE)
4874 xmlBufferCat(buffer, tmp->content);
4875 else
4876 xmlNodeBufGetContent(buffer, tmp);
4877 tmp = tmp->next;
4878 }
4879 break;
4880 }
4881 case XML_COMMENT_NODE:
4882 case XML_PI_NODE:
4883 xmlBufferCat(buffer, cur->content);
4884 break;
4885 case XML_ENTITY_REF_NODE:{
4886 xmlEntityPtr ent;
4887 xmlNodePtr tmp;
4888
4889 /* lookup entity declaration */
4890 ent = xmlGetDocEntity(cur->doc, cur->name);
4891 if (ent == NULL)
4892 return(-1);
4893
4894 /* an entity content can be any "well balanced chunk",
4895 * i.e. the result of the content [43] production:
4896 * http://www.w3.org/TR/REC-xml#NT-content
4897 * -> we iterate through child nodes and recursive call
4898 * xmlNodeGetContent() which handles all possible node types */
4899 tmp = ent->children;
4900 while (tmp) {
4901 xmlNodeBufGetContent(buffer, tmp);
4902 tmp = tmp->next;
4903 }
4904 break;
4905 }
4906 case XML_ENTITY_NODE:
4907 case XML_DOCUMENT_TYPE_NODE:
4908 case XML_NOTATION_NODE:
4909 case XML_DTD_NODE:
4910 case XML_XINCLUDE_START:
4911 case XML_XINCLUDE_END:
4912 break;
4913 case XML_DOCUMENT_NODE:
4914#ifdef LIBXML_DOCB_ENABLED
4915 case XML_DOCB_DOCUMENT_NODE:
4916#endif
4917 case XML_HTML_DOCUMENT_NODE:
4918 cur = cur->children;
4919 while (cur!= NULL) {
4920 if ((cur->type == XML_ELEMENT_NODE) ||
4921 (cur->type == XML_TEXT_NODE) ||
4922 (cur->type == XML_CDATA_SECTION_NODE)) {
4923 xmlNodeBufGetContent(buffer, cur);
4924 }
4925 cur = cur->next;
4926 }
4927 break;
4928 case XML_NAMESPACE_DECL:
4929 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
4930 break;
4931 case XML_ELEMENT_DECL:
4932 case XML_ATTRIBUTE_DECL:
4933 case XML_ENTITY_DECL:
4934 break;
4935 }
4936 return(0);
4937}
4938/**
Owen Taylor3473f882001-02-23 17:55:21 +00004939 * xmlNodeGetContent:
4940 * @cur: the node being read
4941 *
4942 * Read the value of a node, this can be either the text carried
4943 * directly by this node if it's a TEXT node or the aggregate string
4944 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004945 * Entity references are substituted.
4946 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004947 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004948 */
4949xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004950xmlNodeGetContent(xmlNodePtr cur)
4951{
4952 if (cur == NULL)
4953 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004954 switch (cur->type) {
4955 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004956 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00004957 xmlBufferPtr buffer;
4958 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004959
Daniel Veillard814a76d2003-01-23 18:24:20 +00004960 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004961 if (buffer == NULL)
4962 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00004963 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004964 ret = buffer->content;
4965 buffer->content = NULL;
4966 xmlBufferFree(buffer);
4967 return (ret);
4968 }
4969 case XML_ATTRIBUTE_NODE:{
4970 xmlAttrPtr attr = (xmlAttrPtr) cur;
4971
4972 if (attr->parent != NULL)
4973 return (xmlNodeListGetString
4974 (attr->parent->doc, attr->children, 1));
4975 else
4976 return (xmlNodeListGetString(NULL, attr->children, 1));
4977 break;
4978 }
Owen Taylor3473f882001-02-23 17:55:21 +00004979 case XML_COMMENT_NODE:
4980 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004981 if (cur->content != NULL)
4982 return (xmlStrdup(cur->content));
4983 return (NULL);
4984 case XML_ENTITY_REF_NODE:{
4985 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00004986 xmlBufferPtr buffer;
4987 xmlChar *ret;
4988
4989 /* lookup entity declaration */
4990 ent = xmlGetDocEntity(cur->doc, cur->name);
4991 if (ent == NULL)
4992 return (NULL);
4993
4994 buffer = xmlBufferCreate();
4995 if (buffer == NULL)
4996 return (NULL);
4997
Daniel Veillardc4696922003-10-19 21:47:14 +00004998 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004999
5000 ret = buffer->content;
5001 buffer->content = NULL;
5002 xmlBufferFree(buffer);
5003 return (ret);
5004 }
Owen Taylor3473f882001-02-23 17:55:21 +00005005 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005006 case XML_DOCUMENT_TYPE_NODE:
5007 case XML_NOTATION_NODE:
5008 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005009 case XML_XINCLUDE_START:
5010 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00005011 return (NULL);
5012 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005013#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005014 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005015#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005016 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00005017 xmlBufferPtr buffer;
5018 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005019
Daniel Veillardc4696922003-10-19 21:47:14 +00005020 buffer = xmlBufferCreate();
5021 if (buffer == NULL)
5022 return (NULL);
5023
5024 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5025
5026 ret = buffer->content;
5027 buffer->content = NULL;
5028 xmlBufferFree(buffer);
5029 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005030 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005031 case XML_NAMESPACE_DECL: {
5032 xmlChar *tmp;
5033
5034 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5035 return (tmp);
5036 }
Owen Taylor3473f882001-02-23 17:55:21 +00005037 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005038 /* TODO !!! */
5039 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005040 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005041 /* TODO !!! */
5042 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005043 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005044 /* TODO !!! */
5045 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005046 case XML_CDATA_SECTION_NODE:
5047 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005048 if (cur->content != NULL)
5049 return (xmlStrdup(cur->content));
5050 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005051 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005052 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005053}
Daniel Veillard652327a2003-09-29 18:02:38 +00005054
Owen Taylor3473f882001-02-23 17:55:21 +00005055/**
5056 * xmlNodeSetContent:
5057 * @cur: the node being modified
5058 * @content: the new value of the content
5059 *
5060 * Replace the content of a node.
5061 */
5062void
5063xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5064 if (cur == NULL) {
5065#ifdef DEBUG_TREE
5066 xmlGenericError(xmlGenericErrorContext,
5067 "xmlNodeSetContent : node == NULL\n");
5068#endif
5069 return;
5070 }
5071 switch (cur->type) {
5072 case XML_DOCUMENT_FRAG_NODE:
5073 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005074 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005075 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5076 cur->children = xmlStringGetNodeList(cur->doc, content);
5077 UPDATE_LAST_CHILD_AND_PARENT(cur)
5078 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005079 case XML_TEXT_NODE:
5080 case XML_CDATA_SECTION_NODE:
5081 case XML_ENTITY_REF_NODE:
5082 case XML_ENTITY_NODE:
5083 case XML_PI_NODE:
5084 case XML_COMMENT_NODE:
5085 if (cur->content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005086 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
Daniel Veillard370ba3d2004-10-25 16:23:56 +00005087 (!xmlDictOwns(cur->doc->dict, cur->content))))
William M. Brack7762bb12004-01-04 14:49:01 +00005088 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005089 }
5090 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5091 cur->last = cur->children = NULL;
5092 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005093 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005094 } else
5095 cur->content = NULL;
5096 break;
5097 case XML_DOCUMENT_NODE:
5098 case XML_HTML_DOCUMENT_NODE:
5099 case XML_DOCUMENT_TYPE_NODE:
5100 case XML_XINCLUDE_START:
5101 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005102#ifdef LIBXML_DOCB_ENABLED
5103 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005104#endif
5105 break;
5106 case XML_NOTATION_NODE:
5107 break;
5108 case XML_DTD_NODE:
5109 break;
5110 case XML_NAMESPACE_DECL:
5111 break;
5112 case XML_ELEMENT_DECL:
5113 /* TODO !!! */
5114 break;
5115 case XML_ATTRIBUTE_DECL:
5116 /* TODO !!! */
5117 break;
5118 case XML_ENTITY_DECL:
5119 /* TODO !!! */
5120 break;
5121 }
5122}
5123
Daniel Veillard652327a2003-09-29 18:02:38 +00005124#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005125/**
5126 * xmlNodeSetContentLen:
5127 * @cur: the node being modified
5128 * @content: the new value of the content
5129 * @len: the size of @content
5130 *
5131 * Replace the content of a node.
5132 */
5133void
5134xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5135 if (cur == NULL) {
5136#ifdef DEBUG_TREE
5137 xmlGenericError(xmlGenericErrorContext,
5138 "xmlNodeSetContentLen : node == NULL\n");
5139#endif
5140 return;
5141 }
5142 switch (cur->type) {
5143 case XML_DOCUMENT_FRAG_NODE:
5144 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005145 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005146 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5147 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5148 UPDATE_LAST_CHILD_AND_PARENT(cur)
5149 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005150 case XML_TEXT_NODE:
5151 case XML_CDATA_SECTION_NODE:
5152 case XML_ENTITY_REF_NODE:
5153 case XML_ENTITY_NODE:
5154 case XML_PI_NODE:
5155 case XML_COMMENT_NODE:
5156 case XML_NOTATION_NODE:
5157 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005158 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005159 }
5160 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5161 cur->children = cur->last = NULL;
5162 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005163 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005164 } else
5165 cur->content = NULL;
5166 break;
5167 case XML_DOCUMENT_NODE:
5168 case XML_DTD_NODE:
5169 case XML_HTML_DOCUMENT_NODE:
5170 case XML_DOCUMENT_TYPE_NODE:
5171 case XML_NAMESPACE_DECL:
5172 case XML_XINCLUDE_START:
5173 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005174#ifdef LIBXML_DOCB_ENABLED
5175 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005176#endif
5177 break;
5178 case XML_ELEMENT_DECL:
5179 /* TODO !!! */
5180 break;
5181 case XML_ATTRIBUTE_DECL:
5182 /* TODO !!! */
5183 break;
5184 case XML_ENTITY_DECL:
5185 /* TODO !!! */
5186 break;
5187 }
5188}
Daniel Veillard652327a2003-09-29 18:02:38 +00005189#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005190
5191/**
5192 * xmlNodeAddContentLen:
5193 * @cur: the node being modified
5194 * @content: extra content
5195 * @len: the size of @content
5196 *
5197 * Append the extra substring to the node content.
5198 */
5199void
5200xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5201 if (cur == NULL) {
5202#ifdef DEBUG_TREE
5203 xmlGenericError(xmlGenericErrorContext,
5204 "xmlNodeAddContentLen : node == NULL\n");
5205#endif
5206 return;
5207 }
5208 if (len <= 0) return;
5209 switch (cur->type) {
5210 case XML_DOCUMENT_FRAG_NODE:
5211 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005212 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005213
Daniel Veillard7db37732001-07-12 01:20:08 +00005214 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005215 newNode = xmlNewTextLen(content, len);
5216 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005217 tmp = xmlAddChild(cur, newNode);
5218 if (tmp != newNode)
5219 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005220 if ((last != NULL) && (last->next == newNode)) {
5221 xmlTextMerge(last, newNode);
5222 }
5223 }
5224 break;
5225 }
5226 case XML_ATTRIBUTE_NODE:
5227 break;
5228 case XML_TEXT_NODE:
5229 case XML_CDATA_SECTION_NODE:
5230 case XML_ENTITY_REF_NODE:
5231 case XML_ENTITY_NODE:
5232 case XML_PI_NODE:
5233 case XML_COMMENT_NODE:
5234 case XML_NOTATION_NODE:
5235 if (content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005236 if ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5237 xmlDictOwns(cur->doc->dict, cur->content)) {
5238 cur->content =
5239 xmlStrncatNew(cur->content, content, len);
5240 break;
5241 }
Owen Taylor3473f882001-02-23 17:55:21 +00005242 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005243 }
5244 case XML_DOCUMENT_NODE:
5245 case XML_DTD_NODE:
5246 case XML_HTML_DOCUMENT_NODE:
5247 case XML_DOCUMENT_TYPE_NODE:
5248 case XML_NAMESPACE_DECL:
5249 case XML_XINCLUDE_START:
5250 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005251#ifdef LIBXML_DOCB_ENABLED
5252 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005253#endif
5254 break;
5255 case XML_ELEMENT_DECL:
5256 case XML_ATTRIBUTE_DECL:
5257 case XML_ENTITY_DECL:
5258 break;
5259 }
5260}
5261
5262/**
5263 * xmlNodeAddContent:
5264 * @cur: the node being modified
5265 * @content: extra content
5266 *
5267 * Append the extra substring to the node content.
5268 */
5269void
5270xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5271 int len;
5272
5273 if (cur == NULL) {
5274#ifdef DEBUG_TREE
5275 xmlGenericError(xmlGenericErrorContext,
5276 "xmlNodeAddContent : node == NULL\n");
5277#endif
5278 return;
5279 }
5280 if (content == NULL) return;
5281 len = xmlStrlen(content);
5282 xmlNodeAddContentLen(cur, content, len);
5283}
5284
5285/**
5286 * xmlTextMerge:
5287 * @first: the first text node
5288 * @second: the second text node being merged
5289 *
5290 * Merge two text nodes into one
5291 * Returns the first text node augmented
5292 */
5293xmlNodePtr
5294xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5295 if (first == NULL) return(second);
5296 if (second == NULL) return(first);
5297 if (first->type != XML_TEXT_NODE) return(first);
5298 if (second->type != XML_TEXT_NODE) return(first);
5299 if (second->name != first->name)
5300 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005301 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005302 xmlUnlinkNode(second);
5303 xmlFreeNode(second);
5304 return(first);
5305}
5306
Daniel Veillard2156d432004-03-04 15:59:36 +00005307#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005308/**
5309 * xmlGetNsList:
5310 * @doc: the document
5311 * @node: the current node
5312 *
5313 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005314 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005315 * that need to be freed by the caller or NULL if no
5316 * namespace if defined
5317 */
5318xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005319xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5320{
Owen Taylor3473f882001-02-23 17:55:21 +00005321 xmlNsPtr cur;
5322 xmlNsPtr *ret = NULL;
5323 int nbns = 0;
5324 int maxns = 10;
5325 int i;
5326
5327 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005328 if (node->type == XML_ELEMENT_NODE) {
5329 cur = node->nsDef;
5330 while (cur != NULL) {
5331 if (ret == NULL) {
5332 ret =
5333 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5334 sizeof(xmlNsPtr));
5335 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005336 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005337 return (NULL);
5338 }
5339 ret[nbns] = NULL;
5340 }
5341 for (i = 0; i < nbns; i++) {
5342 if ((cur->prefix == ret[i]->prefix) ||
5343 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5344 break;
5345 }
5346 if (i >= nbns) {
5347 if (nbns >= maxns) {
5348 maxns *= 2;
5349 ret = (xmlNsPtr *) xmlRealloc(ret,
5350 (maxns +
5351 1) *
5352 sizeof(xmlNsPtr));
5353 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005354 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005355 return (NULL);
5356 }
5357 }
5358 ret[nbns++] = cur;
5359 ret[nbns] = NULL;
5360 }
Owen Taylor3473f882001-02-23 17:55:21 +00005361
Daniel Veillard77044732001-06-29 21:31:07 +00005362 cur = cur->next;
5363 }
5364 }
5365 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005366 }
Daniel Veillard77044732001-06-29 21:31:07 +00005367 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005368}
Daniel Veillard652327a2003-09-29 18:02:38 +00005369#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005370
5371/**
5372 * xmlSearchNs:
5373 * @doc: the document
5374 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005375 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005376 *
5377 * Search a Ns registered under a given name space for a document.
5378 * recurse on the parents until it finds the defined namespace
5379 * or return NULL otherwise.
5380 * @nameSpace can be NULL, this is a search for the default namespace.
5381 * We don't allow to cross entities boundaries. If you don't declare
5382 * the namespace within those you will be in troubles !!! A warning
5383 * is generated to cover this case.
5384 *
5385 * Returns the namespace pointer or NULL.
5386 */
5387xmlNsPtr
5388xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005389
Owen Taylor3473f882001-02-23 17:55:21 +00005390 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005391 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005392
5393 if (node == NULL) return(NULL);
5394 if ((nameSpace != NULL) &&
5395 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005396 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5397 /*
5398 * The XML-1.0 namespace is normally held on the root
5399 * element. In this case exceptionally create it on the
5400 * node element.
5401 */
5402 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5403 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005404 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005405 return(NULL);
5406 }
5407 memset(cur, 0, sizeof(xmlNs));
5408 cur->type = XML_LOCAL_NAMESPACE;
5409 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5410 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5411 cur->next = node->nsDef;
5412 node->nsDef = cur;
5413 return(cur);
5414 }
Owen Taylor3473f882001-02-23 17:55:21 +00005415 if (doc->oldNs == NULL) {
5416 /*
5417 * Allocate a new Namespace and fill the fields.
5418 */
5419 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5420 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005421 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005422 return(NULL);
5423 }
5424 memset(doc->oldNs, 0, sizeof(xmlNs));
5425 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5426
5427 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5428 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5429 }
5430 return(doc->oldNs);
5431 }
5432 while (node != NULL) {
5433 if ((node->type == XML_ENTITY_REF_NODE) ||
5434 (node->type == XML_ENTITY_NODE) ||
5435 (node->type == XML_ENTITY_DECL))
5436 return(NULL);
5437 if (node->type == XML_ELEMENT_NODE) {
5438 cur = node->nsDef;
5439 while (cur != NULL) {
5440 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5441 (cur->href != NULL))
5442 return(cur);
5443 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5444 (cur->href != NULL) &&
5445 (xmlStrEqual(cur->prefix, nameSpace)))
5446 return(cur);
5447 cur = cur->next;
5448 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005449 if (orig != node) {
5450 cur = node->ns;
5451 if (cur != NULL) {
5452 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5453 (cur->href != NULL))
5454 return(cur);
5455 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5456 (cur->href != NULL) &&
5457 (xmlStrEqual(cur->prefix, nameSpace)))
5458 return(cur);
5459 }
5460 }
Owen Taylor3473f882001-02-23 17:55:21 +00005461 }
5462 node = node->parent;
5463 }
5464 return(NULL);
5465}
5466
5467/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005468 * xmlNsInScope:
5469 * @doc: the document
5470 * @node: the current node
5471 * @ancestor: the ancestor carrying the namespace
5472 * @prefix: the namespace prefix
5473 *
5474 * Verify that the given namespace held on @ancestor is still in scope
5475 * on node.
5476 *
5477 * Returns 1 if true, 0 if false and -1 in case of error.
5478 */
5479static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005480xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5481 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005482{
5483 xmlNsPtr tst;
5484
5485 while ((node != NULL) && (node != ancestor)) {
5486 if ((node->type == XML_ENTITY_REF_NODE) ||
5487 (node->type == XML_ENTITY_NODE) ||
5488 (node->type == XML_ENTITY_DECL))
5489 return (-1);
5490 if (node->type == XML_ELEMENT_NODE) {
5491 tst = node->nsDef;
5492 while (tst != NULL) {
5493 if ((tst->prefix == NULL)
5494 && (prefix == NULL))
5495 return (0);
5496 if ((tst->prefix != NULL)
5497 && (prefix != NULL)
5498 && (xmlStrEqual(tst->prefix, prefix)))
5499 return (0);
5500 tst = tst->next;
5501 }
5502 }
5503 node = node->parent;
5504 }
5505 if (node != ancestor)
5506 return (-1);
5507 return (1);
5508}
5509
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005510/**
Owen Taylor3473f882001-02-23 17:55:21 +00005511 * xmlSearchNsByHref:
5512 * @doc: the document
5513 * @node: the current node
5514 * @href: the namespace value
5515 *
5516 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5517 * the defined namespace or return NULL otherwise.
5518 * Returns the namespace pointer or NULL.
5519 */
5520xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005521xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5522{
Owen Taylor3473f882001-02-23 17:55:21 +00005523 xmlNsPtr cur;
5524 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005525 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005526
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005527 if ((node == NULL) || (href == NULL))
5528 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005529 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005530 /*
5531 * Only the document can hold the XML spec namespace.
5532 */
5533 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5534 /*
5535 * The XML-1.0 namespace is normally held on the root
5536 * element. In this case exceptionally create it on the
5537 * node element.
5538 */
5539 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5540 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005541 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005542 return (NULL);
5543 }
5544 memset(cur, 0, sizeof(xmlNs));
5545 cur->type = XML_LOCAL_NAMESPACE;
5546 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5547 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5548 cur->next = node->nsDef;
5549 node->nsDef = cur;
5550 return (cur);
5551 }
5552 if (doc->oldNs == NULL) {
5553 /*
5554 * Allocate a new Namespace and fill the fields.
5555 */
5556 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5557 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005558 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005559 return (NULL);
5560 }
5561 memset(doc->oldNs, 0, sizeof(xmlNs));
5562 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005563
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005564 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5565 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5566 }
5567 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005568 }
Daniel Veillard62040be2004-05-17 03:17:26 +00005569 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00005570 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005571 if ((node->type == XML_ENTITY_REF_NODE) ||
5572 (node->type == XML_ENTITY_NODE) ||
5573 (node->type == XML_ENTITY_DECL))
5574 return (NULL);
5575 if (node->type == XML_ELEMENT_NODE) {
5576 cur = node->nsDef;
5577 while (cur != NULL) {
5578 if ((cur->href != NULL) && (href != NULL) &&
5579 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005580 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00005581 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005582 return (cur);
5583 }
5584 cur = cur->next;
5585 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005586 if (orig != node) {
5587 cur = node->ns;
5588 if (cur != NULL) {
5589 if ((cur->href != NULL) && (href != NULL) &&
5590 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005591 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00005592 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00005593 return (cur);
5594 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005595 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005596 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005597 }
5598 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005599 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005600 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005601}
5602
5603/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005604 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005605 * @doc: the document
5606 * @tree: a node expected to hold the new namespace
5607 * @ns: the original namespace
5608 *
5609 * This function tries to locate a namespace definition in a tree
5610 * ancestors, or create a new namespace definition node similar to
5611 * @ns trying to reuse the same prefix. However if the given prefix is
5612 * null (default namespace) or reused within the subtree defined by
5613 * @tree or on one of its ancestors then a new prefix is generated.
5614 * Returns the (new) namespace definition or NULL in case of error
5615 */
5616xmlNsPtr
5617xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5618 xmlNsPtr def;
5619 xmlChar prefix[50];
5620 int counter = 1;
5621
5622 if (tree == NULL) {
5623#ifdef DEBUG_TREE
5624 xmlGenericError(xmlGenericErrorContext,
5625 "xmlNewReconciliedNs : tree == NULL\n");
5626#endif
5627 return(NULL);
5628 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00005629 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005630#ifdef DEBUG_TREE
5631 xmlGenericError(xmlGenericErrorContext,
5632 "xmlNewReconciliedNs : ns == NULL\n");
5633#endif
5634 return(NULL);
5635 }
5636 /*
5637 * Search an existing namespace definition inherited.
5638 */
5639 def = xmlSearchNsByHref(doc, tree, ns->href);
5640 if (def != NULL)
5641 return(def);
5642
5643 /*
5644 * Find a close prefix which is not already in use.
5645 * Let's strip namespace prefixes longer than 20 chars !
5646 */
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");
Daniel Veillardf742d342002-03-07 00:05:35 +00005649 else
William M. Brack13dfa872004-09-18 04:52:08 +00005650 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005651
Owen Taylor3473f882001-02-23 17:55:21 +00005652 def = xmlSearchNs(doc, tree, prefix);
5653 while (def != NULL) {
5654 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005655 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005656 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005657 else
William M. Brack13dfa872004-09-18 04:52:08 +00005658 snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
5659 (char *)ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005660 def = xmlSearchNs(doc, tree, prefix);
5661 }
5662
5663 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005664 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005665 */
5666 def = xmlNewNs(tree, ns->href, prefix);
5667 return(def);
5668}
5669
Daniel Veillard652327a2003-09-29 18:02:38 +00005670#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005671/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005672 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005673 * @doc: the document
5674 * @tree: a node defining the subtree to reconciliate
5675 *
5676 * This function checks that all the namespaces declared within the given
5677 * tree are properly declared. This is needed for example after Copy or Cut
5678 * and then paste operations. The subtree may still hold pointers to
5679 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005680 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005681 * the new environment. If not possible the new namespaces are redeclared
5682 * on @tree at the top of the given subtree.
5683 * Returns the number of namespace declarations created or -1 in case of error.
5684 */
5685int
5686xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5687 xmlNsPtr *oldNs = NULL;
5688 xmlNsPtr *newNs = NULL;
5689 int sizeCache = 0;
5690 int nbCache = 0;
5691
5692 xmlNsPtr n;
5693 xmlNodePtr node = tree;
5694 xmlAttrPtr attr;
5695 int ret = 0, i;
5696
Daniel Veillardce244ad2004-11-05 10:03:46 +00005697 if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1);
5698 if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1);
5699 if (node->doc != doc) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005700 while (node != NULL) {
5701 /*
5702 * Reconciliate the node namespace
5703 */
5704 if (node->ns != NULL) {
5705 /*
5706 * initialize the cache if needed
5707 */
5708 if (sizeCache == 0) {
5709 sizeCache = 10;
5710 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5711 sizeof(xmlNsPtr));
5712 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005713 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005714 return(-1);
5715 }
5716 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5717 sizeof(xmlNsPtr));
5718 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005719 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005720 xmlFree(oldNs);
5721 return(-1);
5722 }
5723 }
5724 for (i = 0;i < nbCache;i++) {
5725 if (oldNs[i] == node->ns) {
5726 node->ns = newNs[i];
5727 break;
5728 }
5729 }
5730 if (i == nbCache) {
5731 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005732 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005733 */
5734 n = xmlNewReconciliedNs(doc, tree, node->ns);
5735 if (n != NULL) { /* :-( what if else ??? */
5736 /*
5737 * check if we need to grow the cache buffers.
5738 */
5739 if (sizeCache <= nbCache) {
5740 sizeCache *= 2;
5741 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5742 sizeof(xmlNsPtr));
5743 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005744 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005745 xmlFree(newNs);
5746 return(-1);
5747 }
5748 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5749 sizeof(xmlNsPtr));
5750 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005751 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005752 xmlFree(oldNs);
5753 return(-1);
5754 }
5755 }
5756 newNs[nbCache] = n;
5757 oldNs[nbCache++] = node->ns;
5758 node->ns = n;
5759 }
5760 }
5761 }
5762 /*
5763 * now check for namespace hold by attributes on the node.
5764 */
5765 attr = node->properties;
5766 while (attr != NULL) {
5767 if (attr->ns != NULL) {
5768 /*
5769 * initialize the cache if needed
5770 */
5771 if (sizeCache == 0) {
5772 sizeCache = 10;
5773 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5774 sizeof(xmlNsPtr));
5775 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005776 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005777 return(-1);
5778 }
5779 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5780 sizeof(xmlNsPtr));
5781 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005782 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005783 xmlFree(oldNs);
5784 return(-1);
5785 }
5786 }
5787 for (i = 0;i < nbCache;i++) {
5788 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005789 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005790 break;
5791 }
5792 }
5793 if (i == nbCache) {
5794 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005795 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005796 */
5797 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5798 if (n != NULL) { /* :-( what if else ??? */
5799 /*
5800 * check if we need to grow the cache buffers.
5801 */
5802 if (sizeCache <= nbCache) {
5803 sizeCache *= 2;
5804 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5805 sizeof(xmlNsPtr));
5806 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005807 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005808 xmlFree(newNs);
5809 return(-1);
5810 }
5811 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5812 sizeof(xmlNsPtr));
5813 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005814 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005815 xmlFree(oldNs);
5816 return(-1);
5817 }
5818 }
5819 newNs[nbCache] = n;
5820 oldNs[nbCache++] = attr->ns;
5821 attr->ns = n;
5822 }
5823 }
5824 }
5825 attr = attr->next;
5826 }
5827
5828 /*
5829 * Browse the full subtree, deep first
5830 */
Daniel Veillardac996a12004-07-30 12:02:58 +00005831 if (node->children != NULL && node->type != XML_ENTITY_REF_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00005832 /* deep first */
5833 node = node->children;
5834 } else if ((node != tree) && (node->next != NULL)) {
5835 /* then siblings */
5836 node = node->next;
5837 } else if (node != tree) {
5838 /* go up to parents->next if needed */
5839 while (node != tree) {
5840 if (node->parent != NULL)
5841 node = node->parent;
5842 if ((node != tree) && (node->next != NULL)) {
5843 node = node->next;
5844 break;
5845 }
5846 if (node->parent == NULL) {
5847 node = NULL;
5848 break;
5849 }
5850 }
5851 /* exit condition */
5852 if (node == tree)
5853 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005854 } else
5855 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005856 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005857 if (oldNs != NULL)
5858 xmlFree(oldNs);
5859 if (newNs != NULL)
5860 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005861 return(ret);
5862}
Daniel Veillard652327a2003-09-29 18:02:38 +00005863#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005864
5865/**
5866 * xmlHasProp:
5867 * @node: the node
5868 * @name: the attribute name
5869 *
5870 * Search an attribute associated to a node
5871 * This function also looks in DTD attribute declaration for #FIXED or
5872 * default declaration values unless DTD use has been turned off.
5873 *
5874 * Returns the attribute or the attribute declaration or NULL if
5875 * neither was found.
5876 */
5877xmlAttrPtr
5878xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5879 xmlAttrPtr prop;
5880 xmlDocPtr doc;
5881
5882 if ((node == NULL) || (name == NULL)) return(NULL);
5883 /*
5884 * Check on the properties attached to the node
5885 */
5886 prop = node->properties;
5887 while (prop != NULL) {
5888 if (xmlStrEqual(prop->name, name)) {
5889 return(prop);
5890 }
5891 prop = prop->next;
5892 }
5893 if (!xmlCheckDTD) return(NULL);
5894
5895 /*
5896 * Check if there is a default declaration in the internal
5897 * or external subsets
5898 */
5899 doc = node->doc;
5900 if (doc != NULL) {
5901 xmlAttributePtr attrDecl;
5902 if (doc->intSubset != NULL) {
5903 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5904 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5905 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005906 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5907 /* return attribute declaration only if a default value is given
5908 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005909 return((xmlAttrPtr) attrDecl);
5910 }
5911 }
5912 return(NULL);
5913}
5914
5915/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005916 * xmlHasNsProp:
5917 * @node: the node
5918 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005919 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005920 *
5921 * Search for an attribute associated to a node
5922 * This attribute has to be anchored in the namespace specified.
5923 * This does the entity substitution.
5924 * This function looks in DTD attribute declaration for #FIXED or
5925 * default declaration values unless DTD use has been turned off.
William M. Brack2c228442004-10-03 04:10:00 +00005926 * Note that a namespace of NULL indicates to use the default namespace.
Daniel Veillarde95e2392001-06-06 10:46:28 +00005927 *
5928 * Returns the attribute or the attribute declaration or NULL
5929 * if neither was found.
5930 */
5931xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005932xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005933 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00005934#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005935 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00005936#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005937
5938 if (node == NULL)
5939 return(NULL);
5940
5941 prop = node->properties;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005942 while (prop != NULL) {
5943 /*
5944 * One need to have
5945 * - same attribute names
5946 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005947 */
William M. Brack2c228442004-10-03 04:10:00 +00005948 if (xmlStrEqual(prop->name, name)) {
5949 if (((prop->ns != NULL) &&
5950 (xmlStrEqual(prop->ns->href, nameSpace))) ||
5951 ((prop->ns == NULL) && (nameSpace == NULL))) {
5952 return(prop);
5953 }
Daniel Veillarde95e2392001-06-06 10:46:28 +00005954 }
5955 prop = prop->next;
5956 }
5957 if (!xmlCheckDTD) return(NULL);
5958
Daniel Veillard652327a2003-09-29 18:02:38 +00005959#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005960 /*
5961 * Check if there is a default declaration in the internal
5962 * or external subsets
5963 */
5964 doc = node->doc;
5965 if (doc != NULL) {
5966 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005967 xmlAttributePtr attrDecl = NULL;
5968 xmlNsPtr *nsList, *cur;
5969 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005970
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005971 nsList = xmlGetNsList(node->doc, node);
5972 if (nsList == NULL)
5973 return(NULL);
5974 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5975 ename = xmlStrdup(node->ns->prefix);
5976 ename = xmlStrcat(ename, BAD_CAST ":");
5977 ename = xmlStrcat(ename, node->name);
5978 } else {
5979 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005980 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005981 if (ename == NULL) {
5982 xmlFree(nsList);
5983 return(NULL);
5984 }
5985
William M. Brack2c228442004-10-03 04:10:00 +00005986 if (nameSpace == NULL) {
5987 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5988 name, NULL);
5989 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
5990 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5991 name, NULL);
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005992 }
William M. Brack2c228442004-10-03 04:10:00 +00005993 } else {
5994 cur = nsList;
5995 while (*cur != NULL) {
5996 if (xmlStrEqual((*cur)->href, nameSpace)) {
5997 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5998 name, (*cur)->prefix);
5999 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6000 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6001 name, (*cur)->prefix);
6002 }
6003 cur++;
6004 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006005 }
6006 xmlFree(nsList);
6007 xmlFree(ename);
6008 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006009 }
6010 }
Daniel Veillard652327a2003-09-29 18:02:38 +00006011#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00006012 return(NULL);
6013}
6014
6015/**
Owen Taylor3473f882001-02-23 17:55:21 +00006016 * xmlGetProp:
6017 * @node: the node
6018 * @name: the attribute name
6019 *
6020 * Search and get the value of an attribute associated to a node
6021 * This does the entity substitution.
6022 * This function looks in DTD attribute declaration for #FIXED or
6023 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00006024 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00006025 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6026 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00006027 *
6028 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006029 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006030 */
6031xmlChar *
6032xmlGetProp(xmlNodePtr node, const xmlChar *name) {
6033 xmlAttrPtr prop;
6034 xmlDocPtr doc;
6035
6036 if ((node == NULL) || (name == NULL)) return(NULL);
6037 /*
6038 * Check on the properties attached to the node
6039 */
6040 prop = node->properties;
6041 while (prop != NULL) {
6042 if (xmlStrEqual(prop->name, name)) {
6043 xmlChar *ret;
6044
6045 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6046 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6047 return(ret);
6048 }
6049 prop = prop->next;
6050 }
6051 if (!xmlCheckDTD) return(NULL);
6052
6053 /*
6054 * Check if there is a default declaration in the internal
6055 * or external subsets
6056 */
6057 doc = node->doc;
6058 if (doc != NULL) {
6059 xmlAttributePtr attrDecl;
6060 if (doc->intSubset != NULL) {
6061 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6062 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6063 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006064 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6065 /* return attribute declaration only if a default value is given
6066 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006067 return(xmlStrdup(attrDecl->defaultValue));
6068 }
6069 }
6070 return(NULL);
6071}
6072
6073/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006074 * xmlGetNoNsProp:
6075 * @node: the node
6076 * @name: the attribute name
6077 *
6078 * Search and get the value of an attribute associated to a node
6079 * This does the entity substitution.
6080 * This function looks in DTD attribute declaration for #FIXED or
6081 * default declaration values unless DTD use has been turned off.
6082 * This function is similar to xmlGetProp except it will accept only
6083 * an attribute in no namespace.
6084 *
6085 * Returns the attribute value or NULL if not found.
6086 * It's up to the caller to free the memory with xmlFree().
6087 */
6088xmlChar *
6089xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6090 xmlAttrPtr prop;
6091 xmlDocPtr doc;
6092
6093 if ((node == NULL) || (name == NULL)) return(NULL);
6094 /*
6095 * Check on the properties attached to the node
6096 */
6097 prop = node->properties;
6098 while (prop != NULL) {
6099 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6100 xmlChar *ret;
6101
6102 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6103 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6104 return(ret);
6105 }
6106 prop = prop->next;
6107 }
6108 if (!xmlCheckDTD) return(NULL);
6109
6110 /*
6111 * Check if there is a default declaration in the internal
6112 * or external subsets
6113 */
6114 doc = node->doc;
6115 if (doc != NULL) {
6116 xmlAttributePtr attrDecl;
6117 if (doc->intSubset != NULL) {
6118 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6119 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6120 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006121 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6122 /* return attribute declaration only if a default value is given
6123 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006124 return(xmlStrdup(attrDecl->defaultValue));
6125 }
6126 }
6127 return(NULL);
6128}
6129
6130/**
Owen Taylor3473f882001-02-23 17:55:21 +00006131 * xmlGetNsProp:
6132 * @node: the node
6133 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006134 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006135 *
6136 * Search and get the value of an attribute associated to a node
6137 * This attribute has to be anchored in the namespace specified.
6138 * This does the entity substitution.
6139 * This function looks in DTD attribute declaration for #FIXED or
6140 * default declaration values unless DTD use has been turned off.
6141 *
6142 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006143 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006144 */
6145xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006146xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006147 xmlAttrPtr prop;
6148 xmlDocPtr doc;
6149 xmlNsPtr ns;
6150
6151 if (node == NULL)
6152 return(NULL);
6153
6154 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006155 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006156 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006157 while (prop != NULL) {
6158 /*
6159 * One need to have
6160 * - same attribute names
6161 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006162 */
6163 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006164 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006165 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006166 xmlChar *ret;
6167
6168 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6169 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6170 return(ret);
6171 }
6172 prop = prop->next;
6173 }
6174 if (!xmlCheckDTD) return(NULL);
6175
6176 /*
6177 * Check if there is a default declaration in the internal
6178 * or external subsets
6179 */
6180 doc = node->doc;
6181 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006182 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006183 xmlAttributePtr attrDecl;
6184
Owen Taylor3473f882001-02-23 17:55:21 +00006185 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6186 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6187 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6188
6189 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6190 /*
6191 * The DTD declaration only allows a prefix search
6192 */
6193 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006194 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006195 return(xmlStrdup(attrDecl->defaultValue));
6196 }
6197 }
6198 }
6199 return(NULL);
6200}
6201
Daniel Veillard2156d432004-03-04 15:59:36 +00006202#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6203/**
6204 * xmlUnsetProp:
6205 * @node: the node
6206 * @name: the attribute name
6207 *
6208 * Remove an attribute carried by a node.
6209 * Returns 0 if successful, -1 if not found
6210 */
6211int
6212xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
6213 xmlAttrPtr prop, prev = NULL;;
6214
6215 if ((node == NULL) || (name == NULL))
6216 return(-1);
6217 prop = node->properties;
6218 while (prop != NULL) {
6219 if ((xmlStrEqual(prop->name, name)) &&
6220 (prop->ns == NULL)) {
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00006221 xmlUnlinkNode((xmlNodePtr) prop);
Daniel Veillard2156d432004-03-04 15:59:36 +00006222 xmlFreeProp(prop);
6223 return(0);
6224 }
6225 prev = prop;
6226 prop = prop->next;
6227 }
6228 return(-1);
6229}
6230
6231/**
6232 * xmlUnsetNsProp:
6233 * @node: the node
6234 * @ns: the namespace definition
6235 * @name: the attribute name
6236 *
6237 * Remove an attribute carried by a node.
6238 * Returns 0 if successful, -1 if not found
6239 */
6240int
6241xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
Daniel Veillard27f20102004-11-05 11:50:11 +00006242 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard2156d432004-03-04 15:59:36 +00006243
6244 if ((node == NULL) || (name == NULL))
6245 return(-1);
Daniel Veillard27f20102004-11-05 11:50:11 +00006246 prop = node->properties;
Daniel Veillard2156d432004-03-04 15:59:36 +00006247 if (ns == NULL)
6248 return(xmlUnsetProp(node, name));
6249 if (ns->href == NULL)
6250 return(-1);
6251 while (prop != NULL) {
6252 if ((xmlStrEqual(prop->name, name)) &&
6253 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00006254 xmlUnlinkNode((xmlNodePtr) prop);
Daniel Veillard2156d432004-03-04 15:59:36 +00006255 xmlFreeProp(prop);
6256 return(0);
6257 }
6258 prev = prop;
6259 prop = prop->next;
6260 }
6261 return(-1);
6262}
6263#endif
6264
6265#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006266/**
6267 * xmlSetProp:
6268 * @node: the node
6269 * @name: the attribute name
6270 * @value: the attribute value
6271 *
6272 * Set (or reset) an attribute carried by a node.
6273 * Returns the attribute pointer.
6274 */
6275xmlAttrPtr
6276xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006277 xmlAttrPtr prop;
6278 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006279
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006280 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006281 return(NULL);
6282 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006283 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006284 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006285 if ((xmlStrEqual(prop->name, name)) &&
6286 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006287 xmlNodePtr oldprop = prop->children;
6288
Owen Taylor3473f882001-02-23 17:55:21 +00006289 prop->children = NULL;
6290 prop->last = NULL;
6291 if (value != NULL) {
6292 xmlChar *buffer;
6293 xmlNodePtr tmp;
6294
6295 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6296 prop->children = xmlStringGetNodeList(node->doc, buffer);
6297 prop->last = NULL;
6298 prop->doc = doc;
6299 tmp = prop->children;
6300 while (tmp != NULL) {
6301 tmp->parent = (xmlNodePtr) prop;
6302 tmp->doc = doc;
6303 if (tmp->next == NULL)
6304 prop->last = tmp;
6305 tmp = tmp->next;
6306 }
6307 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006308 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006309 if (oldprop != NULL)
6310 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006311 return(prop);
6312 }
6313 prop = prop->next;
6314 }
6315 prop = xmlNewProp(node, name, value);
6316 return(prop);
6317}
6318
6319/**
6320 * xmlSetNsProp:
6321 * @node: the node
6322 * @ns: the namespace definition
6323 * @name: the attribute name
6324 * @value: the attribute value
6325 *
6326 * Set (or reset) an attribute carried by a node.
6327 * The ns structure must be in scope, this is not checked.
6328 *
6329 * Returns the attribute pointer.
6330 */
6331xmlAttrPtr
6332xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6333 const xmlChar *value) {
6334 xmlAttrPtr prop;
6335
Daniel Veillardb6b36d32005-02-09 16:48:53 +00006336 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006337 return(NULL);
6338
6339 if (ns == NULL)
6340 return(xmlSetProp(node, name, value));
6341 if (ns->href == NULL)
6342 return(NULL);
6343 prop = node->properties;
6344
6345 while (prop != NULL) {
6346 /*
6347 * One need to have
6348 * - same attribute names
6349 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006350 */
6351 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006352 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006353 if (prop->children != NULL)
6354 xmlFreeNodeList(prop->children);
6355 prop->children = NULL;
6356 prop->last = NULL;
6357 prop->ns = ns;
6358 if (value != NULL) {
6359 xmlChar *buffer;
6360 xmlNodePtr tmp;
6361
6362 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6363 prop->children = xmlStringGetNodeList(node->doc, buffer);
6364 prop->last = NULL;
6365 tmp = prop->children;
6366 while (tmp != NULL) {
6367 tmp->parent = (xmlNodePtr) prop;
6368 if (tmp->next == NULL)
6369 prop->last = tmp;
6370 tmp = tmp->next;
6371 }
6372 xmlFree(buffer);
6373 }
6374 return(prop);
6375 }
6376 prop = prop->next;
6377 }
6378 prop = xmlNewNsProp(node, ns, name, value);
6379 return(prop);
6380}
6381
Daniel Veillard652327a2003-09-29 18:02:38 +00006382#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006383
6384/**
Owen Taylor3473f882001-02-23 17:55:21 +00006385 * xmlNodeIsText:
6386 * @node: the node
6387 *
6388 * Is this node a Text node ?
6389 * Returns 1 yes, 0 no
6390 */
6391int
6392xmlNodeIsText(xmlNodePtr node) {
6393 if (node == NULL) return(0);
6394
6395 if (node->type == XML_TEXT_NODE) return(1);
6396 return(0);
6397}
6398
6399/**
6400 * xmlIsBlankNode:
6401 * @node: the node
6402 *
6403 * Checks whether this node is an empty or whitespace only
6404 * (and possibly ignorable) text-node.
6405 *
6406 * Returns 1 yes, 0 no
6407 */
6408int
6409xmlIsBlankNode(xmlNodePtr node) {
6410 const xmlChar *cur;
6411 if (node == NULL) return(0);
6412
Daniel Veillard7db37732001-07-12 01:20:08 +00006413 if ((node->type != XML_TEXT_NODE) &&
6414 (node->type != XML_CDATA_SECTION_NODE))
6415 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006416 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006417 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006418 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006419 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006420 cur++;
6421 }
6422
6423 return(1);
6424}
6425
6426/**
6427 * xmlTextConcat:
6428 * @node: the node
6429 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006430 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006431 *
6432 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006433 *
6434 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006435 */
6436
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006437int
Owen Taylor3473f882001-02-23 17:55:21 +00006438xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006439 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006440
6441 if ((node->type != XML_TEXT_NODE) &&
6442 (node->type != XML_CDATA_SECTION_NODE)) {
6443#ifdef DEBUG_TREE
6444 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006445 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006446#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006447 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006448 }
William M. Brack7762bb12004-01-04 14:49:01 +00006449 /* need to check if content is currently in the dictionary */
6450 if ((node->doc != NULL) && (node->doc->dict != NULL) &&
6451 xmlDictOwns(node->doc->dict, node->content)) {
6452 node->content = xmlStrncatNew(node->content, content, len);
6453 } else {
6454 node->content = xmlStrncat(node->content, content, len);
6455 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006456 if (node->content == NULL)
6457 return(-1);
6458 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006459}
6460
6461/************************************************************************
6462 * *
6463 * Output : to a FILE or in memory *
6464 * *
6465 ************************************************************************/
6466
Owen Taylor3473f882001-02-23 17:55:21 +00006467/**
6468 * xmlBufferCreate:
6469 *
6470 * routine to create an XML buffer.
6471 * returns the new structure.
6472 */
6473xmlBufferPtr
6474xmlBufferCreate(void) {
6475 xmlBufferPtr ret;
6476
6477 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6478 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006479 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006480 return(NULL);
6481 }
6482 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006483 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006484 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006485 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006486 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006487 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006488 xmlFree(ret);
6489 return(NULL);
6490 }
6491 ret->content[0] = 0;
6492 return(ret);
6493}
6494
6495/**
6496 * xmlBufferCreateSize:
6497 * @size: initial size of buffer
6498 *
6499 * routine to create an XML buffer.
6500 * returns the new structure.
6501 */
6502xmlBufferPtr
6503xmlBufferCreateSize(size_t size) {
6504 xmlBufferPtr ret;
6505
6506 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6507 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006508 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006509 return(NULL);
6510 }
6511 ret->use = 0;
6512 ret->alloc = xmlBufferAllocScheme;
6513 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6514 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006515 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006516 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006517 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006518 xmlFree(ret);
6519 return(NULL);
6520 }
6521 ret->content[0] = 0;
6522 } else
6523 ret->content = NULL;
6524 return(ret);
6525}
6526
6527/**
Daniel Veillard53350552003-09-18 13:35:51 +00006528 * xmlBufferCreateStatic:
6529 * @mem: the memory area
6530 * @size: the size in byte
6531 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006532 * routine to create an XML buffer from an immutable memory area.
6533 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006534 * present until the end of the buffer lifetime.
6535 *
6536 * returns the new structure.
6537 */
6538xmlBufferPtr
6539xmlBufferCreateStatic(void *mem, size_t size) {
6540 xmlBufferPtr ret;
6541
6542 if ((mem == NULL) || (size == 0))
6543 return(NULL);
6544
6545 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6546 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006547 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006548 return(NULL);
6549 }
6550 ret->use = size;
6551 ret->size = size;
6552 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6553 ret->content = (xmlChar *) mem;
6554 return(ret);
6555}
6556
6557/**
Owen Taylor3473f882001-02-23 17:55:21 +00006558 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006559 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006560 * @scheme: allocation scheme to use
6561 *
6562 * Sets the allocation scheme for this buffer
6563 */
6564void
6565xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6566 xmlBufferAllocationScheme scheme) {
6567 if (buf == NULL) {
6568#ifdef DEBUG_BUFFER
6569 xmlGenericError(xmlGenericErrorContext,
6570 "xmlBufferSetAllocationScheme: buf == NULL\n");
6571#endif
6572 return;
6573 }
Daniel Veillard53350552003-09-18 13:35:51 +00006574 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006575
6576 buf->alloc = scheme;
6577}
6578
6579/**
6580 * xmlBufferFree:
6581 * @buf: the buffer to free
6582 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006583 * Frees an XML buffer. It frees both the content and the structure which
6584 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006585 */
6586void
6587xmlBufferFree(xmlBufferPtr buf) {
6588 if (buf == NULL) {
6589#ifdef DEBUG_BUFFER
6590 xmlGenericError(xmlGenericErrorContext,
6591 "xmlBufferFree: buf == NULL\n");
6592#endif
6593 return;
6594 }
Daniel Veillard53350552003-09-18 13:35:51 +00006595
6596 if ((buf->content != NULL) &&
6597 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006598 xmlFree(buf->content);
6599 }
Owen Taylor3473f882001-02-23 17:55:21 +00006600 xmlFree(buf);
6601}
6602
6603/**
6604 * xmlBufferEmpty:
6605 * @buf: the buffer
6606 *
6607 * empty a buffer.
6608 */
6609void
6610xmlBufferEmpty(xmlBufferPtr buf) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006611 if (buf == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006612 if (buf->content == NULL) return;
6613 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006614 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006615 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006616 } else {
6617 memset(buf->content, 0, buf->size);
6618 }
Owen Taylor3473f882001-02-23 17:55:21 +00006619}
6620
6621/**
6622 * xmlBufferShrink:
6623 * @buf: the buffer to dump
6624 * @len: the number of xmlChar to remove
6625 *
6626 * Remove the beginning of an XML buffer.
6627 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006628 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006629 */
6630int
6631xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
Daniel Veillard3d97e662004-11-04 10:49:00 +00006632 if (buf == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006633 if (len == 0) return(0);
6634 if (len > buf->use) return(-1);
6635
6636 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006637 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6638 buf->content += len;
6639 } else {
6640 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6641 buf->content[buf->use] = 0;
6642 }
Owen Taylor3473f882001-02-23 17:55:21 +00006643 return(len);
6644}
6645
6646/**
6647 * xmlBufferGrow:
6648 * @buf: the buffer
6649 * @len: the minimum free size to allocate
6650 *
6651 * Grow the available space of an XML buffer.
6652 *
6653 * Returns the new available space or -1 in case of error
6654 */
6655int
6656xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6657 int size;
6658 xmlChar *newbuf;
6659
Daniel Veillard3d97e662004-11-04 10:49:00 +00006660 if (buf == NULL) return(-1);
6661
Daniel Veillard53350552003-09-18 13:35:51 +00006662 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006663 if (len + buf->use < buf->size) return(0);
6664
William M. Brack30fe43f2004-07-26 18:00:58 +00006665/*
6666 * Windows has a BIG problem on realloc timing, so we try to double
6667 * the buffer size (if that's enough) (bug 146697)
6668 */
6669#ifdef WIN32
6670 if (buf->size > len)
6671 size = buf->size * 2;
6672 else
6673 size = buf->use + len + 100;
6674#else
Owen Taylor3473f882001-02-23 17:55:21 +00006675 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00006676#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006677
6678 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006679 if (newbuf == NULL) {
6680 xmlTreeErrMemory("growing buffer");
6681 return(-1);
6682 }
Owen Taylor3473f882001-02-23 17:55:21 +00006683 buf->content = newbuf;
6684 buf->size = size;
6685 return(buf->size - buf->use);
6686}
6687
6688/**
6689 * xmlBufferDump:
6690 * @file: the file output
6691 * @buf: the buffer to dump
6692 *
6693 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006694 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006695 */
6696int
6697xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6698 int ret;
6699
6700 if (buf == NULL) {
6701#ifdef DEBUG_BUFFER
6702 xmlGenericError(xmlGenericErrorContext,
6703 "xmlBufferDump: buf == NULL\n");
6704#endif
6705 return(0);
6706 }
6707 if (buf->content == NULL) {
6708#ifdef DEBUG_BUFFER
6709 xmlGenericError(xmlGenericErrorContext,
6710 "xmlBufferDump: buf->content == NULL\n");
6711#endif
6712 return(0);
6713 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006714 if (file == NULL)
6715 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006716 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6717 return(ret);
6718}
6719
6720/**
6721 * xmlBufferContent:
6722 * @buf: the buffer
6723 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006724 * Function to extract the content of a buffer
6725 *
Owen Taylor3473f882001-02-23 17:55:21 +00006726 * Returns the internal content
6727 */
6728
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006729const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006730xmlBufferContent(const xmlBufferPtr buf)
6731{
6732 if(!buf)
6733 return NULL;
6734
6735 return buf->content;
6736}
6737
6738/**
6739 * xmlBufferLength:
6740 * @buf: the buffer
6741 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006742 * Function to get the length of a buffer
6743 *
Owen Taylor3473f882001-02-23 17:55:21 +00006744 * Returns the length of data in the internal content
6745 */
6746
6747int
6748xmlBufferLength(const xmlBufferPtr buf)
6749{
6750 if(!buf)
6751 return 0;
6752
6753 return buf->use;
6754}
6755
6756/**
6757 * xmlBufferResize:
6758 * @buf: the buffer to resize
6759 * @size: the desired size
6760 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006761 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006762 *
6763 * Returns 0 in case of problems, 1 otherwise
6764 */
6765int
6766xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6767{
6768 unsigned int newSize;
6769 xmlChar* rebuf = NULL;
6770
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006771 if (buf == NULL)
6772 return(0);
6773
Daniel Veillard53350552003-09-18 13:35:51 +00006774 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6775
Owen Taylor3473f882001-02-23 17:55:21 +00006776 /* Don't resize if we don't have to */
6777 if (size < buf->size)
6778 return 1;
6779
6780 /* figure out new size */
6781 switch (buf->alloc){
6782 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillardbf629492004-04-20 22:20:59 +00006783 /*take care of empty case*/
6784 newSize = (buf->size ? buf->size*2 : size + 10);
Owen Taylor3473f882001-02-23 17:55:21 +00006785 while (size > newSize) newSize *= 2;
6786 break;
6787 case XML_BUFFER_ALLOC_EXACT:
6788 newSize = size+10;
6789 break;
6790 default:
6791 newSize = size+10;
6792 break;
6793 }
6794
6795 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006796 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006797 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006798 rebuf = (xmlChar *) xmlRealloc(buf->content,
6799 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006800 } else {
6801 /*
6802 * if we are reallocating a buffer far from being full, it's
6803 * better to make a new allocation and copy only the used range
6804 * and free the old one.
6805 */
6806 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6807 if (rebuf != NULL) {
6808 memcpy(rebuf, buf->content, buf->use);
6809 xmlFree(buf->content);
William M. Brack42331a92004-07-29 07:07:16 +00006810 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006811 }
6812 }
Owen Taylor3473f882001-02-23 17:55:21 +00006813 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006814 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006815 return 0;
6816 }
6817 buf->content = rebuf;
6818 buf->size = newSize;
6819
6820 return 1;
6821}
6822
6823/**
6824 * xmlBufferAdd:
6825 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006826 * @str: the #xmlChar string
6827 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006828 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006829 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006830 * str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006831 *
6832 * Returns 0 successful, a positive error code number otherwise
6833 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006834 */
William M. Bracka3215c72004-07-31 16:24:01 +00006835int
Owen Taylor3473f882001-02-23 17:55:21 +00006836xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6837 unsigned int needSize;
6838
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006839 if ((str == NULL) || (buf == NULL)) {
William M. Bracka3215c72004-07-31 16:24:01 +00006840 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006841 }
William M. Bracka3215c72004-07-31 16:24:01 +00006842 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006843 if (len < -1) {
6844#ifdef DEBUG_BUFFER
6845 xmlGenericError(xmlGenericErrorContext,
6846 "xmlBufferAdd: len < 0\n");
6847#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006848 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006849 }
William M. Bracka3215c72004-07-31 16:24:01 +00006850 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006851
6852 if (len < 0)
6853 len = xmlStrlen(str);
6854
William M. Bracka3215c72004-07-31 16:24:01 +00006855 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006856
6857 needSize = buf->use + len + 2;
6858 if (needSize > buf->size){
6859 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006860 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006861 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006862 }
6863 }
6864
6865 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6866 buf->use += len;
6867 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006868 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006869}
6870
6871/**
6872 * xmlBufferAddHead:
6873 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006874 * @str: the #xmlChar string
6875 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006876 *
6877 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006878 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006879 *
6880 * Returns 0 successful, a positive error code number otherwise
6881 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006882 */
William M. Bracka3215c72004-07-31 16:24:01 +00006883int
Owen Taylor3473f882001-02-23 17:55:21 +00006884xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6885 unsigned int needSize;
6886
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006887 if (buf == NULL)
6888 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00006889 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006890 if (str == NULL) {
6891#ifdef DEBUG_BUFFER
6892 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006893 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006894#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006895 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006896 }
6897 if (len < -1) {
6898#ifdef DEBUG_BUFFER
6899 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006900 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006901#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006902 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006903 }
William M. Bracka3215c72004-07-31 16:24:01 +00006904 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006905
6906 if (len < 0)
6907 len = xmlStrlen(str);
6908
William M. Bracka3215c72004-07-31 16:24:01 +00006909 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006910
6911 needSize = buf->use + len + 2;
6912 if (needSize > buf->size){
6913 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006914 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006915 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006916 }
6917 }
6918
6919 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6920 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6921 buf->use += len;
6922 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006923 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006924}
6925
6926/**
6927 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00006928 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00006929 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006930 *
6931 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00006932 *
6933 * Returns 0 successful, a positive error code number otherwise
6934 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006935 */
William M. Bracka3215c72004-07-31 16:24:01 +00006936int
Owen Taylor3473f882001-02-23 17:55:21 +00006937xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006938 if (buf == NULL)
6939 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00006940 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
6941 if (str == NULL) return -1;
6942 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00006943}
6944
6945/**
6946 * xmlBufferCCat:
6947 * @buf: the buffer to dump
6948 * @str: the C char string
6949 *
6950 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00006951 *
6952 * Returns 0 successful, a positive error code number otherwise
6953 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006954 */
William M. Bracka3215c72004-07-31 16:24:01 +00006955int
Owen Taylor3473f882001-02-23 17:55:21 +00006956xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6957 const char *cur;
6958
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006959 if (buf == NULL)
6960 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00006961 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006962 if (str == NULL) {
6963#ifdef DEBUG_BUFFER
6964 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006965 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006966#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006967 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006968 }
6969 for (cur = str;*cur != 0;cur++) {
6970 if (buf->use + 10 >= buf->size) {
6971 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006972 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006973 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006974 }
6975 }
6976 buf->content[buf->use++] = *cur;
6977 }
6978 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006979 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006980}
6981
6982/**
6983 * xmlBufferWriteCHAR:
6984 * @buf: the XML buffer
6985 * @string: the string to add
6986 *
6987 * routine which manages and grows an output buffer. This one adds
6988 * xmlChars at the end of the buffer.
6989 */
6990void
Daniel Veillard53350552003-09-18 13:35:51 +00006991xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006992 if (buf == NULL)
6993 return;
Daniel Veillard53350552003-09-18 13:35:51 +00006994 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006995 xmlBufferCat(buf, string);
6996}
6997
6998/**
6999 * xmlBufferWriteChar:
7000 * @buf: the XML buffer output
7001 * @string: the string to add
7002 *
7003 * routine which manage and grows an output buffer. This one add
7004 * C chars at the end of the array.
7005 */
7006void
7007xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007008 if (buf == NULL)
7009 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007010 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007011 xmlBufferCCat(buf, string);
7012}
7013
7014
7015/**
7016 * xmlBufferWriteQuotedString:
7017 * @buf: the XML buffer output
7018 * @string: the string to add
7019 *
7020 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00007021 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00007022 * quote or double-quotes internally
7023 */
7024void
7025xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00007026 const xmlChar *cur, *base;
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007027 if (buf == NULL)
7028 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007029 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00007030 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00007031 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00007032#ifdef DEBUG_BUFFER
7033 xmlGenericError(xmlGenericErrorContext,
7034 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7035#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00007036 xmlBufferCCat(buf, "\"");
7037 base = cur = string;
7038 while(*cur != 0){
7039 if(*cur == '"'){
7040 if (base != cur)
7041 xmlBufferAdd(buf, base, cur - base);
7042 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7043 cur++;
7044 base = cur;
7045 }
7046 else {
7047 cur++;
7048 }
7049 }
7050 if (base != cur)
7051 xmlBufferAdd(buf, base, cur - base);
7052 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007053 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007054 else{
7055 xmlBufferCCat(buf, "\'");
7056 xmlBufferCat(buf, string);
7057 xmlBufferCCat(buf, "\'");
7058 }
Owen Taylor3473f882001-02-23 17:55:21 +00007059 } else {
7060 xmlBufferCCat(buf, "\"");
7061 xmlBufferCat(buf, string);
7062 xmlBufferCCat(buf, "\"");
7063 }
7064}
7065
7066
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007067/**
7068 * xmlGetDocCompressMode:
7069 * @doc: the document
7070 *
7071 * get the compression ratio for a document, ZLIB based
7072 * Returns 0 (uncompressed) to 9 (max compression)
7073 */
7074int
7075xmlGetDocCompressMode (xmlDocPtr doc) {
7076 if (doc == NULL) return(-1);
7077 return(doc->compression);
7078}
7079
7080/**
7081 * xmlSetDocCompressMode:
7082 * @doc: the document
7083 * @mode: the compression ratio
7084 *
7085 * set the compression ratio for a document, ZLIB based
7086 * Correct values: 0 (uncompressed) to 9 (max compression)
7087 */
7088void
7089xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7090 if (doc == NULL) return;
7091 if (mode < 0) doc->compression = 0;
7092 else if (mode > 9) doc->compression = 9;
7093 else doc->compression = mode;
7094}
7095
7096/**
7097 * xmlGetCompressMode:
7098 *
7099 * get the default compression mode used, ZLIB based.
7100 * Returns 0 (uncompressed) to 9 (max compression)
7101 */
7102int
7103xmlGetCompressMode(void)
7104{
7105 return (xmlCompressMode);
7106}
7107
7108/**
7109 * xmlSetCompressMode:
7110 * @mode: the compression ratio
7111 *
7112 * set the default compression mode used, ZLIB based
7113 * Correct values: 0 (uncompressed) to 9 (max compression)
7114 */
7115void
7116xmlSetCompressMode(int mode) {
7117 if (mode < 0) xmlCompressMode = 0;
7118 else if (mode > 9) xmlCompressMode = 9;
7119 else xmlCompressMode = mode;
7120}
7121