blob: 7b88beb9eed0fd0639300af66a8e65645577047e [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
William M. Brack21e4ef22005-01-02 09:53:13 +00001724#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
1725 defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00001726/**
1727 * xmlNewProp:
1728 * @node: the holding node
1729 * @name: the name of the attribute
1730 * @value: the value of the attribute
1731 *
1732 * Create a new property carried by a node.
1733 * Returns a pointer to the attribute
1734 */
1735xmlAttrPtr
1736xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1737 xmlAttrPtr cur;
1738 xmlDocPtr doc = NULL;
1739
1740 if (name == NULL) {
1741#ifdef DEBUG_TREE
1742 xmlGenericError(xmlGenericErrorContext,
1743 "xmlNewProp : name == NULL\n");
1744#endif
1745 return(NULL);
1746 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001747 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1748 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001749
1750 /*
1751 * Allocate a new property and fill the fields.
1752 */
1753 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1754 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001755 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001756 return(NULL);
1757 }
1758 memset(cur, 0, sizeof(xmlAttr));
1759 cur->type = XML_ATTRIBUTE_NODE;
1760
1761 cur->parent = node;
1762 if (node != NULL) {
1763 doc = node->doc;
1764 cur->doc = doc;
1765 }
Daniel Veillard03a53c32004-10-26 16:06:51 +00001766 if ((doc != NULL) && (doc->dict != NULL))
1767 cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
1768 else
1769 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00001770 if (value != NULL) {
1771 xmlChar *buffer;
1772 xmlNodePtr tmp;
1773
1774 buffer = xmlEncodeEntitiesReentrant(doc, value);
1775 cur->children = xmlStringGetNodeList(doc, buffer);
1776 cur->last = NULL;
1777 tmp = cur->children;
1778 while (tmp != NULL) {
1779 tmp->parent = (xmlNodePtr) cur;
1780 tmp->doc = doc;
1781 if (tmp->next == NULL)
1782 cur->last = tmp;
1783 tmp = tmp->next;
1784 }
1785 xmlFree(buffer);
1786 }
1787
1788 /*
1789 * Add it at the end to preserve parsing order ...
1790 */
1791 if (node != NULL) {
1792 if (node->properties == NULL) {
1793 node->properties = cur;
1794 } else {
1795 xmlAttrPtr prev = node->properties;
1796
1797 while (prev->next != NULL) prev = prev->next;
1798 prev->next = cur;
1799 cur->prev = prev;
1800 }
1801 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001802
Daniel Veillarda880b122003-04-21 21:36:41 +00001803 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001804 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001805 return(cur);
1806}
Daniel Veillard652327a2003-09-29 18:02:38 +00001807#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001808
1809/**
1810 * xmlNewNsProp:
1811 * @node: the holding node
1812 * @ns: the namespace
1813 * @name: the name of the attribute
1814 * @value: the value of the attribute
1815 *
1816 * Create a new property tagged with a namespace and carried by a node.
1817 * Returns a pointer to the attribute
1818 */
1819xmlAttrPtr
1820xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1821 const xmlChar *value) {
1822 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001823 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001824
1825 if (name == NULL) {
1826#ifdef DEBUG_TREE
1827 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001828 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001829#endif
1830 return(NULL);
1831 }
1832
1833 /*
1834 * Allocate a new property and fill the fields.
1835 */
1836 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1837 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001838 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001839 return(NULL);
1840 }
1841 memset(cur, 0, sizeof(xmlAttr));
1842 cur->type = XML_ATTRIBUTE_NODE;
1843
1844 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001845 if (node != NULL) {
1846 doc = node->doc;
1847 cur->doc = doc;
1848 }
Owen Taylor3473f882001-02-23 17:55:21 +00001849 cur->ns = ns;
Daniel Veillard03a53c32004-10-26 16:06:51 +00001850 if ((doc != NULL) && (doc->dict != NULL))
1851 cur->name = xmlDictLookup(doc->dict, name, -1);
1852 else
1853 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00001854 if (value != NULL) {
1855 xmlChar *buffer;
1856 xmlNodePtr tmp;
1857
Daniel Veillarda682b212001-06-07 19:59:42 +00001858 buffer = xmlEncodeEntitiesReentrant(doc, value);
1859 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001860 cur->last = NULL;
1861 tmp = cur->children;
1862 while (tmp != NULL) {
1863 tmp->parent = (xmlNodePtr) cur;
1864 if (tmp->next == NULL)
1865 cur->last = tmp;
1866 tmp = tmp->next;
1867 }
1868 xmlFree(buffer);
1869 }
1870
1871 /*
1872 * Add it at the end to preserve parsing order ...
1873 */
1874 if (node != NULL) {
1875 if (node->properties == NULL) {
1876 node->properties = cur;
1877 } else {
1878 xmlAttrPtr prev = node->properties;
1879
1880 while (prev->next != NULL) prev = prev->next;
1881 prev->next = cur;
1882 cur->prev = prev;
1883 }
1884 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001885
Daniel Veillarda880b122003-04-21 21:36:41 +00001886 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001887 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001888 return(cur);
1889}
1890
1891/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001892 * xmlNewNsPropEatName:
1893 * @node: the holding node
1894 * @ns: the namespace
1895 * @name: the name of the attribute
1896 * @value: the value of the attribute
1897 *
1898 * Create a new property tagged with a namespace and carried by a node.
1899 * Returns a pointer to the attribute
1900 */
1901xmlAttrPtr
1902xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1903 const xmlChar *value) {
1904 xmlAttrPtr cur;
1905 xmlDocPtr doc = NULL;
1906
1907 if (name == NULL) {
1908#ifdef DEBUG_TREE
1909 xmlGenericError(xmlGenericErrorContext,
1910 "xmlNewNsPropEatName : name == NULL\n");
1911#endif
1912 return(NULL);
1913 }
1914
1915 /*
1916 * Allocate a new property and fill the fields.
1917 */
1918 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1919 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001920 xmlTreeErrMemory("building attribute");
Daniel Veillard46de64e2002-05-29 08:21:33 +00001921 return(NULL);
1922 }
1923 memset(cur, 0, sizeof(xmlAttr));
1924 cur->type = XML_ATTRIBUTE_NODE;
1925
1926 cur->parent = node;
1927 if (node != NULL) {
1928 doc = node->doc;
1929 cur->doc = doc;
1930 }
1931 cur->ns = ns;
1932 cur->name = name;
1933 if (value != NULL) {
1934 xmlChar *buffer;
1935 xmlNodePtr tmp;
1936
1937 buffer = xmlEncodeEntitiesReentrant(doc, value);
1938 cur->children = xmlStringGetNodeList(doc, buffer);
1939 cur->last = NULL;
1940 tmp = cur->children;
1941 while (tmp != NULL) {
1942 tmp->parent = (xmlNodePtr) cur;
1943 if (tmp->next == NULL)
1944 cur->last = tmp;
1945 tmp = tmp->next;
1946 }
1947 xmlFree(buffer);
1948 }
1949
1950 /*
1951 * Add it at the end to preserve parsing order ...
1952 */
1953 if (node != NULL) {
1954 if (node->properties == NULL) {
1955 node->properties = cur;
1956 } else {
1957 xmlAttrPtr prev = node->properties;
1958
1959 while (prev->next != NULL) prev = prev->next;
1960 prev->next = cur;
1961 cur->prev = prev;
1962 }
1963 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001964
Daniel Veillarda880b122003-04-21 21:36:41 +00001965 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001966 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001967 return(cur);
1968}
1969
1970/**
Owen Taylor3473f882001-02-23 17:55:21 +00001971 * xmlNewDocProp:
1972 * @doc: the document
1973 * @name: the name of the attribute
1974 * @value: the value of the attribute
1975 *
1976 * Create a new property carried by a document.
1977 * Returns a pointer to the attribute
1978 */
1979xmlAttrPtr
1980xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1981 xmlAttrPtr cur;
1982
1983 if (name == NULL) {
1984#ifdef DEBUG_TREE
1985 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001986 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001987#endif
1988 return(NULL);
1989 }
1990
1991 /*
1992 * Allocate a new property and fill the fields.
1993 */
1994 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1995 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001996 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001997 return(NULL);
1998 }
1999 memset(cur, 0, sizeof(xmlAttr));
2000 cur->type = XML_ATTRIBUTE_NODE;
2001
Daniel Veillard03a53c32004-10-26 16:06:51 +00002002 if ((doc != NULL) && (doc->dict != NULL))
2003 cur->name = xmlDictLookup(doc->dict, name, -1);
2004 else
2005 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00002006 cur->doc = doc;
2007 if (value != NULL) {
2008 xmlNodePtr tmp;
2009
2010 cur->children = xmlStringGetNodeList(doc, value);
2011 cur->last = NULL;
2012
2013 tmp = cur->children;
2014 while (tmp != NULL) {
2015 tmp->parent = (xmlNodePtr) cur;
2016 if (tmp->next == NULL)
2017 cur->last = tmp;
2018 tmp = tmp->next;
2019 }
2020 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002021
Daniel Veillarda880b122003-04-21 21:36:41 +00002022 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002023 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002024 return(cur);
2025}
2026
2027/**
2028 * xmlFreePropList:
2029 * @cur: the first property in the list
2030 *
2031 * Free a property and all its siblings, all the children are freed too.
2032 */
2033void
2034xmlFreePropList(xmlAttrPtr cur) {
2035 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002036 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002037 while (cur != NULL) {
2038 next = cur->next;
2039 xmlFreeProp(cur);
2040 cur = next;
2041 }
2042}
2043
2044/**
2045 * xmlFreeProp:
2046 * @cur: an attribute
2047 *
2048 * Free one attribute, all the content is freed too
2049 */
2050void
2051xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002052 xmlDictPtr dict = NULL;
2053 if (cur == NULL) return;
2054
2055 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002056
Daniel Veillarda880b122003-04-21 21:36:41 +00002057 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002058 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
2059
Owen Taylor3473f882001-02-23 17:55:21 +00002060 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00002061 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
2062 ((cur->parent->doc->intSubset != NULL) ||
2063 (cur->parent->doc->extSubset != NULL))) {
2064 if (xmlIsID(cur->parent->doc, cur->parent, cur))
2065 xmlRemoveID(cur->parent->doc, cur);
2066 }
Owen Taylor3473f882001-02-23 17:55:21 +00002067 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002068 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002069 xmlFree(cur);
2070}
2071
Daniel Veillard652327a2003-09-29 18:02:38 +00002072#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002073/**
2074 * xmlRemoveProp:
2075 * @cur: an attribute
2076 *
2077 * Unlink and free one attribute, all the content is freed too
2078 * Note this doesn't work for namespace definition attributes
2079 *
2080 * Returns 0 if success and -1 in case of error.
2081 */
2082int
2083xmlRemoveProp(xmlAttrPtr cur) {
2084 xmlAttrPtr tmp;
2085 if (cur == NULL) {
2086#ifdef DEBUG_TREE
2087 xmlGenericError(xmlGenericErrorContext,
2088 "xmlRemoveProp : cur == NULL\n");
2089#endif
2090 return(-1);
2091 }
2092 if (cur->parent == NULL) {
2093#ifdef DEBUG_TREE
2094 xmlGenericError(xmlGenericErrorContext,
2095 "xmlRemoveProp : cur->parent == NULL\n");
2096#endif
2097 return(-1);
2098 }
2099 tmp = cur->parent->properties;
2100 if (tmp == cur) {
2101 cur->parent->properties = cur->next;
2102 xmlFreeProp(cur);
2103 return(0);
2104 }
2105 while (tmp != NULL) {
2106 if (tmp->next == cur) {
2107 tmp->next = cur->next;
2108 if (tmp->next != NULL)
2109 tmp->next->prev = tmp;
2110 xmlFreeProp(cur);
2111 return(0);
2112 }
2113 tmp = tmp->next;
2114 }
2115#ifdef DEBUG_TREE
2116 xmlGenericError(xmlGenericErrorContext,
2117 "xmlRemoveProp : attribute not owned by its node\n");
2118#endif
2119 return(-1);
2120}
Daniel Veillard652327a2003-09-29 18:02:38 +00002121#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002122
2123/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002124 * xmlNewDocPI:
2125 * @doc: the target document
Owen Taylor3473f882001-02-23 17:55:21 +00002126 * @name: the processing instruction name
2127 * @content: the PI content
2128 *
2129 * Creation of a processing instruction element.
2130 * Returns a pointer to the new node object.
2131 */
2132xmlNodePtr
Daniel Veillard03a53c32004-10-26 16:06:51 +00002133xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
Owen Taylor3473f882001-02-23 17:55:21 +00002134 xmlNodePtr cur;
2135
2136 if (name == NULL) {
2137#ifdef DEBUG_TREE
2138 xmlGenericError(xmlGenericErrorContext,
2139 "xmlNewPI : name == NULL\n");
2140#endif
2141 return(NULL);
2142 }
2143
2144 /*
2145 * Allocate a new node and fill the fields.
2146 */
2147 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2148 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002149 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002150 return(NULL);
2151 }
2152 memset(cur, 0, sizeof(xmlNode));
2153 cur->type = XML_PI_NODE;
2154
Daniel Veillard03a53c32004-10-26 16:06:51 +00002155 if ((doc != NULL) && (doc->dict != NULL))
2156 cur->name = xmlDictLookup(doc->dict, name, -1);
2157 else
2158 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00002159 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002160 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002161 }
Daniel Veillarda03e3652004-11-02 18:45:30 +00002162 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002163
Daniel Veillarda880b122003-04-21 21:36:41 +00002164 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002165 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002166 return(cur);
2167}
2168
2169/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002170 * xmlNewPI:
2171 * @name: the processing instruction name
2172 * @content: the PI content
2173 *
2174 * Creation of a processing instruction element.
2175 * Use xmlDocNewPI preferably to get string interning
2176 *
2177 * Returns a pointer to the new node object.
2178 */
2179xmlNodePtr
2180xmlNewPI(const xmlChar *name, const xmlChar *content) {
2181 return(xmlNewDocPI(NULL, name, content));
2182}
2183
2184/**
Owen Taylor3473f882001-02-23 17:55:21 +00002185 * xmlNewNode:
2186 * @ns: namespace if any
2187 * @name: the node name
2188 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002189 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002190 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002191 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2192 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002193 */
2194xmlNodePtr
2195xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2196 xmlNodePtr cur;
2197
2198 if (name == NULL) {
2199#ifdef DEBUG_TREE
2200 xmlGenericError(xmlGenericErrorContext,
2201 "xmlNewNode : name == NULL\n");
2202#endif
2203 return(NULL);
2204 }
2205
2206 /*
2207 * Allocate a new node and fill the fields.
2208 */
2209 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2210 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002211 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002212 return(NULL);
2213 }
2214 memset(cur, 0, sizeof(xmlNode));
2215 cur->type = XML_ELEMENT_NODE;
2216
2217 cur->name = xmlStrdup(name);
2218 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002219
Daniel Veillarda880b122003-04-21 21:36:41 +00002220 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002221 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002222 return(cur);
2223}
2224
2225/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002226 * xmlNewNodeEatName:
2227 * @ns: namespace if any
2228 * @name: the node name
2229 *
2230 * Creation of a new node element. @ns is optional (NULL).
2231 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002232 * Returns a pointer to the new node object, with pointer @name as
2233 * new node's name. Use xmlNewNode() if a copy of @name string is
2234 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002235 */
2236xmlNodePtr
2237xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2238 xmlNodePtr cur;
2239
2240 if (name == NULL) {
2241#ifdef DEBUG_TREE
2242 xmlGenericError(xmlGenericErrorContext,
2243 "xmlNewNode : name == NULL\n");
2244#endif
2245 return(NULL);
2246 }
2247
2248 /*
2249 * Allocate a new node and fill the fields.
2250 */
2251 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2252 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002253 xmlTreeErrMemory("building node");
Daniel Veillard46de64e2002-05-29 08:21:33 +00002254 return(NULL);
2255 }
2256 memset(cur, 0, sizeof(xmlNode));
2257 cur->type = XML_ELEMENT_NODE;
2258
2259 cur->name = name;
2260 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002261
Daniel Veillarda880b122003-04-21 21:36:41 +00002262 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002263 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002264 return(cur);
2265}
2266
2267/**
Owen Taylor3473f882001-02-23 17:55:21 +00002268 * xmlNewDocNode:
2269 * @doc: the document
2270 * @ns: namespace if any
2271 * @name: the node name
2272 * @content: the XML text content if any
2273 *
2274 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002275 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002276 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2277 * references, but XML special chars need to be escaped first by using
2278 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2279 * need entities support.
2280 *
2281 * Returns a pointer to the new node object.
2282 */
2283xmlNodePtr
2284xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2285 const xmlChar *name, const xmlChar *content) {
2286 xmlNodePtr cur;
2287
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002288 if ((doc != NULL) && (doc->dict != NULL))
Daniel Veillard03a53c32004-10-26 16:06:51 +00002289 cur = xmlNewNodeEatName(ns, (xmlChar *)
2290 xmlDictLookup(doc->dict, name, -1));
2291 else
2292 cur = xmlNewNode(ns, name);
Owen Taylor3473f882001-02-23 17:55:21 +00002293 if (cur != NULL) {
2294 cur->doc = doc;
2295 if (content != NULL) {
2296 cur->children = xmlStringGetNodeList(doc, content);
2297 UPDATE_LAST_CHILD_AND_PARENT(cur)
2298 }
2299 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002300
Owen Taylor3473f882001-02-23 17:55:21 +00002301 return(cur);
2302}
2303
Daniel Veillard46de64e2002-05-29 08:21:33 +00002304/**
2305 * xmlNewDocNodeEatName:
2306 * @doc: the document
2307 * @ns: namespace if any
2308 * @name: the node name
2309 * @content: the XML text content if any
2310 *
2311 * Creation of a new node element within a document. @ns and @content
2312 * are optional (NULL).
2313 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2314 * references, but XML special chars need to be escaped first by using
2315 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2316 * need entities support.
2317 *
2318 * Returns a pointer to the new node object.
2319 */
2320xmlNodePtr
2321xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2322 xmlChar *name, const xmlChar *content) {
2323 xmlNodePtr cur;
2324
2325 cur = xmlNewNodeEatName(ns, name);
2326 if (cur != NULL) {
2327 cur->doc = doc;
2328 if (content != NULL) {
2329 cur->children = xmlStringGetNodeList(doc, content);
2330 UPDATE_LAST_CHILD_AND_PARENT(cur)
2331 }
2332 }
2333 return(cur);
2334}
2335
Daniel Veillard652327a2003-09-29 18:02:38 +00002336#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002337/**
2338 * xmlNewDocRawNode:
2339 * @doc: the document
2340 * @ns: namespace if any
2341 * @name: the node name
2342 * @content: the text content if any
2343 *
2344 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002345 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002346 *
2347 * Returns a pointer to the new node object.
2348 */
2349xmlNodePtr
2350xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2351 const xmlChar *name, const xmlChar *content) {
2352 xmlNodePtr cur;
2353
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002354 cur = xmlNewDocNode(doc, ns, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002355 if (cur != NULL) {
2356 cur->doc = doc;
2357 if (content != NULL) {
2358 cur->children = xmlNewDocText(doc, content);
2359 UPDATE_LAST_CHILD_AND_PARENT(cur)
2360 }
2361 }
2362 return(cur);
2363}
2364
2365/**
2366 * xmlNewDocFragment:
2367 * @doc: the document owning the fragment
2368 *
2369 * Creation of a new Fragment node.
2370 * Returns a pointer to the new node object.
2371 */
2372xmlNodePtr
2373xmlNewDocFragment(xmlDocPtr doc) {
2374 xmlNodePtr cur;
2375
2376 /*
2377 * Allocate a new DocumentFragment node and fill the fields.
2378 */
2379 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2380 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002381 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002382 return(NULL);
2383 }
2384 memset(cur, 0, sizeof(xmlNode));
2385 cur->type = XML_DOCUMENT_FRAG_NODE;
2386
2387 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002388
Daniel Veillarda880b122003-04-21 21:36:41 +00002389 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002390 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002391 return(cur);
2392}
Daniel Veillard652327a2003-09-29 18:02:38 +00002393#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002394
2395/**
2396 * xmlNewText:
2397 * @content: the text content
2398 *
2399 * Creation of a new text node.
2400 * Returns a pointer to the new node object.
2401 */
2402xmlNodePtr
2403xmlNewText(const xmlChar *content) {
2404 xmlNodePtr cur;
2405
2406 /*
2407 * Allocate a new node and fill the fields.
2408 */
2409 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2410 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002411 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002412 return(NULL);
2413 }
2414 memset(cur, 0, sizeof(xmlNode));
2415 cur->type = XML_TEXT_NODE;
2416
2417 cur->name = xmlStringText;
2418 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002419 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002420 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002421
Daniel Veillarda880b122003-04-21 21:36:41 +00002422 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002423 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002424 return(cur);
2425}
2426
Daniel Veillard652327a2003-09-29 18:02:38 +00002427#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002428/**
2429 * xmlNewTextChild:
2430 * @parent: the parent node
2431 * @ns: a namespace if any
2432 * @name: the name of the child
2433 * @content: the text content of the child if any.
2434 *
2435 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002436 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2437 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002438 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002439 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2440 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2441 * reserved XML chars that might appear in @content, such as the ampersand,
2442 * greater-than or less-than signs, are automatically replaced by their XML
2443 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002444 *
2445 * Returns a pointer to the new node object.
2446 */
2447xmlNodePtr
2448xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2449 const xmlChar *name, const xmlChar *content) {
2450 xmlNodePtr cur, prev;
2451
2452 if (parent == NULL) {
2453#ifdef DEBUG_TREE
2454 xmlGenericError(xmlGenericErrorContext,
2455 "xmlNewTextChild : parent == NULL\n");
2456#endif
2457 return(NULL);
2458 }
2459
2460 if (name == NULL) {
2461#ifdef DEBUG_TREE
2462 xmlGenericError(xmlGenericErrorContext,
2463 "xmlNewTextChild : name == NULL\n");
2464#endif
2465 return(NULL);
2466 }
2467
2468 /*
2469 * Allocate a new node
2470 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002471 if (parent->type == XML_ELEMENT_NODE) {
2472 if (ns == NULL)
2473 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2474 else
2475 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2476 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2477 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2478 if (ns == NULL)
2479 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2480 else
2481 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2482 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2483 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2484 } else {
2485 return(NULL);
2486 }
Owen Taylor3473f882001-02-23 17:55:21 +00002487 if (cur == NULL) return(NULL);
2488
2489 /*
2490 * add the new element at the end of the children list.
2491 */
2492 cur->type = XML_ELEMENT_NODE;
2493 cur->parent = parent;
2494 cur->doc = parent->doc;
2495 if (parent->children == NULL) {
2496 parent->children = cur;
2497 parent->last = cur;
2498 } else {
2499 prev = parent->last;
2500 prev->next = cur;
2501 cur->prev = prev;
2502 parent->last = cur;
2503 }
2504
2505 return(cur);
2506}
Daniel Veillard652327a2003-09-29 18:02:38 +00002507#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002508
2509/**
2510 * xmlNewCharRef:
2511 * @doc: the document
2512 * @name: the char ref string, starting with # or "&# ... ;"
2513 *
2514 * Creation of a new character reference node.
2515 * Returns a pointer to the new node object.
2516 */
2517xmlNodePtr
2518xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2519 xmlNodePtr cur;
2520
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002521 if (name == NULL)
2522 return(NULL);
2523
Owen Taylor3473f882001-02-23 17:55:21 +00002524 /*
2525 * Allocate a new node and fill the fields.
2526 */
2527 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2528 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002529 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002530 return(NULL);
2531 }
2532 memset(cur, 0, sizeof(xmlNode));
2533 cur->type = XML_ENTITY_REF_NODE;
2534
2535 cur->doc = doc;
2536 if (name[0] == '&') {
2537 int len;
2538 name++;
2539 len = xmlStrlen(name);
2540 if (name[len - 1] == ';')
2541 cur->name = xmlStrndup(name, len - 1);
2542 else
2543 cur->name = xmlStrndup(name, len);
2544 } else
2545 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002546
Daniel Veillarda880b122003-04-21 21:36:41 +00002547 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002548 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002549 return(cur);
2550}
2551
2552/**
2553 * xmlNewReference:
2554 * @doc: the document
2555 * @name: the reference name, or the reference string with & and ;
2556 *
2557 * Creation of a new reference node.
2558 * Returns a pointer to the new node object.
2559 */
2560xmlNodePtr
2561xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2562 xmlNodePtr cur;
2563 xmlEntityPtr ent;
2564
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002565 if (name == NULL)
2566 return(NULL);
2567
Owen Taylor3473f882001-02-23 17:55:21 +00002568 /*
2569 * Allocate a new node and fill the fields.
2570 */
2571 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2572 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002573 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002574 return(NULL);
2575 }
2576 memset(cur, 0, sizeof(xmlNode));
2577 cur->type = XML_ENTITY_REF_NODE;
2578
2579 cur->doc = doc;
2580 if (name[0] == '&') {
2581 int len;
2582 name++;
2583 len = xmlStrlen(name);
2584 if (name[len - 1] == ';')
2585 cur->name = xmlStrndup(name, len - 1);
2586 else
2587 cur->name = xmlStrndup(name, len);
2588 } else
2589 cur->name = xmlStrdup(name);
2590
2591 ent = xmlGetDocEntity(doc, cur->name);
2592 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002593 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002594 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002595 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002596 * updated. Not sure if this is 100% correct.
2597 * -George
2598 */
2599 cur->children = (xmlNodePtr) ent;
2600 cur->last = (xmlNodePtr) ent;
2601 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002602
Daniel Veillarda880b122003-04-21 21:36:41 +00002603 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002604 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002605 return(cur);
2606}
2607
2608/**
2609 * xmlNewDocText:
2610 * @doc: the document
2611 * @content: the text content
2612 *
2613 * Creation of a new text node within a document.
2614 * Returns a pointer to the new node object.
2615 */
2616xmlNodePtr
2617xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2618 xmlNodePtr cur;
2619
2620 cur = xmlNewText(content);
2621 if (cur != NULL) cur->doc = doc;
2622 return(cur);
2623}
2624
2625/**
2626 * xmlNewTextLen:
2627 * @content: the text content
2628 * @len: the text len.
2629 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002630 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002631 * Returns a pointer to the new node object.
2632 */
2633xmlNodePtr
2634xmlNewTextLen(const xmlChar *content, int len) {
2635 xmlNodePtr cur;
2636
2637 /*
2638 * Allocate a new node and fill the fields.
2639 */
2640 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2641 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002642 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002643 return(NULL);
2644 }
2645 memset(cur, 0, sizeof(xmlNode));
2646 cur->type = XML_TEXT_NODE;
2647
2648 cur->name = xmlStringText;
2649 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002650 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002651 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002652
Daniel Veillarda880b122003-04-21 21:36:41 +00002653 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002654 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002655 return(cur);
2656}
2657
2658/**
2659 * xmlNewDocTextLen:
2660 * @doc: the document
2661 * @content: the text content
2662 * @len: the text len.
2663 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002664 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002665 * text node pertain to a given document.
2666 * Returns a pointer to the new node object.
2667 */
2668xmlNodePtr
2669xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2670 xmlNodePtr cur;
2671
2672 cur = xmlNewTextLen(content, len);
2673 if (cur != NULL) cur->doc = doc;
2674 return(cur);
2675}
2676
2677/**
2678 * xmlNewComment:
2679 * @content: the comment content
2680 *
2681 * Creation of a new node containing a comment.
2682 * Returns a pointer to the new node object.
2683 */
2684xmlNodePtr
2685xmlNewComment(const xmlChar *content) {
2686 xmlNodePtr cur;
2687
2688 /*
2689 * Allocate a new node and fill the fields.
2690 */
2691 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2692 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002693 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002694 return(NULL);
2695 }
2696 memset(cur, 0, sizeof(xmlNode));
2697 cur->type = XML_COMMENT_NODE;
2698
2699 cur->name = xmlStringComment;
2700 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002701 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002702 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002703
Daniel Veillarda880b122003-04-21 21:36:41 +00002704 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002705 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002706 return(cur);
2707}
2708
2709/**
2710 * xmlNewCDataBlock:
2711 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002712 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002713 * @len: the length of the block
2714 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002715 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002716 * Returns a pointer to the new node object.
2717 */
2718xmlNodePtr
2719xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2720 xmlNodePtr cur;
2721
2722 /*
2723 * Allocate a new node and fill the fields.
2724 */
2725 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2726 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002727 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002728 return(NULL);
2729 }
2730 memset(cur, 0, sizeof(xmlNode));
2731 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002732 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002733
2734 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002735 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002736 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002737
Daniel Veillarda880b122003-04-21 21:36:41 +00002738 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002739 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002740 return(cur);
2741}
2742
2743/**
2744 * xmlNewDocComment:
2745 * @doc: the document
2746 * @content: the comment content
2747 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002748 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002749 * Returns a pointer to the new node object.
2750 */
2751xmlNodePtr
2752xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2753 xmlNodePtr cur;
2754
2755 cur = xmlNewComment(content);
2756 if (cur != NULL) cur->doc = doc;
2757 return(cur);
2758}
2759
2760/**
2761 * xmlSetTreeDoc:
2762 * @tree: the top element
2763 * @doc: the document
2764 *
2765 * update all nodes under the tree to point to the right document
2766 */
2767void
2768xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002769 xmlAttrPtr prop;
2770
Owen Taylor3473f882001-02-23 17:55:21 +00002771 if (tree == NULL)
2772 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002773 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002774 if(tree->type == XML_ELEMENT_NODE) {
2775 prop = tree->properties;
2776 while (prop != NULL) {
2777 prop->doc = doc;
2778 xmlSetListDoc(prop->children, doc);
2779 prop = prop->next;
2780 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002781 }
Owen Taylor3473f882001-02-23 17:55:21 +00002782 if (tree->children != NULL)
2783 xmlSetListDoc(tree->children, doc);
2784 tree->doc = doc;
2785 }
2786}
2787
2788/**
2789 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002790 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002791 * @doc: the document
2792 *
2793 * update all nodes in the list to point to the right document
2794 */
2795void
2796xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2797 xmlNodePtr cur;
2798
2799 if (list == NULL)
2800 return;
2801 cur = list;
2802 while (cur != NULL) {
2803 if (cur->doc != doc)
2804 xmlSetTreeDoc(cur, doc);
2805 cur = cur->next;
2806 }
2807}
2808
Daniel Veillard2156d432004-03-04 15:59:36 +00002809#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002810/**
2811 * xmlNewChild:
2812 * @parent: the parent node
2813 * @ns: a namespace if any
2814 * @name: the name of the child
2815 * @content: the XML content of the child if any.
2816 *
2817 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002818 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2819 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002820 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002821 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2822 * references. XML special chars must be escaped first by using
2823 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002824 *
2825 * Returns a pointer to the new node object.
2826 */
2827xmlNodePtr
2828xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2829 const xmlChar *name, const xmlChar *content) {
2830 xmlNodePtr cur, prev;
2831
2832 if (parent == NULL) {
2833#ifdef DEBUG_TREE
2834 xmlGenericError(xmlGenericErrorContext,
2835 "xmlNewChild : parent == NULL\n");
2836#endif
2837 return(NULL);
2838 }
2839
2840 if (name == NULL) {
2841#ifdef DEBUG_TREE
2842 xmlGenericError(xmlGenericErrorContext,
2843 "xmlNewChild : name == NULL\n");
2844#endif
2845 return(NULL);
2846 }
2847
2848 /*
2849 * Allocate a new node
2850 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002851 if (parent->type == XML_ELEMENT_NODE) {
2852 if (ns == NULL)
2853 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2854 else
2855 cur = xmlNewDocNode(parent->doc, ns, name, content);
2856 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2857 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2858 if (ns == NULL)
2859 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2860 else
2861 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002862 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2863 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002864 } else {
2865 return(NULL);
2866 }
Owen Taylor3473f882001-02-23 17:55:21 +00002867 if (cur == NULL) return(NULL);
2868
2869 /*
2870 * add the new element at the end of the children list.
2871 */
2872 cur->type = XML_ELEMENT_NODE;
2873 cur->parent = parent;
2874 cur->doc = parent->doc;
2875 if (parent->children == NULL) {
2876 parent->children = cur;
2877 parent->last = cur;
2878 } else {
2879 prev = parent->last;
2880 prev->next = cur;
2881 cur->prev = prev;
2882 parent->last = cur;
2883 }
2884
2885 return(cur);
2886}
Daniel Veillard652327a2003-09-29 18:02:38 +00002887#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002888
2889/**
2890 * xmlAddNextSibling:
2891 * @cur: the child node
2892 * @elem: the new node
2893 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002894 * Add a new node @elem as the next sibling of @cur
2895 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002896 * first unlinked from its existing context.
2897 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002898 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2899 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002900 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002901 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002902 */
2903xmlNodePtr
2904xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2905 if (cur == NULL) {
2906#ifdef DEBUG_TREE
2907 xmlGenericError(xmlGenericErrorContext,
2908 "xmlAddNextSibling : cur == NULL\n");
2909#endif
2910 return(NULL);
2911 }
2912 if (elem == NULL) {
2913#ifdef DEBUG_TREE
2914 xmlGenericError(xmlGenericErrorContext,
2915 "xmlAddNextSibling : elem == NULL\n");
2916#endif
2917 return(NULL);
2918 }
2919
2920 xmlUnlinkNode(elem);
2921
2922 if (elem->type == XML_TEXT_NODE) {
2923 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002924 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002925 xmlFreeNode(elem);
2926 return(cur);
2927 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002928 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2929 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002930 xmlChar *tmp;
2931
2932 tmp = xmlStrdup(elem->content);
2933 tmp = xmlStrcat(tmp, cur->next->content);
2934 xmlNodeSetContent(cur->next, tmp);
2935 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002936 xmlFreeNode(elem);
2937 return(cur->next);
2938 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002939 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2940 /* check if an attribute with the same name exists */
2941 xmlAttrPtr attr;
2942
2943 if (elem->ns == NULL)
2944 attr = xmlHasProp(cur->parent, elem->name);
2945 else
2946 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2947 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2948 /* different instance, destroy it (attributes must be unique) */
2949 xmlFreeProp(attr);
2950 }
Owen Taylor3473f882001-02-23 17:55:21 +00002951 }
2952
2953 if (elem->doc != cur->doc) {
2954 xmlSetTreeDoc(elem, cur->doc);
2955 }
2956 elem->parent = cur->parent;
2957 elem->prev = cur;
2958 elem->next = cur->next;
2959 cur->next = elem;
2960 if (elem->next != NULL)
2961 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002962 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002963 elem->parent->last = elem;
2964 return(elem);
2965}
2966
William M. Brack21e4ef22005-01-02 09:53:13 +00002967#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
2968 defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002969/**
2970 * xmlAddPrevSibling:
2971 * @cur: the child node
2972 * @elem: the new node
2973 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002974 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002975 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002976 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002977 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002978 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2979 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002980 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002981 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002982 */
2983xmlNodePtr
2984xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2985 if (cur == NULL) {
2986#ifdef DEBUG_TREE
2987 xmlGenericError(xmlGenericErrorContext,
2988 "xmlAddPrevSibling : cur == NULL\n");
2989#endif
2990 return(NULL);
2991 }
2992 if (elem == NULL) {
2993#ifdef DEBUG_TREE
2994 xmlGenericError(xmlGenericErrorContext,
2995 "xmlAddPrevSibling : elem == NULL\n");
2996#endif
2997 return(NULL);
2998 }
2999
3000 xmlUnlinkNode(elem);
3001
3002 if (elem->type == XML_TEXT_NODE) {
3003 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00003004 xmlChar *tmp;
3005
3006 tmp = xmlStrdup(elem->content);
3007 tmp = xmlStrcat(tmp, cur->content);
3008 xmlNodeSetContent(cur, tmp);
3009 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00003010 xmlFreeNode(elem);
3011 return(cur);
3012 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00003013 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
3014 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003015 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003016 xmlFreeNode(elem);
3017 return(cur->prev);
3018 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003019 } else if (elem->type == XML_ATTRIBUTE_NODE) {
3020 /* check if an attribute with the same name exists */
3021 xmlAttrPtr attr;
3022
3023 if (elem->ns == NULL)
3024 attr = xmlHasProp(cur->parent, elem->name);
3025 else
3026 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
3027 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
3028 /* different instance, destroy it (attributes must be unique) */
3029 xmlFreeProp(attr);
3030 }
Owen Taylor3473f882001-02-23 17:55:21 +00003031 }
3032
3033 if (elem->doc != cur->doc) {
3034 xmlSetTreeDoc(elem, cur->doc);
3035 }
3036 elem->parent = cur->parent;
3037 elem->next = cur;
3038 elem->prev = cur->prev;
3039 cur->prev = elem;
3040 if (elem->prev != NULL)
3041 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003042 if (elem->parent != NULL) {
3043 if (elem->type == XML_ATTRIBUTE_NODE) {
3044 if (elem->parent->properties == (xmlAttrPtr) cur) {
3045 elem->parent->properties = (xmlAttrPtr) elem;
3046 }
3047 } else {
3048 if (elem->parent->children == cur) {
3049 elem->parent->children = elem;
3050 }
3051 }
3052 }
Owen Taylor3473f882001-02-23 17:55:21 +00003053 return(elem);
3054}
Daniel Veillard652327a2003-09-29 18:02:38 +00003055#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003056
3057/**
3058 * xmlAddSibling:
3059 * @cur: the child node
3060 * @elem: the new node
3061 *
3062 * Add a new element @elem to the list of siblings of @cur
3063 * merging adjacent TEXT nodes (@elem may be freed)
3064 * If the new element was already inserted in a document it is
3065 * first unlinked from its existing context.
3066 *
3067 * Returns the new element or NULL in case of error.
3068 */
3069xmlNodePtr
3070xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
3071 xmlNodePtr parent;
3072
3073 if (cur == NULL) {
3074#ifdef DEBUG_TREE
3075 xmlGenericError(xmlGenericErrorContext,
3076 "xmlAddSibling : cur == NULL\n");
3077#endif
3078 return(NULL);
3079 }
3080
3081 if (elem == NULL) {
3082#ifdef DEBUG_TREE
3083 xmlGenericError(xmlGenericErrorContext,
3084 "xmlAddSibling : elem == NULL\n");
3085#endif
3086 return(NULL);
3087 }
3088
3089 /*
3090 * Constant time is we can rely on the ->parent->last to find
3091 * the last sibling.
3092 */
3093 if ((cur->parent != NULL) &&
3094 (cur->parent->children != NULL) &&
3095 (cur->parent->last != NULL) &&
3096 (cur->parent->last->next == NULL)) {
3097 cur = cur->parent->last;
3098 } else {
3099 while (cur->next != NULL) cur = cur->next;
3100 }
3101
3102 xmlUnlinkNode(elem);
3103
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003104 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3105 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003106 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003107 xmlFreeNode(elem);
3108 return(cur);
3109 }
3110
3111 if (elem->doc != cur->doc) {
3112 xmlSetTreeDoc(elem, cur->doc);
3113 }
3114 parent = cur->parent;
3115 elem->prev = cur;
3116 elem->next = NULL;
3117 elem->parent = parent;
3118 cur->next = elem;
3119 if (parent != NULL)
3120 parent->last = elem;
3121
3122 return(elem);
3123}
3124
3125/**
3126 * xmlAddChildList:
3127 * @parent: the parent node
3128 * @cur: the first node in the list
3129 *
3130 * Add a list of node at the end of the child list of the parent
3131 * merging adjacent TEXT nodes (@cur may be freed)
3132 *
3133 * Returns the last child or NULL in case of error.
3134 */
3135xmlNodePtr
3136xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3137 xmlNodePtr prev;
3138
3139 if (parent == NULL) {
3140#ifdef DEBUG_TREE
3141 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003142 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003143#endif
3144 return(NULL);
3145 }
3146
3147 if (cur == NULL) {
3148#ifdef DEBUG_TREE
3149 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003150 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003151#endif
3152 return(NULL);
3153 }
3154
3155 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3156 (cur->doc != parent->doc)) {
3157#ifdef DEBUG_TREE
3158 xmlGenericError(xmlGenericErrorContext,
3159 "Elements moved to a different document\n");
3160#endif
3161 }
3162
3163 /*
3164 * add the first element at the end of the children list.
3165 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003166
Owen Taylor3473f882001-02-23 17:55:21 +00003167 if (parent->children == NULL) {
3168 parent->children = cur;
3169 } else {
3170 /*
3171 * If cur and parent->last both are TEXT nodes, then merge them.
3172 */
3173 if ((cur->type == XML_TEXT_NODE) &&
3174 (parent->last->type == XML_TEXT_NODE) &&
3175 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003176 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003177 /*
3178 * if it's the only child, nothing more to be done.
3179 */
3180 if (cur->next == NULL) {
3181 xmlFreeNode(cur);
3182 return(parent->last);
3183 }
3184 prev = cur;
3185 cur = cur->next;
3186 xmlFreeNode(prev);
3187 }
3188 prev = parent->last;
3189 prev->next = cur;
3190 cur->prev = prev;
3191 }
3192 while (cur->next != NULL) {
3193 cur->parent = parent;
3194 if (cur->doc != parent->doc) {
3195 xmlSetTreeDoc(cur, parent->doc);
3196 }
3197 cur = cur->next;
3198 }
3199 cur->parent = parent;
3200 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3201 parent->last = cur;
3202
3203 return(cur);
3204}
3205
3206/**
3207 * xmlAddChild:
3208 * @parent: the parent node
3209 * @cur: the child node
3210 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003211 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003212 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003213 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3214 * If there is an attribute with equal name, it is first destroyed.
3215 *
Owen Taylor3473f882001-02-23 17:55:21 +00003216 * Returns the child or NULL in case of error.
3217 */
3218xmlNodePtr
3219xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3220 xmlNodePtr prev;
3221
3222 if (parent == NULL) {
3223#ifdef DEBUG_TREE
3224 xmlGenericError(xmlGenericErrorContext,
3225 "xmlAddChild : parent == NULL\n");
3226#endif
3227 return(NULL);
3228 }
3229
3230 if (cur == NULL) {
3231#ifdef DEBUG_TREE
3232 xmlGenericError(xmlGenericErrorContext,
3233 "xmlAddChild : child == NULL\n");
3234#endif
3235 return(NULL);
3236 }
3237
Owen Taylor3473f882001-02-23 17:55:21 +00003238 /*
3239 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003240 * cur is then freed.
3241 */
3242 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003243 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003244 (parent->content != NULL) &&
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003245 (parent->name == cur->name) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003246 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003247 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003248 xmlFreeNode(cur);
3249 return(parent);
3250 }
3251 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003252 (parent->last->name == cur->name) &&
3253 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003254 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003255 xmlFreeNode(cur);
3256 return(parent->last);
3257 }
3258 }
3259
3260 /*
3261 * add the new element at the end of the children list.
3262 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003263 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003264 cur->parent = parent;
3265 if (cur->doc != parent->doc) {
3266 xmlSetTreeDoc(cur, parent->doc);
3267 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003268 /* this check prevents a loop on tree-traversions if a developer
3269 * tries to add a node to its parent multiple times
3270 */
3271 if (prev == parent)
3272 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003273
3274 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003275 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003276 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003277 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003278 (parent->content != NULL) &&
3279 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003280 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003281 xmlFreeNode(cur);
3282 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003283 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003284 if (cur->type == XML_ATTRIBUTE_NODE) {
3285 if (parent->properties == NULL) {
3286 parent->properties = (xmlAttrPtr) cur;
3287 } else {
3288 /* check if an attribute with the same name exists */
3289 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003290
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003291 if (cur->ns == NULL)
3292 lastattr = xmlHasProp(parent, cur->name);
3293 else
3294 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3295 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3296 /* different instance, destroy it (attributes must be unique) */
3297 xmlFreeProp(lastattr);
3298 }
3299 /* find the end */
3300 lastattr = parent->properties;
3301 while (lastattr->next != NULL) {
3302 lastattr = lastattr->next;
3303 }
3304 lastattr->next = (xmlAttrPtr) cur;
3305 ((xmlAttrPtr) cur)->prev = lastattr;
3306 }
3307 } else {
3308 if (parent->children == NULL) {
3309 parent->children = cur;
3310 parent->last = cur;
3311 } else {
3312 prev = parent->last;
3313 prev->next = cur;
3314 cur->prev = prev;
3315 parent->last = cur;
3316 }
3317 }
Owen Taylor3473f882001-02-23 17:55:21 +00003318 return(cur);
3319}
3320
3321/**
3322 * xmlGetLastChild:
3323 * @parent: the parent node
3324 *
3325 * Search the last child of a node.
3326 * Returns the last child or NULL if none.
3327 */
3328xmlNodePtr
3329xmlGetLastChild(xmlNodePtr parent) {
3330 if (parent == NULL) {
3331#ifdef DEBUG_TREE
3332 xmlGenericError(xmlGenericErrorContext,
3333 "xmlGetLastChild : parent == NULL\n");
3334#endif
3335 return(NULL);
3336 }
3337 return(parent->last);
3338}
3339
3340/**
3341 * xmlFreeNodeList:
3342 * @cur: the first node in the list
3343 *
3344 * Free a node and all its siblings, this is a recursive behaviour, all
3345 * the children are freed too.
3346 */
3347void
3348xmlFreeNodeList(xmlNodePtr cur) {
3349 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003350 xmlDictPtr dict = NULL;
3351
3352 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003353 if (cur->type == XML_NAMESPACE_DECL) {
3354 xmlFreeNsList((xmlNsPtr) cur);
3355 return;
3356 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003357 if ((cur->type == XML_DOCUMENT_NODE) ||
3358#ifdef LIBXML_DOCB_ENABLED
3359 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003360#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003361 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003362 xmlFreeDoc((xmlDocPtr) cur);
3363 return;
3364 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003365 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003366 while (cur != NULL) {
3367 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003368 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003369
Daniel Veillarda880b122003-04-21 21:36:41 +00003370 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003371 xmlDeregisterNodeDefaultValue(cur);
3372
Daniel Veillard02141ea2001-04-30 11:46:40 +00003373 if ((cur->children != NULL) &&
3374 (cur->type != XML_ENTITY_REF_NODE))
3375 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003376 if (((cur->type == XML_ELEMENT_NODE) ||
3377 (cur->type == XML_XINCLUDE_START) ||
3378 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003379 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003380 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003381 if ((cur->type != XML_ELEMENT_NODE) &&
3382 (cur->type != XML_XINCLUDE_START) &&
3383 (cur->type != XML_XINCLUDE_END) &&
3384 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003385 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003386 }
3387 if (((cur->type == XML_ELEMENT_NODE) ||
3388 (cur->type == XML_XINCLUDE_START) ||
3389 (cur->type == XML_XINCLUDE_END)) &&
3390 (cur->nsDef != NULL))
3391 xmlFreeNsList(cur->nsDef);
3392
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003393 /*
3394 * When a node is a text node or a comment, it uses a global static
3395 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003396 * Otherwise the node name might come from the document's
3397 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003398 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003399 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003400 (cur->type != XML_TEXT_NODE) &&
3401 (cur->type != XML_COMMENT_NODE))
3402 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003403 xmlFree(cur);
3404 }
Owen Taylor3473f882001-02-23 17:55:21 +00003405 cur = next;
3406 }
3407}
3408
3409/**
3410 * xmlFreeNode:
3411 * @cur: the node
3412 *
3413 * Free a node, this is a recursive behaviour, all the children are freed too.
3414 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3415 */
3416void
3417xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003418 xmlDictPtr dict = NULL;
3419
3420 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003421
Daniel Veillard02141ea2001-04-30 11:46:40 +00003422 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003423 if (cur->type == XML_DTD_NODE) {
3424 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003425 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003426 }
3427 if (cur->type == XML_NAMESPACE_DECL) {
3428 xmlFreeNs((xmlNsPtr) cur);
3429 return;
3430 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003431 if (cur->type == XML_ATTRIBUTE_NODE) {
3432 xmlFreeProp((xmlAttrPtr) cur);
3433 return;
3434 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003435
Daniel Veillarda880b122003-04-21 21:36:41 +00003436 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003437 xmlDeregisterNodeDefaultValue(cur);
3438
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003439 if (cur->doc != NULL) dict = cur->doc->dict;
3440
Owen Taylor3473f882001-02-23 17:55:21 +00003441 if ((cur->children != NULL) &&
3442 (cur->type != XML_ENTITY_REF_NODE))
3443 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003444 if (((cur->type == XML_ELEMENT_NODE) ||
3445 (cur->type == XML_XINCLUDE_START) ||
3446 (cur->type == XML_XINCLUDE_END)) &&
3447 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003448 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003449 if ((cur->type != XML_ELEMENT_NODE) &&
3450 (cur->content != NULL) &&
3451 (cur->type != XML_ENTITY_REF_NODE) &&
3452 (cur->type != XML_XINCLUDE_END) &&
3453 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003454 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003455 }
3456
Daniel Veillardacd370f2001-06-09 17:17:51 +00003457 /*
3458 * When a node is a text node or a comment, it uses a global static
3459 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003460 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003461 */
Owen Taylor3473f882001-02-23 17:55:21 +00003462 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003463 (cur->type != XML_TEXT_NODE) &&
3464 (cur->type != XML_COMMENT_NODE))
3465 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003466
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003467 if (((cur->type == XML_ELEMENT_NODE) ||
3468 (cur->type == XML_XINCLUDE_START) ||
3469 (cur->type == XML_XINCLUDE_END)) &&
3470 (cur->nsDef != NULL))
3471 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003472 xmlFree(cur);
3473}
3474
3475/**
3476 * xmlUnlinkNode:
3477 * @cur: the node
3478 *
3479 * Unlink a node from it's current context, the node is not freed
3480 */
3481void
3482xmlUnlinkNode(xmlNodePtr cur) {
3483 if (cur == NULL) {
3484#ifdef DEBUG_TREE
3485 xmlGenericError(xmlGenericErrorContext,
3486 "xmlUnlinkNode : node == NULL\n");
3487#endif
3488 return;
3489 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003490 if (cur->type == XML_DTD_NODE) {
3491 xmlDocPtr doc;
3492 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003493 if (doc != NULL) {
3494 if (doc->intSubset == (xmlDtdPtr) cur)
3495 doc->intSubset = NULL;
3496 if (doc->extSubset == (xmlDtdPtr) cur)
3497 doc->extSubset = NULL;
3498 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003499 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003500 if (cur->parent != NULL) {
3501 xmlNodePtr parent;
3502 parent = cur->parent;
3503 if (cur->type == XML_ATTRIBUTE_NODE) {
3504 if (parent->properties == (xmlAttrPtr) cur)
3505 parent->properties = ((xmlAttrPtr) cur)->next;
3506 } else {
3507 if (parent->children == cur)
3508 parent->children = cur->next;
3509 if (parent->last == cur)
3510 parent->last = cur->prev;
3511 }
3512 cur->parent = NULL;
3513 }
Owen Taylor3473f882001-02-23 17:55:21 +00003514 if (cur->next != NULL)
3515 cur->next->prev = cur->prev;
3516 if (cur->prev != NULL)
3517 cur->prev->next = cur->next;
3518 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003519}
3520
Daniel Veillard2156d432004-03-04 15:59:36 +00003521#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003522/**
3523 * xmlReplaceNode:
3524 * @old: the old node
3525 * @cur: the node
3526 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003527 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003528 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003529 * first unlinked from its existing context.
3530 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003531 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003532 */
3533xmlNodePtr
3534xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00003535 if (old == cur) return(NULL);
Daniel Veillarda03e3652004-11-02 18:45:30 +00003536 if ((old == NULL) || (old->parent == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003537#ifdef DEBUG_TREE
3538 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda03e3652004-11-02 18:45:30 +00003539 "xmlReplaceNode : old == NULL or without parent\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003540#endif
3541 return(NULL);
3542 }
3543 if (cur == NULL) {
3544 xmlUnlinkNode(old);
3545 return(old);
3546 }
3547 if (cur == old) {
3548 return(old);
3549 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003550 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3551#ifdef DEBUG_TREE
3552 xmlGenericError(xmlGenericErrorContext,
3553 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3554#endif
3555 return(old);
3556 }
3557 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3558#ifdef DEBUG_TREE
3559 xmlGenericError(xmlGenericErrorContext,
3560 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3561#endif
3562 return(old);
3563 }
Owen Taylor3473f882001-02-23 17:55:21 +00003564 xmlUnlinkNode(cur);
3565 cur->doc = old->doc;
3566 cur->parent = old->parent;
3567 cur->next = old->next;
3568 if (cur->next != NULL)
3569 cur->next->prev = cur;
3570 cur->prev = old->prev;
3571 if (cur->prev != NULL)
3572 cur->prev->next = cur;
3573 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003574 if (cur->type == XML_ATTRIBUTE_NODE) {
3575 if (cur->parent->properties == (xmlAttrPtr)old)
3576 cur->parent->properties = ((xmlAttrPtr) cur);
3577 } else {
3578 if (cur->parent->children == old)
3579 cur->parent->children = cur;
3580 if (cur->parent->last == old)
3581 cur->parent->last = cur;
3582 }
Owen Taylor3473f882001-02-23 17:55:21 +00003583 }
3584 old->next = old->prev = NULL;
3585 old->parent = NULL;
3586 return(old);
3587}
Daniel Veillard652327a2003-09-29 18:02:38 +00003588#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003589
3590/************************************************************************
3591 * *
3592 * Copy operations *
3593 * *
3594 ************************************************************************/
3595
3596/**
3597 * xmlCopyNamespace:
3598 * @cur: the namespace
3599 *
3600 * Do a copy of the namespace.
3601 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003602 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003603 */
3604xmlNsPtr
3605xmlCopyNamespace(xmlNsPtr cur) {
3606 xmlNsPtr ret;
3607
3608 if (cur == NULL) return(NULL);
3609 switch (cur->type) {
3610 case XML_LOCAL_NAMESPACE:
3611 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3612 break;
3613 default:
3614#ifdef DEBUG_TREE
3615 xmlGenericError(xmlGenericErrorContext,
3616 "xmlCopyNamespace: invalid type %d\n", cur->type);
3617#endif
3618 return(NULL);
3619 }
3620 return(ret);
3621}
3622
3623/**
3624 * xmlCopyNamespaceList:
3625 * @cur: the first namespace
3626 *
3627 * Do a copy of an namespace list.
3628 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003629 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003630 */
3631xmlNsPtr
3632xmlCopyNamespaceList(xmlNsPtr cur) {
3633 xmlNsPtr ret = NULL;
3634 xmlNsPtr p = NULL,q;
3635
3636 while (cur != NULL) {
3637 q = xmlCopyNamespace(cur);
3638 if (p == NULL) {
3639 ret = p = q;
3640 } else {
3641 p->next = q;
3642 p = q;
3643 }
3644 cur = cur->next;
3645 }
3646 return(ret);
3647}
3648
3649static xmlNodePtr
3650xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3651/**
3652 * xmlCopyProp:
3653 * @target: the element where the attribute will be grafted
3654 * @cur: the attribute
3655 *
3656 * Do a copy of the attribute.
3657 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003658 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003659 */
3660xmlAttrPtr
3661xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3662 xmlAttrPtr ret;
3663
3664 if (cur == NULL) return(NULL);
3665 if (target != NULL)
3666 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3667 else if (cur->parent != NULL)
3668 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3669 else if (cur->children != NULL)
3670 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3671 else
3672 ret = xmlNewDocProp(NULL, cur->name, NULL);
3673 if (ret == NULL) return(NULL);
3674 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003675
Owen Taylor3473f882001-02-23 17:55:21 +00003676 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003677 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003678
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003679 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3680 if (ns == NULL) {
3681 /*
3682 * Humm, we are copying an element whose namespace is defined
3683 * out of the new tree scope. Search it in the original tree
3684 * and add it at the top of the new tree
3685 */
3686 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3687 if (ns != NULL) {
3688 xmlNodePtr root = target;
3689 xmlNodePtr pred = NULL;
3690
3691 while (root->parent != NULL) {
3692 pred = root;
3693 root = root->parent;
3694 }
3695 if (root == (xmlNodePtr) target->doc) {
3696 /* correct possibly cycling above the document elt */
3697 root = pred;
3698 }
3699 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3700 }
3701 } else {
3702 /*
3703 * we have to find something appropriate here since
3704 * we cant be sure, that the namespce we found is identified
3705 * by the prefix
3706 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003707 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003708 /* this is the nice case */
3709 ret->ns = ns;
3710 } else {
3711 /*
3712 * we are in trouble: we need a new reconcilied namespace.
3713 * This is expensive
3714 */
3715 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3716 }
3717 }
3718
Owen Taylor3473f882001-02-23 17:55:21 +00003719 } else
3720 ret->ns = NULL;
3721
3722 if (cur->children != NULL) {
3723 xmlNodePtr tmp;
3724
3725 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3726 ret->last = NULL;
3727 tmp = ret->children;
3728 while (tmp != NULL) {
3729 /* tmp->parent = (xmlNodePtr)ret; */
3730 if (tmp->next == NULL)
3731 ret->last = tmp;
3732 tmp = tmp->next;
3733 }
3734 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003735 /*
3736 * Try to handle IDs
3737 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003738 if ((target!= NULL) && (cur!= NULL) &&
3739 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003740 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3741 if (xmlIsID(cur->doc, cur->parent, cur)) {
3742 xmlChar *id;
3743
3744 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3745 if (id != NULL) {
3746 xmlAddID(NULL, target->doc, id, ret);
3747 xmlFree(id);
3748 }
3749 }
3750 }
Owen Taylor3473f882001-02-23 17:55:21 +00003751 return(ret);
3752}
3753
3754/**
3755 * xmlCopyPropList:
3756 * @target: the element where the attributes will be grafted
3757 * @cur: the first attribute
3758 *
3759 * Do a copy of an attribute list.
3760 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003761 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003762 */
3763xmlAttrPtr
3764xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3765 xmlAttrPtr ret = NULL;
3766 xmlAttrPtr p = NULL,q;
3767
3768 while (cur != NULL) {
3769 q = xmlCopyProp(target, cur);
William M. Brack13dfa872004-09-18 04:52:08 +00003770 if (q == NULL)
3771 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003772 if (p == NULL) {
3773 ret = p = q;
3774 } else {
3775 p->next = q;
3776 q->prev = p;
3777 p = q;
3778 }
3779 cur = cur->next;
3780 }
3781 return(ret);
3782}
3783
3784/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003785 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003786 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003787 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003788 * tricky reason: namespaces. Doing a direct copy of a node
3789 * say RPM:Copyright without changing the namespace pointer to
3790 * something else can produce stale links. One way to do it is
3791 * to keep a reference counter but this doesn't work as soon
3792 * as one move the element or the subtree out of the scope of
3793 * the existing namespace. The actual solution seems to add
3794 * a copy of the namespace at the top of the copied tree if
3795 * not available in the subtree.
3796 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00003797 * The argument "recursive" normally indicates a recursive copy
3798 * of the node with values 0 (no) and 1 (yes). For XInclude,
3799 * however, we allow a value of 2 to indicate copy properties and
3800 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00003801 */
3802
3803static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003804xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00003805 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003806 xmlNodePtr ret;
3807
3808 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003809 switch (node->type) {
3810 case XML_TEXT_NODE:
3811 case XML_CDATA_SECTION_NODE:
3812 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003813 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003814 case XML_ENTITY_REF_NODE:
3815 case XML_ENTITY_NODE:
3816 case XML_PI_NODE:
3817 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003818 case XML_XINCLUDE_START:
3819 case XML_XINCLUDE_END:
3820 break;
3821 case XML_ATTRIBUTE_NODE:
3822 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3823 case XML_NAMESPACE_DECL:
3824 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3825
Daniel Veillard39196eb2001-06-19 18:09:42 +00003826 case XML_DOCUMENT_NODE:
3827 case XML_HTML_DOCUMENT_NODE:
3828#ifdef LIBXML_DOCB_ENABLED
3829 case XML_DOCB_DOCUMENT_NODE:
3830#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003831#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00003832 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00003833#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003834 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003835 case XML_NOTATION_NODE:
3836 case XML_DTD_NODE:
3837 case XML_ELEMENT_DECL:
3838 case XML_ATTRIBUTE_DECL:
3839 case XML_ENTITY_DECL:
3840 return(NULL);
3841 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003842
Owen Taylor3473f882001-02-23 17:55:21 +00003843 /*
3844 * Allocate a new node and fill the fields.
3845 */
3846 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3847 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003848 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003849 return(NULL);
3850 }
3851 memset(ret, 0, sizeof(xmlNode));
3852 ret->type = node->type;
3853
3854 ret->doc = doc;
3855 ret->parent = parent;
3856 if (node->name == xmlStringText)
3857 ret->name = xmlStringText;
3858 else if (node->name == xmlStringTextNoenc)
3859 ret->name = xmlStringTextNoenc;
3860 else if (node->name == xmlStringComment)
3861 ret->name = xmlStringComment;
Daniel Veillard03a53c32004-10-26 16:06:51 +00003862 else if (node->name != NULL) {
3863 if ((doc != NULL) && (doc->dict != NULL))
3864 ret->name = xmlDictLookup(doc->dict, node->name, -1);
3865 else
3866 ret->name = xmlStrdup(node->name);
3867 }
Daniel Veillard7db37732001-07-12 01:20:08 +00003868 if ((node->type != XML_ELEMENT_NODE) &&
3869 (node->content != NULL) &&
3870 (node->type != XML_ENTITY_REF_NODE) &&
3871 (node->type != XML_XINCLUDE_END) &&
3872 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003873 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003874 }else{
3875 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003876 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003877 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003878 if (parent != NULL) {
3879 xmlNodePtr tmp;
3880
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003881 /*
3882 * this is a tricky part for the node register thing:
3883 * in case ret does get coalesced in xmlAddChild
3884 * the deregister-node callback is called; so we register ret now already
3885 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003886 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003887 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3888
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003889 tmp = xmlAddChild(parent, ret);
3890 /* node could have coalesced */
3891 if (tmp != ret)
3892 return(tmp);
3893 }
Owen Taylor3473f882001-02-23 17:55:21 +00003894
William M. Brack57e9e912004-03-09 16:19:02 +00003895 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003896 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003897 if (node->nsDef != NULL)
3898 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3899
3900 if (node->ns != NULL) {
3901 xmlNsPtr ns;
3902
3903 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3904 if (ns == NULL) {
3905 /*
3906 * Humm, we are copying an element whose namespace is defined
3907 * out of the new tree scope. Search it in the original tree
3908 * and add it at the top of the new tree
3909 */
3910 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3911 if (ns != NULL) {
3912 xmlNodePtr root = ret;
3913
3914 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003915 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003916 }
3917 } else {
3918 /*
3919 * reference the existing namespace definition in our own tree.
3920 */
3921 ret->ns = ns;
3922 }
3923 }
3924 if (node->properties != NULL)
3925 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003926 if (node->type == XML_ENTITY_REF_NODE) {
3927 if ((doc == NULL) || (node->doc != doc)) {
3928 /*
3929 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003930 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003931 * we cannot keep the reference. Try to find it in the
3932 * target document.
3933 */
3934 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3935 } else {
3936 ret->children = node->children;
3937 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003938 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00003939 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003940 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003941 UPDATE_LAST_CHILD_AND_PARENT(ret)
3942 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003943
3944out:
3945 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00003946 if ((parent == NULL) &&
3947 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003948 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003949 return(ret);
3950}
3951
3952static xmlNodePtr
3953xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3954 xmlNodePtr ret = NULL;
3955 xmlNodePtr p = NULL,q;
3956
3957 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003958#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003959 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003960 if (doc == NULL) {
3961 node = node->next;
3962 continue;
3963 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003964 if (doc->intSubset == NULL) {
3965 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3966 q->doc = doc;
3967 q->parent = parent;
3968 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003969 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003970 } else {
3971 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003972 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003973 }
3974 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003975#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003976 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003977 if (ret == NULL) {
3978 q->prev = NULL;
3979 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003980 } else if (p != q) {
3981 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003982 p->next = q;
3983 q->prev = p;
3984 p = q;
3985 }
3986 node = node->next;
3987 }
3988 return(ret);
3989}
3990
3991/**
3992 * xmlCopyNode:
3993 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00003994 * @extended: if 1 do a recursive copy (properties, namespaces and children
3995 * when applicable)
3996 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00003997 *
3998 * Do a copy of the node.
3999 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004000 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004001 */
4002xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00004003xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00004004 xmlNodePtr ret;
4005
William M. Brack57e9e912004-03-09 16:19:02 +00004006 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00004007 return(ret);
4008}
4009
4010/**
Daniel Veillard82daa812001-04-12 08:55:36 +00004011 * xmlDocCopyNode:
4012 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00004013 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004014 * @extended: if 1 do a recursive copy (properties, namespaces and children
4015 * when applicable)
4016 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00004017 *
4018 * Do a copy of the node to a given document.
4019 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004020 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00004021 */
4022xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00004023xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00004024 xmlNodePtr ret;
4025
William M. Brack57e9e912004-03-09 16:19:02 +00004026 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00004027 return(ret);
4028}
4029
4030/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00004031 * xmlDocCopyNodeList:
4032 * @doc: the target document
4033 * @node: the first node in the list.
4034 *
4035 * Do a recursive copy of the node list.
4036 *
4037 * Returns: a new #xmlNodePtr, or NULL in case of error.
4038 */
4039xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) {
4040 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
4041 return(ret);
4042}
4043
4044/**
Owen Taylor3473f882001-02-23 17:55:21 +00004045 * xmlCopyNodeList:
4046 * @node: the first node in the list.
4047 *
4048 * Do a recursive copy of the node list.
Daniel Veillard03a53c32004-10-26 16:06:51 +00004049 * Use xmlDocCopyNodeList() if possible to ensure string interning.
Owen Taylor3473f882001-02-23 17:55:21 +00004050 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004051 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004052 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00004053xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00004054 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
4055 return(ret);
4056}
4057
Daniel Veillard2156d432004-03-04 15:59:36 +00004058#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004059/**
Owen Taylor3473f882001-02-23 17:55:21 +00004060 * xmlCopyDtd:
4061 * @dtd: the dtd
4062 *
4063 * Do a copy of the dtd.
4064 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004065 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004066 */
4067xmlDtdPtr
4068xmlCopyDtd(xmlDtdPtr dtd) {
4069 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004070 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00004071
4072 if (dtd == NULL) return(NULL);
4073 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4074 if (ret == NULL) return(NULL);
4075 if (dtd->entities != NULL)
4076 ret->entities = (void *) xmlCopyEntitiesTable(
4077 (xmlEntitiesTablePtr) dtd->entities);
4078 if (dtd->notations != NULL)
4079 ret->notations = (void *) xmlCopyNotationTable(
4080 (xmlNotationTablePtr) dtd->notations);
4081 if (dtd->elements != NULL)
4082 ret->elements = (void *) xmlCopyElementTable(
4083 (xmlElementTablePtr) dtd->elements);
4084 if (dtd->attributes != NULL)
4085 ret->attributes = (void *) xmlCopyAttributeTable(
4086 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004087 if (dtd->pentities != NULL)
4088 ret->pentities = (void *) xmlCopyEntitiesTable(
4089 (xmlEntitiesTablePtr) dtd->pentities);
4090
4091 cur = dtd->children;
4092 while (cur != NULL) {
4093 q = NULL;
4094
4095 if (cur->type == XML_ENTITY_DECL) {
4096 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4097 switch (tmp->etype) {
4098 case XML_INTERNAL_GENERAL_ENTITY:
4099 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4100 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4101 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4102 break;
4103 case XML_INTERNAL_PARAMETER_ENTITY:
4104 case XML_EXTERNAL_PARAMETER_ENTITY:
4105 q = (xmlNodePtr)
4106 xmlGetParameterEntityFromDtd(ret, tmp->name);
4107 break;
4108 case XML_INTERNAL_PREDEFINED_ENTITY:
4109 break;
4110 }
4111 } else if (cur->type == XML_ELEMENT_DECL) {
4112 xmlElementPtr tmp = (xmlElementPtr) cur;
4113 q = (xmlNodePtr)
4114 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4115 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4116 xmlAttributePtr tmp = (xmlAttributePtr) cur;
4117 q = (xmlNodePtr)
4118 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4119 } else if (cur->type == XML_COMMENT_NODE) {
4120 q = xmlCopyNode(cur, 0);
4121 }
4122
4123 if (q == NULL) {
4124 cur = cur->next;
4125 continue;
4126 }
4127
4128 if (p == NULL)
4129 ret->children = q;
4130 else
4131 p->next = q;
4132
4133 q->prev = p;
4134 q->parent = (xmlNodePtr) ret;
4135 q->next = NULL;
4136 ret->last = q;
4137 p = q;
4138 cur = cur->next;
4139 }
4140
Owen Taylor3473f882001-02-23 17:55:21 +00004141 return(ret);
4142}
Daniel Veillard2156d432004-03-04 15:59:36 +00004143#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004144
Daniel Veillard2156d432004-03-04 15:59:36 +00004145#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004146/**
4147 * xmlCopyDoc:
4148 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004149 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004150 *
4151 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004152 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004153 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004154 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004155 */
4156xmlDocPtr
4157xmlCopyDoc(xmlDocPtr doc, int recursive) {
4158 xmlDocPtr ret;
4159
4160 if (doc == NULL) return(NULL);
4161 ret = xmlNewDoc(doc->version);
4162 if (ret == NULL) return(NULL);
4163 if (doc->name != NULL)
4164 ret->name = xmlMemStrdup(doc->name);
4165 if (doc->encoding != NULL)
4166 ret->encoding = xmlStrdup(doc->encoding);
Daniel Veillardf59507d2005-01-27 17:26:49 +00004167 if (doc->URL != NULL)
4168 ret->URL = xmlStrdup(doc->URL);
Owen Taylor3473f882001-02-23 17:55:21 +00004169 ret->charset = doc->charset;
4170 ret->compression = doc->compression;
4171 ret->standalone = doc->standalone;
4172 if (!recursive) return(ret);
4173
Daniel Veillardb33c2012001-04-25 12:59:04 +00004174 ret->last = NULL;
4175 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004176#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004177 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004178 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004179 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004180 ret->intSubset->parent = ret;
4181 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004182#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004183 if (doc->oldNs != NULL)
4184 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4185 if (doc->children != NULL) {
4186 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004187
4188 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4189 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004190 ret->last = NULL;
4191 tmp = ret->children;
4192 while (tmp != NULL) {
4193 if (tmp->next == NULL)
4194 ret->last = tmp;
4195 tmp = tmp->next;
4196 }
4197 }
4198 return(ret);
4199}
Daniel Veillard652327a2003-09-29 18:02:38 +00004200#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004201
4202/************************************************************************
4203 * *
4204 * Content access functions *
4205 * *
4206 ************************************************************************/
4207
4208/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004209 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004210 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004211 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004212 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004213 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004214 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004215 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004216 */
4217long
4218xmlGetLineNo(xmlNodePtr node)
4219{
4220 long result = -1;
4221
4222 if (!node)
4223 return result;
4224 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004225 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004226 else if ((node->prev != NULL) &&
4227 ((node->prev->type == XML_ELEMENT_NODE) ||
4228 (node->prev->type == XML_TEXT_NODE)))
4229 result = xmlGetLineNo(node->prev);
4230 else if ((node->parent != NULL) &&
4231 ((node->parent->type == XML_ELEMENT_NODE) ||
4232 (node->parent->type == XML_TEXT_NODE)))
4233 result = xmlGetLineNo(node->parent);
4234
4235 return result;
4236}
4237
Daniel Veillard2156d432004-03-04 15:59:36 +00004238#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004239/**
4240 * xmlGetNodePath:
4241 * @node: a node
4242 *
4243 * Build a structure based Path for the given node
4244 *
4245 * Returns the new path or NULL in case of error. The caller must free
4246 * the returned string
4247 */
4248xmlChar *
4249xmlGetNodePath(xmlNodePtr node)
4250{
4251 xmlNodePtr cur, tmp, next;
4252 xmlChar *buffer = NULL, *temp;
4253 size_t buf_len;
4254 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004255 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004256 const char *name;
4257 char nametemp[100];
4258 int occur = 0;
4259
4260 if (node == NULL)
4261 return (NULL);
4262
4263 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004264 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004265 if (buffer == NULL) {
4266 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004267 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004268 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004269 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004270 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004271 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004272 xmlFree(buffer);
4273 return (NULL);
4274 }
4275
4276 buffer[0] = 0;
4277 cur = node;
4278 do {
4279 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004280 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004281 occur = 0;
4282 if ((cur->type == XML_DOCUMENT_NODE) ||
4283 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4284 if (buffer[0] == '/')
4285 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004286 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004287 next = NULL;
4288 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004289 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004290 name = (const char *) cur->name;
4291 if (cur->ns) {
William M. Brack84d83e32003-12-23 03:45:17 +00004292 if (cur->ns->prefix != NULL)
William M. Brack13dfa872004-09-18 04:52:08 +00004293 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4294 (char *)cur->ns->prefix, (char *)cur->name);
William M. Brack84d83e32003-12-23 03:45:17 +00004295 else
William M. Brack13dfa872004-09-18 04:52:08 +00004296 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4297 (char *)cur->name);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004298 nametemp[sizeof(nametemp) - 1] = 0;
4299 name = nametemp;
4300 }
4301 next = cur->parent;
4302
4303 /*
4304 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004305 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004306 */
4307 tmp = cur->prev;
4308 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004309 if ((tmp->type == XML_ELEMENT_NODE) &&
Daniel Veillard0996a162005-02-05 14:00:10 +00004310 (xmlStrEqual(cur->name, tmp->name)) &&
4311 ((tmp->ns == cur->ns) ||
4312 ((tmp->ns != NULL) && (cur->ns != NULL) &&
4313 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004314 occur++;
4315 tmp = tmp->prev;
4316 }
4317 if (occur == 0) {
4318 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004319 while (tmp != NULL && occur == 0) {
4320 if ((tmp->type == XML_ELEMENT_NODE) &&
Daniel Veillard0996a162005-02-05 14:00:10 +00004321 (xmlStrEqual(cur->name, tmp->name)) &&
4322 ((tmp->ns == cur->ns) ||
4323 ((tmp->ns != NULL) && (cur->ns != NULL) &&
4324 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004325 occur++;
4326 tmp = tmp->next;
4327 }
4328 if (occur != 0)
4329 occur = 1;
4330 } else
4331 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004332 } else if (cur->type == XML_COMMENT_NODE) {
4333 sep = "/";
4334 name = "comment()";
4335 next = cur->parent;
4336
4337 /*
4338 * Thumbler index computation
4339 */
4340 tmp = cur->prev;
4341 while (tmp != NULL) {
4342 if (tmp->type == XML_COMMENT_NODE)
4343 occur++;
4344 tmp = tmp->prev;
4345 }
4346 if (occur == 0) {
4347 tmp = cur->next;
4348 while (tmp != NULL && occur == 0) {
4349 if (tmp->type == XML_COMMENT_NODE)
4350 occur++;
4351 tmp = tmp->next;
4352 }
4353 if (occur != 0)
4354 occur = 1;
4355 } else
4356 occur++;
4357 } else if ((cur->type == XML_TEXT_NODE) ||
4358 (cur->type == XML_CDATA_SECTION_NODE)) {
4359 sep = "/";
4360 name = "text()";
4361 next = cur->parent;
4362
4363 /*
4364 * Thumbler index computation
4365 */
4366 tmp = cur->prev;
4367 while (tmp != NULL) {
4368 if ((cur->type == XML_TEXT_NODE) ||
4369 (cur->type == XML_CDATA_SECTION_NODE))
4370 occur++;
4371 tmp = tmp->prev;
4372 }
4373 if (occur == 0) {
4374 tmp = cur->next;
4375 while (tmp != NULL && occur == 0) {
Daniel Veillard1f8658a2004-08-14 21:46:31 +00004376 if ((tmp->type == XML_TEXT_NODE) ||
4377 (tmp->type == XML_CDATA_SECTION_NODE))
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004378 occur++;
4379 tmp = tmp->next;
4380 }
4381 if (occur != 0)
4382 occur = 1;
4383 } else
4384 occur++;
4385 } else if (cur->type == XML_PI_NODE) {
4386 sep = "/";
4387 snprintf(nametemp, sizeof(nametemp) - 1,
William M. Brack13dfa872004-09-18 04:52:08 +00004388 "processing-instruction('%s')", (char *)cur->name);
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004389 nametemp[sizeof(nametemp) - 1] = 0;
4390 name = nametemp;
4391
4392 next = cur->parent;
4393
4394 /*
4395 * Thumbler index computation
4396 */
4397 tmp = cur->prev;
4398 while (tmp != NULL) {
4399 if ((tmp->type == XML_PI_NODE) &&
4400 (xmlStrEqual(cur->name, tmp->name)))
4401 occur++;
4402 tmp = tmp->prev;
4403 }
4404 if (occur == 0) {
4405 tmp = cur->next;
4406 while (tmp != NULL && occur == 0) {
4407 if ((tmp->type == XML_PI_NODE) &&
4408 (xmlStrEqual(cur->name, tmp->name)))
4409 occur++;
4410 tmp = tmp->next;
4411 }
4412 if (occur != 0)
4413 occur = 1;
4414 } else
4415 occur++;
4416
Daniel Veillard8faa7832001-11-26 15:58:08 +00004417 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004418 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004419 name = (const char *) (((xmlAttrPtr) cur)->name);
4420 next = ((xmlAttrPtr) cur)->parent;
4421 } else {
4422 next = cur->parent;
4423 }
4424
4425 /*
4426 * Make sure there is enough room
4427 */
4428 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4429 buf_len =
4430 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4431 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4432 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004433 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004434 xmlFree(buf);
4435 xmlFree(buffer);
4436 return (NULL);
4437 }
4438 buffer = temp;
4439 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4440 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004441 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004442 xmlFree(buf);
4443 xmlFree(buffer);
4444 return (NULL);
4445 }
4446 buf = temp;
4447 }
4448 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004449 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004450 sep, name, (char *) buffer);
4451 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004452 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004453 sep, name, occur, (char *) buffer);
William M. Brack13dfa872004-09-18 04:52:08 +00004454 snprintf((char *) buffer, buf_len, "%s", (char *)buf);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004455 cur = next;
4456 } while (cur != NULL);
4457 xmlFree(buf);
4458 return (buffer);
4459}
Daniel Veillard652327a2003-09-29 18:02:38 +00004460#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004461
4462/**
Owen Taylor3473f882001-02-23 17:55:21 +00004463 * xmlDocGetRootElement:
4464 * @doc: the document
4465 *
4466 * Get the root element of the document (doc->children is a list
4467 * containing possibly comments, PIs, etc ...).
4468 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004469 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004470 */
4471xmlNodePtr
4472xmlDocGetRootElement(xmlDocPtr doc) {
4473 xmlNodePtr ret;
4474
4475 if (doc == NULL) return(NULL);
4476 ret = doc->children;
4477 while (ret != NULL) {
4478 if (ret->type == XML_ELEMENT_NODE)
4479 return(ret);
4480 ret = ret->next;
4481 }
4482 return(ret);
4483}
4484
Daniel Veillard2156d432004-03-04 15:59:36 +00004485#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004486/**
4487 * xmlDocSetRootElement:
4488 * @doc: the document
4489 * @root: the new document root element
4490 *
4491 * Set the root element of the document (doc->children is a list
4492 * containing possibly comments, PIs, etc ...).
4493 *
4494 * Returns the old root element if any was found
4495 */
4496xmlNodePtr
4497xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4498 xmlNodePtr old = NULL;
4499
4500 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004501 if (root == NULL)
4502 return(NULL);
4503 xmlUnlinkNode(root);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00004504 xmlSetTreeDoc(root, doc);
Daniel Veillardc575b992002-02-08 13:28:40 +00004505 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004506 old = doc->children;
4507 while (old != NULL) {
4508 if (old->type == XML_ELEMENT_NODE)
4509 break;
4510 old = old->next;
4511 }
4512 if (old == NULL) {
4513 if (doc->children == NULL) {
4514 doc->children = root;
4515 doc->last = root;
4516 } else {
4517 xmlAddSibling(doc->children, root);
4518 }
4519 } else {
4520 xmlReplaceNode(old, root);
4521 }
4522 return(old);
4523}
Daniel Veillard2156d432004-03-04 15:59:36 +00004524#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004525
Daniel Veillard2156d432004-03-04 15:59:36 +00004526#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004527/**
4528 * xmlNodeSetLang:
4529 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004530 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004531 *
4532 * Set the language of a node, i.e. the values of the xml:lang
4533 * attribute.
4534 */
4535void
4536xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004537 xmlNsPtr ns;
4538
Owen Taylor3473f882001-02-23 17:55:21 +00004539 if (cur == NULL) return;
4540 switch(cur->type) {
4541 case XML_TEXT_NODE:
4542 case XML_CDATA_SECTION_NODE:
4543 case XML_COMMENT_NODE:
4544 case XML_DOCUMENT_NODE:
4545 case XML_DOCUMENT_TYPE_NODE:
4546 case XML_DOCUMENT_FRAG_NODE:
4547 case XML_NOTATION_NODE:
4548 case XML_HTML_DOCUMENT_NODE:
4549 case XML_DTD_NODE:
4550 case XML_ELEMENT_DECL:
4551 case XML_ATTRIBUTE_DECL:
4552 case XML_ENTITY_DECL:
4553 case XML_PI_NODE:
4554 case XML_ENTITY_REF_NODE:
4555 case XML_ENTITY_NODE:
4556 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004557#ifdef LIBXML_DOCB_ENABLED
4558 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004559#endif
4560 case XML_XINCLUDE_START:
4561 case XML_XINCLUDE_END:
4562 return;
4563 case XML_ELEMENT_NODE:
4564 case XML_ATTRIBUTE_NODE:
4565 break;
4566 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004567 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4568 if (ns == NULL)
4569 return;
4570 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004571}
Daniel Veillard652327a2003-09-29 18:02:38 +00004572#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004573
4574/**
4575 * xmlNodeGetLang:
4576 * @cur: the node being checked
4577 *
4578 * Searches the language of a node, i.e. the values of the xml:lang
4579 * attribute or the one carried by the nearest ancestor.
4580 *
4581 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004582 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004583 */
4584xmlChar *
4585xmlNodeGetLang(xmlNodePtr cur) {
4586 xmlChar *lang;
4587
4588 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004589 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004590 if (lang != NULL)
4591 return(lang);
4592 cur = cur->parent;
4593 }
4594 return(NULL);
4595}
4596
4597
Daniel Veillard652327a2003-09-29 18:02:38 +00004598#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004599/**
4600 * xmlNodeSetSpacePreserve:
4601 * @cur: the node being changed
4602 * @val: the xml:space value ("0": default, 1: "preserve")
4603 *
4604 * Set (or reset) the space preserving behaviour of a node, i.e. the
4605 * value of the xml:space attribute.
4606 */
4607void
4608xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004609 xmlNsPtr ns;
4610
Owen Taylor3473f882001-02-23 17:55:21 +00004611 if (cur == NULL) return;
4612 switch(cur->type) {
4613 case XML_TEXT_NODE:
4614 case XML_CDATA_SECTION_NODE:
4615 case XML_COMMENT_NODE:
4616 case XML_DOCUMENT_NODE:
4617 case XML_DOCUMENT_TYPE_NODE:
4618 case XML_DOCUMENT_FRAG_NODE:
4619 case XML_NOTATION_NODE:
4620 case XML_HTML_DOCUMENT_NODE:
4621 case XML_DTD_NODE:
4622 case XML_ELEMENT_DECL:
4623 case XML_ATTRIBUTE_DECL:
4624 case XML_ENTITY_DECL:
4625 case XML_PI_NODE:
4626 case XML_ENTITY_REF_NODE:
4627 case XML_ENTITY_NODE:
4628 case XML_NAMESPACE_DECL:
4629 case XML_XINCLUDE_START:
4630 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004631#ifdef LIBXML_DOCB_ENABLED
4632 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004633#endif
4634 return;
4635 case XML_ELEMENT_NODE:
4636 case XML_ATTRIBUTE_NODE:
4637 break;
4638 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004639 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4640 if (ns == NULL)
4641 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004642 switch (val) {
4643 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004644 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004645 break;
4646 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004647 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004648 break;
4649 }
4650}
Daniel Veillard652327a2003-09-29 18:02:38 +00004651#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004652
4653/**
4654 * xmlNodeGetSpacePreserve:
4655 * @cur: the node being checked
4656 *
4657 * Searches the space preserving behaviour of a node, i.e. the values
4658 * of the xml:space attribute or the one carried by the nearest
4659 * ancestor.
4660 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004661 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004662 */
4663int
4664xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4665 xmlChar *space;
4666
4667 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004668 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004669 if (space != NULL) {
4670 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4671 xmlFree(space);
4672 return(1);
4673 }
4674 if (xmlStrEqual(space, BAD_CAST "default")) {
4675 xmlFree(space);
4676 return(0);
4677 }
4678 xmlFree(space);
4679 }
4680 cur = cur->parent;
4681 }
4682 return(-1);
4683}
4684
Daniel Veillard652327a2003-09-29 18:02:38 +00004685#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004686/**
4687 * xmlNodeSetName:
4688 * @cur: the node being changed
4689 * @name: the new tag name
4690 *
4691 * Set (or reset) the name of a node.
4692 */
4693void
4694xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00004695 xmlDocPtr doc;
4696 xmlDictPtr dict;
4697
Owen Taylor3473f882001-02-23 17:55:21 +00004698 if (cur == NULL) return;
4699 if (name == NULL) return;
4700 switch(cur->type) {
4701 case XML_TEXT_NODE:
4702 case XML_CDATA_SECTION_NODE:
4703 case XML_COMMENT_NODE:
4704 case XML_DOCUMENT_TYPE_NODE:
4705 case XML_DOCUMENT_FRAG_NODE:
4706 case XML_NOTATION_NODE:
4707 case XML_HTML_DOCUMENT_NODE:
4708 case XML_NAMESPACE_DECL:
4709 case XML_XINCLUDE_START:
4710 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004711#ifdef LIBXML_DOCB_ENABLED
4712 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004713#endif
4714 return;
4715 case XML_ELEMENT_NODE:
4716 case XML_ATTRIBUTE_NODE:
4717 case XML_PI_NODE:
4718 case XML_ENTITY_REF_NODE:
4719 case XML_ENTITY_NODE:
4720 case XML_DTD_NODE:
4721 case XML_DOCUMENT_NODE:
4722 case XML_ELEMENT_DECL:
4723 case XML_ATTRIBUTE_DECL:
4724 case XML_ENTITY_DECL:
4725 break;
4726 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00004727 doc = cur->doc;
4728 if (doc != NULL)
4729 dict = doc->dict;
4730 else
4731 dict = NULL;
4732 if (dict != NULL) {
4733 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
4734 xmlFree((xmlChar *) cur->name);
4735 cur->name = xmlDictLookup(dict, name, -1);
4736 } else {
4737 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4738 cur->name = xmlStrdup(name);
4739 }
Owen Taylor3473f882001-02-23 17:55:21 +00004740}
Daniel Veillard2156d432004-03-04 15:59:36 +00004741#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004742
Daniel Veillard2156d432004-03-04 15:59:36 +00004743#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004744/**
4745 * xmlNodeSetBase:
4746 * @cur: the node being changed
4747 * @uri: the new base URI
4748 *
4749 * Set (or reset) the base URI of a node, i.e. the value of the
4750 * xml:base attribute.
4751 */
4752void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004753xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004754 xmlNsPtr ns;
4755
Owen Taylor3473f882001-02-23 17:55:21 +00004756 if (cur == NULL) return;
4757 switch(cur->type) {
4758 case XML_TEXT_NODE:
4759 case XML_CDATA_SECTION_NODE:
4760 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004761 case XML_DOCUMENT_TYPE_NODE:
4762 case XML_DOCUMENT_FRAG_NODE:
4763 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004764 case XML_DTD_NODE:
4765 case XML_ELEMENT_DECL:
4766 case XML_ATTRIBUTE_DECL:
4767 case XML_ENTITY_DECL:
4768 case XML_PI_NODE:
4769 case XML_ENTITY_REF_NODE:
4770 case XML_ENTITY_NODE:
4771 case XML_NAMESPACE_DECL:
4772 case XML_XINCLUDE_START:
4773 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004774 return;
4775 case XML_ELEMENT_NODE:
4776 case XML_ATTRIBUTE_NODE:
4777 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004778 case XML_DOCUMENT_NODE:
4779#ifdef LIBXML_DOCB_ENABLED
4780 case XML_DOCB_DOCUMENT_NODE:
4781#endif
4782 case XML_HTML_DOCUMENT_NODE: {
4783 xmlDocPtr doc = (xmlDocPtr) cur;
4784
4785 if (doc->URL != NULL)
4786 xmlFree((xmlChar *) doc->URL);
4787 if (uri == NULL)
4788 doc->URL = NULL;
4789 else
4790 doc->URL = xmlStrdup(uri);
4791 return;
4792 }
Owen Taylor3473f882001-02-23 17:55:21 +00004793 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004794
4795 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4796 if (ns == NULL)
4797 return;
4798 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004799}
Daniel Veillard652327a2003-09-29 18:02:38 +00004800#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004801
4802/**
Owen Taylor3473f882001-02-23 17:55:21 +00004803 * xmlNodeGetBase:
4804 * @doc: the document the node pertains to
4805 * @cur: the node being checked
4806 *
4807 * Searches for the BASE URL. The code should work on both XML
4808 * and HTML document even if base mechanisms are completely different.
4809 * It returns the base as defined in RFC 2396 sections
4810 * 5.1.1. Base URI within Document Content
4811 * and
4812 * 5.1.2. Base URI from the Encapsulating Entity
4813 * However it does not return the document base (5.1.3), use
4814 * xmlDocumentGetBase() for this
4815 *
4816 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004817 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004818 */
4819xmlChar *
4820xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004821 xmlChar *oldbase = NULL;
4822 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004823
4824 if ((cur == NULL) && (doc == NULL))
4825 return(NULL);
4826 if (doc == NULL) doc = cur->doc;
4827 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4828 cur = doc->children;
4829 while ((cur != NULL) && (cur->name != NULL)) {
4830 if (cur->type != XML_ELEMENT_NODE) {
4831 cur = cur->next;
4832 continue;
4833 }
4834 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4835 cur = cur->children;
4836 continue;
4837 }
4838 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4839 cur = cur->children;
4840 continue;
4841 }
4842 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4843 return(xmlGetProp(cur, BAD_CAST "href"));
4844 }
4845 cur = cur->next;
4846 }
4847 return(NULL);
4848 }
4849 while (cur != NULL) {
4850 if (cur->type == XML_ENTITY_DECL) {
4851 xmlEntityPtr ent = (xmlEntityPtr) cur;
4852 return(xmlStrdup(ent->URI));
4853 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004854 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004855 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004856 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004857 if (oldbase != NULL) {
4858 newbase = xmlBuildURI(oldbase, base);
4859 if (newbase != NULL) {
4860 xmlFree(oldbase);
4861 xmlFree(base);
4862 oldbase = newbase;
4863 } else {
4864 xmlFree(oldbase);
4865 xmlFree(base);
4866 return(NULL);
4867 }
4868 } else {
4869 oldbase = base;
4870 }
4871 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4872 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4873 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4874 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004875 }
4876 }
Owen Taylor3473f882001-02-23 17:55:21 +00004877 cur = cur->parent;
4878 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004879 if ((doc != NULL) && (doc->URL != NULL)) {
4880 if (oldbase == NULL)
4881 return(xmlStrdup(doc->URL));
4882 newbase = xmlBuildURI(oldbase, doc->URL);
4883 xmlFree(oldbase);
4884 return(newbase);
4885 }
4886 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004887}
4888
4889/**
Daniel Veillard78697292003-10-19 20:44:43 +00004890 * xmlNodeBufGetContent:
4891 * @buffer: a buffer
4892 * @cur: the node being read
4893 *
4894 * Read the value of a node @cur, this can be either the text carried
4895 * directly by this node if it's a TEXT node or the aggregate string
4896 * of the values carried by this node child's (TEXT and ENTITY_REF).
4897 * Entity references are substituted.
4898 * Fills up the buffer @buffer with this value
4899 *
4900 * Returns 0 in case of success and -1 in case of error.
4901 */
4902int
4903xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4904{
4905 if ((cur == NULL) || (buffer == NULL)) return(-1);
4906 switch (cur->type) {
4907 case XML_CDATA_SECTION_NODE:
4908 case XML_TEXT_NODE:
4909 xmlBufferCat(buffer, cur->content);
4910 break;
4911 case XML_DOCUMENT_FRAG_NODE:
4912 case XML_ELEMENT_NODE:{
4913 xmlNodePtr tmp = cur;
4914
4915 while (tmp != NULL) {
4916 switch (tmp->type) {
4917 case XML_CDATA_SECTION_NODE:
4918 case XML_TEXT_NODE:
4919 if (tmp->content != NULL)
4920 xmlBufferCat(buffer, tmp->content);
4921 break;
4922 case XML_ENTITY_REF_NODE:
4923 xmlNodeBufGetContent(buffer, tmp->children);
4924 break;
4925 default:
4926 break;
4927 }
4928 /*
4929 * Skip to next node
4930 */
4931 if (tmp->children != NULL) {
4932 if (tmp->children->type != XML_ENTITY_DECL) {
4933 tmp = tmp->children;
4934 continue;
4935 }
4936 }
4937 if (tmp == cur)
4938 break;
4939
4940 if (tmp->next != NULL) {
4941 tmp = tmp->next;
4942 continue;
4943 }
4944
4945 do {
4946 tmp = tmp->parent;
4947 if (tmp == NULL)
4948 break;
4949 if (tmp == cur) {
4950 tmp = NULL;
4951 break;
4952 }
4953 if (tmp->next != NULL) {
4954 tmp = tmp->next;
4955 break;
4956 }
4957 } while (tmp != NULL);
4958 }
4959 break;
4960 }
4961 case XML_ATTRIBUTE_NODE:{
4962 xmlAttrPtr attr = (xmlAttrPtr) cur;
4963 xmlNodePtr tmp = attr->children;
4964
4965 while (tmp != NULL) {
4966 if (tmp->type == XML_TEXT_NODE)
4967 xmlBufferCat(buffer, tmp->content);
4968 else
4969 xmlNodeBufGetContent(buffer, tmp);
4970 tmp = tmp->next;
4971 }
4972 break;
4973 }
4974 case XML_COMMENT_NODE:
4975 case XML_PI_NODE:
4976 xmlBufferCat(buffer, cur->content);
4977 break;
4978 case XML_ENTITY_REF_NODE:{
4979 xmlEntityPtr ent;
4980 xmlNodePtr tmp;
4981
4982 /* lookup entity declaration */
4983 ent = xmlGetDocEntity(cur->doc, cur->name);
4984 if (ent == NULL)
4985 return(-1);
4986
4987 /* an entity content can be any "well balanced chunk",
4988 * i.e. the result of the content [43] production:
4989 * http://www.w3.org/TR/REC-xml#NT-content
4990 * -> we iterate through child nodes and recursive call
4991 * xmlNodeGetContent() which handles all possible node types */
4992 tmp = ent->children;
4993 while (tmp) {
4994 xmlNodeBufGetContent(buffer, tmp);
4995 tmp = tmp->next;
4996 }
4997 break;
4998 }
4999 case XML_ENTITY_NODE:
5000 case XML_DOCUMENT_TYPE_NODE:
5001 case XML_NOTATION_NODE:
5002 case XML_DTD_NODE:
5003 case XML_XINCLUDE_START:
5004 case XML_XINCLUDE_END:
5005 break;
5006 case XML_DOCUMENT_NODE:
5007#ifdef LIBXML_DOCB_ENABLED
5008 case XML_DOCB_DOCUMENT_NODE:
5009#endif
5010 case XML_HTML_DOCUMENT_NODE:
5011 cur = cur->children;
5012 while (cur!= NULL) {
5013 if ((cur->type == XML_ELEMENT_NODE) ||
5014 (cur->type == XML_TEXT_NODE) ||
5015 (cur->type == XML_CDATA_SECTION_NODE)) {
5016 xmlNodeBufGetContent(buffer, cur);
5017 }
5018 cur = cur->next;
5019 }
5020 break;
5021 case XML_NAMESPACE_DECL:
5022 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
5023 break;
5024 case XML_ELEMENT_DECL:
5025 case XML_ATTRIBUTE_DECL:
5026 case XML_ENTITY_DECL:
5027 break;
5028 }
5029 return(0);
5030}
5031/**
Owen Taylor3473f882001-02-23 17:55:21 +00005032 * xmlNodeGetContent:
5033 * @cur: the node being read
5034 *
5035 * Read the value of a node, this can be either the text carried
5036 * directly by this node if it's a TEXT node or the aggregate string
5037 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00005038 * Entity references are substituted.
5039 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005040 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005041 */
5042xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00005043xmlNodeGetContent(xmlNodePtr cur)
5044{
5045 if (cur == NULL)
5046 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005047 switch (cur->type) {
5048 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005049 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00005050 xmlBufferPtr buffer;
5051 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00005052
Daniel Veillard814a76d2003-01-23 18:24:20 +00005053 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00005054 if (buffer == NULL)
5055 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00005056 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005057 ret = buffer->content;
5058 buffer->content = NULL;
5059 xmlBufferFree(buffer);
5060 return (ret);
5061 }
5062 case XML_ATTRIBUTE_NODE:{
5063 xmlAttrPtr attr = (xmlAttrPtr) cur;
5064
5065 if (attr->parent != NULL)
5066 return (xmlNodeListGetString
5067 (attr->parent->doc, attr->children, 1));
5068 else
5069 return (xmlNodeListGetString(NULL, attr->children, 1));
5070 break;
5071 }
Owen Taylor3473f882001-02-23 17:55:21 +00005072 case XML_COMMENT_NODE:
5073 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005074 if (cur->content != NULL)
5075 return (xmlStrdup(cur->content));
5076 return (NULL);
5077 case XML_ENTITY_REF_NODE:{
5078 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00005079 xmlBufferPtr buffer;
5080 xmlChar *ret;
5081
5082 /* lookup entity declaration */
5083 ent = xmlGetDocEntity(cur->doc, cur->name);
5084 if (ent == NULL)
5085 return (NULL);
5086
5087 buffer = xmlBufferCreate();
5088 if (buffer == NULL)
5089 return (NULL);
5090
Daniel Veillardc4696922003-10-19 21:47:14 +00005091 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005092
5093 ret = buffer->content;
5094 buffer->content = NULL;
5095 xmlBufferFree(buffer);
5096 return (ret);
5097 }
Owen Taylor3473f882001-02-23 17:55:21 +00005098 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005099 case XML_DOCUMENT_TYPE_NODE:
5100 case XML_NOTATION_NODE:
5101 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005102 case XML_XINCLUDE_START:
5103 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00005104 return (NULL);
5105 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005106#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005107 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005108#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005109 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00005110 xmlBufferPtr buffer;
5111 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005112
Daniel Veillardc4696922003-10-19 21:47:14 +00005113 buffer = xmlBufferCreate();
5114 if (buffer == NULL)
5115 return (NULL);
5116
5117 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5118
5119 ret = buffer->content;
5120 buffer->content = NULL;
5121 xmlBufferFree(buffer);
5122 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005123 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005124 case XML_NAMESPACE_DECL: {
5125 xmlChar *tmp;
5126
5127 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5128 return (tmp);
5129 }
Owen Taylor3473f882001-02-23 17:55:21 +00005130 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005131 /* TODO !!! */
5132 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005133 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005134 /* TODO !!! */
5135 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005136 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005137 /* TODO !!! */
5138 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005139 case XML_CDATA_SECTION_NODE:
5140 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005141 if (cur->content != NULL)
5142 return (xmlStrdup(cur->content));
5143 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005144 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005145 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005146}
Daniel Veillard652327a2003-09-29 18:02:38 +00005147
Owen Taylor3473f882001-02-23 17:55:21 +00005148/**
5149 * xmlNodeSetContent:
5150 * @cur: the node being modified
5151 * @content: the new value of the content
5152 *
5153 * Replace the content of a node.
5154 */
5155void
5156xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5157 if (cur == NULL) {
5158#ifdef DEBUG_TREE
5159 xmlGenericError(xmlGenericErrorContext,
5160 "xmlNodeSetContent : node == NULL\n");
5161#endif
5162 return;
5163 }
5164 switch (cur->type) {
5165 case XML_DOCUMENT_FRAG_NODE:
5166 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005167 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005168 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5169 cur->children = xmlStringGetNodeList(cur->doc, content);
5170 UPDATE_LAST_CHILD_AND_PARENT(cur)
5171 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005172 case XML_TEXT_NODE:
5173 case XML_CDATA_SECTION_NODE:
5174 case XML_ENTITY_REF_NODE:
5175 case XML_ENTITY_NODE:
5176 case XML_PI_NODE:
5177 case XML_COMMENT_NODE:
5178 if (cur->content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005179 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
Daniel Veillard370ba3d2004-10-25 16:23:56 +00005180 (!xmlDictOwns(cur->doc->dict, cur->content))))
William M. Brack7762bb12004-01-04 14:49:01 +00005181 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005182 }
5183 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5184 cur->last = cur->children = NULL;
5185 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005186 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005187 } else
5188 cur->content = NULL;
5189 break;
5190 case XML_DOCUMENT_NODE:
5191 case XML_HTML_DOCUMENT_NODE:
5192 case XML_DOCUMENT_TYPE_NODE:
5193 case XML_XINCLUDE_START:
5194 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005195#ifdef LIBXML_DOCB_ENABLED
5196 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005197#endif
5198 break;
5199 case XML_NOTATION_NODE:
5200 break;
5201 case XML_DTD_NODE:
5202 break;
5203 case XML_NAMESPACE_DECL:
5204 break;
5205 case XML_ELEMENT_DECL:
5206 /* TODO !!! */
5207 break;
5208 case XML_ATTRIBUTE_DECL:
5209 /* TODO !!! */
5210 break;
5211 case XML_ENTITY_DECL:
5212 /* TODO !!! */
5213 break;
5214 }
5215}
5216
Daniel Veillard652327a2003-09-29 18:02:38 +00005217#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005218/**
5219 * xmlNodeSetContentLen:
5220 * @cur: the node being modified
5221 * @content: the new value of the content
5222 * @len: the size of @content
5223 *
5224 * Replace the content of a node.
5225 */
5226void
5227xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5228 if (cur == NULL) {
5229#ifdef DEBUG_TREE
5230 xmlGenericError(xmlGenericErrorContext,
5231 "xmlNodeSetContentLen : node == NULL\n");
5232#endif
5233 return;
5234 }
5235 switch (cur->type) {
5236 case XML_DOCUMENT_FRAG_NODE:
5237 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005238 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005239 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5240 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5241 UPDATE_LAST_CHILD_AND_PARENT(cur)
5242 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005243 case XML_TEXT_NODE:
5244 case XML_CDATA_SECTION_NODE:
5245 case XML_ENTITY_REF_NODE:
5246 case XML_ENTITY_NODE:
5247 case XML_PI_NODE:
5248 case XML_COMMENT_NODE:
5249 case XML_NOTATION_NODE:
5250 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005251 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005252 }
5253 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5254 cur->children = cur->last = NULL;
5255 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005256 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005257 } else
5258 cur->content = NULL;
5259 break;
5260 case XML_DOCUMENT_NODE:
5261 case XML_DTD_NODE:
5262 case XML_HTML_DOCUMENT_NODE:
5263 case XML_DOCUMENT_TYPE_NODE:
5264 case XML_NAMESPACE_DECL:
5265 case XML_XINCLUDE_START:
5266 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005267#ifdef LIBXML_DOCB_ENABLED
5268 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005269#endif
5270 break;
5271 case XML_ELEMENT_DECL:
5272 /* TODO !!! */
5273 break;
5274 case XML_ATTRIBUTE_DECL:
5275 /* TODO !!! */
5276 break;
5277 case XML_ENTITY_DECL:
5278 /* TODO !!! */
5279 break;
5280 }
5281}
Daniel Veillard652327a2003-09-29 18:02:38 +00005282#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005283
5284/**
5285 * xmlNodeAddContentLen:
5286 * @cur: the node being modified
5287 * @content: extra content
5288 * @len: the size of @content
5289 *
5290 * Append the extra substring to the node content.
5291 */
5292void
5293xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5294 if (cur == NULL) {
5295#ifdef DEBUG_TREE
5296 xmlGenericError(xmlGenericErrorContext,
5297 "xmlNodeAddContentLen : node == NULL\n");
5298#endif
5299 return;
5300 }
5301 if (len <= 0) return;
5302 switch (cur->type) {
5303 case XML_DOCUMENT_FRAG_NODE:
5304 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005305 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005306
Daniel Veillard7db37732001-07-12 01:20:08 +00005307 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005308 newNode = xmlNewTextLen(content, len);
5309 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005310 tmp = xmlAddChild(cur, newNode);
5311 if (tmp != newNode)
5312 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005313 if ((last != NULL) && (last->next == newNode)) {
5314 xmlTextMerge(last, newNode);
5315 }
5316 }
5317 break;
5318 }
5319 case XML_ATTRIBUTE_NODE:
5320 break;
5321 case XML_TEXT_NODE:
5322 case XML_CDATA_SECTION_NODE:
5323 case XML_ENTITY_REF_NODE:
5324 case XML_ENTITY_NODE:
5325 case XML_PI_NODE:
5326 case XML_COMMENT_NODE:
5327 case XML_NOTATION_NODE:
5328 if (content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005329 if ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5330 xmlDictOwns(cur->doc->dict, cur->content)) {
5331 cur->content =
5332 xmlStrncatNew(cur->content, content, len);
5333 break;
5334 }
Owen Taylor3473f882001-02-23 17:55:21 +00005335 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005336 }
5337 case XML_DOCUMENT_NODE:
5338 case XML_DTD_NODE:
5339 case XML_HTML_DOCUMENT_NODE:
5340 case XML_DOCUMENT_TYPE_NODE:
5341 case XML_NAMESPACE_DECL:
5342 case XML_XINCLUDE_START:
5343 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005344#ifdef LIBXML_DOCB_ENABLED
5345 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005346#endif
5347 break;
5348 case XML_ELEMENT_DECL:
5349 case XML_ATTRIBUTE_DECL:
5350 case XML_ENTITY_DECL:
5351 break;
5352 }
5353}
5354
5355/**
5356 * xmlNodeAddContent:
5357 * @cur: the node being modified
5358 * @content: extra content
5359 *
5360 * Append the extra substring to the node content.
5361 */
5362void
5363xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5364 int len;
5365
5366 if (cur == NULL) {
5367#ifdef DEBUG_TREE
5368 xmlGenericError(xmlGenericErrorContext,
5369 "xmlNodeAddContent : node == NULL\n");
5370#endif
5371 return;
5372 }
5373 if (content == NULL) return;
5374 len = xmlStrlen(content);
5375 xmlNodeAddContentLen(cur, content, len);
5376}
5377
5378/**
5379 * xmlTextMerge:
5380 * @first: the first text node
5381 * @second: the second text node being merged
5382 *
5383 * Merge two text nodes into one
5384 * Returns the first text node augmented
5385 */
5386xmlNodePtr
5387xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5388 if (first == NULL) return(second);
5389 if (second == NULL) return(first);
5390 if (first->type != XML_TEXT_NODE) return(first);
5391 if (second->type != XML_TEXT_NODE) return(first);
5392 if (second->name != first->name)
5393 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005394 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005395 xmlUnlinkNode(second);
5396 xmlFreeNode(second);
5397 return(first);
5398}
5399
Daniel Veillard2156d432004-03-04 15:59:36 +00005400#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005401/**
5402 * xmlGetNsList:
5403 * @doc: the document
5404 * @node: the current node
5405 *
5406 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005407 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005408 * that need to be freed by the caller or NULL if no
5409 * namespace if defined
5410 */
5411xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005412xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5413{
Owen Taylor3473f882001-02-23 17:55:21 +00005414 xmlNsPtr cur;
5415 xmlNsPtr *ret = NULL;
5416 int nbns = 0;
5417 int maxns = 10;
5418 int i;
5419
5420 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005421 if (node->type == XML_ELEMENT_NODE) {
5422 cur = node->nsDef;
5423 while (cur != NULL) {
5424 if (ret == NULL) {
5425 ret =
5426 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5427 sizeof(xmlNsPtr));
5428 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005429 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005430 return (NULL);
5431 }
5432 ret[nbns] = NULL;
5433 }
5434 for (i = 0; i < nbns; i++) {
5435 if ((cur->prefix == ret[i]->prefix) ||
5436 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5437 break;
5438 }
5439 if (i >= nbns) {
5440 if (nbns >= maxns) {
5441 maxns *= 2;
5442 ret = (xmlNsPtr *) xmlRealloc(ret,
5443 (maxns +
5444 1) *
5445 sizeof(xmlNsPtr));
5446 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005447 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005448 return (NULL);
5449 }
5450 }
5451 ret[nbns++] = cur;
5452 ret[nbns] = NULL;
5453 }
Owen Taylor3473f882001-02-23 17:55:21 +00005454
Daniel Veillard77044732001-06-29 21:31:07 +00005455 cur = cur->next;
5456 }
5457 }
5458 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005459 }
Daniel Veillard77044732001-06-29 21:31:07 +00005460 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005461}
Daniel Veillard652327a2003-09-29 18:02:38 +00005462#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005463
5464/**
5465 * xmlSearchNs:
5466 * @doc: the document
5467 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005468 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005469 *
5470 * Search a Ns registered under a given name space for a document.
5471 * recurse on the parents until it finds the defined namespace
5472 * or return NULL otherwise.
5473 * @nameSpace can be NULL, this is a search for the default namespace.
5474 * We don't allow to cross entities boundaries. If you don't declare
5475 * the namespace within those you will be in troubles !!! A warning
5476 * is generated to cover this case.
5477 *
5478 * Returns the namespace pointer or NULL.
5479 */
5480xmlNsPtr
5481xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005482
Owen Taylor3473f882001-02-23 17:55:21 +00005483 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005484 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005485
5486 if (node == NULL) return(NULL);
5487 if ((nameSpace != NULL) &&
5488 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005489 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5490 /*
5491 * The XML-1.0 namespace is normally held on the root
5492 * element. In this case exceptionally create it on the
5493 * node element.
5494 */
5495 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5496 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005497 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005498 return(NULL);
5499 }
5500 memset(cur, 0, sizeof(xmlNs));
5501 cur->type = XML_LOCAL_NAMESPACE;
5502 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5503 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5504 cur->next = node->nsDef;
5505 node->nsDef = cur;
5506 return(cur);
5507 }
Owen Taylor3473f882001-02-23 17:55:21 +00005508 if (doc->oldNs == NULL) {
5509 /*
5510 * Allocate a new Namespace and fill the fields.
5511 */
5512 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5513 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005514 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005515 return(NULL);
5516 }
5517 memset(doc->oldNs, 0, sizeof(xmlNs));
5518 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5519
5520 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5521 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5522 }
5523 return(doc->oldNs);
5524 }
5525 while (node != NULL) {
5526 if ((node->type == XML_ENTITY_REF_NODE) ||
5527 (node->type == XML_ENTITY_NODE) ||
5528 (node->type == XML_ENTITY_DECL))
5529 return(NULL);
5530 if (node->type == XML_ELEMENT_NODE) {
5531 cur = node->nsDef;
5532 while (cur != NULL) {
5533 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5534 (cur->href != NULL))
5535 return(cur);
5536 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5537 (cur->href != NULL) &&
5538 (xmlStrEqual(cur->prefix, nameSpace)))
5539 return(cur);
5540 cur = cur->next;
5541 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005542 if (orig != node) {
5543 cur = node->ns;
5544 if (cur != NULL) {
5545 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5546 (cur->href != NULL))
5547 return(cur);
5548 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5549 (cur->href != NULL) &&
5550 (xmlStrEqual(cur->prefix, nameSpace)))
5551 return(cur);
5552 }
5553 }
Owen Taylor3473f882001-02-23 17:55:21 +00005554 }
5555 node = node->parent;
5556 }
5557 return(NULL);
5558}
5559
5560/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005561 * xmlNsInScope:
5562 * @doc: the document
5563 * @node: the current node
5564 * @ancestor: the ancestor carrying the namespace
5565 * @prefix: the namespace prefix
5566 *
5567 * Verify that the given namespace held on @ancestor is still in scope
5568 * on node.
5569 *
5570 * Returns 1 if true, 0 if false and -1 in case of error.
5571 */
5572static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005573xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5574 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005575{
5576 xmlNsPtr tst;
5577
5578 while ((node != NULL) && (node != ancestor)) {
5579 if ((node->type == XML_ENTITY_REF_NODE) ||
5580 (node->type == XML_ENTITY_NODE) ||
5581 (node->type == XML_ENTITY_DECL))
5582 return (-1);
5583 if (node->type == XML_ELEMENT_NODE) {
5584 tst = node->nsDef;
5585 while (tst != NULL) {
5586 if ((tst->prefix == NULL)
5587 && (prefix == NULL))
5588 return (0);
5589 if ((tst->prefix != NULL)
5590 && (prefix != NULL)
5591 && (xmlStrEqual(tst->prefix, prefix)))
5592 return (0);
5593 tst = tst->next;
5594 }
5595 }
5596 node = node->parent;
5597 }
5598 if (node != ancestor)
5599 return (-1);
5600 return (1);
5601}
5602
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005603/**
Owen Taylor3473f882001-02-23 17:55:21 +00005604 * xmlSearchNsByHref:
5605 * @doc: the document
5606 * @node: the current node
5607 * @href: the namespace value
5608 *
5609 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5610 * the defined namespace or return NULL otherwise.
5611 * Returns the namespace pointer or NULL.
5612 */
5613xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005614xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5615{
Owen Taylor3473f882001-02-23 17:55:21 +00005616 xmlNsPtr cur;
5617 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005618 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005619
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005620 if ((node == NULL) || (href == NULL))
5621 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005622 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005623 /*
5624 * Only the document can hold the XML spec namespace.
5625 */
5626 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5627 /*
5628 * The XML-1.0 namespace is normally held on the root
5629 * element. In this case exceptionally create it on the
5630 * node element.
5631 */
5632 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5633 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005634 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005635 return (NULL);
5636 }
5637 memset(cur, 0, sizeof(xmlNs));
5638 cur->type = XML_LOCAL_NAMESPACE;
5639 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5640 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5641 cur->next = node->nsDef;
5642 node->nsDef = cur;
5643 return (cur);
5644 }
5645 if (doc->oldNs == NULL) {
5646 /*
5647 * Allocate a new Namespace and fill the fields.
5648 */
5649 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5650 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005651 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005652 return (NULL);
5653 }
5654 memset(doc->oldNs, 0, sizeof(xmlNs));
5655 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005656
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005657 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5658 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5659 }
5660 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005661 }
Daniel Veillard62040be2004-05-17 03:17:26 +00005662 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00005663 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005664 if ((node->type == XML_ENTITY_REF_NODE) ||
5665 (node->type == XML_ENTITY_NODE) ||
5666 (node->type == XML_ENTITY_DECL))
5667 return (NULL);
5668 if (node->type == XML_ELEMENT_NODE) {
5669 cur = node->nsDef;
5670 while (cur != NULL) {
5671 if ((cur->href != NULL) && (href != NULL) &&
5672 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005673 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00005674 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005675 return (cur);
5676 }
5677 cur = cur->next;
5678 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005679 if (orig != node) {
5680 cur = node->ns;
5681 if (cur != NULL) {
5682 if ((cur->href != NULL) && (href != NULL) &&
5683 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005684 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00005685 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00005686 return (cur);
5687 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005688 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005689 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005690 }
5691 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005692 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005693 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005694}
5695
5696/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005697 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005698 * @doc: the document
5699 * @tree: a node expected to hold the new namespace
5700 * @ns: the original namespace
5701 *
5702 * This function tries to locate a namespace definition in a tree
5703 * ancestors, or create a new namespace definition node similar to
5704 * @ns trying to reuse the same prefix. However if the given prefix is
5705 * null (default namespace) or reused within the subtree defined by
5706 * @tree or on one of its ancestors then a new prefix is generated.
5707 * Returns the (new) namespace definition or NULL in case of error
5708 */
5709xmlNsPtr
5710xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5711 xmlNsPtr def;
5712 xmlChar prefix[50];
5713 int counter = 1;
5714
5715 if (tree == NULL) {
5716#ifdef DEBUG_TREE
5717 xmlGenericError(xmlGenericErrorContext,
5718 "xmlNewReconciliedNs : tree == NULL\n");
5719#endif
5720 return(NULL);
5721 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00005722 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005723#ifdef DEBUG_TREE
5724 xmlGenericError(xmlGenericErrorContext,
5725 "xmlNewReconciliedNs : ns == NULL\n");
5726#endif
5727 return(NULL);
5728 }
5729 /*
5730 * Search an existing namespace definition inherited.
5731 */
5732 def = xmlSearchNsByHref(doc, tree, ns->href);
5733 if (def != NULL)
5734 return(def);
5735
5736 /*
5737 * Find a close prefix which is not already in use.
5738 * Let's strip namespace prefixes longer than 20 chars !
5739 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005740 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005741 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005742 else
William M. Brack13dfa872004-09-18 04:52:08 +00005743 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005744
Owen Taylor3473f882001-02-23 17:55:21 +00005745 def = xmlSearchNs(doc, tree, prefix);
5746 while (def != NULL) {
5747 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005748 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005749 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005750 else
William M. Brack13dfa872004-09-18 04:52:08 +00005751 snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
5752 (char *)ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005753 def = xmlSearchNs(doc, tree, prefix);
5754 }
5755
5756 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005757 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005758 */
5759 def = xmlNewNs(tree, ns->href, prefix);
5760 return(def);
5761}
5762
Daniel Veillard652327a2003-09-29 18:02:38 +00005763#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005764/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005765 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005766 * @doc: the document
5767 * @tree: a node defining the subtree to reconciliate
5768 *
5769 * This function checks that all the namespaces declared within the given
5770 * tree are properly declared. This is needed for example after Copy or Cut
5771 * and then paste operations. The subtree may still hold pointers to
5772 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005773 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005774 * the new environment. If not possible the new namespaces are redeclared
5775 * on @tree at the top of the given subtree.
5776 * Returns the number of namespace declarations created or -1 in case of error.
5777 */
5778int
5779xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5780 xmlNsPtr *oldNs = NULL;
5781 xmlNsPtr *newNs = NULL;
5782 int sizeCache = 0;
5783 int nbCache = 0;
5784
5785 xmlNsPtr n;
5786 xmlNodePtr node = tree;
5787 xmlAttrPtr attr;
5788 int ret = 0, i;
5789
Daniel Veillardce244ad2004-11-05 10:03:46 +00005790 if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1);
5791 if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1);
5792 if (node->doc != doc) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005793 while (node != NULL) {
5794 /*
5795 * Reconciliate the node namespace
5796 */
5797 if (node->ns != NULL) {
5798 /*
5799 * initialize the cache if needed
5800 */
5801 if (sizeCache == 0) {
5802 sizeCache = 10;
5803 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5804 sizeof(xmlNsPtr));
5805 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005806 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005807 return(-1);
5808 }
5809 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5810 sizeof(xmlNsPtr));
5811 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005812 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005813 xmlFree(oldNs);
5814 return(-1);
5815 }
5816 }
5817 for (i = 0;i < nbCache;i++) {
5818 if (oldNs[i] == node->ns) {
5819 node->ns = newNs[i];
5820 break;
5821 }
5822 }
5823 if (i == nbCache) {
5824 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005825 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005826 */
5827 n = xmlNewReconciliedNs(doc, tree, node->ns);
5828 if (n != NULL) { /* :-( what if else ??? */
5829 /*
5830 * check if we need to grow the cache buffers.
5831 */
5832 if (sizeCache <= nbCache) {
5833 sizeCache *= 2;
5834 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5835 sizeof(xmlNsPtr));
5836 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005837 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005838 xmlFree(newNs);
5839 return(-1);
5840 }
5841 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5842 sizeof(xmlNsPtr));
5843 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005844 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005845 xmlFree(oldNs);
5846 return(-1);
5847 }
5848 }
5849 newNs[nbCache] = n;
5850 oldNs[nbCache++] = node->ns;
5851 node->ns = n;
5852 }
5853 }
5854 }
5855 /*
5856 * now check for namespace hold by attributes on the node.
5857 */
5858 attr = node->properties;
5859 while (attr != NULL) {
5860 if (attr->ns != NULL) {
5861 /*
5862 * initialize the cache if needed
5863 */
5864 if (sizeCache == 0) {
5865 sizeCache = 10;
5866 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5867 sizeof(xmlNsPtr));
5868 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005869 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005870 return(-1);
5871 }
5872 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5873 sizeof(xmlNsPtr));
5874 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005875 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005876 xmlFree(oldNs);
5877 return(-1);
5878 }
5879 }
5880 for (i = 0;i < nbCache;i++) {
5881 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005882 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005883 break;
5884 }
5885 }
5886 if (i == nbCache) {
5887 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005888 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005889 */
5890 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5891 if (n != NULL) { /* :-( what if else ??? */
5892 /*
5893 * check if we need to grow the cache buffers.
5894 */
5895 if (sizeCache <= nbCache) {
5896 sizeCache *= 2;
5897 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5898 sizeof(xmlNsPtr));
5899 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005900 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005901 xmlFree(newNs);
5902 return(-1);
5903 }
5904 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5905 sizeof(xmlNsPtr));
5906 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005907 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005908 xmlFree(oldNs);
5909 return(-1);
5910 }
5911 }
5912 newNs[nbCache] = n;
5913 oldNs[nbCache++] = attr->ns;
5914 attr->ns = n;
5915 }
5916 }
5917 }
5918 attr = attr->next;
5919 }
5920
5921 /*
5922 * Browse the full subtree, deep first
5923 */
Daniel Veillardac996a12004-07-30 12:02:58 +00005924 if (node->children != NULL && node->type != XML_ENTITY_REF_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00005925 /* deep first */
5926 node = node->children;
5927 } else if ((node != tree) && (node->next != NULL)) {
5928 /* then siblings */
5929 node = node->next;
5930 } else if (node != tree) {
5931 /* go up to parents->next if needed */
5932 while (node != tree) {
5933 if (node->parent != NULL)
5934 node = node->parent;
5935 if ((node != tree) && (node->next != NULL)) {
5936 node = node->next;
5937 break;
5938 }
5939 if (node->parent == NULL) {
5940 node = NULL;
5941 break;
5942 }
5943 }
5944 /* exit condition */
5945 if (node == tree)
5946 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005947 } else
5948 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005949 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005950 if (oldNs != NULL)
5951 xmlFree(oldNs);
5952 if (newNs != NULL)
5953 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005954 return(ret);
5955}
Daniel Veillard652327a2003-09-29 18:02:38 +00005956#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005957
5958/**
5959 * xmlHasProp:
5960 * @node: the node
5961 * @name: the attribute name
5962 *
5963 * Search an attribute associated to a node
5964 * This function also looks in DTD attribute declaration for #FIXED or
5965 * default declaration values unless DTD use has been turned off.
5966 *
5967 * Returns the attribute or the attribute declaration or NULL if
5968 * neither was found.
5969 */
5970xmlAttrPtr
5971xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5972 xmlAttrPtr prop;
5973 xmlDocPtr doc;
5974
5975 if ((node == NULL) || (name == NULL)) return(NULL);
5976 /*
5977 * Check on the properties attached to the node
5978 */
5979 prop = node->properties;
5980 while (prop != NULL) {
5981 if (xmlStrEqual(prop->name, name)) {
5982 return(prop);
5983 }
5984 prop = prop->next;
5985 }
5986 if (!xmlCheckDTD) return(NULL);
5987
5988 /*
5989 * Check if there is a default declaration in the internal
5990 * or external subsets
5991 */
5992 doc = node->doc;
5993 if (doc != NULL) {
5994 xmlAttributePtr attrDecl;
5995 if (doc->intSubset != NULL) {
5996 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5997 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5998 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005999 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6000 /* return attribute declaration only if a default value is given
6001 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006002 return((xmlAttrPtr) attrDecl);
6003 }
6004 }
6005 return(NULL);
6006}
6007
6008/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00006009 * xmlHasNsProp:
6010 * @node: the node
6011 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006012 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00006013 *
6014 * Search for an attribute associated to a node
6015 * This attribute has to be anchored in the namespace specified.
6016 * This does the entity substitution.
6017 * This function looks in DTD attribute declaration for #FIXED or
6018 * default declaration values unless DTD use has been turned off.
William M. Brack2c228442004-10-03 04:10:00 +00006019 * Note that a namespace of NULL indicates to use the default namespace.
Daniel Veillarde95e2392001-06-06 10:46:28 +00006020 *
6021 * Returns the attribute or the attribute declaration or NULL
6022 * if neither was found.
6023 */
6024xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00006025xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00006026 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00006027#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00006028 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00006029#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00006030
6031 if (node == NULL)
6032 return(NULL);
6033
6034 prop = node->properties;
Daniel Veillarde95e2392001-06-06 10:46:28 +00006035 while (prop != NULL) {
6036 /*
6037 * One need to have
6038 * - same attribute names
6039 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00006040 */
William M. Brack2c228442004-10-03 04:10:00 +00006041 if (xmlStrEqual(prop->name, name)) {
6042 if (((prop->ns != NULL) &&
6043 (xmlStrEqual(prop->ns->href, nameSpace))) ||
6044 ((prop->ns == NULL) && (nameSpace == NULL))) {
6045 return(prop);
6046 }
Daniel Veillarde95e2392001-06-06 10:46:28 +00006047 }
6048 prop = prop->next;
6049 }
6050 if (!xmlCheckDTD) return(NULL);
6051
Daniel Veillard652327a2003-09-29 18:02:38 +00006052#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00006053 /*
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 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006060 xmlAttributePtr attrDecl = NULL;
6061 xmlNsPtr *nsList, *cur;
6062 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00006063
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006064 nsList = xmlGetNsList(node->doc, node);
6065 if (nsList == NULL)
6066 return(NULL);
6067 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
6068 ename = xmlStrdup(node->ns->prefix);
6069 ename = xmlStrcat(ename, BAD_CAST ":");
6070 ename = xmlStrcat(ename, node->name);
6071 } else {
6072 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006073 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006074 if (ename == NULL) {
6075 xmlFree(nsList);
6076 return(NULL);
6077 }
6078
William M. Brack2c228442004-10-03 04:10:00 +00006079 if (nameSpace == NULL) {
6080 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
6081 name, NULL);
6082 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
6083 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6084 name, NULL);
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006085 }
William M. Brack2c228442004-10-03 04:10:00 +00006086 } else {
6087 cur = nsList;
6088 while (*cur != NULL) {
6089 if (xmlStrEqual((*cur)->href, nameSpace)) {
6090 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
6091 name, (*cur)->prefix);
6092 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6093 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6094 name, (*cur)->prefix);
6095 }
6096 cur++;
6097 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006098 }
6099 xmlFree(nsList);
6100 xmlFree(ename);
6101 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006102 }
6103 }
Daniel Veillard652327a2003-09-29 18:02:38 +00006104#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00006105 return(NULL);
6106}
6107
6108/**
Owen Taylor3473f882001-02-23 17:55:21 +00006109 * xmlGetProp:
6110 * @node: the node
6111 * @name: the attribute name
6112 *
6113 * Search and get the value of an attribute associated to a node
6114 * This does the entity substitution.
6115 * This function looks in DTD attribute declaration for #FIXED or
6116 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00006117 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00006118 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6119 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00006120 *
6121 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006122 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006123 */
6124xmlChar *
6125xmlGetProp(xmlNodePtr node, const xmlChar *name) {
6126 xmlAttrPtr prop;
6127 xmlDocPtr doc;
6128
6129 if ((node == NULL) || (name == NULL)) return(NULL);
6130 /*
6131 * Check on the properties attached to the node
6132 */
6133 prop = node->properties;
6134 while (prop != NULL) {
6135 if (xmlStrEqual(prop->name, name)) {
6136 xmlChar *ret;
6137
6138 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6139 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6140 return(ret);
6141 }
6142 prop = prop->next;
6143 }
6144 if (!xmlCheckDTD) return(NULL);
6145
6146 /*
6147 * Check if there is a default declaration in the internal
6148 * or external subsets
6149 */
6150 doc = node->doc;
6151 if (doc != NULL) {
6152 xmlAttributePtr attrDecl;
6153 if (doc->intSubset != NULL) {
6154 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6155 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6156 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006157 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6158 /* return attribute declaration only if a default value is given
6159 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006160 return(xmlStrdup(attrDecl->defaultValue));
6161 }
6162 }
6163 return(NULL);
6164}
6165
6166/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006167 * xmlGetNoNsProp:
6168 * @node: the node
6169 * @name: the attribute name
6170 *
6171 * Search and get the value of an attribute associated to a node
6172 * This does the entity substitution.
6173 * This function looks in DTD attribute declaration for #FIXED or
6174 * default declaration values unless DTD use has been turned off.
6175 * This function is similar to xmlGetProp except it will accept only
6176 * an attribute in no namespace.
6177 *
6178 * Returns the attribute value or NULL if not found.
6179 * It's up to the caller to free the memory with xmlFree().
6180 */
6181xmlChar *
6182xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6183 xmlAttrPtr prop;
6184 xmlDocPtr doc;
6185
6186 if ((node == NULL) || (name == NULL)) return(NULL);
6187 /*
6188 * Check on the properties attached to the node
6189 */
6190 prop = node->properties;
6191 while (prop != NULL) {
6192 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6193 xmlChar *ret;
6194
6195 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6196 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6197 return(ret);
6198 }
6199 prop = prop->next;
6200 }
6201 if (!xmlCheckDTD) return(NULL);
6202
6203 /*
6204 * Check if there is a default declaration in the internal
6205 * or external subsets
6206 */
6207 doc = node->doc;
6208 if (doc != NULL) {
6209 xmlAttributePtr attrDecl;
6210 if (doc->intSubset != NULL) {
6211 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6212 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6213 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006214 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6215 /* return attribute declaration only if a default value is given
6216 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006217 return(xmlStrdup(attrDecl->defaultValue));
6218 }
6219 }
6220 return(NULL);
6221}
6222
6223/**
Owen Taylor3473f882001-02-23 17:55:21 +00006224 * xmlGetNsProp:
6225 * @node: the node
6226 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006227 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006228 *
6229 * Search and get the value of an attribute associated to a node
6230 * This attribute has to be anchored in the namespace specified.
6231 * This does the entity substitution.
6232 * This function looks in DTD attribute declaration for #FIXED or
6233 * default declaration values unless DTD use has been turned off.
6234 *
6235 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006236 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006237 */
6238xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006239xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006240 xmlAttrPtr prop;
6241 xmlDocPtr doc;
6242 xmlNsPtr ns;
6243
6244 if (node == NULL)
6245 return(NULL);
6246
6247 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006248 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006249 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006250 while (prop != NULL) {
6251 /*
6252 * One need to have
6253 * - same attribute names
6254 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006255 */
6256 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006257 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006258 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006259 xmlChar *ret;
6260
6261 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6262 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6263 return(ret);
6264 }
6265 prop = prop->next;
6266 }
6267 if (!xmlCheckDTD) return(NULL);
6268
6269 /*
6270 * Check if there is a default declaration in the internal
6271 * or external subsets
6272 */
6273 doc = node->doc;
6274 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006275 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006276 xmlAttributePtr attrDecl;
6277
Owen Taylor3473f882001-02-23 17:55:21 +00006278 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6279 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6280 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6281
6282 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6283 /*
6284 * The DTD declaration only allows a prefix search
6285 */
6286 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006287 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006288 return(xmlStrdup(attrDecl->defaultValue));
6289 }
6290 }
6291 }
6292 return(NULL);
6293}
6294
Daniel Veillard2156d432004-03-04 15:59:36 +00006295#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6296/**
6297 * xmlUnsetProp:
6298 * @node: the node
6299 * @name: the attribute name
6300 *
6301 * Remove an attribute carried by a node.
6302 * Returns 0 if successful, -1 if not found
6303 */
6304int
6305xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
6306 xmlAttrPtr prop, prev = NULL;;
6307
6308 if ((node == NULL) || (name == NULL))
6309 return(-1);
6310 prop = node->properties;
6311 while (prop != NULL) {
6312 if ((xmlStrEqual(prop->name, name)) &&
6313 (prop->ns == NULL)) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006314 if (prev == NULL) {
Daniel Veillard2156d432004-03-04 15:59:36 +00006315 node->properties = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006316 if (prop->next != NULL)
6317 prop->next->prev = NULL;
6318 } else {
Daniel Veillard2156d432004-03-04 15:59:36 +00006319 prev->next = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006320 if (prop->next != NULL)
6321 prop->next->prev = NULL;
6322 }
6323 prop->next = NULL;
6324 prop->prev = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00006325 xmlFreeProp(prop);
6326 return(0);
6327 }
6328 prev = prop;
6329 prop = prop->next;
6330 }
6331 return(-1);
6332}
6333
6334/**
6335 * xmlUnsetNsProp:
6336 * @node: the node
6337 * @ns: the namespace definition
6338 * @name: the attribute name
6339 *
6340 * Remove an attribute carried by a node.
6341 * Returns 0 if successful, -1 if not found
6342 */
6343int
6344xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
Daniel Veillard27f20102004-11-05 11:50:11 +00006345 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard2156d432004-03-04 15:59:36 +00006346
6347 if ((node == NULL) || (name == NULL))
6348 return(-1);
Daniel Veillard27f20102004-11-05 11:50:11 +00006349 prop = node->properties;
Daniel Veillard2156d432004-03-04 15:59:36 +00006350 if (ns == NULL)
6351 return(xmlUnsetProp(node, name));
6352 if (ns->href == NULL)
6353 return(-1);
6354 while (prop != NULL) {
6355 if ((xmlStrEqual(prop->name, name)) &&
6356 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006357 if (prev == NULL) {
Daniel Veillard2156d432004-03-04 15:59:36 +00006358 node->properties = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006359 if (prop->next != NULL)
6360 prop->next->prev = NULL;
6361 } else {
Daniel Veillard2156d432004-03-04 15:59:36 +00006362 prev->next = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006363 if (prop->next != NULL)
6364 prop->next->prev = NULL;
6365 }
6366 prop->next = NULL;
6367 prop->prev = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00006368 xmlFreeProp(prop);
6369 return(0);
6370 }
6371 prev = prop;
6372 prop = prop->next;
6373 }
6374 return(-1);
6375}
6376#endif
6377
6378#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006379/**
6380 * xmlSetProp:
6381 * @node: the node
6382 * @name: the attribute name
6383 * @value: the attribute value
6384 *
6385 * Set (or reset) an attribute carried by a node.
6386 * Returns the attribute pointer.
6387 */
6388xmlAttrPtr
6389xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006390 xmlAttrPtr prop;
6391 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006392
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006393 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006394 return(NULL);
6395 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006396 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006397 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006398 if ((xmlStrEqual(prop->name, name)) &&
6399 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006400 xmlNodePtr oldprop = prop->children;
6401
Owen Taylor3473f882001-02-23 17:55:21 +00006402 prop->children = NULL;
6403 prop->last = NULL;
6404 if (value != NULL) {
6405 xmlChar *buffer;
6406 xmlNodePtr tmp;
6407
6408 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6409 prop->children = xmlStringGetNodeList(node->doc, buffer);
6410 prop->last = NULL;
6411 prop->doc = doc;
6412 tmp = prop->children;
6413 while (tmp != NULL) {
6414 tmp->parent = (xmlNodePtr) prop;
6415 tmp->doc = doc;
6416 if (tmp->next == NULL)
6417 prop->last = tmp;
6418 tmp = tmp->next;
6419 }
6420 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006421 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006422 if (oldprop != NULL)
6423 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006424 return(prop);
6425 }
6426 prop = prop->next;
6427 }
6428 prop = xmlNewProp(node, name, value);
6429 return(prop);
6430}
6431
6432/**
6433 * xmlSetNsProp:
6434 * @node: the node
6435 * @ns: the namespace definition
6436 * @name: the attribute name
6437 * @value: the attribute value
6438 *
6439 * Set (or reset) an attribute carried by a node.
6440 * The ns structure must be in scope, this is not checked.
6441 *
6442 * Returns the attribute pointer.
6443 */
6444xmlAttrPtr
6445xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6446 const xmlChar *value) {
6447 xmlAttrPtr prop;
6448
Daniel Veillardb6b36d32005-02-09 16:48:53 +00006449 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006450 return(NULL);
6451
6452 if (ns == NULL)
6453 return(xmlSetProp(node, name, value));
6454 if (ns->href == NULL)
6455 return(NULL);
6456 prop = node->properties;
6457
6458 while (prop != NULL) {
6459 /*
6460 * One need to have
6461 * - same attribute names
6462 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006463 */
6464 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006465 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006466 if (prop->children != NULL)
6467 xmlFreeNodeList(prop->children);
6468 prop->children = NULL;
6469 prop->last = NULL;
6470 prop->ns = ns;
6471 if (value != NULL) {
6472 xmlChar *buffer;
6473 xmlNodePtr tmp;
6474
6475 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6476 prop->children = xmlStringGetNodeList(node->doc, buffer);
6477 prop->last = NULL;
6478 tmp = prop->children;
6479 while (tmp != NULL) {
6480 tmp->parent = (xmlNodePtr) prop;
6481 if (tmp->next == NULL)
6482 prop->last = tmp;
6483 tmp = tmp->next;
6484 }
6485 xmlFree(buffer);
6486 }
6487 return(prop);
6488 }
6489 prop = prop->next;
6490 }
6491 prop = xmlNewNsProp(node, ns, name, value);
6492 return(prop);
6493}
6494
Daniel Veillard652327a2003-09-29 18:02:38 +00006495#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006496
6497/**
Owen Taylor3473f882001-02-23 17:55:21 +00006498 * xmlNodeIsText:
6499 * @node: the node
6500 *
6501 * Is this node a Text node ?
6502 * Returns 1 yes, 0 no
6503 */
6504int
6505xmlNodeIsText(xmlNodePtr node) {
6506 if (node == NULL) return(0);
6507
6508 if (node->type == XML_TEXT_NODE) return(1);
6509 return(0);
6510}
6511
6512/**
6513 * xmlIsBlankNode:
6514 * @node: the node
6515 *
6516 * Checks whether this node is an empty or whitespace only
6517 * (and possibly ignorable) text-node.
6518 *
6519 * Returns 1 yes, 0 no
6520 */
6521int
6522xmlIsBlankNode(xmlNodePtr node) {
6523 const xmlChar *cur;
6524 if (node == NULL) return(0);
6525
Daniel Veillard7db37732001-07-12 01:20:08 +00006526 if ((node->type != XML_TEXT_NODE) &&
6527 (node->type != XML_CDATA_SECTION_NODE))
6528 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006529 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006530 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006531 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006532 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006533 cur++;
6534 }
6535
6536 return(1);
6537}
6538
6539/**
6540 * xmlTextConcat:
6541 * @node: the node
6542 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006543 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006544 *
6545 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006546 *
6547 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006548 */
6549
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006550int
Owen Taylor3473f882001-02-23 17:55:21 +00006551xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006552 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006553
6554 if ((node->type != XML_TEXT_NODE) &&
6555 (node->type != XML_CDATA_SECTION_NODE)) {
6556#ifdef DEBUG_TREE
6557 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006558 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006559#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006560 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006561 }
William M. Brack7762bb12004-01-04 14:49:01 +00006562 /* need to check if content is currently in the dictionary */
6563 if ((node->doc != NULL) && (node->doc->dict != NULL) &&
6564 xmlDictOwns(node->doc->dict, node->content)) {
6565 node->content = xmlStrncatNew(node->content, content, len);
6566 } else {
6567 node->content = xmlStrncat(node->content, content, len);
6568 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006569 if (node->content == NULL)
6570 return(-1);
6571 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006572}
6573
6574/************************************************************************
6575 * *
6576 * Output : to a FILE or in memory *
6577 * *
6578 ************************************************************************/
6579
Owen Taylor3473f882001-02-23 17:55:21 +00006580/**
6581 * xmlBufferCreate:
6582 *
6583 * routine to create an XML buffer.
6584 * returns the new structure.
6585 */
6586xmlBufferPtr
6587xmlBufferCreate(void) {
6588 xmlBufferPtr ret;
6589
6590 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6591 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006592 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006593 return(NULL);
6594 }
6595 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006596 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006597 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006598 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006599 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006600 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006601 xmlFree(ret);
6602 return(NULL);
6603 }
6604 ret->content[0] = 0;
6605 return(ret);
6606}
6607
6608/**
6609 * xmlBufferCreateSize:
6610 * @size: initial size of buffer
6611 *
6612 * routine to create an XML buffer.
6613 * returns the new structure.
6614 */
6615xmlBufferPtr
6616xmlBufferCreateSize(size_t size) {
6617 xmlBufferPtr ret;
6618
6619 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6620 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006621 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006622 return(NULL);
6623 }
6624 ret->use = 0;
6625 ret->alloc = xmlBufferAllocScheme;
6626 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6627 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006628 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006629 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006630 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006631 xmlFree(ret);
6632 return(NULL);
6633 }
6634 ret->content[0] = 0;
6635 } else
6636 ret->content = NULL;
6637 return(ret);
6638}
6639
6640/**
Daniel Veillard53350552003-09-18 13:35:51 +00006641 * xmlBufferCreateStatic:
6642 * @mem: the memory area
6643 * @size: the size in byte
6644 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006645 * routine to create an XML buffer from an immutable memory area.
6646 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006647 * present until the end of the buffer lifetime.
6648 *
6649 * returns the new structure.
6650 */
6651xmlBufferPtr
6652xmlBufferCreateStatic(void *mem, size_t size) {
6653 xmlBufferPtr ret;
6654
6655 if ((mem == NULL) || (size == 0))
6656 return(NULL);
6657
6658 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6659 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006660 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006661 return(NULL);
6662 }
6663 ret->use = size;
6664 ret->size = size;
6665 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6666 ret->content = (xmlChar *) mem;
6667 return(ret);
6668}
6669
6670/**
Owen Taylor3473f882001-02-23 17:55:21 +00006671 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006672 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006673 * @scheme: allocation scheme to use
6674 *
6675 * Sets the allocation scheme for this buffer
6676 */
6677void
6678xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6679 xmlBufferAllocationScheme scheme) {
6680 if (buf == NULL) {
6681#ifdef DEBUG_BUFFER
6682 xmlGenericError(xmlGenericErrorContext,
6683 "xmlBufferSetAllocationScheme: buf == NULL\n");
6684#endif
6685 return;
6686 }
Daniel Veillard53350552003-09-18 13:35:51 +00006687 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006688
6689 buf->alloc = scheme;
6690}
6691
6692/**
6693 * xmlBufferFree:
6694 * @buf: the buffer to free
6695 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006696 * Frees an XML buffer. It frees both the content and the structure which
6697 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006698 */
6699void
6700xmlBufferFree(xmlBufferPtr buf) {
6701 if (buf == NULL) {
6702#ifdef DEBUG_BUFFER
6703 xmlGenericError(xmlGenericErrorContext,
6704 "xmlBufferFree: buf == NULL\n");
6705#endif
6706 return;
6707 }
Daniel Veillard53350552003-09-18 13:35:51 +00006708
6709 if ((buf->content != NULL) &&
6710 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006711 xmlFree(buf->content);
6712 }
Owen Taylor3473f882001-02-23 17:55:21 +00006713 xmlFree(buf);
6714}
6715
6716/**
6717 * xmlBufferEmpty:
6718 * @buf: the buffer
6719 *
6720 * empty a buffer.
6721 */
6722void
6723xmlBufferEmpty(xmlBufferPtr buf) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006724 if (buf == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006725 if (buf->content == NULL) return;
6726 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006727 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006728 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006729 } else {
6730 memset(buf->content, 0, buf->size);
6731 }
Owen Taylor3473f882001-02-23 17:55:21 +00006732}
6733
6734/**
6735 * xmlBufferShrink:
6736 * @buf: the buffer to dump
6737 * @len: the number of xmlChar to remove
6738 *
6739 * Remove the beginning of an XML buffer.
6740 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006741 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006742 */
6743int
6744xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
Daniel Veillard3d97e662004-11-04 10:49:00 +00006745 if (buf == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006746 if (len == 0) return(0);
6747 if (len > buf->use) return(-1);
6748
6749 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006750 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6751 buf->content += len;
6752 } else {
6753 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6754 buf->content[buf->use] = 0;
6755 }
Owen Taylor3473f882001-02-23 17:55:21 +00006756 return(len);
6757}
6758
6759/**
6760 * xmlBufferGrow:
6761 * @buf: the buffer
6762 * @len: the minimum free size to allocate
6763 *
6764 * Grow the available space of an XML buffer.
6765 *
6766 * Returns the new available space or -1 in case of error
6767 */
6768int
6769xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6770 int size;
6771 xmlChar *newbuf;
6772
Daniel Veillard3d97e662004-11-04 10:49:00 +00006773 if (buf == NULL) return(-1);
6774
Daniel Veillard53350552003-09-18 13:35:51 +00006775 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006776 if (len + buf->use < buf->size) return(0);
6777
William M. Brack30fe43f2004-07-26 18:00:58 +00006778/*
6779 * Windows has a BIG problem on realloc timing, so we try to double
6780 * the buffer size (if that's enough) (bug 146697)
6781 */
6782#ifdef WIN32
6783 if (buf->size > len)
6784 size = buf->size * 2;
6785 else
6786 size = buf->use + len + 100;
6787#else
Owen Taylor3473f882001-02-23 17:55:21 +00006788 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00006789#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006790
6791 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006792 if (newbuf == NULL) {
6793 xmlTreeErrMemory("growing buffer");
6794 return(-1);
6795 }
Owen Taylor3473f882001-02-23 17:55:21 +00006796 buf->content = newbuf;
6797 buf->size = size;
6798 return(buf->size - buf->use);
6799}
6800
6801/**
6802 * xmlBufferDump:
6803 * @file: the file output
6804 * @buf: the buffer to dump
6805 *
6806 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006807 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006808 */
6809int
6810xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6811 int ret;
6812
6813 if (buf == NULL) {
6814#ifdef DEBUG_BUFFER
6815 xmlGenericError(xmlGenericErrorContext,
6816 "xmlBufferDump: buf == NULL\n");
6817#endif
6818 return(0);
6819 }
6820 if (buf->content == NULL) {
6821#ifdef DEBUG_BUFFER
6822 xmlGenericError(xmlGenericErrorContext,
6823 "xmlBufferDump: buf->content == NULL\n");
6824#endif
6825 return(0);
6826 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006827 if (file == NULL)
6828 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006829 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6830 return(ret);
6831}
6832
6833/**
6834 * xmlBufferContent:
6835 * @buf: the buffer
6836 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006837 * Function to extract the content of a buffer
6838 *
Owen Taylor3473f882001-02-23 17:55:21 +00006839 * Returns the internal content
6840 */
6841
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006842const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006843xmlBufferContent(const xmlBufferPtr buf)
6844{
6845 if(!buf)
6846 return NULL;
6847
6848 return buf->content;
6849}
6850
6851/**
6852 * xmlBufferLength:
6853 * @buf: the buffer
6854 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006855 * Function to get the length of a buffer
6856 *
Owen Taylor3473f882001-02-23 17:55:21 +00006857 * Returns the length of data in the internal content
6858 */
6859
6860int
6861xmlBufferLength(const xmlBufferPtr buf)
6862{
6863 if(!buf)
6864 return 0;
6865
6866 return buf->use;
6867}
6868
6869/**
6870 * xmlBufferResize:
6871 * @buf: the buffer to resize
6872 * @size: the desired size
6873 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006874 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006875 *
6876 * Returns 0 in case of problems, 1 otherwise
6877 */
6878int
6879xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6880{
6881 unsigned int newSize;
6882 xmlChar* rebuf = NULL;
6883
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006884 if (buf == NULL)
6885 return(0);
6886
Daniel Veillard53350552003-09-18 13:35:51 +00006887 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6888
Owen Taylor3473f882001-02-23 17:55:21 +00006889 /* Don't resize if we don't have to */
6890 if (size < buf->size)
6891 return 1;
6892
6893 /* figure out new size */
6894 switch (buf->alloc){
6895 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillardbf629492004-04-20 22:20:59 +00006896 /*take care of empty case*/
6897 newSize = (buf->size ? buf->size*2 : size + 10);
Owen Taylor3473f882001-02-23 17:55:21 +00006898 while (size > newSize) newSize *= 2;
6899 break;
6900 case XML_BUFFER_ALLOC_EXACT:
6901 newSize = size+10;
6902 break;
6903 default:
6904 newSize = size+10;
6905 break;
6906 }
6907
6908 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006909 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006910 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006911 rebuf = (xmlChar *) xmlRealloc(buf->content,
6912 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006913 } else {
6914 /*
6915 * if we are reallocating a buffer far from being full, it's
6916 * better to make a new allocation and copy only the used range
6917 * and free the old one.
6918 */
6919 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6920 if (rebuf != NULL) {
6921 memcpy(rebuf, buf->content, buf->use);
6922 xmlFree(buf->content);
William M. Brack42331a92004-07-29 07:07:16 +00006923 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006924 }
6925 }
Owen Taylor3473f882001-02-23 17:55:21 +00006926 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006927 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006928 return 0;
6929 }
6930 buf->content = rebuf;
6931 buf->size = newSize;
6932
6933 return 1;
6934}
6935
6936/**
6937 * xmlBufferAdd:
6938 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006939 * @str: the #xmlChar string
6940 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006941 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006942 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006943 * str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006944 *
6945 * Returns 0 successful, a positive error code number otherwise
6946 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006947 */
William M. Bracka3215c72004-07-31 16:24:01 +00006948int
Owen Taylor3473f882001-02-23 17:55:21 +00006949xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6950 unsigned int needSize;
6951
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006952 if ((str == NULL) || (buf == NULL)) {
William M. Bracka3215c72004-07-31 16:24:01 +00006953 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006954 }
William M. Bracka3215c72004-07-31 16:24:01 +00006955 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006956 if (len < -1) {
6957#ifdef DEBUG_BUFFER
6958 xmlGenericError(xmlGenericErrorContext,
6959 "xmlBufferAdd: len < 0\n");
6960#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006961 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006962 }
William M. Bracka3215c72004-07-31 16:24:01 +00006963 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006964
6965 if (len < 0)
6966 len = xmlStrlen(str);
6967
William M. Bracka3215c72004-07-31 16:24:01 +00006968 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006969
6970 needSize = buf->use + len + 2;
6971 if (needSize > buf->size){
6972 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006973 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006974 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006975 }
6976 }
6977
6978 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6979 buf->use += len;
6980 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006981 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006982}
6983
6984/**
6985 * xmlBufferAddHead:
6986 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006987 * @str: the #xmlChar string
6988 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006989 *
6990 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006991 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006992 *
6993 * Returns 0 successful, a positive error code number otherwise
6994 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006995 */
William M. Bracka3215c72004-07-31 16:24:01 +00006996int
Owen Taylor3473f882001-02-23 17:55:21 +00006997xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6998 unsigned int needSize;
6999
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007000 if (buf == NULL)
7001 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007002 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007003 if (str == NULL) {
7004#ifdef DEBUG_BUFFER
7005 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007006 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007007#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007008 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007009 }
7010 if (len < -1) {
7011#ifdef DEBUG_BUFFER
7012 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007013 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007014#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007015 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007016 }
William M. Bracka3215c72004-07-31 16:24:01 +00007017 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007018
7019 if (len < 0)
7020 len = xmlStrlen(str);
7021
William M. Bracka3215c72004-07-31 16:24:01 +00007022 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007023
7024 needSize = buf->use + len + 2;
7025 if (needSize > buf->size){
7026 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007027 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007028 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007029 }
7030 }
7031
7032 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
7033 memmove(&buf->content[0], str, len * sizeof(xmlChar));
7034 buf->use += len;
7035 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007036 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007037}
7038
7039/**
7040 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00007041 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00007042 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00007043 *
7044 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007045 *
7046 * Returns 0 successful, a positive error code number otherwise
7047 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007048 */
William M. Bracka3215c72004-07-31 16:24:01 +00007049int
Owen Taylor3473f882001-02-23 17:55:21 +00007050xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007051 if (buf == NULL)
7052 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007053 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
7054 if (str == NULL) return -1;
7055 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00007056}
7057
7058/**
7059 * xmlBufferCCat:
7060 * @buf: the buffer to dump
7061 * @str: the C char string
7062 *
7063 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007064 *
7065 * Returns 0 successful, a positive error code number otherwise
7066 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007067 */
William M. Bracka3215c72004-07-31 16:24:01 +00007068int
Owen Taylor3473f882001-02-23 17:55:21 +00007069xmlBufferCCat(xmlBufferPtr buf, const char *str) {
7070 const char *cur;
7071
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007072 if (buf == NULL)
7073 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007074 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007075 if (str == NULL) {
7076#ifdef DEBUG_BUFFER
7077 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007078 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007079#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007080 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007081 }
7082 for (cur = str;*cur != 0;cur++) {
7083 if (buf->use + 10 >= buf->size) {
7084 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007085 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007086 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007087 }
7088 }
7089 buf->content[buf->use++] = *cur;
7090 }
7091 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007092 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007093}
7094
7095/**
7096 * xmlBufferWriteCHAR:
7097 * @buf: the XML buffer
7098 * @string: the string to add
7099 *
7100 * routine which manages and grows an output buffer. This one adds
7101 * xmlChars at the end of the buffer.
7102 */
7103void
Daniel Veillard53350552003-09-18 13:35:51 +00007104xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007105 if (buf == NULL)
7106 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007107 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007108 xmlBufferCat(buf, string);
7109}
7110
7111/**
7112 * xmlBufferWriteChar:
7113 * @buf: the XML buffer output
7114 * @string: the string to add
7115 *
7116 * routine which manage and grows an output buffer. This one add
7117 * C chars at the end of the array.
7118 */
7119void
7120xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007121 if (buf == NULL)
7122 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007123 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007124 xmlBufferCCat(buf, string);
7125}
7126
7127
7128/**
7129 * xmlBufferWriteQuotedString:
7130 * @buf: the XML buffer output
7131 * @string: the string to add
7132 *
7133 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00007134 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00007135 * quote or double-quotes internally
7136 */
7137void
7138xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00007139 const xmlChar *cur, *base;
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007140 if (buf == NULL)
7141 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007142 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00007143 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00007144 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00007145#ifdef DEBUG_BUFFER
7146 xmlGenericError(xmlGenericErrorContext,
7147 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7148#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00007149 xmlBufferCCat(buf, "\"");
7150 base = cur = string;
7151 while(*cur != 0){
7152 if(*cur == '"'){
7153 if (base != cur)
7154 xmlBufferAdd(buf, base, cur - base);
7155 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7156 cur++;
7157 base = cur;
7158 }
7159 else {
7160 cur++;
7161 }
7162 }
7163 if (base != cur)
7164 xmlBufferAdd(buf, base, cur - base);
7165 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007166 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007167 else{
7168 xmlBufferCCat(buf, "\'");
7169 xmlBufferCat(buf, string);
7170 xmlBufferCCat(buf, "\'");
7171 }
Owen Taylor3473f882001-02-23 17:55:21 +00007172 } else {
7173 xmlBufferCCat(buf, "\"");
7174 xmlBufferCat(buf, string);
7175 xmlBufferCCat(buf, "\"");
7176 }
7177}
7178
7179
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007180/**
7181 * xmlGetDocCompressMode:
7182 * @doc: the document
7183 *
7184 * get the compression ratio for a document, ZLIB based
7185 * Returns 0 (uncompressed) to 9 (max compression)
7186 */
7187int
7188xmlGetDocCompressMode (xmlDocPtr doc) {
7189 if (doc == NULL) return(-1);
7190 return(doc->compression);
7191}
7192
7193/**
7194 * xmlSetDocCompressMode:
7195 * @doc: the document
7196 * @mode: the compression ratio
7197 *
7198 * set the compression ratio for a document, ZLIB based
7199 * Correct values: 0 (uncompressed) to 9 (max compression)
7200 */
7201void
7202xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7203 if (doc == NULL) return;
7204 if (mode < 0) doc->compression = 0;
7205 else if (mode > 9) doc->compression = 9;
7206 else doc->compression = mode;
7207}
7208
7209/**
7210 * xmlGetCompressMode:
7211 *
7212 * get the default compression mode used, ZLIB based.
7213 * Returns 0 (uncompressed) to 9 (max compression)
7214 */
7215int
7216xmlGetCompressMode(void)
7217{
7218 return (xmlCompressMode);
7219}
7220
7221/**
7222 * xmlSetCompressMode:
7223 * @mode: the compression ratio
7224 *
7225 * set the default compression mode used, ZLIB based
7226 * Correct values: 0 (uncompressed) to 9 (max compression)
7227 */
7228void
7229xmlSetCompressMode(int mode) {
7230 if (mode < 0) xmlCompressMode = 0;
7231 else if (mode > 9) xmlCompressMode = 9;
7232 else xmlCompressMode = mode;
7233}
7234