blob: 805db66927c6249ae63483e440fb5e5895af35ca [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
Daniel Veillardd5c2f922002-11-21 14:10:52 +00004 * References:
5 * XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
6 *
Owen Taylor3473f882001-02-23 17:55:21 +00007 * See Copyright for the status of this software.
8 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00009 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000010 *
Owen Taylor3473f882001-02-23 17:55:21 +000011 */
12
Daniel Veillard34ce8be2002-03-18 19:37:11 +000013#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000014#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000015
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24#ifdef HAVE_ZLIB_H
25#include <zlib.h>
26#endif
27
28#include <libxml/xmlmemory.h>
29#include <libxml/tree.h>
30#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000031#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000032#include <libxml/entities.h>
33#include <libxml/valid.h>
34#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000035#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000036#include <libxml/globals.h>
Daniel Veillardd5c2f922002-11-21 14:10:52 +000037#ifdef LIBXML_HTML_ENABLED
38#include <libxml/HTMLtree.h>
39#endif
William M. Brack1d8c9b22004-12-25 10:14:57 +000040#ifdef LIBXML_DEBUG_ENABLED
41#include <libxml/debugXML.h>
42#endif
Owen Taylor3473f882001-02-23 17:55:21 +000043
Daniel Veillarda880b122003-04-21 21:36:41 +000044int __xmlRegisterCallbacks = 0;
45
Daniel Veillard56a4cb82001-03-24 17:00:36 +000046xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
47
48/************************************************************************
49 * *
Daniel Veillard18ec16e2003-10-07 23:16:40 +000050 * Tree memory error handler *
51 * *
52 ************************************************************************/
53/**
54 * xmlTreeErrMemory:
55 * @extra: extra informations
56 *
57 * Handle an out of memory condition
58 */
59static void
60xmlTreeErrMemory(const char *extra)
61{
62 __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
63}
64
65/**
66 * xmlTreeErr:
67 * @code: the error number
68 * @extra: extra informations
69 *
70 * Handle an out of memory condition
71 */
72static void
73xmlTreeErr(int code, xmlNodePtr node, const char *extra)
74{
75 const char *msg = NULL;
76
77 switch(code) {
78 case XML_TREE_INVALID_HEX:
Daniel Veillardac996a12004-07-30 12:02:58 +000079 msg = "invalid hexadecimal character value\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000080 break;
81 case XML_TREE_INVALID_DEC:
Daniel Veillardac996a12004-07-30 12:02:58 +000082 msg = "invalid decimal character value\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000083 break;
84 case XML_TREE_UNTERMINATED_ENTITY:
Daniel Veillardac996a12004-07-30 12:02:58 +000085 msg = "unterminated entity reference %15s\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000086 break;
87 default:
Daniel Veillardac996a12004-07-30 12:02:58 +000088 msg = "unexpected error number\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000089 }
90 __xmlSimpleError(XML_FROM_TREE, code, node, msg, extra);
91}
92
93/************************************************************************
94 * *
Daniel Veillard56a4cb82001-03-24 17:00:36 +000095 * A few static variables and macros *
96 * *
97 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000098/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000099const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +0000100/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +0000101const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +0000102 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +0000103/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +0000104const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
105
Owen Taylor3473f882001-02-23 17:55:21 +0000106static int xmlCompressMode = 0;
107static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000108
Owen Taylor3473f882001-02-23 17:55:21 +0000109#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
110 xmlNodePtr ulccur = (n)->children; \
111 if (ulccur == NULL) { \
112 (n)->last = NULL; \
113 } else { \
114 while (ulccur->next != NULL) { \
115 ulccur->parent = (n); \
116 ulccur = ulccur->next; \
117 } \
118 ulccur->parent = (n); \
119 (n)->last = ulccur; \
120}}
121
122/* #define DEBUG_BUFFER */
123/* #define DEBUG_TREE */
124
125/************************************************************************
126 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000127 * Functions to move to entities.c once the *
128 * API freeze is smoothen and they can be made public. *
129 * *
130 ************************************************************************/
131#include <libxml/hash.h>
132
Daniel Veillard652327a2003-09-29 18:02:38 +0000133#ifdef LIBXML_TREE_ENABLED
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000134/**
135 * xmlGetEntityFromDtd:
136 * @dtd: A pointer to the DTD to search
137 * @name: The entity name
138 *
139 * Do an entity lookup in the DTD entity hash table and
140 * return the corresponding entity, if found.
141 *
142 * Returns A pointer to the entity structure or NULL if not found.
143 */
144static xmlEntityPtr
145xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
146 xmlEntitiesTablePtr table;
147
148 if((dtd != NULL) && (dtd->entities != NULL)) {
149 table = (xmlEntitiesTablePtr) dtd->entities;
150 return((xmlEntityPtr) xmlHashLookup(table, name));
151 /* return(xmlGetEntityFromTable(table, name)); */
152 }
153 return(NULL);
154}
155/**
156 * xmlGetParameterEntityFromDtd:
157 * @dtd: A pointer to the DTD to search
158 * @name: The entity name
159 *
160 * Do an entity lookup in the DTD pararmeter entity hash table and
161 * return the corresponding entity, if found.
162 *
163 * Returns A pointer to the entity structure or NULL if not found.
164 */
165static xmlEntityPtr
166xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
167 xmlEntitiesTablePtr table;
168
169 if ((dtd != NULL) && (dtd->pentities != NULL)) {
170 table = (xmlEntitiesTablePtr) dtd->pentities;
171 return((xmlEntityPtr) xmlHashLookup(table, name));
172 /* return(xmlGetEntityFromTable(table, name)); */
173 }
174 return(NULL);
175}
Daniel Veillard652327a2003-09-29 18:02:38 +0000176#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000177
178/************************************************************************
179 * *
Daniel Veillardc00cda82003-04-07 10:22:39 +0000180 * QName handling helper *
181 * *
182 ************************************************************************/
183
184/**
185 * xmlBuildQName:
186 * @ncname: the Name
187 * @prefix: the prefix
188 * @memory: preallocated memory
189 * @len: preallocated memory length
190 *
191 * Builds the QName @prefix:@ncname in @memory if there is enough space
192 * and prefix is not NULL nor empty, otherwise allocate a new string.
193 * If prefix is NULL or empty it returns ncname.
194 *
195 * Returns the new string which must be freed by the caller if different from
196 * @memory and @ncname or NULL in case of error
197 */
198xmlChar *
199xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
200 xmlChar *memory, int len) {
201 int lenn, lenp;
202 xmlChar *ret;
203
Daniel Veillard3b7840c2003-09-11 23:42:01 +0000204 if (ncname == NULL) return(NULL);
205 if (prefix == NULL) return((xmlChar *) ncname);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000206
207 lenn = strlen((char *) ncname);
208 lenp = strlen((char *) prefix);
209
210 if ((memory == NULL) || (len < lenn + lenp + 2)) {
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000211 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000212 if (ret == NULL) {
213 xmlTreeErrMemory("building QName");
214 return(NULL);
215 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000216 } else {
217 ret = memory;
218 }
219 memcpy(&ret[0], prefix, lenp);
220 ret[lenp] = ':';
221 memcpy(&ret[lenp + 1], ncname, lenn);
222 ret[lenn + lenp + 1] = 0;
223 return(ret);
224}
225
226/**
227 * xmlSplitQName2:
228 * @name: the full QName
229 * @prefix: a xmlChar **
230 *
231 * parse an XML qualified name string
232 *
233 * [NS 5] QName ::= (Prefix ':')? LocalPart
234 *
235 * [NS 6] Prefix ::= NCName
236 *
237 * [NS 7] LocalPart ::= NCName
238 *
239 * Returns NULL if not a QName, otherwise the local part, and prefix
240 * is updated to get the Prefix if any.
241 */
242
243xmlChar *
244xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
245 int len = 0;
246 xmlChar *ret = NULL;
247
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000248 if (prefix == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000249 *prefix = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000250 if (name == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000251
252#ifndef XML_XML_NAMESPACE
253 /* xml: prefix is not really a namespace */
254 if ((name[0] == 'x') && (name[1] == 'm') &&
255 (name[2] == 'l') && (name[3] == ':'))
256 return(NULL);
257#endif
258
259 /* nasty but valid */
260 if (name[0] == ':')
261 return(NULL);
262
263 /*
264 * we are not trying to validate but just to cut, and yes it will
265 * work even if this is as set of UTF-8 encoded chars
266 */
267 while ((name[len] != 0) && (name[len] != ':'))
268 len++;
269
270 if (name[len] == 0)
271 return(NULL);
272
273 *prefix = xmlStrndup(name, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000274 if (*prefix == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000275 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000276 return(NULL);
277 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000278 ret = xmlStrdup(&name[len + 1]);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000279 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000280 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000281 if (*prefix != NULL) {
282 xmlFree(*prefix);
283 *prefix = NULL;
284 }
285 return(NULL);
286 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000287
288 return(ret);
289}
290
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000291/**
292 * xmlSplitQName3:
293 * @name: the full QName
294 * @len: an int *
295 *
296 * parse an XML qualified name string,i
297 *
298 * returns NULL if it is not a Qualified Name, otherwise, update len
299 * with the lenght in byte of the prefix and return a pointer
300 */
301
302const xmlChar *
303xmlSplitQName3(const xmlChar *name, int *len) {
304 int l = 0;
305
306 if (name == NULL) return(NULL);
307 if (len == NULL) return(NULL);
308
309 /* nasty but valid */
310 if (name[0] == ':')
311 return(NULL);
312
313 /*
314 * we are not trying to validate but just to cut, and yes it will
315 * work even if this is as set of UTF-8 encoded chars
316 */
317 while ((name[l] != 0) && (name[l] != ':'))
318 l++;
319
320 if (name[l] == 0)
321 return(NULL);
322
323 *len = l;
324
325 return(&name[l+1]);
326}
327
Daniel Veillardc00cda82003-04-07 10:22:39 +0000328/************************************************************************
329 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000330 * Check Name, NCName and QName strings *
331 * *
332 ************************************************************************/
333
334#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
335
Daniel Veillard03a53c32004-10-26 16:06:51 +0000336#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000337/**
338 * xmlValidateNCName:
339 * @value: the value to check
340 * @space: allow spaces in front and end of the string
341 *
342 * Check that a value conforms to the lexical space of NCName
343 *
344 * Returns 0 if this validates, a positive error code number otherwise
345 * and -1 in case of internal or API error.
346 */
347int
348xmlValidateNCName(const xmlChar *value, int space) {
349 const xmlChar *cur = value;
350 int c,l;
351
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000352 if (value == NULL)
353 return(-1);
354
Daniel Veillardd2298792003-02-14 16:54:11 +0000355 /*
356 * First quick algorithm for ASCII range
357 */
358 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000359 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000360 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
361 (*cur == '_'))
362 cur++;
363 else
364 goto try_complex;
365 while (((*cur >= 'a') && (*cur <= 'z')) ||
366 ((*cur >= 'A') && (*cur <= 'Z')) ||
367 ((*cur >= '0') && (*cur <= '9')) ||
368 (*cur == '_') || (*cur == '-') || (*cur == '.'))
369 cur++;
370 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000371 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000372 if (*cur == 0)
373 return(0);
374
375try_complex:
376 /*
377 * Second check for chars outside the ASCII range
378 */
379 cur = value;
380 c = CUR_SCHAR(cur, l);
381 if (space) {
382 while (IS_BLANK(c)) {
383 cur += l;
384 c = CUR_SCHAR(cur, l);
385 }
386 }
William M. Brack871611b2003-10-18 04:53:14 +0000387 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000388 return(1);
389 cur += l;
390 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000391 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
392 (c == '-') || (c == '_') || IS_COMBINING(c) ||
393 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000394 cur += l;
395 c = CUR_SCHAR(cur, l);
396 }
397 if (space) {
398 while (IS_BLANK(c)) {
399 cur += l;
400 c = CUR_SCHAR(cur, l);
401 }
402 }
403 if (c != 0)
404 return(1);
405
406 return(0);
407}
Daniel Veillard2156d432004-03-04 15:59:36 +0000408#endif
Daniel Veillardd2298792003-02-14 16:54:11 +0000409
Daniel Veillard2156d432004-03-04 15:59:36 +0000410#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000411/**
412 * xmlValidateQName:
413 * @value: the value to check
414 * @space: allow spaces in front and end of the string
415 *
416 * Check that a value conforms to the lexical space of QName
417 *
418 * Returns 0 if this validates, a positive error code number otherwise
419 * and -1 in case of internal or API error.
420 */
421int
422xmlValidateQName(const xmlChar *value, int space) {
423 const xmlChar *cur = value;
424 int c,l;
425
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000426 if (value == NULL)
427 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +0000428 /*
429 * First quick algorithm for ASCII range
430 */
431 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000432 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000433 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
434 (*cur == '_'))
435 cur++;
436 else
437 goto try_complex;
438 while (((*cur >= 'a') && (*cur <= 'z')) ||
439 ((*cur >= 'A') && (*cur <= 'Z')) ||
440 ((*cur >= '0') && (*cur <= '9')) ||
441 (*cur == '_') || (*cur == '-') || (*cur == '.'))
442 cur++;
443 if (*cur == ':') {
444 cur++;
445 if (((*cur >= 'a') && (*cur <= 'z')) ||
446 ((*cur >= 'A') && (*cur <= 'Z')) ||
447 (*cur == '_'))
448 cur++;
449 else
450 goto try_complex;
451 while (((*cur >= 'a') && (*cur <= 'z')) ||
452 ((*cur >= 'A') && (*cur <= 'Z')) ||
453 ((*cur >= '0') && (*cur <= '9')) ||
454 (*cur == '_') || (*cur == '-') || (*cur == '.'))
455 cur++;
456 }
457 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000458 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000459 if (*cur == 0)
460 return(0);
461
462try_complex:
463 /*
464 * Second check for chars outside the ASCII range
465 */
466 cur = value;
467 c = CUR_SCHAR(cur, l);
468 if (space) {
469 while (IS_BLANK(c)) {
470 cur += l;
471 c = CUR_SCHAR(cur, l);
472 }
473 }
William M. Brack871611b2003-10-18 04:53:14 +0000474 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000475 return(1);
476 cur += l;
477 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000478 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
479 (c == '-') || (c == '_') || IS_COMBINING(c) ||
480 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000481 cur += l;
482 c = CUR_SCHAR(cur, l);
483 }
484 if (c == ':') {
485 cur += l;
486 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000487 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000488 return(1);
489 cur += l;
490 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000491 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
492 (c == '-') || (c == '_') || IS_COMBINING(c) ||
493 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000494 cur += l;
495 c = CUR_SCHAR(cur, l);
496 }
497 }
498 if (space) {
499 while (IS_BLANK(c)) {
500 cur += l;
501 c = CUR_SCHAR(cur, l);
502 }
503 }
504 if (c != 0)
505 return(1);
506 return(0);
507}
508
509/**
510 * xmlValidateName:
511 * @value: the value to check
512 * @space: allow spaces in front and end of the string
513 *
514 * Check that a value conforms to the lexical space of Name
515 *
516 * Returns 0 if this validates, a positive error code number otherwise
517 * and -1 in case of internal or API error.
518 */
519int
520xmlValidateName(const xmlChar *value, int space) {
521 const xmlChar *cur = value;
522 int c,l;
523
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000524 if (value == NULL)
525 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +0000526 /*
527 * First quick algorithm for ASCII range
528 */
529 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000530 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000531 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
532 (*cur == '_') || (*cur == ':'))
533 cur++;
534 else
535 goto try_complex;
536 while (((*cur >= 'a') && (*cur <= 'z')) ||
537 ((*cur >= 'A') && (*cur <= 'Z')) ||
538 ((*cur >= '0') && (*cur <= '9')) ||
539 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
540 cur++;
541 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000542 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000543 if (*cur == 0)
544 return(0);
545
546try_complex:
547 /*
548 * Second check for chars outside the ASCII range
549 */
550 cur = value;
551 c = CUR_SCHAR(cur, l);
552 if (space) {
553 while (IS_BLANK(c)) {
554 cur += l;
555 c = CUR_SCHAR(cur, l);
556 }
557 }
William M. Brack871611b2003-10-18 04:53:14 +0000558 if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000559 return(1);
560 cur += l;
561 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000562 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
563 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000564 cur += l;
565 c = CUR_SCHAR(cur, l);
566 }
567 if (space) {
568 while (IS_BLANK(c)) {
569 cur += l;
570 c = CUR_SCHAR(cur, l);
571 }
572 }
573 if (c != 0)
574 return(1);
575 return(0);
576}
577
Daniel Veillardd4310742003-02-18 21:12:46 +0000578/**
579 * xmlValidateNMToken:
580 * @value: the value to check
581 * @space: allow spaces in front and end of the string
582 *
583 * Check that a value conforms to the lexical space of NMToken
584 *
585 * Returns 0 if this validates, a positive error code number otherwise
586 * and -1 in case of internal or API error.
587 */
588int
589xmlValidateNMToken(const xmlChar *value, int space) {
590 const xmlChar *cur = value;
591 int c,l;
592
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000593 if (value == NULL)
594 return(-1);
Daniel Veillardd4310742003-02-18 21:12:46 +0000595 /*
596 * First quick algorithm for ASCII range
597 */
598 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000599 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000600 if (((*cur >= 'a') && (*cur <= 'z')) ||
601 ((*cur >= 'A') && (*cur <= 'Z')) ||
602 ((*cur >= '0') && (*cur <= '9')) ||
603 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
604 cur++;
605 else
606 goto try_complex;
607 while (((*cur >= 'a') && (*cur <= 'z')) ||
608 ((*cur >= 'A') && (*cur <= 'Z')) ||
609 ((*cur >= '0') && (*cur <= '9')) ||
610 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
611 cur++;
612 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000613 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000614 if (*cur == 0)
615 return(0);
616
617try_complex:
618 /*
619 * Second check for chars outside the ASCII range
620 */
621 cur = value;
622 c = CUR_SCHAR(cur, l);
623 if (space) {
624 while (IS_BLANK(c)) {
625 cur += l;
626 c = CUR_SCHAR(cur, l);
627 }
628 }
William M. Brack871611b2003-10-18 04:53:14 +0000629 if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
630 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
Daniel Veillardd4310742003-02-18 21:12:46 +0000631 return(1);
632 cur += l;
633 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000634 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
635 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd4310742003-02-18 21:12:46 +0000636 cur += l;
637 c = CUR_SCHAR(cur, l);
638 }
639 if (space) {
640 while (IS_BLANK(c)) {
641 cur += l;
642 c = CUR_SCHAR(cur, l);
643 }
644 }
645 if (c != 0)
646 return(1);
647 return(0);
648}
Daniel Veillard652327a2003-09-29 18:02:38 +0000649#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardd4310742003-02-18 21:12:46 +0000650
Daniel Veillardd2298792003-02-14 16:54:11 +0000651/************************************************************************
652 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000653 * Allocation and deallocation of basic structures *
654 * *
655 ************************************************************************/
656
657/**
658 * xmlSetBufferAllocationScheme:
659 * @scheme: allocation method to use
660 *
661 * Set the buffer allocation method. Types are
662 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
663 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
664 * improves performance
665 */
666void
667xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
668 xmlBufferAllocScheme = scheme;
669}
670
671/**
672 * xmlGetBufferAllocationScheme:
673 *
674 * Types are
675 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
676 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
677 * improves performance
678 *
679 * Returns the current allocation scheme
680 */
681xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000682xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000683 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000684}
685
686/**
687 * xmlNewNs:
688 * @node: the element carrying the namespace
689 * @href: the URI associated
690 * @prefix: the prefix for the namespace
691 *
692 * Creation of a new Namespace. This function will refuse to create
693 * a namespace with a similar prefix than an existing one present on this
694 * node.
695 * We use href==NULL in the case of an element creation where the namespace
696 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000697 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000698 */
699xmlNsPtr
700xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
701 xmlNsPtr cur;
702
703 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
704 return(NULL);
705
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000706 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
707 return(NULL);
708
Owen Taylor3473f882001-02-23 17:55:21 +0000709 /*
710 * Allocate a new Namespace and fill the fields.
711 */
712 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
713 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000714 xmlTreeErrMemory("building namespace");
Owen Taylor3473f882001-02-23 17:55:21 +0000715 return(NULL);
716 }
717 memset(cur, 0, sizeof(xmlNs));
718 cur->type = XML_LOCAL_NAMESPACE;
719
720 if (href != NULL)
721 cur->href = xmlStrdup(href);
722 if (prefix != NULL)
723 cur->prefix = xmlStrdup(prefix);
724
725 /*
726 * Add it at the end to preserve parsing order ...
727 * and checks for existing use of the prefix
728 */
729 if (node != NULL) {
730 if (node->nsDef == NULL) {
731 node->nsDef = cur;
732 } else {
733 xmlNsPtr prev = node->nsDef;
734
735 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
736 (xmlStrEqual(prev->prefix, cur->prefix))) {
737 xmlFreeNs(cur);
738 return(NULL);
739 }
740 while (prev->next != NULL) {
741 prev = prev->next;
742 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
743 (xmlStrEqual(prev->prefix, cur->prefix))) {
744 xmlFreeNs(cur);
745 return(NULL);
746 }
747 }
748 prev->next = cur;
749 }
750 }
751 return(cur);
752}
753
754/**
755 * xmlSetNs:
756 * @node: a node in the document
757 * @ns: a namespace pointer
758 *
759 * Associate a namespace to a node, a posteriori.
760 */
761void
762xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
763 if (node == NULL) {
764#ifdef DEBUG_TREE
765 xmlGenericError(xmlGenericErrorContext,
766 "xmlSetNs: node == NULL\n");
767#endif
768 return;
769 }
770 node->ns = ns;
771}
772
773/**
774 * xmlFreeNs:
775 * @cur: the namespace pointer
776 *
777 * Free up the structures associated to a namespace
778 */
779void
780xmlFreeNs(xmlNsPtr cur) {
781 if (cur == NULL) {
782#ifdef DEBUG_TREE
783 xmlGenericError(xmlGenericErrorContext,
784 "xmlFreeNs : ns == NULL\n");
785#endif
786 return;
787 }
788 if (cur->href != NULL) xmlFree((char *) cur->href);
789 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000790 xmlFree(cur);
791}
792
793/**
794 * xmlFreeNsList:
795 * @cur: the first namespace pointer
796 *
797 * Free up all the structures associated to the chained namespaces.
798 */
799void
800xmlFreeNsList(xmlNsPtr cur) {
801 xmlNsPtr next;
802 if (cur == NULL) {
803#ifdef DEBUG_TREE
804 xmlGenericError(xmlGenericErrorContext,
805 "xmlFreeNsList : ns == NULL\n");
806#endif
807 return;
808 }
809 while (cur != NULL) {
810 next = cur->next;
811 xmlFreeNs(cur);
812 cur = next;
813 }
814}
815
816/**
817 * xmlNewDtd:
818 * @doc: the document pointer
819 * @name: the DTD name
820 * @ExternalID: the external ID
821 * @SystemID: the system ID
822 *
823 * Creation of a new DTD for the external subset. To create an
824 * internal subset, use xmlCreateIntSubset().
825 *
826 * Returns a pointer to the new DTD structure
827 */
828xmlDtdPtr
829xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
830 const xmlChar *ExternalID, const xmlChar *SystemID) {
831 xmlDtdPtr cur;
832
833 if ((doc != NULL) && (doc->extSubset != NULL)) {
834#ifdef DEBUG_TREE
835 xmlGenericError(xmlGenericErrorContext,
836 "xmlNewDtd(%s): document %s already have a DTD %s\n",
837 /* !!! */ (char *) name, doc->name,
838 /* !!! */ (char *)doc->extSubset->name);
839#endif
840 return(NULL);
841 }
842
843 /*
844 * Allocate a new DTD and fill the fields.
845 */
846 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
847 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000848 xmlTreeErrMemory("building DTD");
Owen Taylor3473f882001-02-23 17:55:21 +0000849 return(NULL);
850 }
851 memset(cur, 0 , sizeof(xmlDtd));
852 cur->type = XML_DTD_NODE;
853
854 if (name != NULL)
855 cur->name = xmlStrdup(name);
856 if (ExternalID != NULL)
857 cur->ExternalID = xmlStrdup(ExternalID);
858 if (SystemID != NULL)
859 cur->SystemID = xmlStrdup(SystemID);
860 if (doc != NULL)
861 doc->extSubset = cur;
862 cur->doc = doc;
863
Daniel Veillarda880b122003-04-21 21:36:41 +0000864 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000865 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000866 return(cur);
867}
868
869/**
870 * xmlGetIntSubset:
871 * @doc: the document pointer
872 *
873 * Get the internal subset of a document
874 * Returns a pointer to the DTD structure or NULL if not found
875 */
876
877xmlDtdPtr
878xmlGetIntSubset(xmlDocPtr doc) {
879 xmlNodePtr cur;
880
881 if (doc == NULL)
882 return(NULL);
883 cur = doc->children;
884 while (cur != NULL) {
885 if (cur->type == XML_DTD_NODE)
886 return((xmlDtdPtr) cur);
887 cur = cur->next;
888 }
889 return((xmlDtdPtr) doc->intSubset);
890}
891
892/**
893 * xmlCreateIntSubset:
894 * @doc: the document pointer
895 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000896 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000897 * @SystemID: the system ID
898 *
899 * Create the internal subset of a document
900 * Returns a pointer to the new DTD structure
901 */
902xmlDtdPtr
903xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
904 const xmlChar *ExternalID, const xmlChar *SystemID) {
905 xmlDtdPtr cur;
906
907 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
908#ifdef DEBUG_TREE
909 xmlGenericError(xmlGenericErrorContext,
910
911 "xmlCreateIntSubset(): document %s already have an internal subset\n",
912 doc->name);
913#endif
914 return(NULL);
915 }
916
917 /*
918 * Allocate a new DTD and fill the fields.
919 */
920 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
921 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000922 xmlTreeErrMemory("building internal subset");
Owen Taylor3473f882001-02-23 17:55:21 +0000923 return(NULL);
924 }
925 memset(cur, 0, sizeof(xmlDtd));
926 cur->type = XML_DTD_NODE;
927
William M. Bracka3215c72004-07-31 16:24:01 +0000928 if (name != NULL) {
929 cur->name = xmlStrdup(name);
930 if (cur->name == NULL) {
931 xmlTreeErrMemory("building internal subset");
932 xmlFree(cur);
933 return(NULL);
934 }
935 }
936 if (ExternalID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000937 cur->ExternalID = xmlStrdup(ExternalID);
William M. Bracka3215c72004-07-31 16:24:01 +0000938 if (cur->ExternalID == NULL) {
939 xmlTreeErrMemory("building internal subset");
940 if (cur->name != NULL)
941 xmlFree((char *)cur->name);
942 xmlFree(cur);
943 return(NULL);
944 }
945 }
946 if (SystemID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000947 cur->SystemID = xmlStrdup(SystemID);
William M. Bracka3215c72004-07-31 16:24:01 +0000948 if (cur->SystemID == NULL) {
949 xmlTreeErrMemory("building internal subset");
950 if (cur->name != NULL)
951 xmlFree((char *)cur->name);
952 if (cur->ExternalID != NULL)
953 xmlFree((char *)cur->ExternalID);
954 xmlFree(cur);
955 return(NULL);
956 }
957 }
Owen Taylor3473f882001-02-23 17:55:21 +0000958 if (doc != NULL) {
959 doc->intSubset = cur;
960 cur->parent = doc;
961 cur->doc = doc;
962 if (doc->children == NULL) {
963 doc->children = (xmlNodePtr) cur;
964 doc->last = (xmlNodePtr) cur;
965 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000966 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000967 xmlNodePtr prev;
968
Owen Taylor3473f882001-02-23 17:55:21 +0000969 prev = doc->children;
970 prev->prev = (xmlNodePtr) cur;
971 cur->next = prev;
972 doc->children = (xmlNodePtr) cur;
973 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000974 xmlNodePtr next;
975
976 next = doc->children;
977 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
978 next = next->next;
979 if (next == NULL) {
980 cur->prev = doc->last;
981 cur->prev->next = (xmlNodePtr) cur;
982 cur->next = NULL;
983 doc->last = (xmlNodePtr) cur;
984 } else {
985 cur->next = next;
986 cur->prev = next->prev;
987 if (cur->prev == NULL)
988 doc->children = (xmlNodePtr) cur;
989 else
990 cur->prev->next = (xmlNodePtr) cur;
991 next->prev = (xmlNodePtr) cur;
992 }
Owen Taylor3473f882001-02-23 17:55:21 +0000993 }
994 }
995 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000996
Daniel Veillarda880b122003-04-21 21:36:41 +0000997 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000998 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000999 return(cur);
1000}
1001
1002/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001003 * DICT_FREE:
1004 * @str: a string
1005 *
1006 * Free a string if it is not owned by the "dict" dictionnary in the
1007 * current scope
1008 */
1009#define DICT_FREE(str) \
1010 if ((str) && ((!dict) || \
1011 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
1012 xmlFree((char *)(str));
1013
1014/**
Owen Taylor3473f882001-02-23 17:55:21 +00001015 * xmlFreeDtd:
1016 * @cur: the DTD structure to free up
1017 *
1018 * Free a DTD structure.
1019 */
1020void
1021xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001022 xmlDictPtr dict = NULL;
1023
Owen Taylor3473f882001-02-23 17:55:21 +00001024 if (cur == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001025 return;
1026 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001027 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001028
Daniel Veillarda880b122003-04-21 21:36:41 +00001029 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001030 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1031
Owen Taylor3473f882001-02-23 17:55:21 +00001032 if (cur->children != NULL) {
1033 xmlNodePtr next, c = cur->children;
1034
1035 /*
William M. Brack18a04f22004-08-03 16:42:37 +00001036 * Cleanup all nodes which are not part of the specific lists
1037 * of notations, elements, attributes and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00001038 */
1039 while (c != NULL) {
1040 next = c->next;
William M. Brack18a04f22004-08-03 16:42:37 +00001041 if ((c->type != XML_NOTATION_NODE) &&
1042 (c->type != XML_ELEMENT_DECL) &&
1043 (c->type != XML_ATTRIBUTE_DECL) &&
1044 (c->type != XML_ENTITY_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001045 xmlUnlinkNode(c);
1046 xmlFreeNode(c);
1047 }
1048 c = next;
1049 }
1050 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001051 DICT_FREE(cur->name)
1052 DICT_FREE(cur->SystemID)
1053 DICT_FREE(cur->ExternalID)
Owen Taylor3473f882001-02-23 17:55:21 +00001054 /* TODO !!! */
1055 if (cur->notations != NULL)
1056 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1057
1058 if (cur->elements != NULL)
1059 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1060 if (cur->attributes != NULL)
1061 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1062 if (cur->entities != NULL)
1063 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1064 if (cur->pentities != NULL)
1065 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1066
Owen Taylor3473f882001-02-23 17:55:21 +00001067 xmlFree(cur);
1068}
1069
1070/**
1071 * xmlNewDoc:
1072 * @version: xmlChar string giving the version of XML "1.0"
1073 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001074 * Creates a new XML document
1075 *
Owen Taylor3473f882001-02-23 17:55:21 +00001076 * Returns a new document
1077 */
1078xmlDocPtr
1079xmlNewDoc(const xmlChar *version) {
1080 xmlDocPtr cur;
1081
1082 if (version == NULL)
1083 version = (const xmlChar *) "1.0";
1084
1085 /*
1086 * Allocate a new document and fill the fields.
1087 */
1088 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1089 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001090 xmlTreeErrMemory("building doc");
Owen Taylor3473f882001-02-23 17:55:21 +00001091 return(NULL);
1092 }
1093 memset(cur, 0, sizeof(xmlDoc));
1094 cur->type = XML_DOCUMENT_NODE;
1095
1096 cur->version = xmlStrdup(version);
William M. Bracka3215c72004-07-31 16:24:01 +00001097 if (cur->version == NULL) {
1098 xmlTreeErrMemory("building doc");
1099 xmlFree(cur);
1100 return(NULL);
1101 }
Owen Taylor3473f882001-02-23 17:55:21 +00001102 cur->standalone = -1;
1103 cur->compression = -1; /* not initialized */
1104 cur->doc = cur;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001105 /*
1106 * The in memory encoding is always UTF8
1107 * This field will never change and would
1108 * be obsolete if not for binary compatibility.
1109 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001110 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001111
Daniel Veillarda880b122003-04-21 21:36:41 +00001112 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001113 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001114 return(cur);
1115}
1116
1117/**
1118 * xmlFreeDoc:
1119 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001120 *
1121 * Free up all the structures used by a document, tree included.
1122 */
1123void
1124xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001125 xmlDtdPtr extSubset, intSubset;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001126 xmlDictPtr dict = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001127
Owen Taylor3473f882001-02-23 17:55:21 +00001128 if (cur == NULL) {
1129#ifdef DEBUG_TREE
1130 xmlGenericError(xmlGenericErrorContext,
1131 "xmlFreeDoc : document == NULL\n");
1132#endif
1133 return;
1134 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001135#ifdef LIBXML_DEBUG_RUNTIME
1136 xmlDebugCheckDocument(stderr, cur);
1137#endif
1138
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001139 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001140
Daniel Veillarda880b122003-04-21 21:36:41 +00001141 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001142 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1143
Daniel Veillard76d66f42001-05-16 21:05:17 +00001144 /*
1145 * Do this before freeing the children list to avoid ID lookups
1146 */
1147 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1148 cur->ids = NULL;
1149 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1150 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001151 extSubset = cur->extSubset;
1152 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001153 if (intSubset == extSubset)
1154 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001155 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001156 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001157 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001158 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001159 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001160 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001161 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001162 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001163 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001164 }
1165
1166 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001167 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001168
1169 DICT_FREE(cur->version)
1170 DICT_FREE(cur->name)
1171 DICT_FREE(cur->encoding)
1172 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001173 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001174 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001175}
1176
1177/**
1178 * xmlStringLenGetNodeList:
1179 * @doc: the document
1180 * @value: the value of the text
1181 * @len: the length of the string value
1182 *
1183 * Parse the value string and build the node list associated. Should
1184 * produce a flat tree with only TEXTs and ENTITY_REFs.
1185 * Returns a pointer to the first child
1186 */
1187xmlNodePtr
1188xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1189 xmlNodePtr ret = NULL, last = NULL;
1190 xmlNodePtr node;
1191 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001192 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001193 const xmlChar *q;
1194 xmlEntityPtr ent;
1195
1196 if (value == NULL) return(NULL);
1197
1198 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001199 while ((cur < end) && (*cur != 0)) {
1200 if (cur[0] == '&') {
1201 int charval = 0;
1202 xmlChar tmp;
1203
Owen Taylor3473f882001-02-23 17:55:21 +00001204 /*
1205 * Save the current text.
1206 */
1207 if (cur != q) {
1208 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1209 xmlNodeAddContentLen(last, q, cur - q);
1210 } else {
1211 node = xmlNewDocTextLen(doc, q, cur - q);
1212 if (node == NULL) return(ret);
1213 if (last == NULL)
1214 last = ret = node;
1215 else {
1216 last->next = node;
1217 node->prev = last;
1218 last = node;
1219 }
1220 }
1221 }
Owen Taylor3473f882001-02-23 17:55:21 +00001222 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001223 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1224 cur += 3;
1225 if (cur < end)
1226 tmp = *cur;
1227 else
1228 tmp = 0;
1229 while (tmp != ';') { /* Non input consuming loop */
1230 if ((tmp >= '0') && (tmp <= '9'))
1231 charval = charval * 16 + (tmp - '0');
1232 else if ((tmp >= 'a') && (tmp <= 'f'))
1233 charval = charval * 16 + (tmp - 'a') + 10;
1234 else if ((tmp >= 'A') && (tmp <= 'F'))
1235 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001236 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001237 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1238 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001239 charval = 0;
1240 break;
1241 }
1242 cur++;
1243 if (cur < end)
1244 tmp = *cur;
1245 else
1246 tmp = 0;
1247 }
1248 if (tmp == ';')
1249 cur++;
1250 q = cur;
1251 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1252 cur += 2;
1253 if (cur < end)
1254 tmp = *cur;
1255 else
1256 tmp = 0;
1257 while (tmp != ';') { /* Non input consuming loops */
1258 if ((tmp >= '0') && (tmp <= '9'))
1259 charval = charval * 10 + (tmp - '0');
1260 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001261 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1262 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001263 charval = 0;
1264 break;
1265 }
1266 cur++;
1267 if (cur < end)
1268 tmp = *cur;
1269 else
1270 tmp = 0;
1271 }
1272 if (tmp == ';')
1273 cur++;
1274 q = cur;
1275 } else {
1276 /*
1277 * Read the entity string
1278 */
1279 cur++;
1280 q = cur;
1281 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1282 if ((cur >= end) || (*cur == 0)) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001283 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1284 (const char *) q);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001285 return(ret);
1286 }
1287 if (cur != q) {
1288 /*
1289 * Predefined entities don't generate nodes
1290 */
1291 val = xmlStrndup(q, cur - q);
1292 ent = xmlGetDocEntity(doc, val);
1293 if ((ent != NULL) &&
1294 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1295 if (last == NULL) {
1296 node = xmlNewDocText(doc, ent->content);
1297 last = ret = node;
1298 } else if (last->type != XML_TEXT_NODE) {
1299 node = xmlNewDocText(doc, ent->content);
1300 last = xmlAddNextSibling(last, node);
1301 } else
1302 xmlNodeAddContent(last, ent->content);
1303
1304 } else {
1305 /*
1306 * Create a new REFERENCE_REF node
1307 */
1308 node = xmlNewReference(doc, val);
1309 if (node == NULL) {
1310 if (val != NULL) xmlFree(val);
1311 return(ret);
1312 }
1313 else if ((ent != NULL) && (ent->children == NULL)) {
1314 xmlNodePtr temp;
1315
1316 ent->children = xmlStringGetNodeList(doc,
1317 (const xmlChar*)node->content);
1318 ent->owner = 1;
1319 temp = ent->children;
1320 while (temp) {
1321 temp->parent = (xmlNodePtr)ent;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001322 ent->last = temp;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001323 temp = temp->next;
1324 }
1325 }
1326 if (last == NULL) {
1327 last = ret = node;
1328 } else {
1329 last = xmlAddNextSibling(last, node);
1330 }
1331 }
1332 xmlFree(val);
1333 }
1334 cur++;
1335 q = cur;
1336 }
1337 if (charval != 0) {
1338 xmlChar buf[10];
1339 int l;
1340
1341 l = xmlCopyCharMultiByte(buf, charval);
1342 buf[l] = 0;
1343 node = xmlNewDocText(doc, buf);
1344 if (node != NULL) {
1345 if (last == NULL) {
1346 last = ret = node;
1347 } else {
1348 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001349 }
1350 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001351 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001352 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001353 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001354 cur++;
1355 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001356 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001357 /*
1358 * Handle the last piece of text.
1359 */
1360 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1361 xmlNodeAddContentLen(last, q, cur - q);
1362 } else {
1363 node = xmlNewDocTextLen(doc, q, cur - q);
1364 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001365 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001366 last = ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001367 } else {
1368 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001369 }
1370 }
1371 }
1372 return(ret);
1373}
1374
1375/**
1376 * xmlStringGetNodeList:
1377 * @doc: the document
1378 * @value: the value of the attribute
1379 *
1380 * Parse the value string and build the node list associated. Should
1381 * produce a flat tree with only TEXTs and ENTITY_REFs.
1382 * Returns a pointer to the first child
1383 */
1384xmlNodePtr
1385xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1386 xmlNodePtr ret = NULL, last = NULL;
1387 xmlNodePtr node;
1388 xmlChar *val;
1389 const xmlChar *cur = value;
1390 const xmlChar *q;
1391 xmlEntityPtr ent;
1392
1393 if (value == NULL) return(NULL);
1394
1395 q = cur;
1396 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001397 if (cur[0] == '&') {
1398 int charval = 0;
1399 xmlChar tmp;
1400
Owen Taylor3473f882001-02-23 17:55:21 +00001401 /*
1402 * Save the current text.
1403 */
1404 if (cur != q) {
1405 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1406 xmlNodeAddContentLen(last, q, cur - q);
1407 } else {
1408 node = xmlNewDocTextLen(doc, q, cur - q);
1409 if (node == NULL) return(ret);
1410 if (last == NULL)
1411 last = ret = node;
1412 else {
1413 last->next = node;
1414 node->prev = last;
1415 last = node;
1416 }
1417 }
1418 }
Owen Taylor3473f882001-02-23 17:55:21 +00001419 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001420 if ((cur[1] == '#') && (cur[2] == 'x')) {
1421 cur += 3;
1422 tmp = *cur;
1423 while (tmp != ';') { /* Non input consuming loop */
1424 if ((tmp >= '0') && (tmp <= '9'))
1425 charval = charval * 16 + (tmp - '0');
1426 else if ((tmp >= 'a') && (tmp <= 'f'))
1427 charval = charval * 16 + (tmp - 'a') + 10;
1428 else if ((tmp >= 'A') && (tmp <= 'F'))
1429 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001430 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001431 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1432 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001433 charval = 0;
1434 break;
1435 }
1436 cur++;
1437 tmp = *cur;
1438 }
1439 if (tmp == ';')
1440 cur++;
1441 q = cur;
1442 } else if (cur[1] == '#') {
1443 cur += 2;
1444 tmp = *cur;
1445 while (tmp != ';') { /* Non input consuming loops */
1446 if ((tmp >= '0') && (tmp <= '9'))
1447 charval = charval * 10 + (tmp - '0');
1448 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001449 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1450 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001451 charval = 0;
1452 break;
1453 }
1454 cur++;
1455 tmp = *cur;
1456 }
1457 if (tmp == ';')
1458 cur++;
1459 q = cur;
1460 } else {
1461 /*
1462 * Read the entity string
1463 */
1464 cur++;
1465 q = cur;
1466 while ((*cur != 0) && (*cur != ';')) cur++;
1467 if (*cur == 0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001468 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1469 (xmlNodePtr) doc, (const char *) q);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001470 return(ret);
1471 }
1472 if (cur != q) {
1473 /*
1474 * Predefined entities don't generate nodes
1475 */
1476 val = xmlStrndup(q, cur - q);
1477 ent = xmlGetDocEntity(doc, val);
1478 if ((ent != NULL) &&
1479 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1480 if (last == NULL) {
1481 node = xmlNewDocText(doc, ent->content);
1482 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001483 } else if (last->type != XML_TEXT_NODE) {
1484 node = xmlNewDocText(doc, ent->content);
1485 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001486 } else
1487 xmlNodeAddContent(last, ent->content);
1488
1489 } else {
1490 /*
1491 * Create a new REFERENCE_REF node
1492 */
1493 node = xmlNewReference(doc, val);
1494 if (node == NULL) {
1495 if (val != NULL) xmlFree(val);
1496 return(ret);
1497 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001498 else if ((ent != NULL) && (ent->children == NULL)) {
1499 xmlNodePtr temp;
1500
1501 ent->children = xmlStringGetNodeList(doc,
1502 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001503 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001504 temp = ent->children;
1505 while (temp) {
1506 temp->parent = (xmlNodePtr)ent;
1507 temp = temp->next;
1508 }
1509 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001510 if (last == NULL) {
1511 last = ret = node;
1512 } else {
1513 last = xmlAddNextSibling(last, node);
1514 }
1515 }
1516 xmlFree(val);
1517 }
1518 cur++;
1519 q = cur;
1520 }
1521 if (charval != 0) {
1522 xmlChar buf[10];
1523 int len;
1524
1525 len = xmlCopyCharMultiByte(buf, charval);
1526 buf[len] = 0;
1527 node = xmlNewDocText(doc, buf);
1528 if (node != NULL) {
1529 if (last == NULL) {
1530 last = ret = node;
1531 } else {
1532 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001533 }
1534 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001535
1536 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001537 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001538 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001539 cur++;
1540 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001541 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001542 /*
1543 * Handle the last piece of text.
1544 */
1545 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1546 xmlNodeAddContentLen(last, q, cur - q);
1547 } else {
1548 node = xmlNewDocTextLen(doc, q, cur - q);
1549 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001550 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001551 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001552 } else {
1553 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001554 }
1555 }
1556 }
1557 return(ret);
1558}
1559
1560/**
1561 * xmlNodeListGetString:
1562 * @doc: the document
1563 * @list: a Node list
1564 * @inLine: should we replace entity contents or show their external form
1565 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001566 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001567 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001568 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001569 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001570 */
1571xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001572xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1573{
Owen Taylor3473f882001-02-23 17:55:21 +00001574 xmlNodePtr node = list;
1575 xmlChar *ret = NULL;
1576 xmlEntityPtr ent;
1577
Daniel Veillard7646b182002-04-20 06:41:40 +00001578 if (list == NULL)
1579 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001580
1581 while (node != NULL) {
1582 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001583 (node->type == XML_CDATA_SECTION_NODE)) {
1584 if (inLine) {
1585 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001586 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001587 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001588
Daniel Veillard7646b182002-04-20 06:41:40 +00001589 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1590 if (buffer != NULL) {
1591 ret = xmlStrcat(ret, buffer);
1592 xmlFree(buffer);
1593 }
1594 }
1595 } else if (node->type == XML_ENTITY_REF_NODE) {
1596 if (inLine) {
1597 ent = xmlGetDocEntity(doc, node->name);
1598 if (ent != NULL) {
1599 xmlChar *buffer;
1600
1601 /* an entity content can be any "well balanced chunk",
1602 * i.e. the result of the content [43] production:
1603 * http://www.w3.org/TR/REC-xml#NT-content.
1604 * So it can contain text, CDATA section or nested
1605 * entity reference nodes (among others).
1606 * -> we recursive call xmlNodeListGetString()
1607 * which handles these types */
1608 buffer = xmlNodeListGetString(doc, ent->children, 1);
1609 if (buffer != NULL) {
1610 ret = xmlStrcat(ret, buffer);
1611 xmlFree(buffer);
1612 }
1613 } else {
1614 ret = xmlStrcat(ret, node->content);
1615 }
1616 } else {
1617 xmlChar buf[2];
1618
1619 buf[0] = '&';
1620 buf[1] = 0;
1621 ret = xmlStrncat(ret, buf, 1);
1622 ret = xmlStrcat(ret, node->name);
1623 buf[0] = ';';
1624 buf[1] = 0;
1625 ret = xmlStrncat(ret, buf, 1);
1626 }
1627 }
1628#if 0
1629 else {
1630 xmlGenericError(xmlGenericErrorContext,
1631 "xmlGetNodeListString : invalid node type %d\n",
1632 node->type);
1633 }
1634#endif
1635 node = node->next;
1636 }
1637 return (ret);
1638}
Daniel Veillard652327a2003-09-29 18:02:38 +00001639
1640#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001641/**
1642 * xmlNodeListGetRawString:
1643 * @doc: the document
1644 * @list: a Node list
1645 * @inLine: should we replace entity contents or show their external form
1646 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001647 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001648 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1649 * this function doesn't do any character encoding handling.
1650 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001651 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001652 */
1653xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001654xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1655{
Owen Taylor3473f882001-02-23 17:55:21 +00001656 xmlNodePtr node = list;
1657 xmlChar *ret = NULL;
1658 xmlEntityPtr ent;
1659
Daniel Veillard7646b182002-04-20 06:41:40 +00001660 if (list == NULL)
1661 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001662
1663 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001664 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001665 (node->type == XML_CDATA_SECTION_NODE)) {
1666 if (inLine) {
1667 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001668 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001669 xmlChar *buffer;
1670
1671 buffer = xmlEncodeSpecialChars(doc, node->content);
1672 if (buffer != NULL) {
1673 ret = xmlStrcat(ret, buffer);
1674 xmlFree(buffer);
1675 }
1676 }
1677 } else if (node->type == XML_ENTITY_REF_NODE) {
1678 if (inLine) {
1679 ent = xmlGetDocEntity(doc, node->name);
1680 if (ent != NULL) {
1681 xmlChar *buffer;
1682
1683 /* an entity content can be any "well balanced chunk",
1684 * i.e. the result of the content [43] production:
1685 * http://www.w3.org/TR/REC-xml#NT-content.
1686 * So it can contain text, CDATA section or nested
1687 * entity reference nodes (among others).
1688 * -> we recursive call xmlNodeListGetRawString()
1689 * which handles these types */
1690 buffer =
1691 xmlNodeListGetRawString(doc, ent->children, 1);
1692 if (buffer != NULL) {
1693 ret = xmlStrcat(ret, buffer);
1694 xmlFree(buffer);
1695 }
1696 } else {
1697 ret = xmlStrcat(ret, node->content);
1698 }
1699 } else {
1700 xmlChar buf[2];
1701
1702 buf[0] = '&';
1703 buf[1] = 0;
1704 ret = xmlStrncat(ret, buf, 1);
1705 ret = xmlStrcat(ret, node->name);
1706 buf[0] = ';';
1707 buf[1] = 0;
1708 ret = xmlStrncat(ret, buf, 1);
1709 }
1710 }
Owen Taylor3473f882001-02-23 17:55:21 +00001711#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001712 else {
1713 xmlGenericError(xmlGenericErrorContext,
1714 "xmlGetNodeListString : invalid node type %d\n",
1715 node->type);
1716 }
Owen Taylor3473f882001-02-23 17:55:21 +00001717#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001718 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001719 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001720 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001721}
Daniel Veillard652327a2003-09-29 18:02:38 +00001722#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001723
Daniel Veillard2156d432004-03-04 15:59:36 +00001724#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00001725/**
1726 * xmlNewProp:
1727 * @node: the holding node
1728 * @name: the name of the attribute
1729 * @value: the value of the attribute
1730 *
1731 * Create a new property carried by a node.
1732 * Returns a pointer to the attribute
1733 */
1734xmlAttrPtr
1735xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1736 xmlAttrPtr cur;
1737 xmlDocPtr doc = NULL;
1738
1739 if (name == NULL) {
1740#ifdef DEBUG_TREE
1741 xmlGenericError(xmlGenericErrorContext,
1742 "xmlNewProp : name == NULL\n");
1743#endif
1744 return(NULL);
1745 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001746 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1747 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001748
1749 /*
1750 * Allocate a new property and fill the fields.
1751 */
1752 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1753 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001754 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001755 return(NULL);
1756 }
1757 memset(cur, 0, sizeof(xmlAttr));
1758 cur->type = XML_ATTRIBUTE_NODE;
1759
1760 cur->parent = node;
1761 if (node != NULL) {
1762 doc = node->doc;
1763 cur->doc = doc;
1764 }
Daniel Veillard03a53c32004-10-26 16:06:51 +00001765 if ((doc != NULL) && (doc->dict != NULL))
1766 cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
1767 else
1768 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00001769 if (value != NULL) {
1770 xmlChar *buffer;
1771 xmlNodePtr tmp;
1772
1773 buffer = xmlEncodeEntitiesReentrant(doc, value);
1774 cur->children = xmlStringGetNodeList(doc, buffer);
1775 cur->last = NULL;
1776 tmp = cur->children;
1777 while (tmp != NULL) {
1778 tmp->parent = (xmlNodePtr) cur;
1779 tmp->doc = doc;
1780 if (tmp->next == NULL)
1781 cur->last = tmp;
1782 tmp = tmp->next;
1783 }
1784 xmlFree(buffer);
1785 }
1786
1787 /*
1788 * Add it at the end to preserve parsing order ...
1789 */
1790 if (node != NULL) {
1791 if (node->properties == NULL) {
1792 node->properties = cur;
1793 } else {
1794 xmlAttrPtr prev = node->properties;
1795
1796 while (prev->next != NULL) prev = prev->next;
1797 prev->next = cur;
1798 cur->prev = prev;
1799 }
1800 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001801
Daniel Veillarda880b122003-04-21 21:36:41 +00001802 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001803 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001804 return(cur);
1805}
Daniel Veillard652327a2003-09-29 18:02:38 +00001806#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001807
1808/**
1809 * xmlNewNsProp:
1810 * @node: the holding node
1811 * @ns: the namespace
1812 * @name: the name of the attribute
1813 * @value: the value of the attribute
1814 *
1815 * Create a new property tagged with a namespace and carried by a node.
1816 * Returns a pointer to the attribute
1817 */
1818xmlAttrPtr
1819xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1820 const xmlChar *value) {
1821 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001822 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001823
1824 if (name == NULL) {
1825#ifdef DEBUG_TREE
1826 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001827 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001828#endif
1829 return(NULL);
1830 }
1831
1832 /*
1833 * Allocate a new property and fill the fields.
1834 */
1835 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1836 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001837 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001838 return(NULL);
1839 }
1840 memset(cur, 0, sizeof(xmlAttr));
1841 cur->type = XML_ATTRIBUTE_NODE;
1842
1843 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001844 if (node != NULL) {
1845 doc = node->doc;
1846 cur->doc = doc;
1847 }
Owen Taylor3473f882001-02-23 17:55:21 +00001848 cur->ns = ns;
Daniel Veillard03a53c32004-10-26 16:06:51 +00001849 if ((doc != NULL) && (doc->dict != NULL))
1850 cur->name = xmlDictLookup(doc->dict, name, -1);
1851 else
1852 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00001853 if (value != NULL) {
1854 xmlChar *buffer;
1855 xmlNodePtr tmp;
1856
Daniel Veillarda682b212001-06-07 19:59:42 +00001857 buffer = xmlEncodeEntitiesReentrant(doc, value);
1858 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001859 cur->last = NULL;
1860 tmp = cur->children;
1861 while (tmp != NULL) {
1862 tmp->parent = (xmlNodePtr) cur;
1863 if (tmp->next == NULL)
1864 cur->last = tmp;
1865 tmp = tmp->next;
1866 }
1867 xmlFree(buffer);
1868 }
1869
1870 /*
1871 * Add it at the end to preserve parsing order ...
1872 */
1873 if (node != NULL) {
1874 if (node->properties == NULL) {
1875 node->properties = cur;
1876 } else {
1877 xmlAttrPtr prev = node->properties;
1878
1879 while (prev->next != NULL) prev = prev->next;
1880 prev->next = cur;
1881 cur->prev = prev;
1882 }
1883 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001884
Daniel Veillarda880b122003-04-21 21:36:41 +00001885 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001886 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001887 return(cur);
1888}
1889
1890/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001891 * xmlNewNsPropEatName:
1892 * @node: the holding node
1893 * @ns: the namespace
1894 * @name: the name of the attribute
1895 * @value: the value of the attribute
1896 *
1897 * Create a new property tagged with a namespace and carried by a node.
1898 * Returns a pointer to the attribute
1899 */
1900xmlAttrPtr
1901xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1902 const xmlChar *value) {
1903 xmlAttrPtr cur;
1904 xmlDocPtr doc = NULL;
1905
1906 if (name == NULL) {
1907#ifdef DEBUG_TREE
1908 xmlGenericError(xmlGenericErrorContext,
1909 "xmlNewNsPropEatName : name == NULL\n");
1910#endif
1911 return(NULL);
1912 }
1913
1914 /*
1915 * Allocate a new property and fill the fields.
1916 */
1917 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1918 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001919 xmlTreeErrMemory("building attribute");
Daniel Veillard46de64e2002-05-29 08:21:33 +00001920 return(NULL);
1921 }
1922 memset(cur, 0, sizeof(xmlAttr));
1923 cur->type = XML_ATTRIBUTE_NODE;
1924
1925 cur->parent = node;
1926 if (node != NULL) {
1927 doc = node->doc;
1928 cur->doc = doc;
1929 }
1930 cur->ns = ns;
1931 cur->name = name;
1932 if (value != NULL) {
1933 xmlChar *buffer;
1934 xmlNodePtr tmp;
1935
1936 buffer = xmlEncodeEntitiesReentrant(doc, value);
1937 cur->children = xmlStringGetNodeList(doc, buffer);
1938 cur->last = NULL;
1939 tmp = cur->children;
1940 while (tmp != NULL) {
1941 tmp->parent = (xmlNodePtr) cur;
1942 if (tmp->next == NULL)
1943 cur->last = tmp;
1944 tmp = tmp->next;
1945 }
1946 xmlFree(buffer);
1947 }
1948
1949 /*
1950 * Add it at the end to preserve parsing order ...
1951 */
1952 if (node != NULL) {
1953 if (node->properties == NULL) {
1954 node->properties = cur;
1955 } else {
1956 xmlAttrPtr prev = node->properties;
1957
1958 while (prev->next != NULL) prev = prev->next;
1959 prev->next = cur;
1960 cur->prev = prev;
1961 }
1962 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001963
Daniel Veillarda880b122003-04-21 21:36:41 +00001964 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001965 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001966 return(cur);
1967}
1968
1969/**
Owen Taylor3473f882001-02-23 17:55:21 +00001970 * xmlNewDocProp:
1971 * @doc: the document
1972 * @name: the name of the attribute
1973 * @value: the value of the attribute
1974 *
1975 * Create a new property carried by a document.
1976 * Returns a pointer to the attribute
1977 */
1978xmlAttrPtr
1979xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1980 xmlAttrPtr cur;
1981
1982 if (name == NULL) {
1983#ifdef DEBUG_TREE
1984 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001985 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001986#endif
1987 return(NULL);
1988 }
1989
1990 /*
1991 * Allocate a new property and fill the fields.
1992 */
1993 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1994 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001995 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001996 return(NULL);
1997 }
1998 memset(cur, 0, sizeof(xmlAttr));
1999 cur->type = XML_ATTRIBUTE_NODE;
2000
Daniel Veillard03a53c32004-10-26 16:06:51 +00002001 if ((doc != NULL) && (doc->dict != NULL))
2002 cur->name = xmlDictLookup(doc->dict, name, -1);
2003 else
2004 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00002005 cur->doc = doc;
2006 if (value != NULL) {
2007 xmlNodePtr tmp;
2008
2009 cur->children = xmlStringGetNodeList(doc, value);
2010 cur->last = NULL;
2011
2012 tmp = cur->children;
2013 while (tmp != NULL) {
2014 tmp->parent = (xmlNodePtr) cur;
2015 if (tmp->next == NULL)
2016 cur->last = tmp;
2017 tmp = tmp->next;
2018 }
2019 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002020
Daniel Veillarda880b122003-04-21 21:36:41 +00002021 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002022 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002023 return(cur);
2024}
2025
2026/**
2027 * xmlFreePropList:
2028 * @cur: the first property in the list
2029 *
2030 * Free a property and all its siblings, all the children are freed too.
2031 */
2032void
2033xmlFreePropList(xmlAttrPtr cur) {
2034 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002035 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002036 while (cur != NULL) {
2037 next = cur->next;
2038 xmlFreeProp(cur);
2039 cur = next;
2040 }
2041}
2042
2043/**
2044 * xmlFreeProp:
2045 * @cur: an attribute
2046 *
2047 * Free one attribute, all the content is freed too
2048 */
2049void
2050xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002051 xmlDictPtr dict = NULL;
2052 if (cur == NULL) return;
2053
2054 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002055
Daniel Veillarda880b122003-04-21 21:36:41 +00002056 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002057 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
2058
Owen Taylor3473f882001-02-23 17:55:21 +00002059 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00002060 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
2061 ((cur->parent->doc->intSubset != NULL) ||
2062 (cur->parent->doc->extSubset != NULL))) {
2063 if (xmlIsID(cur->parent->doc, cur->parent, cur))
2064 xmlRemoveID(cur->parent->doc, cur);
2065 }
Owen Taylor3473f882001-02-23 17:55:21 +00002066 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002067 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002068 xmlFree(cur);
2069}
2070
Daniel Veillard652327a2003-09-29 18:02:38 +00002071#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002072/**
2073 * xmlRemoveProp:
2074 * @cur: an attribute
2075 *
2076 * Unlink and free one attribute, all the content is freed too
2077 * Note this doesn't work for namespace definition attributes
2078 *
2079 * Returns 0 if success and -1 in case of error.
2080 */
2081int
2082xmlRemoveProp(xmlAttrPtr cur) {
2083 xmlAttrPtr tmp;
2084 if (cur == NULL) {
2085#ifdef DEBUG_TREE
2086 xmlGenericError(xmlGenericErrorContext,
2087 "xmlRemoveProp : cur == NULL\n");
2088#endif
2089 return(-1);
2090 }
2091 if (cur->parent == NULL) {
2092#ifdef DEBUG_TREE
2093 xmlGenericError(xmlGenericErrorContext,
2094 "xmlRemoveProp : cur->parent == NULL\n");
2095#endif
2096 return(-1);
2097 }
2098 tmp = cur->parent->properties;
2099 if (tmp == cur) {
2100 cur->parent->properties = cur->next;
2101 xmlFreeProp(cur);
2102 return(0);
2103 }
2104 while (tmp != NULL) {
2105 if (tmp->next == cur) {
2106 tmp->next = cur->next;
2107 if (tmp->next != NULL)
2108 tmp->next->prev = tmp;
2109 xmlFreeProp(cur);
2110 return(0);
2111 }
2112 tmp = tmp->next;
2113 }
2114#ifdef DEBUG_TREE
2115 xmlGenericError(xmlGenericErrorContext,
2116 "xmlRemoveProp : attribute not owned by its node\n");
2117#endif
2118 return(-1);
2119}
Daniel Veillard652327a2003-09-29 18:02:38 +00002120#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002121
2122/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002123 * xmlNewDocPI:
2124 * @doc: the target document
Owen Taylor3473f882001-02-23 17:55:21 +00002125 * @name: the processing instruction name
2126 * @content: the PI content
2127 *
2128 * Creation of a processing instruction element.
2129 * Returns a pointer to the new node object.
2130 */
2131xmlNodePtr
Daniel Veillard03a53c32004-10-26 16:06:51 +00002132xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
Owen Taylor3473f882001-02-23 17:55:21 +00002133 xmlNodePtr cur;
2134
2135 if (name == NULL) {
2136#ifdef DEBUG_TREE
2137 xmlGenericError(xmlGenericErrorContext,
2138 "xmlNewPI : name == NULL\n");
2139#endif
2140 return(NULL);
2141 }
2142
2143 /*
2144 * Allocate a new node and fill the fields.
2145 */
2146 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2147 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002148 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002149 return(NULL);
2150 }
2151 memset(cur, 0, sizeof(xmlNode));
2152 cur->type = XML_PI_NODE;
2153
Daniel Veillard03a53c32004-10-26 16:06:51 +00002154 if ((doc != NULL) && (doc->dict != NULL))
2155 cur->name = xmlDictLookup(doc->dict, name, -1);
2156 else
2157 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00002158 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002159 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002160 }
Daniel Veillarda03e3652004-11-02 18:45:30 +00002161 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002162
Daniel Veillarda880b122003-04-21 21:36:41 +00002163 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002164 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002165 return(cur);
2166}
2167
2168/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002169 * xmlNewPI:
2170 * @name: the processing instruction name
2171 * @content: the PI content
2172 *
2173 * Creation of a processing instruction element.
2174 * Use xmlDocNewPI preferably to get string interning
2175 *
2176 * Returns a pointer to the new node object.
2177 */
2178xmlNodePtr
2179xmlNewPI(const xmlChar *name, const xmlChar *content) {
2180 return(xmlNewDocPI(NULL, name, content));
2181}
2182
2183/**
Owen Taylor3473f882001-02-23 17:55:21 +00002184 * xmlNewNode:
2185 * @ns: namespace if any
2186 * @name: the node name
2187 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002188 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002189 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002190 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2191 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002192 */
2193xmlNodePtr
2194xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2195 xmlNodePtr cur;
2196
2197 if (name == NULL) {
2198#ifdef DEBUG_TREE
2199 xmlGenericError(xmlGenericErrorContext,
2200 "xmlNewNode : name == NULL\n");
2201#endif
2202 return(NULL);
2203 }
2204
2205 /*
2206 * Allocate a new node and fill the fields.
2207 */
2208 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2209 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002210 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002211 return(NULL);
2212 }
2213 memset(cur, 0, sizeof(xmlNode));
2214 cur->type = XML_ELEMENT_NODE;
2215
2216 cur->name = xmlStrdup(name);
2217 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002218
Daniel Veillarda880b122003-04-21 21:36:41 +00002219 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002220 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002221 return(cur);
2222}
2223
2224/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002225 * xmlNewNodeEatName:
2226 * @ns: namespace if any
2227 * @name: the node name
2228 *
2229 * Creation of a new node element. @ns is optional (NULL).
2230 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002231 * Returns a pointer to the new node object, with pointer @name as
2232 * new node's name. Use xmlNewNode() if a copy of @name string is
2233 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002234 */
2235xmlNodePtr
2236xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2237 xmlNodePtr cur;
2238
2239 if (name == NULL) {
2240#ifdef DEBUG_TREE
2241 xmlGenericError(xmlGenericErrorContext,
2242 "xmlNewNode : name == NULL\n");
2243#endif
2244 return(NULL);
2245 }
2246
2247 /*
2248 * Allocate a new node and fill the fields.
2249 */
2250 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2251 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002252 xmlTreeErrMemory("building node");
Daniel Veillard46de64e2002-05-29 08:21:33 +00002253 return(NULL);
2254 }
2255 memset(cur, 0, sizeof(xmlNode));
2256 cur->type = XML_ELEMENT_NODE;
2257
2258 cur->name = name;
2259 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002260
Daniel Veillarda880b122003-04-21 21:36:41 +00002261 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002262 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002263 return(cur);
2264}
2265
2266/**
Owen Taylor3473f882001-02-23 17:55:21 +00002267 * xmlNewDocNode:
2268 * @doc: the document
2269 * @ns: namespace if any
2270 * @name: the node name
2271 * @content: the XML text content if any
2272 *
2273 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002274 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002275 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2276 * references, but XML special chars need to be escaped first by using
2277 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2278 * need entities support.
2279 *
2280 * Returns a pointer to the new node object.
2281 */
2282xmlNodePtr
2283xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2284 const xmlChar *name, const xmlChar *content) {
2285 xmlNodePtr cur;
2286
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002287 if ((doc != NULL) && (doc->dict != NULL))
Daniel Veillard03a53c32004-10-26 16:06:51 +00002288 cur = xmlNewNodeEatName(ns, (xmlChar *)
2289 xmlDictLookup(doc->dict, name, -1));
2290 else
2291 cur = xmlNewNode(ns, name);
Owen Taylor3473f882001-02-23 17:55:21 +00002292 if (cur != NULL) {
2293 cur->doc = doc;
2294 if (content != NULL) {
2295 cur->children = xmlStringGetNodeList(doc, content);
2296 UPDATE_LAST_CHILD_AND_PARENT(cur)
2297 }
2298 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002299
Owen Taylor3473f882001-02-23 17:55:21 +00002300 return(cur);
2301}
2302
Daniel Veillard46de64e2002-05-29 08:21:33 +00002303/**
2304 * xmlNewDocNodeEatName:
2305 * @doc: the document
2306 * @ns: namespace if any
2307 * @name: the node name
2308 * @content: the XML text content if any
2309 *
2310 * Creation of a new node element within a document. @ns and @content
2311 * are optional (NULL).
2312 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2313 * references, but XML special chars need to be escaped first by using
2314 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2315 * need entities support.
2316 *
2317 * Returns a pointer to the new node object.
2318 */
2319xmlNodePtr
2320xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2321 xmlChar *name, const xmlChar *content) {
2322 xmlNodePtr cur;
2323
2324 cur = xmlNewNodeEatName(ns, name);
2325 if (cur != NULL) {
2326 cur->doc = doc;
2327 if (content != NULL) {
2328 cur->children = xmlStringGetNodeList(doc, content);
2329 UPDATE_LAST_CHILD_AND_PARENT(cur)
2330 }
2331 }
2332 return(cur);
2333}
2334
Daniel Veillard652327a2003-09-29 18:02:38 +00002335#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002336/**
2337 * xmlNewDocRawNode:
2338 * @doc: the document
2339 * @ns: namespace if any
2340 * @name: the node name
2341 * @content: the text content if any
2342 *
2343 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002344 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002345 *
2346 * Returns a pointer to the new node object.
2347 */
2348xmlNodePtr
2349xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2350 const xmlChar *name, const xmlChar *content) {
2351 xmlNodePtr cur;
2352
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002353 cur = xmlNewDocNode(doc, ns, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002354 if (cur != NULL) {
2355 cur->doc = doc;
2356 if (content != NULL) {
2357 cur->children = xmlNewDocText(doc, content);
2358 UPDATE_LAST_CHILD_AND_PARENT(cur)
2359 }
2360 }
2361 return(cur);
2362}
2363
2364/**
2365 * xmlNewDocFragment:
2366 * @doc: the document owning the fragment
2367 *
2368 * Creation of a new Fragment node.
2369 * Returns a pointer to the new node object.
2370 */
2371xmlNodePtr
2372xmlNewDocFragment(xmlDocPtr doc) {
2373 xmlNodePtr cur;
2374
2375 /*
2376 * Allocate a new DocumentFragment node and fill the fields.
2377 */
2378 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2379 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002380 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002381 return(NULL);
2382 }
2383 memset(cur, 0, sizeof(xmlNode));
2384 cur->type = XML_DOCUMENT_FRAG_NODE;
2385
2386 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002387
Daniel Veillarda880b122003-04-21 21:36:41 +00002388 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002389 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002390 return(cur);
2391}
Daniel Veillard652327a2003-09-29 18:02:38 +00002392#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002393
2394/**
2395 * xmlNewText:
2396 * @content: the text content
2397 *
2398 * Creation of a new text node.
2399 * Returns a pointer to the new node object.
2400 */
2401xmlNodePtr
2402xmlNewText(const xmlChar *content) {
2403 xmlNodePtr cur;
2404
2405 /*
2406 * Allocate a new node and fill the fields.
2407 */
2408 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2409 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002410 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002411 return(NULL);
2412 }
2413 memset(cur, 0, sizeof(xmlNode));
2414 cur->type = XML_TEXT_NODE;
2415
2416 cur->name = xmlStringText;
2417 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002418 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002419 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002420
Daniel Veillarda880b122003-04-21 21:36:41 +00002421 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002422 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002423 return(cur);
2424}
2425
Daniel Veillard652327a2003-09-29 18:02:38 +00002426#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002427/**
2428 * xmlNewTextChild:
2429 * @parent: the parent node
2430 * @ns: a namespace if any
2431 * @name: the name of the child
2432 * @content: the text content of the child if any.
2433 *
2434 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002435 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2436 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002437 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002438 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2439 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2440 * reserved XML chars that might appear in @content, such as the ampersand,
2441 * greater-than or less-than signs, are automatically replaced by their XML
2442 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002443 *
2444 * Returns a pointer to the new node object.
2445 */
2446xmlNodePtr
2447xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2448 const xmlChar *name, const xmlChar *content) {
2449 xmlNodePtr cur, prev;
2450
2451 if (parent == NULL) {
2452#ifdef DEBUG_TREE
2453 xmlGenericError(xmlGenericErrorContext,
2454 "xmlNewTextChild : parent == NULL\n");
2455#endif
2456 return(NULL);
2457 }
2458
2459 if (name == NULL) {
2460#ifdef DEBUG_TREE
2461 xmlGenericError(xmlGenericErrorContext,
2462 "xmlNewTextChild : name == NULL\n");
2463#endif
2464 return(NULL);
2465 }
2466
2467 /*
2468 * Allocate a new node
2469 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002470 if (parent->type == XML_ELEMENT_NODE) {
2471 if (ns == NULL)
2472 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2473 else
2474 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2475 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2476 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2477 if (ns == NULL)
2478 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2479 else
2480 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2481 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2482 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2483 } else {
2484 return(NULL);
2485 }
Owen Taylor3473f882001-02-23 17:55:21 +00002486 if (cur == NULL) return(NULL);
2487
2488 /*
2489 * add the new element at the end of the children list.
2490 */
2491 cur->type = XML_ELEMENT_NODE;
2492 cur->parent = parent;
2493 cur->doc = parent->doc;
2494 if (parent->children == NULL) {
2495 parent->children = cur;
2496 parent->last = cur;
2497 } else {
2498 prev = parent->last;
2499 prev->next = cur;
2500 cur->prev = prev;
2501 parent->last = cur;
2502 }
2503
2504 return(cur);
2505}
Daniel Veillard652327a2003-09-29 18:02:38 +00002506#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002507
2508/**
2509 * xmlNewCharRef:
2510 * @doc: the document
2511 * @name: the char ref string, starting with # or "&# ... ;"
2512 *
2513 * Creation of a new character reference node.
2514 * Returns a pointer to the new node object.
2515 */
2516xmlNodePtr
2517xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2518 xmlNodePtr cur;
2519
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002520 if (name == NULL)
2521 return(NULL);
2522
Owen Taylor3473f882001-02-23 17:55:21 +00002523 /*
2524 * Allocate a new node and fill the fields.
2525 */
2526 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2527 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002528 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002529 return(NULL);
2530 }
2531 memset(cur, 0, sizeof(xmlNode));
2532 cur->type = XML_ENTITY_REF_NODE;
2533
2534 cur->doc = doc;
2535 if (name[0] == '&') {
2536 int len;
2537 name++;
2538 len = xmlStrlen(name);
2539 if (name[len - 1] == ';')
2540 cur->name = xmlStrndup(name, len - 1);
2541 else
2542 cur->name = xmlStrndup(name, len);
2543 } else
2544 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002545
Daniel Veillarda880b122003-04-21 21:36:41 +00002546 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002547 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002548 return(cur);
2549}
2550
2551/**
2552 * xmlNewReference:
2553 * @doc: the document
2554 * @name: the reference name, or the reference string with & and ;
2555 *
2556 * Creation of a new reference node.
2557 * Returns a pointer to the new node object.
2558 */
2559xmlNodePtr
2560xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2561 xmlNodePtr cur;
2562 xmlEntityPtr ent;
2563
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002564 if (name == NULL)
2565 return(NULL);
2566
Owen Taylor3473f882001-02-23 17:55:21 +00002567 /*
2568 * Allocate a new node and fill the fields.
2569 */
2570 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2571 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002572 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002573 return(NULL);
2574 }
2575 memset(cur, 0, sizeof(xmlNode));
2576 cur->type = XML_ENTITY_REF_NODE;
2577
2578 cur->doc = doc;
2579 if (name[0] == '&') {
2580 int len;
2581 name++;
2582 len = xmlStrlen(name);
2583 if (name[len - 1] == ';')
2584 cur->name = xmlStrndup(name, len - 1);
2585 else
2586 cur->name = xmlStrndup(name, len);
2587 } else
2588 cur->name = xmlStrdup(name);
2589
2590 ent = xmlGetDocEntity(doc, cur->name);
2591 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002592 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002593 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002594 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002595 * updated. Not sure if this is 100% correct.
2596 * -George
2597 */
2598 cur->children = (xmlNodePtr) ent;
2599 cur->last = (xmlNodePtr) ent;
2600 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002601
Daniel Veillarda880b122003-04-21 21:36:41 +00002602 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002603 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002604 return(cur);
2605}
2606
2607/**
2608 * xmlNewDocText:
2609 * @doc: the document
2610 * @content: the text content
2611 *
2612 * Creation of a new text node within a document.
2613 * Returns a pointer to the new node object.
2614 */
2615xmlNodePtr
2616xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2617 xmlNodePtr cur;
2618
2619 cur = xmlNewText(content);
2620 if (cur != NULL) cur->doc = doc;
2621 return(cur);
2622}
2623
2624/**
2625 * xmlNewTextLen:
2626 * @content: the text content
2627 * @len: the text len.
2628 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002629 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002630 * Returns a pointer to the new node object.
2631 */
2632xmlNodePtr
2633xmlNewTextLen(const xmlChar *content, int len) {
2634 xmlNodePtr cur;
2635
2636 /*
2637 * Allocate a new node and fill the fields.
2638 */
2639 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2640 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002641 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002642 return(NULL);
2643 }
2644 memset(cur, 0, sizeof(xmlNode));
2645 cur->type = XML_TEXT_NODE;
2646
2647 cur->name = xmlStringText;
2648 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002649 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002650 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002651
Daniel Veillarda880b122003-04-21 21:36:41 +00002652 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002653 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002654 return(cur);
2655}
2656
2657/**
2658 * xmlNewDocTextLen:
2659 * @doc: the document
2660 * @content: the text content
2661 * @len: the text len.
2662 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002663 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002664 * text node pertain to a given document.
2665 * Returns a pointer to the new node object.
2666 */
2667xmlNodePtr
2668xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2669 xmlNodePtr cur;
2670
2671 cur = xmlNewTextLen(content, len);
2672 if (cur != NULL) cur->doc = doc;
2673 return(cur);
2674}
2675
2676/**
2677 * xmlNewComment:
2678 * @content: the comment content
2679 *
2680 * Creation of a new node containing a comment.
2681 * Returns a pointer to the new node object.
2682 */
2683xmlNodePtr
2684xmlNewComment(const xmlChar *content) {
2685 xmlNodePtr cur;
2686
2687 /*
2688 * Allocate a new node and fill the fields.
2689 */
2690 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2691 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002692 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002693 return(NULL);
2694 }
2695 memset(cur, 0, sizeof(xmlNode));
2696 cur->type = XML_COMMENT_NODE;
2697
2698 cur->name = xmlStringComment;
2699 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002700 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002701 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002702
Daniel Veillarda880b122003-04-21 21:36:41 +00002703 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002704 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002705 return(cur);
2706}
2707
2708/**
2709 * xmlNewCDataBlock:
2710 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002711 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002712 * @len: the length of the block
2713 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002714 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002715 * Returns a pointer to the new node object.
2716 */
2717xmlNodePtr
2718xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2719 xmlNodePtr cur;
2720
2721 /*
2722 * Allocate a new node and fill the fields.
2723 */
2724 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2725 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002726 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002727 return(NULL);
2728 }
2729 memset(cur, 0, sizeof(xmlNode));
2730 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002731 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002732
2733 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002734 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002735 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002736
Daniel Veillarda880b122003-04-21 21:36:41 +00002737 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002738 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002739 return(cur);
2740}
2741
2742/**
2743 * xmlNewDocComment:
2744 * @doc: the document
2745 * @content: the comment content
2746 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002747 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002748 * Returns a pointer to the new node object.
2749 */
2750xmlNodePtr
2751xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2752 xmlNodePtr cur;
2753
2754 cur = xmlNewComment(content);
2755 if (cur != NULL) cur->doc = doc;
2756 return(cur);
2757}
2758
2759/**
2760 * xmlSetTreeDoc:
2761 * @tree: the top element
2762 * @doc: the document
2763 *
2764 * update all nodes under the tree to point to the right document
2765 */
2766void
2767xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002768 xmlAttrPtr prop;
2769
Owen Taylor3473f882001-02-23 17:55:21 +00002770 if (tree == NULL)
2771 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002772 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002773 if(tree->type == XML_ELEMENT_NODE) {
2774 prop = tree->properties;
2775 while (prop != NULL) {
2776 prop->doc = doc;
2777 xmlSetListDoc(prop->children, doc);
2778 prop = prop->next;
2779 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002780 }
Owen Taylor3473f882001-02-23 17:55:21 +00002781 if (tree->children != NULL)
2782 xmlSetListDoc(tree->children, doc);
2783 tree->doc = doc;
2784 }
2785}
2786
2787/**
2788 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002789 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002790 * @doc: the document
2791 *
2792 * update all nodes in the list to point to the right document
2793 */
2794void
2795xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2796 xmlNodePtr cur;
2797
2798 if (list == NULL)
2799 return;
2800 cur = list;
2801 while (cur != NULL) {
2802 if (cur->doc != doc)
2803 xmlSetTreeDoc(cur, doc);
2804 cur = cur->next;
2805 }
2806}
2807
Daniel Veillard2156d432004-03-04 15:59:36 +00002808#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002809/**
2810 * xmlNewChild:
2811 * @parent: the parent node
2812 * @ns: a namespace if any
2813 * @name: the name of the child
2814 * @content: the XML content of the child if any.
2815 *
2816 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002817 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2818 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002819 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002820 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2821 * references. XML special chars must be escaped first by using
2822 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002823 *
2824 * Returns a pointer to the new node object.
2825 */
2826xmlNodePtr
2827xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2828 const xmlChar *name, const xmlChar *content) {
2829 xmlNodePtr cur, prev;
2830
2831 if (parent == NULL) {
2832#ifdef DEBUG_TREE
2833 xmlGenericError(xmlGenericErrorContext,
2834 "xmlNewChild : parent == NULL\n");
2835#endif
2836 return(NULL);
2837 }
2838
2839 if (name == NULL) {
2840#ifdef DEBUG_TREE
2841 xmlGenericError(xmlGenericErrorContext,
2842 "xmlNewChild : name == NULL\n");
2843#endif
2844 return(NULL);
2845 }
2846
2847 /*
2848 * Allocate a new node
2849 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002850 if (parent->type == XML_ELEMENT_NODE) {
2851 if (ns == NULL)
2852 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2853 else
2854 cur = xmlNewDocNode(parent->doc, ns, name, content);
2855 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2856 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2857 if (ns == NULL)
2858 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2859 else
2860 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002861 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2862 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002863 } else {
2864 return(NULL);
2865 }
Owen Taylor3473f882001-02-23 17:55:21 +00002866 if (cur == NULL) return(NULL);
2867
2868 /*
2869 * add the new element at the end of the children list.
2870 */
2871 cur->type = XML_ELEMENT_NODE;
2872 cur->parent = parent;
2873 cur->doc = parent->doc;
2874 if (parent->children == NULL) {
2875 parent->children = cur;
2876 parent->last = cur;
2877 } else {
2878 prev = parent->last;
2879 prev->next = cur;
2880 cur->prev = prev;
2881 parent->last = cur;
2882 }
2883
2884 return(cur);
2885}
Daniel Veillard652327a2003-09-29 18:02:38 +00002886#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002887
2888/**
2889 * xmlAddNextSibling:
2890 * @cur: the child node
2891 * @elem: the new node
2892 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002893 * Add a new node @elem as the next sibling of @cur
2894 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002895 * first unlinked from its existing context.
2896 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002897 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2898 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002899 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002900 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002901 */
2902xmlNodePtr
2903xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2904 if (cur == NULL) {
2905#ifdef DEBUG_TREE
2906 xmlGenericError(xmlGenericErrorContext,
2907 "xmlAddNextSibling : cur == NULL\n");
2908#endif
2909 return(NULL);
2910 }
2911 if (elem == NULL) {
2912#ifdef DEBUG_TREE
2913 xmlGenericError(xmlGenericErrorContext,
2914 "xmlAddNextSibling : elem == NULL\n");
2915#endif
2916 return(NULL);
2917 }
2918
2919 xmlUnlinkNode(elem);
2920
2921 if (elem->type == XML_TEXT_NODE) {
2922 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002923 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002924 xmlFreeNode(elem);
2925 return(cur);
2926 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002927 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2928 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002929 xmlChar *tmp;
2930
2931 tmp = xmlStrdup(elem->content);
2932 tmp = xmlStrcat(tmp, cur->next->content);
2933 xmlNodeSetContent(cur->next, tmp);
2934 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002935 xmlFreeNode(elem);
2936 return(cur->next);
2937 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002938 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2939 /* check if an attribute with the same name exists */
2940 xmlAttrPtr attr;
2941
2942 if (elem->ns == NULL)
2943 attr = xmlHasProp(cur->parent, elem->name);
2944 else
2945 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2946 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2947 /* different instance, destroy it (attributes must be unique) */
2948 xmlFreeProp(attr);
2949 }
Owen Taylor3473f882001-02-23 17:55:21 +00002950 }
2951
2952 if (elem->doc != cur->doc) {
2953 xmlSetTreeDoc(elem, cur->doc);
2954 }
2955 elem->parent = cur->parent;
2956 elem->prev = cur;
2957 elem->next = cur->next;
2958 cur->next = elem;
2959 if (elem->next != NULL)
2960 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002961 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002962 elem->parent->last = elem;
2963 return(elem);
2964}
2965
Daniel Veillard2156d432004-03-04 15:59:36 +00002966#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002967/**
2968 * xmlAddPrevSibling:
2969 * @cur: the child node
2970 * @elem: the new node
2971 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002972 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002973 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002974 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002975 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002976 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2977 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002978 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002979 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002980 */
2981xmlNodePtr
2982xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2983 if (cur == NULL) {
2984#ifdef DEBUG_TREE
2985 xmlGenericError(xmlGenericErrorContext,
2986 "xmlAddPrevSibling : cur == NULL\n");
2987#endif
2988 return(NULL);
2989 }
2990 if (elem == NULL) {
2991#ifdef DEBUG_TREE
2992 xmlGenericError(xmlGenericErrorContext,
2993 "xmlAddPrevSibling : elem == NULL\n");
2994#endif
2995 return(NULL);
2996 }
2997
2998 xmlUnlinkNode(elem);
2999
3000 if (elem->type == XML_TEXT_NODE) {
3001 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00003002 xmlChar *tmp;
3003
3004 tmp = xmlStrdup(elem->content);
3005 tmp = xmlStrcat(tmp, cur->content);
3006 xmlNodeSetContent(cur, tmp);
3007 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00003008 xmlFreeNode(elem);
3009 return(cur);
3010 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00003011 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
3012 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003013 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003014 xmlFreeNode(elem);
3015 return(cur->prev);
3016 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003017 } else if (elem->type == XML_ATTRIBUTE_NODE) {
3018 /* check if an attribute with the same name exists */
3019 xmlAttrPtr attr;
3020
3021 if (elem->ns == NULL)
3022 attr = xmlHasProp(cur->parent, elem->name);
3023 else
3024 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
3025 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
3026 /* different instance, destroy it (attributes must be unique) */
3027 xmlFreeProp(attr);
3028 }
Owen Taylor3473f882001-02-23 17:55:21 +00003029 }
3030
3031 if (elem->doc != cur->doc) {
3032 xmlSetTreeDoc(elem, cur->doc);
3033 }
3034 elem->parent = cur->parent;
3035 elem->next = cur;
3036 elem->prev = cur->prev;
3037 cur->prev = elem;
3038 if (elem->prev != NULL)
3039 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003040 if (elem->parent != NULL) {
3041 if (elem->type == XML_ATTRIBUTE_NODE) {
3042 if (elem->parent->properties == (xmlAttrPtr) cur) {
3043 elem->parent->properties = (xmlAttrPtr) elem;
3044 }
3045 } else {
3046 if (elem->parent->children == cur) {
3047 elem->parent->children = elem;
3048 }
3049 }
3050 }
Owen Taylor3473f882001-02-23 17:55:21 +00003051 return(elem);
3052}
Daniel Veillard652327a2003-09-29 18:02:38 +00003053#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003054
3055/**
3056 * xmlAddSibling:
3057 * @cur: the child node
3058 * @elem: the new node
3059 *
3060 * Add a new element @elem to the list of siblings of @cur
3061 * merging adjacent TEXT nodes (@elem may be freed)
3062 * If the new element was already inserted in a document it is
3063 * first unlinked from its existing context.
3064 *
3065 * Returns the new element or NULL in case of error.
3066 */
3067xmlNodePtr
3068xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
3069 xmlNodePtr parent;
3070
3071 if (cur == NULL) {
3072#ifdef DEBUG_TREE
3073 xmlGenericError(xmlGenericErrorContext,
3074 "xmlAddSibling : cur == NULL\n");
3075#endif
3076 return(NULL);
3077 }
3078
3079 if (elem == NULL) {
3080#ifdef DEBUG_TREE
3081 xmlGenericError(xmlGenericErrorContext,
3082 "xmlAddSibling : elem == NULL\n");
3083#endif
3084 return(NULL);
3085 }
3086
3087 /*
3088 * Constant time is we can rely on the ->parent->last to find
3089 * the last sibling.
3090 */
3091 if ((cur->parent != NULL) &&
3092 (cur->parent->children != NULL) &&
3093 (cur->parent->last != NULL) &&
3094 (cur->parent->last->next == NULL)) {
3095 cur = cur->parent->last;
3096 } else {
3097 while (cur->next != NULL) cur = cur->next;
3098 }
3099
3100 xmlUnlinkNode(elem);
3101
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003102 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3103 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003104 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003105 xmlFreeNode(elem);
3106 return(cur);
3107 }
3108
3109 if (elem->doc != cur->doc) {
3110 xmlSetTreeDoc(elem, cur->doc);
3111 }
3112 parent = cur->parent;
3113 elem->prev = cur;
3114 elem->next = NULL;
3115 elem->parent = parent;
3116 cur->next = elem;
3117 if (parent != NULL)
3118 parent->last = elem;
3119
3120 return(elem);
3121}
3122
3123/**
3124 * xmlAddChildList:
3125 * @parent: the parent node
3126 * @cur: the first node in the list
3127 *
3128 * Add a list of node at the end of the child list of the parent
3129 * merging adjacent TEXT nodes (@cur may be freed)
3130 *
3131 * Returns the last child or NULL in case of error.
3132 */
3133xmlNodePtr
3134xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3135 xmlNodePtr prev;
3136
3137 if (parent == NULL) {
3138#ifdef DEBUG_TREE
3139 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003140 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003141#endif
3142 return(NULL);
3143 }
3144
3145 if (cur == NULL) {
3146#ifdef DEBUG_TREE
3147 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003148 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003149#endif
3150 return(NULL);
3151 }
3152
3153 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3154 (cur->doc != parent->doc)) {
3155#ifdef DEBUG_TREE
3156 xmlGenericError(xmlGenericErrorContext,
3157 "Elements moved to a different document\n");
3158#endif
3159 }
3160
3161 /*
3162 * add the first element at the end of the children list.
3163 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003164
Owen Taylor3473f882001-02-23 17:55:21 +00003165 if (parent->children == NULL) {
3166 parent->children = cur;
3167 } else {
3168 /*
3169 * If cur and parent->last both are TEXT nodes, then merge them.
3170 */
3171 if ((cur->type == XML_TEXT_NODE) &&
3172 (parent->last->type == XML_TEXT_NODE) &&
3173 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003174 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003175 /*
3176 * if it's the only child, nothing more to be done.
3177 */
3178 if (cur->next == NULL) {
3179 xmlFreeNode(cur);
3180 return(parent->last);
3181 }
3182 prev = cur;
3183 cur = cur->next;
3184 xmlFreeNode(prev);
3185 }
3186 prev = parent->last;
3187 prev->next = cur;
3188 cur->prev = prev;
3189 }
3190 while (cur->next != NULL) {
3191 cur->parent = parent;
3192 if (cur->doc != parent->doc) {
3193 xmlSetTreeDoc(cur, parent->doc);
3194 }
3195 cur = cur->next;
3196 }
3197 cur->parent = parent;
3198 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3199 parent->last = cur;
3200
3201 return(cur);
3202}
3203
3204/**
3205 * xmlAddChild:
3206 * @parent: the parent node
3207 * @cur: the child node
3208 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003209 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003210 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003211 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3212 * If there is an attribute with equal name, it is first destroyed.
3213 *
Owen Taylor3473f882001-02-23 17:55:21 +00003214 * Returns the child or NULL in case of error.
3215 */
3216xmlNodePtr
3217xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3218 xmlNodePtr prev;
3219
3220 if (parent == NULL) {
3221#ifdef DEBUG_TREE
3222 xmlGenericError(xmlGenericErrorContext,
3223 "xmlAddChild : parent == NULL\n");
3224#endif
3225 return(NULL);
3226 }
3227
3228 if (cur == NULL) {
3229#ifdef DEBUG_TREE
3230 xmlGenericError(xmlGenericErrorContext,
3231 "xmlAddChild : child == NULL\n");
3232#endif
3233 return(NULL);
3234 }
3235
Owen Taylor3473f882001-02-23 17:55:21 +00003236 /*
3237 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003238 * cur is then freed.
3239 */
3240 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003241 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003242 (parent->content != NULL) &&
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003243 (parent->name == cur->name) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003244 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003245 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003246 xmlFreeNode(cur);
3247 return(parent);
3248 }
3249 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003250 (parent->last->name == cur->name) &&
3251 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003252 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003253 xmlFreeNode(cur);
3254 return(parent->last);
3255 }
3256 }
3257
3258 /*
3259 * add the new element at the end of the children list.
3260 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003261 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003262 cur->parent = parent;
3263 if (cur->doc != parent->doc) {
3264 xmlSetTreeDoc(cur, parent->doc);
3265 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003266 /* this check prevents a loop on tree-traversions if a developer
3267 * tries to add a node to its parent multiple times
3268 */
3269 if (prev == parent)
3270 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003271
3272 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003273 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003274 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003275 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003276 (parent->content != NULL) &&
3277 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003278 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003279 xmlFreeNode(cur);
3280 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003281 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003282 if (cur->type == XML_ATTRIBUTE_NODE) {
3283 if (parent->properties == NULL) {
3284 parent->properties = (xmlAttrPtr) cur;
3285 } else {
3286 /* check if an attribute with the same name exists */
3287 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003288
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003289 if (cur->ns == NULL)
3290 lastattr = xmlHasProp(parent, cur->name);
3291 else
3292 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3293 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3294 /* different instance, destroy it (attributes must be unique) */
3295 xmlFreeProp(lastattr);
3296 }
3297 /* find the end */
3298 lastattr = parent->properties;
3299 while (lastattr->next != NULL) {
3300 lastattr = lastattr->next;
3301 }
3302 lastattr->next = (xmlAttrPtr) cur;
3303 ((xmlAttrPtr) cur)->prev = lastattr;
3304 }
3305 } else {
3306 if (parent->children == NULL) {
3307 parent->children = cur;
3308 parent->last = cur;
3309 } else {
3310 prev = parent->last;
3311 prev->next = cur;
3312 cur->prev = prev;
3313 parent->last = cur;
3314 }
3315 }
Owen Taylor3473f882001-02-23 17:55:21 +00003316 return(cur);
3317}
3318
3319/**
3320 * xmlGetLastChild:
3321 * @parent: the parent node
3322 *
3323 * Search the last child of a node.
3324 * Returns the last child or NULL if none.
3325 */
3326xmlNodePtr
3327xmlGetLastChild(xmlNodePtr parent) {
3328 if (parent == NULL) {
3329#ifdef DEBUG_TREE
3330 xmlGenericError(xmlGenericErrorContext,
3331 "xmlGetLastChild : parent == NULL\n");
3332#endif
3333 return(NULL);
3334 }
3335 return(parent->last);
3336}
3337
3338/**
3339 * xmlFreeNodeList:
3340 * @cur: the first node in the list
3341 *
3342 * Free a node and all its siblings, this is a recursive behaviour, all
3343 * the children are freed too.
3344 */
3345void
3346xmlFreeNodeList(xmlNodePtr cur) {
3347 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003348 xmlDictPtr dict = NULL;
3349
3350 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003351 if (cur->type == XML_NAMESPACE_DECL) {
3352 xmlFreeNsList((xmlNsPtr) cur);
3353 return;
3354 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003355 if ((cur->type == XML_DOCUMENT_NODE) ||
3356#ifdef LIBXML_DOCB_ENABLED
3357 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003358#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003359 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003360 xmlFreeDoc((xmlDocPtr) cur);
3361 return;
3362 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003363 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003364 while (cur != NULL) {
3365 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003366 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003367
Daniel Veillarda880b122003-04-21 21:36:41 +00003368 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003369 xmlDeregisterNodeDefaultValue(cur);
3370
Daniel Veillard02141ea2001-04-30 11:46:40 +00003371 if ((cur->children != NULL) &&
3372 (cur->type != XML_ENTITY_REF_NODE))
3373 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003374 if (((cur->type == XML_ELEMENT_NODE) ||
3375 (cur->type == XML_XINCLUDE_START) ||
3376 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003377 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003378 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003379 if ((cur->type != XML_ELEMENT_NODE) &&
3380 (cur->type != XML_XINCLUDE_START) &&
3381 (cur->type != XML_XINCLUDE_END) &&
3382 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003383 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003384 }
3385 if (((cur->type == XML_ELEMENT_NODE) ||
3386 (cur->type == XML_XINCLUDE_START) ||
3387 (cur->type == XML_XINCLUDE_END)) &&
3388 (cur->nsDef != NULL))
3389 xmlFreeNsList(cur->nsDef);
3390
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003391 /*
3392 * When a node is a text node or a comment, it uses a global static
3393 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003394 * Otherwise the node name might come from the document's
3395 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003396 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003397 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003398 (cur->type != XML_TEXT_NODE) &&
3399 (cur->type != XML_COMMENT_NODE))
3400 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003401 xmlFree(cur);
3402 }
Owen Taylor3473f882001-02-23 17:55:21 +00003403 cur = next;
3404 }
3405}
3406
3407/**
3408 * xmlFreeNode:
3409 * @cur: the node
3410 *
3411 * Free a node, this is a recursive behaviour, all the children are freed too.
3412 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3413 */
3414void
3415xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003416 xmlDictPtr dict = NULL;
3417
3418 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003419
Daniel Veillard02141ea2001-04-30 11:46:40 +00003420 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003421 if (cur->type == XML_DTD_NODE) {
3422 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003423 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003424 }
3425 if (cur->type == XML_NAMESPACE_DECL) {
3426 xmlFreeNs((xmlNsPtr) cur);
3427 return;
3428 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003429 if (cur->type == XML_ATTRIBUTE_NODE) {
3430 xmlFreeProp((xmlAttrPtr) cur);
3431 return;
3432 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003433
Daniel Veillarda880b122003-04-21 21:36:41 +00003434 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003435 xmlDeregisterNodeDefaultValue(cur);
3436
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003437 if (cur->doc != NULL) dict = cur->doc->dict;
3438
Owen Taylor3473f882001-02-23 17:55:21 +00003439 if ((cur->children != NULL) &&
3440 (cur->type != XML_ENTITY_REF_NODE))
3441 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003442 if (((cur->type == XML_ELEMENT_NODE) ||
3443 (cur->type == XML_XINCLUDE_START) ||
3444 (cur->type == XML_XINCLUDE_END)) &&
3445 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003446 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003447 if ((cur->type != XML_ELEMENT_NODE) &&
3448 (cur->content != NULL) &&
3449 (cur->type != XML_ENTITY_REF_NODE) &&
3450 (cur->type != XML_XINCLUDE_END) &&
3451 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003452 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003453 }
3454
Daniel Veillardacd370f2001-06-09 17:17:51 +00003455 /*
3456 * When a node is a text node or a comment, it uses a global static
3457 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003458 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003459 */
Owen Taylor3473f882001-02-23 17:55:21 +00003460 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003461 (cur->type != XML_TEXT_NODE) &&
3462 (cur->type != XML_COMMENT_NODE))
3463 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003464
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003465 if (((cur->type == XML_ELEMENT_NODE) ||
3466 (cur->type == XML_XINCLUDE_START) ||
3467 (cur->type == XML_XINCLUDE_END)) &&
3468 (cur->nsDef != NULL))
3469 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003470 xmlFree(cur);
3471}
3472
3473/**
3474 * xmlUnlinkNode:
3475 * @cur: the node
3476 *
3477 * Unlink a node from it's current context, the node is not freed
3478 */
3479void
3480xmlUnlinkNode(xmlNodePtr cur) {
3481 if (cur == NULL) {
3482#ifdef DEBUG_TREE
3483 xmlGenericError(xmlGenericErrorContext,
3484 "xmlUnlinkNode : node == NULL\n");
3485#endif
3486 return;
3487 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003488 if (cur->type == XML_DTD_NODE) {
3489 xmlDocPtr doc;
3490 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003491 if (doc != NULL) {
3492 if (doc->intSubset == (xmlDtdPtr) cur)
3493 doc->intSubset = NULL;
3494 if (doc->extSubset == (xmlDtdPtr) cur)
3495 doc->extSubset = NULL;
3496 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003497 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003498 if (cur->parent != NULL) {
3499 xmlNodePtr parent;
3500 parent = cur->parent;
3501 if (cur->type == XML_ATTRIBUTE_NODE) {
3502 if (parent->properties == (xmlAttrPtr) cur)
3503 parent->properties = ((xmlAttrPtr) cur)->next;
3504 } else {
3505 if (parent->children == cur)
3506 parent->children = cur->next;
3507 if (parent->last == cur)
3508 parent->last = cur->prev;
3509 }
3510 cur->parent = NULL;
3511 }
Owen Taylor3473f882001-02-23 17:55:21 +00003512 if (cur->next != NULL)
3513 cur->next->prev = cur->prev;
3514 if (cur->prev != NULL)
3515 cur->prev->next = cur->next;
3516 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003517}
3518
Daniel Veillard2156d432004-03-04 15:59:36 +00003519#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003520/**
3521 * xmlReplaceNode:
3522 * @old: the old node
3523 * @cur: the node
3524 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003525 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003526 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003527 * first unlinked from its existing context.
3528 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003529 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003530 */
3531xmlNodePtr
3532xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00003533 if (old == cur) return(NULL);
Daniel Veillarda03e3652004-11-02 18:45:30 +00003534 if ((old == NULL) || (old->parent == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003535#ifdef DEBUG_TREE
3536 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda03e3652004-11-02 18:45:30 +00003537 "xmlReplaceNode : old == NULL or without parent\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003538#endif
3539 return(NULL);
3540 }
3541 if (cur == NULL) {
3542 xmlUnlinkNode(old);
3543 return(old);
3544 }
3545 if (cur == old) {
3546 return(old);
3547 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003548 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3549#ifdef DEBUG_TREE
3550 xmlGenericError(xmlGenericErrorContext,
3551 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3552#endif
3553 return(old);
3554 }
3555 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3556#ifdef DEBUG_TREE
3557 xmlGenericError(xmlGenericErrorContext,
3558 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3559#endif
3560 return(old);
3561 }
Owen Taylor3473f882001-02-23 17:55:21 +00003562 xmlUnlinkNode(cur);
3563 cur->doc = old->doc;
3564 cur->parent = old->parent;
3565 cur->next = old->next;
3566 if (cur->next != NULL)
3567 cur->next->prev = cur;
3568 cur->prev = old->prev;
3569 if (cur->prev != NULL)
3570 cur->prev->next = cur;
3571 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003572 if (cur->type == XML_ATTRIBUTE_NODE) {
3573 if (cur->parent->properties == (xmlAttrPtr)old)
3574 cur->parent->properties = ((xmlAttrPtr) cur);
3575 } else {
3576 if (cur->parent->children == old)
3577 cur->parent->children = cur;
3578 if (cur->parent->last == old)
3579 cur->parent->last = cur;
3580 }
Owen Taylor3473f882001-02-23 17:55:21 +00003581 }
3582 old->next = old->prev = NULL;
3583 old->parent = NULL;
3584 return(old);
3585}
Daniel Veillard652327a2003-09-29 18:02:38 +00003586#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003587
3588/************************************************************************
3589 * *
3590 * Copy operations *
3591 * *
3592 ************************************************************************/
3593
3594/**
3595 * xmlCopyNamespace:
3596 * @cur: the namespace
3597 *
3598 * Do a copy of the namespace.
3599 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003600 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003601 */
3602xmlNsPtr
3603xmlCopyNamespace(xmlNsPtr cur) {
3604 xmlNsPtr ret;
3605
3606 if (cur == NULL) return(NULL);
3607 switch (cur->type) {
3608 case XML_LOCAL_NAMESPACE:
3609 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3610 break;
3611 default:
3612#ifdef DEBUG_TREE
3613 xmlGenericError(xmlGenericErrorContext,
3614 "xmlCopyNamespace: invalid type %d\n", cur->type);
3615#endif
3616 return(NULL);
3617 }
3618 return(ret);
3619}
3620
3621/**
3622 * xmlCopyNamespaceList:
3623 * @cur: the first namespace
3624 *
3625 * Do a copy of an namespace list.
3626 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003627 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003628 */
3629xmlNsPtr
3630xmlCopyNamespaceList(xmlNsPtr cur) {
3631 xmlNsPtr ret = NULL;
3632 xmlNsPtr p = NULL,q;
3633
3634 while (cur != NULL) {
3635 q = xmlCopyNamespace(cur);
3636 if (p == NULL) {
3637 ret = p = q;
3638 } else {
3639 p->next = q;
3640 p = q;
3641 }
3642 cur = cur->next;
3643 }
3644 return(ret);
3645}
3646
3647static xmlNodePtr
3648xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3649/**
3650 * xmlCopyProp:
3651 * @target: the element where the attribute will be grafted
3652 * @cur: the attribute
3653 *
3654 * Do a copy of the attribute.
3655 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003656 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003657 */
3658xmlAttrPtr
3659xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3660 xmlAttrPtr ret;
3661
3662 if (cur == NULL) return(NULL);
3663 if (target != NULL)
3664 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3665 else if (cur->parent != NULL)
3666 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3667 else if (cur->children != NULL)
3668 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3669 else
3670 ret = xmlNewDocProp(NULL, cur->name, NULL);
3671 if (ret == NULL) return(NULL);
3672 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003673
Owen Taylor3473f882001-02-23 17:55:21 +00003674 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003675 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003676
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003677 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3678 if (ns == NULL) {
3679 /*
3680 * Humm, we are copying an element whose namespace is defined
3681 * out of the new tree scope. Search it in the original tree
3682 * and add it at the top of the new tree
3683 */
3684 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3685 if (ns != NULL) {
3686 xmlNodePtr root = target;
3687 xmlNodePtr pred = NULL;
3688
3689 while (root->parent != NULL) {
3690 pred = root;
3691 root = root->parent;
3692 }
3693 if (root == (xmlNodePtr) target->doc) {
3694 /* correct possibly cycling above the document elt */
3695 root = pred;
3696 }
3697 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3698 }
3699 } else {
3700 /*
3701 * we have to find something appropriate here since
3702 * we cant be sure, that the namespce we found is identified
3703 * by the prefix
3704 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003705 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003706 /* this is the nice case */
3707 ret->ns = ns;
3708 } else {
3709 /*
3710 * we are in trouble: we need a new reconcilied namespace.
3711 * This is expensive
3712 */
3713 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3714 }
3715 }
3716
Owen Taylor3473f882001-02-23 17:55:21 +00003717 } else
3718 ret->ns = NULL;
3719
3720 if (cur->children != NULL) {
3721 xmlNodePtr tmp;
3722
3723 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3724 ret->last = NULL;
3725 tmp = ret->children;
3726 while (tmp != NULL) {
3727 /* tmp->parent = (xmlNodePtr)ret; */
3728 if (tmp->next == NULL)
3729 ret->last = tmp;
3730 tmp = tmp->next;
3731 }
3732 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003733 /*
3734 * Try to handle IDs
3735 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003736 if ((target!= NULL) && (cur!= NULL) &&
3737 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003738 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3739 if (xmlIsID(cur->doc, cur->parent, cur)) {
3740 xmlChar *id;
3741
3742 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3743 if (id != NULL) {
3744 xmlAddID(NULL, target->doc, id, ret);
3745 xmlFree(id);
3746 }
3747 }
3748 }
Owen Taylor3473f882001-02-23 17:55:21 +00003749 return(ret);
3750}
3751
3752/**
3753 * xmlCopyPropList:
3754 * @target: the element where the attributes will be grafted
3755 * @cur: the first attribute
3756 *
3757 * Do a copy of an attribute list.
3758 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003759 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003760 */
3761xmlAttrPtr
3762xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3763 xmlAttrPtr ret = NULL;
3764 xmlAttrPtr p = NULL,q;
3765
3766 while (cur != NULL) {
3767 q = xmlCopyProp(target, cur);
William M. Brack13dfa872004-09-18 04:52:08 +00003768 if (q == NULL)
3769 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003770 if (p == NULL) {
3771 ret = p = q;
3772 } else {
3773 p->next = q;
3774 q->prev = p;
3775 p = q;
3776 }
3777 cur = cur->next;
3778 }
3779 return(ret);
3780}
3781
3782/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003783 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003784 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003785 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003786 * tricky reason: namespaces. Doing a direct copy of a node
3787 * say RPM:Copyright without changing the namespace pointer to
3788 * something else can produce stale links. One way to do it is
3789 * to keep a reference counter but this doesn't work as soon
3790 * as one move the element or the subtree out of the scope of
3791 * the existing namespace. The actual solution seems to add
3792 * a copy of the namespace at the top of the copied tree if
3793 * not available in the subtree.
3794 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00003795 * The argument "recursive" normally indicates a recursive copy
3796 * of the node with values 0 (no) and 1 (yes). For XInclude,
3797 * however, we allow a value of 2 to indicate copy properties and
3798 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00003799 */
3800
3801static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003802xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00003803 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003804 xmlNodePtr ret;
3805
3806 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003807 switch (node->type) {
3808 case XML_TEXT_NODE:
3809 case XML_CDATA_SECTION_NODE:
3810 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003811 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003812 case XML_ENTITY_REF_NODE:
3813 case XML_ENTITY_NODE:
3814 case XML_PI_NODE:
3815 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003816 case XML_XINCLUDE_START:
3817 case XML_XINCLUDE_END:
3818 break;
3819 case XML_ATTRIBUTE_NODE:
3820 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3821 case XML_NAMESPACE_DECL:
3822 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3823
Daniel Veillard39196eb2001-06-19 18:09:42 +00003824 case XML_DOCUMENT_NODE:
3825 case XML_HTML_DOCUMENT_NODE:
3826#ifdef LIBXML_DOCB_ENABLED
3827 case XML_DOCB_DOCUMENT_NODE:
3828#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003829#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00003830 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00003831#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003832 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003833 case XML_NOTATION_NODE:
3834 case XML_DTD_NODE:
3835 case XML_ELEMENT_DECL:
3836 case XML_ATTRIBUTE_DECL:
3837 case XML_ENTITY_DECL:
3838 return(NULL);
3839 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003840
Owen Taylor3473f882001-02-23 17:55:21 +00003841 /*
3842 * Allocate a new node and fill the fields.
3843 */
3844 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3845 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003846 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003847 return(NULL);
3848 }
3849 memset(ret, 0, sizeof(xmlNode));
3850 ret->type = node->type;
3851
3852 ret->doc = doc;
3853 ret->parent = parent;
3854 if (node->name == xmlStringText)
3855 ret->name = xmlStringText;
3856 else if (node->name == xmlStringTextNoenc)
3857 ret->name = xmlStringTextNoenc;
3858 else if (node->name == xmlStringComment)
3859 ret->name = xmlStringComment;
Daniel Veillard03a53c32004-10-26 16:06:51 +00003860 else if (node->name != NULL) {
3861 if ((doc != NULL) && (doc->dict != NULL))
3862 ret->name = xmlDictLookup(doc->dict, node->name, -1);
3863 else
3864 ret->name = xmlStrdup(node->name);
3865 }
Daniel Veillard7db37732001-07-12 01:20:08 +00003866 if ((node->type != XML_ELEMENT_NODE) &&
3867 (node->content != NULL) &&
3868 (node->type != XML_ENTITY_REF_NODE) &&
3869 (node->type != XML_XINCLUDE_END) &&
3870 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003871 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003872 }else{
3873 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003874 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003875 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003876 if (parent != NULL) {
3877 xmlNodePtr tmp;
3878
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003879 /*
3880 * this is a tricky part for the node register thing:
3881 * in case ret does get coalesced in xmlAddChild
3882 * the deregister-node callback is called; so we register ret now already
3883 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003884 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003885 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3886
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003887 tmp = xmlAddChild(parent, ret);
3888 /* node could have coalesced */
3889 if (tmp != ret)
3890 return(tmp);
3891 }
Owen Taylor3473f882001-02-23 17:55:21 +00003892
William M. Brack57e9e912004-03-09 16:19:02 +00003893 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003894 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003895 if (node->nsDef != NULL)
3896 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3897
3898 if (node->ns != NULL) {
3899 xmlNsPtr ns;
3900
3901 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3902 if (ns == NULL) {
3903 /*
3904 * Humm, we are copying an element whose namespace is defined
3905 * out of the new tree scope. Search it in the original tree
3906 * and add it at the top of the new tree
3907 */
3908 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3909 if (ns != NULL) {
3910 xmlNodePtr root = ret;
3911
3912 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003913 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003914 }
3915 } else {
3916 /*
3917 * reference the existing namespace definition in our own tree.
3918 */
3919 ret->ns = ns;
3920 }
3921 }
3922 if (node->properties != NULL)
3923 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003924 if (node->type == XML_ENTITY_REF_NODE) {
3925 if ((doc == NULL) || (node->doc != doc)) {
3926 /*
3927 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003928 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003929 * we cannot keep the reference. Try to find it in the
3930 * target document.
3931 */
3932 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3933 } else {
3934 ret->children = node->children;
3935 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003936 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00003937 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003938 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003939 UPDATE_LAST_CHILD_AND_PARENT(ret)
3940 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003941
3942out:
3943 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00003944 if ((parent == NULL) &&
3945 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003946 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003947 return(ret);
3948}
3949
3950static xmlNodePtr
3951xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3952 xmlNodePtr ret = NULL;
3953 xmlNodePtr p = NULL,q;
3954
3955 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003956#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003957 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003958 if (doc == NULL) {
3959 node = node->next;
3960 continue;
3961 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003962 if (doc->intSubset == NULL) {
3963 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3964 q->doc = doc;
3965 q->parent = parent;
3966 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003967 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003968 } else {
3969 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003970 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003971 }
3972 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003973#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003974 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003975 if (ret == NULL) {
3976 q->prev = NULL;
3977 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003978 } else if (p != q) {
3979 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003980 p->next = q;
3981 q->prev = p;
3982 p = q;
3983 }
3984 node = node->next;
3985 }
3986 return(ret);
3987}
3988
3989/**
3990 * xmlCopyNode:
3991 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00003992 * @extended: if 1 do a recursive copy (properties, namespaces and children
3993 * when applicable)
3994 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00003995 *
3996 * Do a copy of the node.
3997 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003998 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003999 */
4000xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00004001xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00004002 xmlNodePtr ret;
4003
William M. Brack57e9e912004-03-09 16:19:02 +00004004 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00004005 return(ret);
4006}
4007
4008/**
Daniel Veillard82daa812001-04-12 08:55:36 +00004009 * xmlDocCopyNode:
4010 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00004011 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004012 * @extended: if 1 do a recursive copy (properties, namespaces and children
4013 * when applicable)
4014 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00004015 *
4016 * Do a copy of the node to a given document.
4017 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004018 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00004019 */
4020xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00004021xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00004022 xmlNodePtr ret;
4023
William M. Brack57e9e912004-03-09 16:19:02 +00004024 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00004025 return(ret);
4026}
4027
4028/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00004029 * xmlDocCopyNodeList:
4030 * @doc: the target document
4031 * @node: the first node in the list.
4032 *
4033 * Do a recursive copy of the node list.
4034 *
4035 * Returns: a new #xmlNodePtr, or NULL in case of error.
4036 */
4037xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) {
4038 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
4039 return(ret);
4040}
4041
4042/**
Owen Taylor3473f882001-02-23 17:55:21 +00004043 * xmlCopyNodeList:
4044 * @node: the first node in the list.
4045 *
4046 * Do a recursive copy of the node list.
Daniel Veillard03a53c32004-10-26 16:06:51 +00004047 * Use xmlDocCopyNodeList() if possible to ensure string interning.
Owen Taylor3473f882001-02-23 17:55:21 +00004048 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004049 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004050 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00004051xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00004052 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
4053 return(ret);
4054}
4055
Daniel Veillard2156d432004-03-04 15:59:36 +00004056#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004057/**
Owen Taylor3473f882001-02-23 17:55:21 +00004058 * xmlCopyDtd:
4059 * @dtd: the dtd
4060 *
4061 * Do a copy of the dtd.
4062 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004063 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004064 */
4065xmlDtdPtr
4066xmlCopyDtd(xmlDtdPtr dtd) {
4067 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004068 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00004069
4070 if (dtd == NULL) return(NULL);
4071 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4072 if (ret == NULL) return(NULL);
4073 if (dtd->entities != NULL)
4074 ret->entities = (void *) xmlCopyEntitiesTable(
4075 (xmlEntitiesTablePtr) dtd->entities);
4076 if (dtd->notations != NULL)
4077 ret->notations = (void *) xmlCopyNotationTable(
4078 (xmlNotationTablePtr) dtd->notations);
4079 if (dtd->elements != NULL)
4080 ret->elements = (void *) xmlCopyElementTable(
4081 (xmlElementTablePtr) dtd->elements);
4082 if (dtd->attributes != NULL)
4083 ret->attributes = (void *) xmlCopyAttributeTable(
4084 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004085 if (dtd->pentities != NULL)
4086 ret->pentities = (void *) xmlCopyEntitiesTable(
4087 (xmlEntitiesTablePtr) dtd->pentities);
4088
4089 cur = dtd->children;
4090 while (cur != NULL) {
4091 q = NULL;
4092
4093 if (cur->type == XML_ENTITY_DECL) {
4094 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4095 switch (tmp->etype) {
4096 case XML_INTERNAL_GENERAL_ENTITY:
4097 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4098 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4099 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4100 break;
4101 case XML_INTERNAL_PARAMETER_ENTITY:
4102 case XML_EXTERNAL_PARAMETER_ENTITY:
4103 q = (xmlNodePtr)
4104 xmlGetParameterEntityFromDtd(ret, tmp->name);
4105 break;
4106 case XML_INTERNAL_PREDEFINED_ENTITY:
4107 break;
4108 }
4109 } else if (cur->type == XML_ELEMENT_DECL) {
4110 xmlElementPtr tmp = (xmlElementPtr) cur;
4111 q = (xmlNodePtr)
4112 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4113 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4114 xmlAttributePtr tmp = (xmlAttributePtr) cur;
4115 q = (xmlNodePtr)
4116 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4117 } else if (cur->type == XML_COMMENT_NODE) {
4118 q = xmlCopyNode(cur, 0);
4119 }
4120
4121 if (q == NULL) {
4122 cur = cur->next;
4123 continue;
4124 }
4125
4126 if (p == NULL)
4127 ret->children = q;
4128 else
4129 p->next = q;
4130
4131 q->prev = p;
4132 q->parent = (xmlNodePtr) ret;
4133 q->next = NULL;
4134 ret->last = q;
4135 p = q;
4136 cur = cur->next;
4137 }
4138
Owen Taylor3473f882001-02-23 17:55:21 +00004139 return(ret);
4140}
Daniel Veillard2156d432004-03-04 15:59:36 +00004141#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004142
Daniel Veillard2156d432004-03-04 15:59:36 +00004143#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004144/**
4145 * xmlCopyDoc:
4146 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004147 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004148 *
4149 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004150 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004151 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004152 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004153 */
4154xmlDocPtr
4155xmlCopyDoc(xmlDocPtr doc, int recursive) {
4156 xmlDocPtr ret;
4157
4158 if (doc == NULL) return(NULL);
4159 ret = xmlNewDoc(doc->version);
4160 if (ret == NULL) return(NULL);
4161 if (doc->name != NULL)
4162 ret->name = xmlMemStrdup(doc->name);
4163 if (doc->encoding != NULL)
4164 ret->encoding = xmlStrdup(doc->encoding);
4165 ret->charset = doc->charset;
4166 ret->compression = doc->compression;
4167 ret->standalone = doc->standalone;
4168 if (!recursive) return(ret);
4169
Daniel Veillardb33c2012001-04-25 12:59:04 +00004170 ret->last = NULL;
4171 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004172#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004173 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004174 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004175 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004176 ret->intSubset->parent = ret;
4177 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004178#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004179 if (doc->oldNs != NULL)
4180 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4181 if (doc->children != NULL) {
4182 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004183
4184 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4185 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004186 ret->last = NULL;
4187 tmp = ret->children;
4188 while (tmp != NULL) {
4189 if (tmp->next == NULL)
4190 ret->last = tmp;
4191 tmp = tmp->next;
4192 }
4193 }
4194 return(ret);
4195}
Daniel Veillard652327a2003-09-29 18:02:38 +00004196#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004197
4198/************************************************************************
4199 * *
4200 * Content access functions *
4201 * *
4202 ************************************************************************/
4203
4204/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004205 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004206 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004207 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004208 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004209 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004210 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004211 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004212 */
4213long
4214xmlGetLineNo(xmlNodePtr node)
4215{
4216 long result = -1;
4217
4218 if (!node)
4219 return result;
4220 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004221 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004222 else if ((node->prev != NULL) &&
4223 ((node->prev->type == XML_ELEMENT_NODE) ||
4224 (node->prev->type == XML_TEXT_NODE)))
4225 result = xmlGetLineNo(node->prev);
4226 else if ((node->parent != NULL) &&
4227 ((node->parent->type == XML_ELEMENT_NODE) ||
4228 (node->parent->type == XML_TEXT_NODE)))
4229 result = xmlGetLineNo(node->parent);
4230
4231 return result;
4232}
4233
Daniel Veillard2156d432004-03-04 15:59:36 +00004234#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004235/**
4236 * xmlGetNodePath:
4237 * @node: a node
4238 *
4239 * Build a structure based Path for the given node
4240 *
4241 * Returns the new path or NULL in case of error. The caller must free
4242 * the returned string
4243 */
4244xmlChar *
4245xmlGetNodePath(xmlNodePtr node)
4246{
4247 xmlNodePtr cur, tmp, next;
4248 xmlChar *buffer = NULL, *temp;
4249 size_t buf_len;
4250 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004251 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004252 const char *name;
4253 char nametemp[100];
4254 int occur = 0;
4255
4256 if (node == NULL)
4257 return (NULL);
4258
4259 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004260 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004261 if (buffer == NULL) {
4262 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004263 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004264 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004265 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004266 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004267 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004268 xmlFree(buffer);
4269 return (NULL);
4270 }
4271
4272 buffer[0] = 0;
4273 cur = node;
4274 do {
4275 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004276 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004277 occur = 0;
4278 if ((cur->type == XML_DOCUMENT_NODE) ||
4279 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4280 if (buffer[0] == '/')
4281 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004282 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004283 next = NULL;
4284 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004285 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004286 name = (const char *) cur->name;
4287 if (cur->ns) {
William M. Brack84d83e32003-12-23 03:45:17 +00004288 if (cur->ns->prefix != NULL)
William M. Brack13dfa872004-09-18 04:52:08 +00004289 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4290 (char *)cur->ns->prefix, (char *)cur->name);
William M. Brack84d83e32003-12-23 03:45:17 +00004291 else
William M. Brack13dfa872004-09-18 04:52:08 +00004292 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4293 (char *)cur->name);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004294 nametemp[sizeof(nametemp) - 1] = 0;
4295 name = nametemp;
4296 }
4297 next = cur->parent;
4298
4299 /*
4300 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004301 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004302 */
4303 tmp = cur->prev;
4304 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004305 if ((tmp->type == XML_ELEMENT_NODE) &&
4306 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004307 occur++;
4308 tmp = tmp->prev;
4309 }
4310 if (occur == 0) {
4311 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004312 while (tmp != NULL && occur == 0) {
4313 if ((tmp->type == XML_ELEMENT_NODE) &&
4314 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004315 occur++;
4316 tmp = tmp->next;
4317 }
4318 if (occur != 0)
4319 occur = 1;
4320 } else
4321 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004322 } else if (cur->type == XML_COMMENT_NODE) {
4323 sep = "/";
4324 name = "comment()";
4325 next = cur->parent;
4326
4327 /*
4328 * Thumbler index computation
4329 */
4330 tmp = cur->prev;
4331 while (tmp != NULL) {
4332 if (tmp->type == XML_COMMENT_NODE)
4333 occur++;
4334 tmp = tmp->prev;
4335 }
4336 if (occur == 0) {
4337 tmp = cur->next;
4338 while (tmp != NULL && occur == 0) {
4339 if (tmp->type == XML_COMMENT_NODE)
4340 occur++;
4341 tmp = tmp->next;
4342 }
4343 if (occur != 0)
4344 occur = 1;
4345 } else
4346 occur++;
4347 } else if ((cur->type == XML_TEXT_NODE) ||
4348 (cur->type == XML_CDATA_SECTION_NODE)) {
4349 sep = "/";
4350 name = "text()";
4351 next = cur->parent;
4352
4353 /*
4354 * Thumbler index computation
4355 */
4356 tmp = cur->prev;
4357 while (tmp != NULL) {
4358 if ((cur->type == XML_TEXT_NODE) ||
4359 (cur->type == XML_CDATA_SECTION_NODE))
4360 occur++;
4361 tmp = tmp->prev;
4362 }
4363 if (occur == 0) {
4364 tmp = cur->next;
4365 while (tmp != NULL && occur == 0) {
Daniel Veillard1f8658a2004-08-14 21:46:31 +00004366 if ((tmp->type == XML_TEXT_NODE) ||
4367 (tmp->type == XML_CDATA_SECTION_NODE))
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004368 occur++;
4369 tmp = tmp->next;
4370 }
4371 if (occur != 0)
4372 occur = 1;
4373 } else
4374 occur++;
4375 } else if (cur->type == XML_PI_NODE) {
4376 sep = "/";
4377 snprintf(nametemp, sizeof(nametemp) - 1,
William M. Brack13dfa872004-09-18 04:52:08 +00004378 "processing-instruction('%s')", (char *)cur->name);
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004379 nametemp[sizeof(nametemp) - 1] = 0;
4380 name = nametemp;
4381
4382 next = cur->parent;
4383
4384 /*
4385 * Thumbler index computation
4386 */
4387 tmp = cur->prev;
4388 while (tmp != NULL) {
4389 if ((tmp->type == XML_PI_NODE) &&
4390 (xmlStrEqual(cur->name, tmp->name)))
4391 occur++;
4392 tmp = tmp->prev;
4393 }
4394 if (occur == 0) {
4395 tmp = cur->next;
4396 while (tmp != NULL && occur == 0) {
4397 if ((tmp->type == XML_PI_NODE) &&
4398 (xmlStrEqual(cur->name, tmp->name)))
4399 occur++;
4400 tmp = tmp->next;
4401 }
4402 if (occur != 0)
4403 occur = 1;
4404 } else
4405 occur++;
4406
Daniel Veillard8faa7832001-11-26 15:58:08 +00004407 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004408 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004409 name = (const char *) (((xmlAttrPtr) cur)->name);
4410 next = ((xmlAttrPtr) cur)->parent;
4411 } else {
4412 next = cur->parent;
4413 }
4414
4415 /*
4416 * Make sure there is enough room
4417 */
4418 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4419 buf_len =
4420 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4421 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4422 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004423 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004424 xmlFree(buf);
4425 xmlFree(buffer);
4426 return (NULL);
4427 }
4428 buffer = temp;
4429 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4430 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004431 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004432 xmlFree(buf);
4433 xmlFree(buffer);
4434 return (NULL);
4435 }
4436 buf = temp;
4437 }
4438 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004439 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004440 sep, name, (char *) buffer);
4441 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004442 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004443 sep, name, occur, (char *) buffer);
William M. Brack13dfa872004-09-18 04:52:08 +00004444 snprintf((char *) buffer, buf_len, "%s", (char *)buf);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004445 cur = next;
4446 } while (cur != NULL);
4447 xmlFree(buf);
4448 return (buffer);
4449}
Daniel Veillard652327a2003-09-29 18:02:38 +00004450#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004451
4452/**
Owen Taylor3473f882001-02-23 17:55:21 +00004453 * xmlDocGetRootElement:
4454 * @doc: the document
4455 *
4456 * Get the root element of the document (doc->children is a list
4457 * containing possibly comments, PIs, etc ...).
4458 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004459 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004460 */
4461xmlNodePtr
4462xmlDocGetRootElement(xmlDocPtr doc) {
4463 xmlNodePtr ret;
4464
4465 if (doc == NULL) return(NULL);
4466 ret = doc->children;
4467 while (ret != NULL) {
4468 if (ret->type == XML_ELEMENT_NODE)
4469 return(ret);
4470 ret = ret->next;
4471 }
4472 return(ret);
4473}
4474
Daniel Veillard2156d432004-03-04 15:59:36 +00004475#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004476/**
4477 * xmlDocSetRootElement:
4478 * @doc: the document
4479 * @root: the new document root element
4480 *
4481 * Set the root element of the document (doc->children is a list
4482 * containing possibly comments, PIs, etc ...).
4483 *
4484 * Returns the old root element if any was found
4485 */
4486xmlNodePtr
4487xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4488 xmlNodePtr old = NULL;
4489
4490 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004491 if (root == NULL)
4492 return(NULL);
4493 xmlUnlinkNode(root);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00004494 xmlSetTreeDoc(root, doc);
Daniel Veillardc575b992002-02-08 13:28:40 +00004495 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004496 old = doc->children;
4497 while (old != NULL) {
4498 if (old->type == XML_ELEMENT_NODE)
4499 break;
4500 old = old->next;
4501 }
4502 if (old == NULL) {
4503 if (doc->children == NULL) {
4504 doc->children = root;
4505 doc->last = root;
4506 } else {
4507 xmlAddSibling(doc->children, root);
4508 }
4509 } else {
4510 xmlReplaceNode(old, root);
4511 }
4512 return(old);
4513}
Daniel Veillard2156d432004-03-04 15:59:36 +00004514#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004515
Daniel Veillard2156d432004-03-04 15:59:36 +00004516#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004517/**
4518 * xmlNodeSetLang:
4519 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004520 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004521 *
4522 * Set the language of a node, i.e. the values of the xml:lang
4523 * attribute.
4524 */
4525void
4526xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004527 xmlNsPtr ns;
4528
Owen Taylor3473f882001-02-23 17:55:21 +00004529 if (cur == NULL) return;
4530 switch(cur->type) {
4531 case XML_TEXT_NODE:
4532 case XML_CDATA_SECTION_NODE:
4533 case XML_COMMENT_NODE:
4534 case XML_DOCUMENT_NODE:
4535 case XML_DOCUMENT_TYPE_NODE:
4536 case XML_DOCUMENT_FRAG_NODE:
4537 case XML_NOTATION_NODE:
4538 case XML_HTML_DOCUMENT_NODE:
4539 case XML_DTD_NODE:
4540 case XML_ELEMENT_DECL:
4541 case XML_ATTRIBUTE_DECL:
4542 case XML_ENTITY_DECL:
4543 case XML_PI_NODE:
4544 case XML_ENTITY_REF_NODE:
4545 case XML_ENTITY_NODE:
4546 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004547#ifdef LIBXML_DOCB_ENABLED
4548 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004549#endif
4550 case XML_XINCLUDE_START:
4551 case XML_XINCLUDE_END:
4552 return;
4553 case XML_ELEMENT_NODE:
4554 case XML_ATTRIBUTE_NODE:
4555 break;
4556 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004557 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4558 if (ns == NULL)
4559 return;
4560 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004561}
Daniel Veillard652327a2003-09-29 18:02:38 +00004562#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004563
4564/**
4565 * xmlNodeGetLang:
4566 * @cur: the node being checked
4567 *
4568 * Searches the language of a node, i.e. the values of the xml:lang
4569 * attribute or the one carried by the nearest ancestor.
4570 *
4571 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004572 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004573 */
4574xmlChar *
4575xmlNodeGetLang(xmlNodePtr cur) {
4576 xmlChar *lang;
4577
4578 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004579 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004580 if (lang != NULL)
4581 return(lang);
4582 cur = cur->parent;
4583 }
4584 return(NULL);
4585}
4586
4587
Daniel Veillard652327a2003-09-29 18:02:38 +00004588#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004589/**
4590 * xmlNodeSetSpacePreserve:
4591 * @cur: the node being changed
4592 * @val: the xml:space value ("0": default, 1: "preserve")
4593 *
4594 * Set (or reset) the space preserving behaviour of a node, i.e. the
4595 * value of the xml:space attribute.
4596 */
4597void
4598xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004599 xmlNsPtr ns;
4600
Owen Taylor3473f882001-02-23 17:55:21 +00004601 if (cur == NULL) return;
4602 switch(cur->type) {
4603 case XML_TEXT_NODE:
4604 case XML_CDATA_SECTION_NODE:
4605 case XML_COMMENT_NODE:
4606 case XML_DOCUMENT_NODE:
4607 case XML_DOCUMENT_TYPE_NODE:
4608 case XML_DOCUMENT_FRAG_NODE:
4609 case XML_NOTATION_NODE:
4610 case XML_HTML_DOCUMENT_NODE:
4611 case XML_DTD_NODE:
4612 case XML_ELEMENT_DECL:
4613 case XML_ATTRIBUTE_DECL:
4614 case XML_ENTITY_DECL:
4615 case XML_PI_NODE:
4616 case XML_ENTITY_REF_NODE:
4617 case XML_ENTITY_NODE:
4618 case XML_NAMESPACE_DECL:
4619 case XML_XINCLUDE_START:
4620 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004621#ifdef LIBXML_DOCB_ENABLED
4622 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004623#endif
4624 return;
4625 case XML_ELEMENT_NODE:
4626 case XML_ATTRIBUTE_NODE:
4627 break;
4628 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004629 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4630 if (ns == NULL)
4631 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004632 switch (val) {
4633 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004634 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004635 break;
4636 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004637 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004638 break;
4639 }
4640}
Daniel Veillard652327a2003-09-29 18:02:38 +00004641#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004642
4643/**
4644 * xmlNodeGetSpacePreserve:
4645 * @cur: the node being checked
4646 *
4647 * Searches the space preserving behaviour of a node, i.e. the values
4648 * of the xml:space attribute or the one carried by the nearest
4649 * ancestor.
4650 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004651 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004652 */
4653int
4654xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4655 xmlChar *space;
4656
4657 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004658 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004659 if (space != NULL) {
4660 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4661 xmlFree(space);
4662 return(1);
4663 }
4664 if (xmlStrEqual(space, BAD_CAST "default")) {
4665 xmlFree(space);
4666 return(0);
4667 }
4668 xmlFree(space);
4669 }
4670 cur = cur->parent;
4671 }
4672 return(-1);
4673}
4674
Daniel Veillard652327a2003-09-29 18:02:38 +00004675#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004676/**
4677 * xmlNodeSetName:
4678 * @cur: the node being changed
4679 * @name: the new tag name
4680 *
4681 * Set (or reset) the name of a node.
4682 */
4683void
4684xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00004685 xmlDocPtr doc;
4686 xmlDictPtr dict;
4687
Owen Taylor3473f882001-02-23 17:55:21 +00004688 if (cur == NULL) return;
4689 if (name == NULL) return;
4690 switch(cur->type) {
4691 case XML_TEXT_NODE:
4692 case XML_CDATA_SECTION_NODE:
4693 case XML_COMMENT_NODE:
4694 case XML_DOCUMENT_TYPE_NODE:
4695 case XML_DOCUMENT_FRAG_NODE:
4696 case XML_NOTATION_NODE:
4697 case XML_HTML_DOCUMENT_NODE:
4698 case XML_NAMESPACE_DECL:
4699 case XML_XINCLUDE_START:
4700 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004701#ifdef LIBXML_DOCB_ENABLED
4702 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004703#endif
4704 return;
4705 case XML_ELEMENT_NODE:
4706 case XML_ATTRIBUTE_NODE:
4707 case XML_PI_NODE:
4708 case XML_ENTITY_REF_NODE:
4709 case XML_ENTITY_NODE:
4710 case XML_DTD_NODE:
4711 case XML_DOCUMENT_NODE:
4712 case XML_ELEMENT_DECL:
4713 case XML_ATTRIBUTE_DECL:
4714 case XML_ENTITY_DECL:
4715 break;
4716 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00004717 doc = cur->doc;
4718 if (doc != NULL)
4719 dict = doc->dict;
4720 else
4721 dict = NULL;
4722 if (dict != NULL) {
4723 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
4724 xmlFree((xmlChar *) cur->name);
4725 cur->name = xmlDictLookup(dict, name, -1);
4726 } else {
4727 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4728 cur->name = xmlStrdup(name);
4729 }
Owen Taylor3473f882001-02-23 17:55:21 +00004730}
Daniel Veillard2156d432004-03-04 15:59:36 +00004731#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004732
Daniel Veillard2156d432004-03-04 15:59:36 +00004733#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004734/**
4735 * xmlNodeSetBase:
4736 * @cur: the node being changed
4737 * @uri: the new base URI
4738 *
4739 * Set (or reset) the base URI of a node, i.e. the value of the
4740 * xml:base attribute.
4741 */
4742void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004743xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004744 xmlNsPtr ns;
4745
Owen Taylor3473f882001-02-23 17:55:21 +00004746 if (cur == NULL) return;
4747 switch(cur->type) {
4748 case XML_TEXT_NODE:
4749 case XML_CDATA_SECTION_NODE:
4750 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004751 case XML_DOCUMENT_TYPE_NODE:
4752 case XML_DOCUMENT_FRAG_NODE:
4753 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004754 case XML_DTD_NODE:
4755 case XML_ELEMENT_DECL:
4756 case XML_ATTRIBUTE_DECL:
4757 case XML_ENTITY_DECL:
4758 case XML_PI_NODE:
4759 case XML_ENTITY_REF_NODE:
4760 case XML_ENTITY_NODE:
4761 case XML_NAMESPACE_DECL:
4762 case XML_XINCLUDE_START:
4763 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004764 return;
4765 case XML_ELEMENT_NODE:
4766 case XML_ATTRIBUTE_NODE:
4767 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004768 case XML_DOCUMENT_NODE:
4769#ifdef LIBXML_DOCB_ENABLED
4770 case XML_DOCB_DOCUMENT_NODE:
4771#endif
4772 case XML_HTML_DOCUMENT_NODE: {
4773 xmlDocPtr doc = (xmlDocPtr) cur;
4774
4775 if (doc->URL != NULL)
4776 xmlFree((xmlChar *) doc->URL);
4777 if (uri == NULL)
4778 doc->URL = NULL;
4779 else
4780 doc->URL = xmlStrdup(uri);
4781 return;
4782 }
Owen Taylor3473f882001-02-23 17:55:21 +00004783 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004784
4785 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4786 if (ns == NULL)
4787 return;
4788 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004789}
Daniel Veillard652327a2003-09-29 18:02:38 +00004790#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004791
4792/**
Owen Taylor3473f882001-02-23 17:55:21 +00004793 * xmlNodeGetBase:
4794 * @doc: the document the node pertains to
4795 * @cur: the node being checked
4796 *
4797 * Searches for the BASE URL. The code should work on both XML
4798 * and HTML document even if base mechanisms are completely different.
4799 * It returns the base as defined in RFC 2396 sections
4800 * 5.1.1. Base URI within Document Content
4801 * and
4802 * 5.1.2. Base URI from the Encapsulating Entity
4803 * However it does not return the document base (5.1.3), use
4804 * xmlDocumentGetBase() for this
4805 *
4806 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004807 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004808 */
4809xmlChar *
4810xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004811 xmlChar *oldbase = NULL;
4812 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004813
4814 if ((cur == NULL) && (doc == NULL))
4815 return(NULL);
4816 if (doc == NULL) doc = cur->doc;
4817 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4818 cur = doc->children;
4819 while ((cur != NULL) && (cur->name != NULL)) {
4820 if (cur->type != XML_ELEMENT_NODE) {
4821 cur = cur->next;
4822 continue;
4823 }
4824 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4825 cur = cur->children;
4826 continue;
4827 }
4828 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4829 cur = cur->children;
4830 continue;
4831 }
4832 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4833 return(xmlGetProp(cur, BAD_CAST "href"));
4834 }
4835 cur = cur->next;
4836 }
4837 return(NULL);
4838 }
4839 while (cur != NULL) {
4840 if (cur->type == XML_ENTITY_DECL) {
4841 xmlEntityPtr ent = (xmlEntityPtr) cur;
4842 return(xmlStrdup(ent->URI));
4843 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004844 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004845 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004846 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004847 if (oldbase != NULL) {
4848 newbase = xmlBuildURI(oldbase, base);
4849 if (newbase != NULL) {
4850 xmlFree(oldbase);
4851 xmlFree(base);
4852 oldbase = newbase;
4853 } else {
4854 xmlFree(oldbase);
4855 xmlFree(base);
4856 return(NULL);
4857 }
4858 } else {
4859 oldbase = base;
4860 }
4861 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4862 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4863 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4864 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004865 }
4866 }
Owen Taylor3473f882001-02-23 17:55:21 +00004867 cur = cur->parent;
4868 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004869 if ((doc != NULL) && (doc->URL != NULL)) {
4870 if (oldbase == NULL)
4871 return(xmlStrdup(doc->URL));
4872 newbase = xmlBuildURI(oldbase, doc->URL);
4873 xmlFree(oldbase);
4874 return(newbase);
4875 }
4876 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004877}
4878
4879/**
Daniel Veillard78697292003-10-19 20:44:43 +00004880 * xmlNodeBufGetContent:
4881 * @buffer: a buffer
4882 * @cur: the node being read
4883 *
4884 * Read the value of a node @cur, this can be either the text carried
4885 * directly by this node if it's a TEXT node or the aggregate string
4886 * of the values carried by this node child's (TEXT and ENTITY_REF).
4887 * Entity references are substituted.
4888 * Fills up the buffer @buffer with this value
4889 *
4890 * Returns 0 in case of success and -1 in case of error.
4891 */
4892int
4893xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4894{
4895 if ((cur == NULL) || (buffer == NULL)) return(-1);
4896 switch (cur->type) {
4897 case XML_CDATA_SECTION_NODE:
4898 case XML_TEXT_NODE:
4899 xmlBufferCat(buffer, cur->content);
4900 break;
4901 case XML_DOCUMENT_FRAG_NODE:
4902 case XML_ELEMENT_NODE:{
4903 xmlNodePtr tmp = cur;
4904
4905 while (tmp != NULL) {
4906 switch (tmp->type) {
4907 case XML_CDATA_SECTION_NODE:
4908 case XML_TEXT_NODE:
4909 if (tmp->content != NULL)
4910 xmlBufferCat(buffer, tmp->content);
4911 break;
4912 case XML_ENTITY_REF_NODE:
4913 xmlNodeBufGetContent(buffer, tmp->children);
4914 break;
4915 default:
4916 break;
4917 }
4918 /*
4919 * Skip to next node
4920 */
4921 if (tmp->children != NULL) {
4922 if (tmp->children->type != XML_ENTITY_DECL) {
4923 tmp = tmp->children;
4924 continue;
4925 }
4926 }
4927 if (tmp == cur)
4928 break;
4929
4930 if (tmp->next != NULL) {
4931 tmp = tmp->next;
4932 continue;
4933 }
4934
4935 do {
4936 tmp = tmp->parent;
4937 if (tmp == NULL)
4938 break;
4939 if (tmp == cur) {
4940 tmp = NULL;
4941 break;
4942 }
4943 if (tmp->next != NULL) {
4944 tmp = tmp->next;
4945 break;
4946 }
4947 } while (tmp != NULL);
4948 }
4949 break;
4950 }
4951 case XML_ATTRIBUTE_NODE:{
4952 xmlAttrPtr attr = (xmlAttrPtr) cur;
4953 xmlNodePtr tmp = attr->children;
4954
4955 while (tmp != NULL) {
4956 if (tmp->type == XML_TEXT_NODE)
4957 xmlBufferCat(buffer, tmp->content);
4958 else
4959 xmlNodeBufGetContent(buffer, tmp);
4960 tmp = tmp->next;
4961 }
4962 break;
4963 }
4964 case XML_COMMENT_NODE:
4965 case XML_PI_NODE:
4966 xmlBufferCat(buffer, cur->content);
4967 break;
4968 case XML_ENTITY_REF_NODE:{
4969 xmlEntityPtr ent;
4970 xmlNodePtr tmp;
4971
4972 /* lookup entity declaration */
4973 ent = xmlGetDocEntity(cur->doc, cur->name);
4974 if (ent == NULL)
4975 return(-1);
4976
4977 /* an entity content can be any "well balanced chunk",
4978 * i.e. the result of the content [43] production:
4979 * http://www.w3.org/TR/REC-xml#NT-content
4980 * -> we iterate through child nodes and recursive call
4981 * xmlNodeGetContent() which handles all possible node types */
4982 tmp = ent->children;
4983 while (tmp) {
4984 xmlNodeBufGetContent(buffer, tmp);
4985 tmp = tmp->next;
4986 }
4987 break;
4988 }
4989 case XML_ENTITY_NODE:
4990 case XML_DOCUMENT_TYPE_NODE:
4991 case XML_NOTATION_NODE:
4992 case XML_DTD_NODE:
4993 case XML_XINCLUDE_START:
4994 case XML_XINCLUDE_END:
4995 break;
4996 case XML_DOCUMENT_NODE:
4997#ifdef LIBXML_DOCB_ENABLED
4998 case XML_DOCB_DOCUMENT_NODE:
4999#endif
5000 case XML_HTML_DOCUMENT_NODE:
5001 cur = cur->children;
5002 while (cur!= NULL) {
5003 if ((cur->type == XML_ELEMENT_NODE) ||
5004 (cur->type == XML_TEXT_NODE) ||
5005 (cur->type == XML_CDATA_SECTION_NODE)) {
5006 xmlNodeBufGetContent(buffer, cur);
5007 }
5008 cur = cur->next;
5009 }
5010 break;
5011 case XML_NAMESPACE_DECL:
5012 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
5013 break;
5014 case XML_ELEMENT_DECL:
5015 case XML_ATTRIBUTE_DECL:
5016 case XML_ENTITY_DECL:
5017 break;
5018 }
5019 return(0);
5020}
5021/**
Owen Taylor3473f882001-02-23 17:55:21 +00005022 * xmlNodeGetContent:
5023 * @cur: the node being read
5024 *
5025 * Read the value of a node, this can be either the text carried
5026 * directly by this node if it's a TEXT node or the aggregate string
5027 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00005028 * Entity references are substituted.
5029 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005030 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005031 */
5032xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00005033xmlNodeGetContent(xmlNodePtr cur)
5034{
5035 if (cur == NULL)
5036 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005037 switch (cur->type) {
5038 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005039 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00005040 xmlBufferPtr buffer;
5041 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00005042
Daniel Veillard814a76d2003-01-23 18:24:20 +00005043 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00005044 if (buffer == NULL)
5045 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00005046 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005047 ret = buffer->content;
5048 buffer->content = NULL;
5049 xmlBufferFree(buffer);
5050 return (ret);
5051 }
5052 case XML_ATTRIBUTE_NODE:{
5053 xmlAttrPtr attr = (xmlAttrPtr) cur;
5054
5055 if (attr->parent != NULL)
5056 return (xmlNodeListGetString
5057 (attr->parent->doc, attr->children, 1));
5058 else
5059 return (xmlNodeListGetString(NULL, attr->children, 1));
5060 break;
5061 }
Owen Taylor3473f882001-02-23 17:55:21 +00005062 case XML_COMMENT_NODE:
5063 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005064 if (cur->content != NULL)
5065 return (xmlStrdup(cur->content));
5066 return (NULL);
5067 case XML_ENTITY_REF_NODE:{
5068 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00005069 xmlBufferPtr buffer;
5070 xmlChar *ret;
5071
5072 /* lookup entity declaration */
5073 ent = xmlGetDocEntity(cur->doc, cur->name);
5074 if (ent == NULL)
5075 return (NULL);
5076
5077 buffer = xmlBufferCreate();
5078 if (buffer == NULL)
5079 return (NULL);
5080
Daniel Veillardc4696922003-10-19 21:47:14 +00005081 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005082
5083 ret = buffer->content;
5084 buffer->content = NULL;
5085 xmlBufferFree(buffer);
5086 return (ret);
5087 }
Owen Taylor3473f882001-02-23 17:55:21 +00005088 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005089 case XML_DOCUMENT_TYPE_NODE:
5090 case XML_NOTATION_NODE:
5091 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005092 case XML_XINCLUDE_START:
5093 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00005094 return (NULL);
5095 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005096#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005097 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005098#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005099 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00005100 xmlBufferPtr buffer;
5101 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005102
Daniel Veillardc4696922003-10-19 21:47:14 +00005103 buffer = xmlBufferCreate();
5104 if (buffer == NULL)
5105 return (NULL);
5106
5107 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5108
5109 ret = buffer->content;
5110 buffer->content = NULL;
5111 xmlBufferFree(buffer);
5112 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005113 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005114 case XML_NAMESPACE_DECL: {
5115 xmlChar *tmp;
5116
5117 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5118 return (tmp);
5119 }
Owen Taylor3473f882001-02-23 17:55:21 +00005120 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005121 /* TODO !!! */
5122 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005123 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005124 /* TODO !!! */
5125 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005126 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005127 /* TODO !!! */
5128 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005129 case XML_CDATA_SECTION_NODE:
5130 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005131 if (cur->content != NULL)
5132 return (xmlStrdup(cur->content));
5133 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005134 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005135 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005136}
Daniel Veillard652327a2003-09-29 18:02:38 +00005137
Owen Taylor3473f882001-02-23 17:55:21 +00005138/**
5139 * xmlNodeSetContent:
5140 * @cur: the node being modified
5141 * @content: the new value of the content
5142 *
5143 * Replace the content of a node.
5144 */
5145void
5146xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5147 if (cur == NULL) {
5148#ifdef DEBUG_TREE
5149 xmlGenericError(xmlGenericErrorContext,
5150 "xmlNodeSetContent : node == NULL\n");
5151#endif
5152 return;
5153 }
5154 switch (cur->type) {
5155 case XML_DOCUMENT_FRAG_NODE:
5156 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005157 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005158 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5159 cur->children = xmlStringGetNodeList(cur->doc, content);
5160 UPDATE_LAST_CHILD_AND_PARENT(cur)
5161 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005162 case XML_TEXT_NODE:
5163 case XML_CDATA_SECTION_NODE:
5164 case XML_ENTITY_REF_NODE:
5165 case XML_ENTITY_NODE:
5166 case XML_PI_NODE:
5167 case XML_COMMENT_NODE:
5168 if (cur->content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005169 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
Daniel Veillard370ba3d2004-10-25 16:23:56 +00005170 (!xmlDictOwns(cur->doc->dict, cur->content))))
William M. Brack7762bb12004-01-04 14:49:01 +00005171 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005172 }
5173 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5174 cur->last = cur->children = NULL;
5175 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005176 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005177 } else
5178 cur->content = NULL;
5179 break;
5180 case XML_DOCUMENT_NODE:
5181 case XML_HTML_DOCUMENT_NODE:
5182 case XML_DOCUMENT_TYPE_NODE:
5183 case XML_XINCLUDE_START:
5184 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005185#ifdef LIBXML_DOCB_ENABLED
5186 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005187#endif
5188 break;
5189 case XML_NOTATION_NODE:
5190 break;
5191 case XML_DTD_NODE:
5192 break;
5193 case XML_NAMESPACE_DECL:
5194 break;
5195 case XML_ELEMENT_DECL:
5196 /* TODO !!! */
5197 break;
5198 case XML_ATTRIBUTE_DECL:
5199 /* TODO !!! */
5200 break;
5201 case XML_ENTITY_DECL:
5202 /* TODO !!! */
5203 break;
5204 }
5205}
5206
Daniel Veillard652327a2003-09-29 18:02:38 +00005207#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005208/**
5209 * xmlNodeSetContentLen:
5210 * @cur: the node being modified
5211 * @content: the new value of the content
5212 * @len: the size of @content
5213 *
5214 * Replace the content of a node.
5215 */
5216void
5217xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5218 if (cur == NULL) {
5219#ifdef DEBUG_TREE
5220 xmlGenericError(xmlGenericErrorContext,
5221 "xmlNodeSetContentLen : node == NULL\n");
5222#endif
5223 return;
5224 }
5225 switch (cur->type) {
5226 case XML_DOCUMENT_FRAG_NODE:
5227 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005228 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005229 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5230 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5231 UPDATE_LAST_CHILD_AND_PARENT(cur)
5232 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005233 case XML_TEXT_NODE:
5234 case XML_CDATA_SECTION_NODE:
5235 case XML_ENTITY_REF_NODE:
5236 case XML_ENTITY_NODE:
5237 case XML_PI_NODE:
5238 case XML_COMMENT_NODE:
5239 case XML_NOTATION_NODE:
5240 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005241 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005242 }
5243 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5244 cur->children = cur->last = NULL;
5245 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005246 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005247 } else
5248 cur->content = NULL;
5249 break;
5250 case XML_DOCUMENT_NODE:
5251 case XML_DTD_NODE:
5252 case XML_HTML_DOCUMENT_NODE:
5253 case XML_DOCUMENT_TYPE_NODE:
5254 case XML_NAMESPACE_DECL:
5255 case XML_XINCLUDE_START:
5256 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005257#ifdef LIBXML_DOCB_ENABLED
5258 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005259#endif
5260 break;
5261 case XML_ELEMENT_DECL:
5262 /* TODO !!! */
5263 break;
5264 case XML_ATTRIBUTE_DECL:
5265 /* TODO !!! */
5266 break;
5267 case XML_ENTITY_DECL:
5268 /* TODO !!! */
5269 break;
5270 }
5271}
Daniel Veillard652327a2003-09-29 18:02:38 +00005272#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005273
5274/**
5275 * xmlNodeAddContentLen:
5276 * @cur: the node being modified
5277 * @content: extra content
5278 * @len: the size of @content
5279 *
5280 * Append the extra substring to the node content.
5281 */
5282void
5283xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5284 if (cur == NULL) {
5285#ifdef DEBUG_TREE
5286 xmlGenericError(xmlGenericErrorContext,
5287 "xmlNodeAddContentLen : node == NULL\n");
5288#endif
5289 return;
5290 }
5291 if (len <= 0) return;
5292 switch (cur->type) {
5293 case XML_DOCUMENT_FRAG_NODE:
5294 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005295 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005296
Daniel Veillard7db37732001-07-12 01:20:08 +00005297 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005298 newNode = xmlNewTextLen(content, len);
5299 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005300 tmp = xmlAddChild(cur, newNode);
5301 if (tmp != newNode)
5302 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005303 if ((last != NULL) && (last->next == newNode)) {
5304 xmlTextMerge(last, newNode);
5305 }
5306 }
5307 break;
5308 }
5309 case XML_ATTRIBUTE_NODE:
5310 break;
5311 case XML_TEXT_NODE:
5312 case XML_CDATA_SECTION_NODE:
5313 case XML_ENTITY_REF_NODE:
5314 case XML_ENTITY_NODE:
5315 case XML_PI_NODE:
5316 case XML_COMMENT_NODE:
5317 case XML_NOTATION_NODE:
5318 if (content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005319 if ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5320 xmlDictOwns(cur->doc->dict, cur->content)) {
5321 cur->content =
5322 xmlStrncatNew(cur->content, content, len);
5323 break;
5324 }
Owen Taylor3473f882001-02-23 17:55:21 +00005325 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005326 }
5327 case XML_DOCUMENT_NODE:
5328 case XML_DTD_NODE:
5329 case XML_HTML_DOCUMENT_NODE:
5330 case XML_DOCUMENT_TYPE_NODE:
5331 case XML_NAMESPACE_DECL:
5332 case XML_XINCLUDE_START:
5333 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005334#ifdef LIBXML_DOCB_ENABLED
5335 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005336#endif
5337 break;
5338 case XML_ELEMENT_DECL:
5339 case XML_ATTRIBUTE_DECL:
5340 case XML_ENTITY_DECL:
5341 break;
5342 }
5343}
5344
5345/**
5346 * xmlNodeAddContent:
5347 * @cur: the node being modified
5348 * @content: extra content
5349 *
5350 * Append the extra substring to the node content.
5351 */
5352void
5353xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5354 int len;
5355
5356 if (cur == NULL) {
5357#ifdef DEBUG_TREE
5358 xmlGenericError(xmlGenericErrorContext,
5359 "xmlNodeAddContent : node == NULL\n");
5360#endif
5361 return;
5362 }
5363 if (content == NULL) return;
5364 len = xmlStrlen(content);
5365 xmlNodeAddContentLen(cur, content, len);
5366}
5367
5368/**
5369 * xmlTextMerge:
5370 * @first: the first text node
5371 * @second: the second text node being merged
5372 *
5373 * Merge two text nodes into one
5374 * Returns the first text node augmented
5375 */
5376xmlNodePtr
5377xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5378 if (first == NULL) return(second);
5379 if (second == NULL) return(first);
5380 if (first->type != XML_TEXT_NODE) return(first);
5381 if (second->type != XML_TEXT_NODE) return(first);
5382 if (second->name != first->name)
5383 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005384 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005385 xmlUnlinkNode(second);
5386 xmlFreeNode(second);
5387 return(first);
5388}
5389
Daniel Veillard2156d432004-03-04 15:59:36 +00005390#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005391/**
5392 * xmlGetNsList:
5393 * @doc: the document
5394 * @node: the current node
5395 *
5396 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005397 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005398 * that need to be freed by the caller or NULL if no
5399 * namespace if defined
5400 */
5401xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005402xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5403{
Owen Taylor3473f882001-02-23 17:55:21 +00005404 xmlNsPtr cur;
5405 xmlNsPtr *ret = NULL;
5406 int nbns = 0;
5407 int maxns = 10;
5408 int i;
5409
5410 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005411 if (node->type == XML_ELEMENT_NODE) {
5412 cur = node->nsDef;
5413 while (cur != NULL) {
5414 if (ret == NULL) {
5415 ret =
5416 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5417 sizeof(xmlNsPtr));
5418 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005419 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005420 return (NULL);
5421 }
5422 ret[nbns] = NULL;
5423 }
5424 for (i = 0; i < nbns; i++) {
5425 if ((cur->prefix == ret[i]->prefix) ||
5426 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5427 break;
5428 }
5429 if (i >= nbns) {
5430 if (nbns >= maxns) {
5431 maxns *= 2;
5432 ret = (xmlNsPtr *) xmlRealloc(ret,
5433 (maxns +
5434 1) *
5435 sizeof(xmlNsPtr));
5436 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005437 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005438 return (NULL);
5439 }
5440 }
5441 ret[nbns++] = cur;
5442 ret[nbns] = NULL;
5443 }
Owen Taylor3473f882001-02-23 17:55:21 +00005444
Daniel Veillard77044732001-06-29 21:31:07 +00005445 cur = cur->next;
5446 }
5447 }
5448 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005449 }
Daniel Veillard77044732001-06-29 21:31:07 +00005450 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005451}
Daniel Veillard652327a2003-09-29 18:02:38 +00005452#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005453
5454/**
5455 * xmlSearchNs:
5456 * @doc: the document
5457 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005458 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005459 *
5460 * Search a Ns registered under a given name space for a document.
5461 * recurse on the parents until it finds the defined namespace
5462 * or return NULL otherwise.
5463 * @nameSpace can be NULL, this is a search for the default namespace.
5464 * We don't allow to cross entities boundaries. If you don't declare
5465 * the namespace within those you will be in troubles !!! A warning
5466 * is generated to cover this case.
5467 *
5468 * Returns the namespace pointer or NULL.
5469 */
5470xmlNsPtr
5471xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005472
Owen Taylor3473f882001-02-23 17:55:21 +00005473 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005474 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005475
5476 if (node == NULL) return(NULL);
5477 if ((nameSpace != NULL) &&
5478 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005479 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5480 /*
5481 * The XML-1.0 namespace is normally held on the root
5482 * element. In this case exceptionally create it on the
5483 * node element.
5484 */
5485 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5486 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005487 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005488 return(NULL);
5489 }
5490 memset(cur, 0, sizeof(xmlNs));
5491 cur->type = XML_LOCAL_NAMESPACE;
5492 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5493 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5494 cur->next = node->nsDef;
5495 node->nsDef = cur;
5496 return(cur);
5497 }
Owen Taylor3473f882001-02-23 17:55:21 +00005498 if (doc->oldNs == NULL) {
5499 /*
5500 * Allocate a new Namespace and fill the fields.
5501 */
5502 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5503 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005504 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005505 return(NULL);
5506 }
5507 memset(doc->oldNs, 0, sizeof(xmlNs));
5508 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5509
5510 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5511 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5512 }
5513 return(doc->oldNs);
5514 }
5515 while (node != NULL) {
5516 if ((node->type == XML_ENTITY_REF_NODE) ||
5517 (node->type == XML_ENTITY_NODE) ||
5518 (node->type == XML_ENTITY_DECL))
5519 return(NULL);
5520 if (node->type == XML_ELEMENT_NODE) {
5521 cur = node->nsDef;
5522 while (cur != NULL) {
5523 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5524 (cur->href != NULL))
5525 return(cur);
5526 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5527 (cur->href != NULL) &&
5528 (xmlStrEqual(cur->prefix, nameSpace)))
5529 return(cur);
5530 cur = cur->next;
5531 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005532 if (orig != node) {
5533 cur = node->ns;
5534 if (cur != NULL) {
5535 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5536 (cur->href != NULL))
5537 return(cur);
5538 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5539 (cur->href != NULL) &&
5540 (xmlStrEqual(cur->prefix, nameSpace)))
5541 return(cur);
5542 }
5543 }
Owen Taylor3473f882001-02-23 17:55:21 +00005544 }
5545 node = node->parent;
5546 }
5547 return(NULL);
5548}
5549
5550/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005551 * xmlNsInScope:
5552 * @doc: the document
5553 * @node: the current node
5554 * @ancestor: the ancestor carrying the namespace
5555 * @prefix: the namespace prefix
5556 *
5557 * Verify that the given namespace held on @ancestor is still in scope
5558 * on node.
5559 *
5560 * Returns 1 if true, 0 if false and -1 in case of error.
5561 */
5562static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005563xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5564 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005565{
5566 xmlNsPtr tst;
5567
5568 while ((node != NULL) && (node != ancestor)) {
5569 if ((node->type == XML_ENTITY_REF_NODE) ||
5570 (node->type == XML_ENTITY_NODE) ||
5571 (node->type == XML_ENTITY_DECL))
5572 return (-1);
5573 if (node->type == XML_ELEMENT_NODE) {
5574 tst = node->nsDef;
5575 while (tst != NULL) {
5576 if ((tst->prefix == NULL)
5577 && (prefix == NULL))
5578 return (0);
5579 if ((tst->prefix != NULL)
5580 && (prefix != NULL)
5581 && (xmlStrEqual(tst->prefix, prefix)))
5582 return (0);
5583 tst = tst->next;
5584 }
5585 }
5586 node = node->parent;
5587 }
5588 if (node != ancestor)
5589 return (-1);
5590 return (1);
5591}
5592
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005593/**
Owen Taylor3473f882001-02-23 17:55:21 +00005594 * xmlSearchNsByHref:
5595 * @doc: the document
5596 * @node: the current node
5597 * @href: the namespace value
5598 *
5599 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5600 * the defined namespace or return NULL otherwise.
5601 * Returns the namespace pointer or NULL.
5602 */
5603xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005604xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5605{
Owen Taylor3473f882001-02-23 17:55:21 +00005606 xmlNsPtr cur;
5607 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005608 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005609
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005610 if ((node == NULL) || (href == NULL))
5611 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005612 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005613 /*
5614 * Only the document can hold the XML spec namespace.
5615 */
5616 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5617 /*
5618 * The XML-1.0 namespace is normally held on the root
5619 * element. In this case exceptionally create it on the
5620 * node element.
5621 */
5622 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5623 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005624 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005625 return (NULL);
5626 }
5627 memset(cur, 0, sizeof(xmlNs));
5628 cur->type = XML_LOCAL_NAMESPACE;
5629 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5630 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5631 cur->next = node->nsDef;
5632 node->nsDef = cur;
5633 return (cur);
5634 }
5635 if (doc->oldNs == NULL) {
5636 /*
5637 * Allocate a new Namespace and fill the fields.
5638 */
5639 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5640 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005641 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005642 return (NULL);
5643 }
5644 memset(doc->oldNs, 0, sizeof(xmlNs));
5645 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005646
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005647 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5648 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5649 }
5650 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005651 }
Daniel Veillard62040be2004-05-17 03:17:26 +00005652 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00005653 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005654 if ((node->type == XML_ENTITY_REF_NODE) ||
5655 (node->type == XML_ENTITY_NODE) ||
5656 (node->type == XML_ENTITY_DECL))
5657 return (NULL);
5658 if (node->type == XML_ELEMENT_NODE) {
5659 cur = node->nsDef;
5660 while (cur != NULL) {
5661 if ((cur->href != NULL) && (href != NULL) &&
5662 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005663 if (((!is_attr) || (cur->prefix != NULL)) &&
5664 (xmlNsInScope(doc, orig, node, cur->href) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005665 return (cur);
5666 }
5667 cur = cur->next;
5668 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005669 if (orig != node) {
5670 cur = node->ns;
5671 if (cur != NULL) {
5672 if ((cur->href != NULL) && (href != NULL) &&
5673 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005674 if (((!is_attr) || (cur->prefix != NULL)) &&
5675 (xmlNsInScope(doc, orig, node, cur->href) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00005676 return (cur);
5677 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005678 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005679 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005680 }
5681 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005682 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005683 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005684}
5685
5686/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005687 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005688 * @doc: the document
5689 * @tree: a node expected to hold the new namespace
5690 * @ns: the original namespace
5691 *
5692 * This function tries to locate a namespace definition in a tree
5693 * ancestors, or create a new namespace definition node similar to
5694 * @ns trying to reuse the same prefix. However if the given prefix is
5695 * null (default namespace) or reused within the subtree defined by
5696 * @tree or on one of its ancestors then a new prefix is generated.
5697 * Returns the (new) namespace definition or NULL in case of error
5698 */
5699xmlNsPtr
5700xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5701 xmlNsPtr def;
5702 xmlChar prefix[50];
5703 int counter = 1;
5704
5705 if (tree == NULL) {
5706#ifdef DEBUG_TREE
5707 xmlGenericError(xmlGenericErrorContext,
5708 "xmlNewReconciliedNs : tree == NULL\n");
5709#endif
5710 return(NULL);
5711 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00005712 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005713#ifdef DEBUG_TREE
5714 xmlGenericError(xmlGenericErrorContext,
5715 "xmlNewReconciliedNs : ns == NULL\n");
5716#endif
5717 return(NULL);
5718 }
5719 /*
5720 * Search an existing namespace definition inherited.
5721 */
5722 def = xmlSearchNsByHref(doc, tree, ns->href);
5723 if (def != NULL)
5724 return(def);
5725
5726 /*
5727 * Find a close prefix which is not already in use.
5728 * Let's strip namespace prefixes longer than 20 chars !
5729 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005730 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005731 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005732 else
William M. Brack13dfa872004-09-18 04:52:08 +00005733 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005734
Owen Taylor3473f882001-02-23 17:55:21 +00005735 def = xmlSearchNs(doc, tree, prefix);
5736 while (def != NULL) {
5737 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005738 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005739 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005740 else
William M. Brack13dfa872004-09-18 04:52:08 +00005741 snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
5742 (char *)ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005743 def = xmlSearchNs(doc, tree, prefix);
5744 }
5745
5746 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005747 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005748 */
5749 def = xmlNewNs(tree, ns->href, prefix);
5750 return(def);
5751}
5752
Daniel Veillard652327a2003-09-29 18:02:38 +00005753#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005754/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005755 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005756 * @doc: the document
5757 * @tree: a node defining the subtree to reconciliate
5758 *
5759 * This function checks that all the namespaces declared within the given
5760 * tree are properly declared. This is needed for example after Copy or Cut
5761 * and then paste operations. The subtree may still hold pointers to
5762 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005763 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005764 * the new environment. If not possible the new namespaces are redeclared
5765 * on @tree at the top of the given subtree.
5766 * Returns the number of namespace declarations created or -1 in case of error.
5767 */
5768int
5769xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5770 xmlNsPtr *oldNs = NULL;
5771 xmlNsPtr *newNs = NULL;
5772 int sizeCache = 0;
5773 int nbCache = 0;
5774
5775 xmlNsPtr n;
5776 xmlNodePtr node = tree;
5777 xmlAttrPtr attr;
5778 int ret = 0, i;
5779
Daniel Veillardce244ad2004-11-05 10:03:46 +00005780 if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1);
5781 if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1);
5782 if (node->doc != doc) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005783 while (node != NULL) {
5784 /*
5785 * Reconciliate the node namespace
5786 */
5787 if (node->ns != NULL) {
5788 /*
5789 * initialize the cache if needed
5790 */
5791 if (sizeCache == 0) {
5792 sizeCache = 10;
5793 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5794 sizeof(xmlNsPtr));
5795 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005796 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005797 return(-1);
5798 }
5799 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5800 sizeof(xmlNsPtr));
5801 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005802 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005803 xmlFree(oldNs);
5804 return(-1);
5805 }
5806 }
5807 for (i = 0;i < nbCache;i++) {
5808 if (oldNs[i] == node->ns) {
5809 node->ns = newNs[i];
5810 break;
5811 }
5812 }
5813 if (i == nbCache) {
5814 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005815 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005816 */
5817 n = xmlNewReconciliedNs(doc, tree, node->ns);
5818 if (n != NULL) { /* :-( what if else ??? */
5819 /*
5820 * check if we need to grow the cache buffers.
5821 */
5822 if (sizeCache <= nbCache) {
5823 sizeCache *= 2;
5824 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5825 sizeof(xmlNsPtr));
5826 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005827 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005828 xmlFree(newNs);
5829 return(-1);
5830 }
5831 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5832 sizeof(xmlNsPtr));
5833 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005834 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005835 xmlFree(oldNs);
5836 return(-1);
5837 }
5838 }
5839 newNs[nbCache] = n;
5840 oldNs[nbCache++] = node->ns;
5841 node->ns = n;
5842 }
5843 }
5844 }
5845 /*
5846 * now check for namespace hold by attributes on the node.
5847 */
5848 attr = node->properties;
5849 while (attr != NULL) {
5850 if (attr->ns != NULL) {
5851 /*
5852 * initialize the cache if needed
5853 */
5854 if (sizeCache == 0) {
5855 sizeCache = 10;
5856 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5857 sizeof(xmlNsPtr));
5858 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005859 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005860 return(-1);
5861 }
5862 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5863 sizeof(xmlNsPtr));
5864 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005865 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005866 xmlFree(oldNs);
5867 return(-1);
5868 }
5869 }
5870 for (i = 0;i < nbCache;i++) {
5871 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005872 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005873 break;
5874 }
5875 }
5876 if (i == nbCache) {
5877 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005878 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005879 */
5880 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5881 if (n != NULL) { /* :-( what if else ??? */
5882 /*
5883 * check if we need to grow the cache buffers.
5884 */
5885 if (sizeCache <= nbCache) {
5886 sizeCache *= 2;
5887 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5888 sizeof(xmlNsPtr));
5889 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005890 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005891 xmlFree(newNs);
5892 return(-1);
5893 }
5894 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5895 sizeof(xmlNsPtr));
5896 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005897 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005898 xmlFree(oldNs);
5899 return(-1);
5900 }
5901 }
5902 newNs[nbCache] = n;
5903 oldNs[nbCache++] = attr->ns;
5904 attr->ns = n;
5905 }
5906 }
5907 }
5908 attr = attr->next;
5909 }
5910
5911 /*
5912 * Browse the full subtree, deep first
5913 */
Daniel Veillardac996a12004-07-30 12:02:58 +00005914 if (node->children != NULL && node->type != XML_ENTITY_REF_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00005915 /* deep first */
5916 node = node->children;
5917 } else if ((node != tree) && (node->next != NULL)) {
5918 /* then siblings */
5919 node = node->next;
5920 } else if (node != tree) {
5921 /* go up to parents->next if needed */
5922 while (node != tree) {
5923 if (node->parent != NULL)
5924 node = node->parent;
5925 if ((node != tree) && (node->next != NULL)) {
5926 node = node->next;
5927 break;
5928 }
5929 if (node->parent == NULL) {
5930 node = NULL;
5931 break;
5932 }
5933 }
5934 /* exit condition */
5935 if (node == tree)
5936 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005937 } else
5938 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005939 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005940 if (oldNs != NULL)
5941 xmlFree(oldNs);
5942 if (newNs != NULL)
5943 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005944 return(ret);
5945}
Daniel Veillard652327a2003-09-29 18:02:38 +00005946#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005947
5948/**
5949 * xmlHasProp:
5950 * @node: the node
5951 * @name: the attribute name
5952 *
5953 * Search an attribute associated to a node
5954 * This function also looks in DTD attribute declaration for #FIXED or
5955 * default declaration values unless DTD use has been turned off.
5956 *
5957 * Returns the attribute or the attribute declaration or NULL if
5958 * neither was found.
5959 */
5960xmlAttrPtr
5961xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5962 xmlAttrPtr prop;
5963 xmlDocPtr doc;
5964
5965 if ((node == NULL) || (name == NULL)) return(NULL);
5966 /*
5967 * Check on the properties attached to the node
5968 */
5969 prop = node->properties;
5970 while (prop != NULL) {
5971 if (xmlStrEqual(prop->name, name)) {
5972 return(prop);
5973 }
5974 prop = prop->next;
5975 }
5976 if (!xmlCheckDTD) return(NULL);
5977
5978 /*
5979 * Check if there is a default declaration in the internal
5980 * or external subsets
5981 */
5982 doc = node->doc;
5983 if (doc != NULL) {
5984 xmlAttributePtr attrDecl;
5985 if (doc->intSubset != NULL) {
5986 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5987 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5988 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005989 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5990 /* return attribute declaration only if a default value is given
5991 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005992 return((xmlAttrPtr) attrDecl);
5993 }
5994 }
5995 return(NULL);
5996}
5997
5998/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005999 * xmlHasNsProp:
6000 * @node: the node
6001 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006002 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00006003 *
6004 * Search for an attribute associated to a node
6005 * This attribute has to be anchored in the namespace specified.
6006 * This does the entity substitution.
6007 * This function looks in DTD attribute declaration for #FIXED or
6008 * default declaration values unless DTD use has been turned off.
William M. Brack2c228442004-10-03 04:10:00 +00006009 * Note that a namespace of NULL indicates to use the default namespace.
Daniel Veillarde95e2392001-06-06 10:46:28 +00006010 *
6011 * Returns the attribute or the attribute declaration or NULL
6012 * if neither was found.
6013 */
6014xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00006015xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00006016 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00006017#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00006018 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00006019#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00006020
6021 if (node == NULL)
6022 return(NULL);
6023
6024 prop = node->properties;
Daniel Veillarde95e2392001-06-06 10:46:28 +00006025 while (prop != NULL) {
6026 /*
6027 * One need to have
6028 * - same attribute names
6029 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00006030 */
William M. Brack2c228442004-10-03 04:10:00 +00006031 if (xmlStrEqual(prop->name, name)) {
6032 if (((prop->ns != NULL) &&
6033 (xmlStrEqual(prop->ns->href, nameSpace))) ||
6034 ((prop->ns == NULL) && (nameSpace == NULL))) {
6035 return(prop);
6036 }
Daniel Veillarde95e2392001-06-06 10:46:28 +00006037 }
6038 prop = prop->next;
6039 }
6040 if (!xmlCheckDTD) return(NULL);
6041
Daniel Veillard652327a2003-09-29 18:02:38 +00006042#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00006043 /*
6044 * Check if there is a default declaration in the internal
6045 * or external subsets
6046 */
6047 doc = node->doc;
6048 if (doc != NULL) {
6049 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006050 xmlAttributePtr attrDecl = NULL;
6051 xmlNsPtr *nsList, *cur;
6052 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00006053
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006054 nsList = xmlGetNsList(node->doc, node);
6055 if (nsList == NULL)
6056 return(NULL);
6057 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
6058 ename = xmlStrdup(node->ns->prefix);
6059 ename = xmlStrcat(ename, BAD_CAST ":");
6060 ename = xmlStrcat(ename, node->name);
6061 } else {
6062 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006063 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006064 if (ename == NULL) {
6065 xmlFree(nsList);
6066 return(NULL);
6067 }
6068
William M. Brack2c228442004-10-03 04:10:00 +00006069 if (nameSpace == NULL) {
6070 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
6071 name, NULL);
6072 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
6073 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6074 name, NULL);
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006075 }
William M. Brack2c228442004-10-03 04:10:00 +00006076 } else {
6077 cur = nsList;
6078 while (*cur != NULL) {
6079 if (xmlStrEqual((*cur)->href, nameSpace)) {
6080 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
6081 name, (*cur)->prefix);
6082 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6083 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6084 name, (*cur)->prefix);
6085 }
6086 cur++;
6087 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006088 }
6089 xmlFree(nsList);
6090 xmlFree(ename);
6091 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006092 }
6093 }
Daniel Veillard652327a2003-09-29 18:02:38 +00006094#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00006095 return(NULL);
6096}
6097
6098/**
Owen Taylor3473f882001-02-23 17:55:21 +00006099 * xmlGetProp:
6100 * @node: the node
6101 * @name: the attribute name
6102 *
6103 * Search and get the value of an attribute associated to a node
6104 * This does the entity substitution.
6105 * This function looks in DTD attribute declaration for #FIXED or
6106 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00006107 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00006108 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6109 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00006110 *
6111 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006112 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006113 */
6114xmlChar *
6115xmlGetProp(xmlNodePtr node, const xmlChar *name) {
6116 xmlAttrPtr prop;
6117 xmlDocPtr doc;
6118
6119 if ((node == NULL) || (name == NULL)) return(NULL);
6120 /*
6121 * Check on the properties attached to the node
6122 */
6123 prop = node->properties;
6124 while (prop != NULL) {
6125 if (xmlStrEqual(prop->name, name)) {
6126 xmlChar *ret;
6127
6128 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6129 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6130 return(ret);
6131 }
6132 prop = prop->next;
6133 }
6134 if (!xmlCheckDTD) return(NULL);
6135
6136 /*
6137 * Check if there is a default declaration in the internal
6138 * or external subsets
6139 */
6140 doc = node->doc;
6141 if (doc != NULL) {
6142 xmlAttributePtr attrDecl;
6143 if (doc->intSubset != NULL) {
6144 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6145 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6146 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006147 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6148 /* return attribute declaration only if a default value is given
6149 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006150 return(xmlStrdup(attrDecl->defaultValue));
6151 }
6152 }
6153 return(NULL);
6154}
6155
6156/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006157 * xmlGetNoNsProp:
6158 * @node: the node
6159 * @name: the attribute name
6160 *
6161 * Search and get the value of an attribute associated to a node
6162 * This does the entity substitution.
6163 * This function looks in DTD attribute declaration for #FIXED or
6164 * default declaration values unless DTD use has been turned off.
6165 * This function is similar to xmlGetProp except it will accept only
6166 * an attribute in no namespace.
6167 *
6168 * Returns the attribute value or NULL if not found.
6169 * It's up to the caller to free the memory with xmlFree().
6170 */
6171xmlChar *
6172xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6173 xmlAttrPtr prop;
6174 xmlDocPtr doc;
6175
6176 if ((node == NULL) || (name == NULL)) return(NULL);
6177 /*
6178 * Check on the properties attached to the node
6179 */
6180 prop = node->properties;
6181 while (prop != NULL) {
6182 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6183 xmlChar *ret;
6184
6185 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6186 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6187 return(ret);
6188 }
6189 prop = prop->next;
6190 }
6191 if (!xmlCheckDTD) return(NULL);
6192
6193 /*
6194 * Check if there is a default declaration in the internal
6195 * or external subsets
6196 */
6197 doc = node->doc;
6198 if (doc != NULL) {
6199 xmlAttributePtr attrDecl;
6200 if (doc->intSubset != NULL) {
6201 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6202 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6203 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006204 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6205 /* return attribute declaration only if a default value is given
6206 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006207 return(xmlStrdup(attrDecl->defaultValue));
6208 }
6209 }
6210 return(NULL);
6211}
6212
6213/**
Owen Taylor3473f882001-02-23 17:55:21 +00006214 * xmlGetNsProp:
6215 * @node: the node
6216 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006217 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006218 *
6219 * Search and get the value of an attribute associated to a node
6220 * This attribute has to be anchored in the namespace specified.
6221 * This does the entity substitution.
6222 * This function looks in DTD attribute declaration for #FIXED or
6223 * default declaration values unless DTD use has been turned off.
6224 *
6225 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006226 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006227 */
6228xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006229xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006230 xmlAttrPtr prop;
6231 xmlDocPtr doc;
6232 xmlNsPtr ns;
6233
6234 if (node == NULL)
6235 return(NULL);
6236
6237 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006238 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006239 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006240 while (prop != NULL) {
6241 /*
6242 * One need to have
6243 * - same attribute names
6244 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006245 */
6246 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006247 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006248 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006249 xmlChar *ret;
6250
6251 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6252 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6253 return(ret);
6254 }
6255 prop = prop->next;
6256 }
6257 if (!xmlCheckDTD) return(NULL);
6258
6259 /*
6260 * Check if there is a default declaration in the internal
6261 * or external subsets
6262 */
6263 doc = node->doc;
6264 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006265 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006266 xmlAttributePtr attrDecl;
6267
Owen Taylor3473f882001-02-23 17:55:21 +00006268 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6269 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6270 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6271
6272 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6273 /*
6274 * The DTD declaration only allows a prefix search
6275 */
6276 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006277 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006278 return(xmlStrdup(attrDecl->defaultValue));
6279 }
6280 }
6281 }
6282 return(NULL);
6283}
6284
Daniel Veillard2156d432004-03-04 15:59:36 +00006285#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6286/**
6287 * xmlUnsetProp:
6288 * @node: the node
6289 * @name: the attribute name
6290 *
6291 * Remove an attribute carried by a node.
6292 * Returns 0 if successful, -1 if not found
6293 */
6294int
6295xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
6296 xmlAttrPtr prop, prev = NULL;;
6297
6298 if ((node == NULL) || (name == NULL))
6299 return(-1);
6300 prop = node->properties;
6301 while (prop != NULL) {
6302 if ((xmlStrEqual(prop->name, name)) &&
6303 (prop->ns == NULL)) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006304 if (prev == NULL) {
Daniel Veillard2156d432004-03-04 15:59:36 +00006305 node->properties = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006306 if (prop->next != NULL)
6307 prop->next->prev = NULL;
6308 } else {
Daniel Veillard2156d432004-03-04 15:59:36 +00006309 prev->next = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006310 if (prop->next != NULL)
6311 prop->next->prev = NULL;
6312 }
6313 prop->next = NULL;
6314 prop->prev = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00006315 xmlFreeProp(prop);
6316 return(0);
6317 }
6318 prev = prop;
6319 prop = prop->next;
6320 }
6321 return(-1);
6322}
6323
6324/**
6325 * xmlUnsetNsProp:
6326 * @node: the node
6327 * @ns: the namespace definition
6328 * @name: the attribute name
6329 *
6330 * Remove an attribute carried by a node.
6331 * Returns 0 if successful, -1 if not found
6332 */
6333int
6334xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
Daniel Veillard27f20102004-11-05 11:50:11 +00006335 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard2156d432004-03-04 15:59:36 +00006336
6337 if ((node == NULL) || (name == NULL))
6338 return(-1);
Daniel Veillard27f20102004-11-05 11:50:11 +00006339 prop = node->properties;
Daniel Veillard2156d432004-03-04 15:59:36 +00006340 if (ns == NULL)
6341 return(xmlUnsetProp(node, name));
6342 if (ns->href == NULL)
6343 return(-1);
6344 while (prop != NULL) {
6345 if ((xmlStrEqual(prop->name, name)) &&
6346 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006347 if (prev == NULL) {
Daniel Veillard2156d432004-03-04 15:59:36 +00006348 node->properties = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006349 if (prop->next != NULL)
6350 prop->next->prev = NULL;
6351 } else {
Daniel Veillard2156d432004-03-04 15:59:36 +00006352 prev->next = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006353 if (prop->next != NULL)
6354 prop->next->prev = NULL;
6355 }
6356 prop->next = NULL;
6357 prop->prev = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00006358 xmlFreeProp(prop);
6359 return(0);
6360 }
6361 prev = prop;
6362 prop = prop->next;
6363 }
6364 return(-1);
6365}
6366#endif
6367
6368#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006369/**
6370 * xmlSetProp:
6371 * @node: the node
6372 * @name: the attribute name
6373 * @value: the attribute value
6374 *
6375 * Set (or reset) an attribute carried by a node.
6376 * Returns the attribute pointer.
6377 */
6378xmlAttrPtr
6379xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006380 xmlAttrPtr prop;
6381 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006382
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006383 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006384 return(NULL);
6385 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006386 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006387 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006388 if ((xmlStrEqual(prop->name, name)) &&
6389 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006390 xmlNodePtr oldprop = prop->children;
6391
Owen Taylor3473f882001-02-23 17:55:21 +00006392 prop->children = NULL;
6393 prop->last = NULL;
6394 if (value != NULL) {
6395 xmlChar *buffer;
6396 xmlNodePtr tmp;
6397
6398 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6399 prop->children = xmlStringGetNodeList(node->doc, buffer);
6400 prop->last = NULL;
6401 prop->doc = doc;
6402 tmp = prop->children;
6403 while (tmp != NULL) {
6404 tmp->parent = (xmlNodePtr) prop;
6405 tmp->doc = doc;
6406 if (tmp->next == NULL)
6407 prop->last = tmp;
6408 tmp = tmp->next;
6409 }
6410 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006411 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006412 if (oldprop != NULL)
6413 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006414 return(prop);
6415 }
6416 prop = prop->next;
6417 }
6418 prop = xmlNewProp(node, name, value);
6419 return(prop);
6420}
6421
6422/**
6423 * xmlSetNsProp:
6424 * @node: the node
6425 * @ns: the namespace definition
6426 * @name: the attribute name
6427 * @value: the attribute value
6428 *
6429 * Set (or reset) an attribute carried by a node.
6430 * The ns structure must be in scope, this is not checked.
6431 *
6432 * Returns the attribute pointer.
6433 */
6434xmlAttrPtr
6435xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6436 const xmlChar *value) {
6437 xmlAttrPtr prop;
6438
6439 if ((node == NULL) || (name == NULL))
6440 return(NULL);
6441
6442 if (ns == NULL)
6443 return(xmlSetProp(node, name, value));
6444 if (ns->href == NULL)
6445 return(NULL);
6446 prop = node->properties;
6447
6448 while (prop != NULL) {
6449 /*
6450 * One need to have
6451 * - same attribute names
6452 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006453 */
6454 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006455 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006456 if (prop->children != NULL)
6457 xmlFreeNodeList(prop->children);
6458 prop->children = NULL;
6459 prop->last = NULL;
6460 prop->ns = ns;
6461 if (value != NULL) {
6462 xmlChar *buffer;
6463 xmlNodePtr tmp;
6464
6465 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6466 prop->children = xmlStringGetNodeList(node->doc, buffer);
6467 prop->last = NULL;
6468 tmp = prop->children;
6469 while (tmp != NULL) {
6470 tmp->parent = (xmlNodePtr) prop;
6471 if (tmp->next == NULL)
6472 prop->last = tmp;
6473 tmp = tmp->next;
6474 }
6475 xmlFree(buffer);
6476 }
6477 return(prop);
6478 }
6479 prop = prop->next;
6480 }
6481 prop = xmlNewNsProp(node, ns, name, value);
6482 return(prop);
6483}
6484
Daniel Veillard652327a2003-09-29 18:02:38 +00006485#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006486
6487/**
Owen Taylor3473f882001-02-23 17:55:21 +00006488 * xmlNodeIsText:
6489 * @node: the node
6490 *
6491 * Is this node a Text node ?
6492 * Returns 1 yes, 0 no
6493 */
6494int
6495xmlNodeIsText(xmlNodePtr node) {
6496 if (node == NULL) return(0);
6497
6498 if (node->type == XML_TEXT_NODE) return(1);
6499 return(0);
6500}
6501
6502/**
6503 * xmlIsBlankNode:
6504 * @node: the node
6505 *
6506 * Checks whether this node is an empty or whitespace only
6507 * (and possibly ignorable) text-node.
6508 *
6509 * Returns 1 yes, 0 no
6510 */
6511int
6512xmlIsBlankNode(xmlNodePtr node) {
6513 const xmlChar *cur;
6514 if (node == NULL) return(0);
6515
Daniel Veillard7db37732001-07-12 01:20:08 +00006516 if ((node->type != XML_TEXT_NODE) &&
6517 (node->type != XML_CDATA_SECTION_NODE))
6518 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006519 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006520 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006521 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006522 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006523 cur++;
6524 }
6525
6526 return(1);
6527}
6528
6529/**
6530 * xmlTextConcat:
6531 * @node: the node
6532 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006533 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006534 *
6535 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006536 *
6537 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006538 */
6539
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006540int
Owen Taylor3473f882001-02-23 17:55:21 +00006541xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006542 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006543
6544 if ((node->type != XML_TEXT_NODE) &&
6545 (node->type != XML_CDATA_SECTION_NODE)) {
6546#ifdef DEBUG_TREE
6547 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006548 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006549#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006550 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006551 }
William M. Brack7762bb12004-01-04 14:49:01 +00006552 /* need to check if content is currently in the dictionary */
6553 if ((node->doc != NULL) && (node->doc->dict != NULL) &&
6554 xmlDictOwns(node->doc->dict, node->content)) {
6555 node->content = xmlStrncatNew(node->content, content, len);
6556 } else {
6557 node->content = xmlStrncat(node->content, content, len);
6558 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006559 if (node->content == NULL)
6560 return(-1);
6561 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006562}
6563
6564/************************************************************************
6565 * *
6566 * Output : to a FILE or in memory *
6567 * *
6568 ************************************************************************/
6569
Owen Taylor3473f882001-02-23 17:55:21 +00006570/**
6571 * xmlBufferCreate:
6572 *
6573 * routine to create an XML buffer.
6574 * returns the new structure.
6575 */
6576xmlBufferPtr
6577xmlBufferCreate(void) {
6578 xmlBufferPtr ret;
6579
6580 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6581 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006582 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006583 return(NULL);
6584 }
6585 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006586 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006587 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006588 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006589 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006590 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006591 xmlFree(ret);
6592 return(NULL);
6593 }
6594 ret->content[0] = 0;
6595 return(ret);
6596}
6597
6598/**
6599 * xmlBufferCreateSize:
6600 * @size: initial size of buffer
6601 *
6602 * routine to create an XML buffer.
6603 * returns the new structure.
6604 */
6605xmlBufferPtr
6606xmlBufferCreateSize(size_t size) {
6607 xmlBufferPtr ret;
6608
6609 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6610 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006611 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006612 return(NULL);
6613 }
6614 ret->use = 0;
6615 ret->alloc = xmlBufferAllocScheme;
6616 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6617 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006618 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006619 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006620 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006621 xmlFree(ret);
6622 return(NULL);
6623 }
6624 ret->content[0] = 0;
6625 } else
6626 ret->content = NULL;
6627 return(ret);
6628}
6629
6630/**
Daniel Veillard53350552003-09-18 13:35:51 +00006631 * xmlBufferCreateStatic:
6632 * @mem: the memory area
6633 * @size: the size in byte
6634 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006635 * routine to create an XML buffer from an immutable memory area.
6636 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006637 * present until the end of the buffer lifetime.
6638 *
6639 * returns the new structure.
6640 */
6641xmlBufferPtr
6642xmlBufferCreateStatic(void *mem, size_t size) {
6643 xmlBufferPtr ret;
6644
6645 if ((mem == NULL) || (size == 0))
6646 return(NULL);
6647
6648 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6649 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006650 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006651 return(NULL);
6652 }
6653 ret->use = size;
6654 ret->size = size;
6655 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6656 ret->content = (xmlChar *) mem;
6657 return(ret);
6658}
6659
6660/**
Owen Taylor3473f882001-02-23 17:55:21 +00006661 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006662 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006663 * @scheme: allocation scheme to use
6664 *
6665 * Sets the allocation scheme for this buffer
6666 */
6667void
6668xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6669 xmlBufferAllocationScheme scheme) {
6670 if (buf == NULL) {
6671#ifdef DEBUG_BUFFER
6672 xmlGenericError(xmlGenericErrorContext,
6673 "xmlBufferSetAllocationScheme: buf == NULL\n");
6674#endif
6675 return;
6676 }
Daniel Veillard53350552003-09-18 13:35:51 +00006677 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006678
6679 buf->alloc = scheme;
6680}
6681
6682/**
6683 * xmlBufferFree:
6684 * @buf: the buffer to free
6685 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006686 * Frees an XML buffer. It frees both the content and the structure which
6687 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006688 */
6689void
6690xmlBufferFree(xmlBufferPtr buf) {
6691 if (buf == NULL) {
6692#ifdef DEBUG_BUFFER
6693 xmlGenericError(xmlGenericErrorContext,
6694 "xmlBufferFree: buf == NULL\n");
6695#endif
6696 return;
6697 }
Daniel Veillard53350552003-09-18 13:35:51 +00006698
6699 if ((buf->content != NULL) &&
6700 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006701 xmlFree(buf->content);
6702 }
Owen Taylor3473f882001-02-23 17:55:21 +00006703 xmlFree(buf);
6704}
6705
6706/**
6707 * xmlBufferEmpty:
6708 * @buf: the buffer
6709 *
6710 * empty a buffer.
6711 */
6712void
6713xmlBufferEmpty(xmlBufferPtr buf) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006714 if (buf == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006715 if (buf->content == NULL) return;
6716 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006717 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006718 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006719 } else {
6720 memset(buf->content, 0, buf->size);
6721 }
Owen Taylor3473f882001-02-23 17:55:21 +00006722}
6723
6724/**
6725 * xmlBufferShrink:
6726 * @buf: the buffer to dump
6727 * @len: the number of xmlChar to remove
6728 *
6729 * Remove the beginning of an XML buffer.
6730 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006731 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006732 */
6733int
6734xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
Daniel Veillard3d97e662004-11-04 10:49:00 +00006735 if (buf == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006736 if (len == 0) return(0);
6737 if (len > buf->use) return(-1);
6738
6739 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006740 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6741 buf->content += len;
6742 } else {
6743 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6744 buf->content[buf->use] = 0;
6745 }
Owen Taylor3473f882001-02-23 17:55:21 +00006746 return(len);
6747}
6748
6749/**
6750 * xmlBufferGrow:
6751 * @buf: the buffer
6752 * @len: the minimum free size to allocate
6753 *
6754 * Grow the available space of an XML buffer.
6755 *
6756 * Returns the new available space or -1 in case of error
6757 */
6758int
6759xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6760 int size;
6761 xmlChar *newbuf;
6762
Daniel Veillard3d97e662004-11-04 10:49:00 +00006763 if (buf == NULL) return(-1);
6764
Daniel Veillard53350552003-09-18 13:35:51 +00006765 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006766 if (len + buf->use < buf->size) return(0);
6767
William M. Brack30fe43f2004-07-26 18:00:58 +00006768/*
6769 * Windows has a BIG problem on realloc timing, so we try to double
6770 * the buffer size (if that's enough) (bug 146697)
6771 */
6772#ifdef WIN32
6773 if (buf->size > len)
6774 size = buf->size * 2;
6775 else
6776 size = buf->use + len + 100;
6777#else
Owen Taylor3473f882001-02-23 17:55:21 +00006778 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00006779#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006780
6781 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006782 if (newbuf == NULL) {
6783 xmlTreeErrMemory("growing buffer");
6784 return(-1);
6785 }
Owen Taylor3473f882001-02-23 17:55:21 +00006786 buf->content = newbuf;
6787 buf->size = size;
6788 return(buf->size - buf->use);
6789}
6790
6791/**
6792 * xmlBufferDump:
6793 * @file: the file output
6794 * @buf: the buffer to dump
6795 *
6796 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006797 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006798 */
6799int
6800xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6801 int ret;
6802
6803 if (buf == NULL) {
6804#ifdef DEBUG_BUFFER
6805 xmlGenericError(xmlGenericErrorContext,
6806 "xmlBufferDump: buf == NULL\n");
6807#endif
6808 return(0);
6809 }
6810 if (buf->content == NULL) {
6811#ifdef DEBUG_BUFFER
6812 xmlGenericError(xmlGenericErrorContext,
6813 "xmlBufferDump: buf->content == NULL\n");
6814#endif
6815 return(0);
6816 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006817 if (file == NULL)
6818 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006819 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6820 return(ret);
6821}
6822
6823/**
6824 * xmlBufferContent:
6825 * @buf: the buffer
6826 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006827 * Function to extract the content of a buffer
6828 *
Owen Taylor3473f882001-02-23 17:55:21 +00006829 * Returns the internal content
6830 */
6831
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006832const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006833xmlBufferContent(const xmlBufferPtr buf)
6834{
6835 if(!buf)
6836 return NULL;
6837
6838 return buf->content;
6839}
6840
6841/**
6842 * xmlBufferLength:
6843 * @buf: the buffer
6844 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006845 * Function to get the length of a buffer
6846 *
Owen Taylor3473f882001-02-23 17:55:21 +00006847 * Returns the length of data in the internal content
6848 */
6849
6850int
6851xmlBufferLength(const xmlBufferPtr buf)
6852{
6853 if(!buf)
6854 return 0;
6855
6856 return buf->use;
6857}
6858
6859/**
6860 * xmlBufferResize:
6861 * @buf: the buffer to resize
6862 * @size: the desired size
6863 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006864 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006865 *
6866 * Returns 0 in case of problems, 1 otherwise
6867 */
6868int
6869xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6870{
6871 unsigned int newSize;
6872 xmlChar* rebuf = NULL;
6873
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006874 if (buf == NULL)
6875 return(0);
6876
Daniel Veillard53350552003-09-18 13:35:51 +00006877 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6878
Owen Taylor3473f882001-02-23 17:55:21 +00006879 /* Don't resize if we don't have to */
6880 if (size < buf->size)
6881 return 1;
6882
6883 /* figure out new size */
6884 switch (buf->alloc){
6885 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillardbf629492004-04-20 22:20:59 +00006886 /*take care of empty case*/
6887 newSize = (buf->size ? buf->size*2 : size + 10);
Owen Taylor3473f882001-02-23 17:55:21 +00006888 while (size > newSize) newSize *= 2;
6889 break;
6890 case XML_BUFFER_ALLOC_EXACT:
6891 newSize = size+10;
6892 break;
6893 default:
6894 newSize = size+10;
6895 break;
6896 }
6897
6898 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006899 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006900 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006901 rebuf = (xmlChar *) xmlRealloc(buf->content,
6902 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006903 } else {
6904 /*
6905 * if we are reallocating a buffer far from being full, it's
6906 * better to make a new allocation and copy only the used range
6907 * and free the old one.
6908 */
6909 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6910 if (rebuf != NULL) {
6911 memcpy(rebuf, buf->content, buf->use);
6912 xmlFree(buf->content);
William M. Brack42331a92004-07-29 07:07:16 +00006913 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006914 }
6915 }
Owen Taylor3473f882001-02-23 17:55:21 +00006916 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006917 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006918 return 0;
6919 }
6920 buf->content = rebuf;
6921 buf->size = newSize;
6922
6923 return 1;
6924}
6925
6926/**
6927 * xmlBufferAdd:
6928 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006929 * @str: the #xmlChar string
6930 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006931 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006932 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006933 * str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006934 *
6935 * Returns 0 successful, a positive error code number otherwise
6936 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006937 */
William M. Bracka3215c72004-07-31 16:24:01 +00006938int
Owen Taylor3473f882001-02-23 17:55:21 +00006939xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6940 unsigned int needSize;
6941
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006942 if ((str == NULL) || (buf == NULL)) {
William M. Bracka3215c72004-07-31 16:24:01 +00006943 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006944 }
William M. Bracka3215c72004-07-31 16:24:01 +00006945 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006946 if (len < -1) {
6947#ifdef DEBUG_BUFFER
6948 xmlGenericError(xmlGenericErrorContext,
6949 "xmlBufferAdd: len < 0\n");
6950#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006951 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006952 }
William M. Bracka3215c72004-07-31 16:24:01 +00006953 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006954
6955 if (len < 0)
6956 len = xmlStrlen(str);
6957
William M. Bracka3215c72004-07-31 16:24:01 +00006958 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006959
6960 needSize = buf->use + len + 2;
6961 if (needSize > buf->size){
6962 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006963 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006964 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006965 }
6966 }
6967
6968 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6969 buf->use += len;
6970 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006971 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006972}
6973
6974/**
6975 * xmlBufferAddHead:
6976 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006977 * @str: the #xmlChar string
6978 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006979 *
6980 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006981 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006982 *
6983 * Returns 0 successful, a positive error code number otherwise
6984 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006985 */
William M. Bracka3215c72004-07-31 16:24:01 +00006986int
Owen Taylor3473f882001-02-23 17:55:21 +00006987xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6988 unsigned int needSize;
6989
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006990 if (buf == NULL)
6991 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00006992 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006993 if (str == NULL) {
6994#ifdef DEBUG_BUFFER
6995 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006996 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006997#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006998 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006999 }
7000 if (len < -1) {
7001#ifdef DEBUG_BUFFER
7002 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007003 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007004#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007005 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007006 }
William M. Bracka3215c72004-07-31 16:24:01 +00007007 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007008
7009 if (len < 0)
7010 len = xmlStrlen(str);
7011
William M. Bracka3215c72004-07-31 16:24:01 +00007012 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007013
7014 needSize = buf->use + len + 2;
7015 if (needSize > buf->size){
7016 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007017 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007018 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007019 }
7020 }
7021
7022 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
7023 memmove(&buf->content[0], str, len * sizeof(xmlChar));
7024 buf->use += len;
7025 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007026 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007027}
7028
7029/**
7030 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00007031 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00007032 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00007033 *
7034 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007035 *
7036 * Returns 0 successful, a positive error code number otherwise
7037 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007038 */
William M. Bracka3215c72004-07-31 16:24:01 +00007039int
Owen Taylor3473f882001-02-23 17:55:21 +00007040xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007041 if (buf == NULL)
7042 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007043 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
7044 if (str == NULL) return -1;
7045 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00007046}
7047
7048/**
7049 * xmlBufferCCat:
7050 * @buf: the buffer to dump
7051 * @str: the C char string
7052 *
7053 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007054 *
7055 * Returns 0 successful, a positive error code number otherwise
7056 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007057 */
William M. Bracka3215c72004-07-31 16:24:01 +00007058int
Owen Taylor3473f882001-02-23 17:55:21 +00007059xmlBufferCCat(xmlBufferPtr buf, const char *str) {
7060 const char *cur;
7061
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007062 if (buf == NULL)
7063 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007064 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007065 if (str == NULL) {
7066#ifdef DEBUG_BUFFER
7067 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007068 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007069#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007070 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007071 }
7072 for (cur = str;*cur != 0;cur++) {
7073 if (buf->use + 10 >= buf->size) {
7074 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007075 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007076 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007077 }
7078 }
7079 buf->content[buf->use++] = *cur;
7080 }
7081 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007082 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007083}
7084
7085/**
7086 * xmlBufferWriteCHAR:
7087 * @buf: the XML buffer
7088 * @string: the string to add
7089 *
7090 * routine which manages and grows an output buffer. This one adds
7091 * xmlChars at the end of the buffer.
7092 */
7093void
Daniel Veillard53350552003-09-18 13:35:51 +00007094xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007095 if (buf == NULL)
7096 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007097 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007098 xmlBufferCat(buf, string);
7099}
7100
7101/**
7102 * xmlBufferWriteChar:
7103 * @buf: the XML buffer output
7104 * @string: the string to add
7105 *
7106 * routine which manage and grows an output buffer. This one add
7107 * C chars at the end of the array.
7108 */
7109void
7110xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007111 if (buf == NULL)
7112 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007113 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007114 xmlBufferCCat(buf, string);
7115}
7116
7117
7118/**
7119 * xmlBufferWriteQuotedString:
7120 * @buf: the XML buffer output
7121 * @string: the string to add
7122 *
7123 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00007124 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00007125 * quote or double-quotes internally
7126 */
7127void
7128xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00007129 const xmlChar *cur, *base;
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007130 if (buf == NULL)
7131 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007132 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00007133 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00007134 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00007135#ifdef DEBUG_BUFFER
7136 xmlGenericError(xmlGenericErrorContext,
7137 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7138#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00007139 xmlBufferCCat(buf, "\"");
7140 base = cur = string;
7141 while(*cur != 0){
7142 if(*cur == '"'){
7143 if (base != cur)
7144 xmlBufferAdd(buf, base, cur - base);
7145 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7146 cur++;
7147 base = cur;
7148 }
7149 else {
7150 cur++;
7151 }
7152 }
7153 if (base != cur)
7154 xmlBufferAdd(buf, base, cur - base);
7155 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007156 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007157 else{
7158 xmlBufferCCat(buf, "\'");
7159 xmlBufferCat(buf, string);
7160 xmlBufferCCat(buf, "\'");
7161 }
Owen Taylor3473f882001-02-23 17:55:21 +00007162 } else {
7163 xmlBufferCCat(buf, "\"");
7164 xmlBufferCat(buf, string);
7165 xmlBufferCCat(buf, "\"");
7166 }
7167}
7168
7169
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007170/**
7171 * xmlGetDocCompressMode:
7172 * @doc: the document
7173 *
7174 * get the compression ratio for a document, ZLIB based
7175 * Returns 0 (uncompressed) to 9 (max compression)
7176 */
7177int
7178xmlGetDocCompressMode (xmlDocPtr doc) {
7179 if (doc == NULL) return(-1);
7180 return(doc->compression);
7181}
7182
7183/**
7184 * xmlSetDocCompressMode:
7185 * @doc: the document
7186 * @mode: the compression ratio
7187 *
7188 * set the compression ratio for a document, ZLIB based
7189 * Correct values: 0 (uncompressed) to 9 (max compression)
7190 */
7191void
7192xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7193 if (doc == NULL) return;
7194 if (mode < 0) doc->compression = 0;
7195 else if (mode > 9) doc->compression = 9;
7196 else doc->compression = mode;
7197}
7198
7199/**
7200 * xmlGetCompressMode:
7201 *
7202 * get the default compression mode used, ZLIB based.
7203 * Returns 0 (uncompressed) to 9 (max compression)
7204 */
7205int
7206xmlGetCompressMode(void)
7207{
7208 return (xmlCompressMode);
7209}
7210
7211/**
7212 * xmlSetCompressMode:
7213 * @mode: the compression ratio
7214 *
7215 * set the default compression mode used, ZLIB based
7216 * Correct values: 0 (uncompressed) to 9 (max compression)
7217 */
7218void
7219xmlSetCompressMode(int mode) {
7220 if (mode < 0) xmlCompressMode = 0;
7221 else if (mode > 9) xmlCompressMode = 9;
7222 else xmlCompressMode = mode;
7223}
7224