blob: 14ca0186e5c6b89e1e8d79e1782e61755eac34ee [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
Daniel Veillard652327a2003-09-29 18:02:38 +00001988#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001989/**
1990 * xmlRemoveProp:
1991 * @cur: an attribute
1992 *
1993 * Unlink and free one attribute, all the content is freed too
1994 * Note this doesn't work for namespace definition attributes
1995 *
1996 * Returns 0 if success and -1 in case of error.
1997 */
1998int
1999xmlRemoveProp(xmlAttrPtr cur) {
2000 xmlAttrPtr tmp;
2001 if (cur == NULL) {
2002#ifdef DEBUG_TREE
2003 xmlGenericError(xmlGenericErrorContext,
2004 "xmlRemoveProp : cur == NULL\n");
2005#endif
2006 return(-1);
2007 }
2008 if (cur->parent == NULL) {
2009#ifdef DEBUG_TREE
2010 xmlGenericError(xmlGenericErrorContext,
2011 "xmlRemoveProp : cur->parent == NULL\n");
2012#endif
2013 return(-1);
2014 }
2015 tmp = cur->parent->properties;
2016 if (tmp == cur) {
2017 cur->parent->properties = cur->next;
Rob Richards19dc9612005-10-28 16:15:16 +00002018 if (cur->next != NULL)
2019 cur->next->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002020 xmlFreeProp(cur);
2021 return(0);
2022 }
2023 while (tmp != NULL) {
2024 if (tmp->next == cur) {
2025 tmp->next = cur->next;
2026 if (tmp->next != NULL)
2027 tmp->next->prev = tmp;
2028 xmlFreeProp(cur);
2029 return(0);
2030 }
2031 tmp = tmp->next;
2032 }
2033#ifdef DEBUG_TREE
2034 xmlGenericError(xmlGenericErrorContext,
2035 "xmlRemoveProp : attribute not owned by its node\n");
2036#endif
2037 return(-1);
2038}
Daniel Veillard652327a2003-09-29 18:02:38 +00002039#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002040
2041/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002042 * xmlNewDocPI:
2043 * @doc: the target document
Owen Taylor3473f882001-02-23 17:55:21 +00002044 * @name: the processing instruction name
2045 * @content: the PI content
2046 *
2047 * Creation of a processing instruction element.
2048 * Returns a pointer to the new node object.
2049 */
2050xmlNodePtr
Daniel Veillard03a53c32004-10-26 16:06:51 +00002051xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
Owen Taylor3473f882001-02-23 17:55:21 +00002052 xmlNodePtr cur;
2053
2054 if (name == NULL) {
2055#ifdef DEBUG_TREE
2056 xmlGenericError(xmlGenericErrorContext,
2057 "xmlNewPI : name == NULL\n");
2058#endif
2059 return(NULL);
2060 }
2061
2062 /*
2063 * Allocate a new node and fill the fields.
2064 */
2065 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2066 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002067 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002068 return(NULL);
2069 }
2070 memset(cur, 0, sizeof(xmlNode));
2071 cur->type = XML_PI_NODE;
2072
Daniel Veillard03a53c32004-10-26 16:06:51 +00002073 if ((doc != NULL) && (doc->dict != NULL))
2074 cur->name = xmlDictLookup(doc->dict, name, -1);
2075 else
2076 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00002077 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002078 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002079 }
Daniel Veillarda03e3652004-11-02 18:45:30 +00002080 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002081
Daniel Veillarda880b122003-04-21 21:36:41 +00002082 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002083 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002084 return(cur);
2085}
2086
2087/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002088 * xmlNewPI:
2089 * @name: the processing instruction name
2090 * @content: the PI content
2091 *
2092 * Creation of a processing instruction element.
2093 * Use xmlDocNewPI preferably to get string interning
2094 *
2095 * Returns a pointer to the new node object.
2096 */
2097xmlNodePtr
2098xmlNewPI(const xmlChar *name, const xmlChar *content) {
2099 return(xmlNewDocPI(NULL, name, content));
2100}
2101
2102/**
Owen Taylor3473f882001-02-23 17:55:21 +00002103 * xmlNewNode:
2104 * @ns: namespace if any
2105 * @name: the node name
2106 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002107 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002108 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002109 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2110 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002111 */
2112xmlNodePtr
2113xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2114 xmlNodePtr cur;
2115
2116 if (name == NULL) {
2117#ifdef DEBUG_TREE
2118 xmlGenericError(xmlGenericErrorContext,
2119 "xmlNewNode : name == NULL\n");
2120#endif
2121 return(NULL);
2122 }
2123
2124 /*
2125 * Allocate a new node and fill the fields.
2126 */
2127 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2128 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002129 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002130 return(NULL);
2131 }
2132 memset(cur, 0, sizeof(xmlNode));
2133 cur->type = XML_ELEMENT_NODE;
2134
2135 cur->name = xmlStrdup(name);
2136 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002137
Daniel Veillarda880b122003-04-21 21:36:41 +00002138 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002139 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002140 return(cur);
2141}
2142
2143/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002144 * xmlNewNodeEatName:
2145 * @ns: namespace if any
2146 * @name: the node name
2147 *
2148 * Creation of a new node element. @ns is optional (NULL).
2149 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002150 * Returns a pointer to the new node object, with pointer @name as
2151 * new node's name. Use xmlNewNode() if a copy of @name string is
2152 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002153 */
2154xmlNodePtr
2155xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2156 xmlNodePtr cur;
2157
2158 if (name == NULL) {
2159#ifdef DEBUG_TREE
2160 xmlGenericError(xmlGenericErrorContext,
2161 "xmlNewNode : name == NULL\n");
2162#endif
2163 return(NULL);
2164 }
2165
2166 /*
2167 * Allocate a new node and fill the fields.
2168 */
2169 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2170 if (cur == NULL) {
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00002171 xmlFree(name);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002172 xmlTreeErrMemory("building node");
Daniel Veillard46de64e2002-05-29 08:21:33 +00002173 return(NULL);
2174 }
2175 memset(cur, 0, sizeof(xmlNode));
2176 cur->type = XML_ELEMENT_NODE;
2177
2178 cur->name = name;
2179 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002180
Daniel Veillarda880b122003-04-21 21:36:41 +00002181 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002182 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002183 return(cur);
2184}
2185
2186/**
Owen Taylor3473f882001-02-23 17:55:21 +00002187 * xmlNewDocNode:
2188 * @doc: the document
2189 * @ns: namespace if any
2190 * @name: the node name
2191 * @content: the XML text content if any
2192 *
2193 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002194 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002195 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2196 * references, but XML special chars need to be escaped first by using
2197 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2198 * need entities support.
2199 *
2200 * Returns a pointer to the new node object.
2201 */
2202xmlNodePtr
2203xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2204 const xmlChar *name, const xmlChar *content) {
2205 xmlNodePtr cur;
2206
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002207 if ((doc != NULL) && (doc->dict != NULL))
Daniel Veillard03a53c32004-10-26 16:06:51 +00002208 cur = xmlNewNodeEatName(ns, (xmlChar *)
2209 xmlDictLookup(doc->dict, name, -1));
2210 else
2211 cur = xmlNewNode(ns, name);
Owen Taylor3473f882001-02-23 17:55:21 +00002212 if (cur != NULL) {
2213 cur->doc = doc;
2214 if (content != NULL) {
2215 cur->children = xmlStringGetNodeList(doc, content);
2216 UPDATE_LAST_CHILD_AND_PARENT(cur)
2217 }
2218 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002219
Owen Taylor3473f882001-02-23 17:55:21 +00002220 return(cur);
2221}
2222
Daniel Veillard46de64e2002-05-29 08:21:33 +00002223/**
2224 * xmlNewDocNodeEatName:
2225 * @doc: the document
2226 * @ns: namespace if any
2227 * @name: the node name
2228 * @content: the XML text content if any
2229 *
2230 * Creation of a new node element within a document. @ns and @content
2231 * are optional (NULL).
2232 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2233 * references, but XML special chars need to be escaped first by using
2234 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2235 * need entities support.
2236 *
2237 * Returns a pointer to the new node object.
2238 */
2239xmlNodePtr
2240xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2241 xmlChar *name, const xmlChar *content) {
2242 xmlNodePtr cur;
2243
2244 cur = xmlNewNodeEatName(ns, name);
2245 if (cur != NULL) {
2246 cur->doc = doc;
2247 if (content != NULL) {
2248 cur->children = xmlStringGetNodeList(doc, content);
2249 UPDATE_LAST_CHILD_AND_PARENT(cur)
2250 }
2251 }
2252 return(cur);
2253}
2254
Daniel Veillard652327a2003-09-29 18:02:38 +00002255#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002256/**
2257 * xmlNewDocRawNode:
2258 * @doc: the document
2259 * @ns: namespace if any
2260 * @name: the node name
2261 * @content: the text content if any
2262 *
2263 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002264 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002265 *
2266 * Returns a pointer to the new node object.
2267 */
2268xmlNodePtr
2269xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2270 const xmlChar *name, const xmlChar *content) {
2271 xmlNodePtr cur;
2272
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002273 cur = xmlNewDocNode(doc, ns, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002274 if (cur != NULL) {
2275 cur->doc = doc;
2276 if (content != NULL) {
2277 cur->children = xmlNewDocText(doc, content);
2278 UPDATE_LAST_CHILD_AND_PARENT(cur)
2279 }
2280 }
2281 return(cur);
2282}
2283
2284/**
2285 * xmlNewDocFragment:
2286 * @doc: the document owning the fragment
2287 *
2288 * Creation of a new Fragment node.
2289 * Returns a pointer to the new node object.
2290 */
2291xmlNodePtr
2292xmlNewDocFragment(xmlDocPtr doc) {
2293 xmlNodePtr cur;
2294
2295 /*
2296 * Allocate a new DocumentFragment node and fill the fields.
2297 */
2298 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2299 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002300 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002301 return(NULL);
2302 }
2303 memset(cur, 0, sizeof(xmlNode));
2304 cur->type = XML_DOCUMENT_FRAG_NODE;
2305
2306 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002307
Daniel Veillarda880b122003-04-21 21:36:41 +00002308 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002309 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002310 return(cur);
2311}
Daniel Veillard652327a2003-09-29 18:02:38 +00002312#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002313
2314/**
2315 * xmlNewText:
2316 * @content: the text content
2317 *
2318 * Creation of a new text node.
2319 * Returns a pointer to the new node object.
2320 */
2321xmlNodePtr
2322xmlNewText(const xmlChar *content) {
2323 xmlNodePtr cur;
2324
2325 /*
2326 * Allocate a new node and fill the fields.
2327 */
2328 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2329 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002330 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002331 return(NULL);
2332 }
2333 memset(cur, 0, sizeof(xmlNode));
2334 cur->type = XML_TEXT_NODE;
2335
2336 cur->name = xmlStringText;
2337 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002338 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002339 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002340
Daniel Veillarda880b122003-04-21 21:36:41 +00002341 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002342 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002343 return(cur);
2344}
2345
Daniel Veillard652327a2003-09-29 18:02:38 +00002346#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002347/**
2348 * xmlNewTextChild:
2349 * @parent: the parent node
2350 * @ns: a namespace if any
2351 * @name: the name of the child
2352 * @content: the text content of the child if any.
2353 *
2354 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002355 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2356 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002357 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002358 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2359 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2360 * reserved XML chars that might appear in @content, such as the ampersand,
2361 * greater-than or less-than signs, are automatically replaced by their XML
2362 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002363 *
2364 * Returns a pointer to the new node object.
2365 */
2366xmlNodePtr
2367xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2368 const xmlChar *name, const xmlChar *content) {
2369 xmlNodePtr cur, prev;
2370
2371 if (parent == NULL) {
2372#ifdef DEBUG_TREE
2373 xmlGenericError(xmlGenericErrorContext,
2374 "xmlNewTextChild : parent == NULL\n");
2375#endif
2376 return(NULL);
2377 }
2378
2379 if (name == NULL) {
2380#ifdef DEBUG_TREE
2381 xmlGenericError(xmlGenericErrorContext,
2382 "xmlNewTextChild : name == NULL\n");
2383#endif
2384 return(NULL);
2385 }
2386
2387 /*
2388 * Allocate a new node
2389 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002390 if (parent->type == XML_ELEMENT_NODE) {
2391 if (ns == NULL)
2392 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2393 else
2394 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2395 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2396 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2397 if (ns == NULL)
2398 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2399 else
2400 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2401 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2402 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2403 } else {
2404 return(NULL);
2405 }
Owen Taylor3473f882001-02-23 17:55:21 +00002406 if (cur == NULL) return(NULL);
2407
2408 /*
2409 * add the new element at the end of the children list.
2410 */
2411 cur->type = XML_ELEMENT_NODE;
2412 cur->parent = parent;
2413 cur->doc = parent->doc;
2414 if (parent->children == NULL) {
2415 parent->children = cur;
2416 parent->last = cur;
2417 } else {
2418 prev = parent->last;
2419 prev->next = cur;
2420 cur->prev = prev;
2421 parent->last = cur;
2422 }
2423
2424 return(cur);
2425}
Daniel Veillard652327a2003-09-29 18:02:38 +00002426#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002427
2428/**
2429 * xmlNewCharRef:
2430 * @doc: the document
2431 * @name: the char ref string, starting with # or "&# ... ;"
2432 *
2433 * Creation of a new character reference node.
2434 * Returns a pointer to the new node object.
2435 */
2436xmlNodePtr
2437xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2438 xmlNodePtr cur;
2439
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002440 if (name == NULL)
2441 return(NULL);
2442
Owen Taylor3473f882001-02-23 17:55:21 +00002443 /*
2444 * Allocate a new node and fill the fields.
2445 */
2446 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2447 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002448 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002449 return(NULL);
2450 }
2451 memset(cur, 0, sizeof(xmlNode));
2452 cur->type = XML_ENTITY_REF_NODE;
2453
2454 cur->doc = doc;
2455 if (name[0] == '&') {
2456 int len;
2457 name++;
2458 len = xmlStrlen(name);
2459 if (name[len - 1] == ';')
2460 cur->name = xmlStrndup(name, len - 1);
2461 else
2462 cur->name = xmlStrndup(name, len);
2463 } else
2464 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002465
Daniel Veillarda880b122003-04-21 21:36:41 +00002466 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002467 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002468 return(cur);
2469}
2470
2471/**
2472 * xmlNewReference:
2473 * @doc: the document
2474 * @name: the reference name, or the reference string with & and ;
2475 *
2476 * Creation of a new reference node.
2477 * Returns a pointer to the new node object.
2478 */
2479xmlNodePtr
2480xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2481 xmlNodePtr cur;
2482 xmlEntityPtr ent;
2483
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002484 if (name == NULL)
2485 return(NULL);
2486
Owen Taylor3473f882001-02-23 17:55:21 +00002487 /*
2488 * Allocate a new node and fill the fields.
2489 */
2490 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2491 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002492 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002493 return(NULL);
2494 }
2495 memset(cur, 0, sizeof(xmlNode));
2496 cur->type = XML_ENTITY_REF_NODE;
2497
2498 cur->doc = doc;
2499 if (name[0] == '&') {
2500 int len;
2501 name++;
2502 len = xmlStrlen(name);
2503 if (name[len - 1] == ';')
2504 cur->name = xmlStrndup(name, len - 1);
2505 else
2506 cur->name = xmlStrndup(name, len);
2507 } else
2508 cur->name = xmlStrdup(name);
2509
2510 ent = xmlGetDocEntity(doc, cur->name);
2511 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002512 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002513 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002514 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002515 * updated. Not sure if this is 100% correct.
2516 * -George
2517 */
2518 cur->children = (xmlNodePtr) ent;
2519 cur->last = (xmlNodePtr) ent;
2520 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002521
Daniel Veillarda880b122003-04-21 21:36:41 +00002522 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002523 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002524 return(cur);
2525}
2526
2527/**
2528 * xmlNewDocText:
2529 * @doc: the document
2530 * @content: the text content
2531 *
2532 * Creation of a new text node within a document.
2533 * Returns a pointer to the new node object.
2534 */
2535xmlNodePtr
2536xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2537 xmlNodePtr cur;
2538
2539 cur = xmlNewText(content);
2540 if (cur != NULL) cur->doc = doc;
2541 return(cur);
2542}
2543
2544/**
2545 * xmlNewTextLen:
2546 * @content: the text content
2547 * @len: the text len.
2548 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002549 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002550 * Returns a pointer to the new node object.
2551 */
2552xmlNodePtr
2553xmlNewTextLen(const xmlChar *content, int len) {
2554 xmlNodePtr cur;
2555
2556 /*
2557 * Allocate a new node and fill the fields.
2558 */
2559 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2560 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002561 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002562 return(NULL);
2563 }
2564 memset(cur, 0, sizeof(xmlNode));
2565 cur->type = XML_TEXT_NODE;
2566
2567 cur->name = xmlStringText;
2568 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002569 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002570 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002571
Daniel Veillarda880b122003-04-21 21:36:41 +00002572 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002573 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002574 return(cur);
2575}
2576
2577/**
2578 * xmlNewDocTextLen:
2579 * @doc: the document
2580 * @content: the text content
2581 * @len: the text len.
2582 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002583 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002584 * text node pertain to a given document.
2585 * Returns a pointer to the new node object.
2586 */
2587xmlNodePtr
2588xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2589 xmlNodePtr cur;
2590
2591 cur = xmlNewTextLen(content, len);
2592 if (cur != NULL) cur->doc = doc;
2593 return(cur);
2594}
2595
2596/**
2597 * xmlNewComment:
2598 * @content: the comment content
2599 *
2600 * Creation of a new node containing a comment.
2601 * Returns a pointer to the new node object.
2602 */
2603xmlNodePtr
2604xmlNewComment(const xmlChar *content) {
2605 xmlNodePtr cur;
2606
2607 /*
2608 * Allocate a new node and fill the fields.
2609 */
2610 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2611 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002612 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002613 return(NULL);
2614 }
2615 memset(cur, 0, sizeof(xmlNode));
2616 cur->type = XML_COMMENT_NODE;
2617
2618 cur->name = xmlStringComment;
2619 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002620 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002621 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002622
Daniel Veillarda880b122003-04-21 21:36:41 +00002623 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002624 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002625 return(cur);
2626}
2627
2628/**
2629 * xmlNewCDataBlock:
2630 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002631 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002632 * @len: the length of the block
2633 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002634 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002635 * Returns a pointer to the new node object.
2636 */
2637xmlNodePtr
2638xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2639 xmlNodePtr cur;
2640
2641 /*
2642 * Allocate a new node and fill the fields.
2643 */
2644 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2645 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002646 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002647 return(NULL);
2648 }
2649 memset(cur, 0, sizeof(xmlNode));
2650 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002651 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002652
2653 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002654 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002655 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002656
Daniel Veillarda880b122003-04-21 21:36:41 +00002657 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002658 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002659 return(cur);
2660}
2661
2662/**
2663 * xmlNewDocComment:
2664 * @doc: the document
2665 * @content: the comment content
2666 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002667 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002668 * Returns a pointer to the new node object.
2669 */
2670xmlNodePtr
2671xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2672 xmlNodePtr cur;
2673
2674 cur = xmlNewComment(content);
2675 if (cur != NULL) cur->doc = doc;
2676 return(cur);
2677}
2678
2679/**
2680 * xmlSetTreeDoc:
2681 * @tree: the top element
2682 * @doc: the document
2683 *
2684 * update all nodes under the tree to point to the right document
2685 */
2686void
2687xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002688 xmlAttrPtr prop;
2689
Owen Taylor3473f882001-02-23 17:55:21 +00002690 if (tree == NULL)
2691 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002692 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002693 if(tree->type == XML_ELEMENT_NODE) {
2694 prop = tree->properties;
2695 while (prop != NULL) {
2696 prop->doc = doc;
2697 xmlSetListDoc(prop->children, doc);
2698 prop = prop->next;
2699 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002700 }
Owen Taylor3473f882001-02-23 17:55:21 +00002701 if (tree->children != NULL)
2702 xmlSetListDoc(tree->children, doc);
2703 tree->doc = doc;
2704 }
2705}
2706
2707/**
2708 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002709 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002710 * @doc: the document
2711 *
2712 * update all nodes in the list to point to the right document
2713 */
2714void
2715xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2716 xmlNodePtr cur;
2717
2718 if (list == NULL)
2719 return;
2720 cur = list;
2721 while (cur != NULL) {
2722 if (cur->doc != doc)
2723 xmlSetTreeDoc(cur, doc);
2724 cur = cur->next;
2725 }
2726}
2727
Daniel Veillard2156d432004-03-04 15:59:36 +00002728#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002729/**
2730 * xmlNewChild:
2731 * @parent: the parent node
2732 * @ns: a namespace if any
2733 * @name: the name of the child
2734 * @content: the XML content of the child if any.
2735 *
2736 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002737 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2738 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002739 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002740 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2741 * references. XML special chars must be escaped first by using
2742 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002743 *
2744 * Returns a pointer to the new node object.
2745 */
2746xmlNodePtr
2747xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2748 const xmlChar *name, const xmlChar *content) {
2749 xmlNodePtr cur, prev;
2750
2751 if (parent == NULL) {
2752#ifdef DEBUG_TREE
2753 xmlGenericError(xmlGenericErrorContext,
2754 "xmlNewChild : parent == NULL\n");
2755#endif
2756 return(NULL);
2757 }
2758
2759 if (name == NULL) {
2760#ifdef DEBUG_TREE
2761 xmlGenericError(xmlGenericErrorContext,
2762 "xmlNewChild : name == NULL\n");
2763#endif
2764 return(NULL);
2765 }
2766
2767 /*
2768 * Allocate a new node
2769 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002770 if (parent->type == XML_ELEMENT_NODE) {
2771 if (ns == NULL)
2772 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2773 else
2774 cur = xmlNewDocNode(parent->doc, ns, name, content);
2775 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2776 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2777 if (ns == NULL)
2778 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2779 else
2780 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002781 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2782 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002783 } else {
2784 return(NULL);
2785 }
Owen Taylor3473f882001-02-23 17:55:21 +00002786 if (cur == NULL) return(NULL);
2787
2788 /*
2789 * add the new element at the end of the children list.
2790 */
2791 cur->type = XML_ELEMENT_NODE;
2792 cur->parent = parent;
2793 cur->doc = parent->doc;
2794 if (parent->children == NULL) {
2795 parent->children = cur;
2796 parent->last = cur;
2797 } else {
2798 prev = parent->last;
2799 prev->next = cur;
2800 cur->prev = prev;
2801 parent->last = cur;
2802 }
2803
2804 return(cur);
2805}
Daniel Veillard652327a2003-09-29 18:02:38 +00002806#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002807
2808/**
Rob Richards65815122006-02-25 17:13:33 +00002809 * xmlAddPropSibling:
2810 * @prev: the attribute to which @prop is added after
2811 * @cur: the base attribute passed to calling function
2812 * @prop: the new attribute
2813 *
2814 * Add a new attribute after @prev using @cur as base attribute.
2815 * When inserting before @cur, @prev is passed as @cur->prev.
2816 * When inserting after @cur, @prev is passed as @cur.
2817 * If an existing attribute is found it is detroyed prior to adding @prop.
2818 *
2819 * Returns the attribute being inserted or NULL in case of error.
2820 */
2821static xmlNodePtr
2822xmlAddPropSibling(xmlNodePtr prev, xmlNodePtr cur, xmlNodePtr prop) {
2823 xmlAttrPtr attr;
2824
2825 if (cur->type != XML_ATTRIBUTE_NODE)
2826 return(NULL);
2827
2828 /* check if an attribute with the same name exists */
2829 if (prop->ns == NULL)
2830 attr = xmlHasNsProp(cur->parent, prop->name, NULL);
2831 else
2832 attr = xmlHasNsProp(cur->parent, prop->name, prop->ns->href);
2833
2834 if (prop->doc != cur->doc) {
2835 xmlSetTreeDoc(prop, cur->doc);
2836 }
2837 prop->parent = cur->parent;
2838 prop->prev = prev;
2839 if (prev != NULL) {
2840 prop->next = prev->next;
2841 prev->next = prop;
2842 if (prop->next)
2843 prop->next->prev = prop;
2844 } else {
2845 prop->next = cur;
2846 cur->prev = prop;
2847 }
2848 if (prop->prev == NULL && prop->parent != NULL)
2849 prop->parent->properties = (xmlAttrPtr) prop;
2850 if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) {
2851 /* different instance, destroy it (attributes must be unique) */
2852 xmlRemoveProp((xmlAttrPtr) attr);
2853 }
2854 return prop;
2855}
2856
2857/**
Owen Taylor3473f882001-02-23 17:55:21 +00002858 * xmlAddNextSibling:
2859 * @cur: the child node
2860 * @elem: the new node
2861 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002862 * Add a new node @elem as the next sibling of @cur
2863 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002864 * first unlinked from its existing context.
2865 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002866 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2867 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002868 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002869 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002870 */
2871xmlNodePtr
2872xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2873 if (cur == NULL) {
2874#ifdef DEBUG_TREE
2875 xmlGenericError(xmlGenericErrorContext,
2876 "xmlAddNextSibling : cur == NULL\n");
2877#endif
2878 return(NULL);
2879 }
2880 if (elem == NULL) {
2881#ifdef DEBUG_TREE
2882 xmlGenericError(xmlGenericErrorContext,
2883 "xmlAddNextSibling : elem == NULL\n");
2884#endif
2885 return(NULL);
2886 }
2887
Rob Richards19dc9612005-10-28 16:15:16 +00002888 if (cur == elem) {
2889#ifdef DEBUG_TREE
2890 xmlGenericError(xmlGenericErrorContext,
2891 "xmlAddNextSibling : cur == elem\n");
2892#endif
2893 return(NULL);
2894 }
2895
Owen Taylor3473f882001-02-23 17:55:21 +00002896 xmlUnlinkNode(elem);
2897
2898 if (elem->type == XML_TEXT_NODE) {
2899 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002900 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002901 xmlFreeNode(elem);
2902 return(cur);
2903 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002904 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2905 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002906 xmlChar *tmp;
2907
2908 tmp = xmlStrdup(elem->content);
2909 tmp = xmlStrcat(tmp, cur->next->content);
2910 xmlNodeSetContent(cur->next, tmp);
2911 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002912 xmlFreeNode(elem);
2913 return(cur->next);
2914 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002915 } else if (elem->type == XML_ATTRIBUTE_NODE) {
Rob Richards65815122006-02-25 17:13:33 +00002916 return xmlAddPropSibling(cur, cur, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00002917 }
2918
2919 if (elem->doc != cur->doc) {
2920 xmlSetTreeDoc(elem, cur->doc);
2921 }
2922 elem->parent = cur->parent;
2923 elem->prev = cur;
2924 elem->next = cur->next;
2925 cur->next = elem;
2926 if (elem->next != NULL)
2927 elem->next->prev = elem;
Rob Richards65815122006-02-25 17:13:33 +00002928 if ((elem->parent != NULL) && (elem->parent->last == cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002929 elem->parent->last = elem;
2930 return(elem);
2931}
2932
William M. Brack21e4ef22005-01-02 09:53:13 +00002933#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
2934 defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002935/**
2936 * xmlAddPrevSibling:
2937 * @cur: the child node
2938 * @elem: the new node
2939 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002940 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002941 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002942 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002943 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002944 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2945 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002946 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002947 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002948 */
2949xmlNodePtr
2950xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2951 if (cur == NULL) {
2952#ifdef DEBUG_TREE
2953 xmlGenericError(xmlGenericErrorContext,
2954 "xmlAddPrevSibling : cur == NULL\n");
2955#endif
2956 return(NULL);
2957 }
2958 if (elem == NULL) {
2959#ifdef DEBUG_TREE
2960 xmlGenericError(xmlGenericErrorContext,
2961 "xmlAddPrevSibling : elem == NULL\n");
2962#endif
2963 return(NULL);
2964 }
2965
Rob Richards19dc9612005-10-28 16:15:16 +00002966 if (cur == elem) {
2967#ifdef DEBUG_TREE
2968 xmlGenericError(xmlGenericErrorContext,
2969 "xmlAddPrevSibling : cur == elem\n");
2970#endif
2971 return(NULL);
2972 }
2973
Owen Taylor3473f882001-02-23 17:55:21 +00002974 xmlUnlinkNode(elem);
2975
2976 if (elem->type == XML_TEXT_NODE) {
2977 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002978 xmlChar *tmp;
2979
2980 tmp = xmlStrdup(elem->content);
2981 tmp = xmlStrcat(tmp, cur->content);
2982 xmlNodeSetContent(cur, tmp);
2983 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002984 xmlFreeNode(elem);
2985 return(cur);
2986 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002987 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2988 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002989 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002990 xmlFreeNode(elem);
2991 return(cur->prev);
2992 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002993 } else if (elem->type == XML_ATTRIBUTE_NODE) {
Rob Richards65815122006-02-25 17:13:33 +00002994 return xmlAddPropSibling(cur->prev, cur, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00002995 }
2996
2997 if (elem->doc != cur->doc) {
2998 xmlSetTreeDoc(elem, cur->doc);
2999 }
3000 elem->parent = cur->parent;
3001 elem->next = cur;
3002 elem->prev = cur->prev;
3003 cur->prev = elem;
3004 if (elem->prev != NULL)
3005 elem->prev->next = elem;
Rob Richards65815122006-02-25 17:13:33 +00003006 if ((elem->parent != NULL) && (elem->parent->children == cur)) {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003007 elem->parent->children = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003008 }
Owen Taylor3473f882001-02-23 17:55:21 +00003009 return(elem);
3010}
Daniel Veillard652327a2003-09-29 18:02:38 +00003011#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003012
3013/**
3014 * xmlAddSibling:
3015 * @cur: the child node
3016 * @elem: the new node
3017 *
3018 * Add a new element @elem to the list of siblings of @cur
3019 * merging adjacent TEXT nodes (@elem may be freed)
3020 * If the new element was already inserted in a document it is
3021 * first unlinked from its existing context.
3022 *
3023 * Returns the new element or NULL in case of error.
3024 */
3025xmlNodePtr
3026xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
3027 xmlNodePtr parent;
3028
3029 if (cur == NULL) {
3030#ifdef DEBUG_TREE
3031 xmlGenericError(xmlGenericErrorContext,
3032 "xmlAddSibling : cur == NULL\n");
3033#endif
3034 return(NULL);
3035 }
3036
3037 if (elem == NULL) {
3038#ifdef DEBUG_TREE
3039 xmlGenericError(xmlGenericErrorContext,
3040 "xmlAddSibling : elem == NULL\n");
3041#endif
3042 return(NULL);
3043 }
3044
3045 /*
3046 * Constant time is we can rely on the ->parent->last to find
3047 * the last sibling.
3048 */
Rob Richards65815122006-02-25 17:13:33 +00003049 if ((cur->type != XML_ATTRIBUTE_NODE) && (cur->parent != NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00003050 (cur->parent->children != NULL) &&
3051 (cur->parent->last != NULL) &&
3052 (cur->parent->last->next == NULL)) {
3053 cur = cur->parent->last;
3054 } else {
3055 while (cur->next != NULL) cur = cur->next;
3056 }
3057
3058 xmlUnlinkNode(elem);
3059
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003060 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3061 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003062 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003063 xmlFreeNode(elem);
3064 return(cur);
Rob Richards65815122006-02-25 17:13:33 +00003065 } else if (elem->type == XML_ATTRIBUTE_NODE) {
3066 return xmlAddPropSibling(cur, cur, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00003067 }
3068
3069 if (elem->doc != cur->doc) {
3070 xmlSetTreeDoc(elem, cur->doc);
3071 }
3072 parent = cur->parent;
3073 elem->prev = cur;
3074 elem->next = NULL;
3075 elem->parent = parent;
3076 cur->next = elem;
3077 if (parent != NULL)
3078 parent->last = elem;
3079
3080 return(elem);
3081}
3082
3083/**
3084 * xmlAddChildList:
3085 * @parent: the parent node
3086 * @cur: the first node in the list
3087 *
3088 * Add a list of node at the end of the child list of the parent
3089 * merging adjacent TEXT nodes (@cur may be freed)
3090 *
3091 * Returns the last child or NULL in case of error.
3092 */
3093xmlNodePtr
3094xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3095 xmlNodePtr prev;
3096
3097 if (parent == NULL) {
3098#ifdef DEBUG_TREE
3099 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003100 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003101#endif
3102 return(NULL);
3103 }
3104
3105 if (cur == NULL) {
3106#ifdef DEBUG_TREE
3107 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003108 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003109#endif
3110 return(NULL);
3111 }
3112
3113 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3114 (cur->doc != parent->doc)) {
3115#ifdef DEBUG_TREE
3116 xmlGenericError(xmlGenericErrorContext,
3117 "Elements moved to a different document\n");
3118#endif
3119 }
3120
3121 /*
3122 * add the first element at the end of the children list.
3123 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003124
Owen Taylor3473f882001-02-23 17:55:21 +00003125 if (parent->children == NULL) {
3126 parent->children = cur;
3127 } else {
3128 /*
3129 * If cur and parent->last both are TEXT nodes, then merge them.
3130 */
3131 if ((cur->type == XML_TEXT_NODE) &&
3132 (parent->last->type == XML_TEXT_NODE) &&
3133 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003134 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003135 /*
3136 * if it's the only child, nothing more to be done.
3137 */
3138 if (cur->next == NULL) {
3139 xmlFreeNode(cur);
3140 return(parent->last);
3141 }
3142 prev = cur;
3143 cur = cur->next;
3144 xmlFreeNode(prev);
3145 }
3146 prev = parent->last;
3147 prev->next = cur;
3148 cur->prev = prev;
3149 }
3150 while (cur->next != NULL) {
3151 cur->parent = parent;
3152 if (cur->doc != parent->doc) {
3153 xmlSetTreeDoc(cur, parent->doc);
3154 }
3155 cur = cur->next;
3156 }
3157 cur->parent = parent;
3158 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3159 parent->last = cur;
3160
3161 return(cur);
3162}
3163
3164/**
3165 * xmlAddChild:
3166 * @parent: the parent node
3167 * @cur: the child node
3168 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003169 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003170 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003171 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3172 * If there is an attribute with equal name, it is first destroyed.
3173 *
Owen Taylor3473f882001-02-23 17:55:21 +00003174 * Returns the child or NULL in case of error.
3175 */
3176xmlNodePtr
3177xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3178 xmlNodePtr prev;
3179
3180 if (parent == NULL) {
3181#ifdef DEBUG_TREE
3182 xmlGenericError(xmlGenericErrorContext,
3183 "xmlAddChild : parent == NULL\n");
3184#endif
3185 return(NULL);
3186 }
3187
3188 if (cur == NULL) {
3189#ifdef DEBUG_TREE
3190 xmlGenericError(xmlGenericErrorContext,
3191 "xmlAddChild : child == NULL\n");
3192#endif
3193 return(NULL);
3194 }
3195
Rob Richards19dc9612005-10-28 16:15:16 +00003196 if (parent == cur) {
3197#ifdef DEBUG_TREE
3198 xmlGenericError(xmlGenericErrorContext,
3199 "xmlAddChild : parent == cur\n");
3200#endif
3201 return(NULL);
3202 }
Owen Taylor3473f882001-02-23 17:55:21 +00003203 /*
3204 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003205 * cur is then freed.
3206 */
3207 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003208 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003209 (parent->content != NULL) &&
Rob Richards19dc9612005-10-28 16:15:16 +00003210 (parent->name == cur->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003211 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003212 xmlFreeNode(cur);
3213 return(parent);
3214 }
3215 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003216 (parent->last->name == cur->name) &&
3217 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003218 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003219 xmlFreeNode(cur);
3220 return(parent->last);
3221 }
3222 }
3223
3224 /*
3225 * add the new element at the end of the children list.
3226 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003227 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003228 cur->parent = parent;
3229 if (cur->doc != parent->doc) {
3230 xmlSetTreeDoc(cur, parent->doc);
3231 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003232 /* this check prevents a loop on tree-traversions if a developer
3233 * tries to add a node to its parent multiple times
3234 */
3235 if (prev == parent)
3236 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003237
3238 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003239 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003240 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003241 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003242 (parent->content != NULL) &&
3243 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003244 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003245 xmlFreeNode(cur);
3246 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003247 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003248 if (cur->type == XML_ATTRIBUTE_NODE) {
Rob Richards19dc9612005-10-28 16:15:16 +00003249 if (parent->type != XML_ELEMENT_NODE)
3250 return(NULL);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003251 if (parent->properties == NULL) {
3252 parent->properties = (xmlAttrPtr) cur;
3253 } else {
3254 /* check if an attribute with the same name exists */
3255 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003256
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003257 if (cur->ns == NULL)
Rob Richardsc342ec62005-10-25 00:10:12 +00003258 lastattr = xmlHasNsProp(parent, cur->name, NULL);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003259 else
3260 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
Rob Richardsc342ec62005-10-25 00:10:12 +00003261 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur) && (lastattr->type != XML_ATTRIBUTE_DECL)) {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003262 /* different instance, destroy it (attributes must be unique) */
Rob Richards19dc9612005-10-28 16:15:16 +00003263 xmlUnlinkNode((xmlNodePtr) lastattr);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003264 xmlFreeProp(lastattr);
3265 }
Rob Richards19dc9612005-10-28 16:15:16 +00003266 if (lastattr == (xmlAttrPtr) cur)
3267 return(cur);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003268 /* find the end */
3269 lastattr = parent->properties;
3270 while (lastattr->next != NULL) {
3271 lastattr = lastattr->next;
3272 }
3273 lastattr->next = (xmlAttrPtr) cur;
3274 ((xmlAttrPtr) cur)->prev = lastattr;
3275 }
3276 } else {
3277 if (parent->children == NULL) {
3278 parent->children = cur;
3279 parent->last = cur;
3280 } else {
3281 prev = parent->last;
3282 prev->next = cur;
3283 cur->prev = prev;
3284 parent->last = cur;
3285 }
3286 }
Owen Taylor3473f882001-02-23 17:55:21 +00003287 return(cur);
3288}
3289
3290/**
3291 * xmlGetLastChild:
3292 * @parent: the parent node
3293 *
3294 * Search the last child of a node.
3295 * Returns the last child or NULL if none.
3296 */
3297xmlNodePtr
3298xmlGetLastChild(xmlNodePtr parent) {
3299 if (parent == NULL) {
3300#ifdef DEBUG_TREE
3301 xmlGenericError(xmlGenericErrorContext,
3302 "xmlGetLastChild : parent == NULL\n");
3303#endif
3304 return(NULL);
3305 }
3306 return(parent->last);
3307}
3308
3309/**
3310 * xmlFreeNodeList:
3311 * @cur: the first node in the list
3312 *
3313 * Free a node and all its siblings, this is a recursive behaviour, all
3314 * the children are freed too.
3315 */
3316void
3317xmlFreeNodeList(xmlNodePtr cur) {
3318 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003319 xmlDictPtr dict = NULL;
3320
3321 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003322 if (cur->type == XML_NAMESPACE_DECL) {
3323 xmlFreeNsList((xmlNsPtr) cur);
3324 return;
3325 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003326 if ((cur->type == XML_DOCUMENT_NODE) ||
3327#ifdef LIBXML_DOCB_ENABLED
3328 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003329#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003330 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003331 xmlFreeDoc((xmlDocPtr) cur);
3332 return;
3333 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003334 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003335 while (cur != NULL) {
3336 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003337 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003338
Daniel Veillarda880b122003-04-21 21:36:41 +00003339 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003340 xmlDeregisterNodeDefaultValue(cur);
3341
Daniel Veillard02141ea2001-04-30 11:46:40 +00003342 if ((cur->children != NULL) &&
3343 (cur->type != XML_ENTITY_REF_NODE))
3344 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003345 if (((cur->type == XML_ELEMENT_NODE) ||
3346 (cur->type == XML_XINCLUDE_START) ||
3347 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003348 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003349 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003350 if ((cur->type != XML_ELEMENT_NODE) &&
3351 (cur->type != XML_XINCLUDE_START) &&
3352 (cur->type != XML_XINCLUDE_END) &&
Daniel Veillard8874b942005-08-25 13:19:21 +00003353 (cur->type != XML_ENTITY_REF_NODE) &&
3354 (cur->content != (xmlChar *) &(cur->properties))) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003355 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003356 }
3357 if (((cur->type == XML_ELEMENT_NODE) ||
3358 (cur->type == XML_XINCLUDE_START) ||
3359 (cur->type == XML_XINCLUDE_END)) &&
3360 (cur->nsDef != NULL))
3361 xmlFreeNsList(cur->nsDef);
3362
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003363 /*
3364 * When a node is a text node or a comment, it uses a global static
3365 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003366 * Otherwise the node name might come from the document's
3367 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003368 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003369 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003370 (cur->type != XML_TEXT_NODE) &&
3371 (cur->type != XML_COMMENT_NODE))
3372 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003373 xmlFree(cur);
3374 }
Owen Taylor3473f882001-02-23 17:55:21 +00003375 cur = next;
3376 }
3377}
3378
3379/**
3380 * xmlFreeNode:
3381 * @cur: the node
3382 *
3383 * Free a node, this is a recursive behaviour, all the children are freed too.
3384 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3385 */
3386void
3387xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003388 xmlDictPtr dict = NULL;
3389
3390 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003391
Daniel Veillard02141ea2001-04-30 11:46:40 +00003392 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003393 if (cur->type == XML_DTD_NODE) {
3394 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003395 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003396 }
3397 if (cur->type == XML_NAMESPACE_DECL) {
3398 xmlFreeNs((xmlNsPtr) cur);
3399 return;
3400 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003401 if (cur->type == XML_ATTRIBUTE_NODE) {
3402 xmlFreeProp((xmlAttrPtr) cur);
3403 return;
3404 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003405
Daniel Veillarda880b122003-04-21 21:36:41 +00003406 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003407 xmlDeregisterNodeDefaultValue(cur);
3408
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003409 if (cur->doc != NULL) dict = cur->doc->dict;
3410
Owen Taylor3473f882001-02-23 17:55:21 +00003411 if ((cur->children != NULL) &&
3412 (cur->type != XML_ENTITY_REF_NODE))
3413 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003414 if (((cur->type == XML_ELEMENT_NODE) ||
3415 (cur->type == XML_XINCLUDE_START) ||
3416 (cur->type == XML_XINCLUDE_END)) &&
3417 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003418 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003419 if ((cur->type != XML_ELEMENT_NODE) &&
3420 (cur->content != NULL) &&
3421 (cur->type != XML_ENTITY_REF_NODE) &&
3422 (cur->type != XML_XINCLUDE_END) &&
Daniel Veillard8874b942005-08-25 13:19:21 +00003423 (cur->type != XML_XINCLUDE_START) &&
3424 (cur->content != (xmlChar *) &(cur->properties))) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003425 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003426 }
3427
Daniel Veillardacd370f2001-06-09 17:17:51 +00003428 /*
3429 * When a node is a text node or a comment, it uses a global static
3430 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003431 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003432 */
Owen Taylor3473f882001-02-23 17:55:21 +00003433 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003434 (cur->type != XML_TEXT_NODE) &&
3435 (cur->type != XML_COMMENT_NODE))
3436 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003437
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003438 if (((cur->type == XML_ELEMENT_NODE) ||
3439 (cur->type == XML_XINCLUDE_START) ||
3440 (cur->type == XML_XINCLUDE_END)) &&
3441 (cur->nsDef != NULL))
3442 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003443 xmlFree(cur);
3444}
3445
3446/**
3447 * xmlUnlinkNode:
3448 * @cur: the node
3449 *
3450 * Unlink a node from it's current context, the node is not freed
3451 */
3452void
3453xmlUnlinkNode(xmlNodePtr cur) {
3454 if (cur == NULL) {
3455#ifdef DEBUG_TREE
3456 xmlGenericError(xmlGenericErrorContext,
3457 "xmlUnlinkNode : node == NULL\n");
3458#endif
3459 return;
3460 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003461 if (cur->type == XML_DTD_NODE) {
3462 xmlDocPtr doc;
3463 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003464 if (doc != NULL) {
3465 if (doc->intSubset == (xmlDtdPtr) cur)
3466 doc->intSubset = NULL;
3467 if (doc->extSubset == (xmlDtdPtr) cur)
3468 doc->extSubset = NULL;
3469 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003470 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003471 if (cur->parent != NULL) {
3472 xmlNodePtr parent;
3473 parent = cur->parent;
3474 if (cur->type == XML_ATTRIBUTE_NODE) {
3475 if (parent->properties == (xmlAttrPtr) cur)
3476 parent->properties = ((xmlAttrPtr) cur)->next;
3477 } else {
3478 if (parent->children == cur)
3479 parent->children = cur->next;
3480 if (parent->last == cur)
3481 parent->last = cur->prev;
3482 }
3483 cur->parent = NULL;
3484 }
Owen Taylor3473f882001-02-23 17:55:21 +00003485 if (cur->next != NULL)
3486 cur->next->prev = cur->prev;
3487 if (cur->prev != NULL)
3488 cur->prev->next = cur->next;
3489 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003490}
3491
Daniel Veillard2156d432004-03-04 15:59:36 +00003492#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003493/**
3494 * xmlReplaceNode:
3495 * @old: the old node
3496 * @cur: the node
3497 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003498 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003499 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003500 * first unlinked from its existing context.
3501 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003502 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003503 */
3504xmlNodePtr
3505xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00003506 if (old == cur) return(NULL);
Daniel Veillarda03e3652004-11-02 18:45:30 +00003507 if ((old == NULL) || (old->parent == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003508#ifdef DEBUG_TREE
3509 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda03e3652004-11-02 18:45:30 +00003510 "xmlReplaceNode : old == NULL or without parent\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003511#endif
3512 return(NULL);
3513 }
3514 if (cur == NULL) {
3515 xmlUnlinkNode(old);
3516 return(old);
3517 }
3518 if (cur == old) {
3519 return(old);
3520 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003521 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3522#ifdef DEBUG_TREE
3523 xmlGenericError(xmlGenericErrorContext,
3524 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3525#endif
3526 return(old);
3527 }
3528 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3529#ifdef DEBUG_TREE
3530 xmlGenericError(xmlGenericErrorContext,
3531 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3532#endif
3533 return(old);
3534 }
Owen Taylor3473f882001-02-23 17:55:21 +00003535 xmlUnlinkNode(cur);
Daniel Veillard64d7d122005-05-11 18:03:42 +00003536 xmlSetTreeDoc(cur, old->doc);
Owen Taylor3473f882001-02-23 17:55:21 +00003537 cur->parent = old->parent;
3538 cur->next = old->next;
3539 if (cur->next != NULL)
3540 cur->next->prev = cur;
3541 cur->prev = old->prev;
3542 if (cur->prev != NULL)
3543 cur->prev->next = cur;
3544 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003545 if (cur->type == XML_ATTRIBUTE_NODE) {
3546 if (cur->parent->properties == (xmlAttrPtr)old)
3547 cur->parent->properties = ((xmlAttrPtr) cur);
3548 } else {
3549 if (cur->parent->children == old)
3550 cur->parent->children = cur;
3551 if (cur->parent->last == old)
3552 cur->parent->last = cur;
3553 }
Owen Taylor3473f882001-02-23 17:55:21 +00003554 }
3555 old->next = old->prev = NULL;
3556 old->parent = NULL;
3557 return(old);
3558}
Daniel Veillard652327a2003-09-29 18:02:38 +00003559#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003560
3561/************************************************************************
3562 * *
3563 * Copy operations *
3564 * *
3565 ************************************************************************/
3566
3567/**
3568 * xmlCopyNamespace:
3569 * @cur: the namespace
3570 *
3571 * Do a copy of the namespace.
3572 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003573 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003574 */
3575xmlNsPtr
3576xmlCopyNamespace(xmlNsPtr cur) {
3577 xmlNsPtr ret;
3578
3579 if (cur == NULL) return(NULL);
3580 switch (cur->type) {
3581 case XML_LOCAL_NAMESPACE:
3582 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3583 break;
3584 default:
3585#ifdef DEBUG_TREE
3586 xmlGenericError(xmlGenericErrorContext,
3587 "xmlCopyNamespace: invalid type %d\n", cur->type);
3588#endif
3589 return(NULL);
3590 }
3591 return(ret);
3592}
3593
3594/**
3595 * xmlCopyNamespaceList:
3596 * @cur: the first namespace
3597 *
3598 * Do a copy of an namespace list.
3599 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003600 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003601 */
3602xmlNsPtr
3603xmlCopyNamespaceList(xmlNsPtr cur) {
3604 xmlNsPtr ret = NULL;
3605 xmlNsPtr p = NULL,q;
3606
3607 while (cur != NULL) {
3608 q = xmlCopyNamespace(cur);
3609 if (p == NULL) {
3610 ret = p = q;
3611 } else {
3612 p->next = q;
3613 p = q;
3614 }
3615 cur = cur->next;
3616 }
3617 return(ret);
3618}
3619
3620static xmlNodePtr
3621xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
Rob Richards19dc9612005-10-28 16:15:16 +00003622
3623static xmlAttrPtr
3624xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003625 xmlAttrPtr ret;
3626
3627 if (cur == NULL) return(NULL);
3628 if (target != NULL)
3629 ret = xmlNewDocProp(target->doc, cur->name, NULL);
Rob Richards19dc9612005-10-28 16:15:16 +00003630 else if (doc != NULL)
3631 ret = xmlNewDocProp(doc, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003632 else if (cur->parent != NULL)
3633 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3634 else if (cur->children != NULL)
3635 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3636 else
3637 ret = xmlNewDocProp(NULL, cur->name, NULL);
3638 if (ret == NULL) return(NULL);
3639 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003640
Owen Taylor3473f882001-02-23 17:55:21 +00003641 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003642 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003643
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003644 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3645 if (ns == NULL) {
3646 /*
3647 * Humm, we are copying an element whose namespace is defined
3648 * out of the new tree scope. Search it in the original tree
3649 * and add it at the top of the new tree
3650 */
3651 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3652 if (ns != NULL) {
3653 xmlNodePtr root = target;
3654 xmlNodePtr pred = NULL;
3655
3656 while (root->parent != NULL) {
3657 pred = root;
3658 root = root->parent;
3659 }
3660 if (root == (xmlNodePtr) target->doc) {
3661 /* correct possibly cycling above the document elt */
3662 root = pred;
3663 }
3664 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3665 }
3666 } else {
3667 /*
3668 * we have to find something appropriate here since
3669 * we cant be sure, that the namespce we found is identified
3670 * by the prefix
3671 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003672 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003673 /* this is the nice case */
3674 ret->ns = ns;
3675 } else {
3676 /*
3677 * we are in trouble: we need a new reconcilied namespace.
3678 * This is expensive
3679 */
3680 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3681 }
3682 }
3683
Owen Taylor3473f882001-02-23 17:55:21 +00003684 } else
3685 ret->ns = NULL;
3686
3687 if (cur->children != NULL) {
3688 xmlNodePtr tmp;
3689
3690 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3691 ret->last = NULL;
3692 tmp = ret->children;
3693 while (tmp != NULL) {
3694 /* tmp->parent = (xmlNodePtr)ret; */
3695 if (tmp->next == NULL)
3696 ret->last = tmp;
3697 tmp = tmp->next;
3698 }
3699 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003700 /*
3701 * Try to handle IDs
3702 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003703 if ((target!= NULL) && (cur!= NULL) &&
3704 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003705 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3706 if (xmlIsID(cur->doc, cur->parent, cur)) {
3707 xmlChar *id;
3708
3709 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3710 if (id != NULL) {
3711 xmlAddID(NULL, target->doc, id, ret);
3712 xmlFree(id);
3713 }
3714 }
3715 }
Owen Taylor3473f882001-02-23 17:55:21 +00003716 return(ret);
3717}
3718
3719/**
Rob Richards19dc9612005-10-28 16:15:16 +00003720 * xmlCopyProp:
3721 * @target: the element where the attribute will be grafted
3722 * @cur: the attribute
3723 *
3724 * Do a copy of the attribute.
3725 *
3726 * Returns: a new #xmlAttrPtr, or NULL in case of error.
3727 */
3728xmlAttrPtr
3729xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3730 return xmlCopyPropInternal(NULL, target, cur);
3731}
3732
3733/**
Owen Taylor3473f882001-02-23 17:55:21 +00003734 * xmlCopyPropList:
3735 * @target: the element where the attributes will be grafted
3736 * @cur: the first attribute
3737 *
3738 * Do a copy of an attribute list.
3739 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003740 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003741 */
3742xmlAttrPtr
3743xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3744 xmlAttrPtr ret = NULL;
3745 xmlAttrPtr p = NULL,q;
3746
3747 while (cur != NULL) {
3748 q = xmlCopyProp(target, cur);
William M. Brack13dfa872004-09-18 04:52:08 +00003749 if (q == NULL)
3750 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003751 if (p == NULL) {
3752 ret = p = q;
3753 } else {
3754 p->next = q;
3755 q->prev = p;
3756 p = q;
3757 }
3758 cur = cur->next;
3759 }
3760 return(ret);
3761}
3762
3763/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003764 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003765 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003766 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003767 * tricky reason: namespaces. Doing a direct copy of a node
3768 * say RPM:Copyright without changing the namespace pointer to
3769 * something else can produce stale links. One way to do it is
3770 * to keep a reference counter but this doesn't work as soon
3771 * as one move the element or the subtree out of the scope of
3772 * the existing namespace. The actual solution seems to add
3773 * a copy of the namespace at the top of the copied tree if
3774 * not available in the subtree.
3775 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00003776 * The argument "recursive" normally indicates a recursive copy
3777 * of the node with values 0 (no) and 1 (yes). For XInclude,
3778 * however, we allow a value of 2 to indicate copy properties and
3779 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00003780 */
3781
3782static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003783xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00003784 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003785 xmlNodePtr ret;
3786
3787 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003788 switch (node->type) {
3789 case XML_TEXT_NODE:
3790 case XML_CDATA_SECTION_NODE:
3791 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003792 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003793 case XML_ENTITY_REF_NODE:
3794 case XML_ENTITY_NODE:
3795 case XML_PI_NODE:
3796 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003797 case XML_XINCLUDE_START:
3798 case XML_XINCLUDE_END:
3799 break;
3800 case XML_ATTRIBUTE_NODE:
Rob Richards19dc9612005-10-28 16:15:16 +00003801 return((xmlNodePtr) xmlCopyPropInternal(doc, parent, (xmlAttrPtr) node));
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003802 case XML_NAMESPACE_DECL:
3803 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3804
Daniel Veillard39196eb2001-06-19 18:09:42 +00003805 case XML_DOCUMENT_NODE:
3806 case XML_HTML_DOCUMENT_NODE:
3807#ifdef LIBXML_DOCB_ENABLED
3808 case XML_DOCB_DOCUMENT_NODE:
3809#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003810#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00003811 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00003812#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003813 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003814 case XML_NOTATION_NODE:
3815 case XML_DTD_NODE:
3816 case XML_ELEMENT_DECL:
3817 case XML_ATTRIBUTE_DECL:
3818 case XML_ENTITY_DECL:
3819 return(NULL);
3820 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003821
Owen Taylor3473f882001-02-23 17:55:21 +00003822 /*
3823 * Allocate a new node and fill the fields.
3824 */
3825 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3826 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003827 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003828 return(NULL);
3829 }
3830 memset(ret, 0, sizeof(xmlNode));
3831 ret->type = node->type;
3832
3833 ret->doc = doc;
3834 ret->parent = parent;
3835 if (node->name == xmlStringText)
3836 ret->name = xmlStringText;
3837 else if (node->name == xmlStringTextNoenc)
3838 ret->name = xmlStringTextNoenc;
3839 else if (node->name == xmlStringComment)
3840 ret->name = xmlStringComment;
Daniel Veillard03a53c32004-10-26 16:06:51 +00003841 else if (node->name != NULL) {
3842 if ((doc != NULL) && (doc->dict != NULL))
3843 ret->name = xmlDictLookup(doc->dict, node->name, -1);
3844 else
3845 ret->name = xmlStrdup(node->name);
3846 }
Daniel Veillard7db37732001-07-12 01:20:08 +00003847 if ((node->type != XML_ELEMENT_NODE) &&
3848 (node->content != NULL) &&
3849 (node->type != XML_ENTITY_REF_NODE) &&
3850 (node->type != XML_XINCLUDE_END) &&
3851 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003852 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003853 }else{
3854 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003855 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003856 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003857 if (parent != NULL) {
3858 xmlNodePtr tmp;
3859
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003860 /*
3861 * this is a tricky part for the node register thing:
3862 * in case ret does get coalesced in xmlAddChild
3863 * the deregister-node callback is called; so we register ret now already
3864 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003865 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003866 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3867
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003868 tmp = xmlAddChild(parent, ret);
3869 /* node could have coalesced */
3870 if (tmp != ret)
3871 return(tmp);
3872 }
Owen Taylor3473f882001-02-23 17:55:21 +00003873
William M. Brack57e9e912004-03-09 16:19:02 +00003874 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003875 goto out;
Daniel Veillard8874b942005-08-25 13:19:21 +00003876 if ((node->type == XML_ELEMENT_NODE) && (node->nsDef != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00003877 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3878
3879 if (node->ns != NULL) {
3880 xmlNsPtr ns;
3881
3882 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3883 if (ns == NULL) {
3884 /*
3885 * Humm, we are copying an element whose namespace is defined
3886 * out of the new tree scope. Search it in the original tree
3887 * and add it at the top of the new tree
3888 */
3889 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3890 if (ns != NULL) {
3891 xmlNodePtr root = ret;
3892
3893 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003894 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003895 }
3896 } else {
3897 /*
3898 * reference the existing namespace definition in our own tree.
3899 */
3900 ret->ns = ns;
3901 }
3902 }
Daniel Veillard8874b942005-08-25 13:19:21 +00003903 if ((node->type == XML_ELEMENT_NODE) && (node->properties != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00003904 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003905 if (node->type == XML_ENTITY_REF_NODE) {
3906 if ((doc == NULL) || (node->doc != doc)) {
3907 /*
3908 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003909 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003910 * we cannot keep the reference. Try to find it in the
3911 * target document.
3912 */
3913 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3914 } else {
3915 ret->children = node->children;
3916 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003917 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00003918 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003919 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003920 UPDATE_LAST_CHILD_AND_PARENT(ret)
3921 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003922
3923out:
3924 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00003925 if ((parent == NULL) &&
3926 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003927 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003928 return(ret);
3929}
3930
3931static xmlNodePtr
3932xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3933 xmlNodePtr ret = NULL;
3934 xmlNodePtr p = NULL,q;
3935
3936 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003937#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003938 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003939 if (doc == NULL) {
3940 node = node->next;
3941 continue;
3942 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003943 if (doc->intSubset == NULL) {
3944 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3945 q->doc = doc;
3946 q->parent = parent;
3947 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003948 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003949 } else {
3950 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003951 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003952 }
3953 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003954#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003955 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003956 if (ret == NULL) {
3957 q->prev = NULL;
3958 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003959 } else if (p != q) {
3960 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003961 p->next = q;
3962 q->prev = p;
3963 p = q;
3964 }
3965 node = node->next;
3966 }
3967 return(ret);
3968}
3969
3970/**
3971 * xmlCopyNode:
3972 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00003973 * @extended: if 1 do a recursive copy (properties, namespaces and children
3974 * when applicable)
3975 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00003976 *
3977 * Do a copy of the node.
3978 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003979 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003980 */
3981xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003982xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003983 xmlNodePtr ret;
3984
William M. Brack57e9e912004-03-09 16:19:02 +00003985 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00003986 return(ret);
3987}
3988
3989/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003990 * xmlDocCopyNode:
3991 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003992 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00003993 * @extended: if 1 do a recursive copy (properties, namespaces and children
3994 * when applicable)
3995 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00003996 *
3997 * Do a copy of the node to a given document.
3998 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003999 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00004000 */
4001xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00004002xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00004003 xmlNodePtr ret;
4004
William M. Brack57e9e912004-03-09 16:19:02 +00004005 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00004006 return(ret);
4007}
4008
4009/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00004010 * xmlDocCopyNodeList:
4011 * @doc: the target document
4012 * @node: the first node in the list.
4013 *
4014 * Do a recursive copy of the node list.
4015 *
4016 * Returns: a new #xmlNodePtr, or NULL in case of error.
4017 */
4018xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) {
4019 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
4020 return(ret);
4021}
4022
4023/**
Owen Taylor3473f882001-02-23 17:55:21 +00004024 * xmlCopyNodeList:
4025 * @node: the first node in the list.
4026 *
4027 * Do a recursive copy of the node list.
Daniel Veillard03a53c32004-10-26 16:06:51 +00004028 * Use xmlDocCopyNodeList() if possible to ensure string interning.
Owen Taylor3473f882001-02-23 17:55:21 +00004029 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004030 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004031 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00004032xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00004033 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
4034 return(ret);
4035}
4036
Daniel Veillard2156d432004-03-04 15:59:36 +00004037#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004038/**
Owen Taylor3473f882001-02-23 17:55:21 +00004039 * xmlCopyDtd:
4040 * @dtd: the dtd
4041 *
4042 * Do a copy of the dtd.
4043 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004044 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004045 */
4046xmlDtdPtr
4047xmlCopyDtd(xmlDtdPtr dtd) {
4048 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004049 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00004050
4051 if (dtd == NULL) return(NULL);
4052 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4053 if (ret == NULL) return(NULL);
4054 if (dtd->entities != NULL)
4055 ret->entities = (void *) xmlCopyEntitiesTable(
4056 (xmlEntitiesTablePtr) dtd->entities);
4057 if (dtd->notations != NULL)
4058 ret->notations = (void *) xmlCopyNotationTable(
4059 (xmlNotationTablePtr) dtd->notations);
4060 if (dtd->elements != NULL)
4061 ret->elements = (void *) xmlCopyElementTable(
4062 (xmlElementTablePtr) dtd->elements);
4063 if (dtd->attributes != NULL)
4064 ret->attributes = (void *) xmlCopyAttributeTable(
4065 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004066 if (dtd->pentities != NULL)
4067 ret->pentities = (void *) xmlCopyEntitiesTable(
4068 (xmlEntitiesTablePtr) dtd->pentities);
4069
4070 cur = dtd->children;
4071 while (cur != NULL) {
4072 q = NULL;
4073
4074 if (cur->type == XML_ENTITY_DECL) {
4075 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4076 switch (tmp->etype) {
4077 case XML_INTERNAL_GENERAL_ENTITY:
4078 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4079 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4080 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4081 break;
4082 case XML_INTERNAL_PARAMETER_ENTITY:
4083 case XML_EXTERNAL_PARAMETER_ENTITY:
4084 q = (xmlNodePtr)
4085 xmlGetParameterEntityFromDtd(ret, tmp->name);
4086 break;
4087 case XML_INTERNAL_PREDEFINED_ENTITY:
4088 break;
4089 }
4090 } else if (cur->type == XML_ELEMENT_DECL) {
4091 xmlElementPtr tmp = (xmlElementPtr) cur;
4092 q = (xmlNodePtr)
4093 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4094 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4095 xmlAttributePtr tmp = (xmlAttributePtr) cur;
4096 q = (xmlNodePtr)
4097 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4098 } else if (cur->type == XML_COMMENT_NODE) {
4099 q = xmlCopyNode(cur, 0);
4100 }
4101
4102 if (q == NULL) {
4103 cur = cur->next;
4104 continue;
4105 }
4106
4107 if (p == NULL)
4108 ret->children = q;
4109 else
4110 p->next = q;
4111
4112 q->prev = p;
4113 q->parent = (xmlNodePtr) ret;
4114 q->next = NULL;
4115 ret->last = q;
4116 p = q;
4117 cur = cur->next;
4118 }
4119
Owen Taylor3473f882001-02-23 17:55:21 +00004120 return(ret);
4121}
Daniel Veillard2156d432004-03-04 15:59:36 +00004122#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004123
Daniel Veillard2156d432004-03-04 15:59:36 +00004124#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004125/**
4126 * xmlCopyDoc:
4127 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004128 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004129 *
4130 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004131 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004132 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004133 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004134 */
4135xmlDocPtr
4136xmlCopyDoc(xmlDocPtr doc, int recursive) {
4137 xmlDocPtr ret;
4138
4139 if (doc == NULL) return(NULL);
4140 ret = xmlNewDoc(doc->version);
4141 if (ret == NULL) return(NULL);
4142 if (doc->name != NULL)
4143 ret->name = xmlMemStrdup(doc->name);
4144 if (doc->encoding != NULL)
4145 ret->encoding = xmlStrdup(doc->encoding);
Daniel Veillardf59507d2005-01-27 17:26:49 +00004146 if (doc->URL != NULL)
4147 ret->URL = xmlStrdup(doc->URL);
Owen Taylor3473f882001-02-23 17:55:21 +00004148 ret->charset = doc->charset;
4149 ret->compression = doc->compression;
4150 ret->standalone = doc->standalone;
4151 if (!recursive) return(ret);
4152
Daniel Veillardb33c2012001-04-25 12:59:04 +00004153 ret->last = NULL;
4154 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004155#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004156 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004157 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004158 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004159 ret->intSubset->parent = ret;
4160 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004161#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004162 if (doc->oldNs != NULL)
4163 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4164 if (doc->children != NULL) {
4165 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004166
4167 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4168 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004169 ret->last = NULL;
4170 tmp = ret->children;
4171 while (tmp != NULL) {
4172 if (tmp->next == NULL)
4173 ret->last = tmp;
4174 tmp = tmp->next;
4175 }
4176 }
4177 return(ret);
4178}
Daniel Veillard652327a2003-09-29 18:02:38 +00004179#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004180
4181/************************************************************************
4182 * *
4183 * Content access functions *
4184 * *
4185 ************************************************************************/
4186
4187/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004188 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004189 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004190 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004191 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004192 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004193 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004194 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004195 */
4196long
4197xmlGetLineNo(xmlNodePtr node)
4198{
4199 long result = -1;
4200
4201 if (!node)
4202 return result;
Daniel Veillard73da77e2005-08-24 14:05:37 +00004203 if ((node->type == XML_ELEMENT_NODE) ||
4204 (node->type == XML_TEXT_NODE) ||
4205 (node->type == XML_COMMENT_NODE) ||
4206 (node->type == XML_PI_NODE))
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004207 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004208 else if ((node->prev != NULL) &&
4209 ((node->prev->type == XML_ELEMENT_NODE) ||
Daniel Veillard73da77e2005-08-24 14:05:37 +00004210 (node->prev->type == XML_TEXT_NODE) ||
4211 (node->prev->type == XML_COMMENT_NODE) ||
4212 (node->prev->type == XML_PI_NODE)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004213 result = xmlGetLineNo(node->prev);
4214 else if ((node->parent != NULL) &&
Daniel Veillard73da77e2005-08-24 14:05:37 +00004215 (node->parent->type == XML_ELEMENT_NODE))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004216 result = xmlGetLineNo(node->parent);
4217
4218 return result;
4219}
4220
Daniel Veillard2156d432004-03-04 15:59:36 +00004221#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004222/**
4223 * xmlGetNodePath:
4224 * @node: a node
4225 *
4226 * Build a structure based Path for the given node
4227 *
4228 * Returns the new path or NULL in case of error. The caller must free
4229 * the returned string
4230 */
4231xmlChar *
4232xmlGetNodePath(xmlNodePtr node)
4233{
4234 xmlNodePtr cur, tmp, next;
4235 xmlChar *buffer = NULL, *temp;
4236 size_t buf_len;
4237 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004238 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004239 const char *name;
4240 char nametemp[100];
4241 int occur = 0;
4242
4243 if (node == NULL)
4244 return (NULL);
4245
4246 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004247 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004248 if (buffer == NULL) {
4249 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004250 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004251 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004252 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004253 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004254 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004255 xmlFree(buffer);
4256 return (NULL);
4257 }
4258
4259 buffer[0] = 0;
4260 cur = node;
4261 do {
4262 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004263 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004264 occur = 0;
4265 if ((cur->type == XML_DOCUMENT_NODE) ||
4266 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4267 if (buffer[0] == '/')
4268 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004269 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004270 next = NULL;
4271 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004272 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004273 name = (const char *) cur->name;
4274 if (cur->ns) {
William M. Brack84d83e32003-12-23 03:45:17 +00004275 if (cur->ns->prefix != NULL)
William M. Brack13dfa872004-09-18 04:52:08 +00004276 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4277 (char *)cur->ns->prefix, (char *)cur->name);
William M. Brack84d83e32003-12-23 03:45:17 +00004278 else
William M. Brack13dfa872004-09-18 04:52:08 +00004279 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4280 (char *)cur->name);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004281 nametemp[sizeof(nametemp) - 1] = 0;
4282 name = nametemp;
4283 }
4284 next = cur->parent;
4285
4286 /*
4287 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004288 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004289 */
4290 tmp = cur->prev;
4291 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004292 if ((tmp->type == XML_ELEMENT_NODE) &&
Daniel Veillard0996a162005-02-05 14:00:10 +00004293 (xmlStrEqual(cur->name, tmp->name)) &&
4294 ((tmp->ns == cur->ns) ||
4295 ((tmp->ns != NULL) && (cur->ns != NULL) &&
4296 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004297 occur++;
4298 tmp = tmp->prev;
4299 }
4300 if (occur == 0) {
4301 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004302 while (tmp != NULL && occur == 0) {
4303 if ((tmp->type == XML_ELEMENT_NODE) &&
Daniel Veillard0996a162005-02-05 14:00:10 +00004304 (xmlStrEqual(cur->name, tmp->name)) &&
4305 ((tmp->ns == cur->ns) ||
4306 ((tmp->ns != NULL) && (cur->ns != NULL) &&
4307 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004308 occur++;
4309 tmp = tmp->next;
4310 }
4311 if (occur != 0)
4312 occur = 1;
4313 } else
4314 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004315 } else if (cur->type == XML_COMMENT_NODE) {
4316 sep = "/";
4317 name = "comment()";
4318 next = cur->parent;
4319
4320 /*
4321 * Thumbler index computation
4322 */
4323 tmp = cur->prev;
4324 while (tmp != NULL) {
4325 if (tmp->type == XML_COMMENT_NODE)
4326 occur++;
4327 tmp = tmp->prev;
4328 }
4329 if (occur == 0) {
4330 tmp = cur->next;
4331 while (tmp != NULL && occur == 0) {
4332 if (tmp->type == XML_COMMENT_NODE)
4333 occur++;
4334 tmp = tmp->next;
4335 }
4336 if (occur != 0)
4337 occur = 1;
4338 } else
4339 occur++;
4340 } else if ((cur->type == XML_TEXT_NODE) ||
4341 (cur->type == XML_CDATA_SECTION_NODE)) {
4342 sep = "/";
4343 name = "text()";
4344 next = cur->parent;
4345
4346 /*
4347 * Thumbler index computation
4348 */
4349 tmp = cur->prev;
4350 while (tmp != NULL) {
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004351 if ((tmp->type == XML_TEXT_NODE) ||
4352 (tmp->type == XML_CDATA_SECTION_NODE))
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004353 occur++;
4354 tmp = tmp->prev;
4355 }
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004356 /*
4357 * Evaluate if this is the only text- or CDATA-section-node;
4358 * if yes, then we'll get "text()", otherwise "text()[1]".
4359 */
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004360 if (occur == 0) {
4361 tmp = cur->next;
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004362 while (tmp != NULL) {
4363 if ((tmp->type == XML_TEXT_NODE) ||
4364 (tmp->type == XML_CDATA_SECTION_NODE))
4365 {
4366 occur = 1;
4367 break;
4368 }
4369 tmp = tmp->next;
4370 }
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004371 } else
4372 occur++;
4373 } else if (cur->type == XML_PI_NODE) {
4374 sep = "/";
4375 snprintf(nametemp, sizeof(nametemp) - 1,
William M. Brack13dfa872004-09-18 04:52:08 +00004376 "processing-instruction('%s')", (char *)cur->name);
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004377 nametemp[sizeof(nametemp) - 1] = 0;
4378 name = nametemp;
4379
4380 next = cur->parent;
4381
4382 /*
4383 * Thumbler index computation
4384 */
4385 tmp = cur->prev;
4386 while (tmp != NULL) {
4387 if ((tmp->type == XML_PI_NODE) &&
4388 (xmlStrEqual(cur->name, tmp->name)))
4389 occur++;
4390 tmp = tmp->prev;
4391 }
4392 if (occur == 0) {
4393 tmp = cur->next;
4394 while (tmp != NULL && occur == 0) {
4395 if ((tmp->type == XML_PI_NODE) &&
4396 (xmlStrEqual(cur->name, tmp->name)))
4397 occur++;
4398 tmp = tmp->next;
4399 }
4400 if (occur != 0)
4401 occur = 1;
4402 } else
4403 occur++;
4404
Daniel Veillard8faa7832001-11-26 15:58:08 +00004405 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004406 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004407 name = (const char *) (((xmlAttrPtr) cur)->name);
Daniel Veillard365c8062005-07-19 11:31:55 +00004408 if (cur->ns) {
4409 if (cur->ns->prefix != NULL)
4410 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4411 (char *)cur->ns->prefix, (char *)cur->name);
4412 else
4413 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4414 (char *)cur->name);
4415 nametemp[sizeof(nametemp) - 1] = 0;
4416 name = nametemp;
4417 }
Daniel Veillard8faa7832001-11-26 15:58:08 +00004418 next = ((xmlAttrPtr) cur)->parent;
4419 } else {
4420 next = cur->parent;
4421 }
4422
4423 /*
4424 * Make sure there is enough room
4425 */
4426 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4427 buf_len =
4428 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4429 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4430 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004431 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004432 xmlFree(buf);
4433 xmlFree(buffer);
4434 return (NULL);
4435 }
4436 buffer = temp;
4437 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4438 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004439 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004440 xmlFree(buf);
4441 xmlFree(buffer);
4442 return (NULL);
4443 }
4444 buf = temp;
4445 }
4446 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004447 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004448 sep, name, (char *) buffer);
4449 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004450 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004451 sep, name, occur, (char *) buffer);
William M. Brack13dfa872004-09-18 04:52:08 +00004452 snprintf((char *) buffer, buf_len, "%s", (char *)buf);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004453 cur = next;
4454 } while (cur != NULL);
4455 xmlFree(buf);
4456 return (buffer);
4457}
Daniel Veillard652327a2003-09-29 18:02:38 +00004458#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004459
4460/**
Owen Taylor3473f882001-02-23 17:55:21 +00004461 * xmlDocGetRootElement:
4462 * @doc: the document
4463 *
4464 * Get the root element of the document (doc->children is a list
4465 * containing possibly comments, PIs, etc ...).
4466 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004467 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004468 */
4469xmlNodePtr
4470xmlDocGetRootElement(xmlDocPtr doc) {
4471 xmlNodePtr ret;
4472
4473 if (doc == NULL) return(NULL);
4474 ret = doc->children;
4475 while (ret != NULL) {
4476 if (ret->type == XML_ELEMENT_NODE)
4477 return(ret);
4478 ret = ret->next;
4479 }
4480 return(ret);
4481}
4482
Daniel Veillard2156d432004-03-04 15:59:36 +00004483#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004484/**
4485 * xmlDocSetRootElement:
4486 * @doc: the document
4487 * @root: the new document root element
4488 *
4489 * Set the root element of the document (doc->children is a list
4490 * containing possibly comments, PIs, etc ...).
4491 *
4492 * Returns the old root element if any was found
4493 */
4494xmlNodePtr
4495xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4496 xmlNodePtr old = NULL;
4497
4498 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004499 if (root == NULL)
4500 return(NULL);
4501 xmlUnlinkNode(root);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00004502 xmlSetTreeDoc(root, doc);
Daniel Veillardc575b992002-02-08 13:28:40 +00004503 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004504 old = doc->children;
4505 while (old != NULL) {
4506 if (old->type == XML_ELEMENT_NODE)
4507 break;
4508 old = old->next;
4509 }
4510 if (old == NULL) {
4511 if (doc->children == NULL) {
4512 doc->children = root;
4513 doc->last = root;
4514 } else {
4515 xmlAddSibling(doc->children, root);
4516 }
4517 } else {
4518 xmlReplaceNode(old, root);
4519 }
4520 return(old);
4521}
Daniel Veillard2156d432004-03-04 15:59:36 +00004522#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004523
Daniel Veillard2156d432004-03-04 15:59:36 +00004524#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004525/**
4526 * xmlNodeSetLang:
4527 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004528 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004529 *
4530 * Set the language of a node, i.e. the values of the xml:lang
4531 * attribute.
4532 */
4533void
4534xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004535 xmlNsPtr ns;
4536
Owen Taylor3473f882001-02-23 17:55:21 +00004537 if (cur == NULL) return;
4538 switch(cur->type) {
4539 case XML_TEXT_NODE:
4540 case XML_CDATA_SECTION_NODE:
4541 case XML_COMMENT_NODE:
4542 case XML_DOCUMENT_NODE:
4543 case XML_DOCUMENT_TYPE_NODE:
4544 case XML_DOCUMENT_FRAG_NODE:
4545 case XML_NOTATION_NODE:
4546 case XML_HTML_DOCUMENT_NODE:
4547 case XML_DTD_NODE:
4548 case XML_ELEMENT_DECL:
4549 case XML_ATTRIBUTE_DECL:
4550 case XML_ENTITY_DECL:
4551 case XML_PI_NODE:
4552 case XML_ENTITY_REF_NODE:
4553 case XML_ENTITY_NODE:
4554 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004555#ifdef LIBXML_DOCB_ENABLED
4556 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004557#endif
4558 case XML_XINCLUDE_START:
4559 case XML_XINCLUDE_END:
4560 return;
4561 case XML_ELEMENT_NODE:
4562 case XML_ATTRIBUTE_NODE:
4563 break;
4564 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004565 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4566 if (ns == NULL)
4567 return;
4568 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004569}
Daniel Veillard652327a2003-09-29 18:02:38 +00004570#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004571
4572/**
4573 * xmlNodeGetLang:
4574 * @cur: the node being checked
4575 *
4576 * Searches the language of a node, i.e. the values of the xml:lang
4577 * attribute or the one carried by the nearest ancestor.
4578 *
4579 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004580 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004581 */
4582xmlChar *
4583xmlNodeGetLang(xmlNodePtr cur) {
4584 xmlChar *lang;
4585
4586 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004587 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004588 if (lang != NULL)
4589 return(lang);
4590 cur = cur->parent;
4591 }
4592 return(NULL);
4593}
4594
4595
Daniel Veillard652327a2003-09-29 18:02:38 +00004596#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004597/**
4598 * xmlNodeSetSpacePreserve:
4599 * @cur: the node being changed
4600 * @val: the xml:space value ("0": default, 1: "preserve")
4601 *
4602 * Set (or reset) the space preserving behaviour of a node, i.e. the
4603 * value of the xml:space attribute.
4604 */
4605void
4606xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004607 xmlNsPtr ns;
4608
Owen Taylor3473f882001-02-23 17:55:21 +00004609 if (cur == NULL) return;
4610 switch(cur->type) {
4611 case XML_TEXT_NODE:
4612 case XML_CDATA_SECTION_NODE:
4613 case XML_COMMENT_NODE:
4614 case XML_DOCUMENT_NODE:
4615 case XML_DOCUMENT_TYPE_NODE:
4616 case XML_DOCUMENT_FRAG_NODE:
4617 case XML_NOTATION_NODE:
4618 case XML_HTML_DOCUMENT_NODE:
4619 case XML_DTD_NODE:
4620 case XML_ELEMENT_DECL:
4621 case XML_ATTRIBUTE_DECL:
4622 case XML_ENTITY_DECL:
4623 case XML_PI_NODE:
4624 case XML_ENTITY_REF_NODE:
4625 case XML_ENTITY_NODE:
4626 case XML_NAMESPACE_DECL:
4627 case XML_XINCLUDE_START:
4628 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004629#ifdef LIBXML_DOCB_ENABLED
4630 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004631#endif
4632 return;
4633 case XML_ELEMENT_NODE:
4634 case XML_ATTRIBUTE_NODE:
4635 break;
4636 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004637 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4638 if (ns == NULL)
4639 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004640 switch (val) {
4641 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004642 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004643 break;
4644 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004645 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004646 break;
4647 }
4648}
Daniel Veillard652327a2003-09-29 18:02:38 +00004649#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004650
4651/**
4652 * xmlNodeGetSpacePreserve:
4653 * @cur: the node being checked
4654 *
4655 * Searches the space preserving behaviour of a node, i.e. the values
4656 * of the xml:space attribute or the one carried by the nearest
4657 * ancestor.
4658 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004659 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004660 */
4661int
4662xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4663 xmlChar *space;
4664
4665 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004666 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004667 if (space != NULL) {
4668 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4669 xmlFree(space);
4670 return(1);
4671 }
4672 if (xmlStrEqual(space, BAD_CAST "default")) {
4673 xmlFree(space);
4674 return(0);
4675 }
4676 xmlFree(space);
4677 }
4678 cur = cur->parent;
4679 }
4680 return(-1);
4681}
4682
Daniel Veillard652327a2003-09-29 18:02:38 +00004683#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004684/**
4685 * xmlNodeSetName:
4686 * @cur: the node being changed
4687 * @name: the new tag name
4688 *
4689 * Set (or reset) the name of a node.
4690 */
4691void
4692xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00004693 xmlDocPtr doc;
4694 xmlDictPtr dict;
4695
Owen Taylor3473f882001-02-23 17:55:21 +00004696 if (cur == NULL) return;
4697 if (name == NULL) return;
4698 switch(cur->type) {
4699 case XML_TEXT_NODE:
4700 case XML_CDATA_SECTION_NODE:
4701 case XML_COMMENT_NODE:
4702 case XML_DOCUMENT_TYPE_NODE:
4703 case XML_DOCUMENT_FRAG_NODE:
4704 case XML_NOTATION_NODE:
4705 case XML_HTML_DOCUMENT_NODE:
4706 case XML_NAMESPACE_DECL:
4707 case XML_XINCLUDE_START:
4708 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004709#ifdef LIBXML_DOCB_ENABLED
4710 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004711#endif
4712 return;
4713 case XML_ELEMENT_NODE:
4714 case XML_ATTRIBUTE_NODE:
4715 case XML_PI_NODE:
4716 case XML_ENTITY_REF_NODE:
4717 case XML_ENTITY_NODE:
4718 case XML_DTD_NODE:
4719 case XML_DOCUMENT_NODE:
4720 case XML_ELEMENT_DECL:
4721 case XML_ATTRIBUTE_DECL:
4722 case XML_ENTITY_DECL:
4723 break;
4724 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00004725 doc = cur->doc;
4726 if (doc != NULL)
4727 dict = doc->dict;
4728 else
4729 dict = NULL;
4730 if (dict != NULL) {
4731 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
4732 xmlFree((xmlChar *) cur->name);
4733 cur->name = xmlDictLookup(dict, name, -1);
4734 } else {
4735 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4736 cur->name = xmlStrdup(name);
4737 }
Owen Taylor3473f882001-02-23 17:55:21 +00004738}
Daniel Veillard2156d432004-03-04 15:59:36 +00004739#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004740
Daniel Veillard2156d432004-03-04 15:59:36 +00004741#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004742/**
4743 * xmlNodeSetBase:
4744 * @cur: the node being changed
4745 * @uri: the new base URI
4746 *
4747 * Set (or reset) the base URI of a node, i.e. the value of the
4748 * xml:base attribute.
4749 */
4750void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004751xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004752 xmlNsPtr ns;
4753
Owen Taylor3473f882001-02-23 17:55:21 +00004754 if (cur == NULL) return;
4755 switch(cur->type) {
4756 case XML_TEXT_NODE:
4757 case XML_CDATA_SECTION_NODE:
4758 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004759 case XML_DOCUMENT_TYPE_NODE:
4760 case XML_DOCUMENT_FRAG_NODE:
4761 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004762 case XML_DTD_NODE:
4763 case XML_ELEMENT_DECL:
4764 case XML_ATTRIBUTE_DECL:
4765 case XML_ENTITY_DECL:
4766 case XML_PI_NODE:
4767 case XML_ENTITY_REF_NODE:
4768 case XML_ENTITY_NODE:
4769 case XML_NAMESPACE_DECL:
4770 case XML_XINCLUDE_START:
4771 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004772 return;
4773 case XML_ELEMENT_NODE:
4774 case XML_ATTRIBUTE_NODE:
4775 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004776 case XML_DOCUMENT_NODE:
4777#ifdef LIBXML_DOCB_ENABLED
4778 case XML_DOCB_DOCUMENT_NODE:
4779#endif
4780 case XML_HTML_DOCUMENT_NODE: {
4781 xmlDocPtr doc = (xmlDocPtr) cur;
4782
4783 if (doc->URL != NULL)
4784 xmlFree((xmlChar *) doc->URL);
4785 if (uri == NULL)
4786 doc->URL = NULL;
4787 else
4788 doc->URL = xmlStrdup(uri);
4789 return;
4790 }
Owen Taylor3473f882001-02-23 17:55:21 +00004791 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004792
4793 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4794 if (ns == NULL)
4795 return;
4796 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004797}
Daniel Veillard652327a2003-09-29 18:02:38 +00004798#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004799
4800/**
Owen Taylor3473f882001-02-23 17:55:21 +00004801 * xmlNodeGetBase:
4802 * @doc: the document the node pertains to
4803 * @cur: the node being checked
4804 *
4805 * Searches for the BASE URL. The code should work on both XML
4806 * and HTML document even if base mechanisms are completely different.
4807 * It returns the base as defined in RFC 2396 sections
4808 * 5.1.1. Base URI within Document Content
4809 * and
4810 * 5.1.2. Base URI from the Encapsulating Entity
4811 * However it does not return the document base (5.1.3), use
4812 * xmlDocumentGetBase() for this
4813 *
4814 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004815 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004816 */
4817xmlChar *
4818xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004819 xmlChar *oldbase = NULL;
4820 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004821
4822 if ((cur == NULL) && (doc == NULL))
4823 return(NULL);
4824 if (doc == NULL) doc = cur->doc;
4825 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4826 cur = doc->children;
4827 while ((cur != NULL) && (cur->name != NULL)) {
4828 if (cur->type != XML_ELEMENT_NODE) {
4829 cur = cur->next;
4830 continue;
4831 }
4832 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4833 cur = cur->children;
4834 continue;
4835 }
4836 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4837 cur = cur->children;
4838 continue;
4839 }
4840 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4841 return(xmlGetProp(cur, BAD_CAST "href"));
4842 }
4843 cur = cur->next;
4844 }
4845 return(NULL);
4846 }
4847 while (cur != NULL) {
4848 if (cur->type == XML_ENTITY_DECL) {
4849 xmlEntityPtr ent = (xmlEntityPtr) cur;
4850 return(xmlStrdup(ent->URI));
4851 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004852 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004853 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004854 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004855 if (oldbase != NULL) {
4856 newbase = xmlBuildURI(oldbase, base);
4857 if (newbase != NULL) {
4858 xmlFree(oldbase);
4859 xmlFree(base);
4860 oldbase = newbase;
4861 } else {
4862 xmlFree(oldbase);
4863 xmlFree(base);
4864 return(NULL);
4865 }
4866 } else {
4867 oldbase = base;
4868 }
4869 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4870 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4871 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4872 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004873 }
4874 }
Owen Taylor3473f882001-02-23 17:55:21 +00004875 cur = cur->parent;
4876 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004877 if ((doc != NULL) && (doc->URL != NULL)) {
4878 if (oldbase == NULL)
4879 return(xmlStrdup(doc->URL));
4880 newbase = xmlBuildURI(oldbase, doc->URL);
4881 xmlFree(oldbase);
4882 return(newbase);
4883 }
4884 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004885}
4886
4887/**
Daniel Veillard78697292003-10-19 20:44:43 +00004888 * xmlNodeBufGetContent:
4889 * @buffer: a buffer
4890 * @cur: the node being read
4891 *
4892 * Read the value of a node @cur, this can be either the text carried
4893 * directly by this node if it's a TEXT node or the aggregate string
4894 * of the values carried by this node child's (TEXT and ENTITY_REF).
4895 * Entity references are substituted.
4896 * Fills up the buffer @buffer with this value
4897 *
4898 * Returns 0 in case of success and -1 in case of error.
4899 */
4900int
4901xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4902{
4903 if ((cur == NULL) || (buffer == NULL)) return(-1);
4904 switch (cur->type) {
4905 case XML_CDATA_SECTION_NODE:
4906 case XML_TEXT_NODE:
4907 xmlBufferCat(buffer, cur->content);
4908 break;
4909 case XML_DOCUMENT_FRAG_NODE:
4910 case XML_ELEMENT_NODE:{
4911 xmlNodePtr tmp = cur;
4912
4913 while (tmp != NULL) {
4914 switch (tmp->type) {
4915 case XML_CDATA_SECTION_NODE:
4916 case XML_TEXT_NODE:
4917 if (tmp->content != NULL)
4918 xmlBufferCat(buffer, tmp->content);
4919 break;
4920 case XML_ENTITY_REF_NODE:
Rob Richards77b92ff2005-12-20 15:55:14 +00004921 xmlNodeBufGetContent(buffer, tmp);
4922 break;
Daniel Veillard78697292003-10-19 20:44:43 +00004923 default:
4924 break;
4925 }
4926 /*
4927 * Skip to next node
4928 */
4929 if (tmp->children != NULL) {
4930 if (tmp->children->type != XML_ENTITY_DECL) {
4931 tmp = tmp->children;
4932 continue;
4933 }
4934 }
4935 if (tmp == cur)
4936 break;
4937
4938 if (tmp->next != NULL) {
4939 tmp = tmp->next;
4940 continue;
4941 }
4942
4943 do {
4944 tmp = tmp->parent;
4945 if (tmp == NULL)
4946 break;
4947 if (tmp == cur) {
4948 tmp = NULL;
4949 break;
4950 }
4951 if (tmp->next != NULL) {
4952 tmp = tmp->next;
4953 break;
4954 }
4955 } while (tmp != NULL);
4956 }
4957 break;
4958 }
4959 case XML_ATTRIBUTE_NODE:{
4960 xmlAttrPtr attr = (xmlAttrPtr) cur;
4961 xmlNodePtr tmp = attr->children;
4962
4963 while (tmp != NULL) {
4964 if (tmp->type == XML_TEXT_NODE)
4965 xmlBufferCat(buffer, tmp->content);
4966 else
4967 xmlNodeBufGetContent(buffer, tmp);
4968 tmp = tmp->next;
4969 }
4970 break;
4971 }
4972 case XML_COMMENT_NODE:
4973 case XML_PI_NODE:
4974 xmlBufferCat(buffer, cur->content);
4975 break;
4976 case XML_ENTITY_REF_NODE:{
4977 xmlEntityPtr ent;
4978 xmlNodePtr tmp;
4979
4980 /* lookup entity declaration */
4981 ent = xmlGetDocEntity(cur->doc, cur->name);
4982 if (ent == NULL)
4983 return(-1);
4984
4985 /* an entity content can be any "well balanced chunk",
4986 * i.e. the result of the content [43] production:
4987 * http://www.w3.org/TR/REC-xml#NT-content
4988 * -> we iterate through child nodes and recursive call
4989 * xmlNodeGetContent() which handles all possible node types */
4990 tmp = ent->children;
4991 while (tmp) {
4992 xmlNodeBufGetContent(buffer, tmp);
4993 tmp = tmp->next;
4994 }
4995 break;
4996 }
4997 case XML_ENTITY_NODE:
4998 case XML_DOCUMENT_TYPE_NODE:
4999 case XML_NOTATION_NODE:
5000 case XML_DTD_NODE:
5001 case XML_XINCLUDE_START:
5002 case XML_XINCLUDE_END:
5003 break;
5004 case XML_DOCUMENT_NODE:
5005#ifdef LIBXML_DOCB_ENABLED
5006 case XML_DOCB_DOCUMENT_NODE:
5007#endif
5008 case XML_HTML_DOCUMENT_NODE:
5009 cur = cur->children;
5010 while (cur!= NULL) {
5011 if ((cur->type == XML_ELEMENT_NODE) ||
5012 (cur->type == XML_TEXT_NODE) ||
5013 (cur->type == XML_CDATA_SECTION_NODE)) {
5014 xmlNodeBufGetContent(buffer, cur);
5015 }
5016 cur = cur->next;
5017 }
5018 break;
5019 case XML_NAMESPACE_DECL:
5020 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
5021 break;
5022 case XML_ELEMENT_DECL:
5023 case XML_ATTRIBUTE_DECL:
5024 case XML_ENTITY_DECL:
5025 break;
5026 }
5027 return(0);
5028}
5029/**
Owen Taylor3473f882001-02-23 17:55:21 +00005030 * xmlNodeGetContent:
5031 * @cur: the node being read
5032 *
5033 * Read the value of a node, this can be either the text carried
5034 * directly by this node if it's a TEXT node or the aggregate string
5035 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00005036 * Entity references are substituted.
5037 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005038 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005039 */
5040xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00005041xmlNodeGetContent(xmlNodePtr cur)
5042{
5043 if (cur == NULL)
5044 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005045 switch (cur->type) {
5046 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005047 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00005048 xmlBufferPtr buffer;
5049 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00005050
Daniel Veillard814a76d2003-01-23 18:24:20 +00005051 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00005052 if (buffer == NULL)
5053 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00005054 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005055 ret = buffer->content;
5056 buffer->content = NULL;
5057 xmlBufferFree(buffer);
5058 return (ret);
5059 }
5060 case XML_ATTRIBUTE_NODE:{
5061 xmlAttrPtr attr = (xmlAttrPtr) cur;
5062
5063 if (attr->parent != NULL)
5064 return (xmlNodeListGetString
5065 (attr->parent->doc, attr->children, 1));
5066 else
5067 return (xmlNodeListGetString(NULL, attr->children, 1));
5068 break;
5069 }
Owen Taylor3473f882001-02-23 17:55:21 +00005070 case XML_COMMENT_NODE:
5071 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005072 if (cur->content != NULL)
5073 return (xmlStrdup(cur->content));
5074 return (NULL);
5075 case XML_ENTITY_REF_NODE:{
5076 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00005077 xmlBufferPtr buffer;
5078 xmlChar *ret;
5079
5080 /* lookup entity declaration */
5081 ent = xmlGetDocEntity(cur->doc, cur->name);
5082 if (ent == NULL)
5083 return (NULL);
5084
5085 buffer = xmlBufferCreate();
5086 if (buffer == NULL)
5087 return (NULL);
5088
Daniel Veillardc4696922003-10-19 21:47:14 +00005089 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005090
5091 ret = buffer->content;
5092 buffer->content = NULL;
5093 xmlBufferFree(buffer);
5094 return (ret);
5095 }
Owen Taylor3473f882001-02-23 17:55:21 +00005096 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005097 case XML_DOCUMENT_TYPE_NODE:
5098 case XML_NOTATION_NODE:
5099 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005100 case XML_XINCLUDE_START:
5101 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00005102 return (NULL);
5103 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005104#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005105 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005106#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005107 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00005108 xmlBufferPtr buffer;
5109 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005110
Daniel Veillardc4696922003-10-19 21:47:14 +00005111 buffer = xmlBufferCreate();
5112 if (buffer == NULL)
5113 return (NULL);
5114
5115 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5116
5117 ret = buffer->content;
5118 buffer->content = NULL;
5119 xmlBufferFree(buffer);
5120 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005121 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005122 case XML_NAMESPACE_DECL: {
5123 xmlChar *tmp;
5124
5125 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5126 return (tmp);
5127 }
Owen Taylor3473f882001-02-23 17:55:21 +00005128 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005129 /* TODO !!! */
5130 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005131 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005132 /* TODO !!! */
5133 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005134 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005135 /* TODO !!! */
5136 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005137 case XML_CDATA_SECTION_NODE:
5138 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005139 if (cur->content != NULL)
5140 return (xmlStrdup(cur->content));
5141 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005142 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005143 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005144}
Daniel Veillard652327a2003-09-29 18:02:38 +00005145
Owen Taylor3473f882001-02-23 17:55:21 +00005146/**
5147 * xmlNodeSetContent:
5148 * @cur: the node being modified
5149 * @content: the new value of the content
5150 *
5151 * Replace the content of a node.
5152 */
5153void
5154xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5155 if (cur == NULL) {
5156#ifdef DEBUG_TREE
5157 xmlGenericError(xmlGenericErrorContext,
5158 "xmlNodeSetContent : node == NULL\n");
5159#endif
5160 return;
5161 }
5162 switch (cur->type) {
5163 case XML_DOCUMENT_FRAG_NODE:
5164 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005165 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005166 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5167 cur->children = xmlStringGetNodeList(cur->doc, content);
5168 UPDATE_LAST_CHILD_AND_PARENT(cur)
5169 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005170 case XML_TEXT_NODE:
5171 case XML_CDATA_SECTION_NODE:
5172 case XML_ENTITY_REF_NODE:
5173 case XML_ENTITY_NODE:
5174 case XML_PI_NODE:
5175 case XML_COMMENT_NODE:
Daniel Veillard8874b942005-08-25 13:19:21 +00005176 if ((cur->content != NULL) &&
5177 (cur->content != (xmlChar *) &(cur->properties))) {
William M. Brack7762bb12004-01-04 14:49:01 +00005178 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
Daniel Veillardc587bce2005-05-10 15:28:08 +00005179 (xmlDictOwns(cur->doc->dict, cur->content))))
William M. Brack7762bb12004-01-04 14:49:01 +00005180 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005181 }
5182 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5183 cur->last = cur->children = NULL;
5184 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005185 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005186 } else
5187 cur->content = NULL;
Daniel Veillard8874b942005-08-25 13:19:21 +00005188 cur->properties = NULL;
5189 cur->nsDef = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00005190 break;
5191 case XML_DOCUMENT_NODE:
5192 case XML_HTML_DOCUMENT_NODE:
5193 case XML_DOCUMENT_TYPE_NODE:
5194 case XML_XINCLUDE_START:
5195 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005196#ifdef LIBXML_DOCB_ENABLED
5197 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005198#endif
5199 break;
5200 case XML_NOTATION_NODE:
5201 break;
5202 case XML_DTD_NODE:
5203 break;
5204 case XML_NAMESPACE_DECL:
5205 break;
5206 case XML_ELEMENT_DECL:
5207 /* TODO !!! */
5208 break;
5209 case XML_ATTRIBUTE_DECL:
5210 /* TODO !!! */
5211 break;
5212 case XML_ENTITY_DECL:
5213 /* TODO !!! */
5214 break;
5215 }
5216}
5217
Daniel Veillard652327a2003-09-29 18:02:38 +00005218#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005219/**
5220 * xmlNodeSetContentLen:
5221 * @cur: the node being modified
5222 * @content: the new value of the content
5223 * @len: the size of @content
5224 *
5225 * Replace the content of a node.
5226 */
5227void
5228xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5229 if (cur == NULL) {
5230#ifdef DEBUG_TREE
5231 xmlGenericError(xmlGenericErrorContext,
5232 "xmlNodeSetContentLen : node == NULL\n");
5233#endif
5234 return;
5235 }
5236 switch (cur->type) {
5237 case XML_DOCUMENT_FRAG_NODE:
5238 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005239 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005240 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5241 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5242 UPDATE_LAST_CHILD_AND_PARENT(cur)
5243 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005244 case XML_TEXT_NODE:
5245 case XML_CDATA_SECTION_NODE:
5246 case XML_ENTITY_REF_NODE:
5247 case XML_ENTITY_NODE:
5248 case XML_PI_NODE:
5249 case XML_COMMENT_NODE:
5250 case XML_NOTATION_NODE:
Daniel Veillard8874b942005-08-25 13:19:21 +00005251 if ((cur->content != NULL) &&
5252 (cur->content != (xmlChar *) &(cur->properties))) {
5253 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5254 (xmlDictOwns(cur->doc->dict, cur->content))))
5255 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005256 }
5257 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5258 cur->children = cur->last = NULL;
5259 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005260 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005261 } else
5262 cur->content = NULL;
Daniel Veillard8874b942005-08-25 13:19:21 +00005263 cur->properties = NULL;
5264 cur->nsDef = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00005265 break;
5266 case XML_DOCUMENT_NODE:
5267 case XML_DTD_NODE:
5268 case XML_HTML_DOCUMENT_NODE:
5269 case XML_DOCUMENT_TYPE_NODE:
5270 case XML_NAMESPACE_DECL:
5271 case XML_XINCLUDE_START:
5272 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005273#ifdef LIBXML_DOCB_ENABLED
5274 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005275#endif
5276 break;
5277 case XML_ELEMENT_DECL:
5278 /* TODO !!! */
5279 break;
5280 case XML_ATTRIBUTE_DECL:
5281 /* TODO !!! */
5282 break;
5283 case XML_ENTITY_DECL:
5284 /* TODO !!! */
5285 break;
5286 }
5287}
Daniel Veillard652327a2003-09-29 18:02:38 +00005288#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005289
5290/**
5291 * xmlNodeAddContentLen:
5292 * @cur: the node being modified
5293 * @content: extra content
5294 * @len: the size of @content
5295 *
5296 * Append the extra substring to the node content.
5297 */
5298void
5299xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5300 if (cur == NULL) {
5301#ifdef DEBUG_TREE
5302 xmlGenericError(xmlGenericErrorContext,
5303 "xmlNodeAddContentLen : node == NULL\n");
5304#endif
5305 return;
5306 }
5307 if (len <= 0) return;
5308 switch (cur->type) {
5309 case XML_DOCUMENT_FRAG_NODE:
5310 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005311 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005312
Daniel Veillard7db37732001-07-12 01:20:08 +00005313 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005314 newNode = xmlNewTextLen(content, len);
5315 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005316 tmp = xmlAddChild(cur, newNode);
5317 if (tmp != newNode)
5318 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005319 if ((last != NULL) && (last->next == newNode)) {
5320 xmlTextMerge(last, newNode);
5321 }
5322 }
5323 break;
5324 }
5325 case XML_ATTRIBUTE_NODE:
5326 break;
5327 case XML_TEXT_NODE:
5328 case XML_CDATA_SECTION_NODE:
5329 case XML_ENTITY_REF_NODE:
5330 case XML_ENTITY_NODE:
5331 case XML_PI_NODE:
5332 case XML_COMMENT_NODE:
5333 case XML_NOTATION_NODE:
5334 if (content != NULL) {
Daniel Veillard8874b942005-08-25 13:19:21 +00005335 if ((cur->content == (xmlChar *) &(cur->properties)) ||
5336 ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5337 xmlDictOwns(cur->doc->dict, cur->content))) {
5338 cur->content = xmlStrncatNew(cur->content, content, len);
5339 cur->properties = NULL;
5340 cur->nsDef = NULL;
William M. Brack7762bb12004-01-04 14:49:01 +00005341 break;
5342 }
Owen Taylor3473f882001-02-23 17:55:21 +00005343 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005344 }
5345 case XML_DOCUMENT_NODE:
5346 case XML_DTD_NODE:
5347 case XML_HTML_DOCUMENT_NODE:
5348 case XML_DOCUMENT_TYPE_NODE:
5349 case XML_NAMESPACE_DECL:
5350 case XML_XINCLUDE_START:
5351 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005352#ifdef LIBXML_DOCB_ENABLED
5353 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005354#endif
5355 break;
5356 case XML_ELEMENT_DECL:
5357 case XML_ATTRIBUTE_DECL:
5358 case XML_ENTITY_DECL:
5359 break;
5360 }
5361}
5362
5363/**
5364 * xmlNodeAddContent:
5365 * @cur: the node being modified
5366 * @content: extra content
5367 *
5368 * Append the extra substring to the node content.
5369 */
5370void
5371xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5372 int len;
5373
5374 if (cur == NULL) {
5375#ifdef DEBUG_TREE
5376 xmlGenericError(xmlGenericErrorContext,
5377 "xmlNodeAddContent : node == NULL\n");
5378#endif
5379 return;
5380 }
5381 if (content == NULL) return;
5382 len = xmlStrlen(content);
5383 xmlNodeAddContentLen(cur, content, len);
5384}
5385
5386/**
5387 * xmlTextMerge:
5388 * @first: the first text node
5389 * @second: the second text node being merged
5390 *
5391 * Merge two text nodes into one
5392 * Returns the first text node augmented
5393 */
5394xmlNodePtr
5395xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5396 if (first == NULL) return(second);
5397 if (second == NULL) return(first);
5398 if (first->type != XML_TEXT_NODE) return(first);
5399 if (second->type != XML_TEXT_NODE) return(first);
5400 if (second->name != first->name)
5401 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005402 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005403 xmlUnlinkNode(second);
5404 xmlFreeNode(second);
5405 return(first);
5406}
5407
Daniel Veillard2156d432004-03-04 15:59:36 +00005408#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005409/**
5410 * xmlGetNsList:
5411 * @doc: the document
5412 * @node: the current node
5413 *
5414 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005415 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005416 * that need to be freed by the caller or NULL if no
5417 * namespace if defined
5418 */
5419xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005420xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5421{
Owen Taylor3473f882001-02-23 17:55:21 +00005422 xmlNsPtr cur;
5423 xmlNsPtr *ret = NULL;
5424 int nbns = 0;
5425 int maxns = 10;
5426 int i;
5427
5428 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005429 if (node->type == XML_ELEMENT_NODE) {
5430 cur = node->nsDef;
5431 while (cur != NULL) {
5432 if (ret == NULL) {
5433 ret =
5434 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5435 sizeof(xmlNsPtr));
5436 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005437 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005438 return (NULL);
5439 }
5440 ret[nbns] = NULL;
5441 }
5442 for (i = 0; i < nbns; i++) {
5443 if ((cur->prefix == ret[i]->prefix) ||
5444 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5445 break;
5446 }
5447 if (i >= nbns) {
5448 if (nbns >= maxns) {
5449 maxns *= 2;
5450 ret = (xmlNsPtr *) xmlRealloc(ret,
5451 (maxns +
5452 1) *
5453 sizeof(xmlNsPtr));
5454 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005455 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005456 return (NULL);
5457 }
5458 }
5459 ret[nbns++] = cur;
5460 ret[nbns] = NULL;
5461 }
Owen Taylor3473f882001-02-23 17:55:21 +00005462
Daniel Veillard77044732001-06-29 21:31:07 +00005463 cur = cur->next;
5464 }
5465 }
5466 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005467 }
Daniel Veillard77044732001-06-29 21:31:07 +00005468 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005469}
Daniel Veillard652327a2003-09-29 18:02:38 +00005470#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005471
5472/**
5473 * xmlSearchNs:
5474 * @doc: the document
5475 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005476 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005477 *
5478 * Search a Ns registered under a given name space for a document.
5479 * recurse on the parents until it finds the defined namespace
5480 * or return NULL otherwise.
5481 * @nameSpace can be NULL, this is a search for the default namespace.
5482 * We don't allow to cross entities boundaries. If you don't declare
5483 * the namespace within those you will be in troubles !!! A warning
5484 * is generated to cover this case.
5485 *
5486 * Returns the namespace pointer or NULL.
5487 */
5488xmlNsPtr
5489xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005490
Owen Taylor3473f882001-02-23 17:55:21 +00005491 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005492 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005493
5494 if (node == NULL) return(NULL);
5495 if ((nameSpace != NULL) &&
5496 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005497 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5498 /*
5499 * The XML-1.0 namespace is normally held on the root
5500 * element. In this case exceptionally create it on the
5501 * node element.
5502 */
5503 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5504 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005505 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005506 return(NULL);
5507 }
5508 memset(cur, 0, sizeof(xmlNs));
5509 cur->type = XML_LOCAL_NAMESPACE;
5510 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5511 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5512 cur->next = node->nsDef;
5513 node->nsDef = cur;
5514 return(cur);
5515 }
Daniel Veillard11ce4002006-03-10 00:36:23 +00005516 if (doc == NULL) {
5517 doc = node->doc;
5518 if (doc == NULL)
5519 return(NULL);
5520 }
Owen Taylor3473f882001-02-23 17:55:21 +00005521 if (doc->oldNs == NULL) {
5522 /*
5523 * Allocate a new Namespace and fill the fields.
5524 */
5525 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5526 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005527 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005528 return(NULL);
5529 }
5530 memset(doc->oldNs, 0, sizeof(xmlNs));
5531 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5532
5533 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5534 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5535 }
5536 return(doc->oldNs);
5537 }
5538 while (node != NULL) {
5539 if ((node->type == XML_ENTITY_REF_NODE) ||
5540 (node->type == XML_ENTITY_NODE) ||
5541 (node->type == XML_ENTITY_DECL))
5542 return(NULL);
5543 if (node->type == XML_ELEMENT_NODE) {
5544 cur = node->nsDef;
5545 while (cur != NULL) {
5546 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5547 (cur->href != NULL))
5548 return(cur);
5549 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5550 (cur->href != NULL) &&
5551 (xmlStrEqual(cur->prefix, nameSpace)))
5552 return(cur);
5553 cur = cur->next;
5554 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005555 if (orig != node) {
5556 cur = node->ns;
5557 if (cur != NULL) {
5558 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5559 (cur->href != NULL))
5560 return(cur);
5561 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5562 (cur->href != NULL) &&
5563 (xmlStrEqual(cur->prefix, nameSpace)))
5564 return(cur);
5565 }
5566 }
Owen Taylor3473f882001-02-23 17:55:21 +00005567 }
5568 node = node->parent;
5569 }
5570 return(NULL);
5571}
5572
5573/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005574 * xmlNsInScope:
5575 * @doc: the document
5576 * @node: the current node
5577 * @ancestor: the ancestor carrying the namespace
5578 * @prefix: the namespace prefix
5579 *
5580 * Verify that the given namespace held on @ancestor is still in scope
5581 * on node.
5582 *
5583 * Returns 1 if true, 0 if false and -1 in case of error.
5584 */
5585static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005586xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5587 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005588{
5589 xmlNsPtr tst;
5590
5591 while ((node != NULL) && (node != ancestor)) {
5592 if ((node->type == XML_ENTITY_REF_NODE) ||
5593 (node->type == XML_ENTITY_NODE) ||
5594 (node->type == XML_ENTITY_DECL))
5595 return (-1);
5596 if (node->type == XML_ELEMENT_NODE) {
5597 tst = node->nsDef;
5598 while (tst != NULL) {
5599 if ((tst->prefix == NULL)
5600 && (prefix == NULL))
5601 return (0);
5602 if ((tst->prefix != NULL)
5603 && (prefix != NULL)
5604 && (xmlStrEqual(tst->prefix, prefix)))
5605 return (0);
5606 tst = tst->next;
5607 }
5608 }
5609 node = node->parent;
5610 }
5611 if (node != ancestor)
5612 return (-1);
5613 return (1);
5614}
5615
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005616/**
Owen Taylor3473f882001-02-23 17:55:21 +00005617 * xmlSearchNsByHref:
5618 * @doc: the document
5619 * @node: the current node
5620 * @href: the namespace value
5621 *
5622 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5623 * the defined namespace or return NULL otherwise.
5624 * Returns the namespace pointer or NULL.
5625 */
5626xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005627xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5628{
Owen Taylor3473f882001-02-23 17:55:21 +00005629 xmlNsPtr cur;
5630 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005631 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005632
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005633 if ((node == NULL) || (href == NULL))
5634 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005635 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005636 /*
5637 * Only the document can hold the XML spec namespace.
5638 */
5639 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5640 /*
5641 * The XML-1.0 namespace is normally held on the root
5642 * element. In this case exceptionally create it on the
5643 * node element.
5644 */
5645 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5646 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005647 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005648 return (NULL);
5649 }
5650 memset(cur, 0, sizeof(xmlNs));
5651 cur->type = XML_LOCAL_NAMESPACE;
5652 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5653 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5654 cur->next = node->nsDef;
5655 node->nsDef = cur;
5656 return (cur);
5657 }
Daniel Veillard11ce4002006-03-10 00:36:23 +00005658 if (doc == NULL) {
5659 doc = node->doc;
5660 if (doc == NULL)
5661 return(NULL);
5662 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005663 if (doc->oldNs == NULL) {
5664 /*
5665 * Allocate a new Namespace and fill the fields.
5666 */
5667 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5668 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005669 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005670 return (NULL);
5671 }
5672 memset(doc->oldNs, 0, sizeof(xmlNs));
5673 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005674
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005675 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5676 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5677 }
5678 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005679 }
Daniel Veillard62040be2004-05-17 03:17:26 +00005680 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00005681 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005682 if ((node->type == XML_ENTITY_REF_NODE) ||
5683 (node->type == XML_ENTITY_NODE) ||
5684 (node->type == XML_ENTITY_DECL))
5685 return (NULL);
5686 if (node->type == XML_ELEMENT_NODE) {
5687 cur = node->nsDef;
5688 while (cur != NULL) {
5689 if ((cur->href != NULL) && (href != NULL) &&
5690 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005691 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00005692 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005693 return (cur);
5694 }
5695 cur = cur->next;
5696 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005697 if (orig != node) {
5698 cur = node->ns;
5699 if (cur != NULL) {
5700 if ((cur->href != NULL) && (href != NULL) &&
5701 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005702 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00005703 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00005704 return (cur);
5705 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005706 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005707 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005708 }
5709 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005710 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005711 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005712}
5713
5714/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005715 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005716 * @doc: the document
5717 * @tree: a node expected to hold the new namespace
5718 * @ns: the original namespace
5719 *
5720 * This function tries to locate a namespace definition in a tree
5721 * ancestors, or create a new namespace definition node similar to
5722 * @ns trying to reuse the same prefix. However if the given prefix is
5723 * null (default namespace) or reused within the subtree defined by
5724 * @tree or on one of its ancestors then a new prefix is generated.
5725 * Returns the (new) namespace definition or NULL in case of error
5726 */
5727xmlNsPtr
5728xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5729 xmlNsPtr def;
5730 xmlChar prefix[50];
5731 int counter = 1;
5732
5733 if (tree == NULL) {
5734#ifdef DEBUG_TREE
5735 xmlGenericError(xmlGenericErrorContext,
5736 "xmlNewReconciliedNs : tree == NULL\n");
5737#endif
5738 return(NULL);
5739 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00005740 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005741#ifdef DEBUG_TREE
5742 xmlGenericError(xmlGenericErrorContext,
5743 "xmlNewReconciliedNs : ns == NULL\n");
5744#endif
5745 return(NULL);
5746 }
5747 /*
5748 * Search an existing namespace definition inherited.
5749 */
5750 def = xmlSearchNsByHref(doc, tree, ns->href);
5751 if (def != NULL)
5752 return(def);
5753
5754 /*
5755 * Find a close prefix which is not already in use.
5756 * Let's strip namespace prefixes longer than 20 chars !
5757 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005758 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005759 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005760 else
William M. Brack13dfa872004-09-18 04:52:08 +00005761 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005762
Owen Taylor3473f882001-02-23 17:55:21 +00005763 def = xmlSearchNs(doc, tree, prefix);
5764 while (def != NULL) {
5765 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005766 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005767 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005768 else
William M. Brack13dfa872004-09-18 04:52:08 +00005769 snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
5770 (char *)ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005771 def = xmlSearchNs(doc, tree, prefix);
5772 }
5773
5774 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005775 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005776 */
5777 def = xmlNewNs(tree, ns->href, prefix);
5778 return(def);
5779}
5780
Daniel Veillard652327a2003-09-29 18:02:38 +00005781#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005782/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005783 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005784 * @doc: the document
5785 * @tree: a node defining the subtree to reconciliate
5786 *
5787 * This function checks that all the namespaces declared within the given
5788 * tree are properly declared. This is needed for example after Copy or Cut
5789 * and then paste operations. The subtree may still hold pointers to
5790 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005791 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005792 * the new environment. If not possible the new namespaces are redeclared
5793 * on @tree at the top of the given subtree.
5794 * Returns the number of namespace declarations created or -1 in case of error.
5795 */
5796int
5797xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5798 xmlNsPtr *oldNs = NULL;
5799 xmlNsPtr *newNs = NULL;
5800 int sizeCache = 0;
5801 int nbCache = 0;
5802
5803 xmlNsPtr n;
5804 xmlNodePtr node = tree;
5805 xmlAttrPtr attr;
5806 int ret = 0, i;
5807
Daniel Veillardce244ad2004-11-05 10:03:46 +00005808 if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1);
5809 if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1);
5810 if (node->doc != doc) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005811 while (node != NULL) {
5812 /*
5813 * Reconciliate the node namespace
5814 */
5815 if (node->ns != NULL) {
5816 /*
5817 * initialize the cache if needed
5818 */
5819 if (sizeCache == 0) {
5820 sizeCache = 10;
5821 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5822 sizeof(xmlNsPtr));
5823 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005824 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005825 return(-1);
5826 }
5827 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5828 sizeof(xmlNsPtr));
5829 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005830 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005831 xmlFree(oldNs);
5832 return(-1);
5833 }
5834 }
5835 for (i = 0;i < nbCache;i++) {
5836 if (oldNs[i] == node->ns) {
5837 node->ns = newNs[i];
5838 break;
5839 }
5840 }
5841 if (i == nbCache) {
5842 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005843 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005844 */
5845 n = xmlNewReconciliedNs(doc, tree, node->ns);
5846 if (n != NULL) { /* :-( what if else ??? */
5847 /*
5848 * check if we need to grow the cache buffers.
5849 */
5850 if (sizeCache <= nbCache) {
5851 sizeCache *= 2;
5852 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5853 sizeof(xmlNsPtr));
5854 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005855 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005856 xmlFree(newNs);
5857 return(-1);
5858 }
5859 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5860 sizeof(xmlNsPtr));
5861 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005862 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005863 xmlFree(oldNs);
5864 return(-1);
5865 }
5866 }
5867 newNs[nbCache] = n;
5868 oldNs[nbCache++] = node->ns;
5869 node->ns = n;
5870 }
5871 }
5872 }
5873 /*
5874 * now check for namespace hold by attributes on the node.
5875 */
5876 attr = node->properties;
5877 while (attr != NULL) {
5878 if (attr->ns != NULL) {
5879 /*
5880 * initialize the cache if needed
5881 */
5882 if (sizeCache == 0) {
5883 sizeCache = 10;
5884 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5885 sizeof(xmlNsPtr));
5886 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005887 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005888 return(-1);
5889 }
5890 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5891 sizeof(xmlNsPtr));
5892 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005893 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005894 xmlFree(oldNs);
5895 return(-1);
5896 }
5897 }
5898 for (i = 0;i < nbCache;i++) {
5899 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005900 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005901 break;
5902 }
5903 }
5904 if (i == nbCache) {
5905 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005906 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005907 */
5908 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5909 if (n != NULL) { /* :-( what if else ??? */
5910 /*
5911 * check if we need to grow the cache buffers.
5912 */
5913 if (sizeCache <= nbCache) {
5914 sizeCache *= 2;
5915 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5916 sizeof(xmlNsPtr));
5917 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005918 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005919 xmlFree(newNs);
5920 return(-1);
5921 }
5922 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5923 sizeof(xmlNsPtr));
5924 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005925 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005926 xmlFree(oldNs);
5927 return(-1);
5928 }
5929 }
5930 newNs[nbCache] = n;
5931 oldNs[nbCache++] = attr->ns;
5932 attr->ns = n;
5933 }
5934 }
5935 }
5936 attr = attr->next;
5937 }
5938
5939 /*
5940 * Browse the full subtree, deep first
5941 */
Daniel Veillardac996a12004-07-30 12:02:58 +00005942 if (node->children != NULL && node->type != XML_ENTITY_REF_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00005943 /* deep first */
5944 node = node->children;
5945 } else if ((node != tree) && (node->next != NULL)) {
5946 /* then siblings */
5947 node = node->next;
5948 } else if (node != tree) {
5949 /* go up to parents->next if needed */
5950 while (node != tree) {
5951 if (node->parent != NULL)
5952 node = node->parent;
5953 if ((node != tree) && (node->next != NULL)) {
5954 node = node->next;
5955 break;
5956 }
5957 if (node->parent == NULL) {
5958 node = NULL;
5959 break;
5960 }
5961 }
5962 /* exit condition */
5963 if (node == tree)
5964 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005965 } else
5966 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005967 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005968 if (oldNs != NULL)
5969 xmlFree(oldNs);
5970 if (newNs != NULL)
5971 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005972 return(ret);
5973}
Daniel Veillard652327a2003-09-29 18:02:38 +00005974#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005975
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00005976static xmlAttrPtr
5977xmlGetPropNodeInternal(xmlNodePtr node, const xmlChar *name,
5978 const xmlChar *nsName, int useDTD)
5979{
5980 xmlAttrPtr prop;
5981
5982 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
5983 return(NULL);
5984
5985 if (node->properties != NULL) {
5986 prop = node->properties;
5987 if (nsName == NULL) {
5988 /*
5989 * We want the attr to be in no namespace.
5990 */
5991 do {
5992 if ((prop->ns == NULL) && xmlStrEqual(prop->name, name)) {
5993 return(prop);
5994 }
5995 prop = prop->next;
5996 } while (prop != NULL);
5997 } else {
5998 /*
5999 * We want the attr to be in the specified namespace.
6000 */
6001 do {
6002 if ((prop->ns != NULL) && xmlStrEqual(prop->name, name) &&
6003 ((prop->ns->href == nsName) ||
6004 xmlStrEqual(prop->ns->href, nsName)))
6005 {
6006 return(prop);
6007 }
6008 prop = prop->next;
6009 } while (prop != NULL);
6010 }
6011 }
6012
6013#ifdef LIBXML_TREE_ENABLED
6014 if (! useDTD)
6015 return(NULL);
6016 /*
6017 * Check if there is a default/fixed attribute declaration in
6018 * the internal or external subset.
6019 */
6020 if ((node->doc != NULL) && (node->doc->intSubset != NULL)) {
6021 xmlDocPtr doc = node->doc;
6022 xmlAttributePtr attrDecl = NULL;
6023 xmlChar *elemQName, *tmpstr = NULL;
6024
6025 /*
6026 * We need the QName of the element for the DTD-lookup.
6027 */
6028 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
6029 tmpstr = xmlStrdup(node->ns->prefix);
6030 tmpstr = xmlStrcat(tmpstr, BAD_CAST ":");
6031 tmpstr = xmlStrcat(tmpstr, node->name);
6032 if (tmpstr == NULL)
6033 return(NULL);
6034 elemQName = tmpstr;
6035 } else
6036 elemQName = (xmlChar *) node->name;
6037 if (nsName == NULL) {
6038 /*
6039 * The common and nice case: Attr in no namespace.
6040 */
6041 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset,
6042 elemQName, name, NULL);
6043 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
6044 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset,
6045 elemQName, name, NULL);
6046 }
6047 } else {
6048 xmlNsPtr *nsList, *cur;
6049
6050 /*
6051 * The ugly case: Search using the prefixes of in-scope
6052 * ns-decls corresponding to @nsName.
6053 */
6054 nsList = xmlGetNsList(node->doc, node);
6055 if (nsList == NULL) {
6056 if (tmpstr != NULL)
6057 xmlFree(tmpstr);
6058 return(NULL);
6059 }
6060 cur = nsList;
6061 while (*cur != NULL) {
6062 if (xmlStrEqual((*cur)->href, nsName)) {
6063 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elemQName,
6064 name, (*cur)->prefix);
6065 if (attrDecl)
6066 break;
6067 if (doc->extSubset != NULL) {
6068 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elemQName,
6069 name, (*cur)->prefix);
6070 if (attrDecl)
6071 break;
6072 }
6073 }
6074 cur++;
6075 }
6076 xmlFree(nsList);
6077 }
6078 if (tmpstr != NULL)
6079 xmlFree(tmpstr);
6080 /*
6081 * Only default/fixed attrs are relevant.
6082 */
6083 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6084 return((xmlAttrPtr) attrDecl);
6085 }
6086#endif /* LIBXML_TREE_ENABLED */
6087 return(NULL);
6088}
6089
6090static xmlChar*
6091xmlGetPropNodeValueInternal(xmlAttrPtr prop)
6092{
6093 if (prop == NULL)
6094 return(NULL);
6095 if (prop->type == XML_ATTRIBUTE_NODE) {
6096 /*
6097 * Note that we return at least the empty string.
6098 * TODO: Do we really always want that?
6099 */
6100 if (prop->children != NULL) {
6101 if ((prop->children == prop->last) &&
6102 ((prop->children->type == XML_TEXT_NODE) ||
6103 (prop->children->type == XML_CDATA_SECTION_NODE)))
6104 {
6105 /*
6106 * Optimization for the common case: only 1 text node.
6107 */
6108 return(xmlStrdup(prop->children->content));
6109 } else {
6110 xmlChar *ret;
6111
6112 ret = xmlNodeListGetString(prop->doc, prop->children, 1);
6113 if (ret != NULL)
6114 return(ret);
6115 }
6116 }
6117 return(xmlStrdup((xmlChar *)""));
6118 } else if (prop->type == XML_ATTRIBUTE_DECL) {
6119 return(xmlStrdup(((xmlAttributePtr)prop)->defaultValue));
6120 }
6121 return(NULL);
6122}
6123
Owen Taylor3473f882001-02-23 17:55:21 +00006124/**
6125 * xmlHasProp:
6126 * @node: the node
6127 * @name: the attribute name
6128 *
6129 * Search an attribute associated to a node
6130 * This function also looks in DTD attribute declaration for #FIXED or
6131 * default declaration values unless DTD use has been turned off.
6132 *
6133 * Returns the attribute or the attribute declaration or NULL if
6134 * neither was found.
6135 */
6136xmlAttrPtr
6137xmlHasProp(xmlNodePtr node, const xmlChar *name) {
6138 xmlAttrPtr prop;
6139 xmlDocPtr doc;
6140
Daniel Veillard8874b942005-08-25 13:19:21 +00006141 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6142 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006143 /*
6144 * Check on the properties attached to the node
6145 */
6146 prop = node->properties;
6147 while (prop != NULL) {
6148 if (xmlStrEqual(prop->name, name)) {
6149 return(prop);
6150 }
6151 prop = prop->next;
6152 }
6153 if (!xmlCheckDTD) return(NULL);
6154
6155 /*
6156 * Check if there is a default declaration in the internal
6157 * or external subsets
6158 */
6159 doc = node->doc;
6160 if (doc != NULL) {
6161 xmlAttributePtr attrDecl;
6162 if (doc->intSubset != NULL) {
6163 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6164 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6165 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006166 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6167 /* return attribute declaration only if a default value is given
6168 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006169 return((xmlAttrPtr) attrDecl);
6170 }
6171 }
6172 return(NULL);
6173}
6174
6175/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00006176 * xmlHasNsProp:
6177 * @node: the node
6178 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006179 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00006180 *
6181 * Search for an attribute associated to a node
6182 * This attribute has to be anchored in the namespace specified.
6183 * This does the entity substitution.
6184 * This function looks in DTD attribute declaration for #FIXED or
6185 * default declaration values unless DTD use has been turned off.
William M. Brack2c228442004-10-03 04:10:00 +00006186 * Note that a namespace of NULL indicates to use the default namespace.
Daniel Veillarde95e2392001-06-06 10:46:28 +00006187 *
6188 * Returns the attribute or the attribute declaration or NULL
6189 * if neither was found.
6190 */
6191xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00006192xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00006193
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006194 return(xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD));
Daniel Veillarde95e2392001-06-06 10:46:28 +00006195}
6196
6197/**
Owen Taylor3473f882001-02-23 17:55:21 +00006198 * xmlGetProp:
6199 * @node: the node
6200 * @name: the attribute name
6201 *
6202 * Search and get the value of an attribute associated to a node
6203 * This does the entity substitution.
6204 * This function looks in DTD attribute declaration for #FIXED or
6205 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00006206 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00006207 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6208 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00006209 *
6210 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006211 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006212 */
6213xmlChar *
6214xmlGetProp(xmlNodePtr node, const xmlChar *name) {
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006215 xmlAttrPtr prop;
Owen Taylor3473f882001-02-23 17:55:21 +00006216
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006217 prop = xmlHasProp(node, name);
6218 if (prop == NULL)
6219 return(NULL);
6220 return(xmlGetPropNodeValueInternal(prop));
Owen Taylor3473f882001-02-23 17:55:21 +00006221}
6222
6223/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006224 * xmlGetNoNsProp:
6225 * @node: the node
6226 * @name: the attribute name
6227 *
6228 * Search and get the value of an attribute associated to a node
6229 * This does the entity substitution.
6230 * This function looks in DTD attribute declaration for #FIXED or
6231 * default declaration values unless DTD use has been turned off.
6232 * This function is similar to xmlGetProp except it will accept only
6233 * an attribute in no namespace.
6234 *
6235 * Returns the attribute value or NULL if not found.
6236 * It's up to the caller to free the memory with xmlFree().
6237 */
6238xmlChar *
6239xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6240 xmlAttrPtr prop;
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006241
6242 prop = xmlGetPropNodeInternal(node, name, NULL, xmlCheckDTD);
6243 if (prop == NULL)
Daniel Veillard8874b942005-08-25 13:19:21 +00006244 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006245 return(xmlGetPropNodeValueInternal(prop));
Daniel Veillard71531f32003-02-05 13:19:53 +00006246}
6247
6248/**
Owen Taylor3473f882001-02-23 17:55:21 +00006249 * xmlGetNsProp:
6250 * @node: the node
6251 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006252 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006253 *
6254 * Search and get the value of an attribute associated to a node
6255 * This attribute has to be anchored in the namespace specified.
6256 * This does the entity substitution.
6257 * This function looks in DTD attribute declaration for #FIXED or
6258 * default declaration values unless DTD use has been turned off.
6259 *
6260 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006261 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006262 */
6263xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006264xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006265 xmlAttrPtr prop;
Owen Taylor3473f882001-02-23 17:55:21 +00006266
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006267 prop = xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD);
6268 if (prop == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006269 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006270 return(xmlGetPropNodeValueInternal(prop));
Owen Taylor3473f882001-02-23 17:55:21 +00006271}
6272
Daniel Veillard2156d432004-03-04 15:59:36 +00006273#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6274/**
6275 * xmlUnsetProp:
6276 * @node: the node
6277 * @name: the attribute name
6278 *
6279 * Remove an attribute carried by a node.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006280 * This handles only attributes in no namespace.
Daniel Veillard2156d432004-03-04 15:59:36 +00006281 * Returns 0 if successful, -1 if not found
6282 */
6283int
6284xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Kasimier T. Buchcik65c2f1d2005-10-17 12:39:58 +00006285 xmlAttrPtr prop;
Daniel Veillard2156d432004-03-04 15:59:36 +00006286
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006287 prop = xmlGetPropNodeInternal(node, name, NULL, 0);
6288 if (prop == NULL)
Daniel Veillard2156d432004-03-04 15:59:36 +00006289 return(-1);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006290 xmlUnlinkNode((xmlNodePtr) prop);
6291 xmlFreeProp(prop);
6292 return(0);
Daniel Veillard2156d432004-03-04 15:59:36 +00006293}
6294
6295/**
6296 * xmlUnsetNsProp:
6297 * @node: the node
6298 * @ns: the namespace definition
6299 * @name: the attribute name
6300 *
6301 * Remove an attribute carried by a node.
6302 * Returns 0 if successful, -1 if not found
6303 */
6304int
6305xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
Kasimier T. Buchcik65c2f1d2005-10-17 12:39:58 +00006306 xmlAttrPtr prop;
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006307
6308 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
6309 if (prop == NULL)
Daniel Veillard2156d432004-03-04 15:59:36 +00006310 return(-1);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006311 xmlUnlinkNode((xmlNodePtr) prop);
6312 xmlFreeProp(prop);
6313 return(0);
Daniel Veillard2156d432004-03-04 15:59:36 +00006314}
6315#endif
6316
6317#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006318/**
6319 * xmlSetProp:
6320 * @node: the node
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006321 * @name: the attribute name (a QName)
Owen Taylor3473f882001-02-23 17:55:21 +00006322 * @value: the attribute value
6323 *
6324 * Set (or reset) an attribute carried by a node.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006325 * If @name has a prefix, then the corresponding
6326 * namespace-binding will be used, if in scope; it is an
6327 * error it there's no such ns-binding for the prefix in
6328 * scope.
Owen Taylor3473f882001-02-23 17:55:21 +00006329 * Returns the attribute pointer.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006330 *
Owen Taylor3473f882001-02-23 17:55:21 +00006331 */
6332xmlAttrPtr
6333xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006334 int len;
6335 const xmlChar *nqname;
Owen Taylor3473f882001-02-23 17:55:21 +00006336
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006337 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006338 return(NULL);
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006339
6340 /*
6341 * handle QNames
6342 */
6343 nqname = xmlSplitQName3(name, &len);
6344 if (nqname != NULL) {
6345 xmlNsPtr ns;
6346 xmlChar *prefix = xmlStrndup(name, len);
6347 ns = xmlSearchNs(node->doc, node, prefix);
6348 if (prefix != NULL)
6349 xmlFree(prefix);
6350 if (ns != NULL)
6351 return(xmlSetNsProp(node, ns, nqname, value));
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006352 /*
6353 * If we get a QName and the prefix has no namespace-
6354 * binding in scope, then this is an error.
6355 * TODO: Previously this falled-back to non-ns handling.
6356 * Should we revert this?
6357 */
6358 return(NULL);
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006359 }
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006360 return(xmlSetNsProp(node, NULL, name, value));
Owen Taylor3473f882001-02-23 17:55:21 +00006361}
6362
6363/**
6364 * xmlSetNsProp:
6365 * @node: the node
6366 * @ns: the namespace definition
6367 * @name: the attribute name
6368 * @value: the attribute value
6369 *
6370 * Set (or reset) an attribute carried by a node.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006371 * The ns structure must be in scope, this is not checked
Owen Taylor3473f882001-02-23 17:55:21 +00006372 *
6373 * Returns the attribute pointer.
6374 */
6375xmlAttrPtr
6376xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006377 const xmlChar *value)
6378{
Owen Taylor3473f882001-02-23 17:55:21 +00006379 xmlAttrPtr prop;
6380
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006381 if (ns && (ns->href == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006382 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006383 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
6384 if (prop != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006385 /*
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006386 * Modify the attribute's value.
6387 */
6388 if (prop->atype == XML_ATTRIBUTE_ID) {
6389 xmlRemoveID(node->doc, prop);
6390 prop->atype = XML_ATTRIBUTE_ID;
6391 }
6392 if (prop->children != NULL)
6393 xmlFreeNodeList(prop->children);
6394 prop->children = NULL;
6395 prop->last = NULL;
6396 prop->ns = ns;
6397 if (value != NULL) {
6398 xmlChar *buffer;
6399 xmlNodePtr tmp;
6400
6401 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6402 prop->children = xmlStringGetNodeList(node->doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00006403 prop->last = NULL;
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006404 tmp = prop->children;
6405 while (tmp != NULL) {
6406 tmp->parent = (xmlNodePtr) prop;
6407 if (tmp->next == NULL)
6408 prop->last = tmp;
6409 tmp = tmp->next;
6410 }
6411 xmlFree(buffer);
6412 }
6413 if (prop->atype == XML_ATTRIBUTE_ID)
6414 xmlAddID(NULL, node->doc, value, prop);
6415 return(prop);
Owen Taylor3473f882001-02-23 17:55:21 +00006416 }
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006417 /*
6418 * No equal attr found; create a new one.
6419 */
6420 return(xmlNewPropInternal(node, ns, name, value, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006421}
6422
Daniel Veillard652327a2003-09-29 18:02:38 +00006423#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006424
6425/**
Owen Taylor3473f882001-02-23 17:55:21 +00006426 * xmlNodeIsText:
6427 * @node: the node
6428 *
6429 * Is this node a Text node ?
6430 * Returns 1 yes, 0 no
6431 */
6432int
6433xmlNodeIsText(xmlNodePtr node) {
6434 if (node == NULL) return(0);
6435
6436 if (node->type == XML_TEXT_NODE) return(1);
6437 return(0);
6438}
6439
6440/**
6441 * xmlIsBlankNode:
6442 * @node: the node
6443 *
6444 * Checks whether this node is an empty or whitespace only
6445 * (and possibly ignorable) text-node.
6446 *
6447 * Returns 1 yes, 0 no
6448 */
6449int
6450xmlIsBlankNode(xmlNodePtr node) {
6451 const xmlChar *cur;
6452 if (node == NULL) return(0);
6453
Daniel Veillard7db37732001-07-12 01:20:08 +00006454 if ((node->type != XML_TEXT_NODE) &&
6455 (node->type != XML_CDATA_SECTION_NODE))
6456 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006457 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006458 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006459 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006460 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006461 cur++;
6462 }
6463
6464 return(1);
6465}
6466
6467/**
6468 * xmlTextConcat:
6469 * @node: the node
6470 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006471 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006472 *
6473 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006474 *
6475 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006476 */
6477
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006478int
Owen Taylor3473f882001-02-23 17:55:21 +00006479xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006480 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006481
6482 if ((node->type != XML_TEXT_NODE) &&
6483 (node->type != XML_CDATA_SECTION_NODE)) {
6484#ifdef DEBUG_TREE
6485 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006486 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006487#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006488 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006489 }
William M. Brack7762bb12004-01-04 14:49:01 +00006490 /* need to check if content is currently in the dictionary */
Daniel Veillard8874b942005-08-25 13:19:21 +00006491 if ((node->content == (xmlChar *) &(node->properties)) ||
6492 ((node->doc != NULL) && (node->doc->dict != NULL) &&
6493 xmlDictOwns(node->doc->dict, node->content))) {
William M. Brack7762bb12004-01-04 14:49:01 +00006494 node->content = xmlStrncatNew(node->content, content, len);
6495 } else {
6496 node->content = xmlStrncat(node->content, content, len);
6497 }
Daniel Veillard8874b942005-08-25 13:19:21 +00006498 node->properties = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006499 if (node->content == NULL)
6500 return(-1);
6501 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006502}
6503
6504/************************************************************************
6505 * *
6506 * Output : to a FILE or in memory *
6507 * *
6508 ************************************************************************/
6509
Owen Taylor3473f882001-02-23 17:55:21 +00006510/**
6511 * xmlBufferCreate:
6512 *
6513 * routine to create an XML buffer.
6514 * returns the new structure.
6515 */
6516xmlBufferPtr
6517xmlBufferCreate(void) {
6518 xmlBufferPtr ret;
6519
6520 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6521 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006522 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006523 return(NULL);
6524 }
6525 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006526 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006527 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006528 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006529 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006530 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006531 xmlFree(ret);
6532 return(NULL);
6533 }
6534 ret->content[0] = 0;
6535 return(ret);
6536}
6537
6538/**
6539 * xmlBufferCreateSize:
6540 * @size: initial size of buffer
6541 *
6542 * routine to create an XML buffer.
6543 * returns the new structure.
6544 */
6545xmlBufferPtr
6546xmlBufferCreateSize(size_t size) {
6547 xmlBufferPtr ret;
6548
6549 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6550 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006551 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006552 return(NULL);
6553 }
6554 ret->use = 0;
6555 ret->alloc = xmlBufferAllocScheme;
6556 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6557 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006558 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006559 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006560 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006561 xmlFree(ret);
6562 return(NULL);
6563 }
6564 ret->content[0] = 0;
6565 } else
6566 ret->content = NULL;
6567 return(ret);
6568}
6569
6570/**
Daniel Veillard53350552003-09-18 13:35:51 +00006571 * xmlBufferCreateStatic:
6572 * @mem: the memory area
6573 * @size: the size in byte
6574 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006575 * routine to create an XML buffer from an immutable memory area.
6576 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006577 * present until the end of the buffer lifetime.
6578 *
6579 * returns the new structure.
6580 */
6581xmlBufferPtr
6582xmlBufferCreateStatic(void *mem, size_t size) {
6583 xmlBufferPtr ret;
6584
6585 if ((mem == NULL) || (size == 0))
6586 return(NULL);
6587
6588 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6589 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006590 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006591 return(NULL);
6592 }
6593 ret->use = size;
6594 ret->size = size;
6595 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6596 ret->content = (xmlChar *) mem;
6597 return(ret);
6598}
6599
6600/**
Owen Taylor3473f882001-02-23 17:55:21 +00006601 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006602 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006603 * @scheme: allocation scheme to use
6604 *
6605 * Sets the allocation scheme for this buffer
6606 */
6607void
6608xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6609 xmlBufferAllocationScheme scheme) {
6610 if (buf == NULL) {
6611#ifdef DEBUG_BUFFER
6612 xmlGenericError(xmlGenericErrorContext,
6613 "xmlBufferSetAllocationScheme: buf == NULL\n");
6614#endif
6615 return;
6616 }
Daniel Veillard53350552003-09-18 13:35:51 +00006617 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006618
6619 buf->alloc = scheme;
6620}
6621
6622/**
6623 * xmlBufferFree:
6624 * @buf: the buffer to free
6625 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006626 * Frees an XML buffer. It frees both the content and the structure which
6627 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006628 */
6629void
6630xmlBufferFree(xmlBufferPtr buf) {
6631 if (buf == NULL) {
6632#ifdef DEBUG_BUFFER
6633 xmlGenericError(xmlGenericErrorContext,
6634 "xmlBufferFree: buf == NULL\n");
6635#endif
6636 return;
6637 }
Daniel Veillard53350552003-09-18 13:35:51 +00006638
6639 if ((buf->content != NULL) &&
6640 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006641 xmlFree(buf->content);
6642 }
Owen Taylor3473f882001-02-23 17:55:21 +00006643 xmlFree(buf);
6644}
6645
6646/**
6647 * xmlBufferEmpty:
6648 * @buf: the buffer
6649 *
6650 * empty a buffer.
6651 */
6652void
6653xmlBufferEmpty(xmlBufferPtr buf) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006654 if (buf == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006655 if (buf->content == NULL) return;
6656 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006657 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006658 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006659 } else {
6660 memset(buf->content, 0, buf->size);
6661 }
Owen Taylor3473f882001-02-23 17:55:21 +00006662}
6663
6664/**
6665 * xmlBufferShrink:
6666 * @buf: the buffer to dump
6667 * @len: the number of xmlChar to remove
6668 *
6669 * Remove the beginning of an XML buffer.
6670 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006671 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006672 */
6673int
6674xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
Daniel Veillard3d97e662004-11-04 10:49:00 +00006675 if (buf == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006676 if (len == 0) return(0);
6677 if (len > buf->use) return(-1);
6678
6679 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006680 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6681 buf->content += len;
6682 } else {
6683 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6684 buf->content[buf->use] = 0;
6685 }
Owen Taylor3473f882001-02-23 17:55:21 +00006686 return(len);
6687}
6688
6689/**
6690 * xmlBufferGrow:
6691 * @buf: the buffer
6692 * @len: the minimum free size to allocate
6693 *
6694 * Grow the available space of an XML buffer.
6695 *
6696 * Returns the new available space or -1 in case of error
6697 */
6698int
6699xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6700 int size;
6701 xmlChar *newbuf;
6702
Daniel Veillard3d97e662004-11-04 10:49:00 +00006703 if (buf == NULL) return(-1);
6704
Daniel Veillard53350552003-09-18 13:35:51 +00006705 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006706 if (len + buf->use < buf->size) return(0);
6707
William M. Brack30fe43f2004-07-26 18:00:58 +00006708/*
6709 * Windows has a BIG problem on realloc timing, so we try to double
6710 * the buffer size (if that's enough) (bug 146697)
6711 */
6712#ifdef WIN32
6713 if (buf->size > len)
6714 size = buf->size * 2;
6715 else
6716 size = buf->use + len + 100;
6717#else
Owen Taylor3473f882001-02-23 17:55:21 +00006718 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00006719#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006720
6721 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006722 if (newbuf == NULL) {
6723 xmlTreeErrMemory("growing buffer");
6724 return(-1);
6725 }
Owen Taylor3473f882001-02-23 17:55:21 +00006726 buf->content = newbuf;
6727 buf->size = size;
6728 return(buf->size - buf->use);
6729}
6730
6731/**
6732 * xmlBufferDump:
6733 * @file: the file output
6734 * @buf: the buffer to dump
6735 *
6736 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006737 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006738 */
6739int
6740xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6741 int ret;
6742
6743 if (buf == NULL) {
6744#ifdef DEBUG_BUFFER
6745 xmlGenericError(xmlGenericErrorContext,
6746 "xmlBufferDump: buf == NULL\n");
6747#endif
6748 return(0);
6749 }
6750 if (buf->content == NULL) {
6751#ifdef DEBUG_BUFFER
6752 xmlGenericError(xmlGenericErrorContext,
6753 "xmlBufferDump: buf->content == NULL\n");
6754#endif
6755 return(0);
6756 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006757 if (file == NULL)
6758 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006759 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6760 return(ret);
6761}
6762
6763/**
6764 * xmlBufferContent:
6765 * @buf: the buffer
6766 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006767 * Function to extract the content of a buffer
6768 *
Owen Taylor3473f882001-02-23 17:55:21 +00006769 * Returns the internal content
6770 */
6771
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006772const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006773xmlBufferContent(const xmlBufferPtr buf)
6774{
6775 if(!buf)
6776 return NULL;
6777
6778 return buf->content;
6779}
6780
6781/**
6782 * xmlBufferLength:
6783 * @buf: the buffer
6784 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006785 * Function to get the length of a buffer
6786 *
Owen Taylor3473f882001-02-23 17:55:21 +00006787 * Returns the length of data in the internal content
6788 */
6789
6790int
6791xmlBufferLength(const xmlBufferPtr buf)
6792{
6793 if(!buf)
6794 return 0;
6795
6796 return buf->use;
6797}
6798
6799/**
6800 * xmlBufferResize:
6801 * @buf: the buffer to resize
6802 * @size: the desired size
6803 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006804 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006805 *
6806 * Returns 0 in case of problems, 1 otherwise
6807 */
6808int
6809xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6810{
6811 unsigned int newSize;
6812 xmlChar* rebuf = NULL;
6813
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006814 if (buf == NULL)
6815 return(0);
6816
Daniel Veillard53350552003-09-18 13:35:51 +00006817 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6818
Owen Taylor3473f882001-02-23 17:55:21 +00006819 /* Don't resize if we don't have to */
6820 if (size < buf->size)
6821 return 1;
6822
6823 /* figure out new size */
6824 switch (buf->alloc){
6825 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillardbf629492004-04-20 22:20:59 +00006826 /*take care of empty case*/
6827 newSize = (buf->size ? buf->size*2 : size + 10);
Owen Taylor3473f882001-02-23 17:55:21 +00006828 while (size > newSize) newSize *= 2;
6829 break;
6830 case XML_BUFFER_ALLOC_EXACT:
6831 newSize = size+10;
6832 break;
6833 default:
6834 newSize = size+10;
6835 break;
6836 }
6837
6838 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006839 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006840 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006841 rebuf = (xmlChar *) xmlRealloc(buf->content,
6842 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006843 } else {
6844 /*
6845 * if we are reallocating a buffer far from being full, it's
6846 * better to make a new allocation and copy only the used range
6847 * and free the old one.
6848 */
6849 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6850 if (rebuf != NULL) {
6851 memcpy(rebuf, buf->content, buf->use);
6852 xmlFree(buf->content);
William M. Brack42331a92004-07-29 07:07:16 +00006853 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006854 }
6855 }
Owen Taylor3473f882001-02-23 17:55:21 +00006856 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006857 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006858 return 0;
6859 }
6860 buf->content = rebuf;
6861 buf->size = newSize;
6862
6863 return 1;
6864}
6865
6866/**
6867 * xmlBufferAdd:
6868 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006869 * @str: the #xmlChar string
6870 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006871 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006872 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006873 * str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006874 *
6875 * Returns 0 successful, a positive error code number otherwise
6876 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006877 */
William M. Bracka3215c72004-07-31 16:24:01 +00006878int
Owen Taylor3473f882001-02-23 17:55:21 +00006879xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6880 unsigned int needSize;
6881
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006882 if ((str == NULL) || (buf == NULL)) {
William M. Bracka3215c72004-07-31 16:24:01 +00006883 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006884 }
William M. Bracka3215c72004-07-31 16:24:01 +00006885 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006886 if (len < -1) {
6887#ifdef DEBUG_BUFFER
6888 xmlGenericError(xmlGenericErrorContext,
6889 "xmlBufferAdd: len < 0\n");
6890#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006891 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006892 }
William M. Bracka3215c72004-07-31 16:24:01 +00006893 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006894
6895 if (len < 0)
6896 len = xmlStrlen(str);
6897
William M. Bracka3215c72004-07-31 16:24:01 +00006898 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006899
6900 needSize = buf->use + len + 2;
6901 if (needSize > buf->size){
6902 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006903 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006904 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006905 }
6906 }
6907
6908 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6909 buf->use += len;
6910 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006911 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006912}
6913
6914/**
6915 * xmlBufferAddHead:
6916 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006917 * @str: the #xmlChar string
6918 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006919 *
6920 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006921 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006922 *
6923 * Returns 0 successful, a positive error code number otherwise
6924 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006925 */
William M. Bracka3215c72004-07-31 16:24:01 +00006926int
Owen Taylor3473f882001-02-23 17:55:21 +00006927xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6928 unsigned int needSize;
6929
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006930 if (buf == NULL)
6931 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00006932 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006933 if (str == NULL) {
6934#ifdef DEBUG_BUFFER
6935 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006936 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006937#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006938 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006939 }
6940 if (len < -1) {
6941#ifdef DEBUG_BUFFER
6942 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006943 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006944#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006945 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006946 }
William M. Bracka3215c72004-07-31 16:24:01 +00006947 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006948
6949 if (len < 0)
6950 len = xmlStrlen(str);
6951
William M. Bracka3215c72004-07-31 16:24:01 +00006952 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006953
6954 needSize = buf->use + len + 2;
6955 if (needSize > buf->size){
6956 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006957 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006958 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006959 }
6960 }
6961
6962 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6963 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6964 buf->use += len;
6965 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006966 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006967}
6968
6969/**
6970 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00006971 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00006972 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006973 *
6974 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00006975 *
6976 * Returns 0 successful, a positive error code number otherwise
6977 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006978 */
William M. Bracka3215c72004-07-31 16:24:01 +00006979int
Owen Taylor3473f882001-02-23 17:55:21 +00006980xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006981 if (buf == NULL)
6982 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00006983 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
6984 if (str == NULL) return -1;
6985 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00006986}
6987
6988/**
6989 * xmlBufferCCat:
6990 * @buf: the buffer to dump
6991 * @str: the C char string
6992 *
6993 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00006994 *
6995 * Returns 0 successful, a positive error code number otherwise
6996 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006997 */
William M. Bracka3215c72004-07-31 16:24:01 +00006998int
Owen Taylor3473f882001-02-23 17:55:21 +00006999xmlBufferCCat(xmlBufferPtr buf, const char *str) {
7000 const char *cur;
7001
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007002 if (buf == NULL)
7003 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007004 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007005 if (str == NULL) {
7006#ifdef DEBUG_BUFFER
7007 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007008 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007009#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007010 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007011 }
7012 for (cur = str;*cur != 0;cur++) {
7013 if (buf->use + 10 >= buf->size) {
7014 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007015 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007016 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007017 }
7018 }
7019 buf->content[buf->use++] = *cur;
7020 }
7021 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007022 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007023}
7024
7025/**
7026 * xmlBufferWriteCHAR:
7027 * @buf: the XML buffer
7028 * @string: the string to add
7029 *
7030 * routine which manages and grows an output buffer. This one adds
7031 * xmlChars at the end of the buffer.
7032 */
7033void
Daniel Veillard53350552003-09-18 13:35:51 +00007034xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007035 if (buf == NULL)
7036 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007037 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007038 xmlBufferCat(buf, string);
7039}
7040
7041/**
7042 * xmlBufferWriteChar:
7043 * @buf: the XML buffer output
7044 * @string: the string to add
7045 *
7046 * routine which manage and grows an output buffer. This one add
7047 * C chars at the end of the array.
7048 */
7049void
7050xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007051 if (buf == NULL)
7052 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007053 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007054 xmlBufferCCat(buf, string);
7055}
7056
7057
7058/**
7059 * xmlBufferWriteQuotedString:
7060 * @buf: the XML buffer output
7061 * @string: the string to add
7062 *
7063 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00007064 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00007065 * quote or double-quotes internally
7066 */
7067void
7068xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00007069 const xmlChar *cur, *base;
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007070 if (buf == NULL)
7071 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007072 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00007073 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00007074 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00007075#ifdef DEBUG_BUFFER
7076 xmlGenericError(xmlGenericErrorContext,
7077 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7078#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00007079 xmlBufferCCat(buf, "\"");
7080 base = cur = string;
7081 while(*cur != 0){
7082 if(*cur == '"'){
7083 if (base != cur)
7084 xmlBufferAdd(buf, base, cur - base);
7085 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7086 cur++;
7087 base = cur;
7088 }
7089 else {
7090 cur++;
7091 }
7092 }
7093 if (base != cur)
7094 xmlBufferAdd(buf, base, cur - base);
7095 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007096 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007097 else{
7098 xmlBufferCCat(buf, "\'");
7099 xmlBufferCat(buf, string);
7100 xmlBufferCCat(buf, "\'");
7101 }
Owen Taylor3473f882001-02-23 17:55:21 +00007102 } else {
7103 xmlBufferCCat(buf, "\"");
7104 xmlBufferCat(buf, string);
7105 xmlBufferCCat(buf, "\"");
7106 }
7107}
7108
7109
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007110/**
7111 * xmlGetDocCompressMode:
7112 * @doc: the document
7113 *
7114 * get the compression ratio for a document, ZLIB based
7115 * Returns 0 (uncompressed) to 9 (max compression)
7116 */
7117int
7118xmlGetDocCompressMode (xmlDocPtr doc) {
7119 if (doc == NULL) return(-1);
7120 return(doc->compression);
7121}
7122
7123/**
7124 * xmlSetDocCompressMode:
7125 * @doc: the document
7126 * @mode: the compression ratio
7127 *
7128 * set the compression ratio for a document, ZLIB based
7129 * Correct values: 0 (uncompressed) to 9 (max compression)
7130 */
7131void
7132xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7133 if (doc == NULL) return;
7134 if (mode < 0) doc->compression = 0;
7135 else if (mode > 9) doc->compression = 9;
7136 else doc->compression = mode;
7137}
7138
7139/**
7140 * xmlGetCompressMode:
7141 *
7142 * get the default compression mode used, ZLIB based.
7143 * Returns 0 (uncompressed) to 9 (max compression)
7144 */
7145int
7146xmlGetCompressMode(void)
7147{
7148 return (xmlCompressMode);
7149}
7150
7151/**
7152 * xmlSetCompressMode:
7153 * @mode: the compression ratio
7154 *
7155 * set the default compression mode used, ZLIB based
7156 * Correct values: 0 (uncompressed) to 9 (max compression)
7157 */
7158void
7159xmlSetCompressMode(int mode) {
7160 if (mode < 0) xmlCompressMode = 0;
7161 else if (mode > 9) xmlCompressMode = 9;
7162 else xmlCompressMode = mode;
7163}
7164
Kasimier T. Buchcik4d9c9482005-06-27 15:04:46 +00007165/*
7166* xmlDOMWrapNewCtxt:
7167*
7168* Allocates and initializes a new DOM-wrapper context.
7169*
7170* Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal errror.
7171*/
7172xmlDOMWrapCtxtPtr
7173xmlDOMWrapNewCtxt(void)
7174{
7175 xmlDOMWrapCtxtPtr ret;
7176
7177 ret = xmlMalloc(sizeof(xmlDOMWrapCtxt));
7178 if (ret == NULL) {
7179 xmlTreeErrMemory("allocating DOM-wrapper context");
7180 return (NULL);
7181 }
7182 memset(ret, 0, sizeof(xmlDOMWrapCtxt));
7183 return (ret);
7184}
7185
7186/*
7187* xmlDOMWrapFreeCtxt:
7188* @ctxt: the DOM-wrapper context
7189*
7190* Frees the DOM-wrapper context.
7191*/
7192void
7193xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt)
7194{
7195 if (ctxt == NULL)
7196 return;
7197 xmlFree(ctxt);
7198}
7199
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007200#define XML_TREE_NSMAP_PARENT -1
7201#define XML_TREE_NSMAP_XML -2
7202#define XML_TREE_NSMAP_DOC -3
7203#define XML_TREE_NSMAP_CUSTOM -4
7204
7205typedef struct xmlNsMapItem *xmlNsMapItemPtr;
7206struct xmlNsMapItem {
7207 xmlNsMapItemPtr next;
7208 xmlNsMapItemPtr prev;
7209 xmlNsPtr oldNs; /* old ns decl reference */
7210 xmlNsPtr newNs; /* new ns decl reference */
7211 int shadowDepth; /* Shadowed at this depth */
7212 /*
7213 * depth:
7214 * >= 0 == @node's ns-decls
7215 * -1 == @parent's ns-decls
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00007216 * -2 == the doc->oldNs XML ns-decl
7217 * -3 == the doc->oldNs storage ns-decls
7218 * -4 == ns-decls provided via custom ns-handling
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007219 */
7220 int depth;
7221};
7222
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007223typedef struct xmlNsMap *xmlNsMapPtr;
7224struct xmlNsMap {
7225 xmlNsMapItemPtr first;
7226 xmlNsMapItemPtr last;
7227 xmlNsMapItemPtr pool;
7228};
7229
7230#define XML_NSMAP_NOTEMPTY(m) (((m) != NULL) && ((m)->first != NULL))
7231#define XML_NSMAP_FOREACH(m, i) for (i = (m)->first; i != NULL; i = (i)->next)
7232#define XML_NSMAP_POP(m, i) \
7233 i = (m)->last; \
7234 (m)->last = (i)->prev; \
7235 if ((m)->last == NULL) \
7236 (m)->first = NULL; \
7237 else \
7238 (m)->last->next = NULL; \
7239 (i)->next = (m)->pool; \
7240 (m)->pool = i;
7241
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007242/*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007243* xmlDOMWrapNsMapFree:
7244* @map: the ns-map
7245*
7246* Frees the ns-map
7247*/
7248static void
7249xmlDOMWrapNsMapFree(xmlNsMapPtr nsmap)
7250{
7251 xmlNsMapItemPtr cur, tmp;
7252
7253 if (nsmap == NULL)
7254 return;
7255 cur = nsmap->pool;
7256 while (cur != NULL) {
7257 tmp = cur;
7258 cur = cur->next;
7259 xmlFree(tmp);
7260 }
7261 cur = nsmap->first;
7262 while (cur != NULL) {
7263 tmp = cur;
7264 cur = cur->next;
7265 xmlFree(tmp);
7266 }
7267 xmlFree(nsmap);
7268}
7269
7270/*
7271* xmlDOMWrapNsMapAddItem:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007272* @map: the ns-map
7273* @cur: the current map entry to append a new entry to
7274* @oldNs: the old ns-struct
7275* @newNs: the new ns-struct
7276* @depth: depth and ns-kind information
7277*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007278* Adds an ns-mapping item.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007279*/
7280static xmlNsMapItemPtr
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007281xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position, /* xmlNsMapItemPtr *cur, */
7282 xmlNsPtr oldNs, xmlNsPtr newNs, int depth)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007283{
7284 xmlNsMapItemPtr ret;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007285 xmlNsMapPtr map;
7286
7287 if (nsmap == NULL)
7288 return(NULL);
7289 if ((position != -1) && (position != 0))
7290 return(NULL);
7291 map = *nsmap;
7292
7293 if (map == NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007294 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007295 * Create the ns-map.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007296 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007297 map = (xmlNsMapPtr) xmlMalloc(sizeof(struct xmlNsMap));
7298 if (map == NULL) {
7299 xmlTreeErrMemory("allocating namespace map");
7300 return (NULL);
7301 }
7302 memset(map, 0, sizeof(struct xmlNsMap));
7303 *nsmap = map;
7304 }
7305
7306 if (map->pool != NULL) {
7307 /*
7308 * Reuse an item from the pool.
7309 */
7310 ret = map->pool;
7311 map->pool = ret->next;
7312 memset(ret, 0, sizeof(struct xmlNsMapItem));
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007313 } else {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007314 /*
7315 * Create a new item.
7316 */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007317 ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem));
7318 if (ret == NULL) {
7319 xmlTreeErrMemory("allocating namespace map item");
7320 return (NULL);
7321 }
7322 memset(ret, 0, sizeof(struct xmlNsMapItem));
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007323 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007324
7325 if (map->first == NULL) {
7326 /*
7327 * First ever.
7328 */
7329 map->first = ret;
7330 map->last = ret;
7331 } else if (position == -1) {
7332 /*
7333 * Append.
7334 */
7335 ret->prev = map->last;
7336 map->last->next = ret;
7337 map->last = ret;
7338 } else if (position == 0) {
7339 /*
7340 * Set on first position.
7341 */
7342 map->first->prev = ret;
7343 ret->next = map->first;
7344 map->first = ret;
7345 } else
7346 return(NULL);
7347
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007348 ret->oldNs = oldNs;
7349 ret->newNs = newNs;
7350 ret->shadowDepth = -1;
7351 ret->depth = depth;
7352 return (ret);
7353}
7354
7355/*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007356* xmlTreeEnsureXMLDecl:
7357* @doc: the doc
7358*
7359* Ensures that there is an XML namespace declaration on the doc.
7360*
7361* Returns the XML ns-struct or NULL on API and internal errors.
7362*/
7363static xmlNsPtr
7364xmlTreeEnsureXMLDecl(xmlDocPtr doc)
7365{
7366 if (doc == NULL)
7367 return (NULL);
7368 if (doc->oldNs != NULL)
7369 return (doc->oldNs);
7370 {
7371 xmlNsPtr ns;
7372 ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
7373 if (ns == NULL) {
7374 xmlTreeErrMemory(
7375 "allocating the XML namespace");
7376 return (NULL);
7377 }
7378 memset(ns, 0, sizeof(xmlNs));
7379 ns->type = XML_LOCAL_NAMESPACE;
7380 ns->href = xmlStrdup(XML_XML_NAMESPACE);
7381 ns->prefix = xmlStrdup((const xmlChar *)"xml");
7382 doc->oldNs = ns;
7383 return (ns);
7384 }
7385}
7386
7387/*
7388* xmlDOMWrapStoreNs:
7389* @doc: the doc
7390* @nsName: the namespace name
7391* @prefix: the prefix
7392*
7393* Creates or reuses an xmlNs struct on doc->oldNs with
7394* the given prefix and namespace name.
7395*
7396* Returns the aquired ns struct or NULL in case of an API
7397* or internal error.
7398*/
7399static xmlNsPtr
7400xmlDOMWrapStoreNs(xmlDocPtr doc,
7401 const xmlChar *nsName,
7402 const xmlChar *prefix)
7403{
7404 xmlNsPtr ns;
7405
7406 if (doc == NULL)
7407 return (NULL);
7408 ns = xmlTreeEnsureXMLDecl(doc);
7409 if (ns == NULL)
7410 return (NULL);
7411 if (ns->next != NULL) {
7412 /* Reuse. */
7413 ns = ns->next;
7414 while (ns != NULL) {
7415 if (((ns->prefix == prefix) ||
7416 xmlStrEqual(ns->prefix, prefix)) &&
7417 xmlStrEqual(ns->href, nsName)) {
7418 return (ns);
7419 }
7420 if (ns->next == NULL)
7421 break;
7422 ns = ns->next;
7423 }
7424 }
7425 /* Create. */
7426 ns->next = xmlNewNs(NULL, nsName, prefix);
7427 return (ns->next);
7428}
7429
7430/*
7431* xmlTreeLookupNsListByPrefix:
7432* @nsList: a list of ns-structs
7433* @prefix: the searched prefix
7434*
7435* Searches for a ns-decl with the given prefix in @nsList.
7436*
7437* Returns the ns-decl if found, NULL if not found and on
7438* API errors.
7439*/
7440static xmlNsPtr
7441xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix)
7442{
7443 if (nsList == NULL)
7444 return (NULL);
7445 {
7446 xmlNsPtr ns;
7447 ns = nsList;
7448 do {
7449 if ((prefix == ns->prefix) ||
7450 xmlStrEqual(prefix, ns->prefix)) {
7451 return (ns);
7452 }
7453 ns = ns->next;
7454 } while (ns != NULL);
7455 }
7456 return (NULL);
7457}
7458
7459/*
7460*
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00007461* xmlDOMWrapNSNormGatherInScopeNs:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007462* @map: the namespace map
7463* @node: the node to start with
7464*
7465* Puts in-scope namespaces into the ns-map.
7466*
7467* Returns 0 on success, -1 on API or internal errors.
7468*/
7469static int
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007470xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapPtr *map,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007471 xmlNodePtr node)
7472{
7473 xmlNodePtr cur;
7474 xmlNsPtr ns;
7475 xmlNsMapItemPtr mi;
7476 int shadowed;
7477
7478 if ((map == NULL) || (*map != NULL))
7479 return (-1);
7480 /*
7481 * Get in-scope ns-decls of @parent.
7482 */
7483 cur = node;
7484 while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) {
7485 if (cur->type == XML_ELEMENT_NODE) {
7486 if (cur->nsDef != NULL) {
7487 ns = cur->nsDef;
7488 do {
7489 shadowed = 0;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007490 if (XML_NSMAP_NOTEMPTY(*map)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007491 /*
7492 * Skip shadowed prefixes.
7493 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007494 XML_NSMAP_FOREACH(*map, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007495 if ((ns->prefix == mi->newNs->prefix) ||
7496 xmlStrEqual(ns->prefix, mi->newNs->prefix)) {
7497 shadowed = 1;
7498 break;
7499 }
7500 }
7501 }
7502 /*
7503 * Insert mapping.
7504 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007505 mi = xmlDOMWrapNsMapAddItem(map, 0, NULL,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007506 ns, XML_TREE_NSMAP_PARENT);
7507 if (mi == NULL)
7508 return (-1);
7509 if (shadowed)
7510 mi->shadowDepth = 0;
7511 ns = ns->next;
7512 } while (ns != NULL);
7513 }
7514 }
7515 cur = cur->parent;
7516 }
7517 return (0);
7518}
7519
7520/*
7521* XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict;
7522* otherwise copy it, when it was in the source-dict.
7523*/
7524#define XML_TREE_ADOPT_STR(str) \
7525 if (adoptStr && (str != NULL)) { \
7526 if (destDoc->dict) { \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00007527 const xmlChar *old = str; \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007528 str = xmlDictLookup(destDoc->dict, str, -1); \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00007529 if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \
7530 (!xmlDictOwns(sourceDoc->dict, old))) \
Daniel Veillard39e5c892005-07-03 22:48:50 +00007531 xmlFree((char *)old); \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007532 } else if ((sourceDoc) && (sourceDoc->dict) && \
7533 xmlDictOwns(sourceDoc->dict, str)) { \
7534 str = BAD_CAST xmlStrdup(str); \
7535 } \
7536 }
7537
7538/*
7539* XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then
7540* put it in dest-dict or copy it.
7541*/
7542#define XML_TREE_ADOPT_STR_2(str) \
7543 if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \
7544 (sourceDoc->dict != NULL) && \
7545 xmlDictOwns(sourceDoc->dict, cur->content)) { \
7546 if (destDoc->dict) \
7547 cur->content = (xmlChar *) \
7548 xmlDictLookup(destDoc->dict, cur->content, -1); \
7549 else \
7550 cur->content = xmlStrdup(BAD_CAST cur->content); \
7551 }
7552
7553/*
7554* xmlDOMWrapNSNormAddNsMapItem2:
7555*
7556* For internal use. Adds a ns-decl mapping.
7557*
7558* Returns 0 on success, -1 on internal errors.
7559*/
7560static int
7561xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number,
7562 xmlNsPtr oldNs, xmlNsPtr newNs)
7563{
7564 if (*list == NULL) {
7565 *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr));
7566 if (*list == NULL) {
7567 xmlTreeErrMemory("alloc ns map item");
7568 return(-1);
7569 }
7570 *size = 3;
7571 *number = 0;
7572 } else if ((*number) >= (*size)) {
7573 *size *= 2;
7574 *list = (xmlNsPtr *) xmlRealloc(*list,
7575 (*size) * 2 * sizeof(xmlNsPtr));
7576 if (*list == NULL) {
7577 xmlTreeErrMemory("realloc ns map item");
7578 return(-1);
7579 }
7580 }
7581 (*list)[2 * (*number)] = oldNs;
7582 (*list)[2 * (*number) +1] = newNs;
7583 (*number)++;
7584 return (0);
7585}
7586
7587/*
7588* xmlDOMWrapRemoveNode:
Daniel Veillard304e78c2005-07-03 16:19:41 +00007589* @ctxt: a DOM wrapper context
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007590* @doc: the doc
7591* @node: the node to be removed.
Daniel Veillard304e78c2005-07-03 16:19:41 +00007592* @options: set of options, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007593*
7594* Unlinks the given node from its owner.
7595* This will substitute ns-references to node->nsDef for
7596* ns-references to doc->oldNs, thus ensuring the removed
7597* branch to be autark wrt ns-references.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00007598* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007599*
7600* Returns 0 on success, 1 if the node is not supported,
7601* -1 on API and internal errors.
7602*/
7603int
7604xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc,
7605 xmlNodePtr node, int options ATTRIBUTE_UNUSED)
7606{
7607 xmlNsPtr *list = NULL;
7608 int sizeList, nbList, i, j;
7609 xmlNsPtr ns;
7610
7611 if ((node == NULL) || (doc == NULL) || (node->doc != doc))
7612 return (-1);
7613
7614 /* TODO: 0 or -1 ? */
7615 if (node->parent == NULL)
7616 return (0);
7617
7618 switch (node->type) {
7619 case XML_TEXT_NODE:
7620 case XML_CDATA_SECTION_NODE:
7621 case XML_ENTITY_REF_NODE:
7622 case XML_PI_NODE:
7623 case XML_COMMENT_NODE:
7624 xmlUnlinkNode(node);
7625 return (0);
7626 case XML_ELEMENT_NODE:
7627 case XML_ATTRIBUTE_NODE:
7628 break;
7629 default:
7630 return (1);
7631 }
7632 xmlUnlinkNode(node);
7633 /*
7634 * Save out-of-scope ns-references in doc->oldNs.
7635 */
7636 do {
7637 switch (node->type) {
7638 case XML_ELEMENT_NODE:
7639 if ((ctxt == NULL) && (node->nsDef != NULL)) {
7640 ns = node->nsDef;
7641 do {
7642 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
7643 &nbList, ns, ns) == -1)
7644 goto internal_error;
7645 ns = ns->next;
7646 } while (ns != NULL);
7647 }
7648 /* No break on purpose. */
7649 case XML_ATTRIBUTE_NODE:
7650 if (node->ns != NULL) {
7651 /*
7652 * Find a mapping.
7653 */
7654 if (list != NULL) {
7655 for (i = 0, j = 0; i < nbList; i++, j += 2) {
7656 if (node->ns == list[j]) {
7657 node->ns = list[++j];
7658 goto next_node;
7659 }
7660 }
7661 }
7662 ns = NULL;
7663 if (ctxt != NULL) {
7664 /*
7665 * User defined.
7666 */
7667 } else {
7668 /*
7669 * Add to doc's oldNs.
7670 */
7671 ns = xmlDOMWrapStoreNs(doc, node->ns->href,
7672 node->ns->prefix);
7673 if (ns == NULL)
7674 goto internal_error;
7675 }
7676 if (ns != NULL) {
7677 /*
7678 * Add mapping.
7679 */
7680 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
7681 &nbList, node->ns, ns) == -1)
7682 goto internal_error;
7683 }
7684 node->ns = ns;
7685 }
7686 if ((node->type == XML_ELEMENT_NODE) &&
7687 (node->properties != NULL)) {
7688 node = (xmlNodePtr) node->properties;
7689 continue;
7690 }
7691 break;
7692 default:
7693 goto next_sibling;
7694 }
7695next_node:
7696 if ((node->type == XML_ELEMENT_NODE) &&
7697 (node->children != NULL)) {
7698 node = node->children;
7699 continue;
7700 }
7701next_sibling:
7702 if (node == NULL)
7703 break;
7704 if (node->next != NULL)
7705 node = node->next;
7706 else {
7707 node = node->parent;
7708 goto next_sibling;
7709 }
7710 } while (node != NULL);
7711
7712 if (list != NULL)
7713 xmlFree(list);
7714 return (0);
7715
7716internal_error:
7717 if (list != NULL)
7718 xmlFree(list);
7719 return (-1);
7720}
7721
7722/*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007723* xmlSearchNsByNamespaceStrict:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007724* @doc: the document
7725* @node: the start node
7726* @nsName: the searched namespace name
7727* @retNs: the resulting ns-decl
7728* @prefixed: if the found ns-decl must have a prefix (for attributes)
7729*
7730* Dynamically searches for a ns-declaration which matches
7731* the given @nsName in the ancestor-or-self axis of @node.
7732*
7733* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7734* and internal errors.
7735*/
7736static int
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007737xmlSearchNsByNamespaceStrict(xmlDocPtr doc, xmlNodePtr node,
7738 const xmlChar* nsName,
7739 xmlNsPtr *retNs, int prefixed)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007740{
7741 xmlNodePtr cur, prev = NULL, out = NULL;
7742 xmlNsPtr ns, prevns;
7743
7744 if ((doc == NULL) || (nsName == NULL) || (retNs == NULL))
7745 return (-1);
7746
7747 *retNs = NULL;
7748 if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
7749 *retNs = xmlTreeEnsureXMLDecl(doc);
7750 if (*retNs == NULL)
7751 return (-1);
7752 return (1);
7753 }
7754 cur = node;
7755 do {
7756 if (cur->type == XML_ELEMENT_NODE) {
7757 if (cur->nsDef != NULL) {
7758 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
7759 if (prefixed && (ns->prefix == NULL))
7760 continue;
7761 if (prev != NULL) {
7762 /*
7763 * Check the last level of ns-decls for a
7764 * shadowing prefix.
7765 */
7766 prevns = prev->nsDef;
7767 do {
7768 if ((prevns->prefix == ns->prefix) ||
7769 ((prevns->prefix != NULL) &&
7770 (ns->prefix != NULL) &&
7771 xmlStrEqual(prevns->prefix, ns->prefix))) {
7772 /*
7773 * Shadowed.
7774 */
7775 break;
7776 }
7777 prevns = prevns->next;
7778 } while (prevns != NULL);
7779 if (prevns != NULL)
7780 continue;
7781 }
7782 /*
7783 * Ns-name comparison.
7784 */
7785 if ((nsName == ns->href) ||
7786 xmlStrEqual(nsName, ns->href)) {
7787 /*
7788 * At this point the prefix can only be shadowed,
7789 * if we are the the (at least) 3rd level of
7790 * ns-decls.
7791 */
7792 if (out) {
7793 int ret;
7794
7795 ret = xmlNsInScope(doc, node, prev, ns->prefix);
7796 if (ret < 0)
7797 return (-1);
7798 /*
7799 * TODO: Should we try to find a matching ns-name
7800 * only once? This here keeps on searching.
7801 * I think we should try further since, there might
7802 * be an other matching ns-decl with an unshadowed
7803 * prefix.
7804 */
7805 if (! ret)
7806 continue;
7807 }
7808 *retNs = ns;
7809 return (1);
7810 }
7811 }
7812 out = prev;
7813 prev = cur;
7814 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007815 } else if ((cur->type == XML_ENTITY_NODE) ||
7816 (cur->type == XML_ENTITY_DECL))
7817 return (0);
7818 cur = cur->parent;
7819 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
7820 return (0);
7821}
7822
7823/*
7824* xmlSearchNsByPrefixStrict:
7825* @doc: the document
7826* @node: the start node
7827* @prefix: the searched namespace prefix
7828* @retNs: the resulting ns-decl
7829* @prefixed: if the found ns-decl must have a prefix (for attributes)
7830*
7831* Dynamically searches for a ns-declaration which matches
7832* the given @nsName in the ancestor-or-self axis of @node.
7833*
7834* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7835* and internal errors.
7836*/
7837static int
7838xmlSearchNsByPrefixStrict(xmlDocPtr doc, xmlNodePtr node,
7839 const xmlChar* prefix,
7840 xmlNsPtr *retNs)
7841{
7842 xmlNodePtr cur;
7843 xmlNsPtr ns;
7844
7845 if ((doc == NULL) || (node == NULL))
7846 return (-1);
7847
7848 if (retNs)
7849 *retNs = NULL;
7850 if (IS_STR_XML(prefix)) {
7851 if (retNs) {
7852 *retNs = xmlTreeEnsureXMLDecl(doc);
7853 if (*retNs == NULL)
7854 return (-1);
7855 }
7856 return (1);
7857 }
7858 cur = node;
7859 do {
7860 if (cur->type == XML_ELEMENT_NODE) {
7861 if (cur->nsDef != NULL) {
7862 ns = cur->nsDef;
7863 do {
7864 if ((prefix == ns->prefix) ||
7865 xmlStrEqual(prefix, ns->prefix))
7866 {
7867 /*
7868 * Disabled namespaces, e.g. xmlns:abc="".
7869 */
7870 if (ns->href == NULL)
7871 return(0);
7872 if (retNs)
7873 *retNs = ns;
7874 return (1);
7875 }
7876 ns = ns->next;
7877 } while (ns != NULL);
7878 }
7879 } else if ((cur->type == XML_ENTITY_NODE) ||
7880 (cur->type == XML_ENTITY_DECL))
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007881 return (0);
7882 cur = cur->parent;
7883 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
7884 return (0);
7885}
7886
7887/*
7888* xmlDOMWrapNSNormDeclareNsForced:
7889* @doc: the doc
7890* @elem: the element-node to declare on
7891* @nsName: the namespace-name of the ns-decl
7892* @prefix: the preferred prefix of the ns-decl
7893* @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls
7894*
7895* Declares a new namespace on @elem. It tries to use the
7896* given @prefix; if a ns-decl with the given prefix is already existent
7897* on @elem, it will generate an other prefix.
7898*
7899* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7900* and internal errors.
7901*/
7902static xmlNsPtr
7903xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc,
7904 xmlNodePtr elem,
7905 const xmlChar *nsName,
7906 const xmlChar *prefix,
7907 int checkShadow)
7908{
7909
7910 xmlNsPtr ret;
7911 char buf[50];
7912 const xmlChar *pref;
7913 int counter = 0;
7914 /*
7915 * Create a ns-decl on @anchor.
7916 */
7917 pref = prefix;
7918 while (1) {
7919 /*
7920 * Lookup whether the prefix is unused in elem's ns-decls.
7921 */
7922 if ((elem->nsDef != NULL) &&
7923 (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL))
7924 goto ns_next_prefix;
7925 if (checkShadow && elem->parent &&
7926 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
7927 /*
7928 * Does it shadow ancestor ns-decls?
7929 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007930 if (xmlSearchNsByPrefixStrict(doc, elem->parent, pref, NULL) == 1)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007931 goto ns_next_prefix;
7932 }
7933 ret = xmlNewNs(NULL, nsName, pref);
7934 if (ret == NULL)
7935 return (NULL);
7936 if (elem->nsDef == NULL)
7937 elem->nsDef = ret;
7938 else {
7939 xmlNsPtr ns2 = elem->nsDef;
7940 while (ns2->next != NULL)
7941 ns2 = ns2->next;
7942 ns2->next = ret;
7943 }
7944 return (ret);
7945ns_next_prefix:
7946 counter++;
7947 if (counter > 1000)
7948 return (NULL);
7949 if (prefix == NULL) {
7950 snprintf((char *) buf, sizeof(buf),
7951 "default%d", counter);
7952 } else
7953 snprintf((char *) buf, sizeof(buf),
7954 "%.30s%d", (char *)prefix, counter);
7955 pref = BAD_CAST buf;
7956 }
7957}
7958
7959/*
7960* xmlDOMWrapNSNormAquireNormalizedNs:
7961* @doc: the doc
7962* @elem: the element-node to declare namespaces on
7963* @ns: the ns-struct to use for the search
7964* @retNs: the found/created ns-struct
7965* @nsMap: the ns-map
7966* @topmi: the last ns-map entry
7967* @depth: the current tree depth
7968* @ancestorsOnly: search in ancestor ns-decls only
7969* @prefixed: if the searched ns-decl must have a prefix (for attributes)
7970*
7971* Searches for a matching ns-name in the ns-decls of @nsMap, if not
7972* found it will either declare it on @elem, or store it in doc->oldNs.
7973* If a new ns-decl needs to be declared on @elem, it tries to use the
7974* @ns->prefix for it, if this prefix is already in use on @elem, it will
7975* change the prefix or the new ns-decl.
7976*
7977* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
7978*/
7979static int
7980xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc,
7981 xmlNodePtr elem,
7982 xmlNsPtr ns,
7983 xmlNsPtr *retNs,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007984 xmlNsMapPtr *nsMap,
7985
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007986 int depth,
7987 int ancestorsOnly,
7988 int prefixed)
7989{
7990 xmlNsMapItemPtr mi;
7991
7992 if ((doc == NULL) || (ns == NULL) || (retNs == NULL) ||
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007993 (nsMap == NULL))
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007994 return (-1);
7995
7996 *retNs = NULL;
7997 /*
7998 * Handle XML namespace.
7999 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008000 if (IS_STR_XML(ns->prefix)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008001 /*
8002 * Insert XML namespace mapping.
8003 */
8004 *retNs = xmlTreeEnsureXMLDecl(doc);
8005 if (*retNs == NULL)
8006 return (-1);
8007 return (0);
8008 }
8009 /*
8010 * If the search should be done in ancestors only and no
8011 * @elem (the first ancestor) was specified, then skip the search.
8012 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008013 if ((! (ancestorsOnly && (elem == NULL))) && (XML_NSMAP_NOTEMPTY(*nsMap)))
8014 {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008015 /*
8016 * Try to find an equal ns-name in in-scope ns-decls.
8017 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008018 XML_NSMAP_FOREACH(*nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008019 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8020 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008021 * ancestorsOnly: This should be turned on to gain speed,
8022 * if one knows that the branch itself was already
8023 * ns-wellformed and no stale references existed.
8024 * I.e. it searches in the ancestor axis only.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008025 */
8026 ((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) &&
8027 /* Skip shadowed prefixes. */
8028 (mi->shadowDepth == -1) &&
8029 /* Skip xmlns="" or xmlns:foo="". */
8030 ((mi->newNs->href != NULL) &&
8031 (mi->newNs->href[0] != 0)) &&
8032 /* Ensure a prefix if wanted. */
8033 ((! prefixed) || (mi->newNs->prefix != NULL)) &&
8034 /* Equal ns name */
8035 ((mi->newNs->href == ns->href) ||
8036 xmlStrEqual(mi->newNs->href, ns->href))) {
8037 /* Set the mapping. */
8038 mi->oldNs = ns;
8039 *retNs = mi->newNs;
8040 return (0);
8041 }
8042 }
8043 }
8044 /*
8045 * No luck, the namespace is out of scope or shadowed.
8046 */
8047 if (elem == NULL) {
8048 xmlNsPtr tmpns;
8049
8050 /*
8051 * Store ns-decls in "oldNs" of the document-node.
8052 */
8053 tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix);
8054 if (tmpns == NULL)
8055 return (-1);
8056 /*
8057 * Insert mapping.
8058 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008059 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008060 tmpns, XML_TREE_NSMAP_DOC) == NULL) {
8061 xmlFreeNs(tmpns);
8062 return (-1);
8063 }
8064 *retNs = tmpns;
8065 } else {
8066 xmlNsPtr tmpns;
8067
8068 tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href,
8069 ns->prefix, 0);
8070 if (tmpns == NULL)
8071 return (-1);
8072
8073 if (*nsMap != NULL) {
8074 /*
8075 * Does it shadow ancestor ns-decls?
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008076 */
8077 XML_NSMAP_FOREACH(*nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008078 if ((mi->depth < depth) &&
8079 (mi->shadowDepth == -1) &&
8080 ((ns->prefix == mi->newNs->prefix) ||
8081 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8082 /*
8083 * Shadows.
8084 */
8085 mi->shadowDepth = depth;
8086 break;
8087 }
8088 }
8089 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008090 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, depth) == NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008091 xmlFreeNs(tmpns);
8092 return (-1);
8093 }
8094 *retNs = tmpns;
8095 }
8096 return (0);
8097}
8098
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008099typedef enum {
8100 XML_DOM_RECONNS_REMOVEREDUND = 1<<0
8101} xmlDOMReconcileNSOptions;
8102
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008103/*
8104* xmlDOMWrapReconcileNamespaces:
Daniel Veillard304e78c2005-07-03 16:19:41 +00008105* @ctxt: DOM wrapper context, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008106* @elem: the element-node
8107* @options: option flags
8108*
8109* Ensures that ns-references point to ns-decls hold on element-nodes.
8110* Ensures that the tree is namespace wellformed by creating additional
8111* ns-decls where needed. Note that, since prefixes of already existent
8112* ns-decls can be shadowed by this process, it could break QNames in
8113* attribute values or element content.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00008114* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008115*
8116* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008117*/
8118
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008119int
8120xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,
8121 xmlNodePtr elem,
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008122 int options)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008123{
8124 int depth = -1, adoptns = 0, parnsdone = 0;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008125 xmlNsPtr ns, prevns;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008126 xmlDocPtr doc;
8127 xmlNodePtr cur, curElem = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008128 xmlNsMapPtr nsMap = NULL;
8129 xmlNsMapItemPtr /* topmi = NULL, */ mi;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008130 /* @ancestorsOnly should be set by an option flag. */
8131 int ancestorsOnly = 0;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008132 int optRemoveDedundantNS =
8133 ((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0;
8134 xmlNsPtr *listRedund = NULL;
8135 int sizeRedund = 0, nbRedund = 0, ret, i, j;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008136
8137 if ((elem == NULL) || (elem->doc == NULL) ||
8138 (elem->type != XML_ELEMENT_NODE))
8139 return (-1);
8140
8141 doc = elem->doc;
8142 cur = elem;
8143 do {
8144 switch (cur->type) {
8145 case XML_ELEMENT_NODE:
8146 adoptns = 1;
8147 curElem = cur;
8148 depth++;
8149 /*
8150 * Namespace declarations.
8151 */
8152 if (cur->nsDef != NULL) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008153 prevns = NULL;
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008154 ns = cur->nsDef;
8155 while (ns != NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008156 if (! parnsdone) {
8157 if ((elem->parent) &&
8158 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8159 /*
8160 * Gather ancestor in-scope ns-decls.
8161 */
8162 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8163 elem->parent) == -1)
8164 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008165 }
8166 parnsdone = 1;
8167 }
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008168
8169 /*
8170 * Lookup the ns ancestor-axis for equal ns-decls in scope.
8171 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008172 if (optRemoveDedundantNS && XML_NSMAP_NOTEMPTY(nsMap)) {
8173 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008174 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8175 (mi->shadowDepth == -1) &&
8176 ((ns->prefix == mi->newNs->prefix) ||
8177 xmlStrEqual(ns->prefix, mi->newNs->prefix)) &&
8178 ((ns->href == mi->newNs->href) ||
8179 xmlStrEqual(ns->href, mi->newNs->href)))
8180 {
8181 /*
8182 * A redundant ns-decl was found.
8183 * Add it to the list of redundant ns-decls.
8184 */
8185 if (xmlDOMWrapNSNormAddNsMapItem2(&listRedund,
8186 &sizeRedund, &nbRedund, ns, mi->newNs) == -1)
8187 goto internal_error;
8188 /*
8189 * Remove the ns-decl from the element-node.
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008190 */
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008191 if (prevns)
8192 prevns->next = ns->next;
8193 else
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008194 cur->nsDef = ns->next;
8195 goto next_ns_decl;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008196 }
8197 }
8198 }
8199
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008200 /*
8201 * Skip ns-references handling if the referenced
8202 * ns-decl is declared on the same element.
8203 */
8204 if ((cur->ns != NULL) && adoptns && (cur->ns == ns))
8205 adoptns = 0;
8206 /*
8207 * Does it shadow any ns-decl?
8208 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008209 if (XML_NSMAP_NOTEMPTY(nsMap)) {
8210 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008211 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8212 (mi->shadowDepth == -1) &&
8213 ((ns->prefix == mi->newNs->prefix) ||
8214 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8215
8216 mi->shadowDepth = depth;
8217 }
8218 }
8219 }
8220 /*
8221 * Push mapping.
8222 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008223 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008224 depth) == NULL)
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008225 goto internal_error;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008226
8227 prevns = ns;
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008228next_ns_decl:
8229 ns = ns->next;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008230 }
8231 }
8232 if (! adoptns)
8233 goto ns_end;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008234 /* No break on purpose. */
8235 case XML_ATTRIBUTE_NODE:
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008236 /* No ns, no fun. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008237 if (cur->ns == NULL)
8238 goto ns_end;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008239
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008240 if (! parnsdone) {
8241 if ((elem->parent) &&
8242 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8243 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8244 elem->parent) == -1)
8245 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008246 }
8247 parnsdone = 1;
8248 }
8249 /*
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008250 * Adjust the reference if this was a redundant ns-decl.
8251 */
8252 if (listRedund) {
8253 for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8254 if (cur->ns == listRedund[j]) {
8255 cur->ns = listRedund[++j];
8256 break;
8257 }
8258 }
8259 }
8260 /*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008261 * Adopt ns-references.
8262 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008263 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008264 /*
8265 * Search for a mapping.
8266 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008267 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008268 if ((mi->shadowDepth == -1) &&
8269 (cur->ns == mi->oldNs)) {
8270
8271 cur->ns = mi->newNs;
8272 goto ns_end;
8273 }
8274 }
8275 }
8276 /*
8277 * Aquire a normalized ns-decl and add it to the map.
8278 */
8279 if (xmlDOMWrapNSNormAquireNormalizedNs(doc, curElem,
8280 cur->ns, &ns,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008281 &nsMap, depth,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008282 ancestorsOnly,
8283 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8284 goto internal_error;
8285 cur->ns = ns;
8286
8287ns_end:
8288 if ((cur->type == XML_ELEMENT_NODE) &&
8289 (cur->properties != NULL)) {
8290 /*
8291 * Process attributes.
8292 */
8293 cur = (xmlNodePtr) cur->properties;
8294 continue;
8295 }
8296 break;
8297 default:
8298 goto next_sibling;
8299 }
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008300into_content:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008301 if ((cur->type == XML_ELEMENT_NODE) &&
8302 (cur->children != NULL)) {
8303 /*
8304 * Process content of element-nodes only.
8305 */
8306 cur = cur->children;
8307 continue;
8308 }
8309next_sibling:
8310 if (cur == elem)
8311 break;
8312 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008313 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008314 /*
8315 * Pop mappings.
8316 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008317 while ((nsMap->last != NULL) &&
8318 (nsMap->last->depth >= depth))
8319 {
8320 XML_NSMAP_POP(nsMap, mi)
8321 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008322 /*
8323 * Unshadow.
8324 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008325 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008326 if (mi->shadowDepth >= depth)
8327 mi->shadowDepth = -1;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008328 }
8329 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008330 depth--;
8331 }
8332 if (cur->next != NULL)
8333 cur = cur->next;
8334 else {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008335 if (cur->type == XML_ATTRIBUTE_NODE) {
8336 cur = cur->parent;
8337 goto into_content;
8338 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008339 cur = cur->parent;
8340 goto next_sibling;
8341 }
8342 } while (cur != NULL);
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008343
8344 ret = 0;
8345 goto exit;
8346internal_error:
8347 ret = -1;
8348exit:
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008349 if (listRedund) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008350 for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8351 xmlFreeNs(listRedund[j]);
8352 }
8353 xmlFree(listRedund);
8354 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008355 if (nsMap != NULL)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008356 xmlDOMWrapNsMapFree(nsMap);
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008357 return (ret);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008358}
8359
8360/*
8361* xmlDOMWrapAdoptBranch:
8362* @ctxt: the optional context for custom processing
8363* @sourceDoc: the optional sourceDoc
8364* @node: the element-node to start with
8365* @destDoc: the destination doc for adoption
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008366* @destParent: the optional new parent of @node in @destDoc
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008367* @options: option flags
8368*
8369* Ensures that ns-references point to @destDoc: either to
8370* elements->nsDef entries if @destParent is given, or to
8371* @destDoc->oldNs otherwise.
8372* If @destParent is given, it ensures that the tree is namespace
8373* wellformed by creating additional ns-decls where needed.
8374* Note that, since prefixes of already existent ns-decls can be
8375* shadowed by this process, it could break QNames in attribute
8376* values or element content.
8377*
8378* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8379*/
8380static int
8381xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
8382 xmlDocPtr sourceDoc,
8383 xmlNodePtr node,
8384 xmlDocPtr destDoc,
8385 xmlNodePtr destParent,
8386 int options ATTRIBUTE_UNUSED)
8387{
8388 int ret = 0;
8389 xmlNodePtr cur, curElem = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008390 xmlNsMapPtr nsMap = NULL;
8391 xmlNsMapItemPtr mi;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008392 xmlNsPtr ns = NULL;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008393 int depth = -1, adoptStr = 1;
8394 /* gather @parent's ns-decls. */
8395 int parnsdone = 0;
8396 /* @ancestorsOnly should be set per option. */
8397 int ancestorsOnly = 0;
8398
8399 /*
8400 * Optimize string adoption for equal or none dicts.
8401 */
8402 if ((sourceDoc != NULL) &&
8403 (sourceDoc->dict == destDoc->dict))
8404 adoptStr = 0;
8405 else
8406 adoptStr = 1;
8407
8408 cur = node;
8409 while (cur != NULL) {
8410 if (cur->doc != sourceDoc) {
8411 /*
8412 * We'll assume XIncluded nodes if the doc differs.
8413 * TODO: Do we need to reconciliate XIncluded nodes?
8414 * This here skips XIncluded nodes and tries to handle
8415 * broken sequences.
8416 */
8417 if (cur->next == NULL)
8418 goto leave_node;
8419 do {
8420 cur = cur->next;
8421 if ((cur->type == XML_XINCLUDE_END) ||
8422 (cur->doc == node->doc))
8423 break;
8424 } while (cur->next != NULL);
8425
8426 if (cur->doc != node->doc)
8427 goto leave_node;
8428 }
8429 cur->doc = destDoc;
8430 switch (cur->type) {
8431 case XML_XINCLUDE_START:
8432 case XML_XINCLUDE_END:
8433 /*
8434 * TODO
8435 */
8436 return (-1);
8437 case XML_ELEMENT_NODE:
8438 curElem = cur;
8439 depth++;
8440 /*
8441 * Namespace declarations.
8442 */
8443 if ((ctxt == NULL) && (cur->nsDef != NULL)) {
8444 if (! parnsdone) {
8445 if (destParent && (ctxt == NULL)) {
8446 /*
8447 * Gather @parent's in-scope ns-decls.
8448 */
8449 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8450 destParent) == -1)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008451 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008452 }
8453 parnsdone = 1;
8454 }
8455 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8456 /*
8457 * ns->prefix and ns->href seem not to be in the dict.
8458 * XML_TREE_ADOPT_STR(ns->prefix)
8459 * XML_TREE_ADOPT_STR(ns->href)
8460 */
8461 /*
8462 * Does it shadow any ns-decl?
8463 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008464 if (XML_NSMAP_NOTEMPTY(nsMap)) {
8465 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008466 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8467 (mi->shadowDepth == -1) &&
8468 ((ns->prefix == mi->newNs->prefix) ||
8469 xmlStrEqual(ns->prefix,
8470 mi->newNs->prefix))) {
8471
8472 mi->shadowDepth = depth;
8473 }
8474 }
8475 }
8476 /*
8477 * Push mapping.
8478 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008479 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008480 ns, ns, depth) == NULL)
8481 goto internal_error;
8482 }
8483 }
8484 /* No break on purpose. */
8485 case XML_ATTRIBUTE_NODE:
8486
8487 if (cur->ns == NULL)
8488 goto ns_end;
8489 if (! parnsdone) {
8490 if (destParent && (ctxt == NULL)) {
8491 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8492 destParent) == -1)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008493 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008494 }
8495 parnsdone = 1;
8496 }
8497 /*
8498 * Adopt ns-references.
8499 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008500 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008501 /*
8502 * Search for a mapping.
8503 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008504 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008505 if ((mi->shadowDepth == -1) &&
8506 (cur->ns == mi->oldNs)) {
8507
8508 cur->ns = mi->newNs;
8509 goto ns_end;
8510 }
8511 }
8512 }
8513 /*
8514 * Start searching for an in-scope ns-decl.
8515 */
8516 if (ctxt != NULL) {
8517 /*
8518 * User-defined behaviour.
8519 */
8520#if 0
8521 ctxt->aquireNsDecl(ctxt, cur->ns, &ns);
8522#endif
8523 /*
8524 * Insert mapping if ns is available; it's the users fault
8525 * if not.
8526 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008527 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008528 ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
8529 goto internal_error;
8530 cur->ns = ns;
8531 } else {
8532 /*
8533 * Aquire a normalized ns-decl and add it to the map.
8534 */
8535 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
8536 /* ns-decls on curElem or on destDoc->oldNs */
8537 destParent ? curElem : NULL,
8538 cur->ns, &ns,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008539 &nsMap, depth,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008540 ancestorsOnly,
8541 /* ns-decls must be prefixed for attributes. */
8542 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8543 goto internal_error;
8544 cur->ns = ns;
8545 }
8546ns_end:
8547 /*
8548 * Further node properties.
8549 * TODO: Is this all?
8550 */
8551 XML_TREE_ADOPT_STR(cur->name)
8552 if (cur->type == XML_ELEMENT_NODE) {
8553 cur->psvi = NULL;
8554 cur->line = 0;
8555 cur->extra = 0;
8556 /*
8557 * Walk attributes.
8558 */
8559 if (cur->properties != NULL) {
8560 /*
8561 * Process first attribute node.
8562 */
8563 cur = (xmlNodePtr) cur->properties;
8564 continue;
8565 }
8566 } else {
8567 /*
8568 * Attributes.
8569 */
8570 if ((sourceDoc != NULL) &&
8571 (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID))
8572 xmlRemoveID(sourceDoc, (xmlAttrPtr) cur);
8573 ((xmlAttrPtr) cur)->atype = 0;
8574 ((xmlAttrPtr) cur)->psvi = NULL;
8575 }
8576 break;
8577 case XML_TEXT_NODE:
8578 case XML_CDATA_SECTION_NODE:
8579 /*
8580 * This puts the content in the dest dict, only if
8581 * it was previously in the source dict.
8582 */
8583 XML_TREE_ADOPT_STR_2(cur->content)
8584 goto leave_node;
8585 case XML_ENTITY_REF_NODE:
8586 /*
8587 * Remove reference to the entitity-node.
8588 */
8589 cur->content = NULL;
8590 cur->children = NULL;
8591 cur->last = NULL;
8592 if ((destDoc->intSubset) || (destDoc->extSubset)) {
8593 xmlEntityPtr ent;
8594 /*
8595 * Assign new entity-node if available.
8596 */
8597 ent = xmlGetDocEntity(destDoc, cur->name);
8598 if (ent != NULL) {
8599 cur->content = ent->content;
8600 cur->children = (xmlNodePtr) ent;
8601 cur->last = (xmlNodePtr) ent;
8602 }
8603 }
8604 goto leave_node;
8605 case XML_PI_NODE:
8606 XML_TREE_ADOPT_STR(cur->name)
8607 XML_TREE_ADOPT_STR_2(cur->content)
8608 break;
8609 case XML_COMMENT_NODE:
8610 break;
8611 default:
8612 goto internal_error;
8613 }
8614 /*
8615 * Walk the tree.
8616 */
8617 if (cur->children != NULL) {
8618 cur = cur->children;
8619 continue;
8620 }
8621
8622leave_node:
8623 if (cur == node)
8624 break;
8625 if ((cur->type == XML_ELEMENT_NODE) ||
8626 (cur->type == XML_XINCLUDE_START) ||
8627 (cur->type == XML_XINCLUDE_END)) {
8628 /*
8629 * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
8630 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008631 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008632 /*
8633 * Pop mappings.
8634 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008635 while ((nsMap->last != NULL) &&
8636 (nsMap->last->depth >= depth))
8637 {
8638 XML_NSMAP_POP(nsMap, mi)
8639 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008640 /*
8641 * Unshadow.
8642 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008643 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008644 if (mi->shadowDepth >= depth)
8645 mi->shadowDepth = -1;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008646 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008647 }
8648 depth--;
8649 }
8650 if (cur->next != NULL)
8651 cur = cur->next;
8652 else {
8653 cur = cur->parent;
8654 goto leave_node;
8655 }
8656 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008657
8658 goto exit;
8659
8660internal_error:
8661 ret = -1;
8662
8663exit:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008664 /*
8665 * Cleanup.
8666 */
8667 if (nsMap != NULL)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008668 xmlDOMWrapNsMapFree(nsMap);
8669 return(ret);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008670}
8671
8672/*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008673* xmlDOMWrapCloneNode:
8674* @ctxt: the optional context for custom processing
8675* @sourceDoc: the optional sourceDoc
8676* @node: the node to start with
8677* @resNode: the clone of the given @node
8678* @destDoc: the destination doc
8679* @destParent: the optional new parent of @node in @destDoc
8680* @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"