blob: d382e29226dcd350aeae381873eb39f613b5a056 [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
Kasimier T. Buchcik44353412006-03-06 13:26:16 +0000122#define IS_STR_XML(str) ((str != NULL) && (str[0] == 'x') && \
123 (str[1] == 'm') && (str[2] == 'l') && (str[3] == 0))
124
Owen Taylor3473f882001-02-23 17:55:21 +0000125/* #define DEBUG_BUFFER */
126/* #define DEBUG_TREE */
127
128/************************************************************************
129 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000130 * Functions to move to entities.c once the *
131 * API freeze is smoothen and they can be made public. *
132 * *
133 ************************************************************************/
134#include <libxml/hash.h>
135
Daniel Veillard652327a2003-09-29 18:02:38 +0000136#ifdef LIBXML_TREE_ENABLED
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000137/**
138 * xmlGetEntityFromDtd:
139 * @dtd: A pointer to the DTD to search
140 * @name: The entity name
141 *
142 * Do an entity lookup in the DTD entity hash table and
143 * return the corresponding entity, if found.
144 *
145 * Returns A pointer to the entity structure or NULL if not found.
146 */
147static xmlEntityPtr
148xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
149 xmlEntitiesTablePtr table;
150
151 if((dtd != NULL) && (dtd->entities != NULL)) {
152 table = (xmlEntitiesTablePtr) dtd->entities;
153 return((xmlEntityPtr) xmlHashLookup(table, name));
154 /* return(xmlGetEntityFromTable(table, name)); */
155 }
156 return(NULL);
157}
158/**
159 * xmlGetParameterEntityFromDtd:
160 * @dtd: A pointer to the DTD to search
161 * @name: The entity name
162 *
163 * Do an entity lookup in the DTD pararmeter entity hash table and
164 * return the corresponding entity, if found.
165 *
166 * Returns A pointer to the entity structure or NULL if not found.
167 */
168static xmlEntityPtr
169xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
170 xmlEntitiesTablePtr table;
171
172 if ((dtd != NULL) && (dtd->pentities != NULL)) {
173 table = (xmlEntitiesTablePtr) dtd->pentities;
174 return((xmlEntityPtr) xmlHashLookup(table, name));
175 /* return(xmlGetEntityFromTable(table, name)); */
176 }
177 return(NULL);
178}
Daniel Veillard652327a2003-09-29 18:02:38 +0000179#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000180
181/************************************************************************
182 * *
Daniel Veillardc00cda82003-04-07 10:22:39 +0000183 * QName handling helper *
184 * *
185 ************************************************************************/
186
187/**
188 * xmlBuildQName:
189 * @ncname: the Name
190 * @prefix: the prefix
191 * @memory: preallocated memory
192 * @len: preallocated memory length
193 *
194 * Builds the QName @prefix:@ncname in @memory if there is enough space
195 * and prefix is not NULL nor empty, otherwise allocate a new string.
196 * If prefix is NULL or empty it returns ncname.
197 *
198 * Returns the new string which must be freed by the caller if different from
199 * @memory and @ncname or NULL in case of error
200 */
201xmlChar *
202xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
203 xmlChar *memory, int len) {
204 int lenn, lenp;
205 xmlChar *ret;
206
Daniel Veillard3b7840c2003-09-11 23:42:01 +0000207 if (ncname == NULL) return(NULL);
208 if (prefix == NULL) return((xmlChar *) ncname);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000209
210 lenn = strlen((char *) ncname);
211 lenp = strlen((char *) prefix);
212
213 if ((memory == NULL) || (len < lenn + lenp + 2)) {
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000214 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000215 if (ret == NULL) {
216 xmlTreeErrMemory("building QName");
217 return(NULL);
218 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000219 } else {
220 ret = memory;
221 }
222 memcpy(&ret[0], prefix, lenp);
223 ret[lenp] = ':';
224 memcpy(&ret[lenp + 1], ncname, lenn);
225 ret[lenn + lenp + 1] = 0;
226 return(ret);
227}
228
229/**
230 * xmlSplitQName2:
231 * @name: the full QName
232 * @prefix: a xmlChar **
233 *
234 * parse an XML qualified name string
235 *
236 * [NS 5] QName ::= (Prefix ':')? LocalPart
237 *
238 * [NS 6] Prefix ::= NCName
239 *
240 * [NS 7] LocalPart ::= NCName
241 *
242 * Returns NULL if not a QName, otherwise the local part, and prefix
243 * is updated to get the Prefix if any.
244 */
245
246xmlChar *
247xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
248 int len = 0;
249 xmlChar *ret = NULL;
250
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000251 if (prefix == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000252 *prefix = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000253 if (name == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000254
255#ifndef XML_XML_NAMESPACE
256 /* xml: prefix is not really a namespace */
257 if ((name[0] == 'x') && (name[1] == 'm') &&
258 (name[2] == 'l') && (name[3] == ':'))
259 return(NULL);
260#endif
261
262 /* nasty but valid */
263 if (name[0] == ':')
264 return(NULL);
265
266 /*
267 * we are not trying to validate but just to cut, and yes it will
268 * work even if this is as set of UTF-8 encoded chars
269 */
270 while ((name[len] != 0) && (name[len] != ':'))
271 len++;
272
273 if (name[len] == 0)
274 return(NULL);
275
276 *prefix = xmlStrndup(name, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000277 if (*prefix == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000278 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000279 return(NULL);
280 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000281 ret = xmlStrdup(&name[len + 1]);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000282 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000283 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000284 if (*prefix != NULL) {
285 xmlFree(*prefix);
286 *prefix = NULL;
287 }
288 return(NULL);
289 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000290
291 return(ret);
292}
293
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000294/**
295 * xmlSplitQName3:
296 * @name: the full QName
297 * @len: an int *
298 *
299 * parse an XML qualified name string,i
300 *
301 * returns NULL if it is not a Qualified Name, otherwise, update len
302 * with the lenght in byte of the prefix and return a pointer
Daniel Veillard54f9a4f2005-09-03 13:28:24 +0000303 * to the start of the name without the prefix
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000304 */
305
306const xmlChar *
307xmlSplitQName3(const xmlChar *name, int *len) {
308 int l = 0;
309
310 if (name == NULL) return(NULL);
311 if (len == NULL) return(NULL);
312
313 /* nasty but valid */
314 if (name[0] == ':')
315 return(NULL);
316
317 /*
318 * we are not trying to validate but just to cut, and yes it will
319 * work even if this is as set of UTF-8 encoded chars
320 */
321 while ((name[l] != 0) && (name[l] != ':'))
322 l++;
323
324 if (name[l] == 0)
325 return(NULL);
326
327 *len = l;
328
329 return(&name[l+1]);
330}
331
Daniel Veillardc00cda82003-04-07 10:22:39 +0000332/************************************************************************
333 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000334 * Check Name, NCName and QName strings *
335 * *
336 ************************************************************************/
337
338#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
339
Daniel Veillard6b6d6802005-07-03 21:00:34 +0000340#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED) || defined (LIBXML_HTML_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000341/**
342 * xmlValidateNCName:
343 * @value: the value to check
344 * @space: allow spaces in front and end of the string
345 *
346 * Check that a value conforms to the lexical space of NCName
347 *
348 * Returns 0 if this validates, a positive error code number otherwise
349 * and -1 in case of internal or API error.
350 */
351int
352xmlValidateNCName(const xmlChar *value, int space) {
353 const xmlChar *cur = value;
354 int c,l;
355
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000356 if (value == NULL)
357 return(-1);
358
Daniel Veillardd2298792003-02-14 16:54:11 +0000359 /*
360 * First quick algorithm for ASCII range
361 */
362 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000363 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000364 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
365 (*cur == '_'))
366 cur++;
367 else
368 goto try_complex;
369 while (((*cur >= 'a') && (*cur <= 'z')) ||
370 ((*cur >= 'A') && (*cur <= 'Z')) ||
371 ((*cur >= '0') && (*cur <= '9')) ||
372 (*cur == '_') || (*cur == '-') || (*cur == '.'))
373 cur++;
374 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000375 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000376 if (*cur == 0)
377 return(0);
378
379try_complex:
380 /*
381 * Second check for chars outside the ASCII range
382 */
383 cur = value;
384 c = CUR_SCHAR(cur, l);
385 if (space) {
386 while (IS_BLANK(c)) {
387 cur += l;
388 c = CUR_SCHAR(cur, l);
389 }
390 }
William M. Brack871611b2003-10-18 04:53:14 +0000391 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000392 return(1);
393 cur += l;
394 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000395 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
396 (c == '-') || (c == '_') || IS_COMBINING(c) ||
397 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000398 cur += l;
399 c = CUR_SCHAR(cur, l);
400 }
401 if (space) {
402 while (IS_BLANK(c)) {
403 cur += l;
404 c = CUR_SCHAR(cur, l);
405 }
406 }
407 if (c != 0)
408 return(1);
409
410 return(0);
411}
Daniel Veillard2156d432004-03-04 15:59:36 +0000412#endif
Daniel Veillardd2298792003-02-14 16:54:11 +0000413
Daniel Veillard2156d432004-03-04 15:59:36 +0000414#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000415/**
416 * xmlValidateQName:
417 * @value: the value to check
418 * @space: allow spaces in front and end of the string
419 *
420 * Check that a value conforms to the lexical space of QName
421 *
422 * Returns 0 if this validates, a positive error code number otherwise
423 * and -1 in case of internal or API error.
424 */
425int
426xmlValidateQName(const xmlChar *value, int space) {
427 const xmlChar *cur = value;
428 int c,l;
429
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000430 if (value == NULL)
431 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +0000432 /*
433 * First quick algorithm for ASCII range
434 */
435 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000436 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000437 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
438 (*cur == '_'))
439 cur++;
440 else
441 goto try_complex;
442 while (((*cur >= 'a') && (*cur <= 'z')) ||
443 ((*cur >= 'A') && (*cur <= 'Z')) ||
444 ((*cur >= '0') && (*cur <= '9')) ||
445 (*cur == '_') || (*cur == '-') || (*cur == '.'))
446 cur++;
447 if (*cur == ':') {
448 cur++;
449 if (((*cur >= 'a') && (*cur <= 'z')) ||
450 ((*cur >= 'A') && (*cur <= 'Z')) ||
451 (*cur == '_'))
452 cur++;
453 else
454 goto try_complex;
455 while (((*cur >= 'a') && (*cur <= 'z')) ||
456 ((*cur >= 'A') && (*cur <= 'Z')) ||
457 ((*cur >= '0') && (*cur <= '9')) ||
458 (*cur == '_') || (*cur == '-') || (*cur == '.'))
459 cur++;
460 }
461 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000462 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000463 if (*cur == 0)
464 return(0);
465
466try_complex:
467 /*
468 * Second check for chars outside the ASCII range
469 */
470 cur = value;
471 c = CUR_SCHAR(cur, l);
472 if (space) {
473 while (IS_BLANK(c)) {
474 cur += l;
475 c = CUR_SCHAR(cur, l);
476 }
477 }
William M. Brack871611b2003-10-18 04:53:14 +0000478 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000479 return(1);
480 cur += l;
481 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000482 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
483 (c == '-') || (c == '_') || IS_COMBINING(c) ||
484 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000485 cur += l;
486 c = CUR_SCHAR(cur, l);
487 }
488 if (c == ':') {
489 cur += l;
490 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000491 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000492 return(1);
493 cur += l;
494 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000495 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
496 (c == '-') || (c == '_') || IS_COMBINING(c) ||
497 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000498 cur += l;
499 c = CUR_SCHAR(cur, l);
500 }
501 }
502 if (space) {
503 while (IS_BLANK(c)) {
504 cur += l;
505 c = CUR_SCHAR(cur, l);
506 }
507 }
508 if (c != 0)
509 return(1);
510 return(0);
511}
512
513/**
514 * xmlValidateName:
515 * @value: the value to check
516 * @space: allow spaces in front and end of the string
517 *
518 * Check that a value conforms to the lexical space of Name
519 *
520 * Returns 0 if this validates, a positive error code number otherwise
521 * and -1 in case of internal or API error.
522 */
523int
524xmlValidateName(const xmlChar *value, int space) {
525 const xmlChar *cur = value;
526 int c,l;
527
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000528 if (value == NULL)
529 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +0000530 /*
531 * First quick algorithm for ASCII range
532 */
533 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000534 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000535 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
536 (*cur == '_') || (*cur == ':'))
537 cur++;
538 else
539 goto try_complex;
540 while (((*cur >= 'a') && (*cur <= 'z')) ||
541 ((*cur >= 'A') && (*cur <= 'Z')) ||
542 ((*cur >= '0') && (*cur <= '9')) ||
543 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
544 cur++;
545 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000546 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000547 if (*cur == 0)
548 return(0);
549
550try_complex:
551 /*
552 * Second check for chars outside the ASCII range
553 */
554 cur = value;
555 c = CUR_SCHAR(cur, l);
556 if (space) {
557 while (IS_BLANK(c)) {
558 cur += l;
559 c = CUR_SCHAR(cur, l);
560 }
561 }
William M. Brack871611b2003-10-18 04:53:14 +0000562 if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000563 return(1);
564 cur += l;
565 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000566 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
567 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000568 cur += l;
569 c = CUR_SCHAR(cur, l);
570 }
571 if (space) {
572 while (IS_BLANK(c)) {
573 cur += l;
574 c = CUR_SCHAR(cur, l);
575 }
576 }
577 if (c != 0)
578 return(1);
579 return(0);
580}
581
Daniel Veillardd4310742003-02-18 21:12:46 +0000582/**
583 * xmlValidateNMToken:
584 * @value: the value to check
585 * @space: allow spaces in front and end of the string
586 *
587 * Check that a value conforms to the lexical space of NMToken
588 *
589 * Returns 0 if this validates, a positive error code number otherwise
590 * and -1 in case of internal or API error.
591 */
592int
593xmlValidateNMToken(const xmlChar *value, int space) {
594 const xmlChar *cur = value;
595 int c,l;
596
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000597 if (value == NULL)
598 return(-1);
Daniel Veillardd4310742003-02-18 21:12:46 +0000599 /*
600 * First quick algorithm for ASCII range
601 */
602 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000603 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000604 if (((*cur >= 'a') && (*cur <= 'z')) ||
605 ((*cur >= 'A') && (*cur <= 'Z')) ||
606 ((*cur >= '0') && (*cur <= '9')) ||
607 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
608 cur++;
609 else
610 goto try_complex;
611 while (((*cur >= 'a') && (*cur <= 'z')) ||
612 ((*cur >= 'A') && (*cur <= 'Z')) ||
613 ((*cur >= '0') && (*cur <= '9')) ||
614 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
615 cur++;
616 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000617 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000618 if (*cur == 0)
619 return(0);
620
621try_complex:
622 /*
623 * Second check for chars outside the ASCII range
624 */
625 cur = value;
626 c = CUR_SCHAR(cur, l);
627 if (space) {
628 while (IS_BLANK(c)) {
629 cur += l;
630 c = CUR_SCHAR(cur, l);
631 }
632 }
William M. Brack871611b2003-10-18 04:53:14 +0000633 if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
634 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
Daniel Veillardd4310742003-02-18 21:12:46 +0000635 return(1);
636 cur += l;
637 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000638 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
639 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd4310742003-02-18 21:12:46 +0000640 cur += l;
641 c = CUR_SCHAR(cur, l);
642 }
643 if (space) {
644 while (IS_BLANK(c)) {
645 cur += l;
646 c = CUR_SCHAR(cur, l);
647 }
648 }
649 if (c != 0)
650 return(1);
651 return(0);
652}
Daniel Veillard652327a2003-09-29 18:02:38 +0000653#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardd4310742003-02-18 21:12:46 +0000654
Daniel Veillardd2298792003-02-14 16:54:11 +0000655/************************************************************************
656 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000657 * Allocation and deallocation of basic structures *
658 * *
659 ************************************************************************/
660
661/**
662 * xmlSetBufferAllocationScheme:
663 * @scheme: allocation method to use
664 *
665 * Set the buffer allocation method. Types are
666 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
667 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
668 * improves performance
669 */
670void
671xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
672 xmlBufferAllocScheme = scheme;
673}
674
675/**
676 * xmlGetBufferAllocationScheme:
677 *
678 * Types are
679 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
680 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
681 * improves performance
682 *
683 * Returns the current allocation scheme
684 */
685xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000686xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000687 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000688}
689
690/**
691 * xmlNewNs:
692 * @node: the element carrying the namespace
693 * @href: the URI associated
694 * @prefix: the prefix for the namespace
695 *
696 * Creation of a new Namespace. This function will refuse to create
697 * a namespace with a similar prefix than an existing one present on this
698 * node.
699 * We use href==NULL in the case of an element creation where the namespace
700 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000701 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000702 */
703xmlNsPtr
704xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
705 xmlNsPtr cur;
706
707 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
708 return(NULL);
709
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000710 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
711 return(NULL);
712
Owen Taylor3473f882001-02-23 17:55:21 +0000713 /*
714 * Allocate a new Namespace and fill the fields.
715 */
716 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
717 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000718 xmlTreeErrMemory("building namespace");
Owen Taylor3473f882001-02-23 17:55:21 +0000719 return(NULL);
720 }
721 memset(cur, 0, sizeof(xmlNs));
722 cur->type = XML_LOCAL_NAMESPACE;
723
724 if (href != NULL)
725 cur->href = xmlStrdup(href);
726 if (prefix != NULL)
727 cur->prefix = xmlStrdup(prefix);
728
729 /*
730 * Add it at the end to preserve parsing order ...
731 * and checks for existing use of the prefix
732 */
733 if (node != NULL) {
734 if (node->nsDef == NULL) {
735 node->nsDef = cur;
736 } else {
737 xmlNsPtr prev = node->nsDef;
738
739 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
740 (xmlStrEqual(prev->prefix, cur->prefix))) {
741 xmlFreeNs(cur);
742 return(NULL);
743 }
744 while (prev->next != NULL) {
745 prev = prev->next;
746 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
747 (xmlStrEqual(prev->prefix, cur->prefix))) {
748 xmlFreeNs(cur);
749 return(NULL);
750 }
751 }
752 prev->next = cur;
753 }
754 }
755 return(cur);
756}
757
758/**
759 * xmlSetNs:
760 * @node: a node in the document
761 * @ns: a namespace pointer
762 *
763 * Associate a namespace to a node, a posteriori.
764 */
765void
766xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
767 if (node == NULL) {
768#ifdef DEBUG_TREE
769 xmlGenericError(xmlGenericErrorContext,
770 "xmlSetNs: node == NULL\n");
771#endif
772 return;
773 }
774 node->ns = ns;
775}
776
777/**
778 * xmlFreeNs:
779 * @cur: the namespace pointer
780 *
781 * Free up the structures associated to a namespace
782 */
783void
784xmlFreeNs(xmlNsPtr cur) {
785 if (cur == NULL) {
786#ifdef DEBUG_TREE
787 xmlGenericError(xmlGenericErrorContext,
788 "xmlFreeNs : ns == NULL\n");
789#endif
790 return;
791 }
792 if (cur->href != NULL) xmlFree((char *) cur->href);
793 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000794 xmlFree(cur);
795}
796
797/**
798 * xmlFreeNsList:
799 * @cur: the first namespace pointer
800 *
801 * Free up all the structures associated to the chained namespaces.
802 */
803void
804xmlFreeNsList(xmlNsPtr cur) {
805 xmlNsPtr next;
806 if (cur == NULL) {
807#ifdef DEBUG_TREE
808 xmlGenericError(xmlGenericErrorContext,
809 "xmlFreeNsList : ns == NULL\n");
810#endif
811 return;
812 }
813 while (cur != NULL) {
814 next = cur->next;
815 xmlFreeNs(cur);
816 cur = next;
817 }
818}
819
820/**
821 * xmlNewDtd:
822 * @doc: the document pointer
823 * @name: the DTD name
824 * @ExternalID: the external ID
825 * @SystemID: the system ID
826 *
827 * Creation of a new DTD for the external subset. To create an
828 * internal subset, use xmlCreateIntSubset().
829 *
830 * Returns a pointer to the new DTD structure
831 */
832xmlDtdPtr
833xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
834 const xmlChar *ExternalID, const xmlChar *SystemID) {
835 xmlDtdPtr cur;
836
837 if ((doc != NULL) && (doc->extSubset != NULL)) {
838#ifdef DEBUG_TREE
839 xmlGenericError(xmlGenericErrorContext,
840 "xmlNewDtd(%s): document %s already have a DTD %s\n",
841 /* !!! */ (char *) name, doc->name,
842 /* !!! */ (char *)doc->extSubset->name);
843#endif
844 return(NULL);
845 }
846
847 /*
848 * Allocate a new DTD and fill the fields.
849 */
850 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
851 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000852 xmlTreeErrMemory("building DTD");
Owen Taylor3473f882001-02-23 17:55:21 +0000853 return(NULL);
854 }
855 memset(cur, 0 , sizeof(xmlDtd));
856 cur->type = XML_DTD_NODE;
857
858 if (name != NULL)
859 cur->name = xmlStrdup(name);
860 if (ExternalID != NULL)
861 cur->ExternalID = xmlStrdup(ExternalID);
862 if (SystemID != NULL)
863 cur->SystemID = xmlStrdup(SystemID);
864 if (doc != NULL)
865 doc->extSubset = cur;
866 cur->doc = doc;
867
Daniel Veillarda880b122003-04-21 21:36:41 +0000868 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000869 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000870 return(cur);
871}
872
873/**
874 * xmlGetIntSubset:
875 * @doc: the document pointer
876 *
877 * Get the internal subset of a document
878 * Returns a pointer to the DTD structure or NULL if not found
879 */
880
881xmlDtdPtr
882xmlGetIntSubset(xmlDocPtr doc) {
883 xmlNodePtr cur;
884
885 if (doc == NULL)
886 return(NULL);
887 cur = doc->children;
888 while (cur != NULL) {
889 if (cur->type == XML_DTD_NODE)
890 return((xmlDtdPtr) cur);
891 cur = cur->next;
892 }
893 return((xmlDtdPtr) doc->intSubset);
894}
895
896/**
897 * xmlCreateIntSubset:
898 * @doc: the document pointer
899 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000900 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000901 * @SystemID: the system ID
902 *
903 * Create the internal subset of a document
904 * Returns a pointer to the new DTD structure
905 */
906xmlDtdPtr
907xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
908 const xmlChar *ExternalID, const xmlChar *SystemID) {
909 xmlDtdPtr cur;
910
911 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
912#ifdef DEBUG_TREE
913 xmlGenericError(xmlGenericErrorContext,
914
915 "xmlCreateIntSubset(): document %s already have an internal subset\n",
916 doc->name);
917#endif
918 return(NULL);
919 }
920
921 /*
922 * Allocate a new DTD and fill the fields.
923 */
924 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
925 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000926 xmlTreeErrMemory("building internal subset");
Owen Taylor3473f882001-02-23 17:55:21 +0000927 return(NULL);
928 }
929 memset(cur, 0, sizeof(xmlDtd));
930 cur->type = XML_DTD_NODE;
931
William M. Bracka3215c72004-07-31 16:24:01 +0000932 if (name != NULL) {
933 cur->name = xmlStrdup(name);
934 if (cur->name == NULL) {
935 xmlTreeErrMemory("building internal subset");
936 xmlFree(cur);
937 return(NULL);
938 }
939 }
940 if (ExternalID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000941 cur->ExternalID = xmlStrdup(ExternalID);
William M. Bracka3215c72004-07-31 16:24:01 +0000942 if (cur->ExternalID == NULL) {
943 xmlTreeErrMemory("building internal subset");
944 if (cur->name != NULL)
945 xmlFree((char *)cur->name);
946 xmlFree(cur);
947 return(NULL);
948 }
949 }
950 if (SystemID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000951 cur->SystemID = xmlStrdup(SystemID);
William M. Bracka3215c72004-07-31 16:24:01 +0000952 if (cur->SystemID == NULL) {
953 xmlTreeErrMemory("building internal subset");
954 if (cur->name != NULL)
955 xmlFree((char *)cur->name);
956 if (cur->ExternalID != NULL)
957 xmlFree((char *)cur->ExternalID);
958 xmlFree(cur);
959 return(NULL);
960 }
961 }
Owen Taylor3473f882001-02-23 17:55:21 +0000962 if (doc != NULL) {
963 doc->intSubset = cur;
964 cur->parent = doc;
965 cur->doc = doc;
966 if (doc->children == NULL) {
967 doc->children = (xmlNodePtr) cur;
968 doc->last = (xmlNodePtr) cur;
969 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000970 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000971 xmlNodePtr prev;
972
Owen Taylor3473f882001-02-23 17:55:21 +0000973 prev = doc->children;
974 prev->prev = (xmlNodePtr) cur;
975 cur->next = prev;
976 doc->children = (xmlNodePtr) cur;
977 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000978 xmlNodePtr next;
979
980 next = doc->children;
981 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
982 next = next->next;
983 if (next == NULL) {
984 cur->prev = doc->last;
985 cur->prev->next = (xmlNodePtr) cur;
986 cur->next = NULL;
987 doc->last = (xmlNodePtr) cur;
988 } else {
989 cur->next = next;
990 cur->prev = next->prev;
991 if (cur->prev == NULL)
992 doc->children = (xmlNodePtr) cur;
993 else
994 cur->prev->next = (xmlNodePtr) cur;
995 next->prev = (xmlNodePtr) cur;
996 }
Owen Taylor3473f882001-02-23 17:55:21 +0000997 }
998 }
999 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001000
Daniel Veillarda880b122003-04-21 21:36:41 +00001001 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001002 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001003 return(cur);
1004}
1005
1006/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001007 * DICT_FREE:
1008 * @str: a string
1009 *
1010 * Free a string if it is not owned by the "dict" dictionnary in the
1011 * current scope
1012 */
1013#define DICT_FREE(str) \
1014 if ((str) && ((!dict) || \
1015 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
1016 xmlFree((char *)(str));
1017
1018/**
Owen Taylor3473f882001-02-23 17:55:21 +00001019 * xmlFreeDtd:
1020 * @cur: the DTD structure to free up
1021 *
1022 * Free a DTD structure.
1023 */
1024void
1025xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001026 xmlDictPtr dict = NULL;
1027
Owen Taylor3473f882001-02-23 17:55:21 +00001028 if (cur == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001029 return;
1030 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001031 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001032
Daniel Veillarda880b122003-04-21 21:36:41 +00001033 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001034 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1035
Owen Taylor3473f882001-02-23 17:55:21 +00001036 if (cur->children != NULL) {
1037 xmlNodePtr next, c = cur->children;
1038
1039 /*
William M. Brack18a04f22004-08-03 16:42:37 +00001040 * Cleanup all nodes which are not part of the specific lists
1041 * of notations, elements, attributes and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00001042 */
1043 while (c != NULL) {
1044 next = c->next;
William M. Brack18a04f22004-08-03 16:42:37 +00001045 if ((c->type != XML_NOTATION_NODE) &&
1046 (c->type != XML_ELEMENT_DECL) &&
1047 (c->type != XML_ATTRIBUTE_DECL) &&
1048 (c->type != XML_ENTITY_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001049 xmlUnlinkNode(c);
1050 xmlFreeNode(c);
1051 }
1052 c = next;
1053 }
1054 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001055 DICT_FREE(cur->name)
1056 DICT_FREE(cur->SystemID)
1057 DICT_FREE(cur->ExternalID)
Owen Taylor3473f882001-02-23 17:55:21 +00001058 /* TODO !!! */
1059 if (cur->notations != NULL)
1060 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1061
1062 if (cur->elements != NULL)
1063 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1064 if (cur->attributes != NULL)
1065 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1066 if (cur->entities != NULL)
1067 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1068 if (cur->pentities != NULL)
1069 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1070
Owen Taylor3473f882001-02-23 17:55:21 +00001071 xmlFree(cur);
1072}
1073
1074/**
1075 * xmlNewDoc:
1076 * @version: xmlChar string giving the version of XML "1.0"
1077 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001078 * Creates a new XML document
1079 *
Owen Taylor3473f882001-02-23 17:55:21 +00001080 * Returns a new document
1081 */
1082xmlDocPtr
1083xmlNewDoc(const xmlChar *version) {
1084 xmlDocPtr cur;
1085
1086 if (version == NULL)
1087 version = (const xmlChar *) "1.0";
1088
1089 /*
1090 * Allocate a new document and fill the fields.
1091 */
1092 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1093 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001094 xmlTreeErrMemory("building doc");
Owen Taylor3473f882001-02-23 17:55:21 +00001095 return(NULL);
1096 }
1097 memset(cur, 0, sizeof(xmlDoc));
1098 cur->type = XML_DOCUMENT_NODE;
1099
1100 cur->version = xmlStrdup(version);
William M. Bracka3215c72004-07-31 16:24:01 +00001101 if (cur->version == NULL) {
1102 xmlTreeErrMemory("building doc");
1103 xmlFree(cur);
1104 return(NULL);
1105 }
Owen Taylor3473f882001-02-23 17:55:21 +00001106 cur->standalone = -1;
1107 cur->compression = -1; /* not initialized */
1108 cur->doc = cur;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001109 /*
1110 * The in memory encoding is always UTF8
1111 * This field will never change and would
1112 * be obsolete if not for binary compatibility.
1113 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001114 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001115
Daniel Veillarda880b122003-04-21 21:36:41 +00001116 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001117 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001118 return(cur);
1119}
1120
1121/**
1122 * xmlFreeDoc:
1123 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001124 *
1125 * Free up all the structures used by a document, tree included.
1126 */
1127void
1128xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001129 xmlDtdPtr extSubset, intSubset;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001130 xmlDictPtr dict = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001131
Owen Taylor3473f882001-02-23 17:55:21 +00001132 if (cur == NULL) {
1133#ifdef DEBUG_TREE
1134 xmlGenericError(xmlGenericErrorContext,
1135 "xmlFreeDoc : document == NULL\n");
1136#endif
1137 return;
1138 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001139#ifdef LIBXML_DEBUG_RUNTIME
Daniel Veillardbca3ad22005-08-23 22:14:02 +00001140#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001141 xmlDebugCheckDocument(stderr, cur);
1142#endif
Daniel Veillardbca3ad22005-08-23 22:14:02 +00001143#endif
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001144
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001145 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001146
Daniel Veillarda880b122003-04-21 21:36:41 +00001147 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001148 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1149
Daniel Veillard76d66f42001-05-16 21:05:17 +00001150 /*
1151 * Do this before freeing the children list to avoid ID lookups
1152 */
1153 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1154 cur->ids = NULL;
1155 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1156 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001157 extSubset = cur->extSubset;
1158 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001159 if (intSubset == extSubset)
1160 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001161 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001162 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001163 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001164 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001165 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001166 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001167 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001168 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001169 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001170 }
1171
1172 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001173 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001174
1175 DICT_FREE(cur->version)
1176 DICT_FREE(cur->name)
1177 DICT_FREE(cur->encoding)
1178 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001179 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001180 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001181}
1182
1183/**
1184 * xmlStringLenGetNodeList:
1185 * @doc: the document
1186 * @value: the value of the text
1187 * @len: the length of the string value
1188 *
1189 * Parse the value string and build the node list associated. Should
1190 * produce a flat tree with only TEXTs and ENTITY_REFs.
1191 * Returns a pointer to the first child
1192 */
1193xmlNodePtr
1194xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1195 xmlNodePtr ret = NULL, last = NULL;
1196 xmlNodePtr node;
1197 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001198 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001199 const xmlChar *q;
1200 xmlEntityPtr ent;
1201
1202 if (value == NULL) return(NULL);
1203
1204 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001205 while ((cur < end) && (*cur != 0)) {
1206 if (cur[0] == '&') {
1207 int charval = 0;
1208 xmlChar tmp;
1209
Owen Taylor3473f882001-02-23 17:55:21 +00001210 /*
1211 * Save the current text.
1212 */
1213 if (cur != q) {
1214 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1215 xmlNodeAddContentLen(last, q, cur - q);
1216 } else {
1217 node = xmlNewDocTextLen(doc, q, cur - q);
1218 if (node == NULL) return(ret);
1219 if (last == NULL)
1220 last = ret = node;
1221 else {
1222 last->next = node;
1223 node->prev = last;
1224 last = node;
1225 }
1226 }
1227 }
Owen Taylor3473f882001-02-23 17:55:21 +00001228 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001229 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1230 cur += 3;
1231 if (cur < end)
1232 tmp = *cur;
1233 else
1234 tmp = 0;
1235 while (tmp != ';') { /* Non input consuming loop */
1236 if ((tmp >= '0') && (tmp <= '9'))
1237 charval = charval * 16 + (tmp - '0');
1238 else if ((tmp >= 'a') && (tmp <= 'f'))
1239 charval = charval * 16 + (tmp - 'a') + 10;
1240 else if ((tmp >= 'A') && (tmp <= 'F'))
1241 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001242 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001243 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1244 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001245 charval = 0;
1246 break;
1247 }
1248 cur++;
1249 if (cur < end)
1250 tmp = *cur;
1251 else
1252 tmp = 0;
1253 }
1254 if (tmp == ';')
1255 cur++;
1256 q = cur;
1257 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1258 cur += 2;
1259 if (cur < end)
1260 tmp = *cur;
1261 else
1262 tmp = 0;
1263 while (tmp != ';') { /* Non input consuming loops */
1264 if ((tmp >= '0') && (tmp <= '9'))
1265 charval = charval * 10 + (tmp - '0');
1266 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001267 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1268 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001269 charval = 0;
1270 break;
1271 }
1272 cur++;
1273 if (cur < end)
1274 tmp = *cur;
1275 else
1276 tmp = 0;
1277 }
1278 if (tmp == ';')
1279 cur++;
1280 q = cur;
1281 } else {
1282 /*
1283 * Read the entity string
1284 */
1285 cur++;
1286 q = cur;
1287 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1288 if ((cur >= end) || (*cur == 0)) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001289 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1290 (const char *) q);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001291 return(ret);
1292 }
1293 if (cur != q) {
1294 /*
1295 * Predefined entities don't generate nodes
1296 */
1297 val = xmlStrndup(q, cur - q);
1298 ent = xmlGetDocEntity(doc, val);
1299 if ((ent != NULL) &&
1300 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1301 if (last == NULL) {
1302 node = xmlNewDocText(doc, ent->content);
1303 last = ret = node;
1304 } else if (last->type != XML_TEXT_NODE) {
1305 node = xmlNewDocText(doc, ent->content);
1306 last = xmlAddNextSibling(last, node);
1307 } else
1308 xmlNodeAddContent(last, ent->content);
1309
1310 } else {
1311 /*
1312 * Create a new REFERENCE_REF node
1313 */
1314 node = xmlNewReference(doc, val);
1315 if (node == NULL) {
1316 if (val != NULL) xmlFree(val);
1317 return(ret);
1318 }
1319 else if ((ent != NULL) && (ent->children == NULL)) {
1320 xmlNodePtr temp;
1321
1322 ent->children = xmlStringGetNodeList(doc,
1323 (const xmlChar*)node->content);
1324 ent->owner = 1;
1325 temp = ent->children;
1326 while (temp) {
1327 temp->parent = (xmlNodePtr)ent;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001328 ent->last = temp;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001329 temp = temp->next;
1330 }
1331 }
1332 if (last == NULL) {
1333 last = ret = node;
1334 } else {
1335 last = xmlAddNextSibling(last, node);
1336 }
1337 }
1338 xmlFree(val);
1339 }
1340 cur++;
1341 q = cur;
1342 }
1343 if (charval != 0) {
1344 xmlChar buf[10];
1345 int l;
1346
1347 l = xmlCopyCharMultiByte(buf, charval);
1348 buf[l] = 0;
1349 node = xmlNewDocText(doc, buf);
1350 if (node != NULL) {
1351 if (last == NULL) {
1352 last = ret = node;
1353 } else {
1354 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001355 }
1356 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001357 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001358 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001359 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001360 cur++;
1361 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001362 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001363 /*
1364 * Handle the last piece of text.
1365 */
1366 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1367 xmlNodeAddContentLen(last, q, cur - q);
1368 } else {
1369 node = xmlNewDocTextLen(doc, q, cur - q);
1370 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001371 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001372 last = ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001373 } else {
1374 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001375 }
1376 }
1377 }
1378 return(ret);
1379}
1380
1381/**
1382 * xmlStringGetNodeList:
1383 * @doc: the document
1384 * @value: the value of the attribute
1385 *
1386 * Parse the value string and build the node list associated. Should
1387 * produce a flat tree with only TEXTs and ENTITY_REFs.
1388 * Returns a pointer to the first child
1389 */
1390xmlNodePtr
1391xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1392 xmlNodePtr ret = NULL, last = NULL;
1393 xmlNodePtr node;
1394 xmlChar *val;
1395 const xmlChar *cur = value;
1396 const xmlChar *q;
1397 xmlEntityPtr ent;
1398
1399 if (value == NULL) return(NULL);
1400
1401 q = cur;
1402 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001403 if (cur[0] == '&') {
1404 int charval = 0;
1405 xmlChar tmp;
1406
Owen Taylor3473f882001-02-23 17:55:21 +00001407 /*
1408 * Save the current text.
1409 */
1410 if (cur != q) {
1411 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1412 xmlNodeAddContentLen(last, q, cur - q);
1413 } else {
1414 node = xmlNewDocTextLen(doc, q, cur - q);
1415 if (node == NULL) return(ret);
1416 if (last == NULL)
1417 last = ret = node;
1418 else {
1419 last->next = node;
1420 node->prev = last;
1421 last = node;
1422 }
1423 }
1424 }
Owen Taylor3473f882001-02-23 17:55:21 +00001425 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001426 if ((cur[1] == '#') && (cur[2] == 'x')) {
1427 cur += 3;
1428 tmp = *cur;
1429 while (tmp != ';') { /* Non input consuming loop */
1430 if ((tmp >= '0') && (tmp <= '9'))
1431 charval = charval * 16 + (tmp - '0');
1432 else if ((tmp >= 'a') && (tmp <= 'f'))
1433 charval = charval * 16 + (tmp - 'a') + 10;
1434 else if ((tmp >= 'A') && (tmp <= 'F'))
1435 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001436 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001437 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1438 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001439 charval = 0;
1440 break;
1441 }
1442 cur++;
1443 tmp = *cur;
1444 }
1445 if (tmp == ';')
1446 cur++;
1447 q = cur;
1448 } else if (cur[1] == '#') {
1449 cur += 2;
1450 tmp = *cur;
1451 while (tmp != ';') { /* Non input consuming loops */
1452 if ((tmp >= '0') && (tmp <= '9'))
1453 charval = charval * 10 + (tmp - '0');
1454 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001455 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1456 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001457 charval = 0;
1458 break;
1459 }
1460 cur++;
1461 tmp = *cur;
1462 }
1463 if (tmp == ';')
1464 cur++;
1465 q = cur;
1466 } else {
1467 /*
1468 * Read the entity string
1469 */
1470 cur++;
1471 q = cur;
1472 while ((*cur != 0) && (*cur != ';')) cur++;
1473 if (*cur == 0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001474 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1475 (xmlNodePtr) doc, (const char *) q);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001476 return(ret);
1477 }
1478 if (cur != q) {
1479 /*
1480 * Predefined entities don't generate nodes
1481 */
1482 val = xmlStrndup(q, cur - q);
1483 ent = xmlGetDocEntity(doc, val);
1484 if ((ent != NULL) &&
1485 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1486 if (last == NULL) {
1487 node = xmlNewDocText(doc, ent->content);
1488 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001489 } else if (last->type != XML_TEXT_NODE) {
1490 node = xmlNewDocText(doc, ent->content);
1491 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001492 } else
1493 xmlNodeAddContent(last, ent->content);
1494
1495 } else {
1496 /*
1497 * Create a new REFERENCE_REF node
1498 */
1499 node = xmlNewReference(doc, val);
1500 if (node == NULL) {
1501 if (val != NULL) xmlFree(val);
1502 return(ret);
1503 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001504 else if ((ent != NULL) && (ent->children == NULL)) {
1505 xmlNodePtr temp;
1506
1507 ent->children = xmlStringGetNodeList(doc,
1508 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001509 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001510 temp = ent->children;
1511 while (temp) {
1512 temp->parent = (xmlNodePtr)ent;
1513 temp = temp->next;
1514 }
1515 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001516 if (last == NULL) {
1517 last = ret = node;
1518 } else {
1519 last = xmlAddNextSibling(last, node);
1520 }
1521 }
1522 xmlFree(val);
1523 }
1524 cur++;
1525 q = cur;
1526 }
1527 if (charval != 0) {
1528 xmlChar buf[10];
1529 int len;
1530
1531 len = xmlCopyCharMultiByte(buf, charval);
1532 buf[len] = 0;
1533 node = xmlNewDocText(doc, buf);
1534 if (node != NULL) {
1535 if (last == NULL) {
1536 last = ret = node;
1537 } else {
1538 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001539 }
1540 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001541
1542 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001543 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001544 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001545 cur++;
1546 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001547 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001548 /*
1549 * Handle the last piece of text.
1550 */
1551 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1552 xmlNodeAddContentLen(last, q, cur - q);
1553 } else {
1554 node = xmlNewDocTextLen(doc, q, cur - q);
1555 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001556 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001557 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001558 } else {
1559 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001560 }
1561 }
1562 }
1563 return(ret);
1564}
1565
1566/**
1567 * xmlNodeListGetString:
1568 * @doc: the document
1569 * @list: a Node list
1570 * @inLine: should we replace entity contents or show their external form
1571 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001572 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001573 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001574 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001575 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001576 */
1577xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001578xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1579{
Owen Taylor3473f882001-02-23 17:55:21 +00001580 xmlNodePtr node = list;
1581 xmlChar *ret = NULL;
1582 xmlEntityPtr ent;
1583
Daniel Veillard7646b182002-04-20 06:41:40 +00001584 if (list == NULL)
1585 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001586
1587 while (node != NULL) {
1588 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001589 (node->type == XML_CDATA_SECTION_NODE)) {
1590 if (inLine) {
1591 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001592 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001593 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001594
Daniel Veillard7646b182002-04-20 06:41:40 +00001595 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1596 if (buffer != NULL) {
1597 ret = xmlStrcat(ret, buffer);
1598 xmlFree(buffer);
1599 }
1600 }
1601 } else if (node->type == XML_ENTITY_REF_NODE) {
1602 if (inLine) {
1603 ent = xmlGetDocEntity(doc, node->name);
1604 if (ent != NULL) {
1605 xmlChar *buffer;
1606
1607 /* an entity content can be any "well balanced chunk",
1608 * i.e. the result of the content [43] production:
1609 * http://www.w3.org/TR/REC-xml#NT-content.
1610 * So it can contain text, CDATA section or nested
1611 * entity reference nodes (among others).
1612 * -> we recursive call xmlNodeListGetString()
1613 * which handles these types */
1614 buffer = xmlNodeListGetString(doc, ent->children, 1);
1615 if (buffer != NULL) {
1616 ret = xmlStrcat(ret, buffer);
1617 xmlFree(buffer);
1618 }
1619 } else {
1620 ret = xmlStrcat(ret, node->content);
1621 }
1622 } else {
1623 xmlChar buf[2];
1624
1625 buf[0] = '&';
1626 buf[1] = 0;
1627 ret = xmlStrncat(ret, buf, 1);
1628 ret = xmlStrcat(ret, node->name);
1629 buf[0] = ';';
1630 buf[1] = 0;
1631 ret = xmlStrncat(ret, buf, 1);
1632 }
1633 }
1634#if 0
1635 else {
1636 xmlGenericError(xmlGenericErrorContext,
1637 "xmlGetNodeListString : invalid node type %d\n",
1638 node->type);
1639 }
1640#endif
1641 node = node->next;
1642 }
1643 return (ret);
1644}
Daniel Veillard652327a2003-09-29 18:02:38 +00001645
1646#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001647/**
1648 * xmlNodeListGetRawString:
1649 * @doc: the document
1650 * @list: a Node list
1651 * @inLine: should we replace entity contents or show their external form
1652 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001653 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001654 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1655 * this function doesn't do any character encoding handling.
1656 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001657 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001658 */
1659xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001660xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1661{
Owen Taylor3473f882001-02-23 17:55:21 +00001662 xmlNodePtr node = list;
1663 xmlChar *ret = NULL;
1664 xmlEntityPtr ent;
1665
Daniel Veillard7646b182002-04-20 06:41:40 +00001666 if (list == NULL)
1667 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001668
1669 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001670 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001671 (node->type == XML_CDATA_SECTION_NODE)) {
1672 if (inLine) {
1673 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001674 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001675 xmlChar *buffer;
1676
1677 buffer = xmlEncodeSpecialChars(doc, node->content);
1678 if (buffer != NULL) {
1679 ret = xmlStrcat(ret, buffer);
1680 xmlFree(buffer);
1681 }
1682 }
1683 } else if (node->type == XML_ENTITY_REF_NODE) {
1684 if (inLine) {
1685 ent = xmlGetDocEntity(doc, node->name);
1686 if (ent != NULL) {
1687 xmlChar *buffer;
1688
1689 /* an entity content can be any "well balanced chunk",
1690 * i.e. the result of the content [43] production:
1691 * http://www.w3.org/TR/REC-xml#NT-content.
1692 * So it can contain text, CDATA section or nested
1693 * entity reference nodes (among others).
1694 * -> we recursive call xmlNodeListGetRawString()
1695 * which handles these types */
1696 buffer =
1697 xmlNodeListGetRawString(doc, ent->children, 1);
1698 if (buffer != NULL) {
1699 ret = xmlStrcat(ret, buffer);
1700 xmlFree(buffer);
1701 }
1702 } else {
1703 ret = xmlStrcat(ret, node->content);
1704 }
1705 } else {
1706 xmlChar buf[2];
1707
1708 buf[0] = '&';
1709 buf[1] = 0;
1710 ret = xmlStrncat(ret, buf, 1);
1711 ret = xmlStrcat(ret, node->name);
1712 buf[0] = ';';
1713 buf[1] = 0;
1714 ret = xmlStrncat(ret, buf, 1);
1715 }
1716 }
Owen Taylor3473f882001-02-23 17:55:21 +00001717#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001718 else {
1719 xmlGenericError(xmlGenericErrorContext,
1720 "xmlGetNodeListString : invalid node type %d\n",
1721 node->type);
1722 }
Owen Taylor3473f882001-02-23 17:55:21 +00001723#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001724 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001725 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001726 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001727}
Daniel Veillard652327a2003-09-29 18:02:38 +00001728#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001729
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001730static xmlAttrPtr
1731xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns,
1732 const xmlChar * name, const xmlChar * value,
1733 int eatname)
1734{
Owen Taylor3473f882001-02-23 17:55:21 +00001735 xmlAttrPtr cur;
1736 xmlDocPtr doc = NULL;
1737
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001738 if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001739 if (eatname == 1)
1740 xmlFree((xmlChar *) name);
1741 return (NULL);
1742 }
Owen Taylor3473f882001-02-23 17:55:21 +00001743
1744 /*
1745 * Allocate a new property and fill the fields.
1746 */
1747 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1748 if (cur == NULL) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001749 if (eatname == 1)
1750 xmlFree((xmlChar *) name);
1751 xmlTreeErrMemory("building attribute");
1752 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001753 }
1754 memset(cur, 0, sizeof(xmlAttr));
1755 cur->type = XML_ATTRIBUTE_NODE;
1756
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001757 cur->parent = node;
Owen Taylor3473f882001-02-23 17:55:21 +00001758 if (node != NULL) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001759 doc = node->doc;
1760 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001761 }
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001762 cur->ns = ns;
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001763
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001764 if (eatname == 0) {
1765 if ((doc != NULL) && (doc->dict != NULL))
1766 cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
1767 else
1768 cur->name = xmlStrdup(name);
1769 } else
1770 cur->name = name;
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001771
Owen Taylor3473f882001-02-23 17:55:21 +00001772 if (value != NULL) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001773 xmlChar *buffer;
1774 xmlNodePtr tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00001775
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001776 buffer = xmlEncodeEntitiesReentrant(doc, value);
1777 cur->children = xmlStringGetNodeList(doc, buffer);
1778 cur->last = NULL;
1779 tmp = cur->children;
1780 while (tmp != NULL) {
1781 tmp->parent = (xmlNodePtr) cur;
1782 if (tmp->next == NULL)
1783 cur->last = tmp;
1784 tmp = tmp->next;
1785 }
1786 xmlFree(buffer);
1787 }
Owen Taylor3473f882001-02-23 17:55:21 +00001788
1789 /*
1790 * Add it at the end to preserve parsing order ...
1791 */
1792 if (node != NULL) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001793 if (node->properties == NULL) {
1794 node->properties = cur;
1795 } else {
1796 xmlAttrPtr prev = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00001797
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001798 while (prev->next != NULL)
1799 prev = prev->next;
1800 prev->next = cur;
1801 cur->prev = prev;
1802 }
Owen Taylor3473f882001-02-23 17:55:21 +00001803 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001804
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001805 if (xmlIsID((node == NULL) ? NULL : node->doc, node, cur) == 1)
1806 xmlAddID(NULL, node->doc, value, cur);
1807
Daniel Veillarda880b122003-04-21 21:36:41 +00001808 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001809 xmlRegisterNodeDefaultValue((xmlNodePtr) cur);
1810 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001811}
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001812
1813#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
1814 defined(LIBXML_SCHEMAS_ENABLED)
1815/**
1816 * xmlNewProp:
1817 * @node: the holding node
1818 * @name: the name of the attribute
1819 * @value: the value of the attribute
1820 *
1821 * Create a new property carried by a node.
1822 * Returns a pointer to the attribute
1823 */
1824xmlAttrPtr
1825xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1826
1827 if (name == NULL) {
1828#ifdef DEBUG_TREE
1829 xmlGenericError(xmlGenericErrorContext,
1830 "xmlNewProp : name == NULL\n");
1831#endif
1832 return(NULL);
1833 }
1834
1835 return xmlNewPropInternal(node, NULL, name, value, 0);
1836}
Daniel Veillard652327a2003-09-29 18:02:38 +00001837#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001838
1839/**
1840 * xmlNewNsProp:
1841 * @node: the holding node
1842 * @ns: the namespace
1843 * @name: the name of the attribute
1844 * @value: the value of the attribute
1845 *
1846 * Create a new property tagged with a namespace and carried by a node.
1847 * Returns a pointer to the attribute
1848 */
1849xmlAttrPtr
1850xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1851 const xmlChar *value) {
Owen Taylor3473f882001-02-23 17:55:21 +00001852
1853 if (name == NULL) {
1854#ifdef DEBUG_TREE
1855 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001856 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001857#endif
1858 return(NULL);
1859 }
1860
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001861 return xmlNewPropInternal(node, ns, name, value, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001862}
1863
1864/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001865 * xmlNewNsPropEatName:
1866 * @node: the holding node
1867 * @ns: the namespace
1868 * @name: the name of the attribute
1869 * @value: the value of the attribute
1870 *
1871 * Create a new property tagged with a namespace and carried by a node.
1872 * Returns a pointer to the attribute
1873 */
1874xmlAttrPtr
1875xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1876 const xmlChar *value) {
Daniel Veillard46de64e2002-05-29 08:21:33 +00001877
1878 if (name == NULL) {
1879#ifdef DEBUG_TREE
1880 xmlGenericError(xmlGenericErrorContext,
1881 "xmlNewNsPropEatName : name == NULL\n");
1882#endif
1883 return(NULL);
1884 }
1885
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001886 return xmlNewPropInternal(node, ns, name, value, 1);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001887}
1888
1889/**
Owen Taylor3473f882001-02-23 17:55:21 +00001890 * xmlNewDocProp:
1891 * @doc: the document
1892 * @name: the name of the attribute
1893 * @value: the value of the attribute
1894 *
1895 * Create a new property carried by a document.
1896 * Returns a pointer to the attribute
1897 */
1898xmlAttrPtr
1899xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1900 xmlAttrPtr cur;
1901
1902 if (name == NULL) {
1903#ifdef DEBUG_TREE
1904 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001905 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001906#endif
1907 return(NULL);
1908 }
1909
1910 /*
1911 * Allocate a new property and fill the fields.
1912 */
1913 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1914 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001915 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001916 return(NULL);
1917 }
1918 memset(cur, 0, sizeof(xmlAttr));
1919 cur->type = XML_ATTRIBUTE_NODE;
1920
Daniel Veillard03a53c32004-10-26 16:06:51 +00001921 if ((doc != NULL) && (doc->dict != NULL))
1922 cur->name = xmlDictLookup(doc->dict, name, -1);
1923 else
1924 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00001925 cur->doc = doc;
1926 if (value != NULL) {
1927 xmlNodePtr tmp;
1928
1929 cur->children = xmlStringGetNodeList(doc, value);
1930 cur->last = NULL;
1931
1932 tmp = cur->children;
1933 while (tmp != NULL) {
1934 tmp->parent = (xmlNodePtr) cur;
1935 if (tmp->next == NULL)
1936 cur->last = tmp;
1937 tmp = tmp->next;
1938 }
1939 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001940
Daniel Veillarda880b122003-04-21 21:36:41 +00001941 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001942 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001943 return(cur);
1944}
1945
1946/**
1947 * xmlFreePropList:
1948 * @cur: the first property in the list
1949 *
1950 * Free a property and all its siblings, all the children are freed too.
1951 */
1952void
1953xmlFreePropList(xmlAttrPtr cur) {
1954 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001955 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001956 while (cur != NULL) {
1957 next = cur->next;
1958 xmlFreeProp(cur);
1959 cur = next;
1960 }
1961}
1962
1963/**
1964 * xmlFreeProp:
1965 * @cur: an attribute
1966 *
1967 * Free one attribute, all the content is freed too
1968 */
1969void
1970xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001971 xmlDictPtr dict = NULL;
1972 if (cur == NULL) return;
1973
1974 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001975
Daniel Veillarda880b122003-04-21 21:36:41 +00001976 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001977 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1978
Owen Taylor3473f882001-02-23 17:55:21 +00001979 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillardda6f4af2005-06-20 17:17:54 +00001980 if ((cur->doc != NULL) && (cur->atype == XML_ATTRIBUTE_ID)) {
1981 xmlRemoveID(cur->doc, cur);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001982 }
Owen Taylor3473f882001-02-23 17:55:21 +00001983 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001984 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00001985 xmlFree(cur);
1986}
1987
1988/**
1989 * xmlRemoveProp:
1990 * @cur: an attribute
1991 *
1992 * Unlink and free one attribute, all the content is freed too
1993 * Note this doesn't work for namespace definition attributes
1994 *
1995 * Returns 0 if success and -1 in case of error.
1996 */
1997int
1998xmlRemoveProp(xmlAttrPtr cur) {
1999 xmlAttrPtr tmp;
2000 if (cur == NULL) {
2001#ifdef DEBUG_TREE
2002 xmlGenericError(xmlGenericErrorContext,
2003 "xmlRemoveProp : cur == NULL\n");
2004#endif
2005 return(-1);
2006 }
2007 if (cur->parent == NULL) {
2008#ifdef DEBUG_TREE
2009 xmlGenericError(xmlGenericErrorContext,
2010 "xmlRemoveProp : cur->parent == NULL\n");
2011#endif
2012 return(-1);
2013 }
2014 tmp = cur->parent->properties;
2015 if (tmp == cur) {
2016 cur->parent->properties = cur->next;
Rob Richards19dc9612005-10-28 16:15:16 +00002017 if (cur->next != NULL)
2018 cur->next->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002019 xmlFreeProp(cur);
2020 return(0);
2021 }
2022 while (tmp != NULL) {
2023 if (tmp->next == cur) {
2024 tmp->next = cur->next;
2025 if (tmp->next != NULL)
2026 tmp->next->prev = tmp;
2027 xmlFreeProp(cur);
2028 return(0);
2029 }
2030 tmp = tmp->next;
2031 }
2032#ifdef DEBUG_TREE
2033 xmlGenericError(xmlGenericErrorContext,
2034 "xmlRemoveProp : attribute not owned by its node\n");
2035#endif
2036 return(-1);
2037}
2038
2039/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002040 * xmlNewDocPI:
2041 * @doc: the target document
Owen Taylor3473f882001-02-23 17:55:21 +00002042 * @name: the processing instruction name
2043 * @content: the PI content
2044 *
2045 * Creation of a processing instruction element.
2046 * Returns a pointer to the new node object.
2047 */
2048xmlNodePtr
Daniel Veillard03a53c32004-10-26 16:06:51 +00002049xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
Owen Taylor3473f882001-02-23 17:55:21 +00002050 xmlNodePtr cur;
2051
2052 if (name == NULL) {
2053#ifdef DEBUG_TREE
2054 xmlGenericError(xmlGenericErrorContext,
2055 "xmlNewPI : name == NULL\n");
2056#endif
2057 return(NULL);
2058 }
2059
2060 /*
2061 * Allocate a new node and fill the fields.
2062 */
2063 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2064 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002065 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002066 return(NULL);
2067 }
2068 memset(cur, 0, sizeof(xmlNode));
2069 cur->type = XML_PI_NODE;
2070
Daniel Veillard03a53c32004-10-26 16:06:51 +00002071 if ((doc != NULL) && (doc->dict != NULL))
2072 cur->name = xmlDictLookup(doc->dict, name, -1);
2073 else
2074 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00002075 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002076 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002077 }
Daniel Veillarda03e3652004-11-02 18:45:30 +00002078 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002079
Daniel Veillarda880b122003-04-21 21:36:41 +00002080 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002081 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002082 return(cur);
2083}
2084
2085/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002086 * xmlNewPI:
2087 * @name: the processing instruction name
2088 * @content: the PI content
2089 *
2090 * Creation of a processing instruction element.
2091 * Use xmlDocNewPI preferably to get string interning
2092 *
2093 * Returns a pointer to the new node object.
2094 */
2095xmlNodePtr
2096xmlNewPI(const xmlChar *name, const xmlChar *content) {
2097 return(xmlNewDocPI(NULL, name, content));
2098}
2099
2100/**
Owen Taylor3473f882001-02-23 17:55:21 +00002101 * xmlNewNode:
2102 * @ns: namespace if any
2103 * @name: the node name
2104 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002105 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002106 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002107 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2108 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002109 */
2110xmlNodePtr
2111xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2112 xmlNodePtr cur;
2113
2114 if (name == NULL) {
2115#ifdef DEBUG_TREE
2116 xmlGenericError(xmlGenericErrorContext,
2117 "xmlNewNode : name == NULL\n");
2118#endif
2119 return(NULL);
2120 }
2121
2122 /*
2123 * Allocate a new node and fill the fields.
2124 */
2125 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2126 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002127 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002128 return(NULL);
2129 }
2130 memset(cur, 0, sizeof(xmlNode));
2131 cur->type = XML_ELEMENT_NODE;
2132
2133 cur->name = xmlStrdup(name);
2134 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002135
Daniel Veillarda880b122003-04-21 21:36:41 +00002136 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002137 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002138 return(cur);
2139}
2140
2141/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002142 * xmlNewNodeEatName:
2143 * @ns: namespace if any
2144 * @name: the node name
2145 *
2146 * Creation of a new node element. @ns is optional (NULL).
2147 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002148 * Returns a pointer to the new node object, with pointer @name as
2149 * new node's name. Use xmlNewNode() if a copy of @name string is
2150 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002151 */
2152xmlNodePtr
2153xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2154 xmlNodePtr cur;
2155
2156 if (name == NULL) {
2157#ifdef DEBUG_TREE
2158 xmlGenericError(xmlGenericErrorContext,
2159 "xmlNewNode : name == NULL\n");
2160#endif
2161 return(NULL);
2162 }
2163
2164 /*
2165 * Allocate a new node and fill the fields.
2166 */
2167 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2168 if (cur == NULL) {
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00002169 xmlFree(name);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002170 xmlTreeErrMemory("building node");
Daniel Veillard46de64e2002-05-29 08:21:33 +00002171 return(NULL);
2172 }
2173 memset(cur, 0, sizeof(xmlNode));
2174 cur->type = XML_ELEMENT_NODE;
2175
2176 cur->name = name;
2177 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002178
Daniel Veillarda880b122003-04-21 21:36:41 +00002179 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002180 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002181 return(cur);
2182}
2183
2184/**
Owen Taylor3473f882001-02-23 17:55:21 +00002185 * xmlNewDocNode:
2186 * @doc: the document
2187 * @ns: namespace if any
2188 * @name: the node name
2189 * @content: the XML text content if any
2190 *
2191 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002192 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002193 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2194 * references, but XML special chars need to be escaped first by using
2195 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2196 * need entities support.
2197 *
2198 * Returns a pointer to the new node object.
2199 */
2200xmlNodePtr
2201xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2202 const xmlChar *name, const xmlChar *content) {
2203 xmlNodePtr cur;
2204
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002205 if ((doc != NULL) && (doc->dict != NULL))
Daniel Veillard03a53c32004-10-26 16:06:51 +00002206 cur = xmlNewNodeEatName(ns, (xmlChar *)
2207 xmlDictLookup(doc->dict, name, -1));
2208 else
2209 cur = xmlNewNode(ns, name);
Owen Taylor3473f882001-02-23 17:55:21 +00002210 if (cur != NULL) {
2211 cur->doc = doc;
2212 if (content != NULL) {
2213 cur->children = xmlStringGetNodeList(doc, content);
2214 UPDATE_LAST_CHILD_AND_PARENT(cur)
2215 }
2216 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002217
Owen Taylor3473f882001-02-23 17:55:21 +00002218 return(cur);
2219}
2220
Daniel Veillard46de64e2002-05-29 08:21:33 +00002221/**
2222 * xmlNewDocNodeEatName:
2223 * @doc: the document
2224 * @ns: namespace if any
2225 * @name: the node name
2226 * @content: the XML text content if any
2227 *
2228 * Creation of a new node element within a document. @ns and @content
2229 * are optional (NULL).
2230 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2231 * references, but XML special chars need to be escaped first by using
2232 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2233 * need entities support.
2234 *
2235 * Returns a pointer to the new node object.
2236 */
2237xmlNodePtr
2238xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2239 xmlChar *name, const xmlChar *content) {
2240 xmlNodePtr cur;
2241
2242 cur = xmlNewNodeEatName(ns, name);
2243 if (cur != NULL) {
2244 cur->doc = doc;
2245 if (content != NULL) {
2246 cur->children = xmlStringGetNodeList(doc, content);
2247 UPDATE_LAST_CHILD_AND_PARENT(cur)
2248 }
2249 }
2250 return(cur);
2251}
2252
Daniel Veillard652327a2003-09-29 18:02:38 +00002253#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002254/**
2255 * xmlNewDocRawNode:
2256 * @doc: the document
2257 * @ns: namespace if any
2258 * @name: the node name
2259 * @content: the text content if any
2260 *
2261 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002262 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002263 *
2264 * Returns a pointer to the new node object.
2265 */
2266xmlNodePtr
2267xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2268 const xmlChar *name, const xmlChar *content) {
2269 xmlNodePtr cur;
2270
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002271 cur = xmlNewDocNode(doc, ns, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002272 if (cur != NULL) {
2273 cur->doc = doc;
2274 if (content != NULL) {
2275 cur->children = xmlNewDocText(doc, content);
2276 UPDATE_LAST_CHILD_AND_PARENT(cur)
2277 }
2278 }
2279 return(cur);
2280}
2281
2282/**
2283 * xmlNewDocFragment:
2284 * @doc: the document owning the fragment
2285 *
2286 * Creation of a new Fragment node.
2287 * Returns a pointer to the new node object.
2288 */
2289xmlNodePtr
2290xmlNewDocFragment(xmlDocPtr doc) {
2291 xmlNodePtr cur;
2292
2293 /*
2294 * Allocate a new DocumentFragment node and fill the fields.
2295 */
2296 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2297 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002298 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002299 return(NULL);
2300 }
2301 memset(cur, 0, sizeof(xmlNode));
2302 cur->type = XML_DOCUMENT_FRAG_NODE;
2303
2304 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002305
Daniel Veillarda880b122003-04-21 21:36:41 +00002306 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002307 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002308 return(cur);
2309}
Daniel Veillard652327a2003-09-29 18:02:38 +00002310#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002311
2312/**
2313 * xmlNewText:
2314 * @content: the text content
2315 *
2316 * Creation of a new text node.
2317 * Returns a pointer to the new node object.
2318 */
2319xmlNodePtr
2320xmlNewText(const xmlChar *content) {
2321 xmlNodePtr cur;
2322
2323 /*
2324 * Allocate a new node and fill the fields.
2325 */
2326 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2327 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002328 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002329 return(NULL);
2330 }
2331 memset(cur, 0, sizeof(xmlNode));
2332 cur->type = XML_TEXT_NODE;
2333
2334 cur->name = xmlStringText;
2335 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002336 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002337 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002338
Daniel Veillarda880b122003-04-21 21:36:41 +00002339 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002340 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002341 return(cur);
2342}
2343
Daniel Veillard652327a2003-09-29 18:02:38 +00002344#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002345/**
2346 * xmlNewTextChild:
2347 * @parent: the parent node
2348 * @ns: a namespace if any
2349 * @name: the name of the child
2350 * @content: the text content of the child if any.
2351 *
2352 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002353 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2354 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002355 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002356 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2357 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2358 * reserved XML chars that might appear in @content, such as the ampersand,
2359 * greater-than or less-than signs, are automatically replaced by their XML
2360 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002361 *
2362 * Returns a pointer to the new node object.
2363 */
2364xmlNodePtr
2365xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2366 const xmlChar *name, const xmlChar *content) {
2367 xmlNodePtr cur, prev;
2368
2369 if (parent == NULL) {
2370#ifdef DEBUG_TREE
2371 xmlGenericError(xmlGenericErrorContext,
2372 "xmlNewTextChild : parent == NULL\n");
2373#endif
2374 return(NULL);
2375 }
2376
2377 if (name == NULL) {
2378#ifdef DEBUG_TREE
2379 xmlGenericError(xmlGenericErrorContext,
2380 "xmlNewTextChild : name == NULL\n");
2381#endif
2382 return(NULL);
2383 }
2384
2385 /*
2386 * Allocate a new node
2387 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002388 if (parent->type == XML_ELEMENT_NODE) {
2389 if (ns == NULL)
2390 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2391 else
2392 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2393 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2394 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2395 if (ns == NULL)
2396 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2397 else
2398 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2399 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2400 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2401 } else {
2402 return(NULL);
2403 }
Owen Taylor3473f882001-02-23 17:55:21 +00002404 if (cur == NULL) return(NULL);
2405
2406 /*
2407 * add the new element at the end of the children list.
2408 */
2409 cur->type = XML_ELEMENT_NODE;
2410 cur->parent = parent;
2411 cur->doc = parent->doc;
2412 if (parent->children == NULL) {
2413 parent->children = cur;
2414 parent->last = cur;
2415 } else {
2416 prev = parent->last;
2417 prev->next = cur;
2418 cur->prev = prev;
2419 parent->last = cur;
2420 }
2421
2422 return(cur);
2423}
Daniel Veillard652327a2003-09-29 18:02:38 +00002424#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002425
2426/**
2427 * xmlNewCharRef:
2428 * @doc: the document
2429 * @name: the char ref string, starting with # or "&# ... ;"
2430 *
2431 * Creation of a new character reference node.
2432 * Returns a pointer to the new node object.
2433 */
2434xmlNodePtr
2435xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2436 xmlNodePtr cur;
2437
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002438 if (name == NULL)
2439 return(NULL);
2440
Owen Taylor3473f882001-02-23 17:55:21 +00002441 /*
2442 * Allocate a new node and fill the fields.
2443 */
2444 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2445 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002446 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002447 return(NULL);
2448 }
2449 memset(cur, 0, sizeof(xmlNode));
2450 cur->type = XML_ENTITY_REF_NODE;
2451
2452 cur->doc = doc;
2453 if (name[0] == '&') {
2454 int len;
2455 name++;
2456 len = xmlStrlen(name);
2457 if (name[len - 1] == ';')
2458 cur->name = xmlStrndup(name, len - 1);
2459 else
2460 cur->name = xmlStrndup(name, len);
2461 } else
2462 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002463
Daniel Veillarda880b122003-04-21 21:36:41 +00002464 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002465 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002466 return(cur);
2467}
2468
2469/**
2470 * xmlNewReference:
2471 * @doc: the document
2472 * @name: the reference name, or the reference string with & and ;
2473 *
2474 * Creation of a new reference node.
2475 * Returns a pointer to the new node object.
2476 */
2477xmlNodePtr
2478xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2479 xmlNodePtr cur;
2480 xmlEntityPtr ent;
2481
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002482 if (name == NULL)
2483 return(NULL);
2484
Owen Taylor3473f882001-02-23 17:55:21 +00002485 /*
2486 * Allocate a new node and fill the fields.
2487 */
2488 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2489 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002490 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002491 return(NULL);
2492 }
2493 memset(cur, 0, sizeof(xmlNode));
2494 cur->type = XML_ENTITY_REF_NODE;
2495
2496 cur->doc = doc;
2497 if (name[0] == '&') {
2498 int len;
2499 name++;
2500 len = xmlStrlen(name);
2501 if (name[len - 1] == ';')
2502 cur->name = xmlStrndup(name, len - 1);
2503 else
2504 cur->name = xmlStrndup(name, len);
2505 } else
2506 cur->name = xmlStrdup(name);
2507
2508 ent = xmlGetDocEntity(doc, cur->name);
2509 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002510 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002511 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002512 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002513 * updated. Not sure if this is 100% correct.
2514 * -George
2515 */
2516 cur->children = (xmlNodePtr) ent;
2517 cur->last = (xmlNodePtr) ent;
2518 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002519
Daniel Veillarda880b122003-04-21 21:36:41 +00002520 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002521 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002522 return(cur);
2523}
2524
2525/**
2526 * xmlNewDocText:
2527 * @doc: the document
2528 * @content: the text content
2529 *
2530 * Creation of a new text node within a document.
2531 * Returns a pointer to the new node object.
2532 */
2533xmlNodePtr
2534xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2535 xmlNodePtr cur;
2536
2537 cur = xmlNewText(content);
2538 if (cur != NULL) cur->doc = doc;
2539 return(cur);
2540}
2541
2542/**
2543 * xmlNewTextLen:
2544 * @content: the text content
2545 * @len: the text len.
2546 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002547 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002548 * Returns a pointer to the new node object.
2549 */
2550xmlNodePtr
2551xmlNewTextLen(const xmlChar *content, int len) {
2552 xmlNodePtr cur;
2553
2554 /*
2555 * Allocate a new node and fill the fields.
2556 */
2557 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2558 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002559 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002560 return(NULL);
2561 }
2562 memset(cur, 0, sizeof(xmlNode));
2563 cur->type = XML_TEXT_NODE;
2564
2565 cur->name = xmlStringText;
2566 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002567 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002568 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002569
Daniel Veillarda880b122003-04-21 21:36:41 +00002570 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002571 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002572 return(cur);
2573}
2574
2575/**
2576 * xmlNewDocTextLen:
2577 * @doc: the document
2578 * @content: the text content
2579 * @len: the text len.
2580 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002581 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002582 * text node pertain to a given document.
2583 * Returns a pointer to the new node object.
2584 */
2585xmlNodePtr
2586xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2587 xmlNodePtr cur;
2588
2589 cur = xmlNewTextLen(content, len);
2590 if (cur != NULL) cur->doc = doc;
2591 return(cur);
2592}
2593
2594/**
2595 * xmlNewComment:
2596 * @content: the comment content
2597 *
2598 * Creation of a new node containing a comment.
2599 * Returns a pointer to the new node object.
2600 */
2601xmlNodePtr
2602xmlNewComment(const xmlChar *content) {
2603 xmlNodePtr cur;
2604
2605 /*
2606 * Allocate a new node and fill the fields.
2607 */
2608 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2609 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002610 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002611 return(NULL);
2612 }
2613 memset(cur, 0, sizeof(xmlNode));
2614 cur->type = XML_COMMENT_NODE;
2615
2616 cur->name = xmlStringComment;
2617 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002618 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002619 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002620
Daniel Veillarda880b122003-04-21 21:36:41 +00002621 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002622 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002623 return(cur);
2624}
2625
2626/**
2627 * xmlNewCDataBlock:
2628 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002629 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002630 * @len: the length of the block
2631 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002632 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002633 * Returns a pointer to the new node object.
2634 */
2635xmlNodePtr
2636xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2637 xmlNodePtr cur;
2638
2639 /*
2640 * Allocate a new node and fill the fields.
2641 */
2642 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2643 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002644 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002645 return(NULL);
2646 }
2647 memset(cur, 0, sizeof(xmlNode));
2648 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002649 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002650
2651 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002652 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002653 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002654
Daniel Veillarda880b122003-04-21 21:36:41 +00002655 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002656 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002657 return(cur);
2658}
2659
2660/**
2661 * xmlNewDocComment:
2662 * @doc: the document
2663 * @content: the comment content
2664 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002665 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002666 * Returns a pointer to the new node object.
2667 */
2668xmlNodePtr
2669xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2670 xmlNodePtr cur;
2671
2672 cur = xmlNewComment(content);
2673 if (cur != NULL) cur->doc = doc;
2674 return(cur);
2675}
2676
2677/**
2678 * xmlSetTreeDoc:
2679 * @tree: the top element
2680 * @doc: the document
2681 *
2682 * update all nodes under the tree to point to the right document
2683 */
2684void
2685xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002686 xmlAttrPtr prop;
2687
Owen Taylor3473f882001-02-23 17:55:21 +00002688 if (tree == NULL)
2689 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002690 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002691 if(tree->type == XML_ELEMENT_NODE) {
2692 prop = tree->properties;
2693 while (prop != NULL) {
2694 prop->doc = doc;
2695 xmlSetListDoc(prop->children, doc);
2696 prop = prop->next;
2697 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002698 }
Owen Taylor3473f882001-02-23 17:55:21 +00002699 if (tree->children != NULL)
2700 xmlSetListDoc(tree->children, doc);
2701 tree->doc = doc;
2702 }
2703}
2704
2705/**
2706 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002707 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002708 * @doc: the document
2709 *
2710 * update all nodes in the list to point to the right document
2711 */
2712void
2713xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2714 xmlNodePtr cur;
2715
2716 if (list == NULL)
2717 return;
2718 cur = list;
2719 while (cur != NULL) {
2720 if (cur->doc != doc)
2721 xmlSetTreeDoc(cur, doc);
2722 cur = cur->next;
2723 }
2724}
2725
Daniel Veillard2156d432004-03-04 15:59:36 +00002726#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002727/**
2728 * xmlNewChild:
2729 * @parent: the parent node
2730 * @ns: a namespace if any
2731 * @name: the name of the child
2732 * @content: the XML content of the child if any.
2733 *
2734 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002735 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2736 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002737 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002738 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2739 * references. XML special chars must be escaped first by using
2740 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002741 *
2742 * Returns a pointer to the new node object.
2743 */
2744xmlNodePtr
2745xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2746 const xmlChar *name, const xmlChar *content) {
2747 xmlNodePtr cur, prev;
2748
2749 if (parent == NULL) {
2750#ifdef DEBUG_TREE
2751 xmlGenericError(xmlGenericErrorContext,
2752 "xmlNewChild : parent == NULL\n");
2753#endif
2754 return(NULL);
2755 }
2756
2757 if (name == NULL) {
2758#ifdef DEBUG_TREE
2759 xmlGenericError(xmlGenericErrorContext,
2760 "xmlNewChild : name == NULL\n");
2761#endif
2762 return(NULL);
2763 }
2764
2765 /*
2766 * Allocate a new node
2767 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002768 if (parent->type == XML_ELEMENT_NODE) {
2769 if (ns == NULL)
2770 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2771 else
2772 cur = xmlNewDocNode(parent->doc, ns, name, content);
2773 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2774 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2775 if (ns == NULL)
2776 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2777 else
2778 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002779 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2780 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002781 } else {
2782 return(NULL);
2783 }
Owen Taylor3473f882001-02-23 17:55:21 +00002784 if (cur == NULL) return(NULL);
2785
2786 /*
2787 * add the new element at the end of the children list.
2788 */
2789 cur->type = XML_ELEMENT_NODE;
2790 cur->parent = parent;
2791 cur->doc = parent->doc;
2792 if (parent->children == NULL) {
2793 parent->children = cur;
2794 parent->last = cur;
2795 } else {
2796 prev = parent->last;
2797 prev->next = cur;
2798 cur->prev = prev;
2799 parent->last = cur;
2800 }
2801
2802 return(cur);
2803}
Daniel Veillard652327a2003-09-29 18:02:38 +00002804#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002805
2806/**
Rob Richards65815122006-02-25 17:13:33 +00002807 * xmlAddPropSibling:
2808 * @prev: the attribute to which @prop is added after
2809 * @cur: the base attribute passed to calling function
2810 * @prop: the new attribute
2811 *
2812 * Add a new attribute after @prev using @cur as base attribute.
2813 * When inserting before @cur, @prev is passed as @cur->prev.
2814 * When inserting after @cur, @prev is passed as @cur.
2815 * If an existing attribute is found it is detroyed prior to adding @prop.
2816 *
2817 * Returns the attribute being inserted or NULL in case of error.
2818 */
2819static xmlNodePtr
2820xmlAddPropSibling(xmlNodePtr prev, xmlNodePtr cur, xmlNodePtr prop) {
2821 xmlAttrPtr attr;
2822
2823 if (cur->type != XML_ATTRIBUTE_NODE)
2824 return(NULL);
2825
2826 /* check if an attribute with the same name exists */
2827 if (prop->ns == NULL)
2828 attr = xmlHasNsProp(cur->parent, prop->name, NULL);
2829 else
2830 attr = xmlHasNsProp(cur->parent, prop->name, prop->ns->href);
2831
2832 if (prop->doc != cur->doc) {
2833 xmlSetTreeDoc(prop, cur->doc);
2834 }
2835 prop->parent = cur->parent;
2836 prop->prev = prev;
2837 if (prev != NULL) {
2838 prop->next = prev->next;
2839 prev->next = prop;
2840 if (prop->next)
2841 prop->next->prev = prop;
2842 } else {
2843 prop->next = cur;
2844 cur->prev = prop;
2845 }
2846 if (prop->prev == NULL && prop->parent != NULL)
2847 prop->parent->properties = (xmlAttrPtr) prop;
2848 if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) {
2849 /* different instance, destroy it (attributes must be unique) */
2850 xmlRemoveProp((xmlAttrPtr) attr);
2851 }
2852 return prop;
2853}
2854
2855/**
Owen Taylor3473f882001-02-23 17:55:21 +00002856 * xmlAddNextSibling:
2857 * @cur: the child node
2858 * @elem: the new node
2859 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002860 * Add a new node @elem as the next sibling of @cur
2861 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002862 * first unlinked from its existing context.
2863 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002864 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2865 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002866 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002867 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002868 */
2869xmlNodePtr
2870xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2871 if (cur == NULL) {
2872#ifdef DEBUG_TREE
2873 xmlGenericError(xmlGenericErrorContext,
2874 "xmlAddNextSibling : cur == NULL\n");
2875#endif
2876 return(NULL);
2877 }
2878 if (elem == NULL) {
2879#ifdef DEBUG_TREE
2880 xmlGenericError(xmlGenericErrorContext,
2881 "xmlAddNextSibling : elem == NULL\n");
2882#endif
2883 return(NULL);
2884 }
2885
Rob Richards19dc9612005-10-28 16:15:16 +00002886 if (cur == elem) {
2887#ifdef DEBUG_TREE
2888 xmlGenericError(xmlGenericErrorContext,
2889 "xmlAddNextSibling : cur == elem\n");
2890#endif
2891 return(NULL);
2892 }
2893
Owen Taylor3473f882001-02-23 17:55:21 +00002894 xmlUnlinkNode(elem);
2895
2896 if (elem->type == XML_TEXT_NODE) {
2897 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002898 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002899 xmlFreeNode(elem);
2900 return(cur);
2901 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002902 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2903 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002904 xmlChar *tmp;
2905
2906 tmp = xmlStrdup(elem->content);
2907 tmp = xmlStrcat(tmp, cur->next->content);
2908 xmlNodeSetContent(cur->next, tmp);
2909 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002910 xmlFreeNode(elem);
2911 return(cur->next);
2912 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002913 } else if (elem->type == XML_ATTRIBUTE_NODE) {
Rob Richards65815122006-02-25 17:13:33 +00002914 return xmlAddPropSibling(cur, cur, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00002915 }
2916
2917 if (elem->doc != cur->doc) {
2918 xmlSetTreeDoc(elem, cur->doc);
2919 }
2920 elem->parent = cur->parent;
2921 elem->prev = cur;
2922 elem->next = cur->next;
2923 cur->next = elem;
2924 if (elem->next != NULL)
2925 elem->next->prev = elem;
Rob Richards65815122006-02-25 17:13:33 +00002926 if ((elem->parent != NULL) && (elem->parent->last == cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002927 elem->parent->last = elem;
2928 return(elem);
2929}
2930
William M. Brack21e4ef22005-01-02 09:53:13 +00002931#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
2932 defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002933/**
2934 * xmlAddPrevSibling:
2935 * @cur: the child node
2936 * @elem: the new node
2937 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002938 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002939 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002940 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002941 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002942 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2943 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002944 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002945 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002946 */
2947xmlNodePtr
2948xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2949 if (cur == NULL) {
2950#ifdef DEBUG_TREE
2951 xmlGenericError(xmlGenericErrorContext,
2952 "xmlAddPrevSibling : cur == NULL\n");
2953#endif
2954 return(NULL);
2955 }
2956 if (elem == NULL) {
2957#ifdef DEBUG_TREE
2958 xmlGenericError(xmlGenericErrorContext,
2959 "xmlAddPrevSibling : elem == NULL\n");
2960#endif
2961 return(NULL);
2962 }
2963
Rob Richards19dc9612005-10-28 16:15:16 +00002964 if (cur == elem) {
2965#ifdef DEBUG_TREE
2966 xmlGenericError(xmlGenericErrorContext,
2967 "xmlAddPrevSibling : cur == elem\n");
2968#endif
2969 return(NULL);
2970 }
2971
Owen Taylor3473f882001-02-23 17:55:21 +00002972 xmlUnlinkNode(elem);
2973
2974 if (elem->type == XML_TEXT_NODE) {
2975 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002976 xmlChar *tmp;
2977
2978 tmp = xmlStrdup(elem->content);
2979 tmp = xmlStrcat(tmp, cur->content);
2980 xmlNodeSetContent(cur, tmp);
2981 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002982 xmlFreeNode(elem);
2983 return(cur);
2984 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002985 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2986 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002987 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002988 xmlFreeNode(elem);
2989 return(cur->prev);
2990 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002991 } else if (elem->type == XML_ATTRIBUTE_NODE) {
Rob Richards65815122006-02-25 17:13:33 +00002992 return xmlAddPropSibling(cur->prev, cur, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00002993 }
2994
2995 if (elem->doc != cur->doc) {
2996 xmlSetTreeDoc(elem, cur->doc);
2997 }
2998 elem->parent = cur->parent;
2999 elem->next = cur;
3000 elem->prev = cur->prev;
3001 cur->prev = elem;
3002 if (elem->prev != NULL)
3003 elem->prev->next = elem;
Rob Richards65815122006-02-25 17:13:33 +00003004 if ((elem->parent != NULL) && (elem->parent->children == cur)) {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003005 elem->parent->children = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003006 }
Owen Taylor3473f882001-02-23 17:55:21 +00003007 return(elem);
3008}
Daniel Veillard652327a2003-09-29 18:02:38 +00003009#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003010
3011/**
3012 * xmlAddSibling:
3013 * @cur: the child node
3014 * @elem: the new node
3015 *
3016 * Add a new element @elem to the list of siblings of @cur
3017 * merging adjacent TEXT nodes (@elem may be freed)
3018 * If the new element was already inserted in a document it is
3019 * first unlinked from its existing context.
3020 *
3021 * Returns the new element or NULL in case of error.
3022 */
3023xmlNodePtr
3024xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
3025 xmlNodePtr parent;
3026
3027 if (cur == NULL) {
3028#ifdef DEBUG_TREE
3029 xmlGenericError(xmlGenericErrorContext,
3030 "xmlAddSibling : cur == NULL\n");
3031#endif
3032 return(NULL);
3033 }
3034
3035 if (elem == NULL) {
3036#ifdef DEBUG_TREE
3037 xmlGenericError(xmlGenericErrorContext,
3038 "xmlAddSibling : elem == NULL\n");
3039#endif
3040 return(NULL);
3041 }
3042
3043 /*
3044 * Constant time is we can rely on the ->parent->last to find
3045 * the last sibling.
3046 */
Rob Richards65815122006-02-25 17:13:33 +00003047 if ((cur->type != XML_ATTRIBUTE_NODE) && (cur->parent != NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00003048 (cur->parent->children != NULL) &&
3049 (cur->parent->last != NULL) &&
3050 (cur->parent->last->next == NULL)) {
3051 cur = cur->parent->last;
3052 } else {
3053 while (cur->next != NULL) cur = cur->next;
3054 }
3055
3056 xmlUnlinkNode(elem);
3057
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003058 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3059 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003060 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003061 xmlFreeNode(elem);
3062 return(cur);
Rob Richards65815122006-02-25 17:13:33 +00003063 } else if (elem->type == XML_ATTRIBUTE_NODE) {
3064 return xmlAddPropSibling(cur, cur, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00003065 }
3066
3067 if (elem->doc != cur->doc) {
3068 xmlSetTreeDoc(elem, cur->doc);
3069 }
3070 parent = cur->parent;
3071 elem->prev = cur;
3072 elem->next = NULL;
3073 elem->parent = parent;
3074 cur->next = elem;
3075 if (parent != NULL)
3076 parent->last = elem;
3077
3078 return(elem);
3079}
3080
3081/**
3082 * xmlAddChildList:
3083 * @parent: the parent node
3084 * @cur: the first node in the list
3085 *
3086 * Add a list of node at the end of the child list of the parent
3087 * merging adjacent TEXT nodes (@cur may be freed)
3088 *
3089 * Returns the last child or NULL in case of error.
3090 */
3091xmlNodePtr
3092xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3093 xmlNodePtr prev;
3094
3095 if (parent == NULL) {
3096#ifdef DEBUG_TREE
3097 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003098 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003099#endif
3100 return(NULL);
3101 }
3102
3103 if (cur == NULL) {
3104#ifdef DEBUG_TREE
3105 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003106 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003107#endif
3108 return(NULL);
3109 }
3110
3111 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3112 (cur->doc != parent->doc)) {
3113#ifdef DEBUG_TREE
3114 xmlGenericError(xmlGenericErrorContext,
3115 "Elements moved to a different document\n");
3116#endif
3117 }
3118
3119 /*
3120 * add the first element at the end of the children list.
3121 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003122
Owen Taylor3473f882001-02-23 17:55:21 +00003123 if (parent->children == NULL) {
3124 parent->children = cur;
3125 } else {
3126 /*
3127 * If cur and parent->last both are TEXT nodes, then merge them.
3128 */
3129 if ((cur->type == XML_TEXT_NODE) &&
3130 (parent->last->type == XML_TEXT_NODE) &&
3131 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003132 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003133 /*
3134 * if it's the only child, nothing more to be done.
3135 */
3136 if (cur->next == NULL) {
3137 xmlFreeNode(cur);
3138 return(parent->last);
3139 }
3140 prev = cur;
3141 cur = cur->next;
3142 xmlFreeNode(prev);
3143 }
3144 prev = parent->last;
3145 prev->next = cur;
3146 cur->prev = prev;
3147 }
3148 while (cur->next != NULL) {
3149 cur->parent = parent;
3150 if (cur->doc != parent->doc) {
3151 xmlSetTreeDoc(cur, parent->doc);
3152 }
3153 cur = cur->next;
3154 }
3155 cur->parent = parent;
3156 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3157 parent->last = cur;
3158
3159 return(cur);
3160}
3161
3162/**
3163 * xmlAddChild:
3164 * @parent: the parent node
3165 * @cur: the child node
3166 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003167 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003168 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003169 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3170 * If there is an attribute with equal name, it is first destroyed.
3171 *
Owen Taylor3473f882001-02-23 17:55:21 +00003172 * Returns the child or NULL in case of error.
3173 */
3174xmlNodePtr
3175xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3176 xmlNodePtr prev;
3177
3178 if (parent == NULL) {
3179#ifdef DEBUG_TREE
3180 xmlGenericError(xmlGenericErrorContext,
3181 "xmlAddChild : parent == NULL\n");
3182#endif
3183 return(NULL);
3184 }
3185
3186 if (cur == NULL) {
3187#ifdef DEBUG_TREE
3188 xmlGenericError(xmlGenericErrorContext,
3189 "xmlAddChild : child == NULL\n");
3190#endif
3191 return(NULL);
3192 }
3193
Rob Richards19dc9612005-10-28 16:15:16 +00003194 if (parent == cur) {
3195#ifdef DEBUG_TREE
3196 xmlGenericError(xmlGenericErrorContext,
3197 "xmlAddChild : parent == cur\n");
3198#endif
3199 return(NULL);
3200 }
Owen Taylor3473f882001-02-23 17:55:21 +00003201 /*
3202 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003203 * cur is then freed.
3204 */
3205 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003206 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003207 (parent->content != NULL) &&
Rob Richards19dc9612005-10-28 16:15:16 +00003208 (parent->name == cur->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003209 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003210 xmlFreeNode(cur);
3211 return(parent);
3212 }
3213 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003214 (parent->last->name == cur->name) &&
3215 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003216 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003217 xmlFreeNode(cur);
3218 return(parent->last);
3219 }
3220 }
3221
3222 /*
3223 * add the new element at the end of the children list.
3224 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003225 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003226 cur->parent = parent;
3227 if (cur->doc != parent->doc) {
3228 xmlSetTreeDoc(cur, parent->doc);
3229 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003230 /* this check prevents a loop on tree-traversions if a developer
3231 * tries to add a node to its parent multiple times
3232 */
3233 if (prev == parent)
3234 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003235
3236 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003237 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003238 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003239 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003240 (parent->content != NULL) &&
3241 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003242 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003243 xmlFreeNode(cur);
3244 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003245 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003246 if (cur->type == XML_ATTRIBUTE_NODE) {
Rob Richards19dc9612005-10-28 16:15:16 +00003247 if (parent->type != XML_ELEMENT_NODE)
3248 return(NULL);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003249 if (parent->properties == NULL) {
3250 parent->properties = (xmlAttrPtr) cur;
3251 } else {
3252 /* check if an attribute with the same name exists */
3253 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003254
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003255 if (cur->ns == NULL)
Rob Richardsc342ec62005-10-25 00:10:12 +00003256 lastattr = xmlHasNsProp(parent, cur->name, NULL);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003257 else
3258 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
Rob Richardsc342ec62005-10-25 00:10:12 +00003259 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur) && (lastattr->type != XML_ATTRIBUTE_DECL)) {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003260 /* different instance, destroy it (attributes must be unique) */
Rob Richards19dc9612005-10-28 16:15:16 +00003261 xmlUnlinkNode((xmlNodePtr) lastattr);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003262 xmlFreeProp(lastattr);
3263 }
Rob Richards19dc9612005-10-28 16:15:16 +00003264 if (lastattr == (xmlAttrPtr) cur)
3265 return(cur);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003266 /* find the end */
3267 lastattr = parent->properties;
3268 while (lastattr->next != NULL) {
3269 lastattr = lastattr->next;
3270 }
3271 lastattr->next = (xmlAttrPtr) cur;
3272 ((xmlAttrPtr) cur)->prev = lastattr;
3273 }
3274 } else {
3275 if (parent->children == NULL) {
3276 parent->children = cur;
3277 parent->last = cur;
3278 } else {
3279 prev = parent->last;
3280 prev->next = cur;
3281 cur->prev = prev;
3282 parent->last = cur;
3283 }
3284 }
Owen Taylor3473f882001-02-23 17:55:21 +00003285 return(cur);
3286}
3287
3288/**
3289 * xmlGetLastChild:
3290 * @parent: the parent node
3291 *
3292 * Search the last child of a node.
3293 * Returns the last child or NULL if none.
3294 */
3295xmlNodePtr
3296xmlGetLastChild(xmlNodePtr parent) {
3297 if (parent == NULL) {
3298#ifdef DEBUG_TREE
3299 xmlGenericError(xmlGenericErrorContext,
3300 "xmlGetLastChild : parent == NULL\n");
3301#endif
3302 return(NULL);
3303 }
3304 return(parent->last);
3305}
3306
3307/**
3308 * xmlFreeNodeList:
3309 * @cur: the first node in the list
3310 *
3311 * Free a node and all its siblings, this is a recursive behaviour, all
3312 * the children are freed too.
3313 */
3314void
3315xmlFreeNodeList(xmlNodePtr cur) {
3316 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003317 xmlDictPtr dict = NULL;
3318
3319 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003320 if (cur->type == XML_NAMESPACE_DECL) {
3321 xmlFreeNsList((xmlNsPtr) cur);
3322 return;
3323 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003324 if ((cur->type == XML_DOCUMENT_NODE) ||
3325#ifdef LIBXML_DOCB_ENABLED
3326 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003327#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003328 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003329 xmlFreeDoc((xmlDocPtr) cur);
3330 return;
3331 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003332 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003333 while (cur != NULL) {
3334 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003335 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003336
Daniel Veillarda880b122003-04-21 21:36:41 +00003337 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003338 xmlDeregisterNodeDefaultValue(cur);
3339
Daniel Veillard02141ea2001-04-30 11:46:40 +00003340 if ((cur->children != NULL) &&
3341 (cur->type != XML_ENTITY_REF_NODE))
3342 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003343 if (((cur->type == XML_ELEMENT_NODE) ||
3344 (cur->type == XML_XINCLUDE_START) ||
3345 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003346 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003347 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003348 if ((cur->type != XML_ELEMENT_NODE) &&
3349 (cur->type != XML_XINCLUDE_START) &&
3350 (cur->type != XML_XINCLUDE_END) &&
Daniel Veillard8874b942005-08-25 13:19:21 +00003351 (cur->type != XML_ENTITY_REF_NODE) &&
3352 (cur->content != (xmlChar *) &(cur->properties))) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003353 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003354 }
3355 if (((cur->type == XML_ELEMENT_NODE) ||
3356 (cur->type == XML_XINCLUDE_START) ||
3357 (cur->type == XML_XINCLUDE_END)) &&
3358 (cur->nsDef != NULL))
3359 xmlFreeNsList(cur->nsDef);
3360
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003361 /*
3362 * When a node is a text node or a comment, it uses a global static
3363 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003364 * Otherwise the node name might come from the document's
3365 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003366 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003367 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003368 (cur->type != XML_TEXT_NODE) &&
3369 (cur->type != XML_COMMENT_NODE))
3370 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003371 xmlFree(cur);
3372 }
Owen Taylor3473f882001-02-23 17:55:21 +00003373 cur = next;
3374 }
3375}
3376
3377/**
3378 * xmlFreeNode:
3379 * @cur: the node
3380 *
3381 * Free a node, this is a recursive behaviour, all the children are freed too.
3382 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3383 */
3384void
3385xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003386 xmlDictPtr dict = NULL;
3387
3388 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003389
Daniel Veillard02141ea2001-04-30 11:46:40 +00003390 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003391 if (cur->type == XML_DTD_NODE) {
3392 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003393 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003394 }
3395 if (cur->type == XML_NAMESPACE_DECL) {
3396 xmlFreeNs((xmlNsPtr) cur);
3397 return;
3398 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003399 if (cur->type == XML_ATTRIBUTE_NODE) {
3400 xmlFreeProp((xmlAttrPtr) cur);
3401 return;
3402 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003403
Daniel Veillarda880b122003-04-21 21:36:41 +00003404 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003405 xmlDeregisterNodeDefaultValue(cur);
3406
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003407 if (cur->doc != NULL) dict = cur->doc->dict;
3408
Owen Taylor3473f882001-02-23 17:55:21 +00003409 if ((cur->children != NULL) &&
3410 (cur->type != XML_ENTITY_REF_NODE))
3411 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003412 if (((cur->type == XML_ELEMENT_NODE) ||
3413 (cur->type == XML_XINCLUDE_START) ||
3414 (cur->type == XML_XINCLUDE_END)) &&
3415 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003416 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003417 if ((cur->type != XML_ELEMENT_NODE) &&
3418 (cur->content != NULL) &&
3419 (cur->type != XML_ENTITY_REF_NODE) &&
3420 (cur->type != XML_XINCLUDE_END) &&
Daniel Veillard8874b942005-08-25 13:19:21 +00003421 (cur->type != XML_XINCLUDE_START) &&
3422 (cur->content != (xmlChar *) &(cur->properties))) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003423 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003424 }
3425
Daniel Veillardacd370f2001-06-09 17:17:51 +00003426 /*
3427 * When a node is a text node or a comment, it uses a global static
3428 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003429 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003430 */
Owen Taylor3473f882001-02-23 17:55:21 +00003431 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003432 (cur->type != XML_TEXT_NODE) &&
3433 (cur->type != XML_COMMENT_NODE))
3434 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003435
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003436 if (((cur->type == XML_ELEMENT_NODE) ||
3437 (cur->type == XML_XINCLUDE_START) ||
3438 (cur->type == XML_XINCLUDE_END)) &&
3439 (cur->nsDef != NULL))
3440 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003441 xmlFree(cur);
3442}
3443
3444/**
3445 * xmlUnlinkNode:
3446 * @cur: the node
3447 *
3448 * Unlink a node from it's current context, the node is not freed
3449 */
3450void
3451xmlUnlinkNode(xmlNodePtr cur) {
3452 if (cur == NULL) {
3453#ifdef DEBUG_TREE
3454 xmlGenericError(xmlGenericErrorContext,
3455 "xmlUnlinkNode : node == NULL\n");
3456#endif
3457 return;
3458 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003459 if (cur->type == XML_DTD_NODE) {
3460 xmlDocPtr doc;
3461 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003462 if (doc != NULL) {
3463 if (doc->intSubset == (xmlDtdPtr) cur)
3464 doc->intSubset = NULL;
3465 if (doc->extSubset == (xmlDtdPtr) cur)
3466 doc->extSubset = NULL;
3467 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003468 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003469 if (cur->parent != NULL) {
3470 xmlNodePtr parent;
3471 parent = cur->parent;
3472 if (cur->type == XML_ATTRIBUTE_NODE) {
3473 if (parent->properties == (xmlAttrPtr) cur)
3474 parent->properties = ((xmlAttrPtr) cur)->next;
3475 } else {
3476 if (parent->children == cur)
3477 parent->children = cur->next;
3478 if (parent->last == cur)
3479 parent->last = cur->prev;
3480 }
3481 cur->parent = NULL;
3482 }
Owen Taylor3473f882001-02-23 17:55:21 +00003483 if (cur->next != NULL)
3484 cur->next->prev = cur->prev;
3485 if (cur->prev != NULL)
3486 cur->prev->next = cur->next;
3487 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003488}
3489
Daniel Veillard2156d432004-03-04 15:59:36 +00003490#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003491/**
3492 * xmlReplaceNode:
3493 * @old: the old node
3494 * @cur: the node
3495 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003496 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003497 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003498 * first unlinked from its existing context.
3499 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003500 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003501 */
3502xmlNodePtr
3503xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00003504 if (old == cur) return(NULL);
Daniel Veillarda03e3652004-11-02 18:45:30 +00003505 if ((old == NULL) || (old->parent == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003506#ifdef DEBUG_TREE
3507 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda03e3652004-11-02 18:45:30 +00003508 "xmlReplaceNode : old == NULL or without parent\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003509#endif
3510 return(NULL);
3511 }
3512 if (cur == NULL) {
3513 xmlUnlinkNode(old);
3514 return(old);
3515 }
3516 if (cur == old) {
3517 return(old);
3518 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003519 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3520#ifdef DEBUG_TREE
3521 xmlGenericError(xmlGenericErrorContext,
3522 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3523#endif
3524 return(old);
3525 }
3526 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3527#ifdef DEBUG_TREE
3528 xmlGenericError(xmlGenericErrorContext,
3529 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3530#endif
3531 return(old);
3532 }
Owen Taylor3473f882001-02-23 17:55:21 +00003533 xmlUnlinkNode(cur);
Daniel Veillard64d7d122005-05-11 18:03:42 +00003534 xmlSetTreeDoc(cur, old->doc);
Owen Taylor3473f882001-02-23 17:55:21 +00003535 cur->parent = old->parent;
3536 cur->next = old->next;
3537 if (cur->next != NULL)
3538 cur->next->prev = cur;
3539 cur->prev = old->prev;
3540 if (cur->prev != NULL)
3541 cur->prev->next = cur;
3542 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003543 if (cur->type == XML_ATTRIBUTE_NODE) {
3544 if (cur->parent->properties == (xmlAttrPtr)old)
3545 cur->parent->properties = ((xmlAttrPtr) cur);
3546 } else {
3547 if (cur->parent->children == old)
3548 cur->parent->children = cur;
3549 if (cur->parent->last == old)
3550 cur->parent->last = cur;
3551 }
Owen Taylor3473f882001-02-23 17:55:21 +00003552 }
3553 old->next = old->prev = NULL;
3554 old->parent = NULL;
3555 return(old);
3556}
Daniel Veillard652327a2003-09-29 18:02:38 +00003557#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003558
3559/************************************************************************
3560 * *
3561 * Copy operations *
3562 * *
3563 ************************************************************************/
3564
3565/**
3566 * xmlCopyNamespace:
3567 * @cur: the namespace
3568 *
3569 * Do a copy of the namespace.
3570 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003571 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003572 */
3573xmlNsPtr
3574xmlCopyNamespace(xmlNsPtr cur) {
3575 xmlNsPtr ret;
3576
3577 if (cur == NULL) return(NULL);
3578 switch (cur->type) {
3579 case XML_LOCAL_NAMESPACE:
3580 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3581 break;
3582 default:
3583#ifdef DEBUG_TREE
3584 xmlGenericError(xmlGenericErrorContext,
3585 "xmlCopyNamespace: invalid type %d\n", cur->type);
3586#endif
3587 return(NULL);
3588 }
3589 return(ret);
3590}
3591
3592/**
3593 * xmlCopyNamespaceList:
3594 * @cur: the first namespace
3595 *
3596 * Do a copy of an namespace list.
3597 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003598 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003599 */
3600xmlNsPtr
3601xmlCopyNamespaceList(xmlNsPtr cur) {
3602 xmlNsPtr ret = NULL;
3603 xmlNsPtr p = NULL,q;
3604
3605 while (cur != NULL) {
3606 q = xmlCopyNamespace(cur);
3607 if (p == NULL) {
3608 ret = p = q;
3609 } else {
3610 p->next = q;
3611 p = q;
3612 }
3613 cur = cur->next;
3614 }
3615 return(ret);
3616}
3617
3618static xmlNodePtr
3619xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
Rob Richards19dc9612005-10-28 16:15:16 +00003620
3621static xmlAttrPtr
3622xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003623 xmlAttrPtr ret;
3624
3625 if (cur == NULL) return(NULL);
3626 if (target != NULL)
3627 ret = xmlNewDocProp(target->doc, cur->name, NULL);
Rob Richards19dc9612005-10-28 16:15:16 +00003628 else if (doc != NULL)
3629 ret = xmlNewDocProp(doc, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003630 else if (cur->parent != NULL)
3631 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3632 else if (cur->children != NULL)
3633 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3634 else
3635 ret = xmlNewDocProp(NULL, cur->name, NULL);
3636 if (ret == NULL) return(NULL);
3637 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003638
Owen Taylor3473f882001-02-23 17:55:21 +00003639 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003640 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003641
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003642 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3643 if (ns == NULL) {
3644 /*
3645 * Humm, we are copying an element whose namespace is defined
3646 * out of the new tree scope. Search it in the original tree
3647 * and add it at the top of the new tree
3648 */
3649 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3650 if (ns != NULL) {
3651 xmlNodePtr root = target;
3652 xmlNodePtr pred = NULL;
3653
3654 while (root->parent != NULL) {
3655 pred = root;
3656 root = root->parent;
3657 }
3658 if (root == (xmlNodePtr) target->doc) {
3659 /* correct possibly cycling above the document elt */
3660 root = pred;
3661 }
3662 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3663 }
3664 } else {
3665 /*
3666 * we have to find something appropriate here since
3667 * we cant be sure, that the namespce we found is identified
3668 * by the prefix
3669 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003670 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003671 /* this is the nice case */
3672 ret->ns = ns;
3673 } else {
3674 /*
3675 * we are in trouble: we need a new reconcilied namespace.
3676 * This is expensive
3677 */
3678 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3679 }
3680 }
3681
Owen Taylor3473f882001-02-23 17:55:21 +00003682 } else
3683 ret->ns = NULL;
3684
3685 if (cur->children != NULL) {
3686 xmlNodePtr tmp;
3687
3688 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3689 ret->last = NULL;
3690 tmp = ret->children;
3691 while (tmp != NULL) {
3692 /* tmp->parent = (xmlNodePtr)ret; */
3693 if (tmp->next == NULL)
3694 ret->last = tmp;
3695 tmp = tmp->next;
3696 }
3697 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003698 /*
3699 * Try to handle IDs
3700 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003701 if ((target!= NULL) && (cur!= NULL) &&
3702 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003703 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3704 if (xmlIsID(cur->doc, cur->parent, cur)) {
3705 xmlChar *id;
3706
3707 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3708 if (id != NULL) {
3709 xmlAddID(NULL, target->doc, id, ret);
3710 xmlFree(id);
3711 }
3712 }
3713 }
Owen Taylor3473f882001-02-23 17:55:21 +00003714 return(ret);
3715}
3716
3717/**
Rob Richards19dc9612005-10-28 16:15:16 +00003718 * xmlCopyProp:
3719 * @target: the element where the attribute will be grafted
3720 * @cur: the attribute
3721 *
3722 * Do a copy of the attribute.
3723 *
3724 * Returns: a new #xmlAttrPtr, or NULL in case of error.
3725 */
3726xmlAttrPtr
3727xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3728 return xmlCopyPropInternal(NULL, target, cur);
3729}
3730
3731/**
Owen Taylor3473f882001-02-23 17:55:21 +00003732 * xmlCopyPropList:
3733 * @target: the element where the attributes will be grafted
3734 * @cur: the first attribute
3735 *
3736 * Do a copy of an attribute list.
3737 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003738 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003739 */
3740xmlAttrPtr
3741xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3742 xmlAttrPtr ret = NULL;
3743 xmlAttrPtr p = NULL,q;
3744
3745 while (cur != NULL) {
3746 q = xmlCopyProp(target, cur);
William M. Brack13dfa872004-09-18 04:52:08 +00003747 if (q == NULL)
3748 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003749 if (p == NULL) {
3750 ret = p = q;
3751 } else {
3752 p->next = q;
3753 q->prev = p;
3754 p = q;
3755 }
3756 cur = cur->next;
3757 }
3758 return(ret);
3759}
3760
3761/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003762 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003763 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003764 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003765 * tricky reason: namespaces. Doing a direct copy of a node
3766 * say RPM:Copyright without changing the namespace pointer to
3767 * something else can produce stale links. One way to do it is
3768 * to keep a reference counter but this doesn't work as soon
3769 * as one move the element or the subtree out of the scope of
3770 * the existing namespace. The actual solution seems to add
3771 * a copy of the namespace at the top of the copied tree if
3772 * not available in the subtree.
3773 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00003774 * The argument "recursive" normally indicates a recursive copy
3775 * of the node with values 0 (no) and 1 (yes). For XInclude,
3776 * however, we allow a value of 2 to indicate copy properties and
3777 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00003778 */
3779
3780static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003781xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00003782 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003783 xmlNodePtr ret;
3784
3785 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003786 switch (node->type) {
3787 case XML_TEXT_NODE:
3788 case XML_CDATA_SECTION_NODE:
3789 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003790 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003791 case XML_ENTITY_REF_NODE:
3792 case XML_ENTITY_NODE:
3793 case XML_PI_NODE:
3794 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003795 case XML_XINCLUDE_START:
3796 case XML_XINCLUDE_END:
3797 break;
3798 case XML_ATTRIBUTE_NODE:
Rob Richards19dc9612005-10-28 16:15:16 +00003799 return((xmlNodePtr) xmlCopyPropInternal(doc, parent, (xmlAttrPtr) node));
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003800 case XML_NAMESPACE_DECL:
3801 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3802
Daniel Veillard39196eb2001-06-19 18:09:42 +00003803 case XML_DOCUMENT_NODE:
3804 case XML_HTML_DOCUMENT_NODE:
3805#ifdef LIBXML_DOCB_ENABLED
3806 case XML_DOCB_DOCUMENT_NODE:
3807#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003808#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00003809 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00003810#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003811 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003812 case XML_NOTATION_NODE:
3813 case XML_DTD_NODE:
3814 case XML_ELEMENT_DECL:
3815 case XML_ATTRIBUTE_DECL:
3816 case XML_ENTITY_DECL:
3817 return(NULL);
3818 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003819
Owen Taylor3473f882001-02-23 17:55:21 +00003820 /*
3821 * Allocate a new node and fill the fields.
3822 */
3823 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3824 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003825 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003826 return(NULL);
3827 }
3828 memset(ret, 0, sizeof(xmlNode));
3829 ret->type = node->type;
3830
3831 ret->doc = doc;
3832 ret->parent = parent;
3833 if (node->name == xmlStringText)
3834 ret->name = xmlStringText;
3835 else if (node->name == xmlStringTextNoenc)
3836 ret->name = xmlStringTextNoenc;
3837 else if (node->name == xmlStringComment)
3838 ret->name = xmlStringComment;
Daniel Veillard03a53c32004-10-26 16:06:51 +00003839 else if (node->name != NULL) {
3840 if ((doc != NULL) && (doc->dict != NULL))
3841 ret->name = xmlDictLookup(doc->dict, node->name, -1);
3842 else
3843 ret->name = xmlStrdup(node->name);
3844 }
Daniel Veillard7db37732001-07-12 01:20:08 +00003845 if ((node->type != XML_ELEMENT_NODE) &&
3846 (node->content != NULL) &&
3847 (node->type != XML_ENTITY_REF_NODE) &&
3848 (node->type != XML_XINCLUDE_END) &&
3849 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003850 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003851 }else{
3852 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003853 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003854 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003855 if (parent != NULL) {
3856 xmlNodePtr tmp;
3857
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003858 /*
3859 * this is a tricky part for the node register thing:
3860 * in case ret does get coalesced in xmlAddChild
3861 * the deregister-node callback is called; so we register ret now already
3862 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003863 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003864 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3865
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003866 tmp = xmlAddChild(parent, ret);
3867 /* node could have coalesced */
3868 if (tmp != ret)
3869 return(tmp);
3870 }
Owen Taylor3473f882001-02-23 17:55:21 +00003871
William M. Brack57e9e912004-03-09 16:19:02 +00003872 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003873 goto out;
Daniel Veillard8874b942005-08-25 13:19:21 +00003874 if ((node->type == XML_ELEMENT_NODE) && (node->nsDef != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00003875 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3876
3877 if (node->ns != NULL) {
3878 xmlNsPtr ns;
3879
3880 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3881 if (ns == NULL) {
3882 /*
3883 * Humm, we are copying an element whose namespace is defined
3884 * out of the new tree scope. Search it in the original tree
3885 * and add it at the top of the new tree
3886 */
3887 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3888 if (ns != NULL) {
3889 xmlNodePtr root = ret;
3890
3891 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003892 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003893 }
3894 } else {
3895 /*
3896 * reference the existing namespace definition in our own tree.
3897 */
3898 ret->ns = ns;
3899 }
3900 }
Daniel Veillard8874b942005-08-25 13:19:21 +00003901 if ((node->type == XML_ELEMENT_NODE) && (node->properties != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00003902 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003903 if (node->type == XML_ENTITY_REF_NODE) {
3904 if ((doc == NULL) || (node->doc != doc)) {
3905 /*
3906 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003907 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003908 * we cannot keep the reference. Try to find it in the
3909 * target document.
3910 */
3911 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3912 } else {
3913 ret->children = node->children;
3914 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003915 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00003916 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003917 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003918 UPDATE_LAST_CHILD_AND_PARENT(ret)
3919 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003920
3921out:
3922 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00003923 if ((parent == NULL) &&
3924 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003925 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003926 return(ret);
3927}
3928
3929static xmlNodePtr
3930xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3931 xmlNodePtr ret = NULL;
3932 xmlNodePtr p = NULL,q;
3933
3934 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003935#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003936 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003937 if (doc == NULL) {
3938 node = node->next;
3939 continue;
3940 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003941 if (doc->intSubset == NULL) {
3942 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3943 q->doc = doc;
3944 q->parent = parent;
3945 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003946 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003947 } else {
3948 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003949 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003950 }
3951 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003952#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003953 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003954 if (ret == NULL) {
3955 q->prev = NULL;
3956 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003957 } else if (p != q) {
3958 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003959 p->next = q;
3960 q->prev = p;
3961 p = q;
3962 }
3963 node = node->next;
3964 }
3965 return(ret);
3966}
3967
3968/**
3969 * xmlCopyNode:
3970 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00003971 * @extended: if 1 do a recursive copy (properties, namespaces and children
3972 * when applicable)
3973 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00003974 *
3975 * Do a copy of the node.
3976 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003977 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003978 */
3979xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003980xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003981 xmlNodePtr ret;
3982
William M. Brack57e9e912004-03-09 16:19:02 +00003983 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00003984 return(ret);
3985}
3986
3987/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003988 * xmlDocCopyNode:
3989 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003990 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00003991 * @extended: if 1 do a recursive copy (properties, namespaces and children
3992 * when applicable)
3993 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00003994 *
3995 * Do a copy of the node to a given document.
3996 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003997 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003998 */
3999xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00004000xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00004001 xmlNodePtr ret;
4002
William M. Brack57e9e912004-03-09 16:19:02 +00004003 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00004004 return(ret);
4005}
4006
4007/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00004008 * xmlDocCopyNodeList:
4009 * @doc: the target document
4010 * @node: the first node in the list.
4011 *
4012 * Do a recursive copy of the node list.
4013 *
4014 * Returns: a new #xmlNodePtr, or NULL in case of error.
4015 */
4016xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) {
4017 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
4018 return(ret);
4019}
4020
4021/**
Owen Taylor3473f882001-02-23 17:55:21 +00004022 * xmlCopyNodeList:
4023 * @node: the first node in the list.
4024 *
4025 * Do a recursive copy of the node list.
Daniel Veillard03a53c32004-10-26 16:06:51 +00004026 * Use xmlDocCopyNodeList() if possible to ensure string interning.
Owen Taylor3473f882001-02-23 17:55:21 +00004027 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004028 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004029 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00004030xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00004031 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
4032 return(ret);
4033}
4034
Daniel Veillard2156d432004-03-04 15:59:36 +00004035#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004036/**
Owen Taylor3473f882001-02-23 17:55:21 +00004037 * xmlCopyDtd:
4038 * @dtd: the dtd
4039 *
4040 * Do a copy of the dtd.
4041 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004042 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004043 */
4044xmlDtdPtr
4045xmlCopyDtd(xmlDtdPtr dtd) {
4046 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004047 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00004048
4049 if (dtd == NULL) return(NULL);
4050 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4051 if (ret == NULL) return(NULL);
4052 if (dtd->entities != NULL)
4053 ret->entities = (void *) xmlCopyEntitiesTable(
4054 (xmlEntitiesTablePtr) dtd->entities);
4055 if (dtd->notations != NULL)
4056 ret->notations = (void *) xmlCopyNotationTable(
4057 (xmlNotationTablePtr) dtd->notations);
4058 if (dtd->elements != NULL)
4059 ret->elements = (void *) xmlCopyElementTable(
4060 (xmlElementTablePtr) dtd->elements);
4061 if (dtd->attributes != NULL)
4062 ret->attributes = (void *) xmlCopyAttributeTable(
4063 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004064 if (dtd->pentities != NULL)
4065 ret->pentities = (void *) xmlCopyEntitiesTable(
4066 (xmlEntitiesTablePtr) dtd->pentities);
4067
4068 cur = dtd->children;
4069 while (cur != NULL) {
4070 q = NULL;
4071
4072 if (cur->type == XML_ENTITY_DECL) {
4073 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4074 switch (tmp->etype) {
4075 case XML_INTERNAL_GENERAL_ENTITY:
4076 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4077 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4078 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4079 break;
4080 case XML_INTERNAL_PARAMETER_ENTITY:
4081 case XML_EXTERNAL_PARAMETER_ENTITY:
4082 q = (xmlNodePtr)
4083 xmlGetParameterEntityFromDtd(ret, tmp->name);
4084 break;
4085 case XML_INTERNAL_PREDEFINED_ENTITY:
4086 break;
4087 }
4088 } else if (cur->type == XML_ELEMENT_DECL) {
4089 xmlElementPtr tmp = (xmlElementPtr) cur;
4090 q = (xmlNodePtr)
4091 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4092 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4093 xmlAttributePtr tmp = (xmlAttributePtr) cur;
4094 q = (xmlNodePtr)
4095 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4096 } else if (cur->type == XML_COMMENT_NODE) {
4097 q = xmlCopyNode(cur, 0);
4098 }
4099
4100 if (q == NULL) {
4101 cur = cur->next;
4102 continue;
4103 }
4104
4105 if (p == NULL)
4106 ret->children = q;
4107 else
4108 p->next = q;
4109
4110 q->prev = p;
4111 q->parent = (xmlNodePtr) ret;
4112 q->next = NULL;
4113 ret->last = q;
4114 p = q;
4115 cur = cur->next;
4116 }
4117
Owen Taylor3473f882001-02-23 17:55:21 +00004118 return(ret);
4119}
Daniel Veillard2156d432004-03-04 15:59:36 +00004120#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004121
Daniel Veillard2156d432004-03-04 15:59:36 +00004122#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004123/**
4124 * xmlCopyDoc:
4125 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004126 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004127 *
4128 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004129 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004130 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004131 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004132 */
4133xmlDocPtr
4134xmlCopyDoc(xmlDocPtr doc, int recursive) {
4135 xmlDocPtr ret;
4136
4137 if (doc == NULL) return(NULL);
4138 ret = xmlNewDoc(doc->version);
4139 if (ret == NULL) return(NULL);
4140 if (doc->name != NULL)
4141 ret->name = xmlMemStrdup(doc->name);
4142 if (doc->encoding != NULL)
4143 ret->encoding = xmlStrdup(doc->encoding);
Daniel Veillardf59507d2005-01-27 17:26:49 +00004144 if (doc->URL != NULL)
4145 ret->URL = xmlStrdup(doc->URL);
Owen Taylor3473f882001-02-23 17:55:21 +00004146 ret->charset = doc->charset;
4147 ret->compression = doc->compression;
4148 ret->standalone = doc->standalone;
4149 if (!recursive) return(ret);
4150
Daniel Veillardb33c2012001-04-25 12:59:04 +00004151 ret->last = NULL;
4152 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004153#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004154 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004155 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004156 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004157 ret->intSubset->parent = ret;
4158 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004159#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004160 if (doc->oldNs != NULL)
4161 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4162 if (doc->children != NULL) {
4163 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004164
4165 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4166 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004167 ret->last = NULL;
4168 tmp = ret->children;
4169 while (tmp != NULL) {
4170 if (tmp->next == NULL)
4171 ret->last = tmp;
4172 tmp = tmp->next;
4173 }
4174 }
4175 return(ret);
4176}
Daniel Veillard652327a2003-09-29 18:02:38 +00004177#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004178
4179/************************************************************************
4180 * *
4181 * Content access functions *
4182 * *
4183 ************************************************************************/
4184
4185/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004186 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004187 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004188 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004189 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004190 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004191 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004192 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004193 */
4194long
4195xmlGetLineNo(xmlNodePtr node)
4196{
4197 long result = -1;
4198
4199 if (!node)
4200 return result;
Daniel Veillard73da77e2005-08-24 14:05:37 +00004201 if ((node->type == XML_ELEMENT_NODE) ||
4202 (node->type == XML_TEXT_NODE) ||
4203 (node->type == XML_COMMENT_NODE) ||
4204 (node->type == XML_PI_NODE))
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004205 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004206 else if ((node->prev != NULL) &&
4207 ((node->prev->type == XML_ELEMENT_NODE) ||
Daniel Veillard73da77e2005-08-24 14:05:37 +00004208 (node->prev->type == XML_TEXT_NODE) ||
4209 (node->prev->type == XML_COMMENT_NODE) ||
4210 (node->prev->type == XML_PI_NODE)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004211 result = xmlGetLineNo(node->prev);
4212 else if ((node->parent != NULL) &&
Daniel Veillard73da77e2005-08-24 14:05:37 +00004213 (node->parent->type == XML_ELEMENT_NODE))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004214 result = xmlGetLineNo(node->parent);
4215
4216 return result;
4217}
4218
Daniel Veillard2156d432004-03-04 15:59:36 +00004219#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004220/**
4221 * xmlGetNodePath:
4222 * @node: a node
4223 *
4224 * Build a structure based Path for the given node
4225 *
4226 * Returns the new path or NULL in case of error. The caller must free
4227 * the returned string
4228 */
4229xmlChar *
4230xmlGetNodePath(xmlNodePtr node)
4231{
4232 xmlNodePtr cur, tmp, next;
4233 xmlChar *buffer = NULL, *temp;
4234 size_t buf_len;
4235 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004236 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004237 const char *name;
4238 char nametemp[100];
4239 int occur = 0;
4240
4241 if (node == NULL)
4242 return (NULL);
4243
4244 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004245 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004246 if (buffer == NULL) {
4247 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004248 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004249 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004250 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004251 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004252 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004253 xmlFree(buffer);
4254 return (NULL);
4255 }
4256
4257 buffer[0] = 0;
4258 cur = node;
4259 do {
4260 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004261 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004262 occur = 0;
4263 if ((cur->type == XML_DOCUMENT_NODE) ||
4264 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4265 if (buffer[0] == '/')
4266 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004267 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004268 next = NULL;
4269 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004270 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004271 name = (const char *) cur->name;
4272 if (cur->ns) {
William M. Brack84d83e32003-12-23 03:45:17 +00004273 if (cur->ns->prefix != NULL)
William M. Brack13dfa872004-09-18 04:52:08 +00004274 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4275 (char *)cur->ns->prefix, (char *)cur->name);
William M. Brack84d83e32003-12-23 03:45:17 +00004276 else
William M. Brack13dfa872004-09-18 04:52:08 +00004277 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4278 (char *)cur->name);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004279 nametemp[sizeof(nametemp) - 1] = 0;
4280 name = nametemp;
4281 }
4282 next = cur->parent;
4283
4284 /*
4285 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004286 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004287 */
4288 tmp = cur->prev;
4289 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004290 if ((tmp->type == XML_ELEMENT_NODE) &&
Daniel Veillard0996a162005-02-05 14:00:10 +00004291 (xmlStrEqual(cur->name, tmp->name)) &&
4292 ((tmp->ns == cur->ns) ||
4293 ((tmp->ns != NULL) && (cur->ns != NULL) &&
4294 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004295 occur++;
4296 tmp = tmp->prev;
4297 }
4298 if (occur == 0) {
4299 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004300 while (tmp != NULL && occur == 0) {
4301 if ((tmp->type == XML_ELEMENT_NODE) &&
Daniel Veillard0996a162005-02-05 14:00:10 +00004302 (xmlStrEqual(cur->name, tmp->name)) &&
4303 ((tmp->ns == cur->ns) ||
4304 ((tmp->ns != NULL) && (cur->ns != NULL) &&
4305 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004306 occur++;
4307 tmp = tmp->next;
4308 }
4309 if (occur != 0)
4310 occur = 1;
4311 } else
4312 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004313 } else if (cur->type == XML_COMMENT_NODE) {
4314 sep = "/";
4315 name = "comment()";
4316 next = cur->parent;
4317
4318 /*
4319 * Thumbler index computation
4320 */
4321 tmp = cur->prev;
4322 while (tmp != NULL) {
4323 if (tmp->type == XML_COMMENT_NODE)
4324 occur++;
4325 tmp = tmp->prev;
4326 }
4327 if (occur == 0) {
4328 tmp = cur->next;
4329 while (tmp != NULL && occur == 0) {
4330 if (tmp->type == XML_COMMENT_NODE)
4331 occur++;
4332 tmp = tmp->next;
4333 }
4334 if (occur != 0)
4335 occur = 1;
4336 } else
4337 occur++;
4338 } else if ((cur->type == XML_TEXT_NODE) ||
4339 (cur->type == XML_CDATA_SECTION_NODE)) {
4340 sep = "/";
4341 name = "text()";
4342 next = cur->parent;
4343
4344 /*
4345 * Thumbler index computation
4346 */
4347 tmp = cur->prev;
4348 while (tmp != NULL) {
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004349 if ((tmp->type == XML_TEXT_NODE) ||
4350 (tmp->type == XML_CDATA_SECTION_NODE))
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004351 occur++;
4352 tmp = tmp->prev;
4353 }
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004354 /*
4355 * Evaluate if this is the only text- or CDATA-section-node;
4356 * if yes, then we'll get "text()", otherwise "text()[1]".
4357 */
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004358 if (occur == 0) {
4359 tmp = cur->next;
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004360 while (tmp != NULL) {
4361 if ((tmp->type == XML_TEXT_NODE) ||
4362 (tmp->type == XML_CDATA_SECTION_NODE))
4363 {
4364 occur = 1;
4365 break;
4366 }
4367 tmp = tmp->next;
4368 }
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004369 } else
4370 occur++;
4371 } else if (cur->type == XML_PI_NODE) {
4372 sep = "/";
4373 snprintf(nametemp, sizeof(nametemp) - 1,
William M. Brack13dfa872004-09-18 04:52:08 +00004374 "processing-instruction('%s')", (char *)cur->name);
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004375 nametemp[sizeof(nametemp) - 1] = 0;
4376 name = nametemp;
4377
4378 next = cur->parent;
4379
4380 /*
4381 * Thumbler index computation
4382 */
4383 tmp = cur->prev;
4384 while (tmp != NULL) {
4385 if ((tmp->type == XML_PI_NODE) &&
4386 (xmlStrEqual(cur->name, tmp->name)))
4387 occur++;
4388 tmp = tmp->prev;
4389 }
4390 if (occur == 0) {
4391 tmp = cur->next;
4392 while (tmp != NULL && occur == 0) {
4393 if ((tmp->type == XML_PI_NODE) &&
4394 (xmlStrEqual(cur->name, tmp->name)))
4395 occur++;
4396 tmp = tmp->next;
4397 }
4398 if (occur != 0)
4399 occur = 1;
4400 } else
4401 occur++;
4402
Daniel Veillard8faa7832001-11-26 15:58:08 +00004403 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004404 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004405 name = (const char *) (((xmlAttrPtr) cur)->name);
Daniel Veillard365c8062005-07-19 11:31:55 +00004406 if (cur->ns) {
4407 if (cur->ns->prefix != NULL)
4408 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4409 (char *)cur->ns->prefix, (char *)cur->name);
4410 else
4411 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4412 (char *)cur->name);
4413 nametemp[sizeof(nametemp) - 1] = 0;
4414 name = nametemp;
4415 }
Daniel Veillard8faa7832001-11-26 15:58:08 +00004416 next = ((xmlAttrPtr) cur)->parent;
4417 } else {
4418 next = cur->parent;
4419 }
4420
4421 /*
4422 * Make sure there is enough room
4423 */
4424 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4425 buf_len =
4426 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4427 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4428 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004429 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004430 xmlFree(buf);
4431 xmlFree(buffer);
4432 return (NULL);
4433 }
4434 buffer = temp;
4435 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4436 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004437 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004438 xmlFree(buf);
4439 xmlFree(buffer);
4440 return (NULL);
4441 }
4442 buf = temp;
4443 }
4444 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004445 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004446 sep, name, (char *) buffer);
4447 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004448 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004449 sep, name, occur, (char *) buffer);
William M. Brack13dfa872004-09-18 04:52:08 +00004450 snprintf((char *) buffer, buf_len, "%s", (char *)buf);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004451 cur = next;
4452 } while (cur != NULL);
4453 xmlFree(buf);
4454 return (buffer);
4455}
Daniel Veillard652327a2003-09-29 18:02:38 +00004456#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004457
4458/**
Owen Taylor3473f882001-02-23 17:55:21 +00004459 * xmlDocGetRootElement:
4460 * @doc: the document
4461 *
4462 * Get the root element of the document (doc->children is a list
4463 * containing possibly comments, PIs, etc ...).
4464 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004465 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004466 */
4467xmlNodePtr
4468xmlDocGetRootElement(xmlDocPtr doc) {
4469 xmlNodePtr ret;
4470
4471 if (doc == NULL) return(NULL);
4472 ret = doc->children;
4473 while (ret != NULL) {
4474 if (ret->type == XML_ELEMENT_NODE)
4475 return(ret);
4476 ret = ret->next;
4477 }
4478 return(ret);
4479}
4480
Daniel Veillard2156d432004-03-04 15:59:36 +00004481#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004482/**
4483 * xmlDocSetRootElement:
4484 * @doc: the document
4485 * @root: the new document root element
4486 *
4487 * Set the root element of the document (doc->children is a list
4488 * containing possibly comments, PIs, etc ...).
4489 *
4490 * Returns the old root element if any was found
4491 */
4492xmlNodePtr
4493xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4494 xmlNodePtr old = NULL;
4495
4496 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004497 if (root == NULL)
4498 return(NULL);
4499 xmlUnlinkNode(root);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00004500 xmlSetTreeDoc(root, doc);
Daniel Veillardc575b992002-02-08 13:28:40 +00004501 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004502 old = doc->children;
4503 while (old != NULL) {
4504 if (old->type == XML_ELEMENT_NODE)
4505 break;
4506 old = old->next;
4507 }
4508 if (old == NULL) {
4509 if (doc->children == NULL) {
4510 doc->children = root;
4511 doc->last = root;
4512 } else {
4513 xmlAddSibling(doc->children, root);
4514 }
4515 } else {
4516 xmlReplaceNode(old, root);
4517 }
4518 return(old);
4519}
Daniel Veillard2156d432004-03-04 15:59:36 +00004520#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004521
Daniel Veillard2156d432004-03-04 15:59:36 +00004522#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004523/**
4524 * xmlNodeSetLang:
4525 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004526 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004527 *
4528 * Set the language of a node, i.e. the values of the xml:lang
4529 * attribute.
4530 */
4531void
4532xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004533 xmlNsPtr ns;
4534
Owen Taylor3473f882001-02-23 17:55:21 +00004535 if (cur == NULL) return;
4536 switch(cur->type) {
4537 case XML_TEXT_NODE:
4538 case XML_CDATA_SECTION_NODE:
4539 case XML_COMMENT_NODE:
4540 case XML_DOCUMENT_NODE:
4541 case XML_DOCUMENT_TYPE_NODE:
4542 case XML_DOCUMENT_FRAG_NODE:
4543 case XML_NOTATION_NODE:
4544 case XML_HTML_DOCUMENT_NODE:
4545 case XML_DTD_NODE:
4546 case XML_ELEMENT_DECL:
4547 case XML_ATTRIBUTE_DECL:
4548 case XML_ENTITY_DECL:
4549 case XML_PI_NODE:
4550 case XML_ENTITY_REF_NODE:
4551 case XML_ENTITY_NODE:
4552 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004553#ifdef LIBXML_DOCB_ENABLED
4554 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004555#endif
4556 case XML_XINCLUDE_START:
4557 case XML_XINCLUDE_END:
4558 return;
4559 case XML_ELEMENT_NODE:
4560 case XML_ATTRIBUTE_NODE:
4561 break;
4562 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004563 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4564 if (ns == NULL)
4565 return;
4566 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004567}
Daniel Veillard652327a2003-09-29 18:02:38 +00004568#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004569
4570/**
4571 * xmlNodeGetLang:
4572 * @cur: the node being checked
4573 *
4574 * Searches the language of a node, i.e. the values of the xml:lang
4575 * attribute or the one carried by the nearest ancestor.
4576 *
4577 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004578 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004579 */
4580xmlChar *
4581xmlNodeGetLang(xmlNodePtr cur) {
4582 xmlChar *lang;
4583
4584 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004585 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004586 if (lang != NULL)
4587 return(lang);
4588 cur = cur->parent;
4589 }
4590 return(NULL);
4591}
4592
4593
Daniel Veillard652327a2003-09-29 18:02:38 +00004594#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004595/**
4596 * xmlNodeSetSpacePreserve:
4597 * @cur: the node being changed
4598 * @val: the xml:space value ("0": default, 1: "preserve")
4599 *
4600 * Set (or reset) the space preserving behaviour of a node, i.e. the
4601 * value of the xml:space attribute.
4602 */
4603void
4604xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004605 xmlNsPtr ns;
4606
Owen Taylor3473f882001-02-23 17:55:21 +00004607 if (cur == NULL) return;
4608 switch(cur->type) {
4609 case XML_TEXT_NODE:
4610 case XML_CDATA_SECTION_NODE:
4611 case XML_COMMENT_NODE:
4612 case XML_DOCUMENT_NODE:
4613 case XML_DOCUMENT_TYPE_NODE:
4614 case XML_DOCUMENT_FRAG_NODE:
4615 case XML_NOTATION_NODE:
4616 case XML_HTML_DOCUMENT_NODE:
4617 case XML_DTD_NODE:
4618 case XML_ELEMENT_DECL:
4619 case XML_ATTRIBUTE_DECL:
4620 case XML_ENTITY_DECL:
4621 case XML_PI_NODE:
4622 case XML_ENTITY_REF_NODE:
4623 case XML_ENTITY_NODE:
4624 case XML_NAMESPACE_DECL:
4625 case XML_XINCLUDE_START:
4626 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004627#ifdef LIBXML_DOCB_ENABLED
4628 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004629#endif
4630 return;
4631 case XML_ELEMENT_NODE:
4632 case XML_ATTRIBUTE_NODE:
4633 break;
4634 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004635 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4636 if (ns == NULL)
4637 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004638 switch (val) {
4639 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004640 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004641 break;
4642 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004643 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004644 break;
4645 }
4646}
Daniel Veillard652327a2003-09-29 18:02:38 +00004647#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004648
4649/**
4650 * xmlNodeGetSpacePreserve:
4651 * @cur: the node being checked
4652 *
4653 * Searches the space preserving behaviour of a node, i.e. the values
4654 * of the xml:space attribute or the one carried by the nearest
4655 * ancestor.
4656 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004657 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004658 */
4659int
4660xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4661 xmlChar *space;
4662
4663 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004664 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004665 if (space != NULL) {
4666 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4667 xmlFree(space);
4668 return(1);
4669 }
4670 if (xmlStrEqual(space, BAD_CAST "default")) {
4671 xmlFree(space);
4672 return(0);
4673 }
4674 xmlFree(space);
4675 }
4676 cur = cur->parent;
4677 }
4678 return(-1);
4679}
4680
Daniel Veillard652327a2003-09-29 18:02:38 +00004681#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004682/**
4683 * xmlNodeSetName:
4684 * @cur: the node being changed
4685 * @name: the new tag name
4686 *
4687 * Set (or reset) the name of a node.
4688 */
4689void
4690xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00004691 xmlDocPtr doc;
4692 xmlDictPtr dict;
4693
Owen Taylor3473f882001-02-23 17:55:21 +00004694 if (cur == NULL) return;
4695 if (name == NULL) return;
4696 switch(cur->type) {
4697 case XML_TEXT_NODE:
4698 case XML_CDATA_SECTION_NODE:
4699 case XML_COMMENT_NODE:
4700 case XML_DOCUMENT_TYPE_NODE:
4701 case XML_DOCUMENT_FRAG_NODE:
4702 case XML_NOTATION_NODE:
4703 case XML_HTML_DOCUMENT_NODE:
4704 case XML_NAMESPACE_DECL:
4705 case XML_XINCLUDE_START:
4706 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004707#ifdef LIBXML_DOCB_ENABLED
4708 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004709#endif
4710 return;
4711 case XML_ELEMENT_NODE:
4712 case XML_ATTRIBUTE_NODE:
4713 case XML_PI_NODE:
4714 case XML_ENTITY_REF_NODE:
4715 case XML_ENTITY_NODE:
4716 case XML_DTD_NODE:
4717 case XML_DOCUMENT_NODE:
4718 case XML_ELEMENT_DECL:
4719 case XML_ATTRIBUTE_DECL:
4720 case XML_ENTITY_DECL:
4721 break;
4722 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00004723 doc = cur->doc;
4724 if (doc != NULL)
4725 dict = doc->dict;
4726 else
4727 dict = NULL;
4728 if (dict != NULL) {
4729 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
4730 xmlFree((xmlChar *) cur->name);
4731 cur->name = xmlDictLookup(dict, name, -1);
4732 } else {
4733 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4734 cur->name = xmlStrdup(name);
4735 }
Owen Taylor3473f882001-02-23 17:55:21 +00004736}
Daniel Veillard2156d432004-03-04 15:59:36 +00004737#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004738
Daniel Veillard2156d432004-03-04 15:59:36 +00004739#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004740/**
4741 * xmlNodeSetBase:
4742 * @cur: the node being changed
4743 * @uri: the new base URI
4744 *
4745 * Set (or reset) the base URI of a node, i.e. the value of the
4746 * xml:base attribute.
4747 */
4748void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004749xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004750 xmlNsPtr ns;
4751
Owen Taylor3473f882001-02-23 17:55:21 +00004752 if (cur == NULL) return;
4753 switch(cur->type) {
4754 case XML_TEXT_NODE:
4755 case XML_CDATA_SECTION_NODE:
4756 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004757 case XML_DOCUMENT_TYPE_NODE:
4758 case XML_DOCUMENT_FRAG_NODE:
4759 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004760 case XML_DTD_NODE:
4761 case XML_ELEMENT_DECL:
4762 case XML_ATTRIBUTE_DECL:
4763 case XML_ENTITY_DECL:
4764 case XML_PI_NODE:
4765 case XML_ENTITY_REF_NODE:
4766 case XML_ENTITY_NODE:
4767 case XML_NAMESPACE_DECL:
4768 case XML_XINCLUDE_START:
4769 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004770 return;
4771 case XML_ELEMENT_NODE:
4772 case XML_ATTRIBUTE_NODE:
4773 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004774 case XML_DOCUMENT_NODE:
4775#ifdef LIBXML_DOCB_ENABLED
4776 case XML_DOCB_DOCUMENT_NODE:
4777#endif
4778 case XML_HTML_DOCUMENT_NODE: {
4779 xmlDocPtr doc = (xmlDocPtr) cur;
4780
4781 if (doc->URL != NULL)
4782 xmlFree((xmlChar *) doc->URL);
4783 if (uri == NULL)
4784 doc->URL = NULL;
4785 else
4786 doc->URL = xmlStrdup(uri);
4787 return;
4788 }
Owen Taylor3473f882001-02-23 17:55:21 +00004789 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004790
4791 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4792 if (ns == NULL)
4793 return;
4794 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004795}
Daniel Veillard652327a2003-09-29 18:02:38 +00004796#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004797
4798/**
Owen Taylor3473f882001-02-23 17:55:21 +00004799 * xmlNodeGetBase:
4800 * @doc: the document the node pertains to
4801 * @cur: the node being checked
4802 *
4803 * Searches for the BASE URL. The code should work on both XML
4804 * and HTML document even if base mechanisms are completely different.
4805 * It returns the base as defined in RFC 2396 sections
4806 * 5.1.1. Base URI within Document Content
4807 * and
4808 * 5.1.2. Base URI from the Encapsulating Entity
4809 * However it does not return the document base (5.1.3), use
4810 * xmlDocumentGetBase() for this
4811 *
4812 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004813 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004814 */
4815xmlChar *
4816xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004817 xmlChar *oldbase = NULL;
4818 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004819
4820 if ((cur == NULL) && (doc == NULL))
4821 return(NULL);
4822 if (doc == NULL) doc = cur->doc;
4823 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4824 cur = doc->children;
4825 while ((cur != NULL) && (cur->name != NULL)) {
4826 if (cur->type != XML_ELEMENT_NODE) {
4827 cur = cur->next;
4828 continue;
4829 }
4830 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4831 cur = cur->children;
4832 continue;
4833 }
4834 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4835 cur = cur->children;
4836 continue;
4837 }
4838 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4839 return(xmlGetProp(cur, BAD_CAST "href"));
4840 }
4841 cur = cur->next;
4842 }
4843 return(NULL);
4844 }
4845 while (cur != NULL) {
4846 if (cur->type == XML_ENTITY_DECL) {
4847 xmlEntityPtr ent = (xmlEntityPtr) cur;
4848 return(xmlStrdup(ent->URI));
4849 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004850 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004851 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004852 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004853 if (oldbase != NULL) {
4854 newbase = xmlBuildURI(oldbase, base);
4855 if (newbase != NULL) {
4856 xmlFree(oldbase);
4857 xmlFree(base);
4858 oldbase = newbase;
4859 } else {
4860 xmlFree(oldbase);
4861 xmlFree(base);
4862 return(NULL);
4863 }
4864 } else {
4865 oldbase = base;
4866 }
4867 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4868 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4869 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4870 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004871 }
4872 }
Owen Taylor3473f882001-02-23 17:55:21 +00004873 cur = cur->parent;
4874 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004875 if ((doc != NULL) && (doc->URL != NULL)) {
4876 if (oldbase == NULL)
4877 return(xmlStrdup(doc->URL));
4878 newbase = xmlBuildURI(oldbase, doc->URL);
4879 xmlFree(oldbase);
4880 return(newbase);
4881 }
4882 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004883}
4884
4885/**
Daniel Veillard78697292003-10-19 20:44:43 +00004886 * xmlNodeBufGetContent:
4887 * @buffer: a buffer
4888 * @cur: the node being read
4889 *
4890 * Read the value of a node @cur, this can be either the text carried
4891 * directly by this node if it's a TEXT node or the aggregate string
4892 * of the values carried by this node child's (TEXT and ENTITY_REF).
4893 * Entity references are substituted.
4894 * Fills up the buffer @buffer with this value
4895 *
4896 * Returns 0 in case of success and -1 in case of error.
4897 */
4898int
4899xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4900{
4901 if ((cur == NULL) || (buffer == NULL)) return(-1);
4902 switch (cur->type) {
4903 case XML_CDATA_SECTION_NODE:
4904 case XML_TEXT_NODE:
4905 xmlBufferCat(buffer, cur->content);
4906 break;
4907 case XML_DOCUMENT_FRAG_NODE:
4908 case XML_ELEMENT_NODE:{
4909 xmlNodePtr tmp = cur;
4910
4911 while (tmp != NULL) {
4912 switch (tmp->type) {
4913 case XML_CDATA_SECTION_NODE:
4914 case XML_TEXT_NODE:
4915 if (tmp->content != NULL)
4916 xmlBufferCat(buffer, tmp->content);
4917 break;
4918 case XML_ENTITY_REF_NODE:
Rob Richards77b92ff2005-12-20 15:55:14 +00004919 xmlNodeBufGetContent(buffer, tmp);
4920 break;
Daniel Veillard78697292003-10-19 20:44:43 +00004921 default:
4922 break;
4923 }
4924 /*
4925 * Skip to next node
4926 */
4927 if (tmp->children != NULL) {
4928 if (tmp->children->type != XML_ENTITY_DECL) {
4929 tmp = tmp->children;
4930 continue;
4931 }
4932 }
4933 if (tmp == cur)
4934 break;
4935
4936 if (tmp->next != NULL) {
4937 tmp = tmp->next;
4938 continue;
4939 }
4940
4941 do {
4942 tmp = tmp->parent;
4943 if (tmp == NULL)
4944 break;
4945 if (tmp == cur) {
4946 tmp = NULL;
4947 break;
4948 }
4949 if (tmp->next != NULL) {
4950 tmp = tmp->next;
4951 break;
4952 }
4953 } while (tmp != NULL);
4954 }
4955 break;
4956 }
4957 case XML_ATTRIBUTE_NODE:{
4958 xmlAttrPtr attr = (xmlAttrPtr) cur;
4959 xmlNodePtr tmp = attr->children;
4960
4961 while (tmp != NULL) {
4962 if (tmp->type == XML_TEXT_NODE)
4963 xmlBufferCat(buffer, tmp->content);
4964 else
4965 xmlNodeBufGetContent(buffer, tmp);
4966 tmp = tmp->next;
4967 }
4968 break;
4969 }
4970 case XML_COMMENT_NODE:
4971 case XML_PI_NODE:
4972 xmlBufferCat(buffer, cur->content);
4973 break;
4974 case XML_ENTITY_REF_NODE:{
4975 xmlEntityPtr ent;
4976 xmlNodePtr tmp;
4977
4978 /* lookup entity declaration */
4979 ent = xmlGetDocEntity(cur->doc, cur->name);
4980 if (ent == NULL)
4981 return(-1);
4982
4983 /* an entity content can be any "well balanced chunk",
4984 * i.e. the result of the content [43] production:
4985 * http://www.w3.org/TR/REC-xml#NT-content
4986 * -> we iterate through child nodes and recursive call
4987 * xmlNodeGetContent() which handles all possible node types */
4988 tmp = ent->children;
4989 while (tmp) {
4990 xmlNodeBufGetContent(buffer, tmp);
4991 tmp = tmp->next;
4992 }
4993 break;
4994 }
4995 case XML_ENTITY_NODE:
4996 case XML_DOCUMENT_TYPE_NODE:
4997 case XML_NOTATION_NODE:
4998 case XML_DTD_NODE:
4999 case XML_XINCLUDE_START:
5000 case XML_XINCLUDE_END:
5001 break;
5002 case XML_DOCUMENT_NODE:
5003#ifdef LIBXML_DOCB_ENABLED
5004 case XML_DOCB_DOCUMENT_NODE:
5005#endif
5006 case XML_HTML_DOCUMENT_NODE:
5007 cur = cur->children;
5008 while (cur!= NULL) {
5009 if ((cur->type == XML_ELEMENT_NODE) ||
5010 (cur->type == XML_TEXT_NODE) ||
5011 (cur->type == XML_CDATA_SECTION_NODE)) {
5012 xmlNodeBufGetContent(buffer, cur);
5013 }
5014 cur = cur->next;
5015 }
5016 break;
5017 case XML_NAMESPACE_DECL:
5018 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
5019 break;
5020 case XML_ELEMENT_DECL:
5021 case XML_ATTRIBUTE_DECL:
5022 case XML_ENTITY_DECL:
5023 break;
5024 }
5025 return(0);
5026}
5027/**
Owen Taylor3473f882001-02-23 17:55:21 +00005028 * xmlNodeGetContent:
5029 * @cur: the node being read
5030 *
5031 * Read the value of a node, this can be either the text carried
5032 * directly by this node if it's a TEXT node or the aggregate string
5033 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00005034 * Entity references are substituted.
5035 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005036 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005037 */
5038xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00005039xmlNodeGetContent(xmlNodePtr cur)
5040{
5041 if (cur == NULL)
5042 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005043 switch (cur->type) {
5044 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005045 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00005046 xmlBufferPtr buffer;
5047 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00005048
Daniel Veillard814a76d2003-01-23 18:24:20 +00005049 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00005050 if (buffer == NULL)
5051 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00005052 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005053 ret = buffer->content;
5054 buffer->content = NULL;
5055 xmlBufferFree(buffer);
5056 return (ret);
5057 }
5058 case XML_ATTRIBUTE_NODE:{
5059 xmlAttrPtr attr = (xmlAttrPtr) cur;
5060
5061 if (attr->parent != NULL)
5062 return (xmlNodeListGetString
5063 (attr->parent->doc, attr->children, 1));
5064 else
5065 return (xmlNodeListGetString(NULL, attr->children, 1));
5066 break;
5067 }
Owen Taylor3473f882001-02-23 17:55:21 +00005068 case XML_COMMENT_NODE:
5069 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005070 if (cur->content != NULL)
5071 return (xmlStrdup(cur->content));
5072 return (NULL);
5073 case XML_ENTITY_REF_NODE:{
5074 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00005075 xmlBufferPtr buffer;
5076 xmlChar *ret;
5077
5078 /* lookup entity declaration */
5079 ent = xmlGetDocEntity(cur->doc, cur->name);
5080 if (ent == NULL)
5081 return (NULL);
5082
5083 buffer = xmlBufferCreate();
5084 if (buffer == NULL)
5085 return (NULL);
5086
Daniel Veillardc4696922003-10-19 21:47:14 +00005087 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005088
5089 ret = buffer->content;
5090 buffer->content = NULL;
5091 xmlBufferFree(buffer);
5092 return (ret);
5093 }
Owen Taylor3473f882001-02-23 17:55:21 +00005094 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005095 case XML_DOCUMENT_TYPE_NODE:
5096 case XML_NOTATION_NODE:
5097 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005098 case XML_XINCLUDE_START:
5099 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00005100 return (NULL);
5101 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005102#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005103 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005104#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005105 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00005106 xmlBufferPtr buffer;
5107 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005108
Daniel Veillardc4696922003-10-19 21:47:14 +00005109 buffer = xmlBufferCreate();
5110 if (buffer == NULL)
5111 return (NULL);
5112
5113 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5114
5115 ret = buffer->content;
5116 buffer->content = NULL;
5117 xmlBufferFree(buffer);
5118 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005119 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005120 case XML_NAMESPACE_DECL: {
5121 xmlChar *tmp;
5122
5123 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5124 return (tmp);
5125 }
Owen Taylor3473f882001-02-23 17:55:21 +00005126 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005127 /* TODO !!! */
5128 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005129 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005130 /* TODO !!! */
5131 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005132 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005133 /* TODO !!! */
5134 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005135 case XML_CDATA_SECTION_NODE:
5136 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005137 if (cur->content != NULL)
5138 return (xmlStrdup(cur->content));
5139 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005140 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005141 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005142}
Daniel Veillard652327a2003-09-29 18:02:38 +00005143
Owen Taylor3473f882001-02-23 17:55:21 +00005144/**
5145 * xmlNodeSetContent:
5146 * @cur: the node being modified
5147 * @content: the new value of the content
5148 *
5149 * Replace the content of a node.
5150 */
5151void
5152xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5153 if (cur == NULL) {
5154#ifdef DEBUG_TREE
5155 xmlGenericError(xmlGenericErrorContext,
5156 "xmlNodeSetContent : node == NULL\n");
5157#endif
5158 return;
5159 }
5160 switch (cur->type) {
5161 case XML_DOCUMENT_FRAG_NODE:
5162 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005163 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005164 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5165 cur->children = xmlStringGetNodeList(cur->doc, content);
5166 UPDATE_LAST_CHILD_AND_PARENT(cur)
5167 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005168 case XML_TEXT_NODE:
5169 case XML_CDATA_SECTION_NODE:
5170 case XML_ENTITY_REF_NODE:
5171 case XML_ENTITY_NODE:
5172 case XML_PI_NODE:
5173 case XML_COMMENT_NODE:
Daniel Veillard8874b942005-08-25 13:19:21 +00005174 if ((cur->content != NULL) &&
5175 (cur->content != (xmlChar *) &(cur->properties))) {
William M. Brack7762bb12004-01-04 14:49:01 +00005176 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
Daniel Veillardc587bce2005-05-10 15:28:08 +00005177 (xmlDictOwns(cur->doc->dict, cur->content))))
William M. Brack7762bb12004-01-04 14:49:01 +00005178 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005179 }
5180 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5181 cur->last = cur->children = NULL;
5182 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005183 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005184 } else
5185 cur->content = NULL;
Daniel Veillard8874b942005-08-25 13:19:21 +00005186 cur->properties = NULL;
5187 cur->nsDef = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00005188 break;
5189 case XML_DOCUMENT_NODE:
5190 case XML_HTML_DOCUMENT_NODE:
5191 case XML_DOCUMENT_TYPE_NODE:
5192 case XML_XINCLUDE_START:
5193 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005194#ifdef LIBXML_DOCB_ENABLED
5195 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005196#endif
5197 break;
5198 case XML_NOTATION_NODE:
5199 break;
5200 case XML_DTD_NODE:
5201 break;
5202 case XML_NAMESPACE_DECL:
5203 break;
5204 case XML_ELEMENT_DECL:
5205 /* TODO !!! */
5206 break;
5207 case XML_ATTRIBUTE_DECL:
5208 /* TODO !!! */
5209 break;
5210 case XML_ENTITY_DECL:
5211 /* TODO !!! */
5212 break;
5213 }
5214}
5215
Daniel Veillard652327a2003-09-29 18:02:38 +00005216#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005217/**
5218 * xmlNodeSetContentLen:
5219 * @cur: the node being modified
5220 * @content: the new value of the content
5221 * @len: the size of @content
5222 *
5223 * Replace the content of a node.
5224 */
5225void
5226xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5227 if (cur == NULL) {
5228#ifdef DEBUG_TREE
5229 xmlGenericError(xmlGenericErrorContext,
5230 "xmlNodeSetContentLen : node == NULL\n");
5231#endif
5232 return;
5233 }
5234 switch (cur->type) {
5235 case XML_DOCUMENT_FRAG_NODE:
5236 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005237 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005238 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5239 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5240 UPDATE_LAST_CHILD_AND_PARENT(cur)
5241 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005242 case XML_TEXT_NODE:
5243 case XML_CDATA_SECTION_NODE:
5244 case XML_ENTITY_REF_NODE:
5245 case XML_ENTITY_NODE:
5246 case XML_PI_NODE:
5247 case XML_COMMENT_NODE:
5248 case XML_NOTATION_NODE:
Daniel Veillard8874b942005-08-25 13:19:21 +00005249 if ((cur->content != NULL) &&
5250 (cur->content != (xmlChar *) &(cur->properties))) {
5251 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5252 (xmlDictOwns(cur->doc->dict, cur->content))))
5253 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005254 }
5255 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5256 cur->children = cur->last = NULL;
5257 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005258 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005259 } else
5260 cur->content = NULL;
Daniel Veillard8874b942005-08-25 13:19:21 +00005261 cur->properties = NULL;
5262 cur->nsDef = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00005263 break;
5264 case XML_DOCUMENT_NODE:
5265 case XML_DTD_NODE:
5266 case XML_HTML_DOCUMENT_NODE:
5267 case XML_DOCUMENT_TYPE_NODE:
5268 case XML_NAMESPACE_DECL:
5269 case XML_XINCLUDE_START:
5270 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005271#ifdef LIBXML_DOCB_ENABLED
5272 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005273#endif
5274 break;
5275 case XML_ELEMENT_DECL:
5276 /* TODO !!! */
5277 break;
5278 case XML_ATTRIBUTE_DECL:
5279 /* TODO !!! */
5280 break;
5281 case XML_ENTITY_DECL:
5282 /* TODO !!! */
5283 break;
5284 }
5285}
Daniel Veillard652327a2003-09-29 18:02:38 +00005286#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005287
5288/**
5289 * xmlNodeAddContentLen:
5290 * @cur: the node being modified
5291 * @content: extra content
5292 * @len: the size of @content
5293 *
5294 * Append the extra substring to the node content.
5295 */
5296void
5297xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5298 if (cur == NULL) {
5299#ifdef DEBUG_TREE
5300 xmlGenericError(xmlGenericErrorContext,
5301 "xmlNodeAddContentLen : node == NULL\n");
5302#endif
5303 return;
5304 }
5305 if (len <= 0) return;
5306 switch (cur->type) {
5307 case XML_DOCUMENT_FRAG_NODE:
5308 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005309 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005310
Daniel Veillard7db37732001-07-12 01:20:08 +00005311 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005312 newNode = xmlNewTextLen(content, len);
5313 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005314 tmp = xmlAddChild(cur, newNode);
5315 if (tmp != newNode)
5316 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005317 if ((last != NULL) && (last->next == newNode)) {
5318 xmlTextMerge(last, newNode);
5319 }
5320 }
5321 break;
5322 }
5323 case XML_ATTRIBUTE_NODE:
5324 break;
5325 case XML_TEXT_NODE:
5326 case XML_CDATA_SECTION_NODE:
5327 case XML_ENTITY_REF_NODE:
5328 case XML_ENTITY_NODE:
5329 case XML_PI_NODE:
5330 case XML_COMMENT_NODE:
5331 case XML_NOTATION_NODE:
5332 if (content != NULL) {
Daniel Veillard8874b942005-08-25 13:19:21 +00005333 if ((cur->content == (xmlChar *) &(cur->properties)) ||
5334 ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5335 xmlDictOwns(cur->doc->dict, cur->content))) {
5336 cur->content = xmlStrncatNew(cur->content, content, len);
5337 cur->properties = NULL;
5338 cur->nsDef = NULL;
William M. Brack7762bb12004-01-04 14:49:01 +00005339 break;
5340 }
Owen Taylor3473f882001-02-23 17:55:21 +00005341 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005342 }
5343 case XML_DOCUMENT_NODE:
5344 case XML_DTD_NODE:
5345 case XML_HTML_DOCUMENT_NODE:
5346 case XML_DOCUMENT_TYPE_NODE:
5347 case XML_NAMESPACE_DECL:
5348 case XML_XINCLUDE_START:
5349 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005350#ifdef LIBXML_DOCB_ENABLED
5351 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005352#endif
5353 break;
5354 case XML_ELEMENT_DECL:
5355 case XML_ATTRIBUTE_DECL:
5356 case XML_ENTITY_DECL:
5357 break;
5358 }
5359}
5360
5361/**
5362 * xmlNodeAddContent:
5363 * @cur: the node being modified
5364 * @content: extra content
5365 *
5366 * Append the extra substring to the node content.
5367 */
5368void
5369xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5370 int len;
5371
5372 if (cur == NULL) {
5373#ifdef DEBUG_TREE
5374 xmlGenericError(xmlGenericErrorContext,
5375 "xmlNodeAddContent : node == NULL\n");
5376#endif
5377 return;
5378 }
5379 if (content == NULL) return;
5380 len = xmlStrlen(content);
5381 xmlNodeAddContentLen(cur, content, len);
5382}
5383
5384/**
5385 * xmlTextMerge:
5386 * @first: the first text node
5387 * @second: the second text node being merged
5388 *
5389 * Merge two text nodes into one
5390 * Returns the first text node augmented
5391 */
5392xmlNodePtr
5393xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5394 if (first == NULL) return(second);
5395 if (second == NULL) return(first);
5396 if (first->type != XML_TEXT_NODE) return(first);
5397 if (second->type != XML_TEXT_NODE) return(first);
5398 if (second->name != first->name)
5399 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005400 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005401 xmlUnlinkNode(second);
5402 xmlFreeNode(second);
5403 return(first);
5404}
5405
Daniel Veillard2156d432004-03-04 15:59:36 +00005406#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005407/**
5408 * xmlGetNsList:
5409 * @doc: the document
5410 * @node: the current node
5411 *
5412 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005413 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005414 * that need to be freed by the caller or NULL if no
5415 * namespace if defined
5416 */
5417xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005418xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5419{
Owen Taylor3473f882001-02-23 17:55:21 +00005420 xmlNsPtr cur;
5421 xmlNsPtr *ret = NULL;
5422 int nbns = 0;
5423 int maxns = 10;
5424 int i;
5425
5426 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005427 if (node->type == XML_ELEMENT_NODE) {
5428 cur = node->nsDef;
5429 while (cur != NULL) {
5430 if (ret == NULL) {
5431 ret =
5432 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5433 sizeof(xmlNsPtr));
5434 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005435 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005436 return (NULL);
5437 }
5438 ret[nbns] = NULL;
5439 }
5440 for (i = 0; i < nbns; i++) {
5441 if ((cur->prefix == ret[i]->prefix) ||
5442 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5443 break;
5444 }
5445 if (i >= nbns) {
5446 if (nbns >= maxns) {
5447 maxns *= 2;
5448 ret = (xmlNsPtr *) xmlRealloc(ret,
5449 (maxns +
5450 1) *
5451 sizeof(xmlNsPtr));
5452 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005453 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005454 return (NULL);
5455 }
5456 }
5457 ret[nbns++] = cur;
5458 ret[nbns] = NULL;
5459 }
Owen Taylor3473f882001-02-23 17:55:21 +00005460
Daniel Veillard77044732001-06-29 21:31:07 +00005461 cur = cur->next;
5462 }
5463 }
5464 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005465 }
Daniel Veillard77044732001-06-29 21:31:07 +00005466 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005467}
Daniel Veillard652327a2003-09-29 18:02:38 +00005468#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005469
5470/**
5471 * xmlSearchNs:
5472 * @doc: the document
5473 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005474 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005475 *
5476 * Search a Ns registered under a given name space for a document.
5477 * recurse on the parents until it finds the defined namespace
5478 * or return NULL otherwise.
5479 * @nameSpace can be NULL, this is a search for the default namespace.
5480 * We don't allow to cross entities boundaries. If you don't declare
5481 * the namespace within those you will be in troubles !!! A warning
5482 * is generated to cover this case.
5483 *
5484 * Returns the namespace pointer or NULL.
5485 */
5486xmlNsPtr
5487xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005488
Owen Taylor3473f882001-02-23 17:55:21 +00005489 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005490 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005491
5492 if (node == NULL) return(NULL);
5493 if ((nameSpace != NULL) &&
5494 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005495 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5496 /*
5497 * The XML-1.0 namespace is normally held on the root
5498 * element. In this case exceptionally create it on the
5499 * node element.
5500 */
5501 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5502 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005503 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005504 return(NULL);
5505 }
5506 memset(cur, 0, sizeof(xmlNs));
5507 cur->type = XML_LOCAL_NAMESPACE;
5508 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5509 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5510 cur->next = node->nsDef;
5511 node->nsDef = cur;
5512 return(cur);
5513 }
Daniel Veillard11ce4002006-03-10 00:36:23 +00005514 if (doc == NULL) {
5515 doc = node->doc;
5516 if (doc == NULL)
5517 return(NULL);
5518 }
Owen Taylor3473f882001-02-23 17:55:21 +00005519 if (doc->oldNs == NULL) {
5520 /*
5521 * Allocate a new Namespace and fill the fields.
5522 */
5523 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5524 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005525 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005526 return(NULL);
5527 }
5528 memset(doc->oldNs, 0, sizeof(xmlNs));
5529 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5530
5531 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5532 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5533 }
5534 return(doc->oldNs);
5535 }
5536 while (node != NULL) {
5537 if ((node->type == XML_ENTITY_REF_NODE) ||
5538 (node->type == XML_ENTITY_NODE) ||
5539 (node->type == XML_ENTITY_DECL))
5540 return(NULL);
5541 if (node->type == XML_ELEMENT_NODE) {
5542 cur = node->nsDef;
5543 while (cur != NULL) {
5544 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5545 (cur->href != NULL))
5546 return(cur);
5547 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5548 (cur->href != NULL) &&
5549 (xmlStrEqual(cur->prefix, nameSpace)))
5550 return(cur);
5551 cur = cur->next;
5552 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005553 if (orig != node) {
5554 cur = node->ns;
5555 if (cur != NULL) {
5556 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5557 (cur->href != NULL))
5558 return(cur);
5559 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5560 (cur->href != NULL) &&
5561 (xmlStrEqual(cur->prefix, nameSpace)))
5562 return(cur);
5563 }
5564 }
Owen Taylor3473f882001-02-23 17:55:21 +00005565 }
5566 node = node->parent;
5567 }
5568 return(NULL);
5569}
5570
5571/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005572 * xmlNsInScope:
5573 * @doc: the document
5574 * @node: the current node
5575 * @ancestor: the ancestor carrying the namespace
5576 * @prefix: the namespace prefix
5577 *
5578 * Verify that the given namespace held on @ancestor is still in scope
5579 * on node.
5580 *
5581 * Returns 1 if true, 0 if false and -1 in case of error.
5582 */
5583static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005584xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5585 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005586{
5587 xmlNsPtr tst;
5588
5589 while ((node != NULL) && (node != ancestor)) {
5590 if ((node->type == XML_ENTITY_REF_NODE) ||
5591 (node->type == XML_ENTITY_NODE) ||
5592 (node->type == XML_ENTITY_DECL))
5593 return (-1);
5594 if (node->type == XML_ELEMENT_NODE) {
5595 tst = node->nsDef;
5596 while (tst != NULL) {
5597 if ((tst->prefix == NULL)
5598 && (prefix == NULL))
5599 return (0);
5600 if ((tst->prefix != NULL)
5601 && (prefix != NULL)
5602 && (xmlStrEqual(tst->prefix, prefix)))
5603 return (0);
5604 tst = tst->next;
5605 }
5606 }
5607 node = node->parent;
5608 }
5609 if (node != ancestor)
5610 return (-1);
5611 return (1);
5612}
5613
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005614/**
Owen Taylor3473f882001-02-23 17:55:21 +00005615 * xmlSearchNsByHref:
5616 * @doc: the document
5617 * @node: the current node
5618 * @href: the namespace value
5619 *
5620 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5621 * the defined namespace or return NULL otherwise.
5622 * Returns the namespace pointer or NULL.
5623 */
5624xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005625xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5626{
Owen Taylor3473f882001-02-23 17:55:21 +00005627 xmlNsPtr cur;
5628 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005629 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005630
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005631 if ((node == NULL) || (href == NULL))
5632 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005633 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005634 /*
5635 * Only the document can hold the XML spec namespace.
5636 */
5637 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5638 /*
5639 * The XML-1.0 namespace is normally held on the root
5640 * element. In this case exceptionally create it on the
5641 * node element.
5642 */
5643 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5644 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005645 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005646 return (NULL);
5647 }
5648 memset(cur, 0, sizeof(xmlNs));
5649 cur->type = XML_LOCAL_NAMESPACE;
5650 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5651 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5652 cur->next = node->nsDef;
5653 node->nsDef = cur;
5654 return (cur);
5655 }
Daniel Veillard11ce4002006-03-10 00:36:23 +00005656 if (doc == NULL) {
5657 doc = node->doc;
5658 if (doc == NULL)
5659 return(NULL);
5660 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005661 if (doc->oldNs == NULL) {
5662 /*
5663 * Allocate a new Namespace and fill the fields.
5664 */
5665 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5666 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005667 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005668 return (NULL);
5669 }
5670 memset(doc->oldNs, 0, sizeof(xmlNs));
5671 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005672
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005673 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5674 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5675 }
5676 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005677 }
Daniel Veillard62040be2004-05-17 03:17:26 +00005678 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00005679 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005680 if ((node->type == XML_ENTITY_REF_NODE) ||
5681 (node->type == XML_ENTITY_NODE) ||
5682 (node->type == XML_ENTITY_DECL))
5683 return (NULL);
5684 if (node->type == XML_ELEMENT_NODE) {
5685 cur = node->nsDef;
5686 while (cur != NULL) {
5687 if ((cur->href != NULL) && (href != NULL) &&
5688 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005689 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00005690 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005691 return (cur);
5692 }
5693 cur = cur->next;
5694 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005695 if (orig != node) {
5696 cur = node->ns;
5697 if (cur != NULL) {
5698 if ((cur->href != NULL) && (href != NULL) &&
5699 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005700 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00005701 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00005702 return (cur);
5703 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005704 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005705 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005706 }
5707 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005708 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005709 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005710}
5711
5712/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005713 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005714 * @doc: the document
5715 * @tree: a node expected to hold the new namespace
5716 * @ns: the original namespace
5717 *
5718 * This function tries to locate a namespace definition in a tree
5719 * ancestors, or create a new namespace definition node similar to
5720 * @ns trying to reuse the same prefix. However if the given prefix is
5721 * null (default namespace) or reused within the subtree defined by
5722 * @tree or on one of its ancestors then a new prefix is generated.
5723 * Returns the (new) namespace definition or NULL in case of error
5724 */
5725xmlNsPtr
5726xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5727 xmlNsPtr def;
5728 xmlChar prefix[50];
5729 int counter = 1;
5730
5731 if (tree == NULL) {
5732#ifdef DEBUG_TREE
5733 xmlGenericError(xmlGenericErrorContext,
5734 "xmlNewReconciliedNs : tree == NULL\n");
5735#endif
5736 return(NULL);
5737 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00005738 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005739#ifdef DEBUG_TREE
5740 xmlGenericError(xmlGenericErrorContext,
5741 "xmlNewReconciliedNs : ns == NULL\n");
5742#endif
5743 return(NULL);
5744 }
5745 /*
5746 * Search an existing namespace definition inherited.
5747 */
5748 def = xmlSearchNsByHref(doc, tree, ns->href);
5749 if (def != NULL)
5750 return(def);
5751
5752 /*
5753 * Find a close prefix which is not already in use.
5754 * Let's strip namespace prefixes longer than 20 chars !
5755 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005756 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005757 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005758 else
William M. Brack13dfa872004-09-18 04:52:08 +00005759 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005760
Owen Taylor3473f882001-02-23 17:55:21 +00005761 def = xmlSearchNs(doc, tree, prefix);
5762 while (def != NULL) {
5763 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005764 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005765 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005766 else
William M. Brack13dfa872004-09-18 04:52:08 +00005767 snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
5768 (char *)ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005769 def = xmlSearchNs(doc, tree, prefix);
5770 }
5771
5772 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005773 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005774 */
5775 def = xmlNewNs(tree, ns->href, prefix);
5776 return(def);
5777}
5778
Daniel Veillard652327a2003-09-29 18:02:38 +00005779#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005780/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005781 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005782 * @doc: the document
5783 * @tree: a node defining the subtree to reconciliate
5784 *
5785 * This function checks that all the namespaces declared within the given
5786 * tree are properly declared. This is needed for example after Copy or Cut
5787 * and then paste operations. The subtree may still hold pointers to
5788 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005789 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005790 * the new environment. If not possible the new namespaces are redeclared
5791 * on @tree at the top of the given subtree.
5792 * Returns the number of namespace declarations created or -1 in case of error.
5793 */
5794int
5795xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5796 xmlNsPtr *oldNs = NULL;
5797 xmlNsPtr *newNs = NULL;
5798 int sizeCache = 0;
5799 int nbCache = 0;
5800
5801 xmlNsPtr n;
5802 xmlNodePtr node = tree;
5803 xmlAttrPtr attr;
5804 int ret = 0, i;
5805
Daniel Veillardce244ad2004-11-05 10:03:46 +00005806 if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1);
5807 if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1);
5808 if (node->doc != doc) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005809 while (node != NULL) {
5810 /*
5811 * Reconciliate the node namespace
5812 */
5813 if (node->ns != NULL) {
5814 /*
5815 * initialize the cache if needed
5816 */
5817 if (sizeCache == 0) {
5818 sizeCache = 10;
5819 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5820 sizeof(xmlNsPtr));
5821 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005822 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005823 return(-1);
5824 }
5825 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5826 sizeof(xmlNsPtr));
5827 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005828 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005829 xmlFree(oldNs);
5830 return(-1);
5831 }
5832 }
5833 for (i = 0;i < nbCache;i++) {
5834 if (oldNs[i] == node->ns) {
5835 node->ns = newNs[i];
5836 break;
5837 }
5838 }
5839 if (i == nbCache) {
5840 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005841 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005842 */
5843 n = xmlNewReconciliedNs(doc, tree, node->ns);
5844 if (n != NULL) { /* :-( what if else ??? */
5845 /*
5846 * check if we need to grow the cache buffers.
5847 */
5848 if (sizeCache <= nbCache) {
5849 sizeCache *= 2;
5850 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5851 sizeof(xmlNsPtr));
5852 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005853 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005854 xmlFree(newNs);
5855 return(-1);
5856 }
5857 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5858 sizeof(xmlNsPtr));
5859 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005860 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005861 xmlFree(oldNs);
5862 return(-1);
5863 }
5864 }
5865 newNs[nbCache] = n;
5866 oldNs[nbCache++] = node->ns;
5867 node->ns = n;
5868 }
5869 }
5870 }
5871 /*
5872 * now check for namespace hold by attributes on the node.
5873 */
5874 attr = node->properties;
5875 while (attr != NULL) {
5876 if (attr->ns != NULL) {
5877 /*
5878 * initialize the cache if needed
5879 */
5880 if (sizeCache == 0) {
5881 sizeCache = 10;
5882 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5883 sizeof(xmlNsPtr));
5884 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005885 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005886 return(-1);
5887 }
5888 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5889 sizeof(xmlNsPtr));
5890 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005891 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005892 xmlFree(oldNs);
5893 return(-1);
5894 }
5895 }
5896 for (i = 0;i < nbCache;i++) {
5897 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005898 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005899 break;
5900 }
5901 }
5902 if (i == nbCache) {
5903 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005904 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005905 */
5906 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5907 if (n != NULL) { /* :-( what if else ??? */
5908 /*
5909 * check if we need to grow the cache buffers.
5910 */
5911 if (sizeCache <= nbCache) {
5912 sizeCache *= 2;
5913 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5914 sizeof(xmlNsPtr));
5915 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005916 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005917 xmlFree(newNs);
5918 return(-1);
5919 }
5920 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5921 sizeof(xmlNsPtr));
5922 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005923 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005924 xmlFree(oldNs);
5925 return(-1);
5926 }
5927 }
5928 newNs[nbCache] = n;
5929 oldNs[nbCache++] = attr->ns;
5930 attr->ns = n;
5931 }
5932 }
5933 }
5934 attr = attr->next;
5935 }
5936
5937 /*
5938 * Browse the full subtree, deep first
5939 */
Daniel Veillardac996a12004-07-30 12:02:58 +00005940 if (node->children != NULL && node->type != XML_ENTITY_REF_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00005941 /* deep first */
5942 node = node->children;
5943 } else if ((node != tree) && (node->next != NULL)) {
5944 /* then siblings */
5945 node = node->next;
5946 } else if (node != tree) {
5947 /* go up to parents->next if needed */
5948 while (node != tree) {
5949 if (node->parent != NULL)
5950 node = node->parent;
5951 if ((node != tree) && (node->next != NULL)) {
5952 node = node->next;
5953 break;
5954 }
5955 if (node->parent == NULL) {
5956 node = NULL;
5957 break;
5958 }
5959 }
5960 /* exit condition */
5961 if (node == tree)
5962 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005963 } else
5964 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005965 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005966 if (oldNs != NULL)
5967 xmlFree(oldNs);
5968 if (newNs != NULL)
5969 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005970 return(ret);
5971}
Daniel Veillard652327a2003-09-29 18:02:38 +00005972#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005973
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00005974static xmlAttrPtr
5975xmlGetPropNodeInternal(xmlNodePtr node, const xmlChar *name,
5976 const xmlChar *nsName, int useDTD)
5977{
5978 xmlAttrPtr prop;
5979
5980 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
5981 return(NULL);
5982
5983 if (node->properties != NULL) {
5984 prop = node->properties;
5985 if (nsName == NULL) {
5986 /*
5987 * We want the attr to be in no namespace.
5988 */
5989 do {
5990 if ((prop->ns == NULL) && xmlStrEqual(prop->name, name)) {
5991 return(prop);
5992 }
5993 prop = prop->next;
5994 } while (prop != NULL);
5995 } else {
5996 /*
5997 * We want the attr to be in the specified namespace.
5998 */
5999 do {
6000 if ((prop->ns != NULL) && xmlStrEqual(prop->name, name) &&
6001 ((prop->ns->href == nsName) ||
6002 xmlStrEqual(prop->ns->href, nsName)))
6003 {
6004 return(prop);
6005 }
6006 prop = prop->next;
6007 } while (prop != NULL);
6008 }
6009 }
6010
6011#ifdef LIBXML_TREE_ENABLED
6012 if (! useDTD)
6013 return(NULL);
6014 /*
6015 * Check if there is a default/fixed attribute declaration in
6016 * the internal or external subset.
6017 */
6018 if ((node->doc != NULL) && (node->doc->intSubset != NULL)) {
6019 xmlDocPtr doc = node->doc;
6020 xmlAttributePtr attrDecl = NULL;
6021 xmlChar *elemQName, *tmpstr = NULL;
6022
6023 /*
6024 * We need the QName of the element for the DTD-lookup.
6025 */
6026 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
6027 tmpstr = xmlStrdup(node->ns->prefix);
6028 tmpstr = xmlStrcat(tmpstr, BAD_CAST ":");
6029 tmpstr = xmlStrcat(tmpstr, node->name);
6030 if (tmpstr == NULL)
6031 return(NULL);
6032 elemQName = tmpstr;
6033 } else
6034 elemQName = (xmlChar *) node->name;
6035 if (nsName == NULL) {
6036 /*
6037 * The common and nice case: Attr in no namespace.
6038 */
6039 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset,
6040 elemQName, name, NULL);
6041 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
6042 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset,
6043 elemQName, name, NULL);
6044 }
6045 } else {
6046 xmlNsPtr *nsList, *cur;
6047
6048 /*
6049 * The ugly case: Search using the prefixes of in-scope
6050 * ns-decls corresponding to @nsName.
6051 */
6052 nsList = xmlGetNsList(node->doc, node);
6053 if (nsList == NULL) {
6054 if (tmpstr != NULL)
6055 xmlFree(tmpstr);
6056 return(NULL);
6057 }
6058 cur = nsList;
6059 while (*cur != NULL) {
6060 if (xmlStrEqual((*cur)->href, nsName)) {
6061 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elemQName,
6062 name, (*cur)->prefix);
6063 if (attrDecl)
6064 break;
6065 if (doc->extSubset != NULL) {
6066 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elemQName,
6067 name, (*cur)->prefix);
6068 if (attrDecl)
6069 break;
6070 }
6071 }
6072 cur++;
6073 }
6074 xmlFree(nsList);
6075 }
6076 if (tmpstr != NULL)
6077 xmlFree(tmpstr);
6078 /*
6079 * Only default/fixed attrs are relevant.
6080 */
6081 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6082 return((xmlAttrPtr) attrDecl);
6083 }
6084#endif /* LIBXML_TREE_ENABLED */
6085 return(NULL);
6086}
6087
6088static xmlChar*
6089xmlGetPropNodeValueInternal(xmlAttrPtr prop)
6090{
6091 if (prop == NULL)
6092 return(NULL);
6093 if (prop->type == XML_ATTRIBUTE_NODE) {
6094 /*
6095 * Note that we return at least the empty string.
6096 * TODO: Do we really always want that?
6097 */
6098 if (prop->children != NULL) {
6099 if ((prop->children == prop->last) &&
6100 ((prop->children->type == XML_TEXT_NODE) ||
6101 (prop->children->type == XML_CDATA_SECTION_NODE)))
6102 {
6103 /*
6104 * Optimization for the common case: only 1 text node.
6105 */
6106 return(xmlStrdup(prop->children->content));
6107 } else {
6108 xmlChar *ret;
6109
6110 ret = xmlNodeListGetString(prop->doc, prop->children, 1);
6111 if (ret != NULL)
6112 return(ret);
6113 }
6114 }
6115 return(xmlStrdup((xmlChar *)""));
6116 } else if (prop->type == XML_ATTRIBUTE_DECL) {
6117 return(xmlStrdup(((xmlAttributePtr)prop)->defaultValue));
6118 }
6119 return(NULL);
6120}
6121
Owen Taylor3473f882001-02-23 17:55:21 +00006122/**
6123 * xmlHasProp:
6124 * @node: the node
6125 * @name: the attribute name
6126 *
6127 * Search an attribute associated to a node
6128 * This function also looks in DTD attribute declaration for #FIXED or
6129 * default declaration values unless DTD use has been turned off.
6130 *
6131 * Returns the attribute or the attribute declaration or NULL if
6132 * neither was found.
6133 */
6134xmlAttrPtr
6135xmlHasProp(xmlNodePtr node, const xmlChar *name) {
6136 xmlAttrPtr prop;
6137 xmlDocPtr doc;
6138
Daniel Veillard8874b942005-08-25 13:19:21 +00006139 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6140 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006141 /*
6142 * Check on the properties attached to the node
6143 */
6144 prop = node->properties;
6145 while (prop != NULL) {
6146 if (xmlStrEqual(prop->name, name)) {
6147 return(prop);
6148 }
6149 prop = prop->next;
6150 }
6151 if (!xmlCheckDTD) return(NULL);
6152
6153 /*
6154 * Check if there is a default declaration in the internal
6155 * or external subsets
6156 */
6157 doc = node->doc;
6158 if (doc != NULL) {
6159 xmlAttributePtr attrDecl;
6160 if (doc->intSubset != NULL) {
6161 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6162 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6163 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006164 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6165 /* return attribute declaration only if a default value is given
6166 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006167 return((xmlAttrPtr) attrDecl);
6168 }
6169 }
6170 return(NULL);
6171}
6172
6173/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00006174 * xmlHasNsProp:
6175 * @node: the node
6176 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006177 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00006178 *
6179 * Search for an attribute associated to a node
6180 * This attribute has to be anchored in the namespace specified.
6181 * This does the entity substitution.
6182 * This function looks in DTD attribute declaration for #FIXED or
6183 * default declaration values unless DTD use has been turned off.
William M. Brack2c228442004-10-03 04:10:00 +00006184 * Note that a namespace of NULL indicates to use the default namespace.
Daniel Veillarde95e2392001-06-06 10:46:28 +00006185 *
6186 * Returns the attribute or the attribute declaration or NULL
6187 * if neither was found.
6188 */
6189xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00006190xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00006191
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006192 return(xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD));
Daniel Veillarde95e2392001-06-06 10:46:28 +00006193}
6194
6195/**
Owen Taylor3473f882001-02-23 17:55:21 +00006196 * xmlGetProp:
6197 * @node: the node
6198 * @name: the attribute name
6199 *
6200 * Search and get the value of an attribute associated to a node
6201 * This does the entity substitution.
6202 * This function looks in DTD attribute declaration for #FIXED or
6203 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00006204 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00006205 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6206 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00006207 *
6208 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006209 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006210 */
6211xmlChar *
6212xmlGetProp(xmlNodePtr node, const xmlChar *name) {
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006213 xmlAttrPtr prop;
Owen Taylor3473f882001-02-23 17:55:21 +00006214
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006215 prop = xmlHasProp(node, name);
6216 if (prop == NULL)
6217 return(NULL);
6218 return(xmlGetPropNodeValueInternal(prop));
Owen Taylor3473f882001-02-23 17:55:21 +00006219}
6220
6221/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006222 * xmlGetNoNsProp:
6223 * @node: the node
6224 * @name: the attribute name
6225 *
6226 * Search and get the value of an attribute associated to a node
6227 * This does the entity substitution.
6228 * This function looks in DTD attribute declaration for #FIXED or
6229 * default declaration values unless DTD use has been turned off.
6230 * This function is similar to xmlGetProp except it will accept only
6231 * an attribute in no namespace.
6232 *
6233 * Returns the attribute value or NULL if not found.
6234 * It's up to the caller to free the memory with xmlFree().
6235 */
6236xmlChar *
6237xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6238 xmlAttrPtr prop;
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006239
6240 prop = xmlGetPropNodeInternal(node, name, NULL, xmlCheckDTD);
6241 if (prop == NULL)
Daniel Veillard8874b942005-08-25 13:19:21 +00006242 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006243 return(xmlGetPropNodeValueInternal(prop));
Daniel Veillard71531f32003-02-05 13:19:53 +00006244}
6245
6246/**
Owen Taylor3473f882001-02-23 17:55:21 +00006247 * xmlGetNsProp:
6248 * @node: the node
6249 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006250 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006251 *
6252 * Search and get the value of an attribute associated to a node
6253 * This attribute has to be anchored in the namespace specified.
6254 * This does the entity substitution.
6255 * This function looks in DTD attribute declaration for #FIXED or
6256 * default declaration values unless DTD use has been turned off.
6257 *
6258 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006259 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006260 */
6261xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006262xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006263 xmlAttrPtr prop;
Owen Taylor3473f882001-02-23 17:55:21 +00006264
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006265 prop = xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD);
6266 if (prop == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006267 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006268 return(xmlGetPropNodeValueInternal(prop));
Owen Taylor3473f882001-02-23 17:55:21 +00006269}
6270
Daniel Veillard2156d432004-03-04 15:59:36 +00006271#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6272/**
6273 * xmlUnsetProp:
6274 * @node: the node
6275 * @name: the attribute name
6276 *
6277 * Remove an attribute carried by a node.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006278 * This handles only attributes in no namespace.
Daniel Veillard2156d432004-03-04 15:59:36 +00006279 * Returns 0 if successful, -1 if not found
6280 */
6281int
6282xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Kasimier T. Buchcik65c2f1d2005-10-17 12:39:58 +00006283 xmlAttrPtr prop;
Daniel Veillard2156d432004-03-04 15:59:36 +00006284
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006285 prop = xmlGetPropNodeInternal(node, name, NULL, 0);
6286 if (prop == NULL)
Daniel Veillard2156d432004-03-04 15:59:36 +00006287 return(-1);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006288 xmlUnlinkNode((xmlNodePtr) prop);
6289 xmlFreeProp(prop);
6290 return(0);
Daniel Veillard2156d432004-03-04 15:59:36 +00006291}
6292
6293/**
6294 * xmlUnsetNsProp:
6295 * @node: the node
6296 * @ns: the namespace definition
6297 * @name: the attribute name
6298 *
6299 * Remove an attribute carried by a node.
6300 * Returns 0 if successful, -1 if not found
6301 */
6302int
6303xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
Kasimier T. Buchcik65c2f1d2005-10-17 12:39:58 +00006304 xmlAttrPtr prop;
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006305
6306 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
6307 if (prop == NULL)
Daniel Veillard2156d432004-03-04 15:59:36 +00006308 return(-1);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006309 xmlUnlinkNode((xmlNodePtr) prop);
6310 xmlFreeProp(prop);
6311 return(0);
Daniel Veillard2156d432004-03-04 15:59:36 +00006312}
6313#endif
6314
6315#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006316/**
6317 * xmlSetProp:
6318 * @node: the node
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006319 * @name: the attribute name (a QName)
Owen Taylor3473f882001-02-23 17:55:21 +00006320 * @value: the attribute value
6321 *
6322 * Set (or reset) an attribute carried by a node.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006323 * If @name has a prefix, then the corresponding
6324 * namespace-binding will be used, if in scope; it is an
6325 * error it there's no such ns-binding for the prefix in
6326 * scope.
Owen Taylor3473f882001-02-23 17:55:21 +00006327 * Returns the attribute pointer.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006328 *
Owen Taylor3473f882001-02-23 17:55:21 +00006329 */
6330xmlAttrPtr
6331xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006332 int len;
6333 const xmlChar *nqname;
Owen Taylor3473f882001-02-23 17:55:21 +00006334
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006335 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006336 return(NULL);
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006337
6338 /*
6339 * handle QNames
6340 */
6341 nqname = xmlSplitQName3(name, &len);
6342 if (nqname != NULL) {
6343 xmlNsPtr ns;
6344 xmlChar *prefix = xmlStrndup(name, len);
6345 ns = xmlSearchNs(node->doc, node, prefix);
6346 if (prefix != NULL)
6347 xmlFree(prefix);
6348 if (ns != NULL)
6349 return(xmlSetNsProp(node, ns, nqname, value));
6350 }
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006351 return(xmlSetNsProp(node, NULL, name, value));
Owen Taylor3473f882001-02-23 17:55:21 +00006352}
6353
6354/**
6355 * xmlSetNsProp:
6356 * @node: the node
6357 * @ns: the namespace definition
6358 * @name: the attribute name
6359 * @value: the attribute value
6360 *
6361 * Set (or reset) an attribute carried by a node.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006362 * The ns structure must be in scope, this is not checked
Owen Taylor3473f882001-02-23 17:55:21 +00006363 *
6364 * Returns the attribute pointer.
6365 */
6366xmlAttrPtr
6367xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006368 const xmlChar *value)
6369{
Owen Taylor3473f882001-02-23 17:55:21 +00006370 xmlAttrPtr prop;
6371
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006372 if (ns && (ns->href == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006373 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006374 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
6375 if (prop != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006376 /*
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006377 * Modify the attribute's value.
6378 */
6379 if (prop->atype == XML_ATTRIBUTE_ID) {
6380 xmlRemoveID(node->doc, prop);
6381 prop->atype = XML_ATTRIBUTE_ID;
6382 }
6383 if (prop->children != NULL)
6384 xmlFreeNodeList(prop->children);
6385 prop->children = NULL;
6386 prop->last = NULL;
6387 prop->ns = ns;
6388 if (value != NULL) {
6389 xmlChar *buffer;
6390 xmlNodePtr tmp;
6391
6392 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6393 prop->children = xmlStringGetNodeList(node->doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00006394 prop->last = NULL;
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006395 tmp = prop->children;
6396 while (tmp != NULL) {
6397 tmp->parent = (xmlNodePtr) prop;
6398 if (tmp->next == NULL)
6399 prop->last = tmp;
6400 tmp = tmp->next;
6401 }
6402 xmlFree(buffer);
6403 }
6404 if (prop->atype == XML_ATTRIBUTE_ID)
6405 xmlAddID(NULL, node->doc, value, prop);
6406 return(prop);
Owen Taylor3473f882001-02-23 17:55:21 +00006407 }
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006408 /*
6409 * No equal attr found; create a new one.
6410 */
6411 return(xmlNewPropInternal(node, ns, name, value, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006412}
6413
Daniel Veillard652327a2003-09-29 18:02:38 +00006414#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006415
6416/**
Owen Taylor3473f882001-02-23 17:55:21 +00006417 * xmlNodeIsText:
6418 * @node: the node
6419 *
6420 * Is this node a Text node ?
6421 * Returns 1 yes, 0 no
6422 */
6423int
6424xmlNodeIsText(xmlNodePtr node) {
6425 if (node == NULL) return(0);
6426
6427 if (node->type == XML_TEXT_NODE) return(1);
6428 return(0);
6429}
6430
6431/**
6432 * xmlIsBlankNode:
6433 * @node: the node
6434 *
6435 * Checks whether this node is an empty or whitespace only
6436 * (and possibly ignorable) text-node.
6437 *
6438 * Returns 1 yes, 0 no
6439 */
6440int
6441xmlIsBlankNode(xmlNodePtr node) {
6442 const xmlChar *cur;
6443 if (node == NULL) return(0);
6444
Daniel Veillard7db37732001-07-12 01:20:08 +00006445 if ((node->type != XML_TEXT_NODE) &&
6446 (node->type != XML_CDATA_SECTION_NODE))
6447 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006448 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006449 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006450 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006451 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006452 cur++;
6453 }
6454
6455 return(1);
6456}
6457
6458/**
6459 * xmlTextConcat:
6460 * @node: the node
6461 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006462 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006463 *
6464 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006465 *
6466 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006467 */
6468
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006469int
Owen Taylor3473f882001-02-23 17:55:21 +00006470xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006471 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006472
6473 if ((node->type != XML_TEXT_NODE) &&
6474 (node->type != XML_CDATA_SECTION_NODE)) {
6475#ifdef DEBUG_TREE
6476 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006477 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006478#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006479 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006480 }
William M. Brack7762bb12004-01-04 14:49:01 +00006481 /* need to check if content is currently in the dictionary */
Daniel Veillard8874b942005-08-25 13:19:21 +00006482 if ((node->content == (xmlChar *) &(node->properties)) ||
6483 ((node->doc != NULL) && (node->doc->dict != NULL) &&
6484 xmlDictOwns(node->doc->dict, node->content))) {
William M. Brack7762bb12004-01-04 14:49:01 +00006485 node->content = xmlStrncatNew(node->content, content, len);
6486 } else {
6487 node->content = xmlStrncat(node->content, content, len);
6488 }
Daniel Veillard8874b942005-08-25 13:19:21 +00006489 node->properties = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006490 if (node->content == NULL)
6491 return(-1);
6492 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006493}
6494
6495/************************************************************************
6496 * *
6497 * Output : to a FILE or in memory *
6498 * *
6499 ************************************************************************/
6500
Owen Taylor3473f882001-02-23 17:55:21 +00006501/**
6502 * xmlBufferCreate:
6503 *
6504 * routine to create an XML buffer.
6505 * returns the new structure.
6506 */
6507xmlBufferPtr
6508xmlBufferCreate(void) {
6509 xmlBufferPtr ret;
6510
6511 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6512 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006513 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006514 return(NULL);
6515 }
6516 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006517 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006518 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006519 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006520 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006521 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006522 xmlFree(ret);
6523 return(NULL);
6524 }
6525 ret->content[0] = 0;
6526 return(ret);
6527}
6528
6529/**
6530 * xmlBufferCreateSize:
6531 * @size: initial size of buffer
6532 *
6533 * routine to create an XML buffer.
6534 * returns the new structure.
6535 */
6536xmlBufferPtr
6537xmlBufferCreateSize(size_t size) {
6538 xmlBufferPtr ret;
6539
6540 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6541 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006542 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006543 return(NULL);
6544 }
6545 ret->use = 0;
6546 ret->alloc = xmlBufferAllocScheme;
6547 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6548 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006549 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006550 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006551 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006552 xmlFree(ret);
6553 return(NULL);
6554 }
6555 ret->content[0] = 0;
6556 } else
6557 ret->content = NULL;
6558 return(ret);
6559}
6560
6561/**
Daniel Veillard53350552003-09-18 13:35:51 +00006562 * xmlBufferCreateStatic:
6563 * @mem: the memory area
6564 * @size: the size in byte
6565 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006566 * routine to create an XML buffer from an immutable memory area.
6567 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006568 * present until the end of the buffer lifetime.
6569 *
6570 * returns the new structure.
6571 */
6572xmlBufferPtr
6573xmlBufferCreateStatic(void *mem, size_t size) {
6574 xmlBufferPtr ret;
6575
6576 if ((mem == NULL) || (size == 0))
6577 return(NULL);
6578
6579 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6580 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006581 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006582 return(NULL);
6583 }
6584 ret->use = size;
6585 ret->size = size;
6586 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6587 ret->content = (xmlChar *) mem;
6588 return(ret);
6589}
6590
6591/**
Owen Taylor3473f882001-02-23 17:55:21 +00006592 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006593 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006594 * @scheme: allocation scheme to use
6595 *
6596 * Sets the allocation scheme for this buffer
6597 */
6598void
6599xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6600 xmlBufferAllocationScheme scheme) {
6601 if (buf == NULL) {
6602#ifdef DEBUG_BUFFER
6603 xmlGenericError(xmlGenericErrorContext,
6604 "xmlBufferSetAllocationScheme: buf == NULL\n");
6605#endif
6606 return;
6607 }
Daniel Veillard53350552003-09-18 13:35:51 +00006608 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006609
6610 buf->alloc = scheme;
6611}
6612
6613/**
6614 * xmlBufferFree:
6615 * @buf: the buffer to free
6616 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006617 * Frees an XML buffer. It frees both the content and the structure which
6618 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006619 */
6620void
6621xmlBufferFree(xmlBufferPtr buf) {
6622 if (buf == NULL) {
6623#ifdef DEBUG_BUFFER
6624 xmlGenericError(xmlGenericErrorContext,
6625 "xmlBufferFree: buf == NULL\n");
6626#endif
6627 return;
6628 }
Daniel Veillard53350552003-09-18 13:35:51 +00006629
6630 if ((buf->content != NULL) &&
6631 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006632 xmlFree(buf->content);
6633 }
Owen Taylor3473f882001-02-23 17:55:21 +00006634 xmlFree(buf);
6635}
6636
6637/**
6638 * xmlBufferEmpty:
6639 * @buf: the buffer
6640 *
6641 * empty a buffer.
6642 */
6643void
6644xmlBufferEmpty(xmlBufferPtr buf) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006645 if (buf == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006646 if (buf->content == NULL) return;
6647 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006648 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006649 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006650 } else {
6651 memset(buf->content, 0, buf->size);
6652 }
Owen Taylor3473f882001-02-23 17:55:21 +00006653}
6654
6655/**
6656 * xmlBufferShrink:
6657 * @buf: the buffer to dump
6658 * @len: the number of xmlChar to remove
6659 *
6660 * Remove the beginning of an XML buffer.
6661 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006662 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006663 */
6664int
6665xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
Daniel Veillard3d97e662004-11-04 10:49:00 +00006666 if (buf == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006667 if (len == 0) return(0);
6668 if (len > buf->use) return(-1);
6669
6670 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006671 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6672 buf->content += len;
6673 } else {
6674 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6675 buf->content[buf->use] = 0;
6676 }
Owen Taylor3473f882001-02-23 17:55:21 +00006677 return(len);
6678}
6679
6680/**
6681 * xmlBufferGrow:
6682 * @buf: the buffer
6683 * @len: the minimum free size to allocate
6684 *
6685 * Grow the available space of an XML buffer.
6686 *
6687 * Returns the new available space or -1 in case of error
6688 */
6689int
6690xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6691 int size;
6692 xmlChar *newbuf;
6693
Daniel Veillard3d97e662004-11-04 10:49:00 +00006694 if (buf == NULL) return(-1);
6695
Daniel Veillard53350552003-09-18 13:35:51 +00006696 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006697 if (len + buf->use < buf->size) return(0);
6698
William M. Brack30fe43f2004-07-26 18:00:58 +00006699/*
6700 * Windows has a BIG problem on realloc timing, so we try to double
6701 * the buffer size (if that's enough) (bug 146697)
6702 */
6703#ifdef WIN32
6704 if (buf->size > len)
6705 size = buf->size * 2;
6706 else
6707 size = buf->use + len + 100;
6708#else
Owen Taylor3473f882001-02-23 17:55:21 +00006709 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00006710#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006711
6712 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006713 if (newbuf == NULL) {
6714 xmlTreeErrMemory("growing buffer");
6715 return(-1);
6716 }
Owen Taylor3473f882001-02-23 17:55:21 +00006717 buf->content = newbuf;
6718 buf->size = size;
6719 return(buf->size - buf->use);
6720}
6721
6722/**
6723 * xmlBufferDump:
6724 * @file: the file output
6725 * @buf: the buffer to dump
6726 *
6727 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006728 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006729 */
6730int
6731xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6732 int ret;
6733
6734 if (buf == NULL) {
6735#ifdef DEBUG_BUFFER
6736 xmlGenericError(xmlGenericErrorContext,
6737 "xmlBufferDump: buf == NULL\n");
6738#endif
6739 return(0);
6740 }
6741 if (buf->content == NULL) {
6742#ifdef DEBUG_BUFFER
6743 xmlGenericError(xmlGenericErrorContext,
6744 "xmlBufferDump: buf->content == NULL\n");
6745#endif
6746 return(0);
6747 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006748 if (file == NULL)
6749 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006750 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6751 return(ret);
6752}
6753
6754/**
6755 * xmlBufferContent:
6756 * @buf: the buffer
6757 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006758 * Function to extract the content of a buffer
6759 *
Owen Taylor3473f882001-02-23 17:55:21 +00006760 * Returns the internal content
6761 */
6762
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006763const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006764xmlBufferContent(const xmlBufferPtr buf)
6765{
6766 if(!buf)
6767 return NULL;
6768
6769 return buf->content;
6770}
6771
6772/**
6773 * xmlBufferLength:
6774 * @buf: the buffer
6775 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006776 * Function to get the length of a buffer
6777 *
Owen Taylor3473f882001-02-23 17:55:21 +00006778 * Returns the length of data in the internal content
6779 */
6780
6781int
6782xmlBufferLength(const xmlBufferPtr buf)
6783{
6784 if(!buf)
6785 return 0;
6786
6787 return buf->use;
6788}
6789
6790/**
6791 * xmlBufferResize:
6792 * @buf: the buffer to resize
6793 * @size: the desired size
6794 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006795 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006796 *
6797 * Returns 0 in case of problems, 1 otherwise
6798 */
6799int
6800xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6801{
6802 unsigned int newSize;
6803 xmlChar* rebuf = NULL;
6804
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006805 if (buf == NULL)
6806 return(0);
6807
Daniel Veillard53350552003-09-18 13:35:51 +00006808 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6809
Owen Taylor3473f882001-02-23 17:55:21 +00006810 /* Don't resize if we don't have to */
6811 if (size < buf->size)
6812 return 1;
6813
6814 /* figure out new size */
6815 switch (buf->alloc){
6816 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillardbf629492004-04-20 22:20:59 +00006817 /*take care of empty case*/
6818 newSize = (buf->size ? buf->size*2 : size + 10);
Owen Taylor3473f882001-02-23 17:55:21 +00006819 while (size > newSize) newSize *= 2;
6820 break;
6821 case XML_BUFFER_ALLOC_EXACT:
6822 newSize = size+10;
6823 break;
6824 default:
6825 newSize = size+10;
6826 break;
6827 }
6828
6829 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006830 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006831 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006832 rebuf = (xmlChar *) xmlRealloc(buf->content,
6833 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006834 } else {
6835 /*
6836 * if we are reallocating a buffer far from being full, it's
6837 * better to make a new allocation and copy only the used range
6838 * and free the old one.
6839 */
6840 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6841 if (rebuf != NULL) {
6842 memcpy(rebuf, buf->content, buf->use);
6843 xmlFree(buf->content);
William M. Brack42331a92004-07-29 07:07:16 +00006844 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006845 }
6846 }
Owen Taylor3473f882001-02-23 17:55:21 +00006847 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006848 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006849 return 0;
6850 }
6851 buf->content = rebuf;
6852 buf->size = newSize;
6853
6854 return 1;
6855}
6856
6857/**
6858 * xmlBufferAdd:
6859 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006860 * @str: the #xmlChar string
6861 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006862 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006863 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006864 * str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006865 *
6866 * Returns 0 successful, a positive error code number otherwise
6867 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006868 */
William M. Bracka3215c72004-07-31 16:24:01 +00006869int
Owen Taylor3473f882001-02-23 17:55:21 +00006870xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6871 unsigned int needSize;
6872
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006873 if ((str == NULL) || (buf == NULL)) {
William M. Bracka3215c72004-07-31 16:24:01 +00006874 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006875 }
William M. Bracka3215c72004-07-31 16:24:01 +00006876 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006877 if (len < -1) {
6878#ifdef DEBUG_BUFFER
6879 xmlGenericError(xmlGenericErrorContext,
6880 "xmlBufferAdd: len < 0\n");
6881#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006882 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006883 }
William M. Bracka3215c72004-07-31 16:24:01 +00006884 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006885
6886 if (len < 0)
6887 len = xmlStrlen(str);
6888
William M. Bracka3215c72004-07-31 16:24:01 +00006889 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006890
6891 needSize = buf->use + len + 2;
6892 if (needSize > buf->size){
6893 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006894 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006895 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006896 }
6897 }
6898
6899 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6900 buf->use += len;
6901 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006902 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006903}
6904
6905/**
6906 * xmlBufferAddHead:
6907 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006908 * @str: the #xmlChar string
6909 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006910 *
6911 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006912 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006913 *
6914 * Returns 0 successful, a positive error code number otherwise
6915 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006916 */
William M. Bracka3215c72004-07-31 16:24:01 +00006917int
Owen Taylor3473f882001-02-23 17:55:21 +00006918xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6919 unsigned int needSize;
6920
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006921 if (buf == NULL)
6922 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00006923 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006924 if (str == NULL) {
6925#ifdef DEBUG_BUFFER
6926 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006927 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006928#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006929 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006930 }
6931 if (len < -1) {
6932#ifdef DEBUG_BUFFER
6933 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006934 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006935#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006936 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006937 }
William M. Bracka3215c72004-07-31 16:24:01 +00006938 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006939
6940 if (len < 0)
6941 len = xmlStrlen(str);
6942
William M. Bracka3215c72004-07-31 16:24:01 +00006943 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006944
6945 needSize = buf->use + len + 2;
6946 if (needSize > buf->size){
6947 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006948 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006949 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006950 }
6951 }
6952
6953 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6954 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6955 buf->use += len;
6956 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006957 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006958}
6959
6960/**
6961 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00006962 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00006963 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006964 *
6965 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00006966 *
6967 * Returns 0 successful, a positive error code number otherwise
6968 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006969 */
William M. Bracka3215c72004-07-31 16:24:01 +00006970int
Owen Taylor3473f882001-02-23 17:55:21 +00006971xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006972 if (buf == NULL)
6973 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00006974 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
6975 if (str == NULL) return -1;
6976 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00006977}
6978
6979/**
6980 * xmlBufferCCat:
6981 * @buf: the buffer to dump
6982 * @str: the C char string
6983 *
6984 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00006985 *
6986 * Returns 0 successful, a positive error code number otherwise
6987 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006988 */
William M. Bracka3215c72004-07-31 16:24:01 +00006989int
Owen Taylor3473f882001-02-23 17:55:21 +00006990xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6991 const char *cur;
6992
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006993 if (buf == NULL)
6994 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00006995 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006996 if (str == NULL) {
6997#ifdef DEBUG_BUFFER
6998 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006999 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007000#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007001 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007002 }
7003 for (cur = str;*cur != 0;cur++) {
7004 if (buf->use + 10 >= buf->size) {
7005 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007006 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007007 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007008 }
7009 }
7010 buf->content[buf->use++] = *cur;
7011 }
7012 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007013 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007014}
7015
7016/**
7017 * xmlBufferWriteCHAR:
7018 * @buf: the XML buffer
7019 * @string: the string to add
7020 *
7021 * routine which manages and grows an output buffer. This one adds
7022 * xmlChars at the end of the buffer.
7023 */
7024void
Daniel Veillard53350552003-09-18 13:35:51 +00007025xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007026 if (buf == NULL)
7027 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007028 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007029 xmlBufferCat(buf, string);
7030}
7031
7032/**
7033 * xmlBufferWriteChar:
7034 * @buf: the XML buffer output
7035 * @string: the string to add
7036 *
7037 * routine which manage and grows an output buffer. This one add
7038 * C chars at the end of the array.
7039 */
7040void
7041xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007042 if (buf == NULL)
7043 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007044 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007045 xmlBufferCCat(buf, string);
7046}
7047
7048
7049/**
7050 * xmlBufferWriteQuotedString:
7051 * @buf: the XML buffer output
7052 * @string: the string to add
7053 *
7054 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00007055 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00007056 * quote or double-quotes internally
7057 */
7058void
7059xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00007060 const xmlChar *cur, *base;
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007061 if (buf == NULL)
7062 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007063 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00007064 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00007065 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00007066#ifdef DEBUG_BUFFER
7067 xmlGenericError(xmlGenericErrorContext,
7068 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7069#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00007070 xmlBufferCCat(buf, "\"");
7071 base = cur = string;
7072 while(*cur != 0){
7073 if(*cur == '"'){
7074 if (base != cur)
7075 xmlBufferAdd(buf, base, cur - base);
7076 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7077 cur++;
7078 base = cur;
7079 }
7080 else {
7081 cur++;
7082 }
7083 }
7084 if (base != cur)
7085 xmlBufferAdd(buf, base, cur - base);
7086 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007087 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007088 else{
7089 xmlBufferCCat(buf, "\'");
7090 xmlBufferCat(buf, string);
7091 xmlBufferCCat(buf, "\'");
7092 }
Owen Taylor3473f882001-02-23 17:55:21 +00007093 } else {
7094 xmlBufferCCat(buf, "\"");
7095 xmlBufferCat(buf, string);
7096 xmlBufferCCat(buf, "\"");
7097 }
7098}
7099
7100
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007101/**
7102 * xmlGetDocCompressMode:
7103 * @doc: the document
7104 *
7105 * get the compression ratio for a document, ZLIB based
7106 * Returns 0 (uncompressed) to 9 (max compression)
7107 */
7108int
7109xmlGetDocCompressMode (xmlDocPtr doc) {
7110 if (doc == NULL) return(-1);
7111 return(doc->compression);
7112}
7113
7114/**
7115 * xmlSetDocCompressMode:
7116 * @doc: the document
7117 * @mode: the compression ratio
7118 *
7119 * set the compression ratio for a document, ZLIB based
7120 * Correct values: 0 (uncompressed) to 9 (max compression)
7121 */
7122void
7123xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7124 if (doc == NULL) return;
7125 if (mode < 0) doc->compression = 0;
7126 else if (mode > 9) doc->compression = 9;
7127 else doc->compression = mode;
7128}
7129
7130/**
7131 * xmlGetCompressMode:
7132 *
7133 * get the default compression mode used, ZLIB based.
7134 * Returns 0 (uncompressed) to 9 (max compression)
7135 */
7136int
7137xmlGetCompressMode(void)
7138{
7139 return (xmlCompressMode);
7140}
7141
7142/**
7143 * xmlSetCompressMode:
7144 * @mode: the compression ratio
7145 *
7146 * set the default compression mode used, ZLIB based
7147 * Correct values: 0 (uncompressed) to 9 (max compression)
7148 */
7149void
7150xmlSetCompressMode(int mode) {
7151 if (mode < 0) xmlCompressMode = 0;
7152 else if (mode > 9) xmlCompressMode = 9;
7153 else xmlCompressMode = mode;
7154}
7155
Kasimier T. Buchcik4d9c9482005-06-27 15:04:46 +00007156/*
7157* xmlDOMWrapNewCtxt:
7158*
7159* Allocates and initializes a new DOM-wrapper context.
7160*
7161* Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal errror.
7162*/
7163xmlDOMWrapCtxtPtr
7164xmlDOMWrapNewCtxt(void)
7165{
7166 xmlDOMWrapCtxtPtr ret;
7167
7168 ret = xmlMalloc(sizeof(xmlDOMWrapCtxt));
7169 if (ret == NULL) {
7170 xmlTreeErrMemory("allocating DOM-wrapper context");
7171 return (NULL);
7172 }
7173 memset(ret, 0, sizeof(xmlDOMWrapCtxt));
7174 return (ret);
7175}
7176
7177/*
7178* xmlDOMWrapFreeCtxt:
7179* @ctxt: the DOM-wrapper context
7180*
7181* Frees the DOM-wrapper context.
7182*/
7183void
7184xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt)
7185{
7186 if (ctxt == NULL)
7187 return;
7188 xmlFree(ctxt);
7189}
7190
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007191#define XML_TREE_NSMAP_PARENT -1
7192#define XML_TREE_NSMAP_XML -2
7193#define XML_TREE_NSMAP_DOC -3
7194#define XML_TREE_NSMAP_CUSTOM -4
7195
7196typedef struct xmlNsMapItem *xmlNsMapItemPtr;
7197struct xmlNsMapItem {
7198 xmlNsMapItemPtr next;
7199 xmlNsMapItemPtr prev;
7200 xmlNsPtr oldNs; /* old ns decl reference */
7201 xmlNsPtr newNs; /* new ns decl reference */
7202 int shadowDepth; /* Shadowed at this depth */
7203 /*
7204 * depth:
7205 * >= 0 == @node's ns-decls
7206 * -1 == @parent's ns-decls
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00007207 * -2 == the doc->oldNs XML ns-decl
7208 * -3 == the doc->oldNs storage ns-decls
7209 * -4 == ns-decls provided via custom ns-handling
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007210 */
7211 int depth;
7212};
7213
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007214typedef struct xmlNsMap *xmlNsMapPtr;
7215struct xmlNsMap {
7216 xmlNsMapItemPtr first;
7217 xmlNsMapItemPtr last;
7218 xmlNsMapItemPtr pool;
7219};
7220
7221#define XML_NSMAP_NOTEMPTY(m) (((m) != NULL) && ((m)->first != NULL))
7222#define XML_NSMAP_FOREACH(m, i) for (i = (m)->first; i != NULL; i = (i)->next)
7223#define XML_NSMAP_POP(m, i) \
7224 i = (m)->last; \
7225 (m)->last = (i)->prev; \
7226 if ((m)->last == NULL) \
7227 (m)->first = NULL; \
7228 else \
7229 (m)->last->next = NULL; \
7230 (i)->next = (m)->pool; \
7231 (m)->pool = i;
7232
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007233/*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007234* xmlDOMWrapNsMapFree:
7235* @map: the ns-map
7236*
7237* Frees the ns-map
7238*/
7239static void
7240xmlDOMWrapNsMapFree(xmlNsMapPtr nsmap)
7241{
7242 xmlNsMapItemPtr cur, tmp;
7243
7244 if (nsmap == NULL)
7245 return;
7246 cur = nsmap->pool;
7247 while (cur != NULL) {
7248 tmp = cur;
7249 cur = cur->next;
7250 xmlFree(tmp);
7251 }
7252 cur = nsmap->first;
7253 while (cur != NULL) {
7254 tmp = cur;
7255 cur = cur->next;
7256 xmlFree(tmp);
7257 }
7258 xmlFree(nsmap);
7259}
7260
7261/*
7262* xmlDOMWrapNsMapAddItem:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007263* @map: the ns-map
7264* @cur: the current map entry to append a new entry to
7265* @oldNs: the old ns-struct
7266* @newNs: the new ns-struct
7267* @depth: depth and ns-kind information
7268*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007269* Adds an ns-mapping item.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007270*/
7271static xmlNsMapItemPtr
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007272xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position, /* xmlNsMapItemPtr *cur, */
7273 xmlNsPtr oldNs, xmlNsPtr newNs, int depth)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007274{
7275 xmlNsMapItemPtr ret;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007276 xmlNsMapPtr map;
7277
7278 if (nsmap == NULL)
7279 return(NULL);
7280 if ((position != -1) && (position != 0))
7281 return(NULL);
7282 map = *nsmap;
7283
7284 if (map == NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007285 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007286 * Create the ns-map.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007287 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007288 map = (xmlNsMapPtr) xmlMalloc(sizeof(struct xmlNsMap));
7289 if (map == NULL) {
7290 xmlTreeErrMemory("allocating namespace map");
7291 return (NULL);
7292 }
7293 memset(map, 0, sizeof(struct xmlNsMap));
7294 *nsmap = map;
7295 }
7296
7297 if (map->pool != NULL) {
7298 /*
7299 * Reuse an item from the pool.
7300 */
7301 ret = map->pool;
7302 map->pool = ret->next;
7303 memset(ret, 0, sizeof(struct xmlNsMapItem));
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007304 } else {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007305 /*
7306 * Create a new item.
7307 */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007308 ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem));
7309 if (ret == NULL) {
7310 xmlTreeErrMemory("allocating namespace map item");
7311 return (NULL);
7312 }
7313 memset(ret, 0, sizeof(struct xmlNsMapItem));
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007314 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007315
7316 if (map->first == NULL) {
7317 /*
7318 * First ever.
7319 */
7320 map->first = ret;
7321 map->last = ret;
7322 } else if (position == -1) {
7323 /*
7324 * Append.
7325 */
7326 ret->prev = map->last;
7327 map->last->next = ret;
7328 map->last = ret;
7329 } else if (position == 0) {
7330 /*
7331 * Set on first position.
7332 */
7333 map->first->prev = ret;
7334 ret->next = map->first;
7335 map->first = ret;
7336 } else
7337 return(NULL);
7338
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007339 ret->oldNs = oldNs;
7340 ret->newNs = newNs;
7341 ret->shadowDepth = -1;
7342 ret->depth = depth;
7343 return (ret);
7344}
7345
7346/*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007347* xmlTreeEnsureXMLDecl:
7348* @doc: the doc
7349*
7350* Ensures that there is an XML namespace declaration on the doc.
7351*
7352* Returns the XML ns-struct or NULL on API and internal errors.
7353*/
7354static xmlNsPtr
7355xmlTreeEnsureXMLDecl(xmlDocPtr doc)
7356{
7357 if (doc == NULL)
7358 return (NULL);
7359 if (doc->oldNs != NULL)
7360 return (doc->oldNs);
7361 {
7362 xmlNsPtr ns;
7363 ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
7364 if (ns == NULL) {
7365 xmlTreeErrMemory(
7366 "allocating the XML namespace");
7367 return (NULL);
7368 }
7369 memset(ns, 0, sizeof(xmlNs));
7370 ns->type = XML_LOCAL_NAMESPACE;
7371 ns->href = xmlStrdup(XML_XML_NAMESPACE);
7372 ns->prefix = xmlStrdup((const xmlChar *)"xml");
7373 doc->oldNs = ns;
7374 return (ns);
7375 }
7376}
7377
7378/*
7379* xmlDOMWrapStoreNs:
7380* @doc: the doc
7381* @nsName: the namespace name
7382* @prefix: the prefix
7383*
7384* Creates or reuses an xmlNs struct on doc->oldNs with
7385* the given prefix and namespace name.
7386*
7387* Returns the aquired ns struct or NULL in case of an API
7388* or internal error.
7389*/
7390static xmlNsPtr
7391xmlDOMWrapStoreNs(xmlDocPtr doc,
7392 const xmlChar *nsName,
7393 const xmlChar *prefix)
7394{
7395 xmlNsPtr ns;
7396
7397 if (doc == NULL)
7398 return (NULL);
7399 ns = xmlTreeEnsureXMLDecl(doc);
7400 if (ns == NULL)
7401 return (NULL);
7402 if (ns->next != NULL) {
7403 /* Reuse. */
7404 ns = ns->next;
7405 while (ns != NULL) {
7406 if (((ns->prefix == prefix) ||
7407 xmlStrEqual(ns->prefix, prefix)) &&
7408 xmlStrEqual(ns->href, nsName)) {
7409 return (ns);
7410 }
7411 if (ns->next == NULL)
7412 break;
7413 ns = ns->next;
7414 }
7415 }
7416 /* Create. */
7417 ns->next = xmlNewNs(NULL, nsName, prefix);
7418 return (ns->next);
7419}
7420
7421/*
7422* xmlTreeLookupNsListByPrefix:
7423* @nsList: a list of ns-structs
7424* @prefix: the searched prefix
7425*
7426* Searches for a ns-decl with the given prefix in @nsList.
7427*
7428* Returns the ns-decl if found, NULL if not found and on
7429* API errors.
7430*/
7431static xmlNsPtr
7432xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix)
7433{
7434 if (nsList == NULL)
7435 return (NULL);
7436 {
7437 xmlNsPtr ns;
7438 ns = nsList;
7439 do {
7440 if ((prefix == ns->prefix) ||
7441 xmlStrEqual(prefix, ns->prefix)) {
7442 return (ns);
7443 }
7444 ns = ns->next;
7445 } while (ns != NULL);
7446 }
7447 return (NULL);
7448}
7449
7450/*
7451*
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00007452* xmlDOMWrapNSNormGatherInScopeNs:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007453* @map: the namespace map
7454* @node: the node to start with
7455*
7456* Puts in-scope namespaces into the ns-map.
7457*
7458* Returns 0 on success, -1 on API or internal errors.
7459*/
7460static int
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007461xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapPtr *map,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007462 xmlNodePtr node)
7463{
7464 xmlNodePtr cur;
7465 xmlNsPtr ns;
7466 xmlNsMapItemPtr mi;
7467 int shadowed;
7468
7469 if ((map == NULL) || (*map != NULL))
7470 return (-1);
7471 /*
7472 * Get in-scope ns-decls of @parent.
7473 */
7474 cur = node;
7475 while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) {
7476 if (cur->type == XML_ELEMENT_NODE) {
7477 if (cur->nsDef != NULL) {
7478 ns = cur->nsDef;
7479 do {
7480 shadowed = 0;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007481 if (XML_NSMAP_NOTEMPTY(*map)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007482 /*
7483 * Skip shadowed prefixes.
7484 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007485 XML_NSMAP_FOREACH(*map, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007486 if ((ns->prefix == mi->newNs->prefix) ||
7487 xmlStrEqual(ns->prefix, mi->newNs->prefix)) {
7488 shadowed = 1;
7489 break;
7490 }
7491 }
7492 }
7493 /*
7494 * Insert mapping.
7495 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007496 mi = xmlDOMWrapNsMapAddItem(map, 0, NULL,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007497 ns, XML_TREE_NSMAP_PARENT);
7498 if (mi == NULL)
7499 return (-1);
7500 if (shadowed)
7501 mi->shadowDepth = 0;
7502 ns = ns->next;
7503 } while (ns != NULL);
7504 }
7505 }
7506 cur = cur->parent;
7507 }
7508 return (0);
7509}
7510
7511/*
7512* XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict;
7513* otherwise copy it, when it was in the source-dict.
7514*/
7515#define XML_TREE_ADOPT_STR(str) \
7516 if (adoptStr && (str != NULL)) { \
7517 if (destDoc->dict) { \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00007518 const xmlChar *old = str; \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007519 str = xmlDictLookup(destDoc->dict, str, -1); \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00007520 if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \
7521 (!xmlDictOwns(sourceDoc->dict, old))) \
Daniel Veillard39e5c892005-07-03 22:48:50 +00007522 xmlFree((char *)old); \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007523 } else if ((sourceDoc) && (sourceDoc->dict) && \
7524 xmlDictOwns(sourceDoc->dict, str)) { \
7525 str = BAD_CAST xmlStrdup(str); \
7526 } \
7527 }
7528
7529/*
7530* XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then
7531* put it in dest-dict or copy it.
7532*/
7533#define XML_TREE_ADOPT_STR_2(str) \
7534 if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \
7535 (sourceDoc->dict != NULL) && \
7536 xmlDictOwns(sourceDoc->dict, cur->content)) { \
7537 if (destDoc->dict) \
7538 cur->content = (xmlChar *) \
7539 xmlDictLookup(destDoc->dict, cur->content, -1); \
7540 else \
7541 cur->content = xmlStrdup(BAD_CAST cur->content); \
7542 }
7543
7544/*
7545* xmlDOMWrapNSNormAddNsMapItem2:
7546*
7547* For internal use. Adds a ns-decl mapping.
7548*
7549* Returns 0 on success, -1 on internal errors.
7550*/
7551static int
7552xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number,
7553 xmlNsPtr oldNs, xmlNsPtr newNs)
7554{
7555 if (*list == NULL) {
7556 *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr));
7557 if (*list == NULL) {
7558 xmlTreeErrMemory("alloc ns map item");
7559 return(-1);
7560 }
7561 *size = 3;
7562 *number = 0;
7563 } else if ((*number) >= (*size)) {
7564 *size *= 2;
7565 *list = (xmlNsPtr *) xmlRealloc(*list,
7566 (*size) * 2 * sizeof(xmlNsPtr));
7567 if (*list == NULL) {
7568 xmlTreeErrMemory("realloc ns map item");
7569 return(-1);
7570 }
7571 }
7572 (*list)[2 * (*number)] = oldNs;
7573 (*list)[2 * (*number) +1] = newNs;
7574 (*number)++;
7575 return (0);
7576}
7577
7578/*
7579* xmlDOMWrapRemoveNode:
Daniel Veillard304e78c2005-07-03 16:19:41 +00007580* @ctxt: a DOM wrapper context
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007581* @doc: the doc
7582* @node: the node to be removed.
Daniel Veillard304e78c2005-07-03 16:19:41 +00007583* @options: set of options, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007584*
7585* Unlinks the given node from its owner.
7586* This will substitute ns-references to node->nsDef for
7587* ns-references to doc->oldNs, thus ensuring the removed
7588* branch to be autark wrt ns-references.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00007589* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007590*
7591* Returns 0 on success, 1 if the node is not supported,
7592* -1 on API and internal errors.
7593*/
7594int
7595xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc,
7596 xmlNodePtr node, int options ATTRIBUTE_UNUSED)
7597{
7598 xmlNsPtr *list = NULL;
7599 int sizeList, nbList, i, j;
7600 xmlNsPtr ns;
7601
7602 if ((node == NULL) || (doc == NULL) || (node->doc != doc))
7603 return (-1);
7604
7605 /* TODO: 0 or -1 ? */
7606 if (node->parent == NULL)
7607 return (0);
7608
7609 switch (node->type) {
7610 case XML_TEXT_NODE:
7611 case XML_CDATA_SECTION_NODE:
7612 case XML_ENTITY_REF_NODE:
7613 case XML_PI_NODE:
7614 case XML_COMMENT_NODE:
7615 xmlUnlinkNode(node);
7616 return (0);
7617 case XML_ELEMENT_NODE:
7618 case XML_ATTRIBUTE_NODE:
7619 break;
7620 default:
7621 return (1);
7622 }
7623 xmlUnlinkNode(node);
7624 /*
7625 * Save out-of-scope ns-references in doc->oldNs.
7626 */
7627 do {
7628 switch (node->type) {
7629 case XML_ELEMENT_NODE:
7630 if ((ctxt == NULL) && (node->nsDef != NULL)) {
7631 ns = node->nsDef;
7632 do {
7633 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
7634 &nbList, ns, ns) == -1)
7635 goto internal_error;
7636 ns = ns->next;
7637 } while (ns != NULL);
7638 }
7639 /* No break on purpose. */
7640 case XML_ATTRIBUTE_NODE:
7641 if (node->ns != NULL) {
7642 /*
7643 * Find a mapping.
7644 */
7645 if (list != NULL) {
7646 for (i = 0, j = 0; i < nbList; i++, j += 2) {
7647 if (node->ns == list[j]) {
7648 node->ns = list[++j];
7649 goto next_node;
7650 }
7651 }
7652 }
7653 ns = NULL;
7654 if (ctxt != NULL) {
7655 /*
7656 * User defined.
7657 */
7658 } else {
7659 /*
7660 * Add to doc's oldNs.
7661 */
7662 ns = xmlDOMWrapStoreNs(doc, node->ns->href,
7663 node->ns->prefix);
7664 if (ns == NULL)
7665 goto internal_error;
7666 }
7667 if (ns != NULL) {
7668 /*
7669 * Add mapping.
7670 */
7671 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
7672 &nbList, node->ns, ns) == -1)
7673 goto internal_error;
7674 }
7675 node->ns = ns;
7676 }
7677 if ((node->type == XML_ELEMENT_NODE) &&
7678 (node->properties != NULL)) {
7679 node = (xmlNodePtr) node->properties;
7680 continue;
7681 }
7682 break;
7683 default:
7684 goto next_sibling;
7685 }
7686next_node:
7687 if ((node->type == XML_ELEMENT_NODE) &&
7688 (node->children != NULL)) {
7689 node = node->children;
7690 continue;
7691 }
7692next_sibling:
7693 if (node == NULL)
7694 break;
7695 if (node->next != NULL)
7696 node = node->next;
7697 else {
7698 node = node->parent;
7699 goto next_sibling;
7700 }
7701 } while (node != NULL);
7702
7703 if (list != NULL)
7704 xmlFree(list);
7705 return (0);
7706
7707internal_error:
7708 if (list != NULL)
7709 xmlFree(list);
7710 return (-1);
7711}
7712
7713/*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007714* xmlSearchNsByNamespaceStrict:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007715* @doc: the document
7716* @node: the start node
7717* @nsName: the searched namespace name
7718* @retNs: the resulting ns-decl
7719* @prefixed: if the found ns-decl must have a prefix (for attributes)
7720*
7721* Dynamically searches for a ns-declaration which matches
7722* the given @nsName in the ancestor-or-self axis of @node.
7723*
7724* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7725* and internal errors.
7726*/
7727static int
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007728xmlSearchNsByNamespaceStrict(xmlDocPtr doc, xmlNodePtr node,
7729 const xmlChar* nsName,
7730 xmlNsPtr *retNs, int prefixed)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007731{
7732 xmlNodePtr cur, prev = NULL, out = NULL;
7733 xmlNsPtr ns, prevns;
7734
7735 if ((doc == NULL) || (nsName == NULL) || (retNs == NULL))
7736 return (-1);
7737
7738 *retNs = NULL;
7739 if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
7740 *retNs = xmlTreeEnsureXMLDecl(doc);
7741 if (*retNs == NULL)
7742 return (-1);
7743 return (1);
7744 }
7745 cur = node;
7746 do {
7747 if (cur->type == XML_ELEMENT_NODE) {
7748 if (cur->nsDef != NULL) {
7749 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
7750 if (prefixed && (ns->prefix == NULL))
7751 continue;
7752 if (prev != NULL) {
7753 /*
7754 * Check the last level of ns-decls for a
7755 * shadowing prefix.
7756 */
7757 prevns = prev->nsDef;
7758 do {
7759 if ((prevns->prefix == ns->prefix) ||
7760 ((prevns->prefix != NULL) &&
7761 (ns->prefix != NULL) &&
7762 xmlStrEqual(prevns->prefix, ns->prefix))) {
7763 /*
7764 * Shadowed.
7765 */
7766 break;
7767 }
7768 prevns = prevns->next;
7769 } while (prevns != NULL);
7770 if (prevns != NULL)
7771 continue;
7772 }
7773 /*
7774 * Ns-name comparison.
7775 */
7776 if ((nsName == ns->href) ||
7777 xmlStrEqual(nsName, ns->href)) {
7778 /*
7779 * At this point the prefix can only be shadowed,
7780 * if we are the the (at least) 3rd level of
7781 * ns-decls.
7782 */
7783 if (out) {
7784 int ret;
7785
7786 ret = xmlNsInScope(doc, node, prev, ns->prefix);
7787 if (ret < 0)
7788 return (-1);
7789 /*
7790 * TODO: Should we try to find a matching ns-name
7791 * only once? This here keeps on searching.
7792 * I think we should try further since, there might
7793 * be an other matching ns-decl with an unshadowed
7794 * prefix.
7795 */
7796 if (! ret)
7797 continue;
7798 }
7799 *retNs = ns;
7800 return (1);
7801 }
7802 }
7803 out = prev;
7804 prev = cur;
7805 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007806 } else if ((cur->type == XML_ENTITY_NODE) ||
7807 (cur->type == XML_ENTITY_DECL))
7808 return (0);
7809 cur = cur->parent;
7810 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
7811 return (0);
7812}
7813
7814/*
7815* xmlSearchNsByPrefixStrict:
7816* @doc: the document
7817* @node: the start node
7818* @prefix: the searched namespace prefix
7819* @retNs: the resulting ns-decl
7820* @prefixed: if the found ns-decl must have a prefix (for attributes)
7821*
7822* Dynamically searches for a ns-declaration which matches
7823* the given @nsName in the ancestor-or-self axis of @node.
7824*
7825* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7826* and internal errors.
7827*/
7828static int
7829xmlSearchNsByPrefixStrict(xmlDocPtr doc, xmlNodePtr node,
7830 const xmlChar* prefix,
7831 xmlNsPtr *retNs)
7832{
7833 xmlNodePtr cur;
7834 xmlNsPtr ns;
7835
7836 if ((doc == NULL) || (node == NULL))
7837 return (-1);
7838
7839 if (retNs)
7840 *retNs = NULL;
7841 if (IS_STR_XML(prefix)) {
7842 if (retNs) {
7843 *retNs = xmlTreeEnsureXMLDecl(doc);
7844 if (*retNs == NULL)
7845 return (-1);
7846 }
7847 return (1);
7848 }
7849 cur = node;
7850 do {
7851 if (cur->type == XML_ELEMENT_NODE) {
7852 if (cur->nsDef != NULL) {
7853 ns = cur->nsDef;
7854 do {
7855 if ((prefix == ns->prefix) ||
7856 xmlStrEqual(prefix, ns->prefix))
7857 {
7858 /*
7859 * Disabled namespaces, e.g. xmlns:abc="".
7860 */
7861 if (ns->href == NULL)
7862 return(0);
7863 if (retNs)
7864 *retNs = ns;
7865 return (1);
7866 }
7867 ns = ns->next;
7868 } while (ns != NULL);
7869 }
7870 } else if ((cur->type == XML_ENTITY_NODE) ||
7871 (cur->type == XML_ENTITY_DECL))
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007872 return (0);
7873 cur = cur->parent;
7874 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
7875 return (0);
7876}
7877
7878/*
7879* xmlDOMWrapNSNormDeclareNsForced:
7880* @doc: the doc
7881* @elem: the element-node to declare on
7882* @nsName: the namespace-name of the ns-decl
7883* @prefix: the preferred prefix of the ns-decl
7884* @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls
7885*
7886* Declares a new namespace on @elem. It tries to use the
7887* given @prefix; if a ns-decl with the given prefix is already existent
7888* on @elem, it will generate an other prefix.
7889*
7890* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7891* and internal errors.
7892*/
7893static xmlNsPtr
7894xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc,
7895 xmlNodePtr elem,
7896 const xmlChar *nsName,
7897 const xmlChar *prefix,
7898 int checkShadow)
7899{
7900
7901 xmlNsPtr ret;
7902 char buf[50];
7903 const xmlChar *pref;
7904 int counter = 0;
7905 /*
7906 * Create a ns-decl on @anchor.
7907 */
7908 pref = prefix;
7909 while (1) {
7910 /*
7911 * Lookup whether the prefix is unused in elem's ns-decls.
7912 */
7913 if ((elem->nsDef != NULL) &&
7914 (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL))
7915 goto ns_next_prefix;
7916 if (checkShadow && elem->parent &&
7917 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
7918 /*
7919 * Does it shadow ancestor ns-decls?
7920 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007921 if (xmlSearchNsByPrefixStrict(doc, elem->parent, pref, NULL) == 1)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007922 goto ns_next_prefix;
7923 }
7924 ret = xmlNewNs(NULL, nsName, pref);
7925 if (ret == NULL)
7926 return (NULL);
7927 if (elem->nsDef == NULL)
7928 elem->nsDef = ret;
7929 else {
7930 xmlNsPtr ns2 = elem->nsDef;
7931 while (ns2->next != NULL)
7932 ns2 = ns2->next;
7933 ns2->next = ret;
7934 }
7935 return (ret);
7936ns_next_prefix:
7937 counter++;
7938 if (counter > 1000)
7939 return (NULL);
7940 if (prefix == NULL) {
7941 snprintf((char *) buf, sizeof(buf),
7942 "default%d", counter);
7943 } else
7944 snprintf((char *) buf, sizeof(buf),
7945 "%.30s%d", (char *)prefix, counter);
7946 pref = BAD_CAST buf;
7947 }
7948}
7949
7950/*
7951* xmlDOMWrapNSNormAquireNormalizedNs:
7952* @doc: the doc
7953* @elem: the element-node to declare namespaces on
7954* @ns: the ns-struct to use for the search
7955* @retNs: the found/created ns-struct
7956* @nsMap: the ns-map
7957* @topmi: the last ns-map entry
7958* @depth: the current tree depth
7959* @ancestorsOnly: search in ancestor ns-decls only
7960* @prefixed: if the searched ns-decl must have a prefix (for attributes)
7961*
7962* Searches for a matching ns-name in the ns-decls of @nsMap, if not
7963* found it will either declare it on @elem, or store it in doc->oldNs.
7964* If a new ns-decl needs to be declared on @elem, it tries to use the
7965* @ns->prefix for it, if this prefix is already in use on @elem, it will
7966* change the prefix or the new ns-decl.
7967*
7968* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
7969*/
7970static int
7971xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc,
7972 xmlNodePtr elem,
7973 xmlNsPtr ns,
7974 xmlNsPtr *retNs,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007975 xmlNsMapPtr *nsMap,
7976
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007977 int depth,
7978 int ancestorsOnly,
7979 int prefixed)
7980{
7981 xmlNsMapItemPtr mi;
7982
7983 if ((doc == NULL) || (ns == NULL) || (retNs == NULL) ||
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007984 (nsMap == NULL))
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007985 return (-1);
7986
7987 *retNs = NULL;
7988 /*
7989 * Handle XML namespace.
7990 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007991 if (IS_STR_XML(ns->prefix)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007992 /*
7993 * Insert XML namespace mapping.
7994 */
7995 *retNs = xmlTreeEnsureXMLDecl(doc);
7996 if (*retNs == NULL)
7997 return (-1);
7998 return (0);
7999 }
8000 /*
8001 * If the search should be done in ancestors only and no
8002 * @elem (the first ancestor) was specified, then skip the search.
8003 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008004 if ((! (ancestorsOnly && (elem == NULL))) && (XML_NSMAP_NOTEMPTY(*nsMap)))
8005 {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008006 /*
8007 * Try to find an equal ns-name in in-scope ns-decls.
8008 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008009 XML_NSMAP_FOREACH(*nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008010 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8011 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008012 * ancestorsOnly: This should be turned on to gain speed,
8013 * if one knows that the branch itself was already
8014 * ns-wellformed and no stale references existed.
8015 * I.e. it searches in the ancestor axis only.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008016 */
8017 ((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) &&
8018 /* Skip shadowed prefixes. */
8019 (mi->shadowDepth == -1) &&
8020 /* Skip xmlns="" or xmlns:foo="". */
8021 ((mi->newNs->href != NULL) &&
8022 (mi->newNs->href[0] != 0)) &&
8023 /* Ensure a prefix if wanted. */
8024 ((! prefixed) || (mi->newNs->prefix != NULL)) &&
8025 /* Equal ns name */
8026 ((mi->newNs->href == ns->href) ||
8027 xmlStrEqual(mi->newNs->href, ns->href))) {
8028 /* Set the mapping. */
8029 mi->oldNs = ns;
8030 *retNs = mi->newNs;
8031 return (0);
8032 }
8033 }
8034 }
8035 /*
8036 * No luck, the namespace is out of scope or shadowed.
8037 */
8038 if (elem == NULL) {
8039 xmlNsPtr tmpns;
8040
8041 /*
8042 * Store ns-decls in "oldNs" of the document-node.
8043 */
8044 tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix);
8045 if (tmpns == NULL)
8046 return (-1);
8047 /*
8048 * Insert mapping.
8049 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008050 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008051 tmpns, XML_TREE_NSMAP_DOC) == NULL) {
8052 xmlFreeNs(tmpns);
8053 return (-1);
8054 }
8055 *retNs = tmpns;
8056 } else {
8057 xmlNsPtr tmpns;
8058
8059 tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href,
8060 ns->prefix, 0);
8061 if (tmpns == NULL)
8062 return (-1);
8063
8064 if (*nsMap != NULL) {
8065 /*
8066 * Does it shadow ancestor ns-decls?
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008067 */
8068 XML_NSMAP_FOREACH(*nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008069 if ((mi->depth < depth) &&
8070 (mi->shadowDepth == -1) &&
8071 ((ns->prefix == mi->newNs->prefix) ||
8072 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8073 /*
8074 * Shadows.
8075 */
8076 mi->shadowDepth = depth;
8077 break;
8078 }
8079 }
8080 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008081 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, depth) == NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008082 xmlFreeNs(tmpns);
8083 return (-1);
8084 }
8085 *retNs = tmpns;
8086 }
8087 return (0);
8088}
8089
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008090typedef enum {
8091 XML_DOM_RECONNS_REMOVEREDUND = 1<<0
8092} xmlDOMReconcileNSOptions;
8093
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008094/*
8095* xmlDOMWrapReconcileNamespaces:
Daniel Veillard304e78c2005-07-03 16:19:41 +00008096* @ctxt: DOM wrapper context, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008097* @elem: the element-node
8098* @options: option flags
8099*
8100* Ensures that ns-references point to ns-decls hold on element-nodes.
8101* Ensures that the tree is namespace wellformed by creating additional
8102* ns-decls where needed. Note that, since prefixes of already existent
8103* ns-decls can be shadowed by this process, it could break QNames in
8104* attribute values or element content.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00008105* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008106*
8107* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008108*/
8109
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008110int
8111xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,
8112 xmlNodePtr elem,
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008113 int options)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008114{
8115 int depth = -1, adoptns = 0, parnsdone = 0;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008116 xmlNsPtr ns, prevns;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008117 xmlDocPtr doc;
8118 xmlNodePtr cur, curElem = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008119 xmlNsMapPtr nsMap = NULL;
8120 xmlNsMapItemPtr /* topmi = NULL, */ mi;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008121 /* @ancestorsOnly should be set by an option flag. */
8122 int ancestorsOnly = 0;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008123 int optRemoveDedundantNS =
8124 ((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0;
8125 xmlNsPtr *listRedund = NULL;
8126 int sizeRedund = 0, nbRedund = 0, ret, i, j;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008127
8128 if ((elem == NULL) || (elem->doc == NULL) ||
8129 (elem->type != XML_ELEMENT_NODE))
8130 return (-1);
8131
8132 doc = elem->doc;
8133 cur = elem;
8134 do {
8135 switch (cur->type) {
8136 case XML_ELEMENT_NODE:
8137 adoptns = 1;
8138 curElem = cur;
8139 depth++;
8140 /*
8141 * Namespace declarations.
8142 */
8143 if (cur->nsDef != NULL) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008144 prevns = NULL;
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008145 ns = cur->nsDef;
8146 while (ns != NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008147 if (! parnsdone) {
8148 if ((elem->parent) &&
8149 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8150 /*
8151 * Gather ancestor in-scope ns-decls.
8152 */
8153 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8154 elem->parent) == -1)
8155 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008156 }
8157 parnsdone = 1;
8158 }
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008159
8160 /*
8161 * Lookup the ns ancestor-axis for equal ns-decls in scope.
8162 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008163 if (optRemoveDedundantNS && XML_NSMAP_NOTEMPTY(nsMap)) {
8164 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008165 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8166 (mi->shadowDepth == -1) &&
8167 ((ns->prefix == mi->newNs->prefix) ||
8168 xmlStrEqual(ns->prefix, mi->newNs->prefix)) &&
8169 ((ns->href == mi->newNs->href) ||
8170 xmlStrEqual(ns->href, mi->newNs->href)))
8171 {
8172 /*
8173 * A redundant ns-decl was found.
8174 * Add it to the list of redundant ns-decls.
8175 */
8176 if (xmlDOMWrapNSNormAddNsMapItem2(&listRedund,
8177 &sizeRedund, &nbRedund, ns, mi->newNs) == -1)
8178 goto internal_error;
8179 /*
8180 * Remove the ns-decl from the element-node.
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008181 */
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008182 if (prevns)
8183 prevns->next = ns->next;
8184 else
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008185 cur->nsDef = ns->next;
8186 goto next_ns_decl;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008187 }
8188 }
8189 }
8190
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008191 /*
8192 * Skip ns-references handling if the referenced
8193 * ns-decl is declared on the same element.
8194 */
8195 if ((cur->ns != NULL) && adoptns && (cur->ns == ns))
8196 adoptns = 0;
8197 /*
8198 * Does it shadow any ns-decl?
8199 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008200 if (XML_NSMAP_NOTEMPTY(nsMap)) {
8201 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008202 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8203 (mi->shadowDepth == -1) &&
8204 ((ns->prefix == mi->newNs->prefix) ||
8205 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8206
8207 mi->shadowDepth = depth;
8208 }
8209 }
8210 }
8211 /*
8212 * Push mapping.
8213 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008214 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008215 depth) == NULL)
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008216 goto internal_error;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008217
8218 prevns = ns;
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008219next_ns_decl:
8220 ns = ns->next;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008221 }
8222 }
8223 if (! adoptns)
8224 goto ns_end;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008225 /* No break on purpose. */
8226 case XML_ATTRIBUTE_NODE:
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008227 /* No ns, no fun. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008228 if (cur->ns == NULL)
8229 goto ns_end;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008230
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008231 if (! parnsdone) {
8232 if ((elem->parent) &&
8233 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8234 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8235 elem->parent) == -1)
8236 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008237 }
8238 parnsdone = 1;
8239 }
8240 /*
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008241 * Adjust the reference if this was a redundant ns-decl.
8242 */
8243 if (listRedund) {
8244 for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8245 if (cur->ns == listRedund[j]) {
8246 cur->ns = listRedund[++j];
8247 break;
8248 }
8249 }
8250 }
8251 /*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008252 * Adopt ns-references.
8253 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008254 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008255 /*
8256 * Search for a mapping.
8257 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008258 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008259 if ((mi->shadowDepth == -1) &&
8260 (cur->ns == mi->oldNs)) {
8261
8262 cur->ns = mi->newNs;
8263 goto ns_end;
8264 }
8265 }
8266 }
8267 /*
8268 * Aquire a normalized ns-decl and add it to the map.
8269 */
8270 if (xmlDOMWrapNSNormAquireNormalizedNs(doc, curElem,
8271 cur->ns, &ns,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008272 &nsMap, depth,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008273 ancestorsOnly,
8274 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8275 goto internal_error;
8276 cur->ns = ns;
8277
8278ns_end:
8279 if ((cur->type == XML_ELEMENT_NODE) &&
8280 (cur->properties != NULL)) {
8281 /*
8282 * Process attributes.
8283 */
8284 cur = (xmlNodePtr) cur->properties;
8285 continue;
8286 }
8287 break;
8288 default:
8289 goto next_sibling;
8290 }
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008291into_content:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008292 if ((cur->type == XML_ELEMENT_NODE) &&
8293 (cur->children != NULL)) {
8294 /*
8295 * Process content of element-nodes only.
8296 */
8297 cur = cur->children;
8298 continue;
8299 }
8300next_sibling:
8301 if (cur == elem)
8302 break;
8303 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008304 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008305 /*
8306 * Pop mappings.
8307 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008308 while ((nsMap->last != NULL) &&
8309 (nsMap->last->depth >= depth))
8310 {
8311 XML_NSMAP_POP(nsMap, mi)
8312 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008313 /*
8314 * Unshadow.
8315 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008316 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008317 if (mi->shadowDepth >= depth)
8318 mi->shadowDepth = -1;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008319 }
8320 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008321 depth--;
8322 }
8323 if (cur->next != NULL)
8324 cur = cur->next;
8325 else {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008326 if (cur->type == XML_ATTRIBUTE_NODE) {
8327 cur = cur->parent;
8328 goto into_content;
8329 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008330 cur = cur->parent;
8331 goto next_sibling;
8332 }
8333 } while (cur != NULL);
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008334
8335 ret = 0;
8336 goto exit;
8337internal_error:
8338 ret = -1;
8339exit:
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008340 if (listRedund) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008341 for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8342 xmlFreeNs(listRedund[j]);
8343 }
8344 xmlFree(listRedund);
8345 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008346 if (nsMap != NULL)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008347 xmlDOMWrapNsMapFree(nsMap);
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008348 return (ret);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008349}
8350
8351/*
8352* xmlDOMWrapAdoptBranch:
8353* @ctxt: the optional context for custom processing
8354* @sourceDoc: the optional sourceDoc
8355* @node: the element-node to start with
8356* @destDoc: the destination doc for adoption
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008357* @destParent: the optional new parent of @node in @destDoc
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008358* @options: option flags
8359*
8360* Ensures that ns-references point to @destDoc: either to
8361* elements->nsDef entries if @destParent is given, or to
8362* @destDoc->oldNs otherwise.
8363* If @destParent is given, it ensures that the tree is namespace
8364* wellformed by creating additional ns-decls where needed.
8365* Note that, since prefixes of already existent ns-decls can be
8366* shadowed by this process, it could break QNames in attribute
8367* values or element content.
8368*
8369* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8370*/
8371static int
8372xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
8373 xmlDocPtr sourceDoc,
8374 xmlNodePtr node,
8375 xmlDocPtr destDoc,
8376 xmlNodePtr destParent,
8377 int options ATTRIBUTE_UNUSED)
8378{
8379 int ret = 0;
8380 xmlNodePtr cur, curElem = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008381 xmlNsMapPtr nsMap = NULL;
8382 xmlNsMapItemPtr mi;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008383 xmlNsPtr ns = NULL;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008384 int depth = -1, adoptStr = 1;
8385 /* gather @parent's ns-decls. */
8386 int parnsdone = 0;
8387 /* @ancestorsOnly should be set per option. */
8388 int ancestorsOnly = 0;
8389
8390 /*
8391 * Optimize string adoption for equal or none dicts.
8392 */
8393 if ((sourceDoc != NULL) &&
8394 (sourceDoc->dict == destDoc->dict))
8395 adoptStr = 0;
8396 else
8397 adoptStr = 1;
8398
8399 cur = node;
8400 while (cur != NULL) {
8401 if (cur->doc != sourceDoc) {
8402 /*
8403 * We'll assume XIncluded nodes if the doc differs.
8404 * TODO: Do we need to reconciliate XIncluded nodes?
8405 * This here skips XIncluded nodes and tries to handle
8406 * broken sequences.
8407 */
8408 if (cur->next == NULL)
8409 goto leave_node;
8410 do {
8411 cur = cur->next;
8412 if ((cur->type == XML_XINCLUDE_END) ||
8413 (cur->doc == node->doc))
8414 break;
8415 } while (cur->next != NULL);
8416
8417 if (cur->doc != node->doc)
8418 goto leave_node;
8419 }
8420 cur->doc = destDoc;
8421 switch (cur->type) {
8422 case XML_XINCLUDE_START:
8423 case XML_XINCLUDE_END:
8424 /*
8425 * TODO
8426 */
8427 return (-1);
8428 case XML_ELEMENT_NODE:
8429 curElem = cur;
8430 depth++;
8431 /*
8432 * Namespace declarations.
8433 */
8434 if ((ctxt == NULL) && (cur->nsDef != NULL)) {
8435 if (! parnsdone) {
8436 if (destParent && (ctxt == NULL)) {
8437 /*
8438 * Gather @parent's in-scope ns-decls.
8439 */
8440 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8441 destParent) == -1)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008442 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008443 }
8444 parnsdone = 1;
8445 }
8446 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8447 /*
8448 * ns->prefix and ns->href seem not to be in the dict.
8449 * XML_TREE_ADOPT_STR(ns->prefix)
8450 * XML_TREE_ADOPT_STR(ns->href)
8451 */
8452 /*
8453 * Does it shadow any ns-decl?
8454 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008455 if (XML_NSMAP_NOTEMPTY(nsMap)) {
8456 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008457 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8458 (mi->shadowDepth == -1) &&
8459 ((ns->prefix == mi->newNs->prefix) ||
8460 xmlStrEqual(ns->prefix,
8461 mi->newNs->prefix))) {
8462
8463 mi->shadowDepth = depth;
8464 }
8465 }
8466 }
8467 /*
8468 * Push mapping.
8469 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008470 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008471 ns, ns, depth) == NULL)
8472 goto internal_error;
8473 }
8474 }
8475 /* No break on purpose. */
8476 case XML_ATTRIBUTE_NODE:
8477
8478 if (cur->ns == NULL)
8479 goto ns_end;
8480 if (! parnsdone) {
8481 if (destParent && (ctxt == NULL)) {
8482 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8483 destParent) == -1)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008484 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008485 }
8486 parnsdone = 1;
8487 }
8488 /*
8489 * Adopt ns-references.
8490 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008491 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008492 /*
8493 * Search for a mapping.
8494 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008495 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008496 if ((mi->shadowDepth == -1) &&
8497 (cur->ns == mi->oldNs)) {
8498
8499 cur->ns = mi->newNs;
8500 goto ns_end;
8501 }
8502 }
8503 }
8504 /*
8505 * Start searching for an in-scope ns-decl.
8506 */
8507 if (ctxt != NULL) {
8508 /*
8509 * User-defined behaviour.
8510 */
8511#if 0
8512 ctxt->aquireNsDecl(ctxt, cur->ns, &ns);
8513#endif
8514 /*
8515 * Insert mapping if ns is available; it's the users fault
8516 * if not.
8517 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008518 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008519 ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
8520 goto internal_error;
8521 cur->ns = ns;
8522 } else {
8523 /*
8524 * Aquire a normalized ns-decl and add it to the map.
8525 */
8526 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
8527 /* ns-decls on curElem or on destDoc->oldNs */
8528 destParent ? curElem : NULL,
8529 cur->ns, &ns,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008530 &nsMap, depth,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008531 ancestorsOnly,
8532 /* ns-decls must be prefixed for attributes. */
8533 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8534 goto internal_error;
8535 cur->ns = ns;
8536 }
8537ns_end:
8538 /*
8539 * Further node properties.
8540 * TODO: Is this all?
8541 */
8542 XML_TREE_ADOPT_STR(cur->name)
8543 if (cur->type == XML_ELEMENT_NODE) {
8544 cur->psvi = NULL;
8545 cur->line = 0;
8546 cur->extra = 0;
8547 /*
8548 * Walk attributes.
8549 */
8550 if (cur->properties != NULL) {
8551 /*
8552 * Process first attribute node.
8553 */
8554 cur = (xmlNodePtr) cur->properties;
8555 continue;
8556 }
8557 } else {
8558 /*
8559 * Attributes.
8560 */
8561 if ((sourceDoc != NULL) &&
8562 (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID))
8563 xmlRemoveID(sourceDoc, (xmlAttrPtr) cur);
8564 ((xmlAttrPtr) cur)->atype = 0;
8565 ((xmlAttrPtr) cur)->psvi = NULL;
8566 }
8567 break;
8568 case XML_TEXT_NODE:
8569 case XML_CDATA_SECTION_NODE:
8570 /*
8571 * This puts the content in the dest dict, only if
8572 * it was previously in the source dict.
8573 */
8574 XML_TREE_ADOPT_STR_2(cur->content)
8575 goto leave_node;
8576 case XML_ENTITY_REF_NODE:
8577 /*
8578 * Remove reference to the entitity-node.
8579 */
8580 cur->content = NULL;
8581 cur->children = NULL;
8582 cur->last = NULL;
8583 if ((destDoc->intSubset) || (destDoc->extSubset)) {
8584 xmlEntityPtr ent;
8585 /*
8586 * Assign new entity-node if available.
8587 */
8588 ent = xmlGetDocEntity(destDoc, cur->name);
8589 if (ent != NULL) {
8590 cur->content = ent->content;
8591 cur->children = (xmlNodePtr) ent;
8592 cur->last = (xmlNodePtr) ent;
8593 }
8594 }
8595 goto leave_node;
8596 case XML_PI_NODE:
8597 XML_TREE_ADOPT_STR(cur->name)
8598 XML_TREE_ADOPT_STR_2(cur->content)
8599 break;
8600 case XML_COMMENT_NODE:
8601 break;
8602 default:
8603 goto internal_error;
8604 }
8605 /*
8606 * Walk the tree.
8607 */
8608 if (cur->children != NULL) {
8609 cur = cur->children;
8610 continue;
8611 }
8612
8613leave_node:
8614 if (cur == node)
8615 break;
8616 if ((cur->type == XML_ELEMENT_NODE) ||
8617 (cur->type == XML_XINCLUDE_START) ||
8618 (cur->type == XML_XINCLUDE_END)) {
8619 /*
8620 * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
8621 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008622 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008623 /*
8624 * Pop mappings.
8625 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008626 while ((nsMap->last != NULL) &&
8627 (nsMap->last->depth >= depth))
8628 {
8629 XML_NSMAP_POP(nsMap, mi)
8630 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008631 /*
8632 * Unshadow.
8633 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008634 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008635 if (mi->shadowDepth >= depth)
8636 mi->shadowDepth = -1;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008637 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008638 }
8639 depth--;
8640 }
8641 if (cur->next != NULL)
8642 cur = cur->next;
8643 else {
8644 cur = cur->parent;
8645 goto leave_node;
8646 }
8647 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008648
8649 goto exit;
8650
8651internal_error:
8652 ret = -1;
8653
8654exit:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008655 /*
8656 * Cleanup.
8657 */
8658 if (nsMap != NULL)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008659 xmlDOMWrapNsMapFree(nsMap);
8660 return(ret);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008661}
8662
8663/*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008664* xmlDOMWrapCloneNode:
8665* @ctxt: the optional context for custom processing
8666* @sourceDoc: the optional sourceDoc
8667* @node: the node to start with
8668* @resNode: the clone of the given @node
8669* @destDoc: the destination doc
8670* @destParent: the optional new parent of @node in @destDoc
Daniel Veillardb2f8f1d2006-04-28 16:30:48 +00008671* @deep: descend into child if set
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008672* @options: option flags
8673*
8674* References of out-of scope ns-decls are remapped to point to @destDoc:
8675* 1) If @destParent is given, then nsDef entries on element-nodes are used
8676* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used
8677* This is the case when you have an unliked node and just want to move it
8678* to the context of
8679*
8680* If @destParent is given, it ensures that the tree is namespace
8681* wellformed by creating additional ns-decls where needed.
8682* Note that, since prefixes of already existent ns-decls can be
8683* shadowed by this process, it could break QNames in attribute
8684* values or element content.
8685* TODO:
8686* 1) Support dicts
8687* Optimize string adoption for equal or none dicts.
8688* 2) XInclude
8689* WARNING: This function is in a experimental state and should only be currently
8690* only be used to test it.
8691*
8692* Returns 0 if the operation succeeded,
8693* 1 if a node of unsupported (or not yet supported) type was given,
8694* -1 on API/internal errors.
8695*/
8696
8697int
8698xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt,
8699 xmlDocPtr sourceDoc,
8700 xmlNodePtr node,
8701 xmlNodePtr *resNode,
8702 xmlDocPtr destDoc,
8703 xmlNodePtr destParent,
8704 int deep,
8705 int options ATTRIBUTE_UNUSED)
8706{
8707 int ret = 0;
8708 xmlNodePtr cur, curElem = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008709 xmlNsMapPtr nsMap = NULL;
8710 xmlNsMapItemPtr mi;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008711 xmlNsPtr ns;
8712 int depth = -1;
8713 /* int adoptStr = 1; */
8714 /* gather @parent's ns-decls. */
8715 int parnsdone = 0;
8716 /* @ancestorsOnly should be set per option. */
8717 int ancestorsOnly = 0;
8718 xmlNodePtr resultClone = NULL, clone = NULL, parentClone = NULL, prevClone = NULL;
8719 xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008720
Daniel Veillard11ce4002006-03-10 00:36:23 +00008721 if ((node == NULL) || (resNode == NULL) || (destDoc == NULL))
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008722 return(-1);
8723 /*
8724 * TODO: Initially we support only element-nodes.
8725 */
8726 if (node->type != XML_ELEMENT_NODE)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008727 return(1);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008728 /*
8729 * Check node->doc sanity.
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008730 */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008731 if ((node->doc != NULL) && (sourceDoc != NULL) &&
8732 (node->doc != sourceDoc)) {
8733 /*
8734 * Might be an XIncluded node.
8735 */
8736 return (-1);
8737 }
8738 if (sourceDoc == NULL)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008739 sourceDoc = node->doc;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008740 if (sourceDoc == NULL)
8741 return (-1);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008742
8743 *resNode = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008744
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008745 cur = node;
8746 while (cur != NULL) {
8747 if (cur->doc != sourceDoc) {
8748 /*
8749 * We'll assume XIncluded nodes if the doc differs.
8750 * TODO: Do we need to reconciliate XIncluded nodes?
8751 * TODO: This here returns -1 in this case.
8752 */
8753 goto internal_error;
8754 }
8755 /*
8756 * Create a new node.
8757 */
8758 switch (cur->type) {
8759 case XML_XINCLUDE_START:
8760 case XML_XINCLUDE_END:
8761 /* TODO: What to do with XInclude? */
8762 goto internal_error;
8763 break;
8764 case XML_TEXT_NODE:
8765 case XML_CDATA_SECTION_NODE:
8766 case XML_ELEMENT_NODE:
8767 case XML_DOCUMENT_FRAG_NODE:
8768 case XML_ENTITY_REF_NODE:
8769 case XML_ENTITY_NODE:
8770 case XML_PI_NODE:
8771 case XML_COMMENT_NODE:
8772 /*
8773 * Nodes of xmlNode structure.
8774 */
8775 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
8776 if (clone == NULL) {
8777 xmlTreeErrMemory("xmlDOMWrapCloneBranch(): allocating a node");
8778 goto internal_error;
8779 }
8780 memset(clone, 0, sizeof(xmlNode));
8781 /*
8782 * Set hierachical links.
8783 */
8784 if (resultClone != NULL) {
8785 clone->parent = parentClone;
8786 if (prevClone) {
8787 prevClone->next = clone;
8788 clone->prev = prevClone;
8789 } else
8790 parentClone->children = clone;
8791 } else
8792 resultClone = clone;
8793
8794 break;
8795 case XML_ATTRIBUTE_NODE:
8796 /*
8797 * Attributes (xmlAttr).
8798 */
8799 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlAttr));
8800 if (clone == NULL) {
8801 xmlTreeErrMemory("xmlDOMWrapCloneBranch(): allocating an attr-node");
8802 goto internal_error;
8803 }
8804 memset(clone, 0, sizeof(xmlAttr));
8805 /*
8806 * Set hierachical links.
8807 */
8808 if (resultClone != NULL) {
8809 clone->parent = parentClone;
8810 if (prevClone) {
8811 prevClone->next = clone;
8812 clone->prev = prevClone;
8813 } else
8814 parentClone->properties = (xmlAttrPtr) clone;
8815 } else
8816 resultClone = clone;
8817 break;
8818 default:
8819 /* TODO */
8820 goto internal_error;
8821 }
8822
8823 clone->type = cur->type;
8824 clone->doc = destDoc;
8825
8826 if (cur->name == xmlStringText)
8827 clone->name = xmlStringText;
8828 else if (cur->name == xmlStringTextNoenc)
8829 /*
8830 * TODO: xmlStringTextNoenc is never assigned to a node
8831 * in tree.c.
8832 */
8833 clone->name = xmlStringTextNoenc;
8834 else if (cur->name == xmlStringComment)
8835 clone->name = xmlStringComment;
8836 else if (cur->name != NULL) {
8837 if ((destDoc != NULL) && (destDoc->dict != NULL))
8838 clone->name = xmlDictLookup(destDoc->dict, cur->name, -1);
8839 else
8840 clone->name = xmlStrdup(cur->name);
8841 }
8842
8843 switch (cur->type) {
8844 case XML_XINCLUDE_START:
8845 case XML_XINCLUDE_END:
8846 /*
8847 * TODO
8848 */
8849 return (-1);
8850 case XML_ELEMENT_NODE:
8851 curElem = cur;
8852 depth++;
8853 /*
8854 * Namespace declarations.
8855 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008856 if (cur->nsDef != NULL) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008857 if (! parnsdone) {
8858 if (destParent && (ctxt == NULL)) {
8859 /*
8860 * Gather @parent's in-scope ns-decls.
8861 */
8862 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8863 destParent) == -1)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008864 goto internal_error;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008865 }
8866 parnsdone = 1;
8867 }
8868 /*
8869 * Clone namespace declarations.
8870 */
8871 cloneNsDefSlot = &(clone->nsDef);
8872 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8873 /*
8874 * Create a new xmlNs.
8875 */
8876 cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
8877 if (cloneNs == NULL) {
8878 xmlTreeErrMemory("xmlDOMWrapCloneBranch(): "
8879 "allocating namespace");
8880 return(-1);
8881 }
8882 memset(cloneNs, 0, sizeof(xmlNs));
8883 cloneNs->type = XML_LOCAL_NAMESPACE;
8884
8885 if (ns->href != NULL)
8886 cloneNs->href = xmlStrdup(ns->href);
8887 if (ns->prefix != NULL)
8888 cloneNs->prefix = xmlStrdup(ns->prefix);
8889
8890 *cloneNsDefSlot = cloneNs;
8891 cloneNsDefSlot = &(cloneNs->next);
8892
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008893 if (ctxt == NULL) {
8894 /*
8895 * Does it shadow any ns-decl?
8896 */
8897 if (XML_NSMAP_NOTEMPTY(nsMap)) {
8898 XML_NSMAP_FOREACH(nsMap, mi) {
8899 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8900 (mi->shadowDepth == -1) &&
8901 ((ns->prefix == mi->newNs->prefix) ||
8902 xmlStrEqual(ns->prefix,
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008903 mi->newNs->prefix))) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008904 /*
8905 * Mark as shadowed at the current
8906 * depth.
8907 */
8908 mi->shadowDepth = depth;
8909 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008910 }
8911 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008912 /*
8913 * Push mapping.
8914 */
8915 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
8916 ns, cloneNs, depth) == NULL)
8917 goto internal_error;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008918 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008919 }
8920 }
8921 /* cur->ns will be processed further down. */
8922 break;
8923 case XML_ATTRIBUTE_NODE:
8924 /* IDs will be processed further down. */
8925 /* cur->ns will be processed further down. */
8926 break;
8927 case XML_TEXT_NODE:
8928 case XML_CDATA_SECTION_NODE:
8929 if (cur->content)
8930 clone->content = xmlStrdup(cur->content);
8931 goto leave_node;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008932 case XML_ENTITY_NODE:
8933 /* TODO: What to do here? */
8934 goto leave_node;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008935 case XML_ENTITY_REF_NODE:
8936 if (sourceDoc != destDoc) {
8937 if ((destDoc->intSubset) || (destDoc->extSubset)) {
8938 xmlEntityPtr ent;
8939 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008940 * Different doc: Assign new entity-node if available.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008941 */
8942 ent = xmlGetDocEntity(destDoc, cur->name);
8943 if (ent != NULL) {
8944 clone->content = ent->content;
8945 clone->children = (xmlNodePtr) ent;
8946 clone->last = (xmlNodePtr) ent;
8947 }
8948 }
8949 } else {
8950 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008951 * Same doc: Use the current node's entity declaration
8952 * and value.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008953 */
8954 clone->content = cur->content;
8955 clone->children = cur->children;
8956 clone->last = cur->last;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008957 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008958 goto leave_node;
8959 case XML_PI_NODE:
8960 if (cur->content)
8961 clone->content = xmlStrdup(cur->content);
8962 goto leave_node;
8963 case XML_COMMENT_NODE:
8964 if (cur->content)
8965 clone->content = xmlStrdup(cur->content);
8966 goto leave_node;
8967 default:
8968 goto internal_error;
8969 }
8970
8971 if (cur->ns == NULL)
8972 goto end_ns_reference;
8973
8974/* handle_ns_reference: */
8975 /*
8976 ** The following will take care of references to ns-decls ********
8977 ** and is intended only for element- and attribute-nodes.
8978 **
8979 */
8980 if (! parnsdone) {
8981 if (destParent && (ctxt == NULL)) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008982 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1)
8983 goto internal_error;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008984 }
8985 parnsdone = 1;
8986 }
8987 /*
8988 * Adopt ns-references.
8989 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008990 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008991 /*
8992 * Search for a mapping.
8993 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008994 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008995 if ((mi->shadowDepth == -1) &&
8996 (cur->ns == mi->oldNs)) {
8997 /*
8998 * This is the nice case: a mapping was found.
8999 */
9000 clone->ns = mi->newNs;
9001 goto end_ns_reference;
9002 }
9003 }
9004 }
9005 /*
9006 * Start searching for an in-scope ns-decl.
9007 */
9008 if (ctxt != NULL) {
9009 /*
9010 * User-defined behaviour.
9011 */
9012#if 0
9013 ctxt->aquireNsDecl(ctxt, cur->ns, &ns);
9014#endif
9015 /*
9016 * Add user's mapping.
9017 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009018 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009019 cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
9020 goto internal_error;
9021 clone->ns = ns;
9022 } else {
9023 /*
9024 * Aquire a normalized ns-decl and add it to the map.
9025 */
9026 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
9027 /* ns-decls on curElem or on destDoc->oldNs */
9028 destParent ? curElem : NULL,
9029 cur->ns, &ns,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009030 &nsMap, depth,
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009031 ancestorsOnly,
9032 /* ns-decls must be prefixed for attributes. */
9033 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
9034 goto internal_error;
9035 clone->ns = ns;
9036 }
9037
9038end_ns_reference:
9039
9040 /*
9041 * Some post-processing.
9042 *
9043 * Handle ID attributes.
9044 */
9045 if ((clone->type == XML_ATTRIBUTE_NODE) &&
9046 (clone->parent != NULL)) {
9047 if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) {
9048
9049 xmlChar *idVal;
9050
9051 idVal = xmlNodeListGetString(cur->doc, cur->children, 1);
9052 if (idVal != NULL) {
9053 if (xmlAddID(NULL, destDoc, idVal, (xmlAttrPtr) cur) == NULL) {
9054 /* TODO: error message. */
9055 xmlFree(idVal);
9056 goto internal_error;
9057 }
9058 xmlFree(idVal);
9059 }
9060 }
9061 }
9062 /*
9063 **
9064 ** The following will traversing the tree ************************
9065 **
9066 *
9067 * Walk the element's attributes before descending into child-nodes.
9068 */
9069 if ((cur->type == XML_ELEMENT_NODE) && (cur->properties != NULL)) {
9070 prevClone = NULL;
9071 parentClone = clone;
9072 cur = (xmlNodePtr) cur->properties;
9073 continue;
9074 }
9075into_content:
9076 /*
9077 * Descend into child-nodes.
9078 */
9079 if (cur->children != NULL) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009080 if (deep || (cur->type == XML_ATTRIBUTE_NODE)) {
9081 prevClone = NULL;
9082 parentClone = clone;
9083 cur = cur->children;
9084 continue;
9085 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009086 }
9087
9088leave_node:
9089 /*
9090 * At this point we are done with the node, its content
9091 * and an element-nodes's attribute-nodes.
9092 */
9093 if (cur == node)
9094 break;
9095 if ((cur->type == XML_ELEMENT_NODE) ||
9096 (cur->type == XML_XINCLUDE_START) ||
9097 (cur->type == XML_XINCLUDE_END)) {
9098 /*
9099 * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
9100 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009101 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009102 /*
9103 * Pop mappings.
9104 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009105 while ((nsMap->last != NULL) &&
9106 (nsMap->last->depth >= depth))
9107 {
9108 XML_NSMAP_POP(nsMap, mi)
9109 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009110 /*
9111 * Unshadow.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009112 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009113 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009114 if (mi->shadowDepth >= depth)
9115 mi->shadowDepth = -1;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009116 }
9117 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009118 depth--;
9119 }
9120 if (cur->next != NULL) {
9121 prevClone = clone;
9122 cur = cur->next;
9123 } else if (cur->type != XML_ATTRIBUTE_NODE) {
9124 /*
9125 * Set clone->last.
9126 */
Daniel Veillard11ce4002006-03-10 00:36:23 +00009127 if (clone->parent != NULL)
9128 clone->parent->last = clone;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009129 clone = clone->parent;
9130 parentClone = clone->parent;
9131 /*
9132 * Process parent --> next;
9133 */
9134 cur = cur->parent;
9135 goto leave_node;
9136 } else {
9137 /* This is for attributes only. */
9138 clone = clone->parent;
9139 parentClone = clone->parent;
9140 /*
9141 * Process parent-element --> children.
9142 */
9143 cur = cur->parent;
9144 goto into_content;
9145 }
9146 }
9147 goto exit;
9148
9149internal_error:
9150 ret = -1;
9151
9152exit:
9153 /*
9154 * Cleanup.
9155 */
9156 if (nsMap != NULL)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009157 xmlDOMWrapNsMapFree(nsMap);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009158 /*
9159 * TODO: Should we try a cleanup of the cloned node in case of a
9160 * fatal error?
9161 */
9162 *resNode = resultClone;
9163 return (ret);
9164}
9165
9166/*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009167* xmlDOMWrapAdoptAttr:
9168* @ctxt: the optional context for custom processing
9169* @sourceDoc: the optional source document of attr
9170* @attr: the attribute-node to be adopted
9171* @destDoc: the destination doc for adoption
9172* @destParent: the optional new parent of @attr in @destDoc
9173* @options: option flags
9174*
9175* @attr is adopted by @destDoc.
9176* Ensures that ns-references point to @destDoc: either to
9177* elements->nsDef entries if @destParent is given, or to
9178* @destDoc->oldNs otherwise.
9179*
9180* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
9181*/
9182static int
9183xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt,
9184 xmlDocPtr sourceDoc,
9185 xmlAttrPtr attr,
9186 xmlDocPtr destDoc,
9187 xmlNodePtr destParent,
9188 int options ATTRIBUTE_UNUSED)
9189{
9190 xmlNodePtr cur;
9191 int adoptStr = 1;
9192
9193 if ((attr == NULL) || (destDoc == NULL))
9194 return (-1);
9195
9196 attr->doc = destDoc;
9197 if (attr->ns != NULL) {
9198 xmlNsPtr ns = NULL;
9199
9200 if (ctxt != NULL) {
9201 /* TODO: User defined. */
9202 }
9203 /* XML Namespace. */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009204 if (IS_STR_XML(attr->ns->prefix)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009205 ns = xmlTreeEnsureXMLDecl(destDoc);
9206 } else if (destParent == NULL) {
9207 /*
9208 * Store in @destDoc->oldNs.
9209 */
9210 ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix);
9211 } else {
9212 /*
9213 * Declare on @destParent.
9214 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009215 if (xmlSearchNsByNamespaceStrict(destDoc, destParent, attr->ns->href,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009216 &ns, 1) == -1)
9217 goto internal_error;
9218 if (ns == NULL) {
9219 ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent,
9220 attr->ns->href, attr->ns->prefix, 1);
9221 }
9222 }
9223 if (ns == NULL)
9224 goto internal_error;
9225 attr->ns = ns;
9226 }
9227
9228 XML_TREE_ADOPT_STR(attr->name);
9229 attr->atype = 0;
9230 attr->psvi = NULL;
9231 /*
9232 * Walk content.
9233 */
9234 if (attr->children == NULL)
9235 return (0);
9236 cur = attr->children;
9237 while (cur != NULL) {
9238 cur->doc = destDoc;
9239 switch (cur->type) {
9240 case XML_TEXT_NODE:
9241 case XML_CDATA_SECTION_NODE:
9242 XML_TREE_ADOPT_STR_2(cur->content)
9243 break;
9244 case XML_ENTITY_REF_NODE:
9245 /*
9246 * Remove reference to the entitity-node.
9247 */
9248 cur->content = NULL;
9249 cur->children = NULL;
9250 cur->last = NULL;
9251 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9252 xmlEntityPtr ent;
9253 /*
9254 * Assign new entity-node if available.
9255 */
9256 ent = xmlGetDocEntity(destDoc, cur->name);
9257 if (ent != NULL) {
9258 cur->content = ent->content;
9259 cur->children = (xmlNodePtr) ent;
9260 cur->last = (xmlNodePtr) ent;
9261 }
9262 }
9263 break;
9264 default:
9265 break;
9266 }
9267 if (cur->children != NULL) {
9268 cur = cur->children;
9269 continue;
9270 }
9271next_sibling:
9272 if (cur == (xmlNodePtr) attr)
9273 break;
9274 if (cur->next != NULL)
9275 cur = cur->next;
9276 else {
9277 cur = cur->parent;
9278 goto next_sibling;
9279 }
9280 }
9281 return (0);
9282internal_error:
9283 return (-1);
9284}
9285
9286/*
9287* xmlDOMWrapAdoptNode:
9288* @ctxt: the optional context for custom processing
9289* @sourceDoc: the optional sourceDoc
9290* @node: the node to start with
9291* @destDoc: the destination doc
Kasimier T. Buchcik4d9c9482005-06-27 15:04:46 +00009292* @destParent: the optional new parent of @node in @destDoc
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009293* @options: option flags
9294*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009295* References of out-of scope ns-decls are remapped to point to @destDoc:
9296* 1) If @destParent is given, then nsDef entries on element-nodes are used
9297* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used
9298* This is the case when you have an unliked node and just want to move it
9299* to the context of
9300*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009301* If @destParent is given, it ensures that the tree is namespace
9302* wellformed by creating additional ns-decls where needed.
9303* Note that, since prefixes of already existent ns-decls can be
9304* shadowed by this process, it could break QNames in attribute
9305* values or element content.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00009306* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009307*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009308* Returns 0 if the operation succeeded,
9309* 1 if a node of unsupported type was given,
9310* 2 if a node of not yet supported type was given and
9311* -1 on API/internal errors.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009312*/
9313int
9314xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt,
9315 xmlDocPtr sourceDoc,
9316 xmlNodePtr node,
9317 xmlDocPtr destDoc,
9318 xmlNodePtr destParent,
9319 int options)
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009320{
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009321 if ((node == NULL) || (destDoc == NULL) ||
9322 ((destParent != NULL) && (destParent->doc != destDoc)))
9323 return(-1);
9324 /*
9325 * Check node->doc sanity.
9326 */
9327 if ((node->doc != NULL) && (sourceDoc != NULL) &&
9328 (node->doc != sourceDoc)) {
9329 /*
9330 * Might be an XIncluded node.
9331 */
9332 return (-1);
9333 }
9334 if (sourceDoc == NULL)
9335 sourceDoc = node->doc;
9336 if (sourceDoc == destDoc)
9337 return (-1);
9338 switch (node->type) {
9339 case XML_ELEMENT_NODE:
9340 case XML_ATTRIBUTE_NODE:
9341 case XML_TEXT_NODE:
9342 case XML_CDATA_SECTION_NODE:
9343 case XML_ENTITY_REF_NODE:
9344 case XML_PI_NODE:
9345 case XML_COMMENT_NODE:
9346 break;
9347 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009348 /* TODO: Support document-fragment-nodes. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009349 return (2);
9350 default:
9351 return (1);
9352 }
9353 /*
9354 * Unlink only if @node was not already added to @destParent.
9355 */
9356 if ((node->parent != NULL) && (destParent != node->parent))
9357 xmlUnlinkNode(node);
9358
9359 if (node->type == XML_ELEMENT_NODE) {
9360 return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node,
9361 destDoc, destParent, options));
9362 } else if (node->type == XML_ATTRIBUTE_NODE) {
9363 return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc,
9364 (xmlAttrPtr) node, destDoc, destParent, options));
9365 } else {
9366 xmlNodePtr cur = node;
9367 int adoptStr = 1;
9368
9369 cur->doc = destDoc;
9370 /*
9371 * Optimize string adoption.
9372 */
9373 if ((sourceDoc != NULL) &&
9374 (sourceDoc->dict == destDoc->dict))
9375 adoptStr = 0;
9376 switch (node->type) {
9377 case XML_TEXT_NODE:
9378 case XML_CDATA_SECTION_NODE:
9379 XML_TREE_ADOPT_STR_2(node->content)
9380 break;
9381 case XML_ENTITY_REF_NODE:
9382 /*
9383 * Remove reference to the entitity-node.
9384 */
9385 node->content = NULL;
9386 node->children = NULL;
9387 node->last = NULL;
9388 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9389 xmlEntityPtr ent;
9390 /*
9391 * Assign new entity-node if available.
9392 */
9393 ent = xmlGetDocEntity(destDoc, node->name);
9394 if (ent != NULL) {
9395 node->content = ent->content;
9396 node->children = (xmlNodePtr) ent;
9397 node->last = (xmlNodePtr) ent;
9398 }
9399 }
9400 XML_TREE_ADOPT_STR(node->name)
9401 break;
Daniel Veillard7e21fd12005-07-03 21:44:07 +00009402 case XML_PI_NODE: {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009403 XML_TREE_ADOPT_STR(node->name)
9404 XML_TREE_ADOPT_STR_2(node->content)
9405 break;
Daniel Veillard7e21fd12005-07-03 21:44:07 +00009406 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009407 default:
9408 break;
9409 }
9410 }
9411 return (0);
9412}
9413
Daniel Veillard5d4644e2005-04-01 13:11:58 +00009414#define bottom_tree
9415#include "elfgcchack.h"