blob: 2ec645d66504a4f3bccf738723357e13c5a196b3 [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];
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004239 int occur = 0, generic;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004240
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) {
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004270 generic = 0;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004271 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004272 name = (const char *) cur->name;
4273 if (cur->ns) {
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004274 if (cur->ns->prefix != NULL) {
William M. Brack13dfa872004-09-18 04:52:08 +00004275 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4276 (char *)cur->ns->prefix, (char *)cur->name);
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004277 nametemp[sizeof(nametemp) - 1] = 0;
4278 name = nametemp;
4279 } else {
4280 /*
4281 * We cannot express named elements in the default
4282 * namespace, so use "*".
4283 */
4284 generic = 1;
4285 name = "*";
4286 }
Daniel Veillard8faa7832001-11-26 15:58:08 +00004287 }
4288 next = cur->parent;
4289
4290 /*
4291 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004292 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004293 */
4294 tmp = cur->prev;
4295 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004296 if ((tmp->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004297 (generic ||
Kasimier T. Buchcik43ceb1e2006-06-12 11:08:18 +00004298 (xmlStrEqual(cur->name, tmp->name) &&
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004299 ((tmp->ns == cur->ns) ||
4300 ((tmp->ns != NULL) && (cur->ns != NULL) &&
Kasimier T. Buchcik43ceb1e2006-06-12 11:08:18 +00004301 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004302 occur++;
4303 tmp = tmp->prev;
4304 }
4305 if (occur == 0) {
4306 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004307 while (tmp != NULL && occur == 0) {
4308 if ((tmp->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004309 (generic ||
Kasimier T. Buchcik43ceb1e2006-06-12 11:08:18 +00004310 (xmlStrEqual(cur->name, tmp->name) &&
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004311 ((tmp->ns == cur->ns) ||
4312 ((tmp->ns != NULL) && (cur->ns != NULL) &&
Kasimier T. Buchcik43ceb1e2006-06-12 11:08:18 +00004313 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004314 occur++;
4315 tmp = tmp->next;
4316 }
4317 if (occur != 0)
4318 occur = 1;
4319 } else
4320 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004321 } else if (cur->type == XML_COMMENT_NODE) {
4322 sep = "/";
4323 name = "comment()";
4324 next = cur->parent;
4325
4326 /*
4327 * Thumbler index computation
4328 */
4329 tmp = cur->prev;
4330 while (tmp != NULL) {
4331 if (tmp->type == XML_COMMENT_NODE)
4332 occur++;
4333 tmp = tmp->prev;
4334 }
4335 if (occur == 0) {
4336 tmp = cur->next;
4337 while (tmp != NULL && occur == 0) {
4338 if (tmp->type == XML_COMMENT_NODE)
4339 occur++;
4340 tmp = tmp->next;
4341 }
4342 if (occur != 0)
4343 occur = 1;
4344 } else
4345 occur++;
4346 } else if ((cur->type == XML_TEXT_NODE) ||
4347 (cur->type == XML_CDATA_SECTION_NODE)) {
4348 sep = "/";
4349 name = "text()";
4350 next = cur->parent;
4351
4352 /*
4353 * Thumbler index computation
4354 */
4355 tmp = cur->prev;
4356 while (tmp != NULL) {
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004357 if ((tmp->type == XML_TEXT_NODE) ||
4358 (tmp->type == XML_CDATA_SECTION_NODE))
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004359 occur++;
4360 tmp = tmp->prev;
4361 }
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004362 /*
4363 * Evaluate if this is the only text- or CDATA-section-node;
4364 * if yes, then we'll get "text()", otherwise "text()[1]".
4365 */
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004366 if (occur == 0) {
4367 tmp = cur->next;
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004368 while (tmp != NULL) {
4369 if ((tmp->type == XML_TEXT_NODE) ||
4370 (tmp->type == XML_CDATA_SECTION_NODE))
4371 {
4372 occur = 1;
4373 break;
4374 }
4375 tmp = tmp->next;
4376 }
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004377 } else
4378 occur++;
4379 } else if (cur->type == XML_PI_NODE) {
4380 sep = "/";
4381 snprintf(nametemp, sizeof(nametemp) - 1,
William M. Brack13dfa872004-09-18 04:52:08 +00004382 "processing-instruction('%s')", (char *)cur->name);
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004383 nametemp[sizeof(nametemp) - 1] = 0;
4384 name = nametemp;
4385
4386 next = cur->parent;
4387
4388 /*
4389 * Thumbler index computation
4390 */
4391 tmp = cur->prev;
4392 while (tmp != NULL) {
4393 if ((tmp->type == XML_PI_NODE) &&
4394 (xmlStrEqual(cur->name, tmp->name)))
4395 occur++;
4396 tmp = tmp->prev;
4397 }
4398 if (occur == 0) {
4399 tmp = cur->next;
4400 while (tmp != NULL && occur == 0) {
4401 if ((tmp->type == XML_PI_NODE) &&
4402 (xmlStrEqual(cur->name, tmp->name)))
4403 occur++;
4404 tmp = tmp->next;
4405 }
4406 if (occur != 0)
4407 occur = 1;
4408 } else
4409 occur++;
4410
Daniel Veillard8faa7832001-11-26 15:58:08 +00004411 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004412 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004413 name = (const char *) (((xmlAttrPtr) cur)->name);
Daniel Veillard365c8062005-07-19 11:31:55 +00004414 if (cur->ns) {
4415 if (cur->ns->prefix != NULL)
4416 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4417 (char *)cur->ns->prefix, (char *)cur->name);
4418 else
4419 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4420 (char *)cur->name);
4421 nametemp[sizeof(nametemp) - 1] = 0;
4422 name = nametemp;
4423 }
Daniel Veillard8faa7832001-11-26 15:58:08 +00004424 next = ((xmlAttrPtr) cur)->parent;
4425 } else {
4426 next = cur->parent;
4427 }
4428
4429 /*
4430 * Make sure there is enough room
4431 */
4432 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4433 buf_len =
4434 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4435 temp = (xmlChar *) xmlRealloc(buffer, 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 buffer = temp;
4443 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4444 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004445 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004446 xmlFree(buf);
4447 xmlFree(buffer);
4448 return (NULL);
4449 }
4450 buf = temp;
4451 }
4452 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004453 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004454 sep, name, (char *) buffer);
4455 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004456 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004457 sep, name, occur, (char *) buffer);
William M. Brack13dfa872004-09-18 04:52:08 +00004458 snprintf((char *) buffer, buf_len, "%s", (char *)buf);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004459 cur = next;
4460 } while (cur != NULL);
4461 xmlFree(buf);
4462 return (buffer);
4463}
Daniel Veillard652327a2003-09-29 18:02:38 +00004464#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004465
4466/**
Owen Taylor3473f882001-02-23 17:55:21 +00004467 * xmlDocGetRootElement:
4468 * @doc: the document
4469 *
4470 * Get the root element of the document (doc->children is a list
4471 * containing possibly comments, PIs, etc ...).
4472 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004473 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004474 */
4475xmlNodePtr
4476xmlDocGetRootElement(xmlDocPtr doc) {
4477 xmlNodePtr ret;
4478
4479 if (doc == NULL) return(NULL);
4480 ret = doc->children;
4481 while (ret != NULL) {
4482 if (ret->type == XML_ELEMENT_NODE)
4483 return(ret);
4484 ret = ret->next;
4485 }
4486 return(ret);
4487}
4488
Daniel Veillard2156d432004-03-04 15:59:36 +00004489#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004490/**
4491 * xmlDocSetRootElement:
4492 * @doc: the document
4493 * @root: the new document root element
4494 *
4495 * Set the root element of the document (doc->children is a list
4496 * containing possibly comments, PIs, etc ...).
4497 *
4498 * Returns the old root element if any was found
4499 */
4500xmlNodePtr
4501xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4502 xmlNodePtr old = NULL;
4503
4504 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004505 if (root == NULL)
4506 return(NULL);
4507 xmlUnlinkNode(root);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00004508 xmlSetTreeDoc(root, doc);
Daniel Veillardc575b992002-02-08 13:28:40 +00004509 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004510 old = doc->children;
4511 while (old != NULL) {
4512 if (old->type == XML_ELEMENT_NODE)
4513 break;
4514 old = old->next;
4515 }
4516 if (old == NULL) {
4517 if (doc->children == NULL) {
4518 doc->children = root;
4519 doc->last = root;
4520 } else {
4521 xmlAddSibling(doc->children, root);
4522 }
4523 } else {
4524 xmlReplaceNode(old, root);
4525 }
4526 return(old);
4527}
Daniel Veillard2156d432004-03-04 15:59:36 +00004528#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004529
Daniel Veillard2156d432004-03-04 15:59:36 +00004530#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004531/**
4532 * xmlNodeSetLang:
4533 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004534 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004535 *
4536 * Set the language of a node, i.e. the values of the xml:lang
4537 * attribute.
4538 */
4539void
4540xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004541 xmlNsPtr ns;
4542
Owen Taylor3473f882001-02-23 17:55:21 +00004543 if (cur == NULL) return;
4544 switch(cur->type) {
4545 case XML_TEXT_NODE:
4546 case XML_CDATA_SECTION_NODE:
4547 case XML_COMMENT_NODE:
4548 case XML_DOCUMENT_NODE:
4549 case XML_DOCUMENT_TYPE_NODE:
4550 case XML_DOCUMENT_FRAG_NODE:
4551 case XML_NOTATION_NODE:
4552 case XML_HTML_DOCUMENT_NODE:
4553 case XML_DTD_NODE:
4554 case XML_ELEMENT_DECL:
4555 case XML_ATTRIBUTE_DECL:
4556 case XML_ENTITY_DECL:
4557 case XML_PI_NODE:
4558 case XML_ENTITY_REF_NODE:
4559 case XML_ENTITY_NODE:
4560 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004561#ifdef LIBXML_DOCB_ENABLED
4562 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004563#endif
4564 case XML_XINCLUDE_START:
4565 case XML_XINCLUDE_END:
4566 return;
4567 case XML_ELEMENT_NODE:
4568 case XML_ATTRIBUTE_NODE:
4569 break;
4570 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004571 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4572 if (ns == NULL)
4573 return;
4574 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004575}
Daniel Veillard652327a2003-09-29 18:02:38 +00004576#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004577
4578/**
4579 * xmlNodeGetLang:
4580 * @cur: the node being checked
4581 *
4582 * Searches the language of a node, i.e. the values of the xml:lang
4583 * attribute or the one carried by the nearest ancestor.
4584 *
4585 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004586 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004587 */
4588xmlChar *
4589xmlNodeGetLang(xmlNodePtr cur) {
4590 xmlChar *lang;
4591
4592 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004593 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004594 if (lang != NULL)
4595 return(lang);
4596 cur = cur->parent;
4597 }
4598 return(NULL);
4599}
4600
4601
Daniel Veillard652327a2003-09-29 18:02:38 +00004602#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004603/**
4604 * xmlNodeSetSpacePreserve:
4605 * @cur: the node being changed
4606 * @val: the xml:space value ("0": default, 1: "preserve")
4607 *
4608 * Set (or reset) the space preserving behaviour of a node, i.e. the
4609 * value of the xml:space attribute.
4610 */
4611void
4612xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004613 xmlNsPtr ns;
4614
Owen Taylor3473f882001-02-23 17:55:21 +00004615 if (cur == NULL) return;
4616 switch(cur->type) {
4617 case XML_TEXT_NODE:
4618 case XML_CDATA_SECTION_NODE:
4619 case XML_COMMENT_NODE:
4620 case XML_DOCUMENT_NODE:
4621 case XML_DOCUMENT_TYPE_NODE:
4622 case XML_DOCUMENT_FRAG_NODE:
4623 case XML_NOTATION_NODE:
4624 case XML_HTML_DOCUMENT_NODE:
4625 case XML_DTD_NODE:
4626 case XML_ELEMENT_DECL:
4627 case XML_ATTRIBUTE_DECL:
4628 case XML_ENTITY_DECL:
4629 case XML_PI_NODE:
4630 case XML_ENTITY_REF_NODE:
4631 case XML_ENTITY_NODE:
4632 case XML_NAMESPACE_DECL:
4633 case XML_XINCLUDE_START:
4634 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004635#ifdef LIBXML_DOCB_ENABLED
4636 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004637#endif
4638 return;
4639 case XML_ELEMENT_NODE:
4640 case XML_ATTRIBUTE_NODE:
4641 break;
4642 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004643 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4644 if (ns == NULL)
4645 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004646 switch (val) {
4647 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004648 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004649 break;
4650 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004651 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004652 break;
4653 }
4654}
Daniel Veillard652327a2003-09-29 18:02:38 +00004655#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004656
4657/**
4658 * xmlNodeGetSpacePreserve:
4659 * @cur: the node being checked
4660 *
4661 * Searches the space preserving behaviour of a node, i.e. the values
4662 * of the xml:space attribute or the one carried by the nearest
4663 * ancestor.
4664 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004665 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004666 */
4667int
4668xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4669 xmlChar *space;
4670
4671 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004672 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004673 if (space != NULL) {
4674 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4675 xmlFree(space);
4676 return(1);
4677 }
4678 if (xmlStrEqual(space, BAD_CAST "default")) {
4679 xmlFree(space);
4680 return(0);
4681 }
4682 xmlFree(space);
4683 }
4684 cur = cur->parent;
4685 }
4686 return(-1);
4687}
4688
Daniel Veillard652327a2003-09-29 18:02:38 +00004689#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004690/**
4691 * xmlNodeSetName:
4692 * @cur: the node being changed
4693 * @name: the new tag name
4694 *
4695 * Set (or reset) the name of a node.
4696 */
4697void
4698xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00004699 xmlDocPtr doc;
4700 xmlDictPtr dict;
4701
Owen Taylor3473f882001-02-23 17:55:21 +00004702 if (cur == NULL) return;
4703 if (name == NULL) return;
4704 switch(cur->type) {
4705 case XML_TEXT_NODE:
4706 case XML_CDATA_SECTION_NODE:
4707 case XML_COMMENT_NODE:
4708 case XML_DOCUMENT_TYPE_NODE:
4709 case XML_DOCUMENT_FRAG_NODE:
4710 case XML_NOTATION_NODE:
4711 case XML_HTML_DOCUMENT_NODE:
4712 case XML_NAMESPACE_DECL:
4713 case XML_XINCLUDE_START:
4714 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004715#ifdef LIBXML_DOCB_ENABLED
4716 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004717#endif
4718 return;
4719 case XML_ELEMENT_NODE:
4720 case XML_ATTRIBUTE_NODE:
4721 case XML_PI_NODE:
4722 case XML_ENTITY_REF_NODE:
4723 case XML_ENTITY_NODE:
4724 case XML_DTD_NODE:
4725 case XML_DOCUMENT_NODE:
4726 case XML_ELEMENT_DECL:
4727 case XML_ATTRIBUTE_DECL:
4728 case XML_ENTITY_DECL:
4729 break;
4730 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00004731 doc = cur->doc;
4732 if (doc != NULL)
4733 dict = doc->dict;
4734 else
4735 dict = NULL;
4736 if (dict != NULL) {
4737 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
4738 xmlFree((xmlChar *) cur->name);
4739 cur->name = xmlDictLookup(dict, name, -1);
4740 } else {
4741 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4742 cur->name = xmlStrdup(name);
4743 }
Owen Taylor3473f882001-02-23 17:55:21 +00004744}
Daniel Veillard2156d432004-03-04 15:59:36 +00004745#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004746
Daniel Veillard2156d432004-03-04 15:59:36 +00004747#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004748/**
4749 * xmlNodeSetBase:
4750 * @cur: the node being changed
4751 * @uri: the new base URI
4752 *
4753 * Set (or reset) the base URI of a node, i.e. the value of the
4754 * xml:base attribute.
4755 */
4756void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004757xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004758 xmlNsPtr ns;
4759
Owen Taylor3473f882001-02-23 17:55:21 +00004760 if (cur == NULL) return;
4761 switch(cur->type) {
4762 case XML_TEXT_NODE:
4763 case XML_CDATA_SECTION_NODE:
4764 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004765 case XML_DOCUMENT_TYPE_NODE:
4766 case XML_DOCUMENT_FRAG_NODE:
4767 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004768 case XML_DTD_NODE:
4769 case XML_ELEMENT_DECL:
4770 case XML_ATTRIBUTE_DECL:
4771 case XML_ENTITY_DECL:
4772 case XML_PI_NODE:
4773 case XML_ENTITY_REF_NODE:
4774 case XML_ENTITY_NODE:
4775 case XML_NAMESPACE_DECL:
4776 case XML_XINCLUDE_START:
4777 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004778 return;
4779 case XML_ELEMENT_NODE:
4780 case XML_ATTRIBUTE_NODE:
4781 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004782 case XML_DOCUMENT_NODE:
4783#ifdef LIBXML_DOCB_ENABLED
4784 case XML_DOCB_DOCUMENT_NODE:
4785#endif
4786 case XML_HTML_DOCUMENT_NODE: {
4787 xmlDocPtr doc = (xmlDocPtr) cur;
4788
4789 if (doc->URL != NULL)
4790 xmlFree((xmlChar *) doc->URL);
4791 if (uri == NULL)
4792 doc->URL = NULL;
4793 else
4794 doc->URL = xmlStrdup(uri);
4795 return;
4796 }
Owen Taylor3473f882001-02-23 17:55:21 +00004797 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004798
4799 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4800 if (ns == NULL)
4801 return;
4802 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004803}
Daniel Veillard652327a2003-09-29 18:02:38 +00004804#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004805
4806/**
Owen Taylor3473f882001-02-23 17:55:21 +00004807 * xmlNodeGetBase:
4808 * @doc: the document the node pertains to
4809 * @cur: the node being checked
4810 *
4811 * Searches for the BASE URL. The code should work on both XML
4812 * and HTML document even if base mechanisms are completely different.
4813 * It returns the base as defined in RFC 2396 sections
4814 * 5.1.1. Base URI within Document Content
4815 * and
4816 * 5.1.2. Base URI from the Encapsulating Entity
4817 * However it does not return the document base (5.1.3), use
4818 * xmlDocumentGetBase() for this
4819 *
4820 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004821 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004822 */
4823xmlChar *
4824xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004825 xmlChar *oldbase = NULL;
4826 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004827
4828 if ((cur == NULL) && (doc == NULL))
4829 return(NULL);
4830 if (doc == NULL) doc = cur->doc;
4831 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4832 cur = doc->children;
4833 while ((cur != NULL) && (cur->name != NULL)) {
4834 if (cur->type != XML_ELEMENT_NODE) {
4835 cur = cur->next;
4836 continue;
4837 }
4838 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4839 cur = cur->children;
4840 continue;
4841 }
4842 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4843 cur = cur->children;
4844 continue;
4845 }
4846 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4847 return(xmlGetProp(cur, BAD_CAST "href"));
4848 }
4849 cur = cur->next;
4850 }
4851 return(NULL);
4852 }
4853 while (cur != NULL) {
4854 if (cur->type == XML_ENTITY_DECL) {
4855 xmlEntityPtr ent = (xmlEntityPtr) cur;
4856 return(xmlStrdup(ent->URI));
4857 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004858 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004859 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004860 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004861 if (oldbase != NULL) {
4862 newbase = xmlBuildURI(oldbase, base);
4863 if (newbase != NULL) {
4864 xmlFree(oldbase);
4865 xmlFree(base);
4866 oldbase = newbase;
4867 } else {
4868 xmlFree(oldbase);
4869 xmlFree(base);
4870 return(NULL);
4871 }
4872 } else {
4873 oldbase = base;
4874 }
4875 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4876 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4877 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4878 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004879 }
4880 }
Owen Taylor3473f882001-02-23 17:55:21 +00004881 cur = cur->parent;
4882 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004883 if ((doc != NULL) && (doc->URL != NULL)) {
4884 if (oldbase == NULL)
4885 return(xmlStrdup(doc->URL));
4886 newbase = xmlBuildURI(oldbase, doc->URL);
4887 xmlFree(oldbase);
4888 return(newbase);
4889 }
4890 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004891}
4892
4893/**
Daniel Veillard78697292003-10-19 20:44:43 +00004894 * xmlNodeBufGetContent:
4895 * @buffer: a buffer
4896 * @cur: the node being read
4897 *
4898 * Read the value of a node @cur, this can be either the text carried
4899 * directly by this node if it's a TEXT node or the aggregate string
4900 * of the values carried by this node child's (TEXT and ENTITY_REF).
4901 * Entity references are substituted.
4902 * Fills up the buffer @buffer with this value
4903 *
4904 * Returns 0 in case of success and -1 in case of error.
4905 */
4906int
4907xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4908{
4909 if ((cur == NULL) || (buffer == NULL)) return(-1);
4910 switch (cur->type) {
4911 case XML_CDATA_SECTION_NODE:
4912 case XML_TEXT_NODE:
4913 xmlBufferCat(buffer, cur->content);
4914 break;
4915 case XML_DOCUMENT_FRAG_NODE:
4916 case XML_ELEMENT_NODE:{
4917 xmlNodePtr tmp = cur;
4918
4919 while (tmp != NULL) {
4920 switch (tmp->type) {
4921 case XML_CDATA_SECTION_NODE:
4922 case XML_TEXT_NODE:
4923 if (tmp->content != NULL)
4924 xmlBufferCat(buffer, tmp->content);
4925 break;
4926 case XML_ENTITY_REF_NODE:
Rob Richards77b92ff2005-12-20 15:55:14 +00004927 xmlNodeBufGetContent(buffer, tmp);
4928 break;
Daniel Veillard78697292003-10-19 20:44:43 +00004929 default:
4930 break;
4931 }
4932 /*
4933 * Skip to next node
4934 */
4935 if (tmp->children != NULL) {
4936 if (tmp->children->type != XML_ENTITY_DECL) {
4937 tmp = tmp->children;
4938 continue;
4939 }
4940 }
4941 if (tmp == cur)
4942 break;
4943
4944 if (tmp->next != NULL) {
4945 tmp = tmp->next;
4946 continue;
4947 }
4948
4949 do {
4950 tmp = tmp->parent;
4951 if (tmp == NULL)
4952 break;
4953 if (tmp == cur) {
4954 tmp = NULL;
4955 break;
4956 }
4957 if (tmp->next != NULL) {
4958 tmp = tmp->next;
4959 break;
4960 }
4961 } while (tmp != NULL);
4962 }
4963 break;
4964 }
4965 case XML_ATTRIBUTE_NODE:{
4966 xmlAttrPtr attr = (xmlAttrPtr) cur;
4967 xmlNodePtr tmp = attr->children;
4968
4969 while (tmp != NULL) {
4970 if (tmp->type == XML_TEXT_NODE)
4971 xmlBufferCat(buffer, tmp->content);
4972 else
4973 xmlNodeBufGetContent(buffer, tmp);
4974 tmp = tmp->next;
4975 }
4976 break;
4977 }
4978 case XML_COMMENT_NODE:
4979 case XML_PI_NODE:
4980 xmlBufferCat(buffer, cur->content);
4981 break;
4982 case XML_ENTITY_REF_NODE:{
4983 xmlEntityPtr ent;
4984 xmlNodePtr tmp;
4985
4986 /* lookup entity declaration */
4987 ent = xmlGetDocEntity(cur->doc, cur->name);
4988 if (ent == NULL)
4989 return(-1);
4990
4991 /* an entity content can be any "well balanced chunk",
4992 * i.e. the result of the content [43] production:
4993 * http://www.w3.org/TR/REC-xml#NT-content
4994 * -> we iterate through child nodes and recursive call
4995 * xmlNodeGetContent() which handles all possible node types */
4996 tmp = ent->children;
4997 while (tmp) {
4998 xmlNodeBufGetContent(buffer, tmp);
4999 tmp = tmp->next;
5000 }
5001 break;
5002 }
5003 case XML_ENTITY_NODE:
5004 case XML_DOCUMENT_TYPE_NODE:
5005 case XML_NOTATION_NODE:
5006 case XML_DTD_NODE:
5007 case XML_XINCLUDE_START:
5008 case XML_XINCLUDE_END:
5009 break;
5010 case XML_DOCUMENT_NODE:
5011#ifdef LIBXML_DOCB_ENABLED
5012 case XML_DOCB_DOCUMENT_NODE:
5013#endif
5014 case XML_HTML_DOCUMENT_NODE:
5015 cur = cur->children;
5016 while (cur!= NULL) {
5017 if ((cur->type == XML_ELEMENT_NODE) ||
5018 (cur->type == XML_TEXT_NODE) ||
5019 (cur->type == XML_CDATA_SECTION_NODE)) {
5020 xmlNodeBufGetContent(buffer, cur);
5021 }
5022 cur = cur->next;
5023 }
5024 break;
5025 case XML_NAMESPACE_DECL:
5026 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
5027 break;
5028 case XML_ELEMENT_DECL:
5029 case XML_ATTRIBUTE_DECL:
5030 case XML_ENTITY_DECL:
5031 break;
5032 }
5033 return(0);
5034}
5035/**
Owen Taylor3473f882001-02-23 17:55:21 +00005036 * xmlNodeGetContent:
5037 * @cur: the node being read
5038 *
5039 * Read the value of a node, this can be either the text carried
5040 * directly by this node if it's a TEXT node or the aggregate string
5041 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00005042 * Entity references are substituted.
5043 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005044 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005045 */
5046xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00005047xmlNodeGetContent(xmlNodePtr cur)
5048{
5049 if (cur == NULL)
5050 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005051 switch (cur->type) {
5052 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005053 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00005054 xmlBufferPtr buffer;
5055 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00005056
Daniel Veillard814a76d2003-01-23 18:24:20 +00005057 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00005058 if (buffer == NULL)
5059 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00005060 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005061 ret = buffer->content;
5062 buffer->content = NULL;
5063 xmlBufferFree(buffer);
5064 return (ret);
5065 }
5066 case XML_ATTRIBUTE_NODE:{
5067 xmlAttrPtr attr = (xmlAttrPtr) cur;
5068
5069 if (attr->parent != NULL)
5070 return (xmlNodeListGetString
5071 (attr->parent->doc, attr->children, 1));
5072 else
5073 return (xmlNodeListGetString(NULL, attr->children, 1));
5074 break;
5075 }
Owen Taylor3473f882001-02-23 17:55:21 +00005076 case XML_COMMENT_NODE:
5077 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005078 if (cur->content != NULL)
5079 return (xmlStrdup(cur->content));
5080 return (NULL);
5081 case XML_ENTITY_REF_NODE:{
5082 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00005083 xmlBufferPtr buffer;
5084 xmlChar *ret;
5085
5086 /* lookup entity declaration */
5087 ent = xmlGetDocEntity(cur->doc, cur->name);
5088 if (ent == NULL)
5089 return (NULL);
5090
5091 buffer = xmlBufferCreate();
5092 if (buffer == NULL)
5093 return (NULL);
5094
Daniel Veillardc4696922003-10-19 21:47:14 +00005095 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005096
5097 ret = buffer->content;
5098 buffer->content = NULL;
5099 xmlBufferFree(buffer);
5100 return (ret);
5101 }
Owen Taylor3473f882001-02-23 17:55:21 +00005102 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005103 case XML_DOCUMENT_TYPE_NODE:
5104 case XML_NOTATION_NODE:
5105 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005106 case XML_XINCLUDE_START:
5107 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00005108 return (NULL);
5109 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005110#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005111 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005112#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005113 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00005114 xmlBufferPtr buffer;
5115 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005116
Daniel Veillardc4696922003-10-19 21:47:14 +00005117 buffer = xmlBufferCreate();
5118 if (buffer == NULL)
5119 return (NULL);
5120
5121 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5122
5123 ret = buffer->content;
5124 buffer->content = NULL;
5125 xmlBufferFree(buffer);
5126 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005127 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005128 case XML_NAMESPACE_DECL: {
5129 xmlChar *tmp;
5130
5131 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5132 return (tmp);
5133 }
Owen Taylor3473f882001-02-23 17:55:21 +00005134 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005135 /* TODO !!! */
5136 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005137 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005138 /* TODO !!! */
5139 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005140 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005141 /* TODO !!! */
5142 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005143 case XML_CDATA_SECTION_NODE:
5144 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005145 if (cur->content != NULL)
5146 return (xmlStrdup(cur->content));
5147 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005148 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005149 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005150}
Daniel Veillard652327a2003-09-29 18:02:38 +00005151
Owen Taylor3473f882001-02-23 17:55:21 +00005152/**
5153 * xmlNodeSetContent:
5154 * @cur: the node being modified
5155 * @content: the new value of the content
5156 *
5157 * Replace the content of a node.
5158 */
5159void
5160xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5161 if (cur == NULL) {
5162#ifdef DEBUG_TREE
5163 xmlGenericError(xmlGenericErrorContext,
5164 "xmlNodeSetContent : node == NULL\n");
5165#endif
5166 return;
5167 }
5168 switch (cur->type) {
5169 case XML_DOCUMENT_FRAG_NODE:
5170 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005171 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005172 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5173 cur->children = xmlStringGetNodeList(cur->doc, content);
5174 UPDATE_LAST_CHILD_AND_PARENT(cur)
5175 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005176 case XML_TEXT_NODE:
5177 case XML_CDATA_SECTION_NODE:
5178 case XML_ENTITY_REF_NODE:
5179 case XML_ENTITY_NODE:
5180 case XML_PI_NODE:
5181 case XML_COMMENT_NODE:
Daniel Veillard8874b942005-08-25 13:19:21 +00005182 if ((cur->content != NULL) &&
5183 (cur->content != (xmlChar *) &(cur->properties))) {
William M. Brack7762bb12004-01-04 14:49:01 +00005184 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
Daniel Veillardc587bce2005-05-10 15:28:08 +00005185 (xmlDictOwns(cur->doc->dict, cur->content))))
William M. Brack7762bb12004-01-04 14:49:01 +00005186 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005187 }
5188 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5189 cur->last = cur->children = NULL;
5190 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005191 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005192 } else
5193 cur->content = NULL;
Daniel Veillard8874b942005-08-25 13:19:21 +00005194 cur->properties = NULL;
5195 cur->nsDef = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00005196 break;
5197 case XML_DOCUMENT_NODE:
5198 case XML_HTML_DOCUMENT_NODE:
5199 case XML_DOCUMENT_TYPE_NODE:
5200 case XML_XINCLUDE_START:
5201 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005202#ifdef LIBXML_DOCB_ENABLED
5203 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005204#endif
5205 break;
5206 case XML_NOTATION_NODE:
5207 break;
5208 case XML_DTD_NODE:
5209 break;
5210 case XML_NAMESPACE_DECL:
5211 break;
5212 case XML_ELEMENT_DECL:
5213 /* TODO !!! */
5214 break;
5215 case XML_ATTRIBUTE_DECL:
5216 /* TODO !!! */
5217 break;
5218 case XML_ENTITY_DECL:
5219 /* TODO !!! */
5220 break;
5221 }
5222}
5223
Daniel Veillard652327a2003-09-29 18:02:38 +00005224#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005225/**
5226 * xmlNodeSetContentLen:
5227 * @cur: the node being modified
5228 * @content: the new value of the content
5229 * @len: the size of @content
5230 *
5231 * Replace the content of a node.
5232 */
5233void
5234xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5235 if (cur == NULL) {
5236#ifdef DEBUG_TREE
5237 xmlGenericError(xmlGenericErrorContext,
5238 "xmlNodeSetContentLen : node == NULL\n");
5239#endif
5240 return;
5241 }
5242 switch (cur->type) {
5243 case XML_DOCUMENT_FRAG_NODE:
5244 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005245 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005246 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5247 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5248 UPDATE_LAST_CHILD_AND_PARENT(cur)
5249 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005250 case XML_TEXT_NODE:
5251 case XML_CDATA_SECTION_NODE:
5252 case XML_ENTITY_REF_NODE:
5253 case XML_ENTITY_NODE:
5254 case XML_PI_NODE:
5255 case XML_COMMENT_NODE:
5256 case XML_NOTATION_NODE:
Daniel Veillard8874b942005-08-25 13:19:21 +00005257 if ((cur->content != NULL) &&
5258 (cur->content != (xmlChar *) &(cur->properties))) {
5259 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5260 (xmlDictOwns(cur->doc->dict, cur->content))))
5261 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005262 }
5263 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5264 cur->children = cur->last = NULL;
5265 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005266 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005267 } else
5268 cur->content = NULL;
Daniel Veillard8874b942005-08-25 13:19:21 +00005269 cur->properties = NULL;
5270 cur->nsDef = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00005271 break;
5272 case XML_DOCUMENT_NODE:
5273 case XML_DTD_NODE:
5274 case XML_HTML_DOCUMENT_NODE:
5275 case XML_DOCUMENT_TYPE_NODE:
5276 case XML_NAMESPACE_DECL:
5277 case XML_XINCLUDE_START:
5278 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005279#ifdef LIBXML_DOCB_ENABLED
5280 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005281#endif
5282 break;
5283 case XML_ELEMENT_DECL:
5284 /* TODO !!! */
5285 break;
5286 case XML_ATTRIBUTE_DECL:
5287 /* TODO !!! */
5288 break;
5289 case XML_ENTITY_DECL:
5290 /* TODO !!! */
5291 break;
5292 }
5293}
Daniel Veillard652327a2003-09-29 18:02:38 +00005294#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005295
5296/**
5297 * xmlNodeAddContentLen:
5298 * @cur: the node being modified
5299 * @content: extra content
5300 * @len: the size of @content
5301 *
5302 * Append the extra substring to the node content.
5303 */
5304void
5305xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5306 if (cur == NULL) {
5307#ifdef DEBUG_TREE
5308 xmlGenericError(xmlGenericErrorContext,
5309 "xmlNodeAddContentLen : node == NULL\n");
5310#endif
5311 return;
5312 }
5313 if (len <= 0) return;
5314 switch (cur->type) {
5315 case XML_DOCUMENT_FRAG_NODE:
5316 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005317 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005318
Daniel Veillard7db37732001-07-12 01:20:08 +00005319 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005320 newNode = xmlNewTextLen(content, len);
5321 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005322 tmp = xmlAddChild(cur, newNode);
5323 if (tmp != newNode)
5324 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005325 if ((last != NULL) && (last->next == newNode)) {
5326 xmlTextMerge(last, newNode);
5327 }
5328 }
5329 break;
5330 }
5331 case XML_ATTRIBUTE_NODE:
5332 break;
5333 case XML_TEXT_NODE:
5334 case XML_CDATA_SECTION_NODE:
5335 case XML_ENTITY_REF_NODE:
5336 case XML_ENTITY_NODE:
5337 case XML_PI_NODE:
5338 case XML_COMMENT_NODE:
5339 case XML_NOTATION_NODE:
5340 if (content != NULL) {
Daniel Veillard8874b942005-08-25 13:19:21 +00005341 if ((cur->content == (xmlChar *) &(cur->properties)) ||
5342 ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5343 xmlDictOwns(cur->doc->dict, cur->content))) {
5344 cur->content = xmlStrncatNew(cur->content, content, len);
5345 cur->properties = NULL;
5346 cur->nsDef = NULL;
William M. Brack7762bb12004-01-04 14:49:01 +00005347 break;
5348 }
Owen Taylor3473f882001-02-23 17:55:21 +00005349 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005350 }
5351 case XML_DOCUMENT_NODE:
5352 case XML_DTD_NODE:
5353 case XML_HTML_DOCUMENT_NODE:
5354 case XML_DOCUMENT_TYPE_NODE:
5355 case XML_NAMESPACE_DECL:
5356 case XML_XINCLUDE_START:
5357 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005358#ifdef LIBXML_DOCB_ENABLED
5359 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005360#endif
5361 break;
5362 case XML_ELEMENT_DECL:
5363 case XML_ATTRIBUTE_DECL:
5364 case XML_ENTITY_DECL:
5365 break;
5366 }
5367}
5368
5369/**
5370 * xmlNodeAddContent:
5371 * @cur: the node being modified
5372 * @content: extra content
5373 *
5374 * Append the extra substring to the node content.
5375 */
5376void
5377xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5378 int len;
5379
5380 if (cur == NULL) {
5381#ifdef DEBUG_TREE
5382 xmlGenericError(xmlGenericErrorContext,
5383 "xmlNodeAddContent : node == NULL\n");
5384#endif
5385 return;
5386 }
5387 if (content == NULL) return;
5388 len = xmlStrlen(content);
5389 xmlNodeAddContentLen(cur, content, len);
5390}
5391
5392/**
5393 * xmlTextMerge:
5394 * @first: the first text node
5395 * @second: the second text node being merged
5396 *
5397 * Merge two text nodes into one
5398 * Returns the first text node augmented
5399 */
5400xmlNodePtr
5401xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5402 if (first == NULL) return(second);
5403 if (second == NULL) return(first);
5404 if (first->type != XML_TEXT_NODE) return(first);
5405 if (second->type != XML_TEXT_NODE) return(first);
5406 if (second->name != first->name)
5407 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005408 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005409 xmlUnlinkNode(second);
5410 xmlFreeNode(second);
5411 return(first);
5412}
5413
Daniel Veillard2156d432004-03-04 15:59:36 +00005414#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005415/**
5416 * xmlGetNsList:
5417 * @doc: the document
5418 * @node: the current node
5419 *
5420 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005421 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005422 * that need to be freed by the caller or NULL if no
5423 * namespace if defined
5424 */
5425xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005426xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5427{
Owen Taylor3473f882001-02-23 17:55:21 +00005428 xmlNsPtr cur;
5429 xmlNsPtr *ret = NULL;
5430 int nbns = 0;
5431 int maxns = 10;
5432 int i;
5433
5434 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005435 if (node->type == XML_ELEMENT_NODE) {
5436 cur = node->nsDef;
5437 while (cur != NULL) {
5438 if (ret == NULL) {
5439 ret =
5440 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5441 sizeof(xmlNsPtr));
5442 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005443 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005444 return (NULL);
5445 }
5446 ret[nbns] = NULL;
5447 }
5448 for (i = 0; i < nbns; i++) {
5449 if ((cur->prefix == ret[i]->prefix) ||
5450 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5451 break;
5452 }
5453 if (i >= nbns) {
5454 if (nbns >= maxns) {
5455 maxns *= 2;
5456 ret = (xmlNsPtr *) xmlRealloc(ret,
5457 (maxns +
5458 1) *
5459 sizeof(xmlNsPtr));
5460 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005461 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005462 return (NULL);
5463 }
5464 }
5465 ret[nbns++] = cur;
5466 ret[nbns] = NULL;
5467 }
Owen Taylor3473f882001-02-23 17:55:21 +00005468
Daniel Veillard77044732001-06-29 21:31:07 +00005469 cur = cur->next;
5470 }
5471 }
5472 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005473 }
Daniel Veillard77044732001-06-29 21:31:07 +00005474 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005475}
Daniel Veillard652327a2003-09-29 18:02:38 +00005476#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005477
5478/**
5479 * xmlSearchNs:
5480 * @doc: the document
5481 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005482 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005483 *
5484 * Search a Ns registered under a given name space for a document.
5485 * recurse on the parents until it finds the defined namespace
5486 * or return NULL otherwise.
5487 * @nameSpace can be NULL, this is a search for the default namespace.
5488 * We don't allow to cross entities boundaries. If you don't declare
5489 * the namespace within those you will be in troubles !!! A warning
5490 * is generated to cover this case.
5491 *
5492 * Returns the namespace pointer or NULL.
5493 */
5494xmlNsPtr
5495xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005496
Owen Taylor3473f882001-02-23 17:55:21 +00005497 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005498 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005499
5500 if (node == NULL) return(NULL);
5501 if ((nameSpace != NULL) &&
5502 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005503 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5504 /*
5505 * The XML-1.0 namespace is normally held on the root
5506 * element. In this case exceptionally create it on the
5507 * node element.
5508 */
5509 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5510 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005511 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005512 return(NULL);
5513 }
5514 memset(cur, 0, sizeof(xmlNs));
5515 cur->type = XML_LOCAL_NAMESPACE;
5516 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5517 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5518 cur->next = node->nsDef;
5519 node->nsDef = cur;
5520 return(cur);
5521 }
Daniel Veillard11ce4002006-03-10 00:36:23 +00005522 if (doc == NULL) {
5523 doc = node->doc;
5524 if (doc == NULL)
5525 return(NULL);
5526 }
Owen Taylor3473f882001-02-23 17:55:21 +00005527 if (doc->oldNs == NULL) {
5528 /*
5529 * Allocate a new Namespace and fill the fields.
5530 */
5531 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5532 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005533 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005534 return(NULL);
5535 }
5536 memset(doc->oldNs, 0, sizeof(xmlNs));
5537 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5538
5539 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5540 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5541 }
5542 return(doc->oldNs);
5543 }
5544 while (node != NULL) {
5545 if ((node->type == XML_ENTITY_REF_NODE) ||
5546 (node->type == XML_ENTITY_NODE) ||
5547 (node->type == XML_ENTITY_DECL))
5548 return(NULL);
5549 if (node->type == XML_ELEMENT_NODE) {
5550 cur = node->nsDef;
5551 while (cur != NULL) {
5552 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5553 (cur->href != NULL))
5554 return(cur);
5555 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5556 (cur->href != NULL) &&
5557 (xmlStrEqual(cur->prefix, nameSpace)))
5558 return(cur);
5559 cur = cur->next;
5560 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005561 if (orig != node) {
5562 cur = node->ns;
5563 if (cur != NULL) {
5564 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5565 (cur->href != NULL))
5566 return(cur);
5567 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5568 (cur->href != NULL) &&
5569 (xmlStrEqual(cur->prefix, nameSpace)))
5570 return(cur);
5571 }
5572 }
Owen Taylor3473f882001-02-23 17:55:21 +00005573 }
5574 node = node->parent;
5575 }
5576 return(NULL);
5577}
5578
5579/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005580 * xmlNsInScope:
5581 * @doc: the document
5582 * @node: the current node
5583 * @ancestor: the ancestor carrying the namespace
5584 * @prefix: the namespace prefix
5585 *
5586 * Verify that the given namespace held on @ancestor is still in scope
5587 * on node.
5588 *
5589 * Returns 1 if true, 0 if false and -1 in case of error.
5590 */
5591static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005592xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5593 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005594{
5595 xmlNsPtr tst;
5596
5597 while ((node != NULL) && (node != ancestor)) {
5598 if ((node->type == XML_ENTITY_REF_NODE) ||
5599 (node->type == XML_ENTITY_NODE) ||
5600 (node->type == XML_ENTITY_DECL))
5601 return (-1);
5602 if (node->type == XML_ELEMENT_NODE) {
5603 tst = node->nsDef;
5604 while (tst != NULL) {
5605 if ((tst->prefix == NULL)
5606 && (prefix == NULL))
5607 return (0);
5608 if ((tst->prefix != NULL)
5609 && (prefix != NULL)
5610 && (xmlStrEqual(tst->prefix, prefix)))
5611 return (0);
5612 tst = tst->next;
5613 }
5614 }
5615 node = node->parent;
5616 }
5617 if (node != ancestor)
5618 return (-1);
5619 return (1);
5620}
5621
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005622/**
Owen Taylor3473f882001-02-23 17:55:21 +00005623 * xmlSearchNsByHref:
5624 * @doc: the document
5625 * @node: the current node
5626 * @href: the namespace value
5627 *
5628 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5629 * the defined namespace or return NULL otherwise.
5630 * Returns the namespace pointer or NULL.
5631 */
5632xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005633xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5634{
Owen Taylor3473f882001-02-23 17:55:21 +00005635 xmlNsPtr cur;
5636 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005637 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005638
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005639 if ((node == NULL) || (href == NULL))
5640 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005641 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005642 /*
5643 * Only the document can hold the XML spec namespace.
5644 */
5645 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5646 /*
5647 * The XML-1.0 namespace is normally held on the root
5648 * element. In this case exceptionally create it on the
5649 * node element.
5650 */
5651 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5652 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005653 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005654 return (NULL);
5655 }
5656 memset(cur, 0, sizeof(xmlNs));
5657 cur->type = XML_LOCAL_NAMESPACE;
5658 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5659 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5660 cur->next = node->nsDef;
5661 node->nsDef = cur;
5662 return (cur);
5663 }
Daniel Veillard11ce4002006-03-10 00:36:23 +00005664 if (doc == NULL) {
5665 doc = node->doc;
5666 if (doc == NULL)
5667 return(NULL);
5668 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005669 if (doc->oldNs == NULL) {
5670 /*
5671 * Allocate a new Namespace and fill the fields.
5672 */
5673 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5674 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005675 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005676 return (NULL);
5677 }
5678 memset(doc->oldNs, 0, sizeof(xmlNs));
5679 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005680
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005681 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5682 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5683 }
5684 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005685 }
Daniel Veillard62040be2004-05-17 03:17:26 +00005686 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00005687 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005688 if ((node->type == XML_ENTITY_REF_NODE) ||
5689 (node->type == XML_ENTITY_NODE) ||
5690 (node->type == XML_ENTITY_DECL))
5691 return (NULL);
5692 if (node->type == XML_ELEMENT_NODE) {
5693 cur = node->nsDef;
5694 while (cur != NULL) {
5695 if ((cur->href != NULL) && (href != NULL) &&
5696 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005697 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00005698 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005699 return (cur);
5700 }
5701 cur = cur->next;
5702 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005703 if (orig != node) {
5704 cur = node->ns;
5705 if (cur != NULL) {
5706 if ((cur->href != NULL) && (href != NULL) &&
5707 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005708 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00005709 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00005710 return (cur);
5711 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005712 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005713 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005714 }
5715 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005716 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005717 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005718}
5719
5720/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005721 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005722 * @doc: the document
5723 * @tree: a node expected to hold the new namespace
5724 * @ns: the original namespace
5725 *
5726 * This function tries to locate a namespace definition in a tree
5727 * ancestors, or create a new namespace definition node similar to
5728 * @ns trying to reuse the same prefix. However if the given prefix is
5729 * null (default namespace) or reused within the subtree defined by
5730 * @tree or on one of its ancestors then a new prefix is generated.
5731 * Returns the (new) namespace definition or NULL in case of error
5732 */
5733xmlNsPtr
5734xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5735 xmlNsPtr def;
5736 xmlChar prefix[50];
5737 int counter = 1;
5738
5739 if (tree == NULL) {
5740#ifdef DEBUG_TREE
5741 xmlGenericError(xmlGenericErrorContext,
5742 "xmlNewReconciliedNs : tree == NULL\n");
5743#endif
5744 return(NULL);
5745 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00005746 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005747#ifdef DEBUG_TREE
5748 xmlGenericError(xmlGenericErrorContext,
5749 "xmlNewReconciliedNs : ns == NULL\n");
5750#endif
5751 return(NULL);
5752 }
5753 /*
5754 * Search an existing namespace definition inherited.
5755 */
5756 def = xmlSearchNsByHref(doc, tree, ns->href);
5757 if (def != NULL)
5758 return(def);
5759
5760 /*
5761 * Find a close prefix which is not already in use.
5762 * Let's strip namespace prefixes longer than 20 chars !
5763 */
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");
Daniel Veillardf742d342002-03-07 00:05:35 +00005766 else
William M. Brack13dfa872004-09-18 04:52:08 +00005767 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005768
Owen Taylor3473f882001-02-23 17:55:21 +00005769 def = xmlSearchNs(doc, tree, prefix);
5770 while (def != NULL) {
5771 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005772 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005773 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005774 else
William M. Brack13dfa872004-09-18 04:52:08 +00005775 snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
5776 (char *)ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005777 def = xmlSearchNs(doc, tree, prefix);
5778 }
5779
5780 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005781 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005782 */
5783 def = xmlNewNs(tree, ns->href, prefix);
5784 return(def);
5785}
5786
Daniel Veillard652327a2003-09-29 18:02:38 +00005787#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005788/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005789 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005790 * @doc: the document
5791 * @tree: a node defining the subtree to reconciliate
5792 *
5793 * This function checks that all the namespaces declared within the given
5794 * tree are properly declared. This is needed for example after Copy or Cut
5795 * and then paste operations. The subtree may still hold pointers to
5796 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005797 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005798 * the new environment. If not possible the new namespaces are redeclared
5799 * on @tree at the top of the given subtree.
5800 * Returns the number of namespace declarations created or -1 in case of error.
5801 */
5802int
5803xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5804 xmlNsPtr *oldNs = NULL;
5805 xmlNsPtr *newNs = NULL;
5806 int sizeCache = 0;
5807 int nbCache = 0;
5808
5809 xmlNsPtr n;
5810 xmlNodePtr node = tree;
5811 xmlAttrPtr attr;
5812 int ret = 0, i;
5813
Daniel Veillardce244ad2004-11-05 10:03:46 +00005814 if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1);
5815 if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1);
5816 if (node->doc != doc) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005817 while (node != NULL) {
5818 /*
5819 * Reconciliate the node namespace
5820 */
5821 if (node->ns != NULL) {
5822 /*
5823 * initialize the cache if needed
5824 */
5825 if (sizeCache == 0) {
5826 sizeCache = 10;
5827 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5828 sizeof(xmlNsPtr));
5829 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005830 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005831 return(-1);
5832 }
5833 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5834 sizeof(xmlNsPtr));
5835 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005836 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005837 xmlFree(oldNs);
5838 return(-1);
5839 }
5840 }
5841 for (i = 0;i < nbCache;i++) {
5842 if (oldNs[i] == node->ns) {
5843 node->ns = newNs[i];
5844 break;
5845 }
5846 }
5847 if (i == nbCache) {
5848 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005849 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005850 */
5851 n = xmlNewReconciliedNs(doc, tree, node->ns);
5852 if (n != NULL) { /* :-( what if else ??? */
5853 /*
5854 * check if we need to grow the cache buffers.
5855 */
5856 if (sizeCache <= nbCache) {
5857 sizeCache *= 2;
5858 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5859 sizeof(xmlNsPtr));
5860 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005861 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005862 xmlFree(newNs);
5863 return(-1);
5864 }
5865 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5866 sizeof(xmlNsPtr));
5867 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005868 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005869 xmlFree(oldNs);
5870 return(-1);
5871 }
5872 }
5873 newNs[nbCache] = n;
5874 oldNs[nbCache++] = node->ns;
5875 node->ns = n;
5876 }
5877 }
5878 }
5879 /*
5880 * now check for namespace hold by attributes on the node.
5881 */
5882 attr = node->properties;
5883 while (attr != NULL) {
5884 if (attr->ns != NULL) {
5885 /*
5886 * initialize the cache if needed
5887 */
5888 if (sizeCache == 0) {
5889 sizeCache = 10;
5890 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5891 sizeof(xmlNsPtr));
5892 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005893 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005894 return(-1);
5895 }
5896 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5897 sizeof(xmlNsPtr));
5898 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005899 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005900 xmlFree(oldNs);
5901 return(-1);
5902 }
5903 }
5904 for (i = 0;i < nbCache;i++) {
5905 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005906 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005907 break;
5908 }
5909 }
5910 if (i == nbCache) {
5911 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005912 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005913 */
5914 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5915 if (n != NULL) { /* :-( what if else ??? */
5916 /*
5917 * check if we need to grow the cache buffers.
5918 */
5919 if (sizeCache <= nbCache) {
5920 sizeCache *= 2;
5921 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5922 sizeof(xmlNsPtr));
5923 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005924 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005925 xmlFree(newNs);
5926 return(-1);
5927 }
5928 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5929 sizeof(xmlNsPtr));
5930 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005931 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005932 xmlFree(oldNs);
5933 return(-1);
5934 }
5935 }
5936 newNs[nbCache] = n;
5937 oldNs[nbCache++] = attr->ns;
5938 attr->ns = n;
5939 }
5940 }
5941 }
5942 attr = attr->next;
5943 }
5944
5945 /*
5946 * Browse the full subtree, deep first
5947 */
Daniel Veillardac996a12004-07-30 12:02:58 +00005948 if (node->children != NULL && node->type != XML_ENTITY_REF_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00005949 /* deep first */
5950 node = node->children;
5951 } else if ((node != tree) && (node->next != NULL)) {
5952 /* then siblings */
5953 node = node->next;
5954 } else if (node != tree) {
5955 /* go up to parents->next if needed */
5956 while (node != tree) {
5957 if (node->parent != NULL)
5958 node = node->parent;
5959 if ((node != tree) && (node->next != NULL)) {
5960 node = node->next;
5961 break;
5962 }
5963 if (node->parent == NULL) {
5964 node = NULL;
5965 break;
5966 }
5967 }
5968 /* exit condition */
5969 if (node == tree)
5970 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005971 } else
5972 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005973 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005974 if (oldNs != NULL)
5975 xmlFree(oldNs);
5976 if (newNs != NULL)
5977 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005978 return(ret);
5979}
Daniel Veillard652327a2003-09-29 18:02:38 +00005980#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005981
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00005982static xmlAttrPtr
5983xmlGetPropNodeInternal(xmlNodePtr node, const xmlChar *name,
5984 const xmlChar *nsName, int useDTD)
5985{
5986 xmlAttrPtr prop;
5987
5988 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
5989 return(NULL);
5990
5991 if (node->properties != NULL) {
5992 prop = node->properties;
5993 if (nsName == NULL) {
5994 /*
5995 * We want the attr to be in no namespace.
5996 */
5997 do {
5998 if ((prop->ns == NULL) && xmlStrEqual(prop->name, name)) {
5999 return(prop);
6000 }
6001 prop = prop->next;
6002 } while (prop != NULL);
6003 } else {
6004 /*
6005 * We want the attr to be in the specified namespace.
6006 */
6007 do {
6008 if ((prop->ns != NULL) && xmlStrEqual(prop->name, name) &&
6009 ((prop->ns->href == nsName) ||
6010 xmlStrEqual(prop->ns->href, nsName)))
6011 {
6012 return(prop);
6013 }
6014 prop = prop->next;
6015 } while (prop != NULL);
6016 }
6017 }
6018
6019#ifdef LIBXML_TREE_ENABLED
6020 if (! useDTD)
6021 return(NULL);
6022 /*
6023 * Check if there is a default/fixed attribute declaration in
6024 * the internal or external subset.
6025 */
6026 if ((node->doc != NULL) && (node->doc->intSubset != NULL)) {
6027 xmlDocPtr doc = node->doc;
6028 xmlAttributePtr attrDecl = NULL;
6029 xmlChar *elemQName, *tmpstr = NULL;
6030
6031 /*
6032 * We need the QName of the element for the DTD-lookup.
6033 */
6034 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
6035 tmpstr = xmlStrdup(node->ns->prefix);
6036 tmpstr = xmlStrcat(tmpstr, BAD_CAST ":");
6037 tmpstr = xmlStrcat(tmpstr, node->name);
6038 if (tmpstr == NULL)
6039 return(NULL);
6040 elemQName = tmpstr;
6041 } else
6042 elemQName = (xmlChar *) node->name;
6043 if (nsName == NULL) {
6044 /*
6045 * The common and nice case: Attr in no namespace.
6046 */
6047 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset,
6048 elemQName, name, NULL);
6049 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
6050 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset,
6051 elemQName, name, NULL);
6052 }
6053 } else {
6054 xmlNsPtr *nsList, *cur;
6055
6056 /*
6057 * The ugly case: Search using the prefixes of in-scope
6058 * ns-decls corresponding to @nsName.
6059 */
6060 nsList = xmlGetNsList(node->doc, node);
6061 if (nsList == NULL) {
6062 if (tmpstr != NULL)
6063 xmlFree(tmpstr);
6064 return(NULL);
6065 }
6066 cur = nsList;
6067 while (*cur != NULL) {
6068 if (xmlStrEqual((*cur)->href, nsName)) {
6069 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elemQName,
6070 name, (*cur)->prefix);
6071 if (attrDecl)
6072 break;
6073 if (doc->extSubset != NULL) {
6074 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elemQName,
6075 name, (*cur)->prefix);
6076 if (attrDecl)
6077 break;
6078 }
6079 }
6080 cur++;
6081 }
6082 xmlFree(nsList);
6083 }
6084 if (tmpstr != NULL)
6085 xmlFree(tmpstr);
6086 /*
6087 * Only default/fixed attrs are relevant.
6088 */
6089 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6090 return((xmlAttrPtr) attrDecl);
6091 }
6092#endif /* LIBXML_TREE_ENABLED */
6093 return(NULL);
6094}
6095
6096static xmlChar*
6097xmlGetPropNodeValueInternal(xmlAttrPtr prop)
6098{
6099 if (prop == NULL)
6100 return(NULL);
6101 if (prop->type == XML_ATTRIBUTE_NODE) {
6102 /*
6103 * Note that we return at least the empty string.
6104 * TODO: Do we really always want that?
6105 */
6106 if (prop->children != NULL) {
6107 if ((prop->children == prop->last) &&
6108 ((prop->children->type == XML_TEXT_NODE) ||
6109 (prop->children->type == XML_CDATA_SECTION_NODE)))
6110 {
6111 /*
6112 * Optimization for the common case: only 1 text node.
6113 */
6114 return(xmlStrdup(prop->children->content));
6115 } else {
6116 xmlChar *ret;
6117
6118 ret = xmlNodeListGetString(prop->doc, prop->children, 1);
6119 if (ret != NULL)
6120 return(ret);
6121 }
6122 }
6123 return(xmlStrdup((xmlChar *)""));
6124 } else if (prop->type == XML_ATTRIBUTE_DECL) {
6125 return(xmlStrdup(((xmlAttributePtr)prop)->defaultValue));
6126 }
6127 return(NULL);
6128}
6129
Owen Taylor3473f882001-02-23 17:55:21 +00006130/**
6131 * xmlHasProp:
6132 * @node: the node
6133 * @name: the attribute name
6134 *
6135 * Search an attribute associated to a node
6136 * This function also looks in DTD attribute declaration for #FIXED or
6137 * default declaration values unless DTD use has been turned off.
6138 *
6139 * Returns the attribute or the attribute declaration or NULL if
6140 * neither was found.
6141 */
6142xmlAttrPtr
6143xmlHasProp(xmlNodePtr node, const xmlChar *name) {
6144 xmlAttrPtr prop;
6145 xmlDocPtr doc;
6146
Daniel Veillard8874b942005-08-25 13:19:21 +00006147 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6148 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006149 /*
6150 * Check on the properties attached to the node
6151 */
6152 prop = node->properties;
6153 while (prop != NULL) {
6154 if (xmlStrEqual(prop->name, name)) {
6155 return(prop);
6156 }
6157 prop = prop->next;
6158 }
6159 if (!xmlCheckDTD) return(NULL);
6160
6161 /*
6162 * Check if there is a default declaration in the internal
6163 * or external subsets
6164 */
6165 doc = node->doc;
6166 if (doc != NULL) {
6167 xmlAttributePtr attrDecl;
6168 if (doc->intSubset != NULL) {
6169 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6170 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6171 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006172 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6173 /* return attribute declaration only if a default value is given
6174 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006175 return((xmlAttrPtr) attrDecl);
6176 }
6177 }
6178 return(NULL);
6179}
6180
6181/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00006182 * xmlHasNsProp:
6183 * @node: the node
6184 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006185 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00006186 *
6187 * Search for an attribute associated to a node
6188 * This attribute has to be anchored in the namespace specified.
6189 * This does the entity substitution.
6190 * This function looks in DTD attribute declaration for #FIXED or
6191 * default declaration values unless DTD use has been turned off.
William M. Brack2c228442004-10-03 04:10:00 +00006192 * Note that a namespace of NULL indicates to use the default namespace.
Daniel Veillarde95e2392001-06-06 10:46:28 +00006193 *
6194 * Returns the attribute or the attribute declaration or NULL
6195 * if neither was found.
6196 */
6197xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00006198xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00006199
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006200 return(xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD));
Daniel Veillarde95e2392001-06-06 10:46:28 +00006201}
6202
6203/**
Owen Taylor3473f882001-02-23 17:55:21 +00006204 * xmlGetProp:
6205 * @node: the node
6206 * @name: the attribute name
6207 *
6208 * Search and get the value of an attribute associated to a node
6209 * This does the entity substitution.
6210 * This function looks in DTD attribute declaration for #FIXED or
6211 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00006212 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00006213 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6214 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00006215 *
6216 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006217 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006218 */
6219xmlChar *
6220xmlGetProp(xmlNodePtr node, const xmlChar *name) {
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006221 xmlAttrPtr prop;
Owen Taylor3473f882001-02-23 17:55:21 +00006222
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006223 prop = xmlHasProp(node, name);
6224 if (prop == NULL)
6225 return(NULL);
6226 return(xmlGetPropNodeValueInternal(prop));
Owen Taylor3473f882001-02-23 17:55:21 +00006227}
6228
6229/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006230 * xmlGetNoNsProp:
6231 * @node: the node
6232 * @name: the attribute name
6233 *
6234 * Search and get the value of an attribute associated to a node
6235 * This does the entity substitution.
6236 * This function looks in DTD attribute declaration for #FIXED or
6237 * default declaration values unless DTD use has been turned off.
6238 * This function is similar to xmlGetProp except it will accept only
6239 * an attribute in no namespace.
6240 *
6241 * Returns the attribute value or NULL if not found.
6242 * It's up to the caller to free the memory with xmlFree().
6243 */
6244xmlChar *
6245xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6246 xmlAttrPtr prop;
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006247
6248 prop = xmlGetPropNodeInternal(node, name, NULL, xmlCheckDTD);
6249 if (prop == NULL)
Daniel Veillard8874b942005-08-25 13:19:21 +00006250 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006251 return(xmlGetPropNodeValueInternal(prop));
Daniel Veillard71531f32003-02-05 13:19:53 +00006252}
6253
6254/**
Owen Taylor3473f882001-02-23 17:55:21 +00006255 * xmlGetNsProp:
6256 * @node: the node
6257 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006258 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006259 *
6260 * Search and get the value of an attribute associated to a node
6261 * This attribute has to be anchored in the namespace specified.
6262 * This does the entity substitution.
6263 * This function looks in DTD attribute declaration for #FIXED or
6264 * default declaration values unless DTD use has been turned off.
6265 *
6266 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006267 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006268 */
6269xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006270xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006271 xmlAttrPtr prop;
Owen Taylor3473f882001-02-23 17:55:21 +00006272
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006273 prop = xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD);
6274 if (prop == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006275 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006276 return(xmlGetPropNodeValueInternal(prop));
Owen Taylor3473f882001-02-23 17:55:21 +00006277}
6278
Daniel Veillard2156d432004-03-04 15:59:36 +00006279#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6280/**
6281 * xmlUnsetProp:
6282 * @node: the node
6283 * @name: the attribute name
6284 *
6285 * Remove an attribute carried by a node.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006286 * This handles only attributes in no namespace.
Daniel Veillard2156d432004-03-04 15:59:36 +00006287 * Returns 0 if successful, -1 if not found
6288 */
6289int
6290xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Kasimier T. Buchcik65c2f1d2005-10-17 12:39:58 +00006291 xmlAttrPtr prop;
Daniel Veillard2156d432004-03-04 15:59:36 +00006292
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006293 prop = xmlGetPropNodeInternal(node, name, NULL, 0);
6294 if (prop == NULL)
Daniel Veillard2156d432004-03-04 15:59:36 +00006295 return(-1);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006296 xmlUnlinkNode((xmlNodePtr) prop);
6297 xmlFreeProp(prop);
6298 return(0);
Daniel Veillard2156d432004-03-04 15:59:36 +00006299}
6300
6301/**
6302 * xmlUnsetNsProp:
6303 * @node: the node
6304 * @ns: the namespace definition
6305 * @name: the attribute name
6306 *
6307 * Remove an attribute carried by a node.
6308 * Returns 0 if successful, -1 if not found
6309 */
6310int
6311xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
Kasimier T. Buchcik65c2f1d2005-10-17 12:39:58 +00006312 xmlAttrPtr prop;
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006313
6314 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
6315 if (prop == NULL)
Daniel Veillard2156d432004-03-04 15:59:36 +00006316 return(-1);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006317 xmlUnlinkNode((xmlNodePtr) prop);
6318 xmlFreeProp(prop);
6319 return(0);
Daniel Veillard2156d432004-03-04 15:59:36 +00006320}
6321#endif
6322
6323#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006324/**
6325 * xmlSetProp:
6326 * @node: the node
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006327 * @name: the attribute name (a QName)
Owen Taylor3473f882001-02-23 17:55:21 +00006328 * @value: the attribute value
6329 *
6330 * Set (or reset) an attribute carried by a node.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006331 * If @name has a prefix, then the corresponding
6332 * namespace-binding will be used, if in scope; it is an
6333 * error it there's no such ns-binding for the prefix in
6334 * scope.
Owen Taylor3473f882001-02-23 17:55:21 +00006335 * Returns the attribute pointer.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006336 *
Owen Taylor3473f882001-02-23 17:55:21 +00006337 */
6338xmlAttrPtr
6339xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006340 int len;
6341 const xmlChar *nqname;
Owen Taylor3473f882001-02-23 17:55:21 +00006342
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006343 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006344 return(NULL);
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006345
6346 /*
6347 * handle QNames
6348 */
6349 nqname = xmlSplitQName3(name, &len);
6350 if (nqname != NULL) {
6351 xmlNsPtr ns;
6352 xmlChar *prefix = xmlStrndup(name, len);
6353 ns = xmlSearchNs(node->doc, node, prefix);
6354 if (prefix != NULL)
6355 xmlFree(prefix);
6356 if (ns != NULL)
6357 return(xmlSetNsProp(node, ns, nqname, value));
6358 }
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006359 return(xmlSetNsProp(node, NULL, name, value));
Owen Taylor3473f882001-02-23 17:55:21 +00006360}
6361
6362/**
6363 * xmlSetNsProp:
6364 * @node: the node
6365 * @ns: the namespace definition
6366 * @name: the attribute name
6367 * @value: the attribute value
6368 *
6369 * Set (or reset) an attribute carried by a node.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006370 * The ns structure must be in scope, this is not checked
Owen Taylor3473f882001-02-23 17:55:21 +00006371 *
6372 * Returns the attribute pointer.
6373 */
6374xmlAttrPtr
6375xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006376 const xmlChar *value)
6377{
Owen Taylor3473f882001-02-23 17:55:21 +00006378 xmlAttrPtr prop;
6379
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006380 if (ns && (ns->href == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006381 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006382 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
6383 if (prop != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006384 /*
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006385 * Modify the attribute's value.
6386 */
6387 if (prop->atype == XML_ATTRIBUTE_ID) {
6388 xmlRemoveID(node->doc, prop);
6389 prop->atype = XML_ATTRIBUTE_ID;
6390 }
6391 if (prop->children != NULL)
6392 xmlFreeNodeList(prop->children);
6393 prop->children = NULL;
6394 prop->last = NULL;
6395 prop->ns = ns;
6396 if (value != NULL) {
6397 xmlChar *buffer;
6398 xmlNodePtr tmp;
6399
6400 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6401 prop->children = xmlStringGetNodeList(node->doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00006402 prop->last = NULL;
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006403 tmp = prop->children;
6404 while (tmp != NULL) {
6405 tmp->parent = (xmlNodePtr) prop;
6406 if (tmp->next == NULL)
6407 prop->last = tmp;
6408 tmp = tmp->next;
6409 }
6410 xmlFree(buffer);
6411 }
6412 if (prop->atype == XML_ATTRIBUTE_ID)
6413 xmlAddID(NULL, node->doc, value, prop);
6414 return(prop);
Owen Taylor3473f882001-02-23 17:55:21 +00006415 }
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006416 /*
6417 * No equal attr found; create a new one.
6418 */
6419 return(xmlNewPropInternal(node, ns, name, value, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006420}
6421
Daniel Veillard652327a2003-09-29 18:02:38 +00006422#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006423
6424/**
Owen Taylor3473f882001-02-23 17:55:21 +00006425 * xmlNodeIsText:
6426 * @node: the node
6427 *
6428 * Is this node a Text node ?
6429 * Returns 1 yes, 0 no
6430 */
6431int
6432xmlNodeIsText(xmlNodePtr node) {
6433 if (node == NULL) return(0);
6434
6435 if (node->type == XML_TEXT_NODE) return(1);
6436 return(0);
6437}
6438
6439/**
6440 * xmlIsBlankNode:
6441 * @node: the node
6442 *
6443 * Checks whether this node is an empty or whitespace only
6444 * (and possibly ignorable) text-node.
6445 *
6446 * Returns 1 yes, 0 no
6447 */
6448int
6449xmlIsBlankNode(xmlNodePtr node) {
6450 const xmlChar *cur;
6451 if (node == NULL) return(0);
6452
Daniel Veillard7db37732001-07-12 01:20:08 +00006453 if ((node->type != XML_TEXT_NODE) &&
6454 (node->type != XML_CDATA_SECTION_NODE))
6455 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006456 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006457 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006458 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006459 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006460 cur++;
6461 }
6462
6463 return(1);
6464}
6465
6466/**
6467 * xmlTextConcat:
6468 * @node: the node
6469 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006470 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006471 *
6472 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006473 *
6474 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006475 */
6476
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006477int
Owen Taylor3473f882001-02-23 17:55:21 +00006478xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006479 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006480
6481 if ((node->type != XML_TEXT_NODE) &&
6482 (node->type != XML_CDATA_SECTION_NODE)) {
6483#ifdef DEBUG_TREE
6484 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006485 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006486#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006487 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006488 }
William M. Brack7762bb12004-01-04 14:49:01 +00006489 /* need to check if content is currently in the dictionary */
Daniel Veillard8874b942005-08-25 13:19:21 +00006490 if ((node->content == (xmlChar *) &(node->properties)) ||
6491 ((node->doc != NULL) && (node->doc->dict != NULL) &&
6492 xmlDictOwns(node->doc->dict, node->content))) {
William M. Brack7762bb12004-01-04 14:49:01 +00006493 node->content = xmlStrncatNew(node->content, content, len);
6494 } else {
6495 node->content = xmlStrncat(node->content, content, len);
6496 }
Daniel Veillard8874b942005-08-25 13:19:21 +00006497 node->properties = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006498 if (node->content == NULL)
6499 return(-1);
6500 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006501}
6502
6503/************************************************************************
6504 * *
6505 * Output : to a FILE or in memory *
6506 * *
6507 ************************************************************************/
6508
Owen Taylor3473f882001-02-23 17:55:21 +00006509/**
6510 * xmlBufferCreate:
6511 *
6512 * routine to create an XML buffer.
6513 * returns the new structure.
6514 */
6515xmlBufferPtr
6516xmlBufferCreate(void) {
6517 xmlBufferPtr ret;
6518
6519 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6520 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006521 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006522 return(NULL);
6523 }
6524 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006525 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006526 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006527 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006528 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006529 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006530 xmlFree(ret);
6531 return(NULL);
6532 }
6533 ret->content[0] = 0;
6534 return(ret);
6535}
6536
6537/**
6538 * xmlBufferCreateSize:
6539 * @size: initial size of buffer
6540 *
6541 * routine to create an XML buffer.
6542 * returns the new structure.
6543 */
6544xmlBufferPtr
6545xmlBufferCreateSize(size_t size) {
6546 xmlBufferPtr ret;
6547
6548 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6549 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006550 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006551 return(NULL);
6552 }
6553 ret->use = 0;
6554 ret->alloc = xmlBufferAllocScheme;
6555 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6556 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006557 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006558 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006559 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006560 xmlFree(ret);
6561 return(NULL);
6562 }
6563 ret->content[0] = 0;
6564 } else
6565 ret->content = NULL;
6566 return(ret);
6567}
6568
6569/**
Daniel Veillard53350552003-09-18 13:35:51 +00006570 * xmlBufferCreateStatic:
6571 * @mem: the memory area
6572 * @size: the size in byte
6573 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006574 * routine to create an XML buffer from an immutable memory area.
6575 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006576 * present until the end of the buffer lifetime.
6577 *
6578 * returns the new structure.
6579 */
6580xmlBufferPtr
6581xmlBufferCreateStatic(void *mem, size_t size) {
6582 xmlBufferPtr ret;
6583
6584 if ((mem == NULL) || (size == 0))
6585 return(NULL);
6586
6587 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6588 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006589 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006590 return(NULL);
6591 }
6592 ret->use = size;
6593 ret->size = size;
6594 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6595 ret->content = (xmlChar *) mem;
6596 return(ret);
6597}
6598
6599/**
Owen Taylor3473f882001-02-23 17:55:21 +00006600 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006601 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006602 * @scheme: allocation scheme to use
6603 *
6604 * Sets the allocation scheme for this buffer
6605 */
6606void
6607xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6608 xmlBufferAllocationScheme scheme) {
6609 if (buf == NULL) {
6610#ifdef DEBUG_BUFFER
6611 xmlGenericError(xmlGenericErrorContext,
6612 "xmlBufferSetAllocationScheme: buf == NULL\n");
6613#endif
6614 return;
6615 }
Daniel Veillard53350552003-09-18 13:35:51 +00006616 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006617
6618 buf->alloc = scheme;
6619}
6620
6621/**
6622 * xmlBufferFree:
6623 * @buf: the buffer to free
6624 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006625 * Frees an XML buffer. It frees both the content and the structure which
6626 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006627 */
6628void
6629xmlBufferFree(xmlBufferPtr buf) {
6630 if (buf == NULL) {
6631#ifdef DEBUG_BUFFER
6632 xmlGenericError(xmlGenericErrorContext,
6633 "xmlBufferFree: buf == NULL\n");
6634#endif
6635 return;
6636 }
Daniel Veillard53350552003-09-18 13:35:51 +00006637
6638 if ((buf->content != NULL) &&
6639 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006640 xmlFree(buf->content);
6641 }
Owen Taylor3473f882001-02-23 17:55:21 +00006642 xmlFree(buf);
6643}
6644
6645/**
6646 * xmlBufferEmpty:
6647 * @buf: the buffer
6648 *
6649 * empty a buffer.
6650 */
6651void
6652xmlBufferEmpty(xmlBufferPtr buf) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006653 if (buf == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006654 if (buf->content == NULL) return;
6655 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006656 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006657 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006658 } else {
6659 memset(buf->content, 0, buf->size);
6660 }
Owen Taylor3473f882001-02-23 17:55:21 +00006661}
6662
6663/**
6664 * xmlBufferShrink:
6665 * @buf: the buffer to dump
6666 * @len: the number of xmlChar to remove
6667 *
6668 * Remove the beginning of an XML buffer.
6669 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006670 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006671 */
6672int
6673xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
Daniel Veillard3d97e662004-11-04 10:49:00 +00006674 if (buf == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006675 if (len == 0) return(0);
6676 if (len > buf->use) return(-1);
6677
6678 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006679 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6680 buf->content += len;
6681 } else {
6682 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6683 buf->content[buf->use] = 0;
6684 }
Owen Taylor3473f882001-02-23 17:55:21 +00006685 return(len);
6686}
6687
6688/**
6689 * xmlBufferGrow:
6690 * @buf: the buffer
6691 * @len: the minimum free size to allocate
6692 *
6693 * Grow the available space of an XML buffer.
6694 *
6695 * Returns the new available space or -1 in case of error
6696 */
6697int
6698xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6699 int size;
6700 xmlChar *newbuf;
6701
Daniel Veillard3d97e662004-11-04 10:49:00 +00006702 if (buf == NULL) return(-1);
6703
Daniel Veillard53350552003-09-18 13:35:51 +00006704 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006705 if (len + buf->use < buf->size) return(0);
6706
William M. Brack30fe43f2004-07-26 18:00:58 +00006707/*
6708 * Windows has a BIG problem on realloc timing, so we try to double
6709 * the buffer size (if that's enough) (bug 146697)
6710 */
6711#ifdef WIN32
6712 if (buf->size > len)
6713 size = buf->size * 2;
6714 else
6715 size = buf->use + len + 100;
6716#else
Owen Taylor3473f882001-02-23 17:55:21 +00006717 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00006718#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006719
6720 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006721 if (newbuf == NULL) {
6722 xmlTreeErrMemory("growing buffer");
6723 return(-1);
6724 }
Owen Taylor3473f882001-02-23 17:55:21 +00006725 buf->content = newbuf;
6726 buf->size = size;
6727 return(buf->size - buf->use);
6728}
6729
6730/**
6731 * xmlBufferDump:
6732 * @file: the file output
6733 * @buf: the buffer to dump
6734 *
6735 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006736 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006737 */
6738int
6739xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6740 int ret;
6741
6742 if (buf == NULL) {
6743#ifdef DEBUG_BUFFER
6744 xmlGenericError(xmlGenericErrorContext,
6745 "xmlBufferDump: buf == NULL\n");
6746#endif
6747 return(0);
6748 }
6749 if (buf->content == NULL) {
6750#ifdef DEBUG_BUFFER
6751 xmlGenericError(xmlGenericErrorContext,
6752 "xmlBufferDump: buf->content == NULL\n");
6753#endif
6754 return(0);
6755 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006756 if (file == NULL)
6757 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006758 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6759 return(ret);
6760}
6761
6762/**
6763 * xmlBufferContent:
6764 * @buf: the buffer
6765 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006766 * Function to extract the content of a buffer
6767 *
Owen Taylor3473f882001-02-23 17:55:21 +00006768 * Returns the internal content
6769 */
6770
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006771const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006772xmlBufferContent(const xmlBufferPtr buf)
6773{
6774 if(!buf)
6775 return NULL;
6776
6777 return buf->content;
6778}
6779
6780/**
6781 * xmlBufferLength:
6782 * @buf: the buffer
6783 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006784 * Function to get the length of a buffer
6785 *
Owen Taylor3473f882001-02-23 17:55:21 +00006786 * Returns the length of data in the internal content
6787 */
6788
6789int
6790xmlBufferLength(const xmlBufferPtr buf)
6791{
6792 if(!buf)
6793 return 0;
6794
6795 return buf->use;
6796}
6797
6798/**
6799 * xmlBufferResize:
6800 * @buf: the buffer to resize
6801 * @size: the desired size
6802 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006803 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006804 *
6805 * Returns 0 in case of problems, 1 otherwise
6806 */
6807int
6808xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6809{
6810 unsigned int newSize;
6811 xmlChar* rebuf = NULL;
6812
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006813 if (buf == NULL)
6814 return(0);
6815
Daniel Veillard53350552003-09-18 13:35:51 +00006816 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6817
Owen Taylor3473f882001-02-23 17:55:21 +00006818 /* Don't resize if we don't have to */
6819 if (size < buf->size)
6820 return 1;
6821
6822 /* figure out new size */
6823 switch (buf->alloc){
6824 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillardbf629492004-04-20 22:20:59 +00006825 /*take care of empty case*/
6826 newSize = (buf->size ? buf->size*2 : size + 10);
Owen Taylor3473f882001-02-23 17:55:21 +00006827 while (size > newSize) newSize *= 2;
6828 break;
6829 case XML_BUFFER_ALLOC_EXACT:
6830 newSize = size+10;
6831 break;
6832 default:
6833 newSize = size+10;
6834 break;
6835 }
6836
6837 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006838 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006839 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006840 rebuf = (xmlChar *) xmlRealloc(buf->content,
6841 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006842 } else {
6843 /*
6844 * if we are reallocating a buffer far from being full, it's
6845 * better to make a new allocation and copy only the used range
6846 * and free the old one.
6847 */
6848 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6849 if (rebuf != NULL) {
6850 memcpy(rebuf, buf->content, buf->use);
6851 xmlFree(buf->content);
William M. Brack42331a92004-07-29 07:07:16 +00006852 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006853 }
6854 }
Owen Taylor3473f882001-02-23 17:55:21 +00006855 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006856 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006857 return 0;
6858 }
6859 buf->content = rebuf;
6860 buf->size = newSize;
6861
6862 return 1;
6863}
6864
6865/**
6866 * xmlBufferAdd:
6867 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006868 * @str: the #xmlChar string
6869 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006870 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006871 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006872 * str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006873 *
6874 * Returns 0 successful, a positive error code number otherwise
6875 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006876 */
William M. Bracka3215c72004-07-31 16:24:01 +00006877int
Owen Taylor3473f882001-02-23 17:55:21 +00006878xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6879 unsigned int needSize;
6880
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006881 if ((str == NULL) || (buf == NULL)) {
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 (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006885 if (len < -1) {
6886#ifdef DEBUG_BUFFER
6887 xmlGenericError(xmlGenericErrorContext,
6888 "xmlBufferAdd: len < 0\n");
6889#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006890 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006891 }
William M. Bracka3215c72004-07-31 16:24:01 +00006892 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006893
6894 if (len < 0)
6895 len = xmlStrlen(str);
6896
William M. Bracka3215c72004-07-31 16:24:01 +00006897 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006898
6899 needSize = buf->use + len + 2;
6900 if (needSize > buf->size){
6901 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006902 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006903 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006904 }
6905 }
6906
6907 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6908 buf->use += len;
6909 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006910 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006911}
6912
6913/**
6914 * xmlBufferAddHead:
6915 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006916 * @str: the #xmlChar string
6917 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006918 *
6919 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006920 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006921 *
6922 * Returns 0 successful, a positive error code number otherwise
6923 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006924 */
William M. Bracka3215c72004-07-31 16:24:01 +00006925int
Owen Taylor3473f882001-02-23 17:55:21 +00006926xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6927 unsigned int needSize;
6928
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006929 if (buf == NULL)
6930 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00006931 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006932 if (str == NULL) {
6933#ifdef DEBUG_BUFFER
6934 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006935 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006936#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006937 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006938 }
6939 if (len < -1) {
6940#ifdef DEBUG_BUFFER
6941 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006942 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006943#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006944 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006945 }
William M. Bracka3215c72004-07-31 16:24:01 +00006946 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006947
6948 if (len < 0)
6949 len = xmlStrlen(str);
6950
William M. Bracka3215c72004-07-31 16:24:01 +00006951 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006952
6953 needSize = buf->use + len + 2;
6954 if (needSize > buf->size){
6955 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006956 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006957 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006958 }
6959 }
6960
6961 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6962 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6963 buf->use += len;
6964 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006965 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006966}
6967
6968/**
6969 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00006970 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00006971 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006972 *
6973 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00006974 *
6975 * Returns 0 successful, a positive error code number otherwise
6976 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006977 */
William M. Bracka3215c72004-07-31 16:24:01 +00006978int
Owen Taylor3473f882001-02-23 17:55:21 +00006979xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006980 if (buf == NULL)
6981 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00006982 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
6983 if (str == NULL) return -1;
6984 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00006985}
6986
6987/**
6988 * xmlBufferCCat:
6989 * @buf: the buffer to dump
6990 * @str: the C char string
6991 *
6992 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00006993 *
6994 * Returns 0 successful, a positive error code number otherwise
6995 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006996 */
William M. Bracka3215c72004-07-31 16:24:01 +00006997int
Owen Taylor3473f882001-02-23 17:55:21 +00006998xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6999 const char *cur;
7000
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007001 if (buf == NULL)
7002 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007003 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007004 if (str == NULL) {
7005#ifdef DEBUG_BUFFER
7006 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007007 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007008#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007009 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007010 }
7011 for (cur = str;*cur != 0;cur++) {
7012 if (buf->use + 10 >= buf->size) {
7013 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007014 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007015 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007016 }
7017 }
7018 buf->content[buf->use++] = *cur;
7019 }
7020 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007021 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007022}
7023
7024/**
7025 * xmlBufferWriteCHAR:
7026 * @buf: the XML buffer
7027 * @string: the string to add
7028 *
7029 * routine which manages and grows an output buffer. This one adds
7030 * xmlChars at the end of the buffer.
7031 */
7032void
Daniel Veillard53350552003-09-18 13:35:51 +00007033xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007034 if (buf == NULL)
7035 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007036 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007037 xmlBufferCat(buf, string);
7038}
7039
7040/**
7041 * xmlBufferWriteChar:
7042 * @buf: the XML buffer output
7043 * @string: the string to add
7044 *
7045 * routine which manage and grows an output buffer. This one add
7046 * C chars at the end of the array.
7047 */
7048void
7049xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007050 if (buf == NULL)
7051 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007052 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007053 xmlBufferCCat(buf, string);
7054}
7055
7056
7057/**
7058 * xmlBufferWriteQuotedString:
7059 * @buf: the XML buffer output
7060 * @string: the string to add
7061 *
7062 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00007063 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00007064 * quote or double-quotes internally
7065 */
7066void
7067xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00007068 const xmlChar *cur, *base;
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007069 if (buf == NULL)
7070 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007071 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00007072 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00007073 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00007074#ifdef DEBUG_BUFFER
7075 xmlGenericError(xmlGenericErrorContext,
7076 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7077#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00007078 xmlBufferCCat(buf, "\"");
7079 base = cur = string;
7080 while(*cur != 0){
7081 if(*cur == '"'){
7082 if (base != cur)
7083 xmlBufferAdd(buf, base, cur - base);
7084 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7085 cur++;
7086 base = cur;
7087 }
7088 else {
7089 cur++;
7090 }
7091 }
7092 if (base != cur)
7093 xmlBufferAdd(buf, base, cur - base);
7094 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007095 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007096 else{
7097 xmlBufferCCat(buf, "\'");
7098 xmlBufferCat(buf, string);
7099 xmlBufferCCat(buf, "\'");
7100 }
Owen Taylor3473f882001-02-23 17:55:21 +00007101 } else {
7102 xmlBufferCCat(buf, "\"");
7103 xmlBufferCat(buf, string);
7104 xmlBufferCCat(buf, "\"");
7105 }
7106}
7107
7108
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007109/**
7110 * xmlGetDocCompressMode:
7111 * @doc: the document
7112 *
7113 * get the compression ratio for a document, ZLIB based
7114 * Returns 0 (uncompressed) to 9 (max compression)
7115 */
7116int
7117xmlGetDocCompressMode (xmlDocPtr doc) {
7118 if (doc == NULL) return(-1);
7119 return(doc->compression);
7120}
7121
7122/**
7123 * xmlSetDocCompressMode:
7124 * @doc: the document
7125 * @mode: the compression ratio
7126 *
7127 * set the compression ratio for a document, ZLIB based
7128 * Correct values: 0 (uncompressed) to 9 (max compression)
7129 */
7130void
7131xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7132 if (doc == NULL) return;
7133 if (mode < 0) doc->compression = 0;
7134 else if (mode > 9) doc->compression = 9;
7135 else doc->compression = mode;
7136}
7137
7138/**
7139 * xmlGetCompressMode:
7140 *
7141 * get the default compression mode used, ZLIB based.
7142 * Returns 0 (uncompressed) to 9 (max compression)
7143 */
7144int
7145xmlGetCompressMode(void)
7146{
7147 return (xmlCompressMode);
7148}
7149
7150/**
7151 * xmlSetCompressMode:
7152 * @mode: the compression ratio
7153 *
7154 * set the default compression mode used, ZLIB based
7155 * Correct values: 0 (uncompressed) to 9 (max compression)
7156 */
7157void
7158xmlSetCompressMode(int mode) {
7159 if (mode < 0) xmlCompressMode = 0;
7160 else if (mode > 9) xmlCompressMode = 9;
7161 else xmlCompressMode = mode;
7162}
7163
Kasimier T. Buchcik4d9c9482005-06-27 15:04:46 +00007164/*
7165* xmlDOMWrapNewCtxt:
7166*
7167* Allocates and initializes a new DOM-wrapper context.
7168*
7169* Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal errror.
7170*/
7171xmlDOMWrapCtxtPtr
7172xmlDOMWrapNewCtxt(void)
7173{
7174 xmlDOMWrapCtxtPtr ret;
7175
7176 ret = xmlMalloc(sizeof(xmlDOMWrapCtxt));
7177 if (ret == NULL) {
7178 xmlTreeErrMemory("allocating DOM-wrapper context");
7179 return (NULL);
7180 }
7181 memset(ret, 0, sizeof(xmlDOMWrapCtxt));
7182 return (ret);
7183}
7184
7185/*
7186* xmlDOMWrapFreeCtxt:
7187* @ctxt: the DOM-wrapper context
7188*
7189* Frees the DOM-wrapper context.
7190*/
7191void
7192xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt)
7193{
7194 if (ctxt == NULL)
7195 return;
7196 xmlFree(ctxt);
7197}
7198
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007199#define XML_TREE_NSMAP_PARENT -1
7200#define XML_TREE_NSMAP_XML -2
7201#define XML_TREE_NSMAP_DOC -3
7202#define XML_TREE_NSMAP_CUSTOM -4
7203
7204typedef struct xmlNsMapItem *xmlNsMapItemPtr;
7205struct xmlNsMapItem {
7206 xmlNsMapItemPtr next;
7207 xmlNsMapItemPtr prev;
7208 xmlNsPtr oldNs; /* old ns decl reference */
7209 xmlNsPtr newNs; /* new ns decl reference */
7210 int shadowDepth; /* Shadowed at this depth */
7211 /*
7212 * depth:
7213 * >= 0 == @node's ns-decls
7214 * -1 == @parent's ns-decls
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00007215 * -2 == the doc->oldNs XML ns-decl
7216 * -3 == the doc->oldNs storage ns-decls
7217 * -4 == ns-decls provided via custom ns-handling
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007218 */
7219 int depth;
7220};
7221
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007222typedef struct xmlNsMap *xmlNsMapPtr;
7223struct xmlNsMap {
7224 xmlNsMapItemPtr first;
7225 xmlNsMapItemPtr last;
7226 xmlNsMapItemPtr pool;
7227};
7228
7229#define XML_NSMAP_NOTEMPTY(m) (((m) != NULL) && ((m)->first != NULL))
7230#define XML_NSMAP_FOREACH(m, i) for (i = (m)->first; i != NULL; i = (i)->next)
7231#define XML_NSMAP_POP(m, i) \
7232 i = (m)->last; \
7233 (m)->last = (i)->prev; \
7234 if ((m)->last == NULL) \
7235 (m)->first = NULL; \
7236 else \
7237 (m)->last->next = NULL; \
7238 (i)->next = (m)->pool; \
7239 (m)->pool = i;
7240
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007241/*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007242* xmlDOMWrapNsMapFree:
7243* @map: the ns-map
7244*
7245* Frees the ns-map
7246*/
7247static void
7248xmlDOMWrapNsMapFree(xmlNsMapPtr nsmap)
7249{
7250 xmlNsMapItemPtr cur, tmp;
7251
7252 if (nsmap == NULL)
7253 return;
7254 cur = nsmap->pool;
7255 while (cur != NULL) {
7256 tmp = cur;
7257 cur = cur->next;
7258 xmlFree(tmp);
7259 }
7260 cur = nsmap->first;
7261 while (cur != NULL) {
7262 tmp = cur;
7263 cur = cur->next;
7264 xmlFree(tmp);
7265 }
7266 xmlFree(nsmap);
7267}
7268
7269/*
7270* xmlDOMWrapNsMapAddItem:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007271* @map: the ns-map
7272* @cur: the current map entry to append a new entry to
7273* @oldNs: the old ns-struct
7274* @newNs: the new ns-struct
7275* @depth: depth and ns-kind information
7276*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007277* Adds an ns-mapping item.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007278*/
7279static xmlNsMapItemPtr
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007280xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position, /* xmlNsMapItemPtr *cur, */
7281 xmlNsPtr oldNs, xmlNsPtr newNs, int depth)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007282{
7283 xmlNsMapItemPtr ret;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007284 xmlNsMapPtr map;
7285
7286 if (nsmap == NULL)
7287 return(NULL);
7288 if ((position != -1) && (position != 0))
7289 return(NULL);
7290 map = *nsmap;
7291
7292 if (map == NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007293 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007294 * Create the ns-map.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007295 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007296 map = (xmlNsMapPtr) xmlMalloc(sizeof(struct xmlNsMap));
7297 if (map == NULL) {
7298 xmlTreeErrMemory("allocating namespace map");
7299 return (NULL);
7300 }
7301 memset(map, 0, sizeof(struct xmlNsMap));
7302 *nsmap = map;
7303 }
7304
7305 if (map->pool != NULL) {
7306 /*
7307 * Reuse an item from the pool.
7308 */
7309 ret = map->pool;
7310 map->pool = ret->next;
7311 memset(ret, 0, sizeof(struct xmlNsMapItem));
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007312 } else {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007313 /*
7314 * Create a new item.
7315 */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007316 ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem));
7317 if (ret == NULL) {
7318 xmlTreeErrMemory("allocating namespace map item");
7319 return (NULL);
7320 }
7321 memset(ret, 0, sizeof(struct xmlNsMapItem));
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007322 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007323
7324 if (map->first == NULL) {
7325 /*
7326 * First ever.
7327 */
7328 map->first = ret;
7329 map->last = ret;
7330 } else if (position == -1) {
7331 /*
7332 * Append.
7333 */
7334 ret->prev = map->last;
7335 map->last->next = ret;
7336 map->last = ret;
7337 } else if (position == 0) {
7338 /*
7339 * Set on first position.
7340 */
7341 map->first->prev = ret;
7342 ret->next = map->first;
7343 map->first = ret;
7344 } else
7345 return(NULL);
7346
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007347 ret->oldNs = oldNs;
7348 ret->newNs = newNs;
7349 ret->shadowDepth = -1;
7350 ret->depth = depth;
7351 return (ret);
7352}
7353
7354/*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007355* xmlTreeEnsureXMLDecl:
7356* @doc: the doc
7357*
7358* Ensures that there is an XML namespace declaration on the doc.
7359*
7360* Returns the XML ns-struct or NULL on API and internal errors.
7361*/
7362static xmlNsPtr
7363xmlTreeEnsureXMLDecl(xmlDocPtr doc)
7364{
7365 if (doc == NULL)
7366 return (NULL);
7367 if (doc->oldNs != NULL)
7368 return (doc->oldNs);
7369 {
7370 xmlNsPtr ns;
7371 ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
7372 if (ns == NULL) {
7373 xmlTreeErrMemory(
7374 "allocating the XML namespace");
7375 return (NULL);
7376 }
7377 memset(ns, 0, sizeof(xmlNs));
7378 ns->type = XML_LOCAL_NAMESPACE;
7379 ns->href = xmlStrdup(XML_XML_NAMESPACE);
7380 ns->prefix = xmlStrdup((const xmlChar *)"xml");
7381 doc->oldNs = ns;
7382 return (ns);
7383 }
7384}
7385
7386/*
7387* xmlDOMWrapStoreNs:
7388* @doc: the doc
7389* @nsName: the namespace name
7390* @prefix: the prefix
7391*
7392* Creates or reuses an xmlNs struct on doc->oldNs with
7393* the given prefix and namespace name.
7394*
7395* Returns the aquired ns struct or NULL in case of an API
7396* or internal error.
7397*/
7398static xmlNsPtr
7399xmlDOMWrapStoreNs(xmlDocPtr doc,
7400 const xmlChar *nsName,
7401 const xmlChar *prefix)
7402{
7403 xmlNsPtr ns;
7404
7405 if (doc == NULL)
7406 return (NULL);
7407 ns = xmlTreeEnsureXMLDecl(doc);
7408 if (ns == NULL)
7409 return (NULL);
7410 if (ns->next != NULL) {
7411 /* Reuse. */
7412 ns = ns->next;
7413 while (ns != NULL) {
7414 if (((ns->prefix == prefix) ||
7415 xmlStrEqual(ns->prefix, prefix)) &&
7416 xmlStrEqual(ns->href, nsName)) {
7417 return (ns);
7418 }
7419 if (ns->next == NULL)
7420 break;
7421 ns = ns->next;
7422 }
7423 }
7424 /* Create. */
7425 ns->next = xmlNewNs(NULL, nsName, prefix);
7426 return (ns->next);
7427}
7428
7429/*
7430* xmlTreeLookupNsListByPrefix:
7431* @nsList: a list of ns-structs
7432* @prefix: the searched prefix
7433*
7434* Searches for a ns-decl with the given prefix in @nsList.
7435*
7436* Returns the ns-decl if found, NULL if not found and on
7437* API errors.
7438*/
7439static xmlNsPtr
7440xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix)
7441{
7442 if (nsList == NULL)
7443 return (NULL);
7444 {
7445 xmlNsPtr ns;
7446 ns = nsList;
7447 do {
7448 if ((prefix == ns->prefix) ||
7449 xmlStrEqual(prefix, ns->prefix)) {
7450 return (ns);
7451 }
7452 ns = ns->next;
7453 } while (ns != NULL);
7454 }
7455 return (NULL);
7456}
7457
7458/*
7459*
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00007460* xmlDOMWrapNSNormGatherInScopeNs:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007461* @map: the namespace map
7462* @node: the node to start with
7463*
7464* Puts in-scope namespaces into the ns-map.
7465*
7466* Returns 0 on success, -1 on API or internal errors.
7467*/
7468static int
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007469xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapPtr *map,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007470 xmlNodePtr node)
7471{
7472 xmlNodePtr cur;
7473 xmlNsPtr ns;
7474 xmlNsMapItemPtr mi;
7475 int shadowed;
7476
7477 if ((map == NULL) || (*map != NULL))
7478 return (-1);
7479 /*
7480 * Get in-scope ns-decls of @parent.
7481 */
7482 cur = node;
7483 while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) {
7484 if (cur->type == XML_ELEMENT_NODE) {
7485 if (cur->nsDef != NULL) {
7486 ns = cur->nsDef;
7487 do {
7488 shadowed = 0;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007489 if (XML_NSMAP_NOTEMPTY(*map)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007490 /*
7491 * Skip shadowed prefixes.
7492 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007493 XML_NSMAP_FOREACH(*map, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007494 if ((ns->prefix == mi->newNs->prefix) ||
7495 xmlStrEqual(ns->prefix, mi->newNs->prefix)) {
7496 shadowed = 1;
7497 break;
7498 }
7499 }
7500 }
7501 /*
7502 * Insert mapping.
7503 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007504 mi = xmlDOMWrapNsMapAddItem(map, 0, NULL,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007505 ns, XML_TREE_NSMAP_PARENT);
7506 if (mi == NULL)
7507 return (-1);
7508 if (shadowed)
7509 mi->shadowDepth = 0;
7510 ns = ns->next;
7511 } while (ns != NULL);
7512 }
7513 }
7514 cur = cur->parent;
7515 }
7516 return (0);
7517}
7518
7519/*
7520* XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict;
7521* otherwise copy it, when it was in the source-dict.
7522*/
7523#define XML_TREE_ADOPT_STR(str) \
7524 if (adoptStr && (str != NULL)) { \
7525 if (destDoc->dict) { \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00007526 const xmlChar *old = str; \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007527 str = xmlDictLookup(destDoc->dict, str, -1); \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00007528 if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \
7529 (!xmlDictOwns(sourceDoc->dict, old))) \
Daniel Veillard39e5c892005-07-03 22:48:50 +00007530 xmlFree((char *)old); \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007531 } else if ((sourceDoc) && (sourceDoc->dict) && \
7532 xmlDictOwns(sourceDoc->dict, str)) { \
7533 str = BAD_CAST xmlStrdup(str); \
7534 } \
7535 }
7536
7537/*
7538* XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then
7539* put it in dest-dict or copy it.
7540*/
7541#define XML_TREE_ADOPT_STR_2(str) \
7542 if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \
7543 (sourceDoc->dict != NULL) && \
7544 xmlDictOwns(sourceDoc->dict, cur->content)) { \
7545 if (destDoc->dict) \
7546 cur->content = (xmlChar *) \
7547 xmlDictLookup(destDoc->dict, cur->content, -1); \
7548 else \
7549 cur->content = xmlStrdup(BAD_CAST cur->content); \
7550 }
7551
7552/*
7553* xmlDOMWrapNSNormAddNsMapItem2:
7554*
7555* For internal use. Adds a ns-decl mapping.
7556*
7557* Returns 0 on success, -1 on internal errors.
7558*/
7559static int
7560xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number,
7561 xmlNsPtr oldNs, xmlNsPtr newNs)
7562{
7563 if (*list == NULL) {
7564 *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr));
7565 if (*list == NULL) {
7566 xmlTreeErrMemory("alloc ns map item");
7567 return(-1);
7568 }
7569 *size = 3;
7570 *number = 0;
7571 } else if ((*number) >= (*size)) {
7572 *size *= 2;
7573 *list = (xmlNsPtr *) xmlRealloc(*list,
7574 (*size) * 2 * sizeof(xmlNsPtr));
7575 if (*list == NULL) {
7576 xmlTreeErrMemory("realloc ns map item");
7577 return(-1);
7578 }
7579 }
7580 (*list)[2 * (*number)] = oldNs;
7581 (*list)[2 * (*number) +1] = newNs;
7582 (*number)++;
7583 return (0);
7584}
7585
7586/*
7587* xmlDOMWrapRemoveNode:
Daniel Veillard304e78c2005-07-03 16:19:41 +00007588* @ctxt: a DOM wrapper context
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007589* @doc: the doc
7590* @node: the node to be removed.
Daniel Veillard304e78c2005-07-03 16:19:41 +00007591* @options: set of options, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007592*
7593* Unlinks the given node from its owner.
7594* This will substitute ns-references to node->nsDef for
7595* ns-references to doc->oldNs, thus ensuring the removed
7596* branch to be autark wrt ns-references.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00007597* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007598*
7599* Returns 0 on success, 1 if the node is not supported,
7600* -1 on API and internal errors.
7601*/
7602int
7603xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc,
7604 xmlNodePtr node, int options ATTRIBUTE_UNUSED)
7605{
7606 xmlNsPtr *list = NULL;
7607 int sizeList, nbList, i, j;
7608 xmlNsPtr ns;
7609
7610 if ((node == NULL) || (doc == NULL) || (node->doc != doc))
7611 return (-1);
7612
7613 /* TODO: 0 or -1 ? */
7614 if (node->parent == NULL)
7615 return (0);
7616
7617 switch (node->type) {
7618 case XML_TEXT_NODE:
7619 case XML_CDATA_SECTION_NODE:
7620 case XML_ENTITY_REF_NODE:
7621 case XML_PI_NODE:
7622 case XML_COMMENT_NODE:
7623 xmlUnlinkNode(node);
7624 return (0);
7625 case XML_ELEMENT_NODE:
7626 case XML_ATTRIBUTE_NODE:
7627 break;
7628 default:
7629 return (1);
7630 }
7631 xmlUnlinkNode(node);
7632 /*
7633 * Save out-of-scope ns-references in doc->oldNs.
7634 */
7635 do {
7636 switch (node->type) {
7637 case XML_ELEMENT_NODE:
7638 if ((ctxt == NULL) && (node->nsDef != NULL)) {
7639 ns = node->nsDef;
7640 do {
7641 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
7642 &nbList, ns, ns) == -1)
7643 goto internal_error;
7644 ns = ns->next;
7645 } while (ns != NULL);
7646 }
7647 /* No break on purpose. */
7648 case XML_ATTRIBUTE_NODE:
7649 if (node->ns != NULL) {
7650 /*
7651 * Find a mapping.
7652 */
7653 if (list != NULL) {
7654 for (i = 0, j = 0; i < nbList; i++, j += 2) {
7655 if (node->ns == list[j]) {
7656 node->ns = list[++j];
7657 goto next_node;
7658 }
7659 }
7660 }
7661 ns = NULL;
7662 if (ctxt != NULL) {
7663 /*
7664 * User defined.
7665 */
7666 } else {
7667 /*
7668 * Add to doc's oldNs.
7669 */
7670 ns = xmlDOMWrapStoreNs(doc, node->ns->href,
7671 node->ns->prefix);
7672 if (ns == NULL)
7673 goto internal_error;
7674 }
7675 if (ns != NULL) {
7676 /*
7677 * Add mapping.
7678 */
7679 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
7680 &nbList, node->ns, ns) == -1)
7681 goto internal_error;
7682 }
7683 node->ns = ns;
7684 }
7685 if ((node->type == XML_ELEMENT_NODE) &&
7686 (node->properties != NULL)) {
7687 node = (xmlNodePtr) node->properties;
7688 continue;
7689 }
7690 break;
7691 default:
7692 goto next_sibling;
7693 }
7694next_node:
7695 if ((node->type == XML_ELEMENT_NODE) &&
7696 (node->children != NULL)) {
7697 node = node->children;
7698 continue;
7699 }
7700next_sibling:
7701 if (node == NULL)
7702 break;
7703 if (node->next != NULL)
7704 node = node->next;
7705 else {
7706 node = node->parent;
7707 goto next_sibling;
7708 }
7709 } while (node != NULL);
7710
7711 if (list != NULL)
7712 xmlFree(list);
7713 return (0);
7714
7715internal_error:
7716 if (list != NULL)
7717 xmlFree(list);
7718 return (-1);
7719}
7720
7721/*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007722* xmlSearchNsByNamespaceStrict:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007723* @doc: the document
7724* @node: the start node
7725* @nsName: the searched namespace name
7726* @retNs: the resulting ns-decl
7727* @prefixed: if the found ns-decl must have a prefix (for attributes)
7728*
7729* Dynamically searches for a ns-declaration which matches
7730* the given @nsName in the ancestor-or-self axis of @node.
7731*
7732* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7733* and internal errors.
7734*/
7735static int
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007736xmlSearchNsByNamespaceStrict(xmlDocPtr doc, xmlNodePtr node,
7737 const xmlChar* nsName,
7738 xmlNsPtr *retNs, int prefixed)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007739{
7740 xmlNodePtr cur, prev = NULL, out = NULL;
7741 xmlNsPtr ns, prevns;
7742
7743 if ((doc == NULL) || (nsName == NULL) || (retNs == NULL))
7744 return (-1);
7745
7746 *retNs = NULL;
7747 if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
7748 *retNs = xmlTreeEnsureXMLDecl(doc);
7749 if (*retNs == NULL)
7750 return (-1);
7751 return (1);
7752 }
7753 cur = node;
7754 do {
7755 if (cur->type == XML_ELEMENT_NODE) {
7756 if (cur->nsDef != NULL) {
7757 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
7758 if (prefixed && (ns->prefix == NULL))
7759 continue;
7760 if (prev != NULL) {
7761 /*
7762 * Check the last level of ns-decls for a
7763 * shadowing prefix.
7764 */
7765 prevns = prev->nsDef;
7766 do {
7767 if ((prevns->prefix == ns->prefix) ||
7768 ((prevns->prefix != NULL) &&
7769 (ns->prefix != NULL) &&
7770 xmlStrEqual(prevns->prefix, ns->prefix))) {
7771 /*
7772 * Shadowed.
7773 */
7774 break;
7775 }
7776 prevns = prevns->next;
7777 } while (prevns != NULL);
7778 if (prevns != NULL)
7779 continue;
7780 }
7781 /*
7782 * Ns-name comparison.
7783 */
7784 if ((nsName == ns->href) ||
7785 xmlStrEqual(nsName, ns->href)) {
7786 /*
7787 * At this point the prefix can only be shadowed,
7788 * if we are the the (at least) 3rd level of
7789 * ns-decls.
7790 */
7791 if (out) {
7792 int ret;
7793
7794 ret = xmlNsInScope(doc, node, prev, ns->prefix);
7795 if (ret < 0)
7796 return (-1);
7797 /*
7798 * TODO: Should we try to find a matching ns-name
7799 * only once? This here keeps on searching.
7800 * I think we should try further since, there might
7801 * be an other matching ns-decl with an unshadowed
7802 * prefix.
7803 */
7804 if (! ret)
7805 continue;
7806 }
7807 *retNs = ns;
7808 return (1);
7809 }
7810 }
7811 out = prev;
7812 prev = cur;
7813 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007814 } else if ((cur->type == XML_ENTITY_NODE) ||
7815 (cur->type == XML_ENTITY_DECL))
7816 return (0);
7817 cur = cur->parent;
7818 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
7819 return (0);
7820}
7821
7822/*
7823* xmlSearchNsByPrefixStrict:
7824* @doc: the document
7825* @node: the start node
7826* @prefix: the searched namespace prefix
7827* @retNs: the resulting ns-decl
7828* @prefixed: if the found ns-decl must have a prefix (for attributes)
7829*
7830* Dynamically searches for a ns-declaration which matches
7831* the given @nsName in the ancestor-or-self axis of @node.
7832*
7833* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7834* and internal errors.
7835*/
7836static int
7837xmlSearchNsByPrefixStrict(xmlDocPtr doc, xmlNodePtr node,
7838 const xmlChar* prefix,
7839 xmlNsPtr *retNs)
7840{
7841 xmlNodePtr cur;
7842 xmlNsPtr ns;
7843
7844 if ((doc == NULL) || (node == NULL))
7845 return (-1);
7846
7847 if (retNs)
7848 *retNs = NULL;
7849 if (IS_STR_XML(prefix)) {
7850 if (retNs) {
7851 *retNs = xmlTreeEnsureXMLDecl(doc);
7852 if (*retNs == NULL)
7853 return (-1);
7854 }
7855 return (1);
7856 }
7857 cur = node;
7858 do {
7859 if (cur->type == XML_ELEMENT_NODE) {
7860 if (cur->nsDef != NULL) {
7861 ns = cur->nsDef;
7862 do {
7863 if ((prefix == ns->prefix) ||
7864 xmlStrEqual(prefix, ns->prefix))
7865 {
7866 /*
7867 * Disabled namespaces, e.g. xmlns:abc="".
7868 */
7869 if (ns->href == NULL)
7870 return(0);
7871 if (retNs)
7872 *retNs = ns;
7873 return (1);
7874 }
7875 ns = ns->next;
7876 } while (ns != NULL);
7877 }
7878 } else if ((cur->type == XML_ENTITY_NODE) ||
7879 (cur->type == XML_ENTITY_DECL))
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007880 return (0);
7881 cur = cur->parent;
7882 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
7883 return (0);
7884}
7885
7886/*
7887* xmlDOMWrapNSNormDeclareNsForced:
7888* @doc: the doc
7889* @elem: the element-node to declare on
7890* @nsName: the namespace-name of the ns-decl
7891* @prefix: the preferred prefix of the ns-decl
7892* @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls
7893*
7894* Declares a new namespace on @elem. It tries to use the
7895* given @prefix; if a ns-decl with the given prefix is already existent
7896* on @elem, it will generate an other prefix.
7897*
7898* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7899* and internal errors.
7900*/
7901static xmlNsPtr
7902xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc,
7903 xmlNodePtr elem,
7904 const xmlChar *nsName,
7905 const xmlChar *prefix,
7906 int checkShadow)
7907{
7908
7909 xmlNsPtr ret;
7910 char buf[50];
7911 const xmlChar *pref;
7912 int counter = 0;
7913 /*
7914 * Create a ns-decl on @anchor.
7915 */
7916 pref = prefix;
7917 while (1) {
7918 /*
7919 * Lookup whether the prefix is unused in elem's ns-decls.
7920 */
7921 if ((elem->nsDef != NULL) &&
7922 (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL))
7923 goto ns_next_prefix;
7924 if (checkShadow && elem->parent &&
7925 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
7926 /*
7927 * Does it shadow ancestor ns-decls?
7928 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007929 if (xmlSearchNsByPrefixStrict(doc, elem->parent, pref, NULL) == 1)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007930 goto ns_next_prefix;
7931 }
7932 ret = xmlNewNs(NULL, nsName, pref);
7933 if (ret == NULL)
7934 return (NULL);
7935 if (elem->nsDef == NULL)
7936 elem->nsDef = ret;
7937 else {
7938 xmlNsPtr ns2 = elem->nsDef;
7939 while (ns2->next != NULL)
7940 ns2 = ns2->next;
7941 ns2->next = ret;
7942 }
7943 return (ret);
7944ns_next_prefix:
7945 counter++;
7946 if (counter > 1000)
7947 return (NULL);
7948 if (prefix == NULL) {
7949 snprintf((char *) buf, sizeof(buf),
7950 "default%d", counter);
7951 } else
7952 snprintf((char *) buf, sizeof(buf),
7953 "%.30s%d", (char *)prefix, counter);
7954 pref = BAD_CAST buf;
7955 }
7956}
7957
7958/*
7959* xmlDOMWrapNSNormAquireNormalizedNs:
7960* @doc: the doc
7961* @elem: the element-node to declare namespaces on
7962* @ns: the ns-struct to use for the search
7963* @retNs: the found/created ns-struct
7964* @nsMap: the ns-map
7965* @topmi: the last ns-map entry
7966* @depth: the current tree depth
7967* @ancestorsOnly: search in ancestor ns-decls only
7968* @prefixed: if the searched ns-decl must have a prefix (for attributes)
7969*
7970* Searches for a matching ns-name in the ns-decls of @nsMap, if not
7971* found it will either declare it on @elem, or store it in doc->oldNs.
7972* If a new ns-decl needs to be declared on @elem, it tries to use the
7973* @ns->prefix for it, if this prefix is already in use on @elem, it will
7974* change the prefix or the new ns-decl.
7975*
7976* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
7977*/
7978static int
7979xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc,
7980 xmlNodePtr elem,
7981 xmlNsPtr ns,
7982 xmlNsPtr *retNs,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007983 xmlNsMapPtr *nsMap,
7984
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007985 int depth,
7986 int ancestorsOnly,
7987 int prefixed)
7988{
7989 xmlNsMapItemPtr mi;
7990
7991 if ((doc == NULL) || (ns == NULL) || (retNs == NULL) ||
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007992 (nsMap == NULL))
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007993 return (-1);
7994
7995 *retNs = NULL;
7996 /*
7997 * Handle XML namespace.
7998 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007999 if (IS_STR_XML(ns->prefix)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008000 /*
8001 * Insert XML namespace mapping.
8002 */
8003 *retNs = xmlTreeEnsureXMLDecl(doc);
8004 if (*retNs == NULL)
8005 return (-1);
8006 return (0);
8007 }
8008 /*
8009 * If the search should be done in ancestors only and no
8010 * @elem (the first ancestor) was specified, then skip the search.
8011 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008012 if ((! (ancestorsOnly && (elem == NULL))) && (XML_NSMAP_NOTEMPTY(*nsMap)))
8013 {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008014 /*
8015 * Try to find an equal ns-name in in-scope ns-decls.
8016 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008017 XML_NSMAP_FOREACH(*nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008018 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8019 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008020 * ancestorsOnly: This should be turned on to gain speed,
8021 * if one knows that the branch itself was already
8022 * ns-wellformed and no stale references existed.
8023 * I.e. it searches in the ancestor axis only.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008024 */
8025 ((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) &&
8026 /* Skip shadowed prefixes. */
8027 (mi->shadowDepth == -1) &&
8028 /* Skip xmlns="" or xmlns:foo="". */
8029 ((mi->newNs->href != NULL) &&
8030 (mi->newNs->href[0] != 0)) &&
8031 /* Ensure a prefix if wanted. */
8032 ((! prefixed) || (mi->newNs->prefix != NULL)) &&
8033 /* Equal ns name */
8034 ((mi->newNs->href == ns->href) ||
8035 xmlStrEqual(mi->newNs->href, ns->href))) {
8036 /* Set the mapping. */
8037 mi->oldNs = ns;
8038 *retNs = mi->newNs;
8039 return (0);
8040 }
8041 }
8042 }
8043 /*
8044 * No luck, the namespace is out of scope or shadowed.
8045 */
8046 if (elem == NULL) {
8047 xmlNsPtr tmpns;
8048
8049 /*
8050 * Store ns-decls in "oldNs" of the document-node.
8051 */
8052 tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix);
8053 if (tmpns == NULL)
8054 return (-1);
8055 /*
8056 * Insert mapping.
8057 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008058 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008059 tmpns, XML_TREE_NSMAP_DOC) == NULL) {
8060 xmlFreeNs(tmpns);
8061 return (-1);
8062 }
8063 *retNs = tmpns;
8064 } else {
8065 xmlNsPtr tmpns;
8066
8067 tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href,
8068 ns->prefix, 0);
8069 if (tmpns == NULL)
8070 return (-1);
8071
8072 if (*nsMap != NULL) {
8073 /*
8074 * Does it shadow ancestor ns-decls?
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008075 */
8076 XML_NSMAP_FOREACH(*nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008077 if ((mi->depth < depth) &&
8078 (mi->shadowDepth == -1) &&
8079 ((ns->prefix == mi->newNs->prefix) ||
8080 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8081 /*
8082 * Shadows.
8083 */
8084 mi->shadowDepth = depth;
8085 break;
8086 }
8087 }
8088 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008089 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, depth) == NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008090 xmlFreeNs(tmpns);
8091 return (-1);
8092 }
8093 *retNs = tmpns;
8094 }
8095 return (0);
8096}
8097
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008098typedef enum {
8099 XML_DOM_RECONNS_REMOVEREDUND = 1<<0
8100} xmlDOMReconcileNSOptions;
8101
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008102/*
8103* xmlDOMWrapReconcileNamespaces:
Daniel Veillard304e78c2005-07-03 16:19:41 +00008104* @ctxt: DOM wrapper context, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008105* @elem: the element-node
8106* @options: option flags
8107*
8108* Ensures that ns-references point to ns-decls hold on element-nodes.
8109* Ensures that the tree is namespace wellformed by creating additional
8110* ns-decls where needed. Note that, since prefixes of already existent
8111* ns-decls can be shadowed by this process, it could break QNames in
8112* attribute values or element content.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00008113* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008114*
8115* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008116*/
8117
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008118int
8119xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,
8120 xmlNodePtr elem,
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008121 int options)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008122{
8123 int depth = -1, adoptns = 0, parnsdone = 0;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008124 xmlNsPtr ns, prevns;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008125 xmlDocPtr doc;
8126 xmlNodePtr cur, curElem = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008127 xmlNsMapPtr nsMap = NULL;
8128 xmlNsMapItemPtr /* topmi = NULL, */ mi;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008129 /* @ancestorsOnly should be set by an option flag. */
8130 int ancestorsOnly = 0;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008131 int optRemoveDedundantNS =
8132 ((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0;
8133 xmlNsPtr *listRedund = NULL;
8134 int sizeRedund = 0, nbRedund = 0, ret, i, j;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008135
8136 if ((elem == NULL) || (elem->doc == NULL) ||
8137 (elem->type != XML_ELEMENT_NODE))
8138 return (-1);
8139
8140 doc = elem->doc;
8141 cur = elem;
8142 do {
8143 switch (cur->type) {
8144 case XML_ELEMENT_NODE:
8145 adoptns = 1;
8146 curElem = cur;
8147 depth++;
8148 /*
8149 * Namespace declarations.
8150 */
8151 if (cur->nsDef != NULL) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008152 prevns = NULL;
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008153 ns = cur->nsDef;
8154 while (ns != NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008155 if (! parnsdone) {
8156 if ((elem->parent) &&
8157 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8158 /*
8159 * Gather ancestor in-scope ns-decls.
8160 */
8161 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8162 elem->parent) == -1)
8163 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008164 }
8165 parnsdone = 1;
8166 }
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008167
8168 /*
8169 * Lookup the ns ancestor-axis for equal ns-decls in scope.
8170 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008171 if (optRemoveDedundantNS && XML_NSMAP_NOTEMPTY(nsMap)) {
8172 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008173 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8174 (mi->shadowDepth == -1) &&
8175 ((ns->prefix == mi->newNs->prefix) ||
8176 xmlStrEqual(ns->prefix, mi->newNs->prefix)) &&
8177 ((ns->href == mi->newNs->href) ||
8178 xmlStrEqual(ns->href, mi->newNs->href)))
8179 {
8180 /*
8181 * A redundant ns-decl was found.
8182 * Add it to the list of redundant ns-decls.
8183 */
8184 if (xmlDOMWrapNSNormAddNsMapItem2(&listRedund,
8185 &sizeRedund, &nbRedund, ns, mi->newNs) == -1)
8186 goto internal_error;
8187 /*
8188 * Remove the ns-decl from the element-node.
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008189 */
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008190 if (prevns)
8191 prevns->next = ns->next;
8192 else
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008193 cur->nsDef = ns->next;
8194 goto next_ns_decl;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008195 }
8196 }
8197 }
8198
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008199 /*
8200 * Skip ns-references handling if the referenced
8201 * ns-decl is declared on the same element.
8202 */
8203 if ((cur->ns != NULL) && adoptns && (cur->ns == ns))
8204 adoptns = 0;
8205 /*
8206 * Does it shadow any ns-decl?
8207 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008208 if (XML_NSMAP_NOTEMPTY(nsMap)) {
8209 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008210 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8211 (mi->shadowDepth == -1) &&
8212 ((ns->prefix == mi->newNs->prefix) ||
8213 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8214
8215 mi->shadowDepth = depth;
8216 }
8217 }
8218 }
8219 /*
8220 * Push mapping.
8221 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008222 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008223 depth) == NULL)
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008224 goto internal_error;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008225
8226 prevns = ns;
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008227next_ns_decl:
8228 ns = ns->next;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008229 }
8230 }
8231 if (! adoptns)
8232 goto ns_end;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008233 /* No break on purpose. */
8234 case XML_ATTRIBUTE_NODE:
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008235 /* No ns, no fun. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008236 if (cur->ns == NULL)
8237 goto ns_end;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008238
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008239 if (! parnsdone) {
8240 if ((elem->parent) &&
8241 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8242 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8243 elem->parent) == -1)
8244 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008245 }
8246 parnsdone = 1;
8247 }
8248 /*
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008249 * Adjust the reference if this was a redundant ns-decl.
8250 */
8251 if (listRedund) {
8252 for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8253 if (cur->ns == listRedund[j]) {
8254 cur->ns = listRedund[++j];
8255 break;
8256 }
8257 }
8258 }
8259 /*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008260 * Adopt ns-references.
8261 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008262 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008263 /*
8264 * Search for a mapping.
8265 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008266 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008267 if ((mi->shadowDepth == -1) &&
8268 (cur->ns == mi->oldNs)) {
8269
8270 cur->ns = mi->newNs;
8271 goto ns_end;
8272 }
8273 }
8274 }
8275 /*
8276 * Aquire a normalized ns-decl and add it to the map.
8277 */
8278 if (xmlDOMWrapNSNormAquireNormalizedNs(doc, curElem,
8279 cur->ns, &ns,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008280 &nsMap, depth,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008281 ancestorsOnly,
8282 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8283 goto internal_error;
8284 cur->ns = ns;
8285
8286ns_end:
8287 if ((cur->type == XML_ELEMENT_NODE) &&
8288 (cur->properties != NULL)) {
8289 /*
8290 * Process attributes.
8291 */
8292 cur = (xmlNodePtr) cur->properties;
8293 continue;
8294 }
8295 break;
8296 default:
8297 goto next_sibling;
8298 }
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008299into_content:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008300 if ((cur->type == XML_ELEMENT_NODE) &&
8301 (cur->children != NULL)) {
8302 /*
8303 * Process content of element-nodes only.
8304 */
8305 cur = cur->children;
8306 continue;
8307 }
8308next_sibling:
8309 if (cur == elem)
8310 break;
8311 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008312 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008313 /*
8314 * Pop mappings.
8315 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008316 while ((nsMap->last != NULL) &&
8317 (nsMap->last->depth >= depth))
8318 {
8319 XML_NSMAP_POP(nsMap, mi)
8320 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008321 /*
8322 * Unshadow.
8323 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008324 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008325 if (mi->shadowDepth >= depth)
8326 mi->shadowDepth = -1;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008327 }
8328 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008329 depth--;
8330 }
8331 if (cur->next != NULL)
8332 cur = cur->next;
8333 else {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008334 if (cur->type == XML_ATTRIBUTE_NODE) {
8335 cur = cur->parent;
8336 goto into_content;
8337 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008338 cur = cur->parent;
8339 goto next_sibling;
8340 }
8341 } while (cur != NULL);
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008342
8343 ret = 0;
8344 goto exit;
8345internal_error:
8346 ret = -1;
8347exit:
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008348 if (listRedund) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008349 for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8350 xmlFreeNs(listRedund[j]);
8351 }
8352 xmlFree(listRedund);
8353 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008354 if (nsMap != NULL)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008355 xmlDOMWrapNsMapFree(nsMap);
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008356 return (ret);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008357}
8358
8359/*
8360* xmlDOMWrapAdoptBranch:
8361* @ctxt: the optional context for custom processing
8362* @sourceDoc: the optional sourceDoc
8363* @node: the element-node to start with
8364* @destDoc: the destination doc for adoption
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008365* @destParent: the optional new parent of @node in @destDoc
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008366* @options: option flags
8367*
8368* Ensures that ns-references point to @destDoc: either to
8369* elements->nsDef entries if @destParent is given, or to
8370* @destDoc->oldNs otherwise.
8371* If @destParent is given, it ensures that the tree is namespace
8372* wellformed by creating additional ns-decls where needed.
8373* Note that, since prefixes of already existent ns-decls can be
8374* shadowed by this process, it could break QNames in attribute
8375* values or element content.
8376*
8377* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8378*/
8379static int
8380xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
8381 xmlDocPtr sourceDoc,
8382 xmlNodePtr node,
8383 xmlDocPtr destDoc,
8384 xmlNodePtr destParent,
8385 int options ATTRIBUTE_UNUSED)
8386{
8387 int ret = 0;
8388 xmlNodePtr cur, curElem = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008389 xmlNsMapPtr nsMap = NULL;
8390 xmlNsMapItemPtr mi;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008391 xmlNsPtr ns = NULL;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008392 int depth = -1, adoptStr = 1;
8393 /* gather @parent's ns-decls. */
8394 int parnsdone = 0;
8395 /* @ancestorsOnly should be set per option. */
8396 int ancestorsOnly = 0;
8397
8398 /*
8399 * Optimize string adoption for equal or none dicts.
8400 */
8401 if ((sourceDoc != NULL) &&
8402 (sourceDoc->dict == destDoc->dict))
8403 adoptStr = 0;
8404 else
8405 adoptStr = 1;
8406
8407 cur = node;
8408 while (cur != NULL) {
8409 if (cur->doc != sourceDoc) {
8410 /*
8411 * We'll assume XIncluded nodes if the doc differs.
8412 * TODO: Do we need to reconciliate XIncluded nodes?
8413 * This here skips XIncluded nodes and tries to handle
8414 * broken sequences.
8415 */
8416 if (cur->next == NULL)
8417 goto leave_node;
8418 do {
8419 cur = cur->next;
8420 if ((cur->type == XML_XINCLUDE_END) ||
8421 (cur->doc == node->doc))
8422 break;
8423 } while (cur->next != NULL);
8424
8425 if (cur->doc != node->doc)
8426 goto leave_node;
8427 }
8428 cur->doc = destDoc;
8429 switch (cur->type) {
8430 case XML_XINCLUDE_START:
8431 case XML_XINCLUDE_END:
8432 /*
8433 * TODO
8434 */
8435 return (-1);
8436 case XML_ELEMENT_NODE:
8437 curElem = cur;
8438 depth++;
8439 /*
8440 * Namespace declarations.
8441 */
8442 if ((ctxt == NULL) && (cur->nsDef != NULL)) {
8443 if (! parnsdone) {
8444 if (destParent && (ctxt == NULL)) {
8445 /*
8446 * Gather @parent's in-scope ns-decls.
8447 */
8448 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8449 destParent) == -1)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008450 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008451 }
8452 parnsdone = 1;
8453 }
8454 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8455 /*
8456 * ns->prefix and ns->href seem not to be in the dict.
8457 * XML_TREE_ADOPT_STR(ns->prefix)
8458 * XML_TREE_ADOPT_STR(ns->href)
8459 */
8460 /*
8461 * Does it shadow any ns-decl?
8462 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008463 if (XML_NSMAP_NOTEMPTY(nsMap)) {
8464 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008465 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8466 (mi->shadowDepth == -1) &&
8467 ((ns->prefix == mi->newNs->prefix) ||
8468 xmlStrEqual(ns->prefix,
8469 mi->newNs->prefix))) {
8470
8471 mi->shadowDepth = depth;
8472 }
8473 }
8474 }
8475 /*
8476 * Push mapping.
8477 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008478 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008479 ns, ns, depth) == NULL)
8480 goto internal_error;
8481 }
8482 }
8483 /* No break on purpose. */
8484 case XML_ATTRIBUTE_NODE:
8485
8486 if (cur->ns == NULL)
8487 goto ns_end;
8488 if (! parnsdone) {
8489 if (destParent && (ctxt == NULL)) {
8490 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8491 destParent) == -1)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008492 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008493 }
8494 parnsdone = 1;
8495 }
8496 /*
8497 * Adopt ns-references.
8498 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008499 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008500 /*
8501 * Search for a mapping.
8502 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008503 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008504 if ((mi->shadowDepth == -1) &&
8505 (cur->ns == mi->oldNs)) {
8506
8507 cur->ns = mi->newNs;
8508 goto ns_end;
8509 }
8510 }
8511 }
8512 /*
8513 * Start searching for an in-scope ns-decl.
8514 */
8515 if (ctxt != NULL) {
8516 /*
8517 * User-defined behaviour.
8518 */
8519#if 0
8520 ctxt->aquireNsDecl(ctxt, cur->ns, &ns);
8521#endif
8522 /*
8523 * Insert mapping if ns is available; it's the users fault
8524 * if not.
8525 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008526 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008527 ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
8528 goto internal_error;
8529 cur->ns = ns;
8530 } else {
8531 /*
8532 * Aquire a normalized ns-decl and add it to the map.
8533 */
8534 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
8535 /* ns-decls on curElem or on destDoc->oldNs */
8536 destParent ? curElem : NULL,
8537 cur->ns, &ns,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008538 &nsMap, depth,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008539 ancestorsOnly,
8540 /* ns-decls must be prefixed for attributes. */
8541 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8542 goto internal_error;
8543 cur->ns = ns;
8544 }
8545ns_end:
8546 /*
8547 * Further node properties.
8548 * TODO: Is this all?
8549 */
8550 XML_TREE_ADOPT_STR(cur->name)
8551 if (cur->type == XML_ELEMENT_NODE) {
8552 cur->psvi = NULL;
8553 cur->line = 0;
8554 cur->extra = 0;
8555 /*
8556 * Walk attributes.
8557 */
8558 if (cur->properties != NULL) {
8559 /*
8560 * Process first attribute node.
8561 */
8562 cur = (xmlNodePtr) cur->properties;
8563 continue;
8564 }
8565 } else {
8566 /*
8567 * Attributes.
8568 */
8569 if ((sourceDoc != NULL) &&
8570 (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID))
8571 xmlRemoveID(sourceDoc, (xmlAttrPtr) cur);
8572 ((xmlAttrPtr) cur)->atype = 0;
8573 ((xmlAttrPtr) cur)->psvi = NULL;
8574 }
8575 break;
8576 case XML_TEXT_NODE:
8577 case XML_CDATA_SECTION_NODE:
8578 /*
8579 * This puts the content in the dest dict, only if
8580 * it was previously in the source dict.
8581 */
8582 XML_TREE_ADOPT_STR_2(cur->content)
8583 goto leave_node;
8584 case XML_ENTITY_REF_NODE:
8585 /*
8586 * Remove reference to the entitity-node.
8587 */
8588 cur->content = NULL;
8589 cur->children = NULL;
8590 cur->last = NULL;
8591 if ((destDoc->intSubset) || (destDoc->extSubset)) {
8592 xmlEntityPtr ent;
8593 /*
8594 * Assign new entity-node if available.
8595 */
8596 ent = xmlGetDocEntity(destDoc, cur->name);
8597 if (ent != NULL) {
8598 cur->content = ent->content;
8599 cur->children = (xmlNodePtr) ent;
8600 cur->last = (xmlNodePtr) ent;
8601 }
8602 }
8603 goto leave_node;
8604 case XML_PI_NODE:
8605 XML_TREE_ADOPT_STR(cur->name)
8606 XML_TREE_ADOPT_STR_2(cur->content)
8607 break;
8608 case XML_COMMENT_NODE:
8609 break;
8610 default:
8611 goto internal_error;
8612 }
8613 /*
8614 * Walk the tree.
8615 */
8616 if (cur->children != NULL) {
8617 cur = cur->children;
8618 continue;
8619 }
8620
8621leave_node:
8622 if (cur == node)
8623 break;
8624 if ((cur->type == XML_ELEMENT_NODE) ||
8625 (cur->type == XML_XINCLUDE_START) ||
8626 (cur->type == XML_XINCLUDE_END)) {
8627 /*
8628 * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
8629 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008630 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008631 /*
8632 * Pop mappings.
8633 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008634 while ((nsMap->last != NULL) &&
8635 (nsMap->last->depth >= depth))
8636 {
8637 XML_NSMAP_POP(nsMap, mi)
8638 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008639 /*
8640 * Unshadow.
8641 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008642 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008643 if (mi->shadowDepth >= depth)
8644 mi->shadowDepth = -1;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008645 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008646 }
8647 depth--;
8648 }
8649 if (cur->next != NULL)
8650 cur = cur->next;
8651 else {
8652 cur = cur->parent;
8653 goto leave_node;
8654 }
8655 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008656
8657 goto exit;
8658
8659internal_error:
8660 ret = -1;
8661
8662exit:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008663 /*
8664 * Cleanup.
8665 */
8666 if (nsMap != NULL)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008667 xmlDOMWrapNsMapFree(nsMap);
8668 return(ret);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008669}
8670
8671/*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008672* xmlDOMWrapCloneNode:
8673* @ctxt: the optional context for custom processing
8674* @sourceDoc: the optional sourceDoc
8675* @node: the node to start with
8676* @resNode: the clone of the given @node
8677* @destDoc: the destination doc
8678* @destParent: the optional new parent of @node in @destDoc
Daniel Veillardb2f8f1d2006-04-28 16:30:48 +00008679* @deep: descend into child if set
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008680* @options: option flags
8681*
8682* References of out-of scope ns-decls are remapped to point to @destDoc:
8683* 1) If @destParent is given, then nsDef entries on element-nodes are used
8684* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used
8685* This is the case when you have an unliked node and just want to move it
8686* to the context of
8687*
8688* If @destParent is given, it ensures that the tree is namespace
8689* wellformed by creating additional ns-decls where needed.
8690* Note that, since prefixes of already existent ns-decls can be
8691* shadowed by this process, it could break QNames in attribute
8692* values or element content.
8693* TODO:
8694* 1) Support dicts
8695* Optimize string adoption for equal or none dicts.
8696* 2) XInclude
8697* WARNING: This function is in a experimental state and should only be currently
8698* only be used to test it.
8699*
8700* Returns 0 if the operation succeeded,
8701* 1 if a node of unsupported (or not yet supported) type was given,
8702* -1 on API/internal errors.
8703*/
8704
8705int
8706xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt,
8707 xmlDocPtr sourceDoc,
8708 xmlNodePtr node,
8709 xmlNodePtr *resNode,
8710 xmlDocPtr destDoc,
8711 xmlNodePtr destParent,
8712 int deep,
8713 int options ATTRIBUTE_UNUSED)
8714{
8715 int ret = 0;
8716 xmlNodePtr cur, curElem = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008717 xmlNsMapPtr nsMap = NULL;
8718 xmlNsMapItemPtr mi;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008719 xmlNsPtr ns;
8720 int depth = -1;
8721 /* int adoptStr = 1; */
8722 /* gather @parent's ns-decls. */
8723 int parnsdone = 0;
8724 /* @ancestorsOnly should be set per option. */
8725 int ancestorsOnly = 0;
8726 xmlNodePtr resultClone = NULL, clone = NULL, parentClone = NULL, prevClone = NULL;
8727 xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008728
Daniel Veillard11ce4002006-03-10 00:36:23 +00008729 if ((node == NULL) || (resNode == NULL) || (destDoc == NULL))
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008730 return(-1);
8731 /*
8732 * TODO: Initially we support only element-nodes.
8733 */
8734 if (node->type != XML_ELEMENT_NODE)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008735 return(1);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008736 /*
8737 * Check node->doc sanity.
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008738 */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008739 if ((node->doc != NULL) && (sourceDoc != NULL) &&
8740 (node->doc != sourceDoc)) {
8741 /*
8742 * Might be an XIncluded node.
8743 */
8744 return (-1);
8745 }
8746 if (sourceDoc == NULL)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008747 sourceDoc = node->doc;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008748 if (sourceDoc == NULL)
8749 return (-1);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008750
8751 *resNode = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008752
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008753 cur = node;
8754 while (cur != NULL) {
8755 if (cur->doc != sourceDoc) {
8756 /*
8757 * We'll assume XIncluded nodes if the doc differs.
8758 * TODO: Do we need to reconciliate XIncluded nodes?
8759 * TODO: This here returns -1 in this case.
8760 */
8761 goto internal_error;
8762 }
8763 /*
8764 * Create a new node.
8765 */
8766 switch (cur->type) {
8767 case XML_XINCLUDE_START:
8768 case XML_XINCLUDE_END:
8769 /* TODO: What to do with XInclude? */
8770 goto internal_error;
8771 break;
8772 case XML_TEXT_NODE:
8773 case XML_CDATA_SECTION_NODE:
8774 case XML_ELEMENT_NODE:
8775 case XML_DOCUMENT_FRAG_NODE:
8776 case XML_ENTITY_REF_NODE:
8777 case XML_ENTITY_NODE:
8778 case XML_PI_NODE:
8779 case XML_COMMENT_NODE:
8780 /*
8781 * Nodes of xmlNode structure.
8782 */
8783 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
8784 if (clone == NULL) {
8785 xmlTreeErrMemory("xmlDOMWrapCloneBranch(): allocating a node");
8786 goto internal_error;
8787 }
8788 memset(clone, 0, sizeof(xmlNode));
8789 /*
8790 * Set hierachical links.
8791 */
8792 if (resultClone != NULL) {
8793 clone->parent = parentClone;
8794 if (prevClone) {
8795 prevClone->next = clone;
8796 clone->prev = prevClone;
8797 } else
8798 parentClone->children = clone;
8799 } else
8800 resultClone = clone;
8801
8802 break;
8803 case XML_ATTRIBUTE_NODE:
8804 /*
8805 * Attributes (xmlAttr).
8806 */
8807 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlAttr));
8808 if (clone == NULL) {
8809 xmlTreeErrMemory("xmlDOMWrapCloneBranch(): allocating an attr-node");
8810 goto internal_error;
8811 }
8812 memset(clone, 0, sizeof(xmlAttr));
8813 /*
8814 * Set hierachical links.
8815 */
8816 if (resultClone != NULL) {
8817 clone->parent = parentClone;
8818 if (prevClone) {
8819 prevClone->next = clone;
8820 clone->prev = prevClone;
8821 } else
8822 parentClone->properties = (xmlAttrPtr) clone;
8823 } else
8824 resultClone = clone;
8825 break;
8826 default:
8827 /* TODO */
8828 goto internal_error;
8829 }
8830
8831 clone->type = cur->type;
8832 clone->doc = destDoc;
8833
8834 if (cur->name == xmlStringText)
8835 clone->name = xmlStringText;
8836 else if (cur->name == xmlStringTextNoenc)
8837 /*
8838 * TODO: xmlStringTextNoenc is never assigned to a node
8839 * in tree.c.
8840 */
8841 clone->name = xmlStringTextNoenc;
8842 else if (cur->name == xmlStringComment)
8843 clone->name = xmlStringComment;
8844 else if (cur->name != NULL) {
8845 if ((destDoc != NULL) && (destDoc->dict != NULL))
8846 clone->name = xmlDictLookup(destDoc->dict, cur->name, -1);
8847 else
8848 clone->name = xmlStrdup(cur->name);
8849 }
8850
8851 switch (cur->type) {
8852 case XML_XINCLUDE_START:
8853 case XML_XINCLUDE_END:
8854 /*
8855 * TODO
8856 */
8857 return (-1);
8858 case XML_ELEMENT_NODE:
8859 curElem = cur;
8860 depth++;
8861 /*
8862 * Namespace declarations.
8863 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008864 if (cur->nsDef != NULL) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008865 if (! parnsdone) {
8866 if (destParent && (ctxt == NULL)) {
8867 /*
8868 * Gather @parent's in-scope ns-decls.
8869 */
8870 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8871 destParent) == -1)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008872 goto internal_error;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008873 }
8874 parnsdone = 1;
8875 }
8876 /*
8877 * Clone namespace declarations.
8878 */
8879 cloneNsDefSlot = &(clone->nsDef);
8880 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8881 /*
8882 * Create a new xmlNs.
8883 */
8884 cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
8885 if (cloneNs == NULL) {
8886 xmlTreeErrMemory("xmlDOMWrapCloneBranch(): "
8887 "allocating namespace");
8888 return(-1);
8889 }
8890 memset(cloneNs, 0, sizeof(xmlNs));
8891 cloneNs->type = XML_LOCAL_NAMESPACE;
8892
8893 if (ns->href != NULL)
8894 cloneNs->href = xmlStrdup(ns->href);
8895 if (ns->prefix != NULL)
8896 cloneNs->prefix = xmlStrdup(ns->prefix);
8897
8898 *cloneNsDefSlot = cloneNs;
8899 cloneNsDefSlot = &(cloneNs->next);
8900
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008901 if (ctxt == NULL) {
8902 /*
8903 * Does it shadow any ns-decl?
8904 */
8905 if (XML_NSMAP_NOTEMPTY(nsMap)) {
8906 XML_NSMAP_FOREACH(nsMap, mi) {
8907 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8908 (mi->shadowDepth == -1) &&
8909 ((ns->prefix == mi->newNs->prefix) ||
8910 xmlStrEqual(ns->prefix,
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008911 mi->newNs->prefix))) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008912 /*
8913 * Mark as shadowed at the current
8914 * depth.
8915 */
8916 mi->shadowDepth = depth;
8917 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008918 }
8919 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008920 /*
8921 * Push mapping.
8922 */
8923 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
8924 ns, cloneNs, depth) == NULL)
8925 goto internal_error;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008926 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008927 }
8928 }
8929 /* cur->ns will be processed further down. */
8930 break;
8931 case XML_ATTRIBUTE_NODE:
8932 /* IDs will be processed further down. */
8933 /* cur->ns will be processed further down. */
8934 break;
8935 case XML_TEXT_NODE:
8936 case XML_CDATA_SECTION_NODE:
8937 if (cur->content)
8938 clone->content = xmlStrdup(cur->content);
8939 goto leave_node;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008940 case XML_ENTITY_NODE:
8941 /* TODO: What to do here? */
8942 goto leave_node;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008943 case XML_ENTITY_REF_NODE:
8944 if (sourceDoc != destDoc) {
8945 if ((destDoc->intSubset) || (destDoc->extSubset)) {
8946 xmlEntityPtr ent;
8947 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008948 * Different doc: Assign new entity-node if available.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008949 */
8950 ent = xmlGetDocEntity(destDoc, cur->name);
8951 if (ent != NULL) {
8952 clone->content = ent->content;
8953 clone->children = (xmlNodePtr) ent;
8954 clone->last = (xmlNodePtr) ent;
8955 }
8956 }
8957 } else {
8958 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008959 * Same doc: Use the current node's entity declaration
8960 * and value.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008961 */
8962 clone->content = cur->content;
8963 clone->children = cur->children;
8964 clone->last = cur->last;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008965 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008966 goto leave_node;
8967 case XML_PI_NODE:
8968 if (cur->content)
8969 clone->content = xmlStrdup(cur->content);
8970 goto leave_node;
8971 case XML_COMMENT_NODE:
8972 if (cur->content)
8973 clone->content = xmlStrdup(cur->content);
8974 goto leave_node;
8975 default:
8976 goto internal_error;
8977 }
8978
8979 if (cur->ns == NULL)
8980 goto end_ns_reference;
8981
8982/* handle_ns_reference: */
8983 /*
8984 ** The following will take care of references to ns-decls ********
8985 ** and is intended only for element- and attribute-nodes.
8986 **
8987 */
8988 if (! parnsdone) {
8989 if (destParent && (ctxt == NULL)) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008990 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1)
8991 goto internal_error;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008992 }
8993 parnsdone = 1;
8994 }
8995 /*
8996 * Adopt ns-references.
8997 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008998 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008999 /*
9000 * Search for a mapping.
9001 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009002 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009003 if ((mi->shadowDepth == -1) &&
9004 (cur->ns == mi->oldNs)) {
9005 /*
9006 * This is the nice case: a mapping was found.
9007 */
9008 clone->ns = mi->newNs;
9009 goto end_ns_reference;
9010 }
9011 }
9012 }
9013 /*
9014 * Start searching for an in-scope ns-decl.
9015 */
9016 if (ctxt != NULL) {
9017 /*
9018 * User-defined behaviour.
9019 */
9020#if 0
9021 ctxt->aquireNsDecl(ctxt, cur->ns, &ns);
9022#endif
9023 /*
9024 * Add user's mapping.
9025 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009026 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009027 cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
9028 goto internal_error;
9029 clone->ns = ns;
9030 } else {
9031 /*
9032 * Aquire a normalized ns-decl and add it to the map.
9033 */
9034 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
9035 /* ns-decls on curElem or on destDoc->oldNs */
9036 destParent ? curElem : NULL,
9037 cur->ns, &ns,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009038 &nsMap, depth,
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009039 ancestorsOnly,
9040 /* ns-decls must be prefixed for attributes. */
9041 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
9042 goto internal_error;
9043 clone->ns = ns;
9044 }
9045
9046end_ns_reference:
9047
9048 /*
9049 * Some post-processing.
9050 *
9051 * Handle ID attributes.
9052 */
9053 if ((clone->type == XML_ATTRIBUTE_NODE) &&
9054 (clone->parent != NULL)) {
9055 if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) {
9056
9057 xmlChar *idVal;
9058
9059 idVal = xmlNodeListGetString(cur->doc, cur->children, 1);
9060 if (idVal != NULL) {
9061 if (xmlAddID(NULL, destDoc, idVal, (xmlAttrPtr) cur) == NULL) {
9062 /* TODO: error message. */
9063 xmlFree(idVal);
9064 goto internal_error;
9065 }
9066 xmlFree(idVal);
9067 }
9068 }
9069 }
9070 /*
9071 **
9072 ** The following will traversing the tree ************************
9073 **
9074 *
9075 * Walk the element's attributes before descending into child-nodes.
9076 */
9077 if ((cur->type == XML_ELEMENT_NODE) && (cur->properties != NULL)) {
9078 prevClone = NULL;
9079 parentClone = clone;
9080 cur = (xmlNodePtr) cur->properties;
9081 continue;
9082 }
9083into_content:
9084 /*
9085 * Descend into child-nodes.
9086 */
9087 if (cur->children != NULL) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009088 if (deep || (cur->type == XML_ATTRIBUTE_NODE)) {
9089 prevClone = NULL;
9090 parentClone = clone;
9091 cur = cur->children;
9092 continue;
9093 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009094 }
9095
9096leave_node:
9097 /*
9098 * At this point we are done with the node, its content
9099 * and an element-nodes's attribute-nodes.
9100 */
9101 if (cur == node)
9102 break;
9103 if ((cur->type == XML_ELEMENT_NODE) ||
9104 (cur->type == XML_XINCLUDE_START) ||
9105 (cur->type == XML_XINCLUDE_END)) {
9106 /*
9107 * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
9108 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009109 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009110 /*
9111 * Pop mappings.
9112 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009113 while ((nsMap->last != NULL) &&
9114 (nsMap->last->depth >= depth))
9115 {
9116 XML_NSMAP_POP(nsMap, mi)
9117 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009118 /*
9119 * Unshadow.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009120 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009121 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009122 if (mi->shadowDepth >= depth)
9123 mi->shadowDepth = -1;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009124 }
9125 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009126 depth--;
9127 }
9128 if (cur->next != NULL) {
9129 prevClone = clone;
9130 cur = cur->next;
9131 } else if (cur->type != XML_ATTRIBUTE_NODE) {
9132 /*
9133 * Set clone->last.
9134 */
Daniel Veillard11ce4002006-03-10 00:36:23 +00009135 if (clone->parent != NULL)
9136 clone->parent->last = clone;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009137 clone = clone->parent;
9138 parentClone = clone->parent;
9139 /*
9140 * Process parent --> next;
9141 */
9142 cur = cur->parent;
9143 goto leave_node;
9144 } else {
9145 /* This is for attributes only. */
9146 clone = clone->parent;
9147 parentClone = clone->parent;
9148 /*
9149 * Process parent-element --> children.
9150 */
9151 cur = cur->parent;
9152 goto into_content;
9153 }
9154 }
9155 goto exit;
9156
9157internal_error:
9158 ret = -1;
9159
9160exit:
9161 /*
9162 * Cleanup.
9163 */
9164 if (nsMap != NULL)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009165 xmlDOMWrapNsMapFree(nsMap);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009166 /*
9167 * TODO: Should we try a cleanup of the cloned node in case of a
9168 * fatal error?
9169 */
9170 *resNode = resultClone;
9171 return (ret);
9172}
9173
9174/*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009175* xmlDOMWrapAdoptAttr:
9176* @ctxt: the optional context for custom processing
9177* @sourceDoc: the optional source document of attr
9178* @attr: the attribute-node to be adopted
9179* @destDoc: the destination doc for adoption
9180* @destParent: the optional new parent of @attr in @destDoc
9181* @options: option flags
9182*
9183* @attr is adopted by @destDoc.
9184* Ensures that ns-references point to @destDoc: either to
9185* elements->nsDef entries if @destParent is given, or to
9186* @destDoc->oldNs otherwise.
9187*
9188* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
9189*/
9190static int
9191xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt,
9192 xmlDocPtr sourceDoc,
9193 xmlAttrPtr attr,
9194 xmlDocPtr destDoc,
9195 xmlNodePtr destParent,
9196 int options ATTRIBUTE_UNUSED)
9197{
9198 xmlNodePtr cur;
9199 int adoptStr = 1;
9200
9201 if ((attr == NULL) || (destDoc == NULL))
9202 return (-1);
9203
9204 attr->doc = destDoc;
9205 if (attr->ns != NULL) {
9206 xmlNsPtr ns = NULL;
9207
9208 if (ctxt != NULL) {
9209 /* TODO: User defined. */
9210 }
9211 /* XML Namespace. */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009212 if (IS_STR_XML(attr->ns->prefix)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009213 ns = xmlTreeEnsureXMLDecl(destDoc);
9214 } else if (destParent == NULL) {
9215 /*
9216 * Store in @destDoc->oldNs.
9217 */
9218 ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix);
9219 } else {
9220 /*
9221 * Declare on @destParent.
9222 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009223 if (xmlSearchNsByNamespaceStrict(destDoc, destParent, attr->ns->href,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009224 &ns, 1) == -1)
9225 goto internal_error;
9226 if (ns == NULL) {
9227 ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent,
9228 attr->ns->href, attr->ns->prefix, 1);
9229 }
9230 }
9231 if (ns == NULL)
9232 goto internal_error;
9233 attr->ns = ns;
9234 }
9235
9236 XML_TREE_ADOPT_STR(attr->name);
9237 attr->atype = 0;
9238 attr->psvi = NULL;
9239 /*
9240 * Walk content.
9241 */
9242 if (attr->children == NULL)
9243 return (0);
9244 cur = attr->children;
9245 while (cur != NULL) {
9246 cur->doc = destDoc;
9247 switch (cur->type) {
9248 case XML_TEXT_NODE:
9249 case XML_CDATA_SECTION_NODE:
9250 XML_TREE_ADOPT_STR_2(cur->content)
9251 break;
9252 case XML_ENTITY_REF_NODE:
9253 /*
9254 * Remove reference to the entitity-node.
9255 */
9256 cur->content = NULL;
9257 cur->children = NULL;
9258 cur->last = NULL;
9259 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9260 xmlEntityPtr ent;
9261 /*
9262 * Assign new entity-node if available.
9263 */
9264 ent = xmlGetDocEntity(destDoc, cur->name);
9265 if (ent != NULL) {
9266 cur->content = ent->content;
9267 cur->children = (xmlNodePtr) ent;
9268 cur->last = (xmlNodePtr) ent;
9269 }
9270 }
9271 break;
9272 default:
9273 break;
9274 }
9275 if (cur->children != NULL) {
9276 cur = cur->children;
9277 continue;
9278 }
9279next_sibling:
9280 if (cur == (xmlNodePtr) attr)
9281 break;
9282 if (cur->next != NULL)
9283 cur = cur->next;
9284 else {
9285 cur = cur->parent;
9286 goto next_sibling;
9287 }
9288 }
9289 return (0);
9290internal_error:
9291 return (-1);
9292}
9293
9294/*
9295* xmlDOMWrapAdoptNode:
9296* @ctxt: the optional context for custom processing
9297* @sourceDoc: the optional sourceDoc
9298* @node: the node to start with
9299* @destDoc: the destination doc
Kasimier T. Buchcik4d9c9482005-06-27 15:04:46 +00009300* @destParent: the optional new parent of @node in @destDoc
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009301* @options: option flags
9302*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009303* References of out-of scope ns-decls are remapped to point to @destDoc:
9304* 1) If @destParent is given, then nsDef entries on element-nodes are used
9305* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used
9306* This is the case when you have an unliked node and just want to move it
9307* to the context of
9308*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009309* If @destParent is given, it ensures that the tree is namespace
9310* wellformed by creating additional ns-decls where needed.
9311* Note that, since prefixes of already existent ns-decls can be
9312* shadowed by this process, it could break QNames in attribute
9313* values or element content.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00009314* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009315*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009316* Returns 0 if the operation succeeded,
9317* 1 if a node of unsupported type was given,
9318* 2 if a node of not yet supported type was given and
9319* -1 on API/internal errors.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009320*/
9321int
9322xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt,
9323 xmlDocPtr sourceDoc,
9324 xmlNodePtr node,
9325 xmlDocPtr destDoc,
9326 xmlNodePtr destParent,
9327 int options)
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009328{
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009329 if ((node == NULL) || (destDoc == NULL) ||
9330 ((destParent != NULL) && (destParent->doc != destDoc)))
9331 return(-1);
9332 /*
9333 * Check node->doc sanity.
9334 */
9335 if ((node->doc != NULL) && (sourceDoc != NULL) &&
9336 (node->doc != sourceDoc)) {
9337 /*
9338 * Might be an XIncluded node.
9339 */
9340 return (-1);
9341 }
9342 if (sourceDoc == NULL)
9343 sourceDoc = node->doc;
9344 if (sourceDoc == destDoc)
9345 return (-1);
9346 switch (node->type) {
9347 case XML_ELEMENT_NODE:
9348 case XML_ATTRIBUTE_NODE:
9349 case XML_TEXT_NODE:
9350 case XML_CDATA_SECTION_NODE:
9351 case XML_ENTITY_REF_NODE:
9352 case XML_PI_NODE:
9353 case XML_COMMENT_NODE:
9354 break;
9355 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009356 /* TODO: Support document-fragment-nodes. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009357 return (2);
9358 default:
9359 return (1);
9360 }
9361 /*
9362 * Unlink only if @node was not already added to @destParent.
9363 */
9364 if ((node->parent != NULL) && (destParent != node->parent))
9365 xmlUnlinkNode(node);
9366
9367 if (node->type == XML_ELEMENT_NODE) {
9368 return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node,
9369 destDoc, destParent, options));
9370 } else if (node->type == XML_ATTRIBUTE_NODE) {
9371 return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc,
9372 (xmlAttrPtr) node, destDoc, destParent, options));
9373 } else {
9374 xmlNodePtr cur = node;
9375 int adoptStr = 1;
9376
9377 cur->doc = destDoc;
9378 /*
9379 * Optimize string adoption.
9380 */
9381 if ((sourceDoc != NULL) &&
9382 (sourceDoc->dict == destDoc->dict))
9383 adoptStr = 0;
9384 switch (node->type) {
9385 case XML_TEXT_NODE:
9386 case XML_CDATA_SECTION_NODE:
9387 XML_TREE_ADOPT_STR_2(node->content)
9388 break;
9389 case XML_ENTITY_REF_NODE:
9390 /*
9391 * Remove reference to the entitity-node.
9392 */
9393 node->content = NULL;
9394 node->children = NULL;
9395 node->last = NULL;
9396 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9397 xmlEntityPtr ent;
9398 /*
9399 * Assign new entity-node if available.
9400 */
9401 ent = xmlGetDocEntity(destDoc, node->name);
9402 if (ent != NULL) {
9403 node->content = ent->content;
9404 node->children = (xmlNodePtr) ent;
9405 node->last = (xmlNodePtr) ent;
9406 }
9407 }
9408 XML_TREE_ADOPT_STR(node->name)
9409 break;
Daniel Veillard7e21fd12005-07-03 21:44:07 +00009410 case XML_PI_NODE: {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009411 XML_TREE_ADOPT_STR(node->name)
9412 XML_TREE_ADOPT_STR_2(node->content)
9413 break;
Daniel Veillard7e21fd12005-07-03 21:44:07 +00009414 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009415 default:
9416 break;
9417 }
9418 }
9419 return (0);
9420}
9421
Daniel Veillard5d4644e2005-04-01 13:11:58 +00009422#define bottom_tree
9423#include "elfgcchack.h"