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