blob: ff3cb75a132d36a97bc4d894d7b2b7ddb9994222 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
Daniel Veillardd5c2f922002-11-21 14:10:52 +00004 * References:
5 * XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
6 *
Owen Taylor3473f882001-02-23 17:55:21 +00007 * See Copyright for the status of this software.
8 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00009 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000010 *
Owen Taylor3473f882001-02-23 17:55:21 +000011 */
12
Daniel Veillard34ce8be2002-03-18 19:37:11 +000013#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000014#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000015
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24#ifdef HAVE_ZLIB_H
25#include <zlib.h>
26#endif
27
28#include <libxml/xmlmemory.h>
29#include <libxml/tree.h>
30#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000031#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000032#include <libxml/entities.h>
33#include <libxml/valid.h>
34#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000035#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000036#include <libxml/globals.h>
Daniel Veillardd5c2f922002-11-21 14:10:52 +000037#ifdef LIBXML_HTML_ENABLED
38#include <libxml/HTMLtree.h>
39#endif
William M. Brack1d8c9b22004-12-25 10:14:57 +000040#ifdef LIBXML_DEBUG_ENABLED
41#include <libxml/debugXML.h>
42#endif
Owen Taylor3473f882001-02-23 17:55:21 +000043
Daniel Veillarda880b122003-04-21 21:36:41 +000044int __xmlRegisterCallbacks = 0;
45
Daniel Veillard56a4cb82001-03-24 17:00:36 +000046xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
47
48/************************************************************************
49 * *
Daniel Veillard18ec16e2003-10-07 23:16:40 +000050 * Tree memory error handler *
51 * *
52 ************************************************************************/
53/**
54 * xmlTreeErrMemory:
55 * @extra: extra informations
56 *
57 * Handle an out of memory condition
58 */
59static void
60xmlTreeErrMemory(const char *extra)
61{
62 __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
63}
64
65/**
66 * xmlTreeErr:
67 * @code: the error number
68 * @extra: extra informations
69 *
70 * Handle an out of memory condition
71 */
72static void
73xmlTreeErr(int code, xmlNodePtr node, const char *extra)
74{
75 const char *msg = NULL;
76
77 switch(code) {
78 case XML_TREE_INVALID_HEX:
Daniel Veillardac996a12004-07-30 12:02:58 +000079 msg = "invalid hexadecimal character value\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000080 break;
81 case XML_TREE_INVALID_DEC:
Daniel Veillardac996a12004-07-30 12:02:58 +000082 msg = "invalid decimal character value\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000083 break;
84 case XML_TREE_UNTERMINATED_ENTITY:
Daniel Veillardac996a12004-07-30 12:02:58 +000085 msg = "unterminated entity reference %15s\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000086 break;
87 default:
Daniel Veillardac996a12004-07-30 12:02:58 +000088 msg = "unexpected error number\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000089 }
90 __xmlSimpleError(XML_FROM_TREE, code, node, msg, extra);
91}
92
93/************************************************************************
94 * *
Daniel Veillard56a4cb82001-03-24 17:00:36 +000095 * A few static variables and macros *
96 * *
97 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000098/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000099const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +0000100/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +0000101const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +0000102 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +0000103/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +0000104const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
105
Owen Taylor3473f882001-02-23 17:55:21 +0000106static int xmlCompressMode = 0;
107static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000108
Owen Taylor3473f882001-02-23 17:55:21 +0000109#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
110 xmlNodePtr ulccur = (n)->children; \
111 if (ulccur == NULL) { \
112 (n)->last = NULL; \
113 } else { \
114 while (ulccur->next != NULL) { \
115 ulccur->parent = (n); \
116 ulccur = ulccur->next; \
117 } \
118 ulccur->parent = (n); \
119 (n)->last = ulccur; \
120}}
121
Kasimier T. Buchcik44353412006-03-06 13:26:16 +0000122#define IS_STR_XML(str) ((str != NULL) && (str[0] == 'x') && \
123 (str[1] == 'm') && (str[2] == 'l') && (str[3] == 0))
124
Owen Taylor3473f882001-02-23 17:55:21 +0000125/* #define DEBUG_BUFFER */
126/* #define DEBUG_TREE */
127
128/************************************************************************
129 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000130 * Functions to move to entities.c once the *
131 * API freeze is smoothen and they can be made public. *
132 * *
133 ************************************************************************/
134#include <libxml/hash.h>
135
Daniel Veillard652327a2003-09-29 18:02:38 +0000136#ifdef LIBXML_TREE_ENABLED
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000137/**
138 * xmlGetEntityFromDtd:
139 * @dtd: A pointer to the DTD to search
140 * @name: The entity name
141 *
142 * Do an entity lookup in the DTD entity hash table and
143 * return the corresponding entity, if found.
144 *
145 * Returns A pointer to the entity structure or NULL if not found.
146 */
147static xmlEntityPtr
148xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
149 xmlEntitiesTablePtr table;
150
151 if((dtd != NULL) && (dtd->entities != NULL)) {
152 table = (xmlEntitiesTablePtr) dtd->entities;
153 return((xmlEntityPtr) xmlHashLookup(table, name));
154 /* return(xmlGetEntityFromTable(table, name)); */
155 }
156 return(NULL);
157}
158/**
159 * xmlGetParameterEntityFromDtd:
160 * @dtd: A pointer to the DTD to search
161 * @name: The entity name
162 *
163 * Do an entity lookup in the DTD pararmeter entity hash table and
164 * return the corresponding entity, if found.
165 *
166 * Returns A pointer to the entity structure or NULL if not found.
167 */
168static xmlEntityPtr
169xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
170 xmlEntitiesTablePtr table;
171
172 if ((dtd != NULL) && (dtd->pentities != NULL)) {
173 table = (xmlEntitiesTablePtr) dtd->pentities;
174 return((xmlEntityPtr) xmlHashLookup(table, name));
175 /* return(xmlGetEntityFromTable(table, name)); */
176 }
177 return(NULL);
178}
Daniel Veillard652327a2003-09-29 18:02:38 +0000179#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000180
181/************************************************************************
182 * *
Daniel Veillardc00cda82003-04-07 10:22:39 +0000183 * QName handling helper *
184 * *
185 ************************************************************************/
186
187/**
188 * xmlBuildQName:
189 * @ncname: the Name
190 * @prefix: the prefix
191 * @memory: preallocated memory
192 * @len: preallocated memory length
193 *
194 * Builds the QName @prefix:@ncname in @memory if there is enough space
195 * and prefix is not NULL nor empty, otherwise allocate a new string.
196 * If prefix is NULL or empty it returns ncname.
197 *
198 * Returns the new string which must be freed by the caller if different from
199 * @memory and @ncname or NULL in case of error
200 */
201xmlChar *
202xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
203 xmlChar *memory, int len) {
204 int lenn, lenp;
205 xmlChar *ret;
206
Daniel Veillard3b7840c2003-09-11 23:42:01 +0000207 if (ncname == NULL) return(NULL);
208 if (prefix == NULL) return((xmlChar *) ncname);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000209
210 lenn = strlen((char *) ncname);
211 lenp = strlen((char *) prefix);
212
213 if ((memory == NULL) || (len < lenn + lenp + 2)) {
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000214 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000215 if (ret == NULL) {
216 xmlTreeErrMemory("building QName");
217 return(NULL);
218 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000219 } else {
220 ret = memory;
221 }
222 memcpy(&ret[0], prefix, lenp);
223 ret[lenp] = ':';
224 memcpy(&ret[lenp + 1], ncname, lenn);
225 ret[lenn + lenp + 1] = 0;
226 return(ret);
227}
228
229/**
230 * xmlSplitQName2:
231 * @name: the full QName
232 * @prefix: a xmlChar **
233 *
234 * parse an XML qualified name string
235 *
236 * [NS 5] QName ::= (Prefix ':')? LocalPart
237 *
238 * [NS 6] Prefix ::= NCName
239 *
240 * [NS 7] LocalPart ::= NCName
241 *
242 * Returns NULL if not a QName, otherwise the local part, and prefix
243 * is updated to get the Prefix if any.
244 */
245
246xmlChar *
247xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
248 int len = 0;
249 xmlChar *ret = NULL;
250
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000251 if (prefix == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000252 *prefix = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000253 if (name == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000254
255#ifndef XML_XML_NAMESPACE
256 /* xml: prefix is not really a namespace */
257 if ((name[0] == 'x') && (name[1] == 'm') &&
258 (name[2] == 'l') && (name[3] == ':'))
259 return(NULL);
260#endif
261
262 /* nasty but valid */
263 if (name[0] == ':')
264 return(NULL);
265
266 /*
267 * we are not trying to validate but just to cut, and yes it will
268 * work even if this is as set of UTF-8 encoded chars
269 */
270 while ((name[len] != 0) && (name[len] != ':'))
271 len++;
272
273 if (name[len] == 0)
274 return(NULL);
275
276 *prefix = xmlStrndup(name, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000277 if (*prefix == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000278 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000279 return(NULL);
280 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000281 ret = xmlStrdup(&name[len + 1]);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000282 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000283 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000284 if (*prefix != NULL) {
285 xmlFree(*prefix);
286 *prefix = NULL;
287 }
288 return(NULL);
289 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000290
291 return(ret);
292}
293
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000294/**
295 * xmlSplitQName3:
296 * @name: the full QName
297 * @len: an int *
298 *
299 * parse an XML qualified name string,i
300 *
301 * returns NULL if it is not a Qualified Name, otherwise, update len
302 * with the lenght in byte of the prefix and return a pointer
Daniel Veillard54f9a4f2005-09-03 13:28:24 +0000303 * to the start of the name without the prefix
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000304 */
305
306const xmlChar *
307xmlSplitQName3(const xmlChar *name, int *len) {
308 int l = 0;
309
310 if (name == NULL) return(NULL);
311 if (len == NULL) return(NULL);
312
313 /* nasty but valid */
314 if (name[0] == ':')
315 return(NULL);
316
317 /*
318 * we are not trying to validate but just to cut, and yes it will
319 * work even if this is as set of UTF-8 encoded chars
320 */
321 while ((name[l] != 0) && (name[l] != ':'))
322 l++;
323
324 if (name[l] == 0)
325 return(NULL);
326
327 *len = l;
328
329 return(&name[l+1]);
330}
331
Daniel Veillardc00cda82003-04-07 10:22:39 +0000332/************************************************************************
333 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000334 * Check Name, NCName and QName strings *
335 * *
336 ************************************************************************/
337
338#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
339
Daniel Veillard6b6d6802005-07-03 21:00:34 +0000340#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED) || defined (LIBXML_HTML_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000341/**
342 * xmlValidateNCName:
343 * @value: the value to check
344 * @space: allow spaces in front and end of the string
345 *
346 * Check that a value conforms to the lexical space of NCName
347 *
348 * Returns 0 if this validates, a positive error code number otherwise
349 * and -1 in case of internal or API error.
350 */
351int
352xmlValidateNCName(const xmlChar *value, int space) {
353 const xmlChar *cur = value;
354 int c,l;
355
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000356 if (value == NULL)
357 return(-1);
358
Daniel Veillardd2298792003-02-14 16:54:11 +0000359 /*
360 * First quick algorithm for ASCII range
361 */
362 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000363 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000364 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
365 (*cur == '_'))
366 cur++;
367 else
368 goto try_complex;
369 while (((*cur >= 'a') && (*cur <= 'z')) ||
370 ((*cur >= 'A') && (*cur <= 'Z')) ||
371 ((*cur >= '0') && (*cur <= '9')) ||
372 (*cur == '_') || (*cur == '-') || (*cur == '.'))
373 cur++;
374 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000375 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000376 if (*cur == 0)
377 return(0);
378
379try_complex:
380 /*
381 * Second check for chars outside the ASCII range
382 */
383 cur = value;
384 c = CUR_SCHAR(cur, l);
385 if (space) {
386 while (IS_BLANK(c)) {
387 cur += l;
388 c = CUR_SCHAR(cur, l);
389 }
390 }
William M. Brack871611b2003-10-18 04:53:14 +0000391 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000392 return(1);
393 cur += l;
394 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000395 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
396 (c == '-') || (c == '_') || IS_COMBINING(c) ||
397 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000398 cur += l;
399 c = CUR_SCHAR(cur, l);
400 }
401 if (space) {
402 while (IS_BLANK(c)) {
403 cur += l;
404 c = CUR_SCHAR(cur, l);
405 }
406 }
407 if (c != 0)
408 return(1);
409
410 return(0);
411}
Daniel Veillard2156d432004-03-04 15:59:36 +0000412#endif
Daniel Veillardd2298792003-02-14 16:54:11 +0000413
Daniel Veillard2156d432004-03-04 15:59:36 +0000414#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000415/**
416 * xmlValidateQName:
417 * @value: the value to check
418 * @space: allow spaces in front and end of the string
419 *
420 * Check that a value conforms to the lexical space of QName
421 *
422 * Returns 0 if this validates, a positive error code number otherwise
423 * and -1 in case of internal or API error.
424 */
425int
426xmlValidateQName(const xmlChar *value, int space) {
427 const xmlChar *cur = value;
428 int c,l;
429
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000430 if (value == NULL)
431 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +0000432 /*
433 * First quick algorithm for ASCII range
434 */
435 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000436 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000437 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
438 (*cur == '_'))
439 cur++;
440 else
441 goto try_complex;
442 while (((*cur >= 'a') && (*cur <= 'z')) ||
443 ((*cur >= 'A') && (*cur <= 'Z')) ||
444 ((*cur >= '0') && (*cur <= '9')) ||
445 (*cur == '_') || (*cur == '-') || (*cur == '.'))
446 cur++;
447 if (*cur == ':') {
448 cur++;
449 if (((*cur >= 'a') && (*cur <= 'z')) ||
450 ((*cur >= 'A') && (*cur <= 'Z')) ||
451 (*cur == '_'))
452 cur++;
453 else
454 goto try_complex;
455 while (((*cur >= 'a') && (*cur <= 'z')) ||
456 ((*cur >= 'A') && (*cur <= 'Z')) ||
457 ((*cur >= '0') && (*cur <= '9')) ||
458 (*cur == '_') || (*cur == '-') || (*cur == '.'))
459 cur++;
460 }
461 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000462 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000463 if (*cur == 0)
464 return(0);
465
466try_complex:
467 /*
468 * Second check for chars outside the ASCII range
469 */
470 cur = value;
471 c = CUR_SCHAR(cur, l);
472 if (space) {
473 while (IS_BLANK(c)) {
474 cur += l;
475 c = CUR_SCHAR(cur, l);
476 }
477 }
William M. Brack871611b2003-10-18 04:53:14 +0000478 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000479 return(1);
480 cur += l;
481 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000482 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
483 (c == '-') || (c == '_') || IS_COMBINING(c) ||
484 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000485 cur += l;
486 c = CUR_SCHAR(cur, l);
487 }
488 if (c == ':') {
489 cur += l;
490 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000491 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000492 return(1);
493 cur += l;
494 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000495 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
496 (c == '-') || (c == '_') || IS_COMBINING(c) ||
497 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000498 cur += l;
499 c = CUR_SCHAR(cur, l);
500 }
501 }
502 if (space) {
503 while (IS_BLANK(c)) {
504 cur += l;
505 c = CUR_SCHAR(cur, l);
506 }
507 }
508 if (c != 0)
509 return(1);
510 return(0);
511}
512
513/**
514 * xmlValidateName:
515 * @value: the value to check
516 * @space: allow spaces in front and end of the string
517 *
518 * Check that a value conforms to the lexical space of Name
519 *
520 * Returns 0 if this validates, a positive error code number otherwise
521 * and -1 in case of internal or API error.
522 */
523int
524xmlValidateName(const xmlChar *value, int space) {
525 const xmlChar *cur = value;
526 int c,l;
527
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000528 if (value == NULL)
529 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +0000530 /*
531 * First quick algorithm for ASCII range
532 */
533 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000534 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000535 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
536 (*cur == '_') || (*cur == ':'))
537 cur++;
538 else
539 goto try_complex;
540 while (((*cur >= 'a') && (*cur <= 'z')) ||
541 ((*cur >= 'A') && (*cur <= 'Z')) ||
542 ((*cur >= '0') && (*cur <= '9')) ||
543 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
544 cur++;
545 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000546 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000547 if (*cur == 0)
548 return(0);
549
550try_complex:
551 /*
552 * Second check for chars outside the ASCII range
553 */
554 cur = value;
555 c = CUR_SCHAR(cur, l);
556 if (space) {
557 while (IS_BLANK(c)) {
558 cur += l;
559 c = CUR_SCHAR(cur, l);
560 }
561 }
William M. Brack871611b2003-10-18 04:53:14 +0000562 if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000563 return(1);
564 cur += l;
565 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000566 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
567 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000568 cur += l;
569 c = CUR_SCHAR(cur, l);
570 }
571 if (space) {
572 while (IS_BLANK(c)) {
573 cur += l;
574 c = CUR_SCHAR(cur, l);
575 }
576 }
577 if (c != 0)
578 return(1);
579 return(0);
580}
581
Daniel Veillardd4310742003-02-18 21:12:46 +0000582/**
583 * xmlValidateNMToken:
584 * @value: the value to check
585 * @space: allow spaces in front and end of the string
586 *
587 * Check that a value conforms to the lexical space of NMToken
588 *
589 * Returns 0 if this validates, a positive error code number otherwise
590 * and -1 in case of internal or API error.
591 */
592int
593xmlValidateNMToken(const xmlChar *value, int space) {
594 const xmlChar *cur = value;
595 int c,l;
596
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000597 if (value == NULL)
598 return(-1);
Daniel Veillardd4310742003-02-18 21:12:46 +0000599 /*
600 * First quick algorithm for ASCII range
601 */
602 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000603 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000604 if (((*cur >= 'a') && (*cur <= 'z')) ||
605 ((*cur >= 'A') && (*cur <= 'Z')) ||
606 ((*cur >= '0') && (*cur <= '9')) ||
607 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
608 cur++;
609 else
610 goto try_complex;
611 while (((*cur >= 'a') && (*cur <= 'z')) ||
612 ((*cur >= 'A') && (*cur <= 'Z')) ||
613 ((*cur >= '0') && (*cur <= '9')) ||
614 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
615 cur++;
616 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000617 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000618 if (*cur == 0)
619 return(0);
620
621try_complex:
622 /*
623 * Second check for chars outside the ASCII range
624 */
625 cur = value;
626 c = CUR_SCHAR(cur, l);
627 if (space) {
628 while (IS_BLANK(c)) {
629 cur += l;
630 c = CUR_SCHAR(cur, l);
631 }
632 }
William M. Brack871611b2003-10-18 04:53:14 +0000633 if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
634 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
Daniel Veillardd4310742003-02-18 21:12:46 +0000635 return(1);
636 cur += l;
637 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000638 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
639 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd4310742003-02-18 21:12:46 +0000640 cur += l;
641 c = CUR_SCHAR(cur, l);
642 }
643 if (space) {
644 while (IS_BLANK(c)) {
645 cur += l;
646 c = CUR_SCHAR(cur, l);
647 }
648 }
649 if (c != 0)
650 return(1);
651 return(0);
652}
Daniel Veillard652327a2003-09-29 18:02:38 +0000653#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardd4310742003-02-18 21:12:46 +0000654
Daniel Veillardd2298792003-02-14 16:54:11 +0000655/************************************************************************
656 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000657 * Allocation and deallocation of basic structures *
658 * *
659 ************************************************************************/
660
661/**
662 * xmlSetBufferAllocationScheme:
663 * @scheme: allocation method to use
664 *
665 * Set the buffer allocation method. Types are
666 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
667 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
668 * improves performance
669 */
670void
671xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
672 xmlBufferAllocScheme = scheme;
673}
674
675/**
676 * xmlGetBufferAllocationScheme:
677 *
678 * Types are
679 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
680 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
681 * improves performance
682 *
683 * Returns the current allocation scheme
684 */
685xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000686xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000687 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000688}
689
690/**
691 * xmlNewNs:
692 * @node: the element carrying the namespace
693 * @href: the URI associated
694 * @prefix: the prefix for the namespace
695 *
696 * Creation of a new Namespace. This function will refuse to create
697 * a namespace with a similar prefix than an existing one present on this
698 * node.
699 * We use href==NULL in the case of an element creation where the namespace
700 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000701 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000702 */
703xmlNsPtr
704xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
705 xmlNsPtr cur;
706
707 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
708 return(NULL);
709
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000710 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
711 return(NULL);
712
Owen Taylor3473f882001-02-23 17:55:21 +0000713 /*
714 * Allocate a new Namespace and fill the fields.
715 */
716 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
717 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000718 xmlTreeErrMemory("building namespace");
Owen Taylor3473f882001-02-23 17:55:21 +0000719 return(NULL);
720 }
721 memset(cur, 0, sizeof(xmlNs));
722 cur->type = XML_LOCAL_NAMESPACE;
723
724 if (href != NULL)
725 cur->href = xmlStrdup(href);
726 if (prefix != NULL)
727 cur->prefix = xmlStrdup(prefix);
728
729 /*
730 * Add it at the end to preserve parsing order ...
731 * and checks for existing use of the prefix
732 */
733 if (node != NULL) {
734 if (node->nsDef == NULL) {
735 node->nsDef = cur;
736 } else {
737 xmlNsPtr prev = node->nsDef;
738
739 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
740 (xmlStrEqual(prev->prefix, cur->prefix))) {
741 xmlFreeNs(cur);
742 return(NULL);
743 }
744 while (prev->next != NULL) {
745 prev = prev->next;
746 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
747 (xmlStrEqual(prev->prefix, cur->prefix))) {
748 xmlFreeNs(cur);
749 return(NULL);
750 }
751 }
752 prev->next = cur;
753 }
754 }
755 return(cur);
756}
757
758/**
759 * xmlSetNs:
760 * @node: a node in the document
761 * @ns: a namespace pointer
762 *
763 * Associate a namespace to a node, a posteriori.
764 */
765void
766xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
767 if (node == NULL) {
768#ifdef DEBUG_TREE
769 xmlGenericError(xmlGenericErrorContext,
770 "xmlSetNs: node == NULL\n");
771#endif
772 return;
773 }
774 node->ns = ns;
775}
776
777/**
778 * xmlFreeNs:
779 * @cur: the namespace pointer
780 *
781 * Free up the structures associated to a namespace
782 */
783void
784xmlFreeNs(xmlNsPtr cur) {
785 if (cur == NULL) {
786#ifdef DEBUG_TREE
787 xmlGenericError(xmlGenericErrorContext,
788 "xmlFreeNs : ns == NULL\n");
789#endif
790 return;
791 }
792 if (cur->href != NULL) xmlFree((char *) cur->href);
793 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000794 xmlFree(cur);
795}
796
797/**
798 * xmlFreeNsList:
799 * @cur: the first namespace pointer
800 *
801 * Free up all the structures associated to the chained namespaces.
802 */
803void
804xmlFreeNsList(xmlNsPtr cur) {
805 xmlNsPtr next;
806 if (cur == NULL) {
807#ifdef DEBUG_TREE
808 xmlGenericError(xmlGenericErrorContext,
809 "xmlFreeNsList : ns == NULL\n");
810#endif
811 return;
812 }
813 while (cur != NULL) {
814 next = cur->next;
815 xmlFreeNs(cur);
816 cur = next;
817 }
818}
819
820/**
821 * xmlNewDtd:
822 * @doc: the document pointer
823 * @name: the DTD name
824 * @ExternalID: the external ID
825 * @SystemID: the system ID
826 *
827 * Creation of a new DTD for the external subset. To create an
828 * internal subset, use xmlCreateIntSubset().
829 *
830 * Returns a pointer to the new DTD structure
831 */
832xmlDtdPtr
833xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
834 const xmlChar *ExternalID, const xmlChar *SystemID) {
835 xmlDtdPtr cur;
836
837 if ((doc != NULL) && (doc->extSubset != NULL)) {
838#ifdef DEBUG_TREE
839 xmlGenericError(xmlGenericErrorContext,
840 "xmlNewDtd(%s): document %s already have a DTD %s\n",
841 /* !!! */ (char *) name, doc->name,
842 /* !!! */ (char *)doc->extSubset->name);
843#endif
844 return(NULL);
845 }
846
847 /*
848 * Allocate a new DTD and fill the fields.
849 */
850 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
851 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000852 xmlTreeErrMemory("building DTD");
Owen Taylor3473f882001-02-23 17:55:21 +0000853 return(NULL);
854 }
855 memset(cur, 0 , sizeof(xmlDtd));
856 cur->type = XML_DTD_NODE;
857
858 if (name != NULL)
859 cur->name = xmlStrdup(name);
860 if (ExternalID != NULL)
861 cur->ExternalID = xmlStrdup(ExternalID);
862 if (SystemID != NULL)
863 cur->SystemID = xmlStrdup(SystemID);
864 if (doc != NULL)
865 doc->extSubset = cur;
866 cur->doc = doc;
867
Daniel Veillarda880b122003-04-21 21:36:41 +0000868 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000869 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000870 return(cur);
871}
872
873/**
874 * xmlGetIntSubset:
875 * @doc: the document pointer
876 *
877 * Get the internal subset of a document
878 * Returns a pointer to the DTD structure or NULL if not found
879 */
880
881xmlDtdPtr
882xmlGetIntSubset(xmlDocPtr doc) {
883 xmlNodePtr cur;
884
885 if (doc == NULL)
886 return(NULL);
887 cur = doc->children;
888 while (cur != NULL) {
889 if (cur->type == XML_DTD_NODE)
890 return((xmlDtdPtr) cur);
891 cur = cur->next;
892 }
893 return((xmlDtdPtr) doc->intSubset);
894}
895
896/**
897 * xmlCreateIntSubset:
898 * @doc: the document pointer
899 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000900 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000901 * @SystemID: the system ID
902 *
903 * Create the internal subset of a document
904 * Returns a pointer to the new DTD structure
905 */
906xmlDtdPtr
907xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
908 const xmlChar *ExternalID, const xmlChar *SystemID) {
909 xmlDtdPtr cur;
910
911 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
912#ifdef DEBUG_TREE
913 xmlGenericError(xmlGenericErrorContext,
914
915 "xmlCreateIntSubset(): document %s already have an internal subset\n",
916 doc->name);
917#endif
918 return(NULL);
919 }
920
921 /*
922 * Allocate a new DTD and fill the fields.
923 */
924 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
925 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000926 xmlTreeErrMemory("building internal subset");
Owen Taylor3473f882001-02-23 17:55:21 +0000927 return(NULL);
928 }
929 memset(cur, 0, sizeof(xmlDtd));
930 cur->type = XML_DTD_NODE;
931
William M. Bracka3215c72004-07-31 16:24:01 +0000932 if (name != NULL) {
933 cur->name = xmlStrdup(name);
934 if (cur->name == NULL) {
935 xmlTreeErrMemory("building internal subset");
936 xmlFree(cur);
937 return(NULL);
938 }
939 }
940 if (ExternalID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000941 cur->ExternalID = xmlStrdup(ExternalID);
William M. Bracka3215c72004-07-31 16:24:01 +0000942 if (cur->ExternalID == NULL) {
943 xmlTreeErrMemory("building internal subset");
944 if (cur->name != NULL)
945 xmlFree((char *)cur->name);
946 xmlFree(cur);
947 return(NULL);
948 }
949 }
950 if (SystemID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000951 cur->SystemID = xmlStrdup(SystemID);
William M. Bracka3215c72004-07-31 16:24:01 +0000952 if (cur->SystemID == NULL) {
953 xmlTreeErrMemory("building internal subset");
954 if (cur->name != NULL)
955 xmlFree((char *)cur->name);
956 if (cur->ExternalID != NULL)
957 xmlFree((char *)cur->ExternalID);
958 xmlFree(cur);
959 return(NULL);
960 }
961 }
Owen Taylor3473f882001-02-23 17:55:21 +0000962 if (doc != NULL) {
963 doc->intSubset = cur;
964 cur->parent = doc;
965 cur->doc = doc;
966 if (doc->children == NULL) {
967 doc->children = (xmlNodePtr) cur;
968 doc->last = (xmlNodePtr) cur;
969 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000970 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000971 xmlNodePtr prev;
972
Owen Taylor3473f882001-02-23 17:55:21 +0000973 prev = doc->children;
974 prev->prev = (xmlNodePtr) cur;
975 cur->next = prev;
976 doc->children = (xmlNodePtr) cur;
977 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000978 xmlNodePtr next;
979
980 next = doc->children;
981 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
982 next = next->next;
983 if (next == NULL) {
984 cur->prev = doc->last;
985 cur->prev->next = (xmlNodePtr) cur;
986 cur->next = NULL;
987 doc->last = (xmlNodePtr) cur;
988 } else {
989 cur->next = next;
990 cur->prev = next->prev;
991 if (cur->prev == NULL)
992 doc->children = (xmlNodePtr) cur;
993 else
994 cur->prev->next = (xmlNodePtr) cur;
995 next->prev = (xmlNodePtr) cur;
996 }
Owen Taylor3473f882001-02-23 17:55:21 +0000997 }
998 }
999 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001000
Daniel Veillarda880b122003-04-21 21:36:41 +00001001 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001002 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001003 return(cur);
1004}
1005
1006/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001007 * DICT_FREE:
1008 * @str: a string
1009 *
1010 * Free a string if it is not owned by the "dict" dictionnary in the
1011 * current scope
1012 */
1013#define DICT_FREE(str) \
1014 if ((str) && ((!dict) || \
1015 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
1016 xmlFree((char *)(str));
1017
1018/**
Owen Taylor3473f882001-02-23 17:55:21 +00001019 * xmlFreeDtd:
1020 * @cur: the DTD structure to free up
1021 *
1022 * Free a DTD structure.
1023 */
1024void
1025xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001026 xmlDictPtr dict = NULL;
1027
Owen Taylor3473f882001-02-23 17:55:21 +00001028 if (cur == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001029 return;
1030 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001031 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001032
Daniel Veillarda880b122003-04-21 21:36:41 +00001033 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001034 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1035
Owen Taylor3473f882001-02-23 17:55:21 +00001036 if (cur->children != NULL) {
1037 xmlNodePtr next, c = cur->children;
1038
1039 /*
William M. Brack18a04f22004-08-03 16:42:37 +00001040 * Cleanup all nodes which are not part of the specific lists
1041 * of notations, elements, attributes and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00001042 */
1043 while (c != NULL) {
1044 next = c->next;
William M. Brack18a04f22004-08-03 16:42:37 +00001045 if ((c->type != XML_NOTATION_NODE) &&
1046 (c->type != XML_ELEMENT_DECL) &&
1047 (c->type != XML_ATTRIBUTE_DECL) &&
1048 (c->type != XML_ENTITY_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001049 xmlUnlinkNode(c);
1050 xmlFreeNode(c);
1051 }
1052 c = next;
1053 }
1054 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001055 DICT_FREE(cur->name)
1056 DICT_FREE(cur->SystemID)
1057 DICT_FREE(cur->ExternalID)
Owen Taylor3473f882001-02-23 17:55:21 +00001058 /* TODO !!! */
1059 if (cur->notations != NULL)
1060 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1061
1062 if (cur->elements != NULL)
1063 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1064 if (cur->attributes != NULL)
1065 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1066 if (cur->entities != NULL)
1067 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1068 if (cur->pentities != NULL)
1069 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1070
Owen Taylor3473f882001-02-23 17:55:21 +00001071 xmlFree(cur);
1072}
1073
1074/**
1075 * xmlNewDoc:
1076 * @version: xmlChar string giving the version of XML "1.0"
1077 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001078 * Creates a new XML document
1079 *
Owen Taylor3473f882001-02-23 17:55:21 +00001080 * Returns a new document
1081 */
1082xmlDocPtr
1083xmlNewDoc(const xmlChar *version) {
1084 xmlDocPtr cur;
1085
1086 if (version == NULL)
1087 version = (const xmlChar *) "1.0";
1088
1089 /*
1090 * Allocate a new document and fill the fields.
1091 */
1092 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1093 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001094 xmlTreeErrMemory("building doc");
Owen Taylor3473f882001-02-23 17:55:21 +00001095 return(NULL);
1096 }
1097 memset(cur, 0, sizeof(xmlDoc));
1098 cur->type = XML_DOCUMENT_NODE;
1099
1100 cur->version = xmlStrdup(version);
William M. Bracka3215c72004-07-31 16:24:01 +00001101 if (cur->version == NULL) {
1102 xmlTreeErrMemory("building doc");
1103 xmlFree(cur);
1104 return(NULL);
1105 }
Owen Taylor3473f882001-02-23 17:55:21 +00001106 cur->standalone = -1;
1107 cur->compression = -1; /* not initialized */
1108 cur->doc = cur;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001109 /*
1110 * The in memory encoding is always UTF8
1111 * This field will never change and would
1112 * be obsolete if not for binary compatibility.
1113 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001114 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001115
Daniel Veillarda880b122003-04-21 21:36:41 +00001116 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001117 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001118 return(cur);
1119}
1120
1121/**
1122 * xmlFreeDoc:
1123 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001124 *
1125 * Free up all the structures used by a document, tree included.
1126 */
1127void
1128xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001129 xmlDtdPtr extSubset, intSubset;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001130 xmlDictPtr dict = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001131
Owen Taylor3473f882001-02-23 17:55:21 +00001132 if (cur == NULL) {
1133#ifdef DEBUG_TREE
1134 xmlGenericError(xmlGenericErrorContext,
1135 "xmlFreeDoc : document == NULL\n");
1136#endif
1137 return;
1138 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001139#ifdef LIBXML_DEBUG_RUNTIME
Daniel Veillardbca3ad22005-08-23 22:14:02 +00001140#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001141 xmlDebugCheckDocument(stderr, cur);
1142#endif
Daniel Veillardbca3ad22005-08-23 22:14:02 +00001143#endif
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001144
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001145 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001146
Daniel Veillarda880b122003-04-21 21:36:41 +00001147 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001148 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1149
Daniel Veillard76d66f42001-05-16 21:05:17 +00001150 /*
1151 * Do this before freeing the children list to avoid ID lookups
1152 */
1153 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1154 cur->ids = NULL;
1155 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1156 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001157 extSubset = cur->extSubset;
1158 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001159 if (intSubset == extSubset)
1160 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001161 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001162 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001163 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001164 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001165 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001166 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001167 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001168 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001169 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001170 }
1171
1172 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001173 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001174
1175 DICT_FREE(cur->version)
1176 DICT_FREE(cur->name)
1177 DICT_FREE(cur->encoding)
1178 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001179 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001180 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001181}
1182
1183/**
1184 * xmlStringLenGetNodeList:
1185 * @doc: the document
1186 * @value: the value of the text
1187 * @len: the length of the string value
1188 *
1189 * Parse the value string and build the node list associated. Should
1190 * produce a flat tree with only TEXTs and ENTITY_REFs.
1191 * Returns a pointer to the first child
1192 */
1193xmlNodePtr
1194xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1195 xmlNodePtr ret = NULL, last = NULL;
1196 xmlNodePtr node;
1197 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001198 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001199 const xmlChar *q;
1200 xmlEntityPtr ent;
1201
1202 if (value == NULL) return(NULL);
1203
1204 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001205 while ((cur < end) && (*cur != 0)) {
1206 if (cur[0] == '&') {
1207 int charval = 0;
1208 xmlChar tmp;
1209
Owen Taylor3473f882001-02-23 17:55:21 +00001210 /*
1211 * Save the current text.
1212 */
1213 if (cur != q) {
1214 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1215 xmlNodeAddContentLen(last, q, cur - q);
1216 } else {
1217 node = xmlNewDocTextLen(doc, q, cur - q);
1218 if (node == NULL) return(ret);
1219 if (last == NULL)
1220 last = ret = node;
1221 else {
1222 last->next = node;
1223 node->prev = last;
1224 last = node;
1225 }
1226 }
1227 }
Owen Taylor3473f882001-02-23 17:55:21 +00001228 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001229 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1230 cur += 3;
1231 if (cur < end)
1232 tmp = *cur;
1233 else
1234 tmp = 0;
1235 while (tmp != ';') { /* Non input consuming loop */
1236 if ((tmp >= '0') && (tmp <= '9'))
1237 charval = charval * 16 + (tmp - '0');
1238 else if ((tmp >= 'a') && (tmp <= 'f'))
1239 charval = charval * 16 + (tmp - 'a') + 10;
1240 else if ((tmp >= 'A') && (tmp <= 'F'))
1241 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001242 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001243 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1244 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001245 charval = 0;
1246 break;
1247 }
1248 cur++;
1249 if (cur < end)
1250 tmp = *cur;
1251 else
1252 tmp = 0;
1253 }
1254 if (tmp == ';')
1255 cur++;
1256 q = cur;
1257 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1258 cur += 2;
1259 if (cur < end)
1260 tmp = *cur;
1261 else
1262 tmp = 0;
1263 while (tmp != ';') { /* Non input consuming loops */
1264 if ((tmp >= '0') && (tmp <= '9'))
1265 charval = charval * 10 + (tmp - '0');
1266 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001267 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1268 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001269 charval = 0;
1270 break;
1271 }
1272 cur++;
1273 if (cur < end)
1274 tmp = *cur;
1275 else
1276 tmp = 0;
1277 }
1278 if (tmp == ';')
1279 cur++;
1280 q = cur;
1281 } else {
1282 /*
1283 * Read the entity string
1284 */
1285 cur++;
1286 q = cur;
1287 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1288 if ((cur >= end) || (*cur == 0)) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001289 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1290 (const char *) q);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001291 return(ret);
1292 }
1293 if (cur != q) {
1294 /*
1295 * Predefined entities don't generate nodes
1296 */
1297 val = xmlStrndup(q, cur - q);
1298 ent = xmlGetDocEntity(doc, val);
1299 if ((ent != NULL) &&
1300 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1301 if (last == NULL) {
1302 node = xmlNewDocText(doc, ent->content);
1303 last = ret = node;
1304 } else if (last->type != XML_TEXT_NODE) {
1305 node = xmlNewDocText(doc, ent->content);
1306 last = xmlAddNextSibling(last, node);
1307 } else
1308 xmlNodeAddContent(last, ent->content);
1309
1310 } else {
1311 /*
1312 * Create a new REFERENCE_REF node
1313 */
1314 node = xmlNewReference(doc, val);
1315 if (node == NULL) {
1316 if (val != NULL) xmlFree(val);
1317 return(ret);
1318 }
1319 else if ((ent != NULL) && (ent->children == NULL)) {
1320 xmlNodePtr temp;
1321
1322 ent->children = xmlStringGetNodeList(doc,
1323 (const xmlChar*)node->content);
1324 ent->owner = 1;
1325 temp = ent->children;
1326 while (temp) {
1327 temp->parent = (xmlNodePtr)ent;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001328 ent->last = temp;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001329 temp = temp->next;
1330 }
1331 }
1332 if (last == NULL) {
1333 last = ret = node;
1334 } else {
1335 last = xmlAddNextSibling(last, node);
1336 }
1337 }
1338 xmlFree(val);
1339 }
1340 cur++;
1341 q = cur;
1342 }
1343 if (charval != 0) {
1344 xmlChar buf[10];
1345 int l;
1346
1347 l = xmlCopyCharMultiByte(buf, charval);
1348 buf[l] = 0;
1349 node = xmlNewDocText(doc, buf);
1350 if (node != NULL) {
1351 if (last == NULL) {
1352 last = ret = node;
1353 } else {
1354 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001355 }
1356 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001357 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001358 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001359 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001360 cur++;
1361 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001362 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001363 /*
1364 * Handle the last piece of text.
1365 */
1366 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1367 xmlNodeAddContentLen(last, q, cur - q);
1368 } else {
1369 node = xmlNewDocTextLen(doc, q, cur - q);
1370 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001371 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001372 last = ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001373 } else {
1374 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001375 }
1376 }
1377 }
1378 return(ret);
1379}
1380
1381/**
1382 * xmlStringGetNodeList:
1383 * @doc: the document
1384 * @value: the value of the attribute
1385 *
1386 * Parse the value string and build the node list associated. Should
1387 * produce a flat tree with only TEXTs and ENTITY_REFs.
1388 * Returns a pointer to the first child
1389 */
1390xmlNodePtr
1391xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1392 xmlNodePtr ret = NULL, last = NULL;
1393 xmlNodePtr node;
1394 xmlChar *val;
1395 const xmlChar *cur = value;
1396 const xmlChar *q;
1397 xmlEntityPtr ent;
1398
1399 if (value == NULL) return(NULL);
1400
1401 q = cur;
1402 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001403 if (cur[0] == '&') {
1404 int charval = 0;
1405 xmlChar tmp;
1406
Owen Taylor3473f882001-02-23 17:55:21 +00001407 /*
1408 * Save the current text.
1409 */
1410 if (cur != q) {
1411 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1412 xmlNodeAddContentLen(last, q, cur - q);
1413 } else {
1414 node = xmlNewDocTextLen(doc, q, cur - q);
1415 if (node == NULL) return(ret);
1416 if (last == NULL)
1417 last = ret = node;
1418 else {
1419 last->next = node;
1420 node->prev = last;
1421 last = node;
1422 }
1423 }
1424 }
Owen Taylor3473f882001-02-23 17:55:21 +00001425 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001426 if ((cur[1] == '#') && (cur[2] == 'x')) {
1427 cur += 3;
1428 tmp = *cur;
1429 while (tmp != ';') { /* Non input consuming loop */
1430 if ((tmp >= '0') && (tmp <= '9'))
1431 charval = charval * 16 + (tmp - '0');
1432 else if ((tmp >= 'a') && (tmp <= 'f'))
1433 charval = charval * 16 + (tmp - 'a') + 10;
1434 else if ((tmp >= 'A') && (tmp <= 'F'))
1435 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001436 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001437 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1438 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001439 charval = 0;
1440 break;
1441 }
1442 cur++;
1443 tmp = *cur;
1444 }
1445 if (tmp == ';')
1446 cur++;
1447 q = cur;
1448 } else if (cur[1] == '#') {
1449 cur += 2;
1450 tmp = *cur;
1451 while (tmp != ';') { /* Non input consuming loops */
1452 if ((tmp >= '0') && (tmp <= '9'))
1453 charval = charval * 10 + (tmp - '0');
1454 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001455 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1456 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001457 charval = 0;
1458 break;
1459 }
1460 cur++;
1461 tmp = *cur;
1462 }
1463 if (tmp == ';')
1464 cur++;
1465 q = cur;
1466 } else {
1467 /*
1468 * Read the entity string
1469 */
1470 cur++;
1471 q = cur;
1472 while ((*cur != 0) && (*cur != ';')) cur++;
1473 if (*cur == 0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001474 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1475 (xmlNodePtr) doc, (const char *) q);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001476 return(ret);
1477 }
1478 if (cur != q) {
1479 /*
1480 * Predefined entities don't generate nodes
1481 */
1482 val = xmlStrndup(q, cur - q);
1483 ent = xmlGetDocEntity(doc, val);
1484 if ((ent != NULL) &&
1485 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1486 if (last == NULL) {
1487 node = xmlNewDocText(doc, ent->content);
1488 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001489 } else if (last->type != XML_TEXT_NODE) {
1490 node = xmlNewDocText(doc, ent->content);
1491 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001492 } else
1493 xmlNodeAddContent(last, ent->content);
1494
1495 } else {
1496 /*
1497 * Create a new REFERENCE_REF node
1498 */
1499 node = xmlNewReference(doc, val);
1500 if (node == NULL) {
1501 if (val != NULL) xmlFree(val);
1502 return(ret);
1503 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001504 else if ((ent != NULL) && (ent->children == NULL)) {
1505 xmlNodePtr temp;
1506
1507 ent->children = xmlStringGetNodeList(doc,
1508 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001509 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001510 temp = ent->children;
1511 while (temp) {
1512 temp->parent = (xmlNodePtr)ent;
1513 temp = temp->next;
1514 }
1515 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001516 if (last == NULL) {
1517 last = ret = node;
1518 } else {
1519 last = xmlAddNextSibling(last, node);
1520 }
1521 }
1522 xmlFree(val);
1523 }
1524 cur++;
1525 q = cur;
1526 }
1527 if (charval != 0) {
1528 xmlChar buf[10];
1529 int len;
1530
1531 len = xmlCopyCharMultiByte(buf, charval);
1532 buf[len] = 0;
1533 node = xmlNewDocText(doc, buf);
1534 if (node != NULL) {
1535 if (last == NULL) {
1536 last = ret = node;
1537 } else {
1538 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001539 }
1540 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001541
1542 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001543 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001544 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001545 cur++;
1546 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001547 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001548 /*
1549 * Handle the last piece of text.
1550 */
1551 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1552 xmlNodeAddContentLen(last, q, cur - q);
1553 } else {
1554 node = xmlNewDocTextLen(doc, q, cur - q);
1555 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001556 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001557 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001558 } else {
1559 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001560 }
1561 }
1562 }
1563 return(ret);
1564}
1565
1566/**
1567 * xmlNodeListGetString:
1568 * @doc: the document
1569 * @list: a Node list
1570 * @inLine: should we replace entity contents or show their external form
1571 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001572 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001573 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001574 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001575 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001576 */
1577xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001578xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1579{
Owen Taylor3473f882001-02-23 17:55:21 +00001580 xmlNodePtr node = list;
1581 xmlChar *ret = NULL;
1582 xmlEntityPtr ent;
1583
Daniel Veillard7646b182002-04-20 06:41:40 +00001584 if (list == NULL)
1585 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001586
1587 while (node != NULL) {
1588 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001589 (node->type == XML_CDATA_SECTION_NODE)) {
1590 if (inLine) {
1591 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001592 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001593 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001594
Daniel Veillard7646b182002-04-20 06:41:40 +00001595 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1596 if (buffer != NULL) {
1597 ret = xmlStrcat(ret, buffer);
1598 xmlFree(buffer);
1599 }
1600 }
1601 } else if (node->type == XML_ENTITY_REF_NODE) {
1602 if (inLine) {
1603 ent = xmlGetDocEntity(doc, node->name);
1604 if (ent != NULL) {
1605 xmlChar *buffer;
1606
1607 /* an entity content can be any "well balanced chunk",
1608 * i.e. the result of the content [43] production:
1609 * http://www.w3.org/TR/REC-xml#NT-content.
1610 * So it can contain text, CDATA section or nested
1611 * entity reference nodes (among others).
1612 * -> we recursive call xmlNodeListGetString()
1613 * which handles these types */
1614 buffer = xmlNodeListGetString(doc, ent->children, 1);
1615 if (buffer != NULL) {
1616 ret = xmlStrcat(ret, buffer);
1617 xmlFree(buffer);
1618 }
1619 } else {
1620 ret = xmlStrcat(ret, node->content);
1621 }
1622 } else {
1623 xmlChar buf[2];
1624
1625 buf[0] = '&';
1626 buf[1] = 0;
1627 ret = xmlStrncat(ret, buf, 1);
1628 ret = xmlStrcat(ret, node->name);
1629 buf[0] = ';';
1630 buf[1] = 0;
1631 ret = xmlStrncat(ret, buf, 1);
1632 }
1633 }
1634#if 0
1635 else {
1636 xmlGenericError(xmlGenericErrorContext,
1637 "xmlGetNodeListString : invalid node type %d\n",
1638 node->type);
1639 }
1640#endif
1641 node = node->next;
1642 }
1643 return (ret);
1644}
Daniel Veillard652327a2003-09-29 18:02:38 +00001645
1646#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001647/**
1648 * xmlNodeListGetRawString:
1649 * @doc: the document
1650 * @list: a Node list
1651 * @inLine: should we replace entity contents or show their external form
1652 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001653 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001654 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1655 * this function doesn't do any character encoding handling.
1656 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001657 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001658 */
1659xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001660xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1661{
Owen Taylor3473f882001-02-23 17:55:21 +00001662 xmlNodePtr node = list;
1663 xmlChar *ret = NULL;
1664 xmlEntityPtr ent;
1665
Daniel Veillard7646b182002-04-20 06:41:40 +00001666 if (list == NULL)
1667 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001668
1669 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001670 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001671 (node->type == XML_CDATA_SECTION_NODE)) {
1672 if (inLine) {
1673 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001674 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001675 xmlChar *buffer;
1676
1677 buffer = xmlEncodeSpecialChars(doc, node->content);
1678 if (buffer != NULL) {
1679 ret = xmlStrcat(ret, buffer);
1680 xmlFree(buffer);
1681 }
1682 }
1683 } else if (node->type == XML_ENTITY_REF_NODE) {
1684 if (inLine) {
1685 ent = xmlGetDocEntity(doc, node->name);
1686 if (ent != NULL) {
1687 xmlChar *buffer;
1688
1689 /* an entity content can be any "well balanced chunk",
1690 * i.e. the result of the content [43] production:
1691 * http://www.w3.org/TR/REC-xml#NT-content.
1692 * So it can contain text, CDATA section or nested
1693 * entity reference nodes (among others).
1694 * -> we recursive call xmlNodeListGetRawString()
1695 * which handles these types */
1696 buffer =
1697 xmlNodeListGetRawString(doc, ent->children, 1);
1698 if (buffer != NULL) {
1699 ret = xmlStrcat(ret, buffer);
1700 xmlFree(buffer);
1701 }
1702 } else {
1703 ret = xmlStrcat(ret, node->content);
1704 }
1705 } else {
1706 xmlChar buf[2];
1707
1708 buf[0] = '&';
1709 buf[1] = 0;
1710 ret = xmlStrncat(ret, buf, 1);
1711 ret = xmlStrcat(ret, node->name);
1712 buf[0] = ';';
1713 buf[1] = 0;
1714 ret = xmlStrncat(ret, buf, 1);
1715 }
1716 }
Owen Taylor3473f882001-02-23 17:55:21 +00001717#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001718 else {
1719 xmlGenericError(xmlGenericErrorContext,
1720 "xmlGetNodeListString : invalid node type %d\n",
1721 node->type);
1722 }
Owen Taylor3473f882001-02-23 17:55:21 +00001723#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001724 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001725 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001726 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001727}
Daniel Veillard652327a2003-09-29 18:02:38 +00001728#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001729
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001730static xmlAttrPtr
1731xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns,
1732 const xmlChar * name, const xmlChar * value,
1733 int eatname)
1734{
Owen Taylor3473f882001-02-23 17:55:21 +00001735 xmlAttrPtr cur;
1736 xmlDocPtr doc = NULL;
1737
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001738 if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001739 if (eatname == 1)
1740 xmlFree((xmlChar *) name);
1741 return (NULL);
1742 }
Owen Taylor3473f882001-02-23 17:55:21 +00001743
1744 /*
1745 * Allocate a new property and fill the fields.
1746 */
1747 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1748 if (cur == NULL) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001749 if (eatname == 1)
1750 xmlFree((xmlChar *) name);
1751 xmlTreeErrMemory("building attribute");
1752 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001753 }
1754 memset(cur, 0, sizeof(xmlAttr));
1755 cur->type = XML_ATTRIBUTE_NODE;
1756
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001757 cur->parent = node;
Owen Taylor3473f882001-02-23 17:55:21 +00001758 if (node != NULL) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001759 doc = node->doc;
1760 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001761 }
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001762 cur->ns = ns;
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001763
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001764 if (eatname == 0) {
1765 if ((doc != NULL) && (doc->dict != NULL))
1766 cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
1767 else
1768 cur->name = xmlStrdup(name);
1769 } else
1770 cur->name = name;
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001771
Owen Taylor3473f882001-02-23 17:55:21 +00001772 if (value != NULL) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001773 xmlChar *buffer;
1774 xmlNodePtr tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00001775
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001776 buffer = xmlEncodeEntitiesReentrant(doc, value);
1777 cur->children = xmlStringGetNodeList(doc, buffer);
1778 cur->last = NULL;
1779 tmp = cur->children;
1780 while (tmp != NULL) {
1781 tmp->parent = (xmlNodePtr) cur;
1782 if (tmp->next == NULL)
1783 cur->last = tmp;
1784 tmp = tmp->next;
1785 }
1786 xmlFree(buffer);
1787 }
Owen Taylor3473f882001-02-23 17:55:21 +00001788
1789 /*
1790 * Add it at the end to preserve parsing order ...
1791 */
1792 if (node != NULL) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001793 if (node->properties == NULL) {
1794 node->properties = cur;
1795 } else {
1796 xmlAttrPtr prev = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00001797
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001798 while (prev->next != NULL)
1799 prev = prev->next;
1800 prev->next = cur;
1801 cur->prev = prev;
1802 }
Owen Taylor3473f882001-02-23 17:55:21 +00001803 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001804
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001805 if (xmlIsID((node == NULL) ? NULL : node->doc, node, cur) == 1)
1806 xmlAddID(NULL, node->doc, value, cur);
1807
Daniel Veillarda880b122003-04-21 21:36:41 +00001808 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001809 xmlRegisterNodeDefaultValue((xmlNodePtr) cur);
1810 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001811}
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001812
1813#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
1814 defined(LIBXML_SCHEMAS_ENABLED)
1815/**
1816 * xmlNewProp:
1817 * @node: the holding node
1818 * @name: the name of the attribute
1819 * @value: the value of the attribute
1820 *
1821 * Create a new property carried by a node.
1822 * Returns a pointer to the attribute
1823 */
1824xmlAttrPtr
1825xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1826
1827 if (name == NULL) {
1828#ifdef DEBUG_TREE
1829 xmlGenericError(xmlGenericErrorContext,
1830 "xmlNewProp : name == NULL\n");
1831#endif
1832 return(NULL);
1833 }
1834
1835 return xmlNewPropInternal(node, NULL, name, value, 0);
1836}
Daniel Veillard652327a2003-09-29 18:02:38 +00001837#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001838
1839/**
1840 * xmlNewNsProp:
1841 * @node: the holding node
1842 * @ns: the namespace
1843 * @name: the name of the attribute
1844 * @value: the value of the attribute
1845 *
1846 * Create a new property tagged with a namespace and carried by a node.
1847 * Returns a pointer to the attribute
1848 */
1849xmlAttrPtr
1850xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1851 const xmlChar *value) {
Owen Taylor3473f882001-02-23 17:55:21 +00001852
1853 if (name == NULL) {
1854#ifdef DEBUG_TREE
1855 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001856 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001857#endif
1858 return(NULL);
1859 }
1860
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001861 return xmlNewPropInternal(node, ns, name, value, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001862}
1863
1864/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001865 * xmlNewNsPropEatName:
1866 * @node: the holding node
1867 * @ns: the namespace
1868 * @name: the name of the attribute
1869 * @value: the value of the attribute
1870 *
1871 * Create a new property tagged with a namespace and carried by a node.
1872 * Returns a pointer to the attribute
1873 */
1874xmlAttrPtr
1875xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1876 const xmlChar *value) {
Daniel Veillard46de64e2002-05-29 08:21:33 +00001877
1878 if (name == NULL) {
1879#ifdef DEBUG_TREE
1880 xmlGenericError(xmlGenericErrorContext,
1881 "xmlNewNsPropEatName : name == NULL\n");
1882#endif
1883 return(NULL);
1884 }
1885
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001886 return xmlNewPropInternal(node, ns, name, value, 1);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001887}
1888
1889/**
Owen Taylor3473f882001-02-23 17:55:21 +00001890 * xmlNewDocProp:
1891 * @doc: the document
1892 * @name: the name of the attribute
1893 * @value: the value of the attribute
1894 *
1895 * Create a new property carried by a document.
1896 * Returns a pointer to the attribute
1897 */
1898xmlAttrPtr
1899xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1900 xmlAttrPtr cur;
1901
1902 if (name == NULL) {
1903#ifdef DEBUG_TREE
1904 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001905 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001906#endif
1907 return(NULL);
1908 }
1909
1910 /*
1911 * Allocate a new property and fill the fields.
1912 */
1913 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1914 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001915 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001916 return(NULL);
1917 }
1918 memset(cur, 0, sizeof(xmlAttr));
1919 cur->type = XML_ATTRIBUTE_NODE;
1920
Daniel Veillard03a53c32004-10-26 16:06:51 +00001921 if ((doc != NULL) && (doc->dict != NULL))
1922 cur->name = xmlDictLookup(doc->dict, name, -1);
1923 else
1924 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00001925 cur->doc = doc;
1926 if (value != NULL) {
1927 xmlNodePtr tmp;
1928
1929 cur->children = xmlStringGetNodeList(doc, value);
1930 cur->last = NULL;
1931
1932 tmp = cur->children;
1933 while (tmp != NULL) {
1934 tmp->parent = (xmlNodePtr) cur;
1935 if (tmp->next == NULL)
1936 cur->last = tmp;
1937 tmp = tmp->next;
1938 }
1939 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001940
Daniel Veillarda880b122003-04-21 21:36:41 +00001941 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001942 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001943 return(cur);
1944}
1945
1946/**
1947 * xmlFreePropList:
1948 * @cur: the first property in the list
1949 *
1950 * Free a property and all its siblings, all the children are freed too.
1951 */
1952void
1953xmlFreePropList(xmlAttrPtr cur) {
1954 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001955 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001956 while (cur != NULL) {
1957 next = cur->next;
1958 xmlFreeProp(cur);
1959 cur = next;
1960 }
1961}
1962
1963/**
1964 * xmlFreeProp:
1965 * @cur: an attribute
1966 *
1967 * Free one attribute, all the content is freed too
1968 */
1969void
1970xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001971 xmlDictPtr dict = NULL;
1972 if (cur == NULL) return;
1973
1974 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001975
Daniel Veillarda880b122003-04-21 21:36:41 +00001976 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001977 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1978
Owen Taylor3473f882001-02-23 17:55:21 +00001979 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillardda6f4af2005-06-20 17:17:54 +00001980 if ((cur->doc != NULL) && (cur->atype == XML_ATTRIBUTE_ID)) {
1981 xmlRemoveID(cur->doc, cur);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001982 }
Owen Taylor3473f882001-02-23 17:55:21 +00001983 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001984 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00001985 xmlFree(cur);
1986}
1987
Daniel Veillard652327a2003-09-29 18:02:38 +00001988#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001989/**
1990 * xmlRemoveProp:
1991 * @cur: an attribute
1992 *
1993 * Unlink and free one attribute, all the content is freed too
1994 * Note this doesn't work for namespace definition attributes
1995 *
1996 * Returns 0 if success and -1 in case of error.
1997 */
1998int
1999xmlRemoveProp(xmlAttrPtr cur) {
2000 xmlAttrPtr tmp;
2001 if (cur == NULL) {
2002#ifdef DEBUG_TREE
2003 xmlGenericError(xmlGenericErrorContext,
2004 "xmlRemoveProp : cur == NULL\n");
2005#endif
2006 return(-1);
2007 }
2008 if (cur->parent == NULL) {
2009#ifdef DEBUG_TREE
2010 xmlGenericError(xmlGenericErrorContext,
2011 "xmlRemoveProp : cur->parent == NULL\n");
2012#endif
2013 return(-1);
2014 }
2015 tmp = cur->parent->properties;
2016 if (tmp == cur) {
2017 cur->parent->properties = cur->next;
Rob Richards19dc9612005-10-28 16:15:16 +00002018 if (cur->next != NULL)
2019 cur->next->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002020 xmlFreeProp(cur);
2021 return(0);
2022 }
2023 while (tmp != NULL) {
2024 if (tmp->next == cur) {
2025 tmp->next = cur->next;
2026 if (tmp->next != NULL)
2027 tmp->next->prev = tmp;
2028 xmlFreeProp(cur);
2029 return(0);
2030 }
2031 tmp = tmp->next;
2032 }
2033#ifdef DEBUG_TREE
2034 xmlGenericError(xmlGenericErrorContext,
2035 "xmlRemoveProp : attribute not owned by its node\n");
2036#endif
2037 return(-1);
2038}
Daniel Veillard652327a2003-09-29 18:02:38 +00002039#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002040
2041/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002042 * xmlNewDocPI:
2043 * @doc: the target document
Owen Taylor3473f882001-02-23 17:55:21 +00002044 * @name: the processing instruction name
2045 * @content: the PI content
2046 *
2047 * Creation of a processing instruction element.
2048 * Returns a pointer to the new node object.
2049 */
2050xmlNodePtr
Daniel Veillard03a53c32004-10-26 16:06:51 +00002051xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
Owen Taylor3473f882001-02-23 17:55:21 +00002052 xmlNodePtr cur;
2053
2054 if (name == NULL) {
2055#ifdef DEBUG_TREE
2056 xmlGenericError(xmlGenericErrorContext,
2057 "xmlNewPI : name == NULL\n");
2058#endif
2059 return(NULL);
2060 }
2061
2062 /*
2063 * Allocate a new node and fill the fields.
2064 */
2065 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2066 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002067 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002068 return(NULL);
2069 }
2070 memset(cur, 0, sizeof(xmlNode));
2071 cur->type = XML_PI_NODE;
2072
Daniel Veillard03a53c32004-10-26 16:06:51 +00002073 if ((doc != NULL) && (doc->dict != NULL))
2074 cur->name = xmlDictLookup(doc->dict, name, -1);
2075 else
2076 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00002077 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002078 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002079 }
Daniel Veillarda03e3652004-11-02 18:45:30 +00002080 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002081
Daniel Veillarda880b122003-04-21 21:36:41 +00002082 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002083 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002084 return(cur);
2085}
2086
2087/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002088 * xmlNewPI:
2089 * @name: the processing instruction name
2090 * @content: the PI content
2091 *
2092 * Creation of a processing instruction element.
2093 * Use xmlDocNewPI preferably to get string interning
2094 *
2095 * Returns a pointer to the new node object.
2096 */
2097xmlNodePtr
2098xmlNewPI(const xmlChar *name, const xmlChar *content) {
2099 return(xmlNewDocPI(NULL, name, content));
2100}
2101
2102/**
Owen Taylor3473f882001-02-23 17:55:21 +00002103 * xmlNewNode:
2104 * @ns: namespace if any
2105 * @name: the node name
2106 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002107 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002108 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002109 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2110 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002111 */
2112xmlNodePtr
2113xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2114 xmlNodePtr cur;
2115
2116 if (name == NULL) {
2117#ifdef DEBUG_TREE
2118 xmlGenericError(xmlGenericErrorContext,
2119 "xmlNewNode : name == NULL\n");
2120#endif
2121 return(NULL);
2122 }
2123
2124 /*
2125 * Allocate a new node and fill the fields.
2126 */
2127 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2128 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002129 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002130 return(NULL);
2131 }
2132 memset(cur, 0, sizeof(xmlNode));
2133 cur->type = XML_ELEMENT_NODE;
2134
2135 cur->name = xmlStrdup(name);
2136 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002137
Daniel Veillarda880b122003-04-21 21:36:41 +00002138 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002139 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002140 return(cur);
2141}
2142
2143/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002144 * xmlNewNodeEatName:
2145 * @ns: namespace if any
2146 * @name: the node name
2147 *
2148 * Creation of a new node element. @ns is optional (NULL).
2149 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002150 * Returns a pointer to the new node object, with pointer @name as
2151 * new node's name. Use xmlNewNode() if a copy of @name string is
2152 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002153 */
2154xmlNodePtr
2155xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2156 xmlNodePtr cur;
2157
2158 if (name == NULL) {
2159#ifdef DEBUG_TREE
2160 xmlGenericError(xmlGenericErrorContext,
2161 "xmlNewNode : name == NULL\n");
2162#endif
2163 return(NULL);
2164 }
2165
2166 /*
2167 * Allocate a new node and fill the fields.
2168 */
2169 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2170 if (cur == NULL) {
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00002171 xmlFree(name);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002172 xmlTreeErrMemory("building node");
Daniel Veillard46de64e2002-05-29 08:21:33 +00002173 return(NULL);
2174 }
2175 memset(cur, 0, sizeof(xmlNode));
2176 cur->type = XML_ELEMENT_NODE;
2177
2178 cur->name = name;
2179 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002180
Daniel Veillarda880b122003-04-21 21:36:41 +00002181 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002182 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002183 return(cur);
2184}
2185
2186/**
Owen Taylor3473f882001-02-23 17:55:21 +00002187 * xmlNewDocNode:
2188 * @doc: the document
2189 * @ns: namespace if any
2190 * @name: the node name
2191 * @content: the XML text content if any
2192 *
2193 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002194 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002195 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2196 * references, but XML special chars need to be escaped first by using
2197 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2198 * need entities support.
2199 *
2200 * Returns a pointer to the new node object.
2201 */
2202xmlNodePtr
2203xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2204 const xmlChar *name, const xmlChar *content) {
2205 xmlNodePtr cur;
2206
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002207 if ((doc != NULL) && (doc->dict != NULL))
Daniel Veillard03a53c32004-10-26 16:06:51 +00002208 cur = xmlNewNodeEatName(ns, (xmlChar *)
2209 xmlDictLookup(doc->dict, name, -1));
2210 else
2211 cur = xmlNewNode(ns, name);
Owen Taylor3473f882001-02-23 17:55:21 +00002212 if (cur != NULL) {
2213 cur->doc = doc;
2214 if (content != NULL) {
2215 cur->children = xmlStringGetNodeList(doc, content);
2216 UPDATE_LAST_CHILD_AND_PARENT(cur)
2217 }
2218 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002219
Owen Taylor3473f882001-02-23 17:55:21 +00002220 return(cur);
2221}
2222
Daniel Veillard46de64e2002-05-29 08:21:33 +00002223/**
2224 * xmlNewDocNodeEatName:
2225 * @doc: the document
2226 * @ns: namespace if any
2227 * @name: the node name
2228 * @content: the XML text content if any
2229 *
2230 * Creation of a new node element within a document. @ns and @content
2231 * are optional (NULL).
2232 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2233 * references, but XML special chars need to be escaped first by using
2234 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2235 * need entities support.
2236 *
2237 * Returns a pointer to the new node object.
2238 */
2239xmlNodePtr
2240xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2241 xmlChar *name, const xmlChar *content) {
2242 xmlNodePtr cur;
2243
2244 cur = xmlNewNodeEatName(ns, name);
2245 if (cur != NULL) {
2246 cur->doc = doc;
2247 if (content != NULL) {
2248 cur->children = xmlStringGetNodeList(doc, content);
2249 UPDATE_LAST_CHILD_AND_PARENT(cur)
2250 }
2251 }
2252 return(cur);
2253}
2254
Daniel Veillard652327a2003-09-29 18:02:38 +00002255#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002256/**
2257 * xmlNewDocRawNode:
2258 * @doc: the document
2259 * @ns: namespace if any
2260 * @name: the node name
2261 * @content: the text content if any
2262 *
2263 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002264 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002265 *
2266 * Returns a pointer to the new node object.
2267 */
2268xmlNodePtr
2269xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2270 const xmlChar *name, const xmlChar *content) {
2271 xmlNodePtr cur;
2272
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002273 cur = xmlNewDocNode(doc, ns, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002274 if (cur != NULL) {
2275 cur->doc = doc;
2276 if (content != NULL) {
2277 cur->children = xmlNewDocText(doc, content);
2278 UPDATE_LAST_CHILD_AND_PARENT(cur)
2279 }
2280 }
2281 return(cur);
2282}
2283
2284/**
2285 * xmlNewDocFragment:
2286 * @doc: the document owning the fragment
2287 *
2288 * Creation of a new Fragment node.
2289 * Returns a pointer to the new node object.
2290 */
2291xmlNodePtr
2292xmlNewDocFragment(xmlDocPtr doc) {
2293 xmlNodePtr cur;
2294
2295 /*
2296 * Allocate a new DocumentFragment node and fill the fields.
2297 */
2298 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2299 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002300 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002301 return(NULL);
2302 }
2303 memset(cur, 0, sizeof(xmlNode));
2304 cur->type = XML_DOCUMENT_FRAG_NODE;
2305
2306 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002307
Daniel Veillarda880b122003-04-21 21:36:41 +00002308 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002309 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002310 return(cur);
2311}
Daniel Veillard652327a2003-09-29 18:02:38 +00002312#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002313
2314/**
2315 * xmlNewText:
2316 * @content: the text content
2317 *
2318 * Creation of a new text node.
2319 * Returns a pointer to the new node object.
2320 */
2321xmlNodePtr
2322xmlNewText(const xmlChar *content) {
2323 xmlNodePtr cur;
2324
2325 /*
2326 * Allocate a new node and fill the fields.
2327 */
2328 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2329 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002330 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002331 return(NULL);
2332 }
2333 memset(cur, 0, sizeof(xmlNode));
2334 cur->type = XML_TEXT_NODE;
2335
2336 cur->name = xmlStringText;
2337 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002338 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002339 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002340
Daniel Veillarda880b122003-04-21 21:36:41 +00002341 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002342 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002343 return(cur);
2344}
2345
Daniel Veillard652327a2003-09-29 18:02:38 +00002346#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002347/**
2348 * xmlNewTextChild:
2349 * @parent: the parent node
2350 * @ns: a namespace if any
2351 * @name: the name of the child
2352 * @content: the text content of the child if any.
2353 *
2354 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002355 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2356 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002357 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002358 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2359 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2360 * reserved XML chars that might appear in @content, such as the ampersand,
2361 * greater-than or less-than signs, are automatically replaced by their XML
2362 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002363 *
2364 * Returns a pointer to the new node object.
2365 */
2366xmlNodePtr
2367xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2368 const xmlChar *name, const xmlChar *content) {
2369 xmlNodePtr cur, prev;
2370
2371 if (parent == NULL) {
2372#ifdef DEBUG_TREE
2373 xmlGenericError(xmlGenericErrorContext,
2374 "xmlNewTextChild : parent == NULL\n");
2375#endif
2376 return(NULL);
2377 }
2378
2379 if (name == NULL) {
2380#ifdef DEBUG_TREE
2381 xmlGenericError(xmlGenericErrorContext,
2382 "xmlNewTextChild : name == NULL\n");
2383#endif
2384 return(NULL);
2385 }
2386
2387 /*
2388 * Allocate a new node
2389 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002390 if (parent->type == XML_ELEMENT_NODE) {
2391 if (ns == NULL)
2392 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2393 else
2394 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2395 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2396 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2397 if (ns == NULL)
2398 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2399 else
2400 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2401 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2402 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2403 } else {
2404 return(NULL);
2405 }
Owen Taylor3473f882001-02-23 17:55:21 +00002406 if (cur == NULL) return(NULL);
2407
2408 /*
2409 * add the new element at the end of the children list.
2410 */
2411 cur->type = XML_ELEMENT_NODE;
2412 cur->parent = parent;
2413 cur->doc = parent->doc;
2414 if (parent->children == NULL) {
2415 parent->children = cur;
2416 parent->last = cur;
2417 } else {
2418 prev = parent->last;
2419 prev->next = cur;
2420 cur->prev = prev;
2421 parent->last = cur;
2422 }
2423
2424 return(cur);
2425}
Daniel Veillard652327a2003-09-29 18:02:38 +00002426#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002427
2428/**
2429 * xmlNewCharRef:
2430 * @doc: the document
2431 * @name: the char ref string, starting with # or "&# ... ;"
2432 *
2433 * Creation of a new character reference node.
2434 * Returns a pointer to the new node object.
2435 */
2436xmlNodePtr
2437xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2438 xmlNodePtr cur;
2439
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002440 if (name == NULL)
2441 return(NULL);
2442
Owen Taylor3473f882001-02-23 17:55:21 +00002443 /*
2444 * Allocate a new node and fill the fields.
2445 */
2446 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2447 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002448 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002449 return(NULL);
2450 }
2451 memset(cur, 0, sizeof(xmlNode));
2452 cur->type = XML_ENTITY_REF_NODE;
2453
2454 cur->doc = doc;
2455 if (name[0] == '&') {
2456 int len;
2457 name++;
2458 len = xmlStrlen(name);
2459 if (name[len - 1] == ';')
2460 cur->name = xmlStrndup(name, len - 1);
2461 else
2462 cur->name = xmlStrndup(name, len);
2463 } else
2464 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002465
Daniel Veillarda880b122003-04-21 21:36:41 +00002466 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002467 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002468 return(cur);
2469}
2470
2471/**
2472 * xmlNewReference:
2473 * @doc: the document
2474 * @name: the reference name, or the reference string with & and ;
2475 *
2476 * Creation of a new reference node.
2477 * Returns a pointer to the new node object.
2478 */
2479xmlNodePtr
2480xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2481 xmlNodePtr cur;
2482 xmlEntityPtr ent;
2483
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002484 if (name == NULL)
2485 return(NULL);
2486
Owen Taylor3473f882001-02-23 17:55:21 +00002487 /*
2488 * Allocate a new node and fill the fields.
2489 */
2490 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2491 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002492 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002493 return(NULL);
2494 }
2495 memset(cur, 0, sizeof(xmlNode));
2496 cur->type = XML_ENTITY_REF_NODE;
2497
2498 cur->doc = doc;
2499 if (name[0] == '&') {
2500 int len;
2501 name++;
2502 len = xmlStrlen(name);
2503 if (name[len - 1] == ';')
2504 cur->name = xmlStrndup(name, len - 1);
2505 else
2506 cur->name = xmlStrndup(name, len);
2507 } else
2508 cur->name = xmlStrdup(name);
2509
2510 ent = xmlGetDocEntity(doc, cur->name);
2511 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002512 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002513 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002514 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002515 * updated. Not sure if this is 100% correct.
2516 * -George
2517 */
2518 cur->children = (xmlNodePtr) ent;
2519 cur->last = (xmlNodePtr) ent;
2520 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002521
Daniel Veillarda880b122003-04-21 21:36:41 +00002522 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002523 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002524 return(cur);
2525}
2526
2527/**
2528 * xmlNewDocText:
2529 * @doc: the document
2530 * @content: the text content
2531 *
2532 * Creation of a new text node within a document.
2533 * Returns a pointer to the new node object.
2534 */
2535xmlNodePtr
2536xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2537 xmlNodePtr cur;
2538
2539 cur = xmlNewText(content);
2540 if (cur != NULL) cur->doc = doc;
2541 return(cur);
2542}
2543
2544/**
2545 * xmlNewTextLen:
2546 * @content: the text content
2547 * @len: the text len.
2548 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002549 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002550 * Returns a pointer to the new node object.
2551 */
2552xmlNodePtr
2553xmlNewTextLen(const xmlChar *content, int len) {
2554 xmlNodePtr cur;
2555
2556 /*
2557 * Allocate a new node and fill the fields.
2558 */
2559 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2560 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002561 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002562 return(NULL);
2563 }
2564 memset(cur, 0, sizeof(xmlNode));
2565 cur->type = XML_TEXT_NODE;
2566
2567 cur->name = xmlStringText;
2568 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002569 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002570 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002571
Daniel Veillarda880b122003-04-21 21:36:41 +00002572 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002573 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002574 return(cur);
2575}
2576
2577/**
2578 * xmlNewDocTextLen:
2579 * @doc: the document
2580 * @content: the text content
2581 * @len: the text len.
2582 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002583 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002584 * text node pertain to a given document.
2585 * Returns a pointer to the new node object.
2586 */
2587xmlNodePtr
2588xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2589 xmlNodePtr cur;
2590
2591 cur = xmlNewTextLen(content, len);
2592 if (cur != NULL) cur->doc = doc;
2593 return(cur);
2594}
2595
2596/**
2597 * xmlNewComment:
2598 * @content: the comment content
2599 *
2600 * Creation of a new node containing a comment.
2601 * Returns a pointer to the new node object.
2602 */
2603xmlNodePtr
2604xmlNewComment(const xmlChar *content) {
2605 xmlNodePtr cur;
2606
2607 /*
2608 * Allocate a new node and fill the fields.
2609 */
2610 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2611 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002612 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002613 return(NULL);
2614 }
2615 memset(cur, 0, sizeof(xmlNode));
2616 cur->type = XML_COMMENT_NODE;
2617
2618 cur->name = xmlStringComment;
2619 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002620 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002621 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002622
Daniel Veillarda880b122003-04-21 21:36:41 +00002623 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002624 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002625 return(cur);
2626}
2627
2628/**
2629 * xmlNewCDataBlock:
2630 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002631 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002632 * @len: the length of the block
2633 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002634 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002635 * Returns a pointer to the new node object.
2636 */
2637xmlNodePtr
2638xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2639 xmlNodePtr cur;
2640
2641 /*
2642 * Allocate a new node and fill the fields.
2643 */
2644 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2645 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002646 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002647 return(NULL);
2648 }
2649 memset(cur, 0, sizeof(xmlNode));
2650 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002651 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002652
2653 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002654 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002655 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002656
Daniel Veillarda880b122003-04-21 21:36:41 +00002657 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002658 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002659 return(cur);
2660}
2661
2662/**
2663 * xmlNewDocComment:
2664 * @doc: the document
2665 * @content: the comment content
2666 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002667 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002668 * Returns a pointer to the new node object.
2669 */
2670xmlNodePtr
2671xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2672 xmlNodePtr cur;
2673
2674 cur = xmlNewComment(content);
2675 if (cur != NULL) cur->doc = doc;
2676 return(cur);
2677}
2678
2679/**
2680 * xmlSetTreeDoc:
2681 * @tree: the top element
2682 * @doc: the document
2683 *
2684 * update all nodes under the tree to point to the right document
2685 */
2686void
2687xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002688 xmlAttrPtr prop;
2689
Owen Taylor3473f882001-02-23 17:55:21 +00002690 if (tree == NULL)
2691 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002692 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002693 if(tree->type == XML_ELEMENT_NODE) {
2694 prop = tree->properties;
2695 while (prop != NULL) {
2696 prop->doc = doc;
2697 xmlSetListDoc(prop->children, doc);
2698 prop = prop->next;
2699 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002700 }
Owen Taylor3473f882001-02-23 17:55:21 +00002701 if (tree->children != NULL)
2702 xmlSetListDoc(tree->children, doc);
2703 tree->doc = doc;
2704 }
2705}
2706
2707/**
2708 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002709 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002710 * @doc: the document
2711 *
2712 * update all nodes in the list to point to the right document
2713 */
2714void
2715xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2716 xmlNodePtr cur;
2717
2718 if (list == NULL)
2719 return;
2720 cur = list;
2721 while (cur != NULL) {
2722 if (cur->doc != doc)
2723 xmlSetTreeDoc(cur, doc);
2724 cur = cur->next;
2725 }
2726}
2727
Daniel Veillard2156d432004-03-04 15:59:36 +00002728#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002729/**
2730 * xmlNewChild:
2731 * @parent: the parent node
2732 * @ns: a namespace if any
2733 * @name: the name of the child
2734 * @content: the XML content of the child if any.
2735 *
2736 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002737 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2738 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002739 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002740 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2741 * references. XML special chars must be escaped first by using
2742 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002743 *
2744 * Returns a pointer to the new node object.
2745 */
2746xmlNodePtr
2747xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2748 const xmlChar *name, const xmlChar *content) {
2749 xmlNodePtr cur, prev;
2750
2751 if (parent == NULL) {
2752#ifdef DEBUG_TREE
2753 xmlGenericError(xmlGenericErrorContext,
2754 "xmlNewChild : parent == NULL\n");
2755#endif
2756 return(NULL);
2757 }
2758
2759 if (name == NULL) {
2760#ifdef DEBUG_TREE
2761 xmlGenericError(xmlGenericErrorContext,
2762 "xmlNewChild : name == NULL\n");
2763#endif
2764 return(NULL);
2765 }
2766
2767 /*
2768 * Allocate a new node
2769 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002770 if (parent->type == XML_ELEMENT_NODE) {
2771 if (ns == NULL)
2772 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2773 else
2774 cur = xmlNewDocNode(parent->doc, ns, name, content);
2775 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2776 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2777 if (ns == NULL)
2778 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2779 else
2780 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002781 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2782 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002783 } else {
2784 return(NULL);
2785 }
Owen Taylor3473f882001-02-23 17:55:21 +00002786 if (cur == NULL) return(NULL);
2787
2788 /*
2789 * add the new element at the end of the children list.
2790 */
2791 cur->type = XML_ELEMENT_NODE;
2792 cur->parent = parent;
2793 cur->doc = parent->doc;
2794 if (parent->children == NULL) {
2795 parent->children = cur;
2796 parent->last = cur;
2797 } else {
2798 prev = parent->last;
2799 prev->next = cur;
2800 cur->prev = prev;
2801 parent->last = cur;
2802 }
2803
2804 return(cur);
2805}
Daniel Veillard652327a2003-09-29 18:02:38 +00002806#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002807
2808/**
Rob Richards65815122006-02-25 17:13:33 +00002809 * xmlAddPropSibling:
2810 * @prev: the attribute to which @prop is added after
2811 * @cur: the base attribute passed to calling function
2812 * @prop: the new attribute
2813 *
2814 * Add a new attribute after @prev using @cur as base attribute.
2815 * When inserting before @cur, @prev is passed as @cur->prev.
2816 * When inserting after @cur, @prev is passed as @cur.
2817 * If an existing attribute is found it is detroyed prior to adding @prop.
2818 *
2819 * Returns the attribute being inserted or NULL in case of error.
2820 */
2821static xmlNodePtr
2822xmlAddPropSibling(xmlNodePtr prev, xmlNodePtr cur, xmlNodePtr prop) {
2823 xmlAttrPtr attr;
2824
2825 if (cur->type != XML_ATTRIBUTE_NODE)
2826 return(NULL);
2827
2828 /* check if an attribute with the same name exists */
2829 if (prop->ns == NULL)
2830 attr = xmlHasNsProp(cur->parent, prop->name, NULL);
2831 else
2832 attr = xmlHasNsProp(cur->parent, prop->name, prop->ns->href);
2833
2834 if (prop->doc != cur->doc) {
2835 xmlSetTreeDoc(prop, cur->doc);
2836 }
2837 prop->parent = cur->parent;
2838 prop->prev = prev;
2839 if (prev != NULL) {
2840 prop->next = prev->next;
2841 prev->next = prop;
2842 if (prop->next)
2843 prop->next->prev = prop;
2844 } else {
2845 prop->next = cur;
2846 cur->prev = prop;
2847 }
2848 if (prop->prev == NULL && prop->parent != NULL)
2849 prop->parent->properties = (xmlAttrPtr) prop;
2850 if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) {
2851 /* different instance, destroy it (attributes must be unique) */
2852 xmlRemoveProp((xmlAttrPtr) attr);
2853 }
2854 return prop;
2855}
2856
2857/**
Owen Taylor3473f882001-02-23 17:55:21 +00002858 * xmlAddNextSibling:
2859 * @cur: the child node
2860 * @elem: the new node
2861 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002862 * Add a new node @elem as the next sibling of @cur
2863 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002864 * first unlinked from its existing context.
2865 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002866 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2867 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002868 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002869 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002870 */
2871xmlNodePtr
2872xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2873 if (cur == NULL) {
2874#ifdef DEBUG_TREE
2875 xmlGenericError(xmlGenericErrorContext,
2876 "xmlAddNextSibling : cur == NULL\n");
2877#endif
2878 return(NULL);
2879 }
2880 if (elem == NULL) {
2881#ifdef DEBUG_TREE
2882 xmlGenericError(xmlGenericErrorContext,
2883 "xmlAddNextSibling : elem == NULL\n");
2884#endif
2885 return(NULL);
2886 }
2887
Rob Richards19dc9612005-10-28 16:15:16 +00002888 if (cur == elem) {
2889#ifdef DEBUG_TREE
2890 xmlGenericError(xmlGenericErrorContext,
2891 "xmlAddNextSibling : cur == elem\n");
2892#endif
2893 return(NULL);
2894 }
2895
Owen Taylor3473f882001-02-23 17:55:21 +00002896 xmlUnlinkNode(elem);
2897
2898 if (elem->type == XML_TEXT_NODE) {
2899 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002900 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002901 xmlFreeNode(elem);
2902 return(cur);
2903 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002904 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2905 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002906 xmlChar *tmp;
2907
2908 tmp = xmlStrdup(elem->content);
2909 tmp = xmlStrcat(tmp, cur->next->content);
2910 xmlNodeSetContent(cur->next, tmp);
2911 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002912 xmlFreeNode(elem);
2913 return(cur->next);
2914 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002915 } else if (elem->type == XML_ATTRIBUTE_NODE) {
Rob Richards65815122006-02-25 17:13:33 +00002916 return xmlAddPropSibling(cur, cur, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00002917 }
2918
2919 if (elem->doc != cur->doc) {
2920 xmlSetTreeDoc(elem, cur->doc);
2921 }
2922 elem->parent = cur->parent;
2923 elem->prev = cur;
2924 elem->next = cur->next;
2925 cur->next = elem;
2926 if (elem->next != NULL)
2927 elem->next->prev = elem;
Rob Richards65815122006-02-25 17:13:33 +00002928 if ((elem->parent != NULL) && (elem->parent->last == cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002929 elem->parent->last = elem;
2930 return(elem);
2931}
2932
William M. Brack21e4ef22005-01-02 09:53:13 +00002933#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
2934 defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002935/**
2936 * xmlAddPrevSibling:
2937 * @cur: the child node
2938 * @elem: the new node
2939 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002940 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002941 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002942 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002943 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002944 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2945 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002946 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002947 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002948 */
2949xmlNodePtr
2950xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2951 if (cur == NULL) {
2952#ifdef DEBUG_TREE
2953 xmlGenericError(xmlGenericErrorContext,
2954 "xmlAddPrevSibling : cur == NULL\n");
2955#endif
2956 return(NULL);
2957 }
2958 if (elem == NULL) {
2959#ifdef DEBUG_TREE
2960 xmlGenericError(xmlGenericErrorContext,
2961 "xmlAddPrevSibling : elem == NULL\n");
2962#endif
2963 return(NULL);
2964 }
2965
Rob Richards19dc9612005-10-28 16:15:16 +00002966 if (cur == elem) {
2967#ifdef DEBUG_TREE
2968 xmlGenericError(xmlGenericErrorContext,
2969 "xmlAddPrevSibling : cur == elem\n");
2970#endif
2971 return(NULL);
2972 }
2973
Owen Taylor3473f882001-02-23 17:55:21 +00002974 xmlUnlinkNode(elem);
2975
2976 if (elem->type == XML_TEXT_NODE) {
2977 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002978 xmlChar *tmp;
2979
2980 tmp = xmlStrdup(elem->content);
2981 tmp = xmlStrcat(tmp, cur->content);
2982 xmlNodeSetContent(cur, tmp);
2983 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002984 xmlFreeNode(elem);
2985 return(cur);
2986 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002987 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2988 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002989 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002990 xmlFreeNode(elem);
2991 return(cur->prev);
2992 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002993 } else if (elem->type == XML_ATTRIBUTE_NODE) {
Rob Richards65815122006-02-25 17:13:33 +00002994 return xmlAddPropSibling(cur->prev, cur, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00002995 }
2996
2997 if (elem->doc != cur->doc) {
2998 xmlSetTreeDoc(elem, cur->doc);
2999 }
3000 elem->parent = cur->parent;
3001 elem->next = cur;
3002 elem->prev = cur->prev;
3003 cur->prev = elem;
3004 if (elem->prev != NULL)
3005 elem->prev->next = elem;
Rob Richards65815122006-02-25 17:13:33 +00003006 if ((elem->parent != NULL) && (elem->parent->children == cur)) {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003007 elem->parent->children = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003008 }
Owen Taylor3473f882001-02-23 17:55:21 +00003009 return(elem);
3010}
Daniel Veillard652327a2003-09-29 18:02:38 +00003011#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003012
3013/**
3014 * xmlAddSibling:
3015 * @cur: the child node
3016 * @elem: the new node
3017 *
3018 * Add a new element @elem to the list of siblings of @cur
3019 * merging adjacent TEXT nodes (@elem may be freed)
3020 * If the new element was already inserted in a document it is
3021 * first unlinked from its existing context.
3022 *
3023 * Returns the new element or NULL in case of error.
3024 */
3025xmlNodePtr
3026xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
3027 xmlNodePtr parent;
3028
3029 if (cur == NULL) {
3030#ifdef DEBUG_TREE
3031 xmlGenericError(xmlGenericErrorContext,
3032 "xmlAddSibling : cur == NULL\n");
3033#endif
3034 return(NULL);
3035 }
3036
3037 if (elem == NULL) {
3038#ifdef DEBUG_TREE
3039 xmlGenericError(xmlGenericErrorContext,
3040 "xmlAddSibling : elem == NULL\n");
3041#endif
3042 return(NULL);
3043 }
3044
3045 /*
3046 * Constant time is we can rely on the ->parent->last to find
3047 * the last sibling.
3048 */
Rob Richards65815122006-02-25 17:13:33 +00003049 if ((cur->type != XML_ATTRIBUTE_NODE) && (cur->parent != NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00003050 (cur->parent->children != NULL) &&
3051 (cur->parent->last != NULL) &&
3052 (cur->parent->last->next == NULL)) {
3053 cur = cur->parent->last;
3054 } else {
3055 while (cur->next != NULL) cur = cur->next;
3056 }
3057
3058 xmlUnlinkNode(elem);
3059
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003060 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3061 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003062 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003063 xmlFreeNode(elem);
3064 return(cur);
Rob Richards65815122006-02-25 17:13:33 +00003065 } else if (elem->type == XML_ATTRIBUTE_NODE) {
3066 return xmlAddPropSibling(cur, cur, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00003067 }
3068
3069 if (elem->doc != cur->doc) {
3070 xmlSetTreeDoc(elem, cur->doc);
3071 }
3072 parent = cur->parent;
3073 elem->prev = cur;
3074 elem->next = NULL;
3075 elem->parent = parent;
3076 cur->next = elem;
3077 if (parent != NULL)
3078 parent->last = elem;
3079
3080 return(elem);
3081}
3082
3083/**
3084 * xmlAddChildList:
3085 * @parent: the parent node
3086 * @cur: the first node in the list
3087 *
3088 * Add a list of node at the end of the child list of the parent
3089 * merging adjacent TEXT nodes (@cur may be freed)
3090 *
3091 * Returns the last child or NULL in case of error.
3092 */
3093xmlNodePtr
3094xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3095 xmlNodePtr prev;
3096
3097 if (parent == NULL) {
3098#ifdef DEBUG_TREE
3099 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003100 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003101#endif
3102 return(NULL);
3103 }
3104
3105 if (cur == NULL) {
3106#ifdef DEBUG_TREE
3107 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003108 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003109#endif
3110 return(NULL);
3111 }
3112
3113 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3114 (cur->doc != parent->doc)) {
3115#ifdef DEBUG_TREE
3116 xmlGenericError(xmlGenericErrorContext,
3117 "Elements moved to a different document\n");
3118#endif
3119 }
3120
3121 /*
3122 * add the first element at the end of the children list.
3123 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003124
Owen Taylor3473f882001-02-23 17:55:21 +00003125 if (parent->children == NULL) {
3126 parent->children = cur;
3127 } else {
3128 /*
3129 * If cur and parent->last both are TEXT nodes, then merge them.
3130 */
3131 if ((cur->type == XML_TEXT_NODE) &&
3132 (parent->last->type == XML_TEXT_NODE) &&
3133 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003134 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003135 /*
3136 * if it's the only child, nothing more to be done.
3137 */
3138 if (cur->next == NULL) {
3139 xmlFreeNode(cur);
3140 return(parent->last);
3141 }
3142 prev = cur;
3143 cur = cur->next;
3144 xmlFreeNode(prev);
3145 }
3146 prev = parent->last;
3147 prev->next = cur;
3148 cur->prev = prev;
3149 }
3150 while (cur->next != NULL) {
3151 cur->parent = parent;
3152 if (cur->doc != parent->doc) {
3153 xmlSetTreeDoc(cur, parent->doc);
3154 }
3155 cur = cur->next;
3156 }
3157 cur->parent = parent;
3158 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3159 parent->last = cur;
3160
3161 return(cur);
3162}
3163
3164/**
3165 * xmlAddChild:
3166 * @parent: the parent node
3167 * @cur: the child node
3168 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003169 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003170 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003171 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3172 * If there is an attribute with equal name, it is first destroyed.
3173 *
Owen Taylor3473f882001-02-23 17:55:21 +00003174 * Returns the child or NULL in case of error.
3175 */
3176xmlNodePtr
3177xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3178 xmlNodePtr prev;
3179
3180 if (parent == NULL) {
3181#ifdef DEBUG_TREE
3182 xmlGenericError(xmlGenericErrorContext,
3183 "xmlAddChild : parent == NULL\n");
3184#endif
3185 return(NULL);
3186 }
3187
3188 if (cur == NULL) {
3189#ifdef DEBUG_TREE
3190 xmlGenericError(xmlGenericErrorContext,
3191 "xmlAddChild : child == NULL\n");
3192#endif
3193 return(NULL);
3194 }
3195
Rob Richards19dc9612005-10-28 16:15:16 +00003196 if (parent == cur) {
3197#ifdef DEBUG_TREE
3198 xmlGenericError(xmlGenericErrorContext,
3199 "xmlAddChild : parent == cur\n");
3200#endif
3201 return(NULL);
3202 }
Owen Taylor3473f882001-02-23 17:55:21 +00003203 /*
3204 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003205 * cur is then freed.
3206 */
3207 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003208 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003209 (parent->content != NULL) &&
Rob Richards19dc9612005-10-28 16:15:16 +00003210 (parent->name == cur->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003211 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003212 xmlFreeNode(cur);
3213 return(parent);
3214 }
3215 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003216 (parent->last->name == cur->name) &&
3217 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003218 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003219 xmlFreeNode(cur);
3220 return(parent->last);
3221 }
3222 }
3223
3224 /*
3225 * add the new element at the end of the children list.
3226 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003227 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003228 cur->parent = parent;
3229 if (cur->doc != parent->doc) {
3230 xmlSetTreeDoc(cur, parent->doc);
3231 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003232 /* this check prevents a loop on tree-traversions if a developer
3233 * tries to add a node to its parent multiple times
3234 */
3235 if (prev == parent)
3236 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003237
3238 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003239 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003240 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003241 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003242 (parent->content != NULL) &&
3243 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003244 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003245 xmlFreeNode(cur);
3246 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003247 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003248 if (cur->type == XML_ATTRIBUTE_NODE) {
Rob Richards19dc9612005-10-28 16:15:16 +00003249 if (parent->type != XML_ELEMENT_NODE)
3250 return(NULL);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003251 if (parent->properties == NULL) {
3252 parent->properties = (xmlAttrPtr) cur;
3253 } else {
3254 /* check if an attribute with the same name exists */
3255 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003256
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003257 if (cur->ns == NULL)
Rob Richardsc342ec62005-10-25 00:10:12 +00003258 lastattr = xmlHasNsProp(parent, cur->name, NULL);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003259 else
3260 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
Rob Richardsc342ec62005-10-25 00:10:12 +00003261 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur) && (lastattr->type != XML_ATTRIBUTE_DECL)) {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003262 /* different instance, destroy it (attributes must be unique) */
Rob Richards19dc9612005-10-28 16:15:16 +00003263 xmlUnlinkNode((xmlNodePtr) lastattr);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003264 xmlFreeProp(lastattr);
3265 }
Rob Richards19dc9612005-10-28 16:15:16 +00003266 if (lastattr == (xmlAttrPtr) cur)
3267 return(cur);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003268 /* find the end */
3269 lastattr = parent->properties;
3270 while (lastattr->next != NULL) {
3271 lastattr = lastattr->next;
3272 }
3273 lastattr->next = (xmlAttrPtr) cur;
3274 ((xmlAttrPtr) cur)->prev = lastattr;
3275 }
3276 } else {
3277 if (parent->children == NULL) {
3278 parent->children = cur;
3279 parent->last = cur;
3280 } else {
3281 prev = parent->last;
3282 prev->next = cur;
3283 cur->prev = prev;
3284 parent->last = cur;
3285 }
3286 }
Owen Taylor3473f882001-02-23 17:55:21 +00003287 return(cur);
3288}
3289
3290/**
3291 * xmlGetLastChild:
3292 * @parent: the parent node
3293 *
3294 * Search the last child of a node.
3295 * Returns the last child or NULL if none.
3296 */
3297xmlNodePtr
3298xmlGetLastChild(xmlNodePtr parent) {
3299 if (parent == NULL) {
3300#ifdef DEBUG_TREE
3301 xmlGenericError(xmlGenericErrorContext,
3302 "xmlGetLastChild : parent == NULL\n");
3303#endif
3304 return(NULL);
3305 }
3306 return(parent->last);
3307}
3308
3309/**
3310 * xmlFreeNodeList:
3311 * @cur: the first node in the list
3312 *
3313 * Free a node and all its siblings, this is a recursive behaviour, all
3314 * the children are freed too.
3315 */
3316void
3317xmlFreeNodeList(xmlNodePtr cur) {
3318 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003319 xmlDictPtr dict = NULL;
3320
3321 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003322 if (cur->type == XML_NAMESPACE_DECL) {
3323 xmlFreeNsList((xmlNsPtr) cur);
3324 return;
3325 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003326 if ((cur->type == XML_DOCUMENT_NODE) ||
3327#ifdef LIBXML_DOCB_ENABLED
3328 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003329#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003330 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003331 xmlFreeDoc((xmlDocPtr) cur);
3332 return;
3333 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003334 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003335 while (cur != NULL) {
3336 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003337 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003338
Daniel Veillarda880b122003-04-21 21:36:41 +00003339 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003340 xmlDeregisterNodeDefaultValue(cur);
3341
Daniel Veillard02141ea2001-04-30 11:46:40 +00003342 if ((cur->children != NULL) &&
3343 (cur->type != XML_ENTITY_REF_NODE))
3344 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003345 if (((cur->type == XML_ELEMENT_NODE) ||
3346 (cur->type == XML_XINCLUDE_START) ||
3347 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003348 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003349 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003350 if ((cur->type != XML_ELEMENT_NODE) &&
3351 (cur->type != XML_XINCLUDE_START) &&
3352 (cur->type != XML_XINCLUDE_END) &&
Daniel Veillard8874b942005-08-25 13:19:21 +00003353 (cur->type != XML_ENTITY_REF_NODE) &&
3354 (cur->content != (xmlChar *) &(cur->properties))) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003355 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003356 }
3357 if (((cur->type == XML_ELEMENT_NODE) ||
3358 (cur->type == XML_XINCLUDE_START) ||
3359 (cur->type == XML_XINCLUDE_END)) &&
3360 (cur->nsDef != NULL))
3361 xmlFreeNsList(cur->nsDef);
3362
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003363 /*
3364 * When a node is a text node or a comment, it uses a global static
3365 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003366 * Otherwise the node name might come from the document's
3367 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003368 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003369 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003370 (cur->type != XML_TEXT_NODE) &&
3371 (cur->type != XML_COMMENT_NODE))
3372 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003373 xmlFree(cur);
3374 }
Owen Taylor3473f882001-02-23 17:55:21 +00003375 cur = next;
3376 }
3377}
3378
3379/**
3380 * xmlFreeNode:
3381 * @cur: the node
3382 *
3383 * Free a node, this is a recursive behaviour, all the children are freed too.
3384 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3385 */
3386void
3387xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003388 xmlDictPtr dict = NULL;
3389
3390 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003391
Daniel Veillard02141ea2001-04-30 11:46:40 +00003392 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003393 if (cur->type == XML_DTD_NODE) {
3394 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003395 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003396 }
3397 if (cur->type == XML_NAMESPACE_DECL) {
3398 xmlFreeNs((xmlNsPtr) cur);
3399 return;
3400 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003401 if (cur->type == XML_ATTRIBUTE_NODE) {
3402 xmlFreeProp((xmlAttrPtr) cur);
3403 return;
3404 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003405
Daniel Veillarda880b122003-04-21 21:36:41 +00003406 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003407 xmlDeregisterNodeDefaultValue(cur);
3408
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003409 if (cur->doc != NULL) dict = cur->doc->dict;
3410
Owen Taylor3473f882001-02-23 17:55:21 +00003411 if ((cur->children != NULL) &&
3412 (cur->type != XML_ENTITY_REF_NODE))
3413 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003414 if (((cur->type == XML_ELEMENT_NODE) ||
3415 (cur->type == XML_XINCLUDE_START) ||
3416 (cur->type == XML_XINCLUDE_END)) &&
3417 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003418 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003419 if ((cur->type != XML_ELEMENT_NODE) &&
3420 (cur->content != NULL) &&
3421 (cur->type != XML_ENTITY_REF_NODE) &&
3422 (cur->type != XML_XINCLUDE_END) &&
Daniel Veillard8874b942005-08-25 13:19:21 +00003423 (cur->type != XML_XINCLUDE_START) &&
3424 (cur->content != (xmlChar *) &(cur->properties))) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003425 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003426 }
3427
Daniel Veillardacd370f2001-06-09 17:17:51 +00003428 /*
3429 * When a node is a text node or a comment, it uses a global static
3430 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003431 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003432 */
Owen Taylor3473f882001-02-23 17:55:21 +00003433 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003434 (cur->type != XML_TEXT_NODE) &&
3435 (cur->type != XML_COMMENT_NODE))
3436 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003437
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003438 if (((cur->type == XML_ELEMENT_NODE) ||
3439 (cur->type == XML_XINCLUDE_START) ||
3440 (cur->type == XML_XINCLUDE_END)) &&
3441 (cur->nsDef != NULL))
3442 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003443 xmlFree(cur);
3444}
3445
3446/**
3447 * xmlUnlinkNode:
3448 * @cur: the node
3449 *
3450 * Unlink a node from it's current context, the node is not freed
3451 */
3452void
3453xmlUnlinkNode(xmlNodePtr cur) {
3454 if (cur == NULL) {
3455#ifdef DEBUG_TREE
3456 xmlGenericError(xmlGenericErrorContext,
3457 "xmlUnlinkNode : node == NULL\n");
3458#endif
3459 return;
3460 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003461 if (cur->type == XML_DTD_NODE) {
3462 xmlDocPtr doc;
3463 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003464 if (doc != NULL) {
3465 if (doc->intSubset == (xmlDtdPtr) cur)
3466 doc->intSubset = NULL;
3467 if (doc->extSubset == (xmlDtdPtr) cur)
3468 doc->extSubset = NULL;
3469 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003470 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003471 if (cur->parent != NULL) {
3472 xmlNodePtr parent;
3473 parent = cur->parent;
3474 if (cur->type == XML_ATTRIBUTE_NODE) {
3475 if (parent->properties == (xmlAttrPtr) cur)
3476 parent->properties = ((xmlAttrPtr) cur)->next;
3477 } else {
3478 if (parent->children == cur)
3479 parent->children = cur->next;
3480 if (parent->last == cur)
3481 parent->last = cur->prev;
3482 }
3483 cur->parent = NULL;
3484 }
Owen Taylor3473f882001-02-23 17:55:21 +00003485 if (cur->next != NULL)
3486 cur->next->prev = cur->prev;
3487 if (cur->prev != NULL)
3488 cur->prev->next = cur->next;
3489 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003490}
3491
Daniel Veillard2156d432004-03-04 15:59:36 +00003492#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003493/**
3494 * xmlReplaceNode:
3495 * @old: the old node
3496 * @cur: the node
3497 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003498 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003499 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003500 * first unlinked from its existing context.
3501 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003502 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003503 */
3504xmlNodePtr
3505xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00003506 if (old == cur) return(NULL);
Daniel Veillarda03e3652004-11-02 18:45:30 +00003507 if ((old == NULL) || (old->parent == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003508#ifdef DEBUG_TREE
3509 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda03e3652004-11-02 18:45:30 +00003510 "xmlReplaceNode : old == NULL or without parent\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003511#endif
3512 return(NULL);
3513 }
3514 if (cur == NULL) {
3515 xmlUnlinkNode(old);
3516 return(old);
3517 }
3518 if (cur == old) {
3519 return(old);
3520 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003521 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3522#ifdef DEBUG_TREE
3523 xmlGenericError(xmlGenericErrorContext,
3524 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3525#endif
3526 return(old);
3527 }
3528 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3529#ifdef DEBUG_TREE
3530 xmlGenericError(xmlGenericErrorContext,
3531 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3532#endif
3533 return(old);
3534 }
Owen Taylor3473f882001-02-23 17:55:21 +00003535 xmlUnlinkNode(cur);
Daniel Veillard64d7d122005-05-11 18:03:42 +00003536 xmlSetTreeDoc(cur, old->doc);
Owen Taylor3473f882001-02-23 17:55:21 +00003537 cur->parent = old->parent;
3538 cur->next = old->next;
3539 if (cur->next != NULL)
3540 cur->next->prev = cur;
3541 cur->prev = old->prev;
3542 if (cur->prev != NULL)
3543 cur->prev->next = cur;
3544 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003545 if (cur->type == XML_ATTRIBUTE_NODE) {
3546 if (cur->parent->properties == (xmlAttrPtr)old)
3547 cur->parent->properties = ((xmlAttrPtr) cur);
3548 } else {
3549 if (cur->parent->children == old)
3550 cur->parent->children = cur;
3551 if (cur->parent->last == old)
3552 cur->parent->last = cur;
3553 }
Owen Taylor3473f882001-02-23 17:55:21 +00003554 }
3555 old->next = old->prev = NULL;
3556 old->parent = NULL;
3557 return(old);
3558}
Daniel Veillard652327a2003-09-29 18:02:38 +00003559#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003560
3561/************************************************************************
3562 * *
3563 * Copy operations *
3564 * *
3565 ************************************************************************/
3566
3567/**
3568 * xmlCopyNamespace:
3569 * @cur: the namespace
3570 *
3571 * Do a copy of the namespace.
3572 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003573 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003574 */
3575xmlNsPtr
3576xmlCopyNamespace(xmlNsPtr cur) {
3577 xmlNsPtr ret;
3578
3579 if (cur == NULL) return(NULL);
3580 switch (cur->type) {
3581 case XML_LOCAL_NAMESPACE:
3582 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3583 break;
3584 default:
3585#ifdef DEBUG_TREE
3586 xmlGenericError(xmlGenericErrorContext,
3587 "xmlCopyNamespace: invalid type %d\n", cur->type);
3588#endif
3589 return(NULL);
3590 }
3591 return(ret);
3592}
3593
3594/**
3595 * xmlCopyNamespaceList:
3596 * @cur: the first namespace
3597 *
3598 * Do a copy of an namespace list.
3599 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003600 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003601 */
3602xmlNsPtr
3603xmlCopyNamespaceList(xmlNsPtr cur) {
3604 xmlNsPtr ret = NULL;
3605 xmlNsPtr p = NULL,q;
3606
3607 while (cur != NULL) {
3608 q = xmlCopyNamespace(cur);
3609 if (p == NULL) {
3610 ret = p = q;
3611 } else {
3612 p->next = q;
3613 p = q;
3614 }
3615 cur = cur->next;
3616 }
3617 return(ret);
3618}
3619
3620static xmlNodePtr
3621xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
Rob Richards19dc9612005-10-28 16:15:16 +00003622
3623static xmlAttrPtr
3624xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003625 xmlAttrPtr ret;
3626
3627 if (cur == NULL) return(NULL);
3628 if (target != NULL)
3629 ret = xmlNewDocProp(target->doc, cur->name, NULL);
Rob Richards19dc9612005-10-28 16:15:16 +00003630 else if (doc != NULL)
3631 ret = xmlNewDocProp(doc, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003632 else if (cur->parent != NULL)
3633 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3634 else if (cur->children != NULL)
3635 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3636 else
3637 ret = xmlNewDocProp(NULL, cur->name, NULL);
3638 if (ret == NULL) return(NULL);
3639 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003640
Owen Taylor3473f882001-02-23 17:55:21 +00003641 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003642 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003643
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003644 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3645 if (ns == NULL) {
3646 /*
3647 * Humm, we are copying an element whose namespace is defined
3648 * out of the new tree scope. Search it in the original tree
3649 * and add it at the top of the new tree
3650 */
3651 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3652 if (ns != NULL) {
3653 xmlNodePtr root = target;
3654 xmlNodePtr pred = NULL;
3655
3656 while (root->parent != NULL) {
3657 pred = root;
3658 root = root->parent;
3659 }
3660 if (root == (xmlNodePtr) target->doc) {
3661 /* correct possibly cycling above the document elt */
3662 root = pred;
3663 }
3664 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3665 }
3666 } else {
3667 /*
3668 * we have to find something appropriate here since
3669 * we cant be sure, that the namespce we found is identified
3670 * by the prefix
3671 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003672 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003673 /* this is the nice case */
3674 ret->ns = ns;
3675 } else {
3676 /*
3677 * we are in trouble: we need a new reconcilied namespace.
3678 * This is expensive
3679 */
3680 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3681 }
3682 }
3683
Owen Taylor3473f882001-02-23 17:55:21 +00003684 } else
3685 ret->ns = NULL;
3686
3687 if (cur->children != NULL) {
3688 xmlNodePtr tmp;
3689
3690 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3691 ret->last = NULL;
3692 tmp = ret->children;
3693 while (tmp != NULL) {
3694 /* tmp->parent = (xmlNodePtr)ret; */
3695 if (tmp->next == NULL)
3696 ret->last = tmp;
3697 tmp = tmp->next;
3698 }
3699 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003700 /*
3701 * Try to handle IDs
3702 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003703 if ((target!= NULL) && (cur!= NULL) &&
3704 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003705 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3706 if (xmlIsID(cur->doc, cur->parent, cur)) {
3707 xmlChar *id;
3708
3709 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3710 if (id != NULL) {
3711 xmlAddID(NULL, target->doc, id, ret);
3712 xmlFree(id);
3713 }
3714 }
3715 }
Owen Taylor3473f882001-02-23 17:55:21 +00003716 return(ret);
3717}
3718
3719/**
Rob Richards19dc9612005-10-28 16:15:16 +00003720 * xmlCopyProp:
3721 * @target: the element where the attribute will be grafted
3722 * @cur: the attribute
3723 *
3724 * Do a copy of the attribute.
3725 *
3726 * Returns: a new #xmlAttrPtr, or NULL in case of error.
3727 */
3728xmlAttrPtr
3729xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3730 return xmlCopyPropInternal(NULL, target, cur);
3731}
3732
3733/**
Owen Taylor3473f882001-02-23 17:55:21 +00003734 * xmlCopyPropList:
3735 * @target: the element where the attributes will be grafted
3736 * @cur: the first attribute
3737 *
3738 * Do a copy of an attribute list.
3739 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003740 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003741 */
3742xmlAttrPtr
3743xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3744 xmlAttrPtr ret = NULL;
3745 xmlAttrPtr p = NULL,q;
3746
3747 while (cur != NULL) {
3748 q = xmlCopyProp(target, cur);
William M. Brack13dfa872004-09-18 04:52:08 +00003749 if (q == NULL)
3750 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003751 if (p == NULL) {
3752 ret = p = q;
3753 } else {
3754 p->next = q;
3755 q->prev = p;
3756 p = q;
3757 }
3758 cur = cur->next;
3759 }
3760 return(ret);
3761}
3762
3763/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003764 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003765 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003766 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003767 * tricky reason: namespaces. Doing a direct copy of a node
3768 * say RPM:Copyright without changing the namespace pointer to
3769 * something else can produce stale links. One way to do it is
3770 * to keep a reference counter but this doesn't work as soon
3771 * as one move the element or the subtree out of the scope of
3772 * the existing namespace. The actual solution seems to add
3773 * a copy of the namespace at the top of the copied tree if
3774 * not available in the subtree.
3775 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00003776 * The argument "recursive" normally indicates a recursive copy
3777 * of the node with values 0 (no) and 1 (yes). For XInclude,
3778 * however, we allow a value of 2 to indicate copy properties and
3779 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00003780 */
3781
3782static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003783xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00003784 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003785 xmlNodePtr ret;
3786
3787 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003788 switch (node->type) {
3789 case XML_TEXT_NODE:
3790 case XML_CDATA_SECTION_NODE:
3791 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003792 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003793 case XML_ENTITY_REF_NODE:
3794 case XML_ENTITY_NODE:
3795 case XML_PI_NODE:
3796 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003797 case XML_XINCLUDE_START:
3798 case XML_XINCLUDE_END:
3799 break;
3800 case XML_ATTRIBUTE_NODE:
Rob Richards19dc9612005-10-28 16:15:16 +00003801 return((xmlNodePtr) xmlCopyPropInternal(doc, parent, (xmlAttrPtr) node));
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003802 case XML_NAMESPACE_DECL:
3803 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3804
Daniel Veillard39196eb2001-06-19 18:09:42 +00003805 case XML_DOCUMENT_NODE:
3806 case XML_HTML_DOCUMENT_NODE:
3807#ifdef LIBXML_DOCB_ENABLED
3808 case XML_DOCB_DOCUMENT_NODE:
3809#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003810#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00003811 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00003812#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003813 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003814 case XML_NOTATION_NODE:
3815 case XML_DTD_NODE:
3816 case XML_ELEMENT_DECL:
3817 case XML_ATTRIBUTE_DECL:
3818 case XML_ENTITY_DECL:
3819 return(NULL);
3820 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003821
Owen Taylor3473f882001-02-23 17:55:21 +00003822 /*
3823 * Allocate a new node and fill the fields.
3824 */
3825 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3826 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003827 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003828 return(NULL);
3829 }
3830 memset(ret, 0, sizeof(xmlNode));
3831 ret->type = node->type;
3832
3833 ret->doc = doc;
3834 ret->parent = parent;
3835 if (node->name == xmlStringText)
3836 ret->name = xmlStringText;
3837 else if (node->name == xmlStringTextNoenc)
3838 ret->name = xmlStringTextNoenc;
3839 else if (node->name == xmlStringComment)
3840 ret->name = xmlStringComment;
Daniel Veillard03a53c32004-10-26 16:06:51 +00003841 else if (node->name != NULL) {
3842 if ((doc != NULL) && (doc->dict != NULL))
3843 ret->name = xmlDictLookup(doc->dict, node->name, -1);
3844 else
3845 ret->name = xmlStrdup(node->name);
3846 }
Daniel Veillard7db37732001-07-12 01:20:08 +00003847 if ((node->type != XML_ELEMENT_NODE) &&
3848 (node->content != NULL) &&
3849 (node->type != XML_ENTITY_REF_NODE) &&
3850 (node->type != XML_XINCLUDE_END) &&
3851 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003852 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003853 }else{
3854 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003855 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003856 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003857 if (parent != NULL) {
3858 xmlNodePtr tmp;
3859
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003860 /*
3861 * this is a tricky part for the node register thing:
3862 * in case ret does get coalesced in xmlAddChild
3863 * the deregister-node callback is called; so we register ret now already
3864 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003865 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003866 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3867
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003868 tmp = xmlAddChild(parent, ret);
3869 /* node could have coalesced */
3870 if (tmp != ret)
3871 return(tmp);
3872 }
Owen Taylor3473f882001-02-23 17:55:21 +00003873
William M. Brack57e9e912004-03-09 16:19:02 +00003874 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003875 goto out;
Daniel Veillard8874b942005-08-25 13:19:21 +00003876 if ((node->type == XML_ELEMENT_NODE) && (node->nsDef != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00003877 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3878
3879 if (node->ns != NULL) {
3880 xmlNsPtr ns;
3881
3882 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3883 if (ns == NULL) {
3884 /*
3885 * Humm, we are copying an element whose namespace is defined
3886 * out of the new tree scope. Search it in the original tree
3887 * and add it at the top of the new tree
3888 */
3889 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3890 if (ns != NULL) {
3891 xmlNodePtr root = ret;
3892
3893 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003894 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003895 }
3896 } else {
3897 /*
3898 * reference the existing namespace definition in our own tree.
3899 */
3900 ret->ns = ns;
3901 }
3902 }
Daniel Veillard8874b942005-08-25 13:19:21 +00003903 if ((node->type == XML_ELEMENT_NODE) && (node->properties != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00003904 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003905 if (node->type == XML_ENTITY_REF_NODE) {
3906 if ((doc == NULL) || (node->doc != doc)) {
3907 /*
3908 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003909 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003910 * we cannot keep the reference. Try to find it in the
3911 * target document.
3912 */
3913 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3914 } else {
3915 ret->children = node->children;
3916 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003917 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00003918 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003919 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003920 UPDATE_LAST_CHILD_AND_PARENT(ret)
3921 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003922
3923out:
3924 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00003925 if ((parent == NULL) &&
3926 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003927 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003928 return(ret);
3929}
3930
3931static xmlNodePtr
3932xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3933 xmlNodePtr ret = NULL;
3934 xmlNodePtr p = NULL,q;
3935
3936 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003937#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003938 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003939 if (doc == NULL) {
3940 node = node->next;
3941 continue;
3942 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003943 if (doc->intSubset == NULL) {
3944 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3945 q->doc = doc;
3946 q->parent = parent;
3947 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003948 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003949 } else {
3950 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003951 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003952 }
3953 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003954#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003955 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003956 if (ret == NULL) {
3957 q->prev = NULL;
3958 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003959 } else if (p != q) {
3960 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003961 p->next = q;
3962 q->prev = p;
3963 p = q;
3964 }
3965 node = node->next;
3966 }
3967 return(ret);
3968}
3969
3970/**
3971 * xmlCopyNode:
3972 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00003973 * @extended: if 1 do a recursive copy (properties, namespaces and children
3974 * when applicable)
3975 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00003976 *
3977 * Do a copy of the node.
3978 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003979 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003980 */
3981xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003982xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003983 xmlNodePtr ret;
3984
William M. Brack57e9e912004-03-09 16:19:02 +00003985 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00003986 return(ret);
3987}
3988
3989/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003990 * xmlDocCopyNode:
3991 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003992 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00003993 * @extended: if 1 do a recursive copy (properties, namespaces and children
3994 * when applicable)
3995 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00003996 *
3997 * Do a copy of the node to a given document.
3998 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003999 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00004000 */
4001xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00004002xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00004003 xmlNodePtr ret;
4004
William M. Brack57e9e912004-03-09 16:19:02 +00004005 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00004006 return(ret);
4007}
4008
4009/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00004010 * xmlDocCopyNodeList:
4011 * @doc: the target document
4012 * @node: the first node in the list.
4013 *
4014 * Do a recursive copy of the node list.
4015 *
4016 * Returns: a new #xmlNodePtr, or NULL in case of error.
4017 */
4018xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) {
4019 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
4020 return(ret);
4021}
4022
4023/**
Owen Taylor3473f882001-02-23 17:55:21 +00004024 * xmlCopyNodeList:
4025 * @node: the first node in the list.
4026 *
4027 * Do a recursive copy of the node list.
Daniel Veillard03a53c32004-10-26 16:06:51 +00004028 * Use xmlDocCopyNodeList() if possible to ensure string interning.
Owen Taylor3473f882001-02-23 17:55:21 +00004029 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004030 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004031 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00004032xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00004033 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
4034 return(ret);
4035}
4036
Daniel Veillard2156d432004-03-04 15:59:36 +00004037#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004038/**
Owen Taylor3473f882001-02-23 17:55:21 +00004039 * xmlCopyDtd:
4040 * @dtd: the dtd
4041 *
4042 * Do a copy of the dtd.
4043 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004044 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004045 */
4046xmlDtdPtr
4047xmlCopyDtd(xmlDtdPtr dtd) {
4048 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004049 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00004050
4051 if (dtd == NULL) return(NULL);
4052 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4053 if (ret == NULL) return(NULL);
4054 if (dtd->entities != NULL)
4055 ret->entities = (void *) xmlCopyEntitiesTable(
4056 (xmlEntitiesTablePtr) dtd->entities);
4057 if (dtd->notations != NULL)
4058 ret->notations = (void *) xmlCopyNotationTable(
4059 (xmlNotationTablePtr) dtd->notations);
4060 if (dtd->elements != NULL)
4061 ret->elements = (void *) xmlCopyElementTable(
4062 (xmlElementTablePtr) dtd->elements);
4063 if (dtd->attributes != NULL)
4064 ret->attributes = (void *) xmlCopyAttributeTable(
4065 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004066 if (dtd->pentities != NULL)
4067 ret->pentities = (void *) xmlCopyEntitiesTable(
4068 (xmlEntitiesTablePtr) dtd->pentities);
4069
4070 cur = dtd->children;
4071 while (cur != NULL) {
4072 q = NULL;
4073
4074 if (cur->type == XML_ENTITY_DECL) {
4075 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4076 switch (tmp->etype) {
4077 case XML_INTERNAL_GENERAL_ENTITY:
4078 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4079 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4080 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4081 break;
4082 case XML_INTERNAL_PARAMETER_ENTITY:
4083 case XML_EXTERNAL_PARAMETER_ENTITY:
4084 q = (xmlNodePtr)
4085 xmlGetParameterEntityFromDtd(ret, tmp->name);
4086 break;
4087 case XML_INTERNAL_PREDEFINED_ENTITY:
4088 break;
4089 }
4090 } else if (cur->type == XML_ELEMENT_DECL) {
4091 xmlElementPtr tmp = (xmlElementPtr) cur;
4092 q = (xmlNodePtr)
4093 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4094 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4095 xmlAttributePtr tmp = (xmlAttributePtr) cur;
4096 q = (xmlNodePtr)
4097 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4098 } else if (cur->type == XML_COMMENT_NODE) {
4099 q = xmlCopyNode(cur, 0);
4100 }
4101
4102 if (q == NULL) {
4103 cur = cur->next;
4104 continue;
4105 }
4106
4107 if (p == NULL)
4108 ret->children = q;
4109 else
4110 p->next = q;
4111
4112 q->prev = p;
4113 q->parent = (xmlNodePtr) ret;
4114 q->next = NULL;
4115 ret->last = q;
4116 p = q;
4117 cur = cur->next;
4118 }
4119
Owen Taylor3473f882001-02-23 17:55:21 +00004120 return(ret);
4121}
Daniel Veillard2156d432004-03-04 15:59:36 +00004122#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004123
Daniel Veillard2156d432004-03-04 15:59:36 +00004124#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004125/**
4126 * xmlCopyDoc:
4127 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004128 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004129 *
4130 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004131 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004132 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004133 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004134 */
4135xmlDocPtr
4136xmlCopyDoc(xmlDocPtr doc, int recursive) {
4137 xmlDocPtr ret;
4138
4139 if (doc == NULL) return(NULL);
4140 ret = xmlNewDoc(doc->version);
4141 if (ret == NULL) return(NULL);
4142 if (doc->name != NULL)
4143 ret->name = xmlMemStrdup(doc->name);
4144 if (doc->encoding != NULL)
4145 ret->encoding = xmlStrdup(doc->encoding);
Daniel Veillardf59507d2005-01-27 17:26:49 +00004146 if (doc->URL != NULL)
4147 ret->URL = xmlStrdup(doc->URL);
Owen Taylor3473f882001-02-23 17:55:21 +00004148 ret->charset = doc->charset;
4149 ret->compression = doc->compression;
4150 ret->standalone = doc->standalone;
4151 if (!recursive) return(ret);
4152
Daniel Veillardb33c2012001-04-25 12:59:04 +00004153 ret->last = NULL;
4154 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004155#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004156 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004157 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004158 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004159 ret->intSubset->parent = ret;
4160 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004161#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004162 if (doc->oldNs != NULL)
4163 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4164 if (doc->children != NULL) {
4165 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004166
4167 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4168 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004169 ret->last = NULL;
4170 tmp = ret->children;
4171 while (tmp != NULL) {
4172 if (tmp->next == NULL)
4173 ret->last = tmp;
4174 tmp = tmp->next;
4175 }
4176 }
4177 return(ret);
4178}
Daniel Veillard652327a2003-09-29 18:02:38 +00004179#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004180
4181/************************************************************************
4182 * *
4183 * Content access functions *
4184 * *
4185 ************************************************************************/
4186
4187/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004188 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004189 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004190 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004191 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004192 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004193 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004194 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004195 */
4196long
4197xmlGetLineNo(xmlNodePtr node)
4198{
4199 long result = -1;
4200
4201 if (!node)
4202 return result;
Daniel Veillard73da77e2005-08-24 14:05:37 +00004203 if ((node->type == XML_ELEMENT_NODE) ||
4204 (node->type == XML_TEXT_NODE) ||
4205 (node->type == XML_COMMENT_NODE) ||
4206 (node->type == XML_PI_NODE))
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004207 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004208 else if ((node->prev != NULL) &&
4209 ((node->prev->type == XML_ELEMENT_NODE) ||
Daniel Veillard73da77e2005-08-24 14:05:37 +00004210 (node->prev->type == XML_TEXT_NODE) ||
4211 (node->prev->type == XML_COMMENT_NODE) ||
4212 (node->prev->type == XML_PI_NODE)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004213 result = xmlGetLineNo(node->prev);
4214 else if ((node->parent != NULL) &&
Daniel Veillard73da77e2005-08-24 14:05:37 +00004215 (node->parent->type == XML_ELEMENT_NODE))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004216 result = xmlGetLineNo(node->parent);
4217
4218 return result;
4219}
4220
Daniel Veillard2156d432004-03-04 15:59:36 +00004221#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004222/**
4223 * xmlGetNodePath:
4224 * @node: a node
4225 *
4226 * Build a structure based Path for the given node
4227 *
4228 * Returns the new path or NULL in case of error. The caller must free
4229 * the returned string
4230 */
4231xmlChar *
4232xmlGetNodePath(xmlNodePtr node)
4233{
4234 xmlNodePtr cur, tmp, next;
4235 xmlChar *buffer = NULL, *temp;
4236 size_t buf_len;
4237 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004238 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004239 const char *name;
4240 char nametemp[100];
4241 int occur = 0;
4242
4243 if (node == NULL)
4244 return (NULL);
4245
4246 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004247 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004248 if (buffer == NULL) {
4249 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004250 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004251 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004252 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004253 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004254 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004255 xmlFree(buffer);
4256 return (NULL);
4257 }
4258
4259 buffer[0] = 0;
4260 cur = node;
4261 do {
4262 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004263 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004264 occur = 0;
4265 if ((cur->type == XML_DOCUMENT_NODE) ||
4266 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4267 if (buffer[0] == '/')
4268 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004269 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004270 next = NULL;
4271 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004272 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004273 name = (const char *) cur->name;
4274 if (cur->ns) {
William M. Brack84d83e32003-12-23 03:45:17 +00004275 if (cur->ns->prefix != NULL)
William M. Brack13dfa872004-09-18 04:52:08 +00004276 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4277 (char *)cur->ns->prefix, (char *)cur->name);
William M. Brack84d83e32003-12-23 03:45:17 +00004278 else
William M. Brack13dfa872004-09-18 04:52:08 +00004279 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4280 (char *)cur->name);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004281 nametemp[sizeof(nametemp) - 1] = 0;
4282 name = nametemp;
4283 }
4284 next = cur->parent;
4285
4286 /*
4287 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004288 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004289 */
4290 tmp = cur->prev;
4291 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004292 if ((tmp->type == XML_ELEMENT_NODE) &&
Daniel Veillard0996a162005-02-05 14:00:10 +00004293 (xmlStrEqual(cur->name, tmp->name)) &&
4294 ((tmp->ns == cur->ns) ||
4295 ((tmp->ns != NULL) && (cur->ns != NULL) &&
4296 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004297 occur++;
4298 tmp = tmp->prev;
4299 }
4300 if (occur == 0) {
4301 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004302 while (tmp != NULL && occur == 0) {
4303 if ((tmp->type == XML_ELEMENT_NODE) &&
Daniel Veillard0996a162005-02-05 14:00:10 +00004304 (xmlStrEqual(cur->name, tmp->name)) &&
4305 ((tmp->ns == cur->ns) ||
4306 ((tmp->ns != NULL) && (cur->ns != NULL) &&
4307 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004308 occur++;
4309 tmp = tmp->next;
4310 }
4311 if (occur != 0)
4312 occur = 1;
4313 } else
4314 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004315 } else if (cur->type == XML_COMMENT_NODE) {
4316 sep = "/";
4317 name = "comment()";
4318 next = cur->parent;
4319
4320 /*
4321 * Thumbler index computation
4322 */
4323 tmp = cur->prev;
4324 while (tmp != NULL) {
4325 if (tmp->type == XML_COMMENT_NODE)
4326 occur++;
4327 tmp = tmp->prev;
4328 }
4329 if (occur == 0) {
4330 tmp = cur->next;
4331 while (tmp != NULL && occur == 0) {
4332 if (tmp->type == XML_COMMENT_NODE)
4333 occur++;
4334 tmp = tmp->next;
4335 }
4336 if (occur != 0)
4337 occur = 1;
4338 } else
4339 occur++;
4340 } else if ((cur->type == XML_TEXT_NODE) ||
4341 (cur->type == XML_CDATA_SECTION_NODE)) {
4342 sep = "/";
4343 name = "text()";
4344 next = cur->parent;
4345
4346 /*
4347 * Thumbler index computation
4348 */
4349 tmp = cur->prev;
4350 while (tmp != NULL) {
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004351 if ((tmp->type == XML_TEXT_NODE) ||
4352 (tmp->type == XML_CDATA_SECTION_NODE))
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004353 occur++;
4354 tmp = tmp->prev;
4355 }
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004356 /*
4357 * Evaluate if this is the only text- or CDATA-section-node;
4358 * if yes, then we'll get "text()", otherwise "text()[1]".
4359 */
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004360 if (occur == 0) {
4361 tmp = cur->next;
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004362 while (tmp != NULL) {
4363 if ((tmp->type == XML_TEXT_NODE) ||
4364 (tmp->type == XML_CDATA_SECTION_NODE))
4365 {
4366 occur = 1;
4367 break;
4368 }
4369 tmp = tmp->next;
4370 }
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004371 } else
4372 occur++;
4373 } else if (cur->type == XML_PI_NODE) {
4374 sep = "/";
4375 snprintf(nametemp, sizeof(nametemp) - 1,
William M. Brack13dfa872004-09-18 04:52:08 +00004376 "processing-instruction('%s')", (char *)cur->name);
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004377 nametemp[sizeof(nametemp) - 1] = 0;
4378 name = nametemp;
4379
4380 next = cur->parent;
4381
4382 /*
4383 * Thumbler index computation
4384 */
4385 tmp = cur->prev;
4386 while (tmp != NULL) {
4387 if ((tmp->type == XML_PI_NODE) &&
4388 (xmlStrEqual(cur->name, tmp->name)))
4389 occur++;
4390 tmp = tmp->prev;
4391 }
4392 if (occur == 0) {
4393 tmp = cur->next;
4394 while (tmp != NULL && occur == 0) {
4395 if ((tmp->type == XML_PI_NODE) &&
4396 (xmlStrEqual(cur->name, tmp->name)))
4397 occur++;
4398 tmp = tmp->next;
4399 }
4400 if (occur != 0)
4401 occur = 1;
4402 } else
4403 occur++;
4404
Daniel Veillard8faa7832001-11-26 15:58:08 +00004405 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004406 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004407 name = (const char *) (((xmlAttrPtr) cur)->name);
Daniel Veillard365c8062005-07-19 11:31:55 +00004408 if (cur->ns) {
4409 if (cur->ns->prefix != NULL)
4410 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4411 (char *)cur->ns->prefix, (char *)cur->name);
4412 else
4413 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4414 (char *)cur->name);
4415 nametemp[sizeof(nametemp) - 1] = 0;
4416 name = nametemp;
4417 }
Daniel Veillard8faa7832001-11-26 15:58:08 +00004418 next = ((xmlAttrPtr) cur)->parent;
4419 } else {
4420 next = cur->parent;
4421 }
4422
4423 /*
4424 * Make sure there is enough room
4425 */
4426 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4427 buf_len =
4428 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4429 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4430 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004431 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004432 xmlFree(buf);
4433 xmlFree(buffer);
4434 return (NULL);
4435 }
4436 buffer = temp;
4437 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4438 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004439 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004440 xmlFree(buf);
4441 xmlFree(buffer);
4442 return (NULL);
4443 }
4444 buf = temp;
4445 }
4446 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004447 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004448 sep, name, (char *) buffer);
4449 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004450 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004451 sep, name, occur, (char *) buffer);
William M. Brack13dfa872004-09-18 04:52:08 +00004452 snprintf((char *) buffer, buf_len, "%s", (char *)buf);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004453 cur = next;
4454 } while (cur != NULL);
4455 xmlFree(buf);
4456 return (buffer);
4457}
Daniel Veillard652327a2003-09-29 18:02:38 +00004458#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004459
4460/**
Owen Taylor3473f882001-02-23 17:55:21 +00004461 * xmlDocGetRootElement:
4462 * @doc: the document
4463 *
4464 * Get the root element of the document (doc->children is a list
4465 * containing possibly comments, PIs, etc ...).
4466 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004467 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004468 */
4469xmlNodePtr
4470xmlDocGetRootElement(xmlDocPtr doc) {
4471 xmlNodePtr ret;
4472
4473 if (doc == NULL) return(NULL);
4474 ret = doc->children;
4475 while (ret != NULL) {
4476 if (ret->type == XML_ELEMENT_NODE)
4477 return(ret);
4478 ret = ret->next;
4479 }
4480 return(ret);
4481}
4482
Daniel Veillard2156d432004-03-04 15:59:36 +00004483#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004484/**
4485 * xmlDocSetRootElement:
4486 * @doc: the document
4487 * @root: the new document root element
4488 *
4489 * Set the root element of the document (doc->children is a list
4490 * containing possibly comments, PIs, etc ...).
4491 *
4492 * Returns the old root element if any was found
4493 */
4494xmlNodePtr
4495xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4496 xmlNodePtr old = NULL;
4497
4498 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004499 if (root == NULL)
4500 return(NULL);
4501 xmlUnlinkNode(root);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00004502 xmlSetTreeDoc(root, doc);
Daniel Veillardc575b992002-02-08 13:28:40 +00004503 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004504 old = doc->children;
4505 while (old != NULL) {
4506 if (old->type == XML_ELEMENT_NODE)
4507 break;
4508 old = old->next;
4509 }
4510 if (old == NULL) {
4511 if (doc->children == NULL) {
4512 doc->children = root;
4513 doc->last = root;
4514 } else {
4515 xmlAddSibling(doc->children, root);
4516 }
4517 } else {
4518 xmlReplaceNode(old, root);
4519 }
4520 return(old);
4521}
Daniel Veillard2156d432004-03-04 15:59:36 +00004522#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004523
Daniel Veillard2156d432004-03-04 15:59:36 +00004524#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004525/**
4526 * xmlNodeSetLang:
4527 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004528 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004529 *
4530 * Set the language of a node, i.e. the values of the xml:lang
4531 * attribute.
4532 */
4533void
4534xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004535 xmlNsPtr ns;
4536
Owen Taylor3473f882001-02-23 17:55:21 +00004537 if (cur == NULL) return;
4538 switch(cur->type) {
4539 case XML_TEXT_NODE:
4540 case XML_CDATA_SECTION_NODE:
4541 case XML_COMMENT_NODE:
4542 case XML_DOCUMENT_NODE:
4543 case XML_DOCUMENT_TYPE_NODE:
4544 case XML_DOCUMENT_FRAG_NODE:
4545 case XML_NOTATION_NODE:
4546 case XML_HTML_DOCUMENT_NODE:
4547 case XML_DTD_NODE:
4548 case XML_ELEMENT_DECL:
4549 case XML_ATTRIBUTE_DECL:
4550 case XML_ENTITY_DECL:
4551 case XML_PI_NODE:
4552 case XML_ENTITY_REF_NODE:
4553 case XML_ENTITY_NODE:
4554 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004555#ifdef LIBXML_DOCB_ENABLED
4556 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004557#endif
4558 case XML_XINCLUDE_START:
4559 case XML_XINCLUDE_END:
4560 return;
4561 case XML_ELEMENT_NODE:
4562 case XML_ATTRIBUTE_NODE:
4563 break;
4564 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004565 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4566 if (ns == NULL)
4567 return;
4568 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004569}
Daniel Veillard652327a2003-09-29 18:02:38 +00004570#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004571
4572/**
4573 * xmlNodeGetLang:
4574 * @cur: the node being checked
4575 *
4576 * Searches the language of a node, i.e. the values of the xml:lang
4577 * attribute or the one carried by the nearest ancestor.
4578 *
4579 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004580 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004581 */
4582xmlChar *
4583xmlNodeGetLang(xmlNodePtr cur) {
4584 xmlChar *lang;
4585
4586 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004587 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004588 if (lang != NULL)
4589 return(lang);
4590 cur = cur->parent;
4591 }
4592 return(NULL);
4593}
4594
4595
Daniel Veillard652327a2003-09-29 18:02:38 +00004596#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004597/**
4598 * xmlNodeSetSpacePreserve:
4599 * @cur: the node being changed
4600 * @val: the xml:space value ("0": default, 1: "preserve")
4601 *
4602 * Set (or reset) the space preserving behaviour of a node, i.e. the
4603 * value of the xml:space attribute.
4604 */
4605void
4606xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004607 xmlNsPtr ns;
4608
Owen Taylor3473f882001-02-23 17:55:21 +00004609 if (cur == NULL) return;
4610 switch(cur->type) {
4611 case XML_TEXT_NODE:
4612 case XML_CDATA_SECTION_NODE:
4613 case XML_COMMENT_NODE:
4614 case XML_DOCUMENT_NODE:
4615 case XML_DOCUMENT_TYPE_NODE:
4616 case XML_DOCUMENT_FRAG_NODE:
4617 case XML_NOTATION_NODE:
4618 case XML_HTML_DOCUMENT_NODE:
4619 case XML_DTD_NODE:
4620 case XML_ELEMENT_DECL:
4621 case XML_ATTRIBUTE_DECL:
4622 case XML_ENTITY_DECL:
4623 case XML_PI_NODE:
4624 case XML_ENTITY_REF_NODE:
4625 case XML_ENTITY_NODE:
4626 case XML_NAMESPACE_DECL:
4627 case XML_XINCLUDE_START:
4628 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004629#ifdef LIBXML_DOCB_ENABLED
4630 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004631#endif
4632 return;
4633 case XML_ELEMENT_NODE:
4634 case XML_ATTRIBUTE_NODE:
4635 break;
4636 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004637 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4638 if (ns == NULL)
4639 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004640 switch (val) {
4641 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004642 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004643 break;
4644 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004645 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004646 break;
4647 }
4648}
Daniel Veillard652327a2003-09-29 18:02:38 +00004649#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004650
4651/**
4652 * xmlNodeGetSpacePreserve:
4653 * @cur: the node being checked
4654 *
4655 * Searches the space preserving behaviour of a node, i.e. the values
4656 * of the xml:space attribute or the one carried by the nearest
4657 * ancestor.
4658 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004659 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004660 */
4661int
4662xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4663 xmlChar *space;
4664
4665 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004666 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004667 if (space != NULL) {
4668 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4669 xmlFree(space);
4670 return(1);
4671 }
4672 if (xmlStrEqual(space, BAD_CAST "default")) {
4673 xmlFree(space);
4674 return(0);
4675 }
4676 xmlFree(space);
4677 }
4678 cur = cur->parent;
4679 }
4680 return(-1);
4681}
4682
Daniel Veillard652327a2003-09-29 18:02:38 +00004683#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004684/**
4685 * xmlNodeSetName:
4686 * @cur: the node being changed
4687 * @name: the new tag name
4688 *
4689 * Set (or reset) the name of a node.
4690 */
4691void
4692xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00004693 xmlDocPtr doc;
4694 xmlDictPtr dict;
4695
Owen Taylor3473f882001-02-23 17:55:21 +00004696 if (cur == NULL) return;
4697 if (name == NULL) return;
4698 switch(cur->type) {
4699 case XML_TEXT_NODE:
4700 case XML_CDATA_SECTION_NODE:
4701 case XML_COMMENT_NODE:
4702 case XML_DOCUMENT_TYPE_NODE:
4703 case XML_DOCUMENT_FRAG_NODE:
4704 case XML_NOTATION_NODE:
4705 case XML_HTML_DOCUMENT_NODE:
4706 case XML_NAMESPACE_DECL:
4707 case XML_XINCLUDE_START:
4708 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004709#ifdef LIBXML_DOCB_ENABLED
4710 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004711#endif
4712 return;
4713 case XML_ELEMENT_NODE:
4714 case XML_ATTRIBUTE_NODE:
4715 case XML_PI_NODE:
4716 case XML_ENTITY_REF_NODE:
4717 case XML_ENTITY_NODE:
4718 case XML_DTD_NODE:
4719 case XML_DOCUMENT_NODE:
4720 case XML_ELEMENT_DECL:
4721 case XML_ATTRIBUTE_DECL:
4722 case XML_ENTITY_DECL:
4723 break;
4724 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00004725 doc = cur->doc;
4726 if (doc != NULL)
4727 dict = doc->dict;
4728 else
4729 dict = NULL;
4730 if (dict != NULL) {
4731 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
4732 xmlFree((xmlChar *) cur->name);
4733 cur->name = xmlDictLookup(dict, name, -1);
4734 } else {
4735 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4736 cur->name = xmlStrdup(name);
4737 }
Owen Taylor3473f882001-02-23 17:55:21 +00004738}
Daniel Veillard2156d432004-03-04 15:59:36 +00004739#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004740
Daniel Veillard2156d432004-03-04 15:59:36 +00004741#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004742/**
4743 * xmlNodeSetBase:
4744 * @cur: the node being changed
4745 * @uri: the new base URI
4746 *
4747 * Set (or reset) the base URI of a node, i.e. the value of the
4748 * xml:base attribute.
4749 */
4750void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004751xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004752 xmlNsPtr ns;
4753
Owen Taylor3473f882001-02-23 17:55:21 +00004754 if (cur == NULL) return;
4755 switch(cur->type) {
4756 case XML_TEXT_NODE:
4757 case XML_CDATA_SECTION_NODE:
4758 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004759 case XML_DOCUMENT_TYPE_NODE:
4760 case XML_DOCUMENT_FRAG_NODE:
4761 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004762 case XML_DTD_NODE:
4763 case XML_ELEMENT_DECL:
4764 case XML_ATTRIBUTE_DECL:
4765 case XML_ENTITY_DECL:
4766 case XML_PI_NODE:
4767 case XML_ENTITY_REF_NODE:
4768 case XML_ENTITY_NODE:
4769 case XML_NAMESPACE_DECL:
4770 case XML_XINCLUDE_START:
4771 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004772 return;
4773 case XML_ELEMENT_NODE:
4774 case XML_ATTRIBUTE_NODE:
4775 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004776 case XML_DOCUMENT_NODE:
4777#ifdef LIBXML_DOCB_ENABLED
4778 case XML_DOCB_DOCUMENT_NODE:
4779#endif
4780 case XML_HTML_DOCUMENT_NODE: {
4781 xmlDocPtr doc = (xmlDocPtr) cur;
4782
4783 if (doc->URL != NULL)
4784 xmlFree((xmlChar *) doc->URL);
4785 if (uri == NULL)
4786 doc->URL = NULL;
4787 else
4788 doc->URL = xmlStrdup(uri);
4789 return;
4790 }
Owen Taylor3473f882001-02-23 17:55:21 +00004791 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004792
4793 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4794 if (ns == NULL)
4795 return;
4796 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004797}
Daniel Veillard652327a2003-09-29 18:02:38 +00004798#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004799
4800/**
Owen Taylor3473f882001-02-23 17:55:21 +00004801 * xmlNodeGetBase:
4802 * @doc: the document the node pertains to
4803 * @cur: the node being checked
4804 *
4805 * Searches for the BASE URL. The code should work on both XML
4806 * and HTML document even if base mechanisms are completely different.
4807 * It returns the base as defined in RFC 2396 sections
4808 * 5.1.1. Base URI within Document Content
4809 * and
4810 * 5.1.2. Base URI from the Encapsulating Entity
4811 * However it does not return the document base (5.1.3), use
4812 * xmlDocumentGetBase() for this
4813 *
4814 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004815 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004816 */
4817xmlChar *
4818xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004819 xmlChar *oldbase = NULL;
4820 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004821
4822 if ((cur == NULL) && (doc == NULL))
4823 return(NULL);
4824 if (doc == NULL) doc = cur->doc;
4825 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4826 cur = doc->children;
4827 while ((cur != NULL) && (cur->name != NULL)) {
4828 if (cur->type != XML_ELEMENT_NODE) {
4829 cur = cur->next;
4830 continue;
4831 }
4832 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4833 cur = cur->children;
4834 continue;
4835 }
4836 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4837 cur = cur->children;
4838 continue;
4839 }
4840 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4841 return(xmlGetProp(cur, BAD_CAST "href"));
4842 }
4843 cur = cur->next;
4844 }
4845 return(NULL);
4846 }
4847 while (cur != NULL) {
4848 if (cur->type == XML_ENTITY_DECL) {
4849 xmlEntityPtr ent = (xmlEntityPtr) cur;
4850 return(xmlStrdup(ent->URI));
4851 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004852 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004853 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004854 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004855 if (oldbase != NULL) {
4856 newbase = xmlBuildURI(oldbase, base);
4857 if (newbase != NULL) {
4858 xmlFree(oldbase);
4859 xmlFree(base);
4860 oldbase = newbase;
4861 } else {
4862 xmlFree(oldbase);
4863 xmlFree(base);
4864 return(NULL);
4865 }
4866 } else {
4867 oldbase = base;
4868 }
4869 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4870 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4871 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4872 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004873 }
4874 }
Owen Taylor3473f882001-02-23 17:55:21 +00004875 cur = cur->parent;
4876 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004877 if ((doc != NULL) && (doc->URL != NULL)) {
4878 if (oldbase == NULL)
4879 return(xmlStrdup(doc->URL));
4880 newbase = xmlBuildURI(oldbase, doc->URL);
4881 xmlFree(oldbase);
4882 return(newbase);
4883 }
4884 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004885}
4886
4887/**
Daniel Veillard78697292003-10-19 20:44:43 +00004888 * xmlNodeBufGetContent:
4889 * @buffer: a buffer
4890 * @cur: the node being read
4891 *
4892 * Read the value of a node @cur, this can be either the text carried
4893 * directly by this node if it's a TEXT node or the aggregate string
4894 * of the values carried by this node child's (TEXT and ENTITY_REF).
4895 * Entity references are substituted.
4896 * Fills up the buffer @buffer with this value
4897 *
4898 * Returns 0 in case of success and -1 in case of error.
4899 */
4900int
4901xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4902{
4903 if ((cur == NULL) || (buffer == NULL)) return(-1);
4904 switch (cur->type) {
4905 case XML_CDATA_SECTION_NODE:
4906 case XML_TEXT_NODE:
4907 xmlBufferCat(buffer, cur->content);
4908 break;
4909 case XML_DOCUMENT_FRAG_NODE:
4910 case XML_ELEMENT_NODE:{
4911 xmlNodePtr tmp = cur;
4912
4913 while (tmp != NULL) {
4914 switch (tmp->type) {
4915 case XML_CDATA_SECTION_NODE:
4916 case XML_TEXT_NODE:
4917 if (tmp->content != NULL)
4918 xmlBufferCat(buffer, tmp->content);
4919 break;
4920 case XML_ENTITY_REF_NODE:
Rob Richards77b92ff2005-12-20 15:55:14 +00004921 xmlNodeBufGetContent(buffer, tmp);
4922 break;
Daniel Veillard78697292003-10-19 20:44:43 +00004923 default:
4924 break;
4925 }
4926 /*
4927 * Skip to next node
4928 */
4929 if (tmp->children != NULL) {
4930 if (tmp->children->type != XML_ENTITY_DECL) {
4931 tmp = tmp->children;
4932 continue;
4933 }
4934 }
4935 if (tmp == cur)
4936 break;
4937
4938 if (tmp->next != NULL) {
4939 tmp = tmp->next;
4940 continue;
4941 }
4942
4943 do {
4944 tmp = tmp->parent;
4945 if (tmp == NULL)
4946 break;
4947 if (tmp == cur) {
4948 tmp = NULL;
4949 break;
4950 }
4951 if (tmp->next != NULL) {
4952 tmp = tmp->next;
4953 break;
4954 }
4955 } while (tmp != NULL);
4956 }
4957 break;
4958 }
4959 case XML_ATTRIBUTE_NODE:{
4960 xmlAttrPtr attr = (xmlAttrPtr) cur;
4961 xmlNodePtr tmp = attr->children;
4962
4963 while (tmp != NULL) {
4964 if (tmp->type == XML_TEXT_NODE)
4965 xmlBufferCat(buffer, tmp->content);
4966 else
4967 xmlNodeBufGetContent(buffer, tmp);
4968 tmp = tmp->next;
4969 }
4970 break;
4971 }
4972 case XML_COMMENT_NODE:
4973 case XML_PI_NODE:
4974 xmlBufferCat(buffer, cur->content);
4975 break;
4976 case XML_ENTITY_REF_NODE:{
4977 xmlEntityPtr ent;
4978 xmlNodePtr tmp;
4979
4980 /* lookup entity declaration */
4981 ent = xmlGetDocEntity(cur->doc, cur->name);
4982 if (ent == NULL)
4983 return(-1);
4984
4985 /* an entity content can be any "well balanced chunk",
4986 * i.e. the result of the content [43] production:
4987 * http://www.w3.org/TR/REC-xml#NT-content
4988 * -> we iterate through child nodes and recursive call
4989 * xmlNodeGetContent() which handles all possible node types */
4990 tmp = ent->children;
4991 while (tmp) {
4992 xmlNodeBufGetContent(buffer, tmp);
4993 tmp = tmp->next;
4994 }
4995 break;
4996 }
4997 case XML_ENTITY_NODE:
4998 case XML_DOCUMENT_TYPE_NODE:
4999 case XML_NOTATION_NODE:
5000 case XML_DTD_NODE:
5001 case XML_XINCLUDE_START:
5002 case XML_XINCLUDE_END:
5003 break;
5004 case XML_DOCUMENT_NODE:
5005#ifdef LIBXML_DOCB_ENABLED
5006 case XML_DOCB_DOCUMENT_NODE:
5007#endif
5008 case XML_HTML_DOCUMENT_NODE:
5009 cur = cur->children;
5010 while (cur!= NULL) {
5011 if ((cur->type == XML_ELEMENT_NODE) ||
5012 (cur->type == XML_TEXT_NODE) ||
5013 (cur->type == XML_CDATA_SECTION_NODE)) {
5014 xmlNodeBufGetContent(buffer, cur);
5015 }
5016 cur = cur->next;
5017 }
5018 break;
5019 case XML_NAMESPACE_DECL:
5020 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
5021 break;
5022 case XML_ELEMENT_DECL:
5023 case XML_ATTRIBUTE_DECL:
5024 case XML_ENTITY_DECL:
5025 break;
5026 }
5027 return(0);
5028}
5029/**
Owen Taylor3473f882001-02-23 17:55:21 +00005030 * xmlNodeGetContent:
5031 * @cur: the node being read
5032 *
5033 * Read the value of a node, this can be either the text carried
5034 * directly by this node if it's a TEXT node or the aggregate string
5035 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00005036 * Entity references are substituted.
5037 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005038 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005039 */
5040xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00005041xmlNodeGetContent(xmlNodePtr cur)
5042{
5043 if (cur == NULL)
5044 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005045 switch (cur->type) {
5046 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005047 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00005048 xmlBufferPtr buffer;
5049 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00005050
Daniel Veillard814a76d2003-01-23 18:24:20 +00005051 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00005052 if (buffer == NULL)
5053 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00005054 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005055 ret = buffer->content;
5056 buffer->content = NULL;
5057 xmlBufferFree(buffer);
5058 return (ret);
5059 }
5060 case XML_ATTRIBUTE_NODE:{
5061 xmlAttrPtr attr = (xmlAttrPtr) cur;
5062
5063 if (attr->parent != NULL)
5064 return (xmlNodeListGetString
5065 (attr->parent->doc, attr->children, 1));
5066 else
5067 return (xmlNodeListGetString(NULL, attr->children, 1));
5068 break;
5069 }
Owen Taylor3473f882001-02-23 17:55:21 +00005070 case XML_COMMENT_NODE:
5071 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005072 if (cur->content != NULL)
5073 return (xmlStrdup(cur->content));
5074 return (NULL);
5075 case XML_ENTITY_REF_NODE:{
5076 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00005077 xmlBufferPtr buffer;
5078 xmlChar *ret;
5079
5080 /* lookup entity declaration */
5081 ent = xmlGetDocEntity(cur->doc, cur->name);
5082 if (ent == NULL)
5083 return (NULL);
5084
5085 buffer = xmlBufferCreate();
5086 if (buffer == NULL)
5087 return (NULL);
5088
Daniel Veillardc4696922003-10-19 21:47:14 +00005089 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005090
5091 ret = buffer->content;
5092 buffer->content = NULL;
5093 xmlBufferFree(buffer);
5094 return (ret);
5095 }
Owen Taylor3473f882001-02-23 17:55:21 +00005096 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005097 case XML_DOCUMENT_TYPE_NODE:
5098 case XML_NOTATION_NODE:
5099 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005100 case XML_XINCLUDE_START:
5101 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00005102 return (NULL);
5103 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005104#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005105 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005106#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005107 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00005108 xmlBufferPtr buffer;
5109 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005110
Daniel Veillardc4696922003-10-19 21:47:14 +00005111 buffer = xmlBufferCreate();
5112 if (buffer == NULL)
5113 return (NULL);
5114
5115 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5116
5117 ret = buffer->content;
5118 buffer->content = NULL;
5119 xmlBufferFree(buffer);
5120 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005121 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005122 case XML_NAMESPACE_DECL: {
5123 xmlChar *tmp;
5124
5125 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5126 return (tmp);
5127 }
Owen Taylor3473f882001-02-23 17:55:21 +00005128 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005129 /* TODO !!! */
5130 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005131 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005132 /* TODO !!! */
5133 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005134 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005135 /* TODO !!! */
5136 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005137 case XML_CDATA_SECTION_NODE:
5138 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005139 if (cur->content != NULL)
5140 return (xmlStrdup(cur->content));
5141 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005142 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005143 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005144}
Daniel Veillard652327a2003-09-29 18:02:38 +00005145
Owen Taylor3473f882001-02-23 17:55:21 +00005146/**
5147 * xmlNodeSetContent:
5148 * @cur: the node being modified
5149 * @content: the new value of the content
5150 *
5151 * Replace the content of a node.
5152 */
5153void
5154xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5155 if (cur == NULL) {
5156#ifdef DEBUG_TREE
5157 xmlGenericError(xmlGenericErrorContext,
5158 "xmlNodeSetContent : node == NULL\n");
5159#endif
5160 return;
5161 }
5162 switch (cur->type) {
5163 case XML_DOCUMENT_FRAG_NODE:
5164 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005165 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005166 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5167 cur->children = xmlStringGetNodeList(cur->doc, content);
5168 UPDATE_LAST_CHILD_AND_PARENT(cur)
5169 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005170 case XML_TEXT_NODE:
5171 case XML_CDATA_SECTION_NODE:
5172 case XML_ENTITY_REF_NODE:
5173 case XML_ENTITY_NODE:
5174 case XML_PI_NODE:
5175 case XML_COMMENT_NODE:
Daniel Veillard8874b942005-08-25 13:19:21 +00005176 if ((cur->content != NULL) &&
5177 (cur->content != (xmlChar *) &(cur->properties))) {
William M. Brack7762bb12004-01-04 14:49:01 +00005178 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
Daniel Veillardc587bce2005-05-10 15:28:08 +00005179 (xmlDictOwns(cur->doc->dict, cur->content))))
William M. Brack7762bb12004-01-04 14:49:01 +00005180 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005181 }
5182 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5183 cur->last = cur->children = NULL;
5184 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005185 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005186 } else
5187 cur->content = NULL;
Daniel Veillard8874b942005-08-25 13:19:21 +00005188 cur->properties = NULL;
5189 cur->nsDef = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00005190 break;
5191 case XML_DOCUMENT_NODE:
5192 case XML_HTML_DOCUMENT_NODE:
5193 case XML_DOCUMENT_TYPE_NODE:
5194 case XML_XINCLUDE_START:
5195 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005196#ifdef LIBXML_DOCB_ENABLED
5197 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005198#endif
5199 break;
5200 case XML_NOTATION_NODE:
5201 break;
5202 case XML_DTD_NODE:
5203 break;
5204 case XML_NAMESPACE_DECL:
5205 break;
5206 case XML_ELEMENT_DECL:
5207 /* TODO !!! */
5208 break;
5209 case XML_ATTRIBUTE_DECL:
5210 /* TODO !!! */
5211 break;
5212 case XML_ENTITY_DECL:
5213 /* TODO !!! */
5214 break;
5215 }
5216}
5217
Daniel Veillard652327a2003-09-29 18:02:38 +00005218#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005219/**
5220 * xmlNodeSetContentLen:
5221 * @cur: the node being modified
5222 * @content: the new value of the content
5223 * @len: the size of @content
5224 *
5225 * Replace the content of a node.
5226 */
5227void
5228xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5229 if (cur == NULL) {
5230#ifdef DEBUG_TREE
5231 xmlGenericError(xmlGenericErrorContext,
5232 "xmlNodeSetContentLen : node == NULL\n");
5233#endif
5234 return;
5235 }
5236 switch (cur->type) {
5237 case XML_DOCUMENT_FRAG_NODE:
5238 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005239 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005240 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5241 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5242 UPDATE_LAST_CHILD_AND_PARENT(cur)
5243 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005244 case XML_TEXT_NODE:
5245 case XML_CDATA_SECTION_NODE:
5246 case XML_ENTITY_REF_NODE:
5247 case XML_ENTITY_NODE:
5248 case XML_PI_NODE:
5249 case XML_COMMENT_NODE:
5250 case XML_NOTATION_NODE:
Daniel Veillard8874b942005-08-25 13:19:21 +00005251 if ((cur->content != NULL) &&
5252 (cur->content != (xmlChar *) &(cur->properties))) {
5253 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5254 (xmlDictOwns(cur->doc->dict, cur->content))))
5255 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005256 }
5257 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5258 cur->children = cur->last = NULL;
5259 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005260 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005261 } else
5262 cur->content = NULL;
Daniel Veillard8874b942005-08-25 13:19:21 +00005263 cur->properties = NULL;
5264 cur->nsDef = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00005265 break;
5266 case XML_DOCUMENT_NODE:
5267 case XML_DTD_NODE:
5268 case XML_HTML_DOCUMENT_NODE:
5269 case XML_DOCUMENT_TYPE_NODE:
5270 case XML_NAMESPACE_DECL:
5271 case XML_XINCLUDE_START:
5272 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005273#ifdef LIBXML_DOCB_ENABLED
5274 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005275#endif
5276 break;
5277 case XML_ELEMENT_DECL:
5278 /* TODO !!! */
5279 break;
5280 case XML_ATTRIBUTE_DECL:
5281 /* TODO !!! */
5282 break;
5283 case XML_ENTITY_DECL:
5284 /* TODO !!! */
5285 break;
5286 }
5287}
Daniel Veillard652327a2003-09-29 18:02:38 +00005288#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005289
5290/**
5291 * xmlNodeAddContentLen:
5292 * @cur: the node being modified
5293 * @content: extra content
5294 * @len: the size of @content
5295 *
5296 * Append the extra substring to the node content.
5297 */
5298void
5299xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5300 if (cur == NULL) {
5301#ifdef DEBUG_TREE
5302 xmlGenericError(xmlGenericErrorContext,
5303 "xmlNodeAddContentLen : node == NULL\n");
5304#endif
5305 return;
5306 }
5307 if (len <= 0) return;
5308 switch (cur->type) {
5309 case XML_DOCUMENT_FRAG_NODE:
5310 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005311 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005312
Daniel Veillard7db37732001-07-12 01:20:08 +00005313 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005314 newNode = xmlNewTextLen(content, len);
5315 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005316 tmp = xmlAddChild(cur, newNode);
5317 if (tmp != newNode)
5318 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005319 if ((last != NULL) && (last->next == newNode)) {
5320 xmlTextMerge(last, newNode);
5321 }
5322 }
5323 break;
5324 }
5325 case XML_ATTRIBUTE_NODE:
5326 break;
5327 case XML_TEXT_NODE:
5328 case XML_CDATA_SECTION_NODE:
5329 case XML_ENTITY_REF_NODE:
5330 case XML_ENTITY_NODE:
5331 case XML_PI_NODE:
5332 case XML_COMMENT_NODE:
5333 case XML_NOTATION_NODE:
5334 if (content != NULL) {
Daniel Veillard8874b942005-08-25 13:19:21 +00005335 if ((cur->content == (xmlChar *) &(cur->properties)) ||
5336 ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5337 xmlDictOwns(cur->doc->dict, cur->content))) {
5338 cur->content = xmlStrncatNew(cur->content, content, len);
5339 cur->properties = NULL;
5340 cur->nsDef = NULL;
William M. Brack7762bb12004-01-04 14:49:01 +00005341 break;
5342 }
Owen Taylor3473f882001-02-23 17:55:21 +00005343 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005344 }
5345 case XML_DOCUMENT_NODE:
5346 case XML_DTD_NODE:
5347 case XML_HTML_DOCUMENT_NODE:
5348 case XML_DOCUMENT_TYPE_NODE:
5349 case XML_NAMESPACE_DECL:
5350 case XML_XINCLUDE_START:
5351 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005352#ifdef LIBXML_DOCB_ENABLED
5353 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005354#endif
5355 break;
5356 case XML_ELEMENT_DECL:
5357 case XML_ATTRIBUTE_DECL:
5358 case XML_ENTITY_DECL:
5359 break;
5360 }
5361}
5362
5363/**
5364 * xmlNodeAddContent:
5365 * @cur: the node being modified
5366 * @content: extra content
5367 *
5368 * Append the extra substring to the node content.
5369 */
5370void
5371xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5372 int len;
5373
5374 if (cur == NULL) {
5375#ifdef DEBUG_TREE
5376 xmlGenericError(xmlGenericErrorContext,
5377 "xmlNodeAddContent : node == NULL\n");
5378#endif
5379 return;
5380 }
5381 if (content == NULL) return;
5382 len = xmlStrlen(content);
5383 xmlNodeAddContentLen(cur, content, len);
5384}
5385
5386/**
5387 * xmlTextMerge:
5388 * @first: the first text node
5389 * @second: the second text node being merged
5390 *
5391 * Merge two text nodes into one
5392 * Returns the first text node augmented
5393 */
5394xmlNodePtr
5395xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5396 if (first == NULL) return(second);
5397 if (second == NULL) return(first);
5398 if (first->type != XML_TEXT_NODE) return(first);
5399 if (second->type != XML_TEXT_NODE) return(first);
5400 if (second->name != first->name)
5401 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005402 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005403 xmlUnlinkNode(second);
5404 xmlFreeNode(second);
5405 return(first);
5406}
5407
Daniel Veillard2156d432004-03-04 15:59:36 +00005408#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005409/**
5410 * xmlGetNsList:
5411 * @doc: the document
5412 * @node: the current node
5413 *
5414 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005415 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005416 * that need to be freed by the caller or NULL if no
5417 * namespace if defined
5418 */
5419xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005420xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5421{
Owen Taylor3473f882001-02-23 17:55:21 +00005422 xmlNsPtr cur;
5423 xmlNsPtr *ret = NULL;
5424 int nbns = 0;
5425 int maxns = 10;
5426 int i;
5427
5428 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005429 if (node->type == XML_ELEMENT_NODE) {
5430 cur = node->nsDef;
5431 while (cur != NULL) {
5432 if (ret == NULL) {
5433 ret =
5434 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5435 sizeof(xmlNsPtr));
5436 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005437 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005438 return (NULL);
5439 }
5440 ret[nbns] = NULL;
5441 }
5442 for (i = 0; i < nbns; i++) {
5443 if ((cur->prefix == ret[i]->prefix) ||
5444 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5445 break;
5446 }
5447 if (i >= nbns) {
5448 if (nbns >= maxns) {
5449 maxns *= 2;
5450 ret = (xmlNsPtr *) xmlRealloc(ret,
5451 (maxns +
5452 1) *
5453 sizeof(xmlNsPtr));
5454 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005455 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005456 return (NULL);
5457 }
5458 }
5459 ret[nbns++] = cur;
5460 ret[nbns] = NULL;
5461 }
Owen Taylor3473f882001-02-23 17:55:21 +00005462
Daniel Veillard77044732001-06-29 21:31:07 +00005463 cur = cur->next;
5464 }
5465 }
5466 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005467 }
Daniel Veillard77044732001-06-29 21:31:07 +00005468 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005469}
Daniel Veillard652327a2003-09-29 18:02:38 +00005470#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005471
5472/**
5473 * xmlSearchNs:
5474 * @doc: the document
5475 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005476 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005477 *
5478 * Search a Ns registered under a given name space for a document.
5479 * recurse on the parents until it finds the defined namespace
5480 * or return NULL otherwise.
5481 * @nameSpace can be NULL, this is a search for the default namespace.
5482 * We don't allow to cross entities boundaries. If you don't declare
5483 * the namespace within those you will be in troubles !!! A warning
5484 * is generated to cover this case.
5485 *
5486 * Returns the namespace pointer or NULL.
5487 */
5488xmlNsPtr
5489xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005490
Owen Taylor3473f882001-02-23 17:55:21 +00005491 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005492 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005493
5494 if (node == NULL) return(NULL);
5495 if ((nameSpace != NULL) &&
5496 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005497 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5498 /*
5499 * The XML-1.0 namespace is normally held on the root
5500 * element. In this case exceptionally create it on the
5501 * node element.
5502 */
5503 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5504 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005505 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005506 return(NULL);
5507 }
5508 memset(cur, 0, sizeof(xmlNs));
5509 cur->type = XML_LOCAL_NAMESPACE;
5510 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5511 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5512 cur->next = node->nsDef;
5513 node->nsDef = cur;
5514 return(cur);
5515 }
Owen Taylor3473f882001-02-23 17:55:21 +00005516 if (doc->oldNs == NULL) {
5517 /*
5518 * Allocate a new Namespace and fill the fields.
5519 */
5520 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5521 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005522 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005523 return(NULL);
5524 }
5525 memset(doc->oldNs, 0, sizeof(xmlNs));
5526 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5527
5528 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5529 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5530 }
5531 return(doc->oldNs);
5532 }
5533 while (node != NULL) {
5534 if ((node->type == XML_ENTITY_REF_NODE) ||
5535 (node->type == XML_ENTITY_NODE) ||
5536 (node->type == XML_ENTITY_DECL))
5537 return(NULL);
5538 if (node->type == XML_ELEMENT_NODE) {
5539 cur = node->nsDef;
5540 while (cur != NULL) {
5541 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5542 (cur->href != NULL))
5543 return(cur);
5544 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5545 (cur->href != NULL) &&
5546 (xmlStrEqual(cur->prefix, nameSpace)))
5547 return(cur);
5548 cur = cur->next;
5549 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005550 if (orig != node) {
5551 cur = node->ns;
5552 if (cur != NULL) {
5553 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5554 (cur->href != NULL))
5555 return(cur);
5556 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5557 (cur->href != NULL) &&
5558 (xmlStrEqual(cur->prefix, nameSpace)))
5559 return(cur);
5560 }
5561 }
Owen Taylor3473f882001-02-23 17:55:21 +00005562 }
5563 node = node->parent;
5564 }
5565 return(NULL);
5566}
5567
5568/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005569 * xmlNsInScope:
5570 * @doc: the document
5571 * @node: the current node
5572 * @ancestor: the ancestor carrying the namespace
5573 * @prefix: the namespace prefix
5574 *
5575 * Verify that the given namespace held on @ancestor is still in scope
5576 * on node.
5577 *
5578 * Returns 1 if true, 0 if false and -1 in case of error.
5579 */
5580static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005581xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5582 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005583{
5584 xmlNsPtr tst;
5585
5586 while ((node != NULL) && (node != ancestor)) {
5587 if ((node->type == XML_ENTITY_REF_NODE) ||
5588 (node->type == XML_ENTITY_NODE) ||
5589 (node->type == XML_ENTITY_DECL))
5590 return (-1);
5591 if (node->type == XML_ELEMENT_NODE) {
5592 tst = node->nsDef;
5593 while (tst != NULL) {
5594 if ((tst->prefix == NULL)
5595 && (prefix == NULL))
5596 return (0);
5597 if ((tst->prefix != NULL)
5598 && (prefix != NULL)
5599 && (xmlStrEqual(tst->prefix, prefix)))
5600 return (0);
5601 tst = tst->next;
5602 }
5603 }
5604 node = node->parent;
5605 }
5606 if (node != ancestor)
5607 return (-1);
5608 return (1);
5609}
5610
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005611/**
Owen Taylor3473f882001-02-23 17:55:21 +00005612 * xmlSearchNsByHref:
5613 * @doc: the document
5614 * @node: the current node
5615 * @href: the namespace value
5616 *
5617 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5618 * the defined namespace or return NULL otherwise.
5619 * Returns the namespace pointer or NULL.
5620 */
5621xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005622xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5623{
Owen Taylor3473f882001-02-23 17:55:21 +00005624 xmlNsPtr cur;
5625 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005626 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005627
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005628 if ((node == NULL) || (href == NULL))
5629 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005630 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005631 /*
5632 * Only the document can hold the XML spec namespace.
5633 */
5634 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5635 /*
5636 * The XML-1.0 namespace is normally held on the root
5637 * element. In this case exceptionally create it on the
5638 * node element.
5639 */
5640 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5641 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005642 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005643 return (NULL);
5644 }
5645 memset(cur, 0, sizeof(xmlNs));
5646 cur->type = XML_LOCAL_NAMESPACE;
5647 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5648 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5649 cur->next = node->nsDef;
5650 node->nsDef = cur;
5651 return (cur);
5652 }
5653 if (doc->oldNs == NULL) {
5654 /*
5655 * Allocate a new Namespace and fill the fields.
5656 */
5657 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5658 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005659 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005660 return (NULL);
5661 }
5662 memset(doc->oldNs, 0, sizeof(xmlNs));
5663 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005664
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005665 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5666 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5667 }
5668 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005669 }
Daniel Veillard62040be2004-05-17 03:17:26 +00005670 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00005671 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005672 if ((node->type == XML_ENTITY_REF_NODE) ||
5673 (node->type == XML_ENTITY_NODE) ||
5674 (node->type == XML_ENTITY_DECL))
5675 return (NULL);
5676 if (node->type == XML_ELEMENT_NODE) {
5677 cur = node->nsDef;
5678 while (cur != NULL) {
5679 if ((cur->href != NULL) && (href != NULL) &&
5680 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005681 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00005682 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005683 return (cur);
5684 }
5685 cur = cur->next;
5686 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005687 if (orig != node) {
5688 cur = node->ns;
5689 if (cur != NULL) {
5690 if ((cur->href != NULL) && (href != NULL) &&
5691 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005692 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00005693 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00005694 return (cur);
5695 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005696 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005697 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005698 }
5699 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005700 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005701 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005702}
5703
5704/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005705 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005706 * @doc: the document
5707 * @tree: a node expected to hold the new namespace
5708 * @ns: the original namespace
5709 *
5710 * This function tries to locate a namespace definition in a tree
5711 * ancestors, or create a new namespace definition node similar to
5712 * @ns trying to reuse the same prefix. However if the given prefix is
5713 * null (default namespace) or reused within the subtree defined by
5714 * @tree or on one of its ancestors then a new prefix is generated.
5715 * Returns the (new) namespace definition or NULL in case of error
5716 */
5717xmlNsPtr
5718xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5719 xmlNsPtr def;
5720 xmlChar prefix[50];
5721 int counter = 1;
5722
5723 if (tree == NULL) {
5724#ifdef DEBUG_TREE
5725 xmlGenericError(xmlGenericErrorContext,
5726 "xmlNewReconciliedNs : tree == NULL\n");
5727#endif
5728 return(NULL);
5729 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00005730 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005731#ifdef DEBUG_TREE
5732 xmlGenericError(xmlGenericErrorContext,
5733 "xmlNewReconciliedNs : ns == NULL\n");
5734#endif
5735 return(NULL);
5736 }
5737 /*
5738 * Search an existing namespace definition inherited.
5739 */
5740 def = xmlSearchNsByHref(doc, tree, ns->href);
5741 if (def != NULL)
5742 return(def);
5743
5744 /*
5745 * Find a close prefix which is not already in use.
5746 * Let's strip namespace prefixes longer than 20 chars !
5747 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005748 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005749 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005750 else
William M. Brack13dfa872004-09-18 04:52:08 +00005751 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005752
Owen Taylor3473f882001-02-23 17:55:21 +00005753 def = xmlSearchNs(doc, tree, prefix);
5754 while (def != NULL) {
5755 if (counter > 1000) return(NULL);
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%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005758 else
William M. Brack13dfa872004-09-18 04:52:08 +00005759 snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
5760 (char *)ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005761 def = xmlSearchNs(doc, tree, prefix);
5762 }
5763
5764 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005765 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005766 */
5767 def = xmlNewNs(tree, ns->href, prefix);
5768 return(def);
5769}
5770
Daniel Veillard652327a2003-09-29 18:02:38 +00005771#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005772/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005773 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005774 * @doc: the document
5775 * @tree: a node defining the subtree to reconciliate
5776 *
5777 * This function checks that all the namespaces declared within the given
5778 * tree are properly declared. This is needed for example after Copy or Cut
5779 * and then paste operations. The subtree may still hold pointers to
5780 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005781 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005782 * the new environment. If not possible the new namespaces are redeclared
5783 * on @tree at the top of the given subtree.
5784 * Returns the number of namespace declarations created or -1 in case of error.
5785 */
5786int
5787xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5788 xmlNsPtr *oldNs = NULL;
5789 xmlNsPtr *newNs = NULL;
5790 int sizeCache = 0;
5791 int nbCache = 0;
5792
5793 xmlNsPtr n;
5794 xmlNodePtr node = tree;
5795 xmlAttrPtr attr;
5796 int ret = 0, i;
5797
Daniel Veillardce244ad2004-11-05 10:03:46 +00005798 if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1);
5799 if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1);
5800 if (node->doc != doc) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005801 while (node != NULL) {
5802 /*
5803 * Reconciliate the node namespace
5804 */
5805 if (node->ns != NULL) {
5806 /*
5807 * initialize the cache if needed
5808 */
5809 if (sizeCache == 0) {
5810 sizeCache = 10;
5811 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5812 sizeof(xmlNsPtr));
5813 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005814 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005815 return(-1);
5816 }
5817 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5818 sizeof(xmlNsPtr));
5819 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005820 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005821 xmlFree(oldNs);
5822 return(-1);
5823 }
5824 }
5825 for (i = 0;i < nbCache;i++) {
5826 if (oldNs[i] == node->ns) {
5827 node->ns = newNs[i];
5828 break;
5829 }
5830 }
5831 if (i == nbCache) {
5832 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005833 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005834 */
5835 n = xmlNewReconciliedNs(doc, tree, node->ns);
5836 if (n != NULL) { /* :-( what if else ??? */
5837 /*
5838 * check if we need to grow the cache buffers.
5839 */
5840 if (sizeCache <= nbCache) {
5841 sizeCache *= 2;
5842 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5843 sizeof(xmlNsPtr));
5844 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005845 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005846 xmlFree(newNs);
5847 return(-1);
5848 }
5849 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5850 sizeof(xmlNsPtr));
5851 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005852 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005853 xmlFree(oldNs);
5854 return(-1);
5855 }
5856 }
5857 newNs[nbCache] = n;
5858 oldNs[nbCache++] = node->ns;
5859 node->ns = n;
5860 }
5861 }
5862 }
5863 /*
5864 * now check for namespace hold by attributes on the node.
5865 */
5866 attr = node->properties;
5867 while (attr != NULL) {
5868 if (attr->ns != NULL) {
5869 /*
5870 * initialize the cache if needed
5871 */
5872 if (sizeCache == 0) {
5873 sizeCache = 10;
5874 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5875 sizeof(xmlNsPtr));
5876 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005877 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005878 return(-1);
5879 }
5880 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5881 sizeof(xmlNsPtr));
5882 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005883 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005884 xmlFree(oldNs);
5885 return(-1);
5886 }
5887 }
5888 for (i = 0;i < nbCache;i++) {
5889 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005890 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005891 break;
5892 }
5893 }
5894 if (i == nbCache) {
5895 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005896 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005897 */
5898 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5899 if (n != NULL) { /* :-( what if else ??? */
5900 /*
5901 * check if we need to grow the cache buffers.
5902 */
5903 if (sizeCache <= nbCache) {
5904 sizeCache *= 2;
5905 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5906 sizeof(xmlNsPtr));
5907 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005908 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005909 xmlFree(newNs);
5910 return(-1);
5911 }
5912 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5913 sizeof(xmlNsPtr));
5914 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005915 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005916 xmlFree(oldNs);
5917 return(-1);
5918 }
5919 }
5920 newNs[nbCache] = n;
5921 oldNs[nbCache++] = attr->ns;
5922 attr->ns = n;
5923 }
5924 }
5925 }
5926 attr = attr->next;
5927 }
5928
5929 /*
5930 * Browse the full subtree, deep first
5931 */
Daniel Veillardac996a12004-07-30 12:02:58 +00005932 if (node->children != NULL && node->type != XML_ENTITY_REF_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00005933 /* deep first */
5934 node = node->children;
5935 } else if ((node != tree) && (node->next != NULL)) {
5936 /* then siblings */
5937 node = node->next;
5938 } else if (node != tree) {
5939 /* go up to parents->next if needed */
5940 while (node != tree) {
5941 if (node->parent != NULL)
5942 node = node->parent;
5943 if ((node != tree) && (node->next != NULL)) {
5944 node = node->next;
5945 break;
5946 }
5947 if (node->parent == NULL) {
5948 node = NULL;
5949 break;
5950 }
5951 }
5952 /* exit condition */
5953 if (node == tree)
5954 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005955 } else
5956 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005957 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005958 if (oldNs != NULL)
5959 xmlFree(oldNs);
5960 if (newNs != NULL)
5961 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005962 return(ret);
5963}
Daniel Veillard652327a2003-09-29 18:02:38 +00005964#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005965
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00005966static xmlAttrPtr
5967xmlGetPropNodeInternal(xmlNodePtr node, const xmlChar *name,
5968 const xmlChar *nsName, int useDTD)
5969{
5970 xmlAttrPtr prop;
5971
5972 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
5973 return(NULL);
5974
5975 if (node->properties != NULL) {
5976 prop = node->properties;
5977 if (nsName == NULL) {
5978 /*
5979 * We want the attr to be in no namespace.
5980 */
5981 do {
5982 if ((prop->ns == NULL) && xmlStrEqual(prop->name, name)) {
5983 return(prop);
5984 }
5985 prop = prop->next;
5986 } while (prop != NULL);
5987 } else {
5988 /*
5989 * We want the attr to be in the specified namespace.
5990 */
5991 do {
5992 if ((prop->ns != NULL) && xmlStrEqual(prop->name, name) &&
5993 ((prop->ns->href == nsName) ||
5994 xmlStrEqual(prop->ns->href, nsName)))
5995 {
5996 return(prop);
5997 }
5998 prop = prop->next;
5999 } while (prop != NULL);
6000 }
6001 }
6002
6003#ifdef LIBXML_TREE_ENABLED
6004 if (! useDTD)
6005 return(NULL);
6006 /*
6007 * Check if there is a default/fixed attribute declaration in
6008 * the internal or external subset.
6009 */
6010 if ((node->doc != NULL) && (node->doc->intSubset != NULL)) {
6011 xmlDocPtr doc = node->doc;
6012 xmlAttributePtr attrDecl = NULL;
6013 xmlChar *elemQName, *tmpstr = NULL;
6014
6015 /*
6016 * We need the QName of the element for the DTD-lookup.
6017 */
6018 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
6019 tmpstr = xmlStrdup(node->ns->prefix);
6020 tmpstr = xmlStrcat(tmpstr, BAD_CAST ":");
6021 tmpstr = xmlStrcat(tmpstr, node->name);
6022 if (tmpstr == NULL)
6023 return(NULL);
6024 elemQName = tmpstr;
6025 } else
6026 elemQName = (xmlChar *) node->name;
6027 if (nsName == NULL) {
6028 /*
6029 * The common and nice case: Attr in no namespace.
6030 */
6031 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset,
6032 elemQName, name, NULL);
6033 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
6034 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset,
6035 elemQName, name, NULL);
6036 }
6037 } else {
6038 xmlNsPtr *nsList, *cur;
6039
6040 /*
6041 * The ugly case: Search using the prefixes of in-scope
6042 * ns-decls corresponding to @nsName.
6043 */
6044 nsList = xmlGetNsList(node->doc, node);
6045 if (nsList == NULL) {
6046 if (tmpstr != NULL)
6047 xmlFree(tmpstr);
6048 return(NULL);
6049 }
6050 cur = nsList;
6051 while (*cur != NULL) {
6052 if (xmlStrEqual((*cur)->href, nsName)) {
6053 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elemQName,
6054 name, (*cur)->prefix);
6055 if (attrDecl)
6056 break;
6057 if (doc->extSubset != NULL) {
6058 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elemQName,
6059 name, (*cur)->prefix);
6060 if (attrDecl)
6061 break;
6062 }
6063 }
6064 cur++;
6065 }
6066 xmlFree(nsList);
6067 }
6068 if (tmpstr != NULL)
6069 xmlFree(tmpstr);
6070 /*
6071 * Only default/fixed attrs are relevant.
6072 */
6073 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6074 return((xmlAttrPtr) attrDecl);
6075 }
6076#endif /* LIBXML_TREE_ENABLED */
6077 return(NULL);
6078}
6079
6080static xmlChar*
6081xmlGetPropNodeValueInternal(xmlAttrPtr prop)
6082{
6083 if (prop == NULL)
6084 return(NULL);
6085 if (prop->type == XML_ATTRIBUTE_NODE) {
6086 /*
6087 * Note that we return at least the empty string.
6088 * TODO: Do we really always want that?
6089 */
6090 if (prop->children != NULL) {
6091 if ((prop->children == prop->last) &&
6092 ((prop->children->type == XML_TEXT_NODE) ||
6093 (prop->children->type == XML_CDATA_SECTION_NODE)))
6094 {
6095 /*
6096 * Optimization for the common case: only 1 text node.
6097 */
6098 return(xmlStrdup(prop->children->content));
6099 } else {
6100 xmlChar *ret;
6101
6102 ret = xmlNodeListGetString(prop->doc, prop->children, 1);
6103 if (ret != NULL)
6104 return(ret);
6105 }
6106 }
6107 return(xmlStrdup((xmlChar *)""));
6108 } else if (prop->type == XML_ATTRIBUTE_DECL) {
6109 return(xmlStrdup(((xmlAttributePtr)prop)->defaultValue));
6110 }
6111 return(NULL);
6112}
6113
Owen Taylor3473f882001-02-23 17:55:21 +00006114/**
6115 * xmlHasProp:
6116 * @node: the node
6117 * @name: the attribute name
6118 *
6119 * Search an attribute associated to a node
6120 * This function also looks in DTD attribute declaration for #FIXED or
6121 * default declaration values unless DTD use has been turned off.
6122 *
6123 * Returns the attribute or the attribute declaration or NULL if
6124 * neither was found.
6125 */
6126xmlAttrPtr
6127xmlHasProp(xmlNodePtr node, const xmlChar *name) {
6128 xmlAttrPtr prop;
6129 xmlDocPtr doc;
6130
Daniel Veillard8874b942005-08-25 13:19:21 +00006131 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6132 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006133 /*
6134 * Check on the properties attached to the node
6135 */
6136 prop = node->properties;
6137 while (prop != NULL) {
6138 if (xmlStrEqual(prop->name, name)) {
6139 return(prop);
6140 }
6141 prop = prop->next;
6142 }
6143 if (!xmlCheckDTD) return(NULL);
6144
6145 /*
6146 * Check if there is a default declaration in the internal
6147 * or external subsets
6148 */
6149 doc = node->doc;
6150 if (doc != NULL) {
6151 xmlAttributePtr attrDecl;
6152 if (doc->intSubset != NULL) {
6153 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6154 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6155 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006156 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6157 /* return attribute declaration only if a default value is given
6158 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006159 return((xmlAttrPtr) attrDecl);
6160 }
6161 }
6162 return(NULL);
6163}
6164
6165/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00006166 * xmlHasNsProp:
6167 * @node: the node
6168 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006169 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00006170 *
6171 * Search for an attribute associated to a node
6172 * This attribute has to be anchored in the namespace specified.
6173 * This does the entity substitution.
6174 * This function looks in DTD attribute declaration for #FIXED or
6175 * default declaration values unless DTD use has been turned off.
William M. Brack2c228442004-10-03 04:10:00 +00006176 * Note that a namespace of NULL indicates to use the default namespace.
Daniel Veillarde95e2392001-06-06 10:46:28 +00006177 *
6178 * Returns the attribute or the attribute declaration or NULL
6179 * if neither was found.
6180 */
6181xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00006182xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00006183
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006184 return(xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD));
Daniel Veillarde95e2392001-06-06 10:46:28 +00006185}
6186
6187/**
Owen Taylor3473f882001-02-23 17:55:21 +00006188 * xmlGetProp:
6189 * @node: the node
6190 * @name: the attribute name
6191 *
6192 * Search and get the value of an attribute associated to a node
6193 * This does the entity substitution.
6194 * This function looks in DTD attribute declaration for #FIXED or
6195 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00006196 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00006197 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6198 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00006199 *
6200 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006201 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006202 */
6203xmlChar *
6204xmlGetProp(xmlNodePtr node, const xmlChar *name) {
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006205 xmlAttrPtr prop;
Owen Taylor3473f882001-02-23 17:55:21 +00006206
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006207 prop = xmlHasProp(node, name);
6208 if (prop == NULL)
6209 return(NULL);
6210 return(xmlGetPropNodeValueInternal(prop));
Owen Taylor3473f882001-02-23 17:55:21 +00006211}
6212
6213/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006214 * xmlGetNoNsProp:
6215 * @node: the node
6216 * @name: the attribute name
6217 *
6218 * Search and get the value of an attribute associated to a node
6219 * This does the entity substitution.
6220 * This function looks in DTD attribute declaration for #FIXED or
6221 * default declaration values unless DTD use has been turned off.
6222 * This function is similar to xmlGetProp except it will accept only
6223 * an attribute in no namespace.
6224 *
6225 * Returns the attribute value or NULL if not found.
6226 * It's up to the caller to free the memory with xmlFree().
6227 */
6228xmlChar *
6229xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6230 xmlAttrPtr prop;
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006231
6232 prop = xmlGetPropNodeInternal(node, name, NULL, xmlCheckDTD);
6233 if (prop == NULL)
Daniel Veillard8874b942005-08-25 13:19:21 +00006234 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006235 return(xmlGetPropNodeValueInternal(prop));
Daniel Veillard71531f32003-02-05 13:19:53 +00006236}
6237
6238/**
Owen Taylor3473f882001-02-23 17:55:21 +00006239 * xmlGetNsProp:
6240 * @node: the node
6241 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006242 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006243 *
6244 * Search and get the value of an attribute associated to a node
6245 * This attribute has to be anchored in the namespace specified.
6246 * This does the entity substitution.
6247 * This function looks in DTD attribute declaration for #FIXED or
6248 * default declaration values unless DTD use has been turned off.
6249 *
6250 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006251 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006252 */
6253xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006254xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006255 xmlAttrPtr prop;
Owen Taylor3473f882001-02-23 17:55:21 +00006256
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006257 prop = xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD);
6258 if (prop == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006259 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006260 return(xmlGetPropNodeValueInternal(prop));
Owen Taylor3473f882001-02-23 17:55:21 +00006261}
6262
Daniel Veillard2156d432004-03-04 15:59:36 +00006263#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6264/**
6265 * xmlUnsetProp:
6266 * @node: the node
6267 * @name: the attribute name
6268 *
6269 * Remove an attribute carried by a node.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006270 * This handles only attributes in no namespace.
Daniel Veillard2156d432004-03-04 15:59:36 +00006271 * Returns 0 if successful, -1 if not found
6272 */
6273int
6274xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Kasimier T. Buchcik65c2f1d2005-10-17 12:39:58 +00006275 xmlAttrPtr prop;
Daniel Veillard2156d432004-03-04 15:59:36 +00006276
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006277 prop = xmlGetPropNodeInternal(node, name, NULL, 0);
6278 if (prop == NULL)
Daniel Veillard2156d432004-03-04 15:59:36 +00006279 return(-1);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006280 xmlUnlinkNode((xmlNodePtr) prop);
6281 xmlFreeProp(prop);
6282 return(0);
Daniel Veillard2156d432004-03-04 15:59:36 +00006283}
6284
6285/**
6286 * xmlUnsetNsProp:
6287 * @node: the node
6288 * @ns: the namespace definition
6289 * @name: the attribute name
6290 *
6291 * Remove an attribute carried by a node.
6292 * Returns 0 if successful, -1 if not found
6293 */
6294int
6295xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
Kasimier T. Buchcik65c2f1d2005-10-17 12:39:58 +00006296 xmlAttrPtr prop;
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006297
6298 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
6299 if (prop == NULL)
Daniel Veillard2156d432004-03-04 15:59:36 +00006300 return(-1);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006301 xmlUnlinkNode((xmlNodePtr) prop);
6302 xmlFreeProp(prop);
6303 return(0);
Daniel Veillard2156d432004-03-04 15:59:36 +00006304}
6305#endif
6306
6307#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006308/**
6309 * xmlSetProp:
6310 * @node: the node
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006311 * @name: the attribute name (a QName)
Owen Taylor3473f882001-02-23 17:55:21 +00006312 * @value: the attribute value
6313 *
6314 * Set (or reset) an attribute carried by a node.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006315 * If @name has a prefix, then the corresponding
6316 * namespace-binding will be used, if in scope; it is an
6317 * error it there's no such ns-binding for the prefix in
6318 * scope.
Owen Taylor3473f882001-02-23 17:55:21 +00006319 * Returns the attribute pointer.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006320 *
Owen Taylor3473f882001-02-23 17:55:21 +00006321 */
6322xmlAttrPtr
6323xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006324 int len;
6325 const xmlChar *nqname;
Owen Taylor3473f882001-02-23 17:55:21 +00006326
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006327 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006328 return(NULL);
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006329
6330 /*
6331 * handle QNames
6332 */
6333 nqname = xmlSplitQName3(name, &len);
6334 if (nqname != NULL) {
6335 xmlNsPtr ns;
6336 xmlChar *prefix = xmlStrndup(name, len);
6337 ns = xmlSearchNs(node->doc, node, prefix);
6338 if (prefix != NULL)
6339 xmlFree(prefix);
6340 if (ns != NULL)
6341 return(xmlSetNsProp(node, ns, nqname, value));
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006342 /*
6343 * If we get a QName and the prefix has no namespace-
6344 * binding in scope, then this is an error.
6345 * TODO: Previously this falled-back to non-ns handling.
6346 * Should we revert this?
6347 */
6348 return(NULL);
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006349 }
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006350 return(xmlSetNsProp(node, NULL, name, value));
Owen Taylor3473f882001-02-23 17:55:21 +00006351}
6352
6353/**
6354 * xmlSetNsProp:
6355 * @node: the node
6356 * @ns: the namespace definition
6357 * @name: the attribute name
6358 * @value: the attribute value
6359 *
6360 * Set (or reset) an attribute carried by a node.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006361 * The ns structure must be in scope, this is not checked
Owen Taylor3473f882001-02-23 17:55:21 +00006362 *
6363 * Returns the attribute pointer.
6364 */
6365xmlAttrPtr
6366xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006367 const xmlChar *value)
6368{
Owen Taylor3473f882001-02-23 17:55:21 +00006369 xmlAttrPtr prop;
6370
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006371 if (ns && (ns->href == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006372 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006373 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
6374 if (prop != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006375 /*
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006376 * Modify the attribute's value.
6377 */
6378 if (prop->atype == XML_ATTRIBUTE_ID) {
6379 xmlRemoveID(node->doc, prop);
6380 prop->atype = XML_ATTRIBUTE_ID;
6381 }
6382 if (prop->children != NULL)
6383 xmlFreeNodeList(prop->children);
6384 prop->children = NULL;
6385 prop->last = NULL;
6386 prop->ns = ns;
6387 if (value != NULL) {
6388 xmlChar *buffer;
6389 xmlNodePtr tmp;
6390
6391 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6392 prop->children = xmlStringGetNodeList(node->doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00006393 prop->last = NULL;
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006394 tmp = prop->children;
6395 while (tmp != NULL) {
6396 tmp->parent = (xmlNodePtr) prop;
6397 if (tmp->next == NULL)
6398 prop->last = tmp;
6399 tmp = tmp->next;
6400 }
6401 xmlFree(buffer);
6402 }
6403 if (prop->atype == XML_ATTRIBUTE_ID)
6404 xmlAddID(NULL, node->doc, value, prop);
6405 return(prop);
Owen Taylor3473f882001-02-23 17:55:21 +00006406 }
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006407 /*
6408 * No equal attr found; create a new one.
6409 */
6410 return(xmlNewPropInternal(node, ns, name, value, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006411}
6412
Daniel Veillard652327a2003-09-29 18:02:38 +00006413#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006414
6415/**
Owen Taylor3473f882001-02-23 17:55:21 +00006416 * xmlNodeIsText:
6417 * @node: the node
6418 *
6419 * Is this node a Text node ?
6420 * Returns 1 yes, 0 no
6421 */
6422int
6423xmlNodeIsText(xmlNodePtr node) {
6424 if (node == NULL) return(0);
6425
6426 if (node->type == XML_TEXT_NODE) return(1);
6427 return(0);
6428}
6429
6430/**
6431 * xmlIsBlankNode:
6432 * @node: the node
6433 *
6434 * Checks whether this node is an empty or whitespace only
6435 * (and possibly ignorable) text-node.
6436 *
6437 * Returns 1 yes, 0 no
6438 */
6439int
6440xmlIsBlankNode(xmlNodePtr node) {
6441 const xmlChar *cur;
6442 if (node == NULL) return(0);
6443
Daniel Veillard7db37732001-07-12 01:20:08 +00006444 if ((node->type != XML_TEXT_NODE) &&
6445 (node->type != XML_CDATA_SECTION_NODE))
6446 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006447 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006448 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006449 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006450 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006451 cur++;
6452 }
6453
6454 return(1);
6455}
6456
6457/**
6458 * xmlTextConcat:
6459 * @node: the node
6460 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006461 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006462 *
6463 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006464 *
6465 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006466 */
6467
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006468int
Owen Taylor3473f882001-02-23 17:55:21 +00006469xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006470 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006471
6472 if ((node->type != XML_TEXT_NODE) &&
6473 (node->type != XML_CDATA_SECTION_NODE)) {
6474#ifdef DEBUG_TREE
6475 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006476 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006477#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006478 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006479 }
William M. Brack7762bb12004-01-04 14:49:01 +00006480 /* need to check if content is currently in the dictionary */
Daniel Veillard8874b942005-08-25 13:19:21 +00006481 if ((node->content == (xmlChar *) &(node->properties)) ||
6482 ((node->doc != NULL) && (node->doc->dict != NULL) &&
6483 xmlDictOwns(node->doc->dict, node->content))) {
William M. Brack7762bb12004-01-04 14:49:01 +00006484 node->content = xmlStrncatNew(node->content, content, len);
6485 } else {
6486 node->content = xmlStrncat(node->content, content, len);
6487 }
Daniel Veillard8874b942005-08-25 13:19:21 +00006488 node->properties = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006489 if (node->content == NULL)
6490 return(-1);
6491 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006492}
6493
6494/************************************************************************
6495 * *
6496 * Output : to a FILE or in memory *
6497 * *
6498 ************************************************************************/
6499
Owen Taylor3473f882001-02-23 17:55:21 +00006500/**
6501 * xmlBufferCreate:
6502 *
6503 * routine to create an XML buffer.
6504 * returns the new structure.
6505 */
6506xmlBufferPtr
6507xmlBufferCreate(void) {
6508 xmlBufferPtr ret;
6509
6510 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6511 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006512 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006513 return(NULL);
6514 }
6515 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006516 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006517 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006518 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006519 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006520 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006521 xmlFree(ret);
6522 return(NULL);
6523 }
6524 ret->content[0] = 0;
6525 return(ret);
6526}
6527
6528/**
6529 * xmlBufferCreateSize:
6530 * @size: initial size of buffer
6531 *
6532 * routine to create an XML buffer.
6533 * returns the new structure.
6534 */
6535xmlBufferPtr
6536xmlBufferCreateSize(size_t size) {
6537 xmlBufferPtr ret;
6538
6539 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6540 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006541 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006542 return(NULL);
6543 }
6544 ret->use = 0;
6545 ret->alloc = xmlBufferAllocScheme;
6546 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6547 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006548 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006549 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006550 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006551 xmlFree(ret);
6552 return(NULL);
6553 }
6554 ret->content[0] = 0;
6555 } else
6556 ret->content = NULL;
6557 return(ret);
6558}
6559
6560/**
Daniel Veillard53350552003-09-18 13:35:51 +00006561 * xmlBufferCreateStatic:
6562 * @mem: the memory area
6563 * @size: the size in byte
6564 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006565 * routine to create an XML buffer from an immutable memory area.
6566 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006567 * present until the end of the buffer lifetime.
6568 *
6569 * returns the new structure.
6570 */
6571xmlBufferPtr
6572xmlBufferCreateStatic(void *mem, size_t size) {
6573 xmlBufferPtr ret;
6574
6575 if ((mem == NULL) || (size == 0))
6576 return(NULL);
6577
6578 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6579 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006580 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006581 return(NULL);
6582 }
6583 ret->use = size;
6584 ret->size = size;
6585 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6586 ret->content = (xmlChar *) mem;
6587 return(ret);
6588}
6589
6590/**
Owen Taylor3473f882001-02-23 17:55:21 +00006591 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006592 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006593 * @scheme: allocation scheme to use
6594 *
6595 * Sets the allocation scheme for this buffer
6596 */
6597void
6598xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6599 xmlBufferAllocationScheme scheme) {
6600 if (buf == NULL) {
6601#ifdef DEBUG_BUFFER
6602 xmlGenericError(xmlGenericErrorContext,
6603 "xmlBufferSetAllocationScheme: buf == NULL\n");
6604#endif
6605 return;
6606 }
Daniel Veillard53350552003-09-18 13:35:51 +00006607 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006608
6609 buf->alloc = scheme;
6610}
6611
6612/**
6613 * xmlBufferFree:
6614 * @buf: the buffer to free
6615 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006616 * Frees an XML buffer. It frees both the content and the structure which
6617 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006618 */
6619void
6620xmlBufferFree(xmlBufferPtr buf) {
6621 if (buf == NULL) {
6622#ifdef DEBUG_BUFFER
6623 xmlGenericError(xmlGenericErrorContext,
6624 "xmlBufferFree: buf == NULL\n");
6625#endif
6626 return;
6627 }
Daniel Veillard53350552003-09-18 13:35:51 +00006628
6629 if ((buf->content != NULL) &&
6630 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006631 xmlFree(buf->content);
6632 }
Owen Taylor3473f882001-02-23 17:55:21 +00006633 xmlFree(buf);
6634}
6635
6636/**
6637 * xmlBufferEmpty:
6638 * @buf: the buffer
6639 *
6640 * empty a buffer.
6641 */
6642void
6643xmlBufferEmpty(xmlBufferPtr buf) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006644 if (buf == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006645 if (buf->content == NULL) return;
6646 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006647 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006648 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006649 } else {
6650 memset(buf->content, 0, buf->size);
6651 }
Owen Taylor3473f882001-02-23 17:55:21 +00006652}
6653
6654/**
6655 * xmlBufferShrink:
6656 * @buf: the buffer to dump
6657 * @len: the number of xmlChar to remove
6658 *
6659 * Remove the beginning of an XML buffer.
6660 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006661 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006662 */
6663int
6664xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
Daniel Veillard3d97e662004-11-04 10:49:00 +00006665 if (buf == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006666 if (len == 0) return(0);
6667 if (len > buf->use) return(-1);
6668
6669 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006670 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6671 buf->content += len;
6672 } else {
6673 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6674 buf->content[buf->use] = 0;
6675 }
Owen Taylor3473f882001-02-23 17:55:21 +00006676 return(len);
6677}
6678
6679/**
6680 * xmlBufferGrow:
6681 * @buf: the buffer
6682 * @len: the minimum free size to allocate
6683 *
6684 * Grow the available space of an XML buffer.
6685 *
6686 * Returns the new available space or -1 in case of error
6687 */
6688int
6689xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6690 int size;
6691 xmlChar *newbuf;
6692
Daniel Veillard3d97e662004-11-04 10:49:00 +00006693 if (buf == NULL) return(-1);
6694
Daniel Veillard53350552003-09-18 13:35:51 +00006695 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006696 if (len + buf->use < buf->size) return(0);
6697
William M. Brack30fe43f2004-07-26 18:00:58 +00006698/*
6699 * Windows has a BIG problem on realloc timing, so we try to double
6700 * the buffer size (if that's enough) (bug 146697)
6701 */
6702#ifdef WIN32
6703 if (buf->size > len)
6704 size = buf->size * 2;
6705 else
6706 size = buf->use + len + 100;
6707#else
Owen Taylor3473f882001-02-23 17:55:21 +00006708 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00006709#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006710
6711 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006712 if (newbuf == NULL) {
6713 xmlTreeErrMemory("growing buffer");
6714 return(-1);
6715 }
Owen Taylor3473f882001-02-23 17:55:21 +00006716 buf->content = newbuf;
6717 buf->size = size;
6718 return(buf->size - buf->use);
6719}
6720
6721/**
6722 * xmlBufferDump:
6723 * @file: the file output
6724 * @buf: the buffer to dump
6725 *
6726 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006727 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006728 */
6729int
6730xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6731 int ret;
6732
6733 if (buf == NULL) {
6734#ifdef DEBUG_BUFFER
6735 xmlGenericError(xmlGenericErrorContext,
6736 "xmlBufferDump: buf == NULL\n");
6737#endif
6738 return(0);
6739 }
6740 if (buf->content == NULL) {
6741#ifdef DEBUG_BUFFER
6742 xmlGenericError(xmlGenericErrorContext,
6743 "xmlBufferDump: buf->content == NULL\n");
6744#endif
6745 return(0);
6746 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006747 if (file == NULL)
6748 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006749 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6750 return(ret);
6751}
6752
6753/**
6754 * xmlBufferContent:
6755 * @buf: the buffer
6756 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006757 * Function to extract the content of a buffer
6758 *
Owen Taylor3473f882001-02-23 17:55:21 +00006759 * Returns the internal content
6760 */
6761
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006762const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006763xmlBufferContent(const xmlBufferPtr buf)
6764{
6765 if(!buf)
6766 return NULL;
6767
6768 return buf->content;
6769}
6770
6771/**
6772 * xmlBufferLength:
6773 * @buf: the buffer
6774 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006775 * Function to get the length of a buffer
6776 *
Owen Taylor3473f882001-02-23 17:55:21 +00006777 * Returns the length of data in the internal content
6778 */
6779
6780int
6781xmlBufferLength(const xmlBufferPtr buf)
6782{
6783 if(!buf)
6784 return 0;
6785
6786 return buf->use;
6787}
6788
6789/**
6790 * xmlBufferResize:
6791 * @buf: the buffer to resize
6792 * @size: the desired size
6793 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006794 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006795 *
6796 * Returns 0 in case of problems, 1 otherwise
6797 */
6798int
6799xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6800{
6801 unsigned int newSize;
6802 xmlChar* rebuf = NULL;
6803
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006804 if (buf == NULL)
6805 return(0);
6806
Daniel Veillard53350552003-09-18 13:35:51 +00006807 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6808
Owen Taylor3473f882001-02-23 17:55:21 +00006809 /* Don't resize if we don't have to */
6810 if (size < buf->size)
6811 return 1;
6812
6813 /* figure out new size */
6814 switch (buf->alloc){
6815 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillardbf629492004-04-20 22:20:59 +00006816 /*take care of empty case*/
6817 newSize = (buf->size ? buf->size*2 : size + 10);
Owen Taylor3473f882001-02-23 17:55:21 +00006818 while (size > newSize) newSize *= 2;
6819 break;
6820 case XML_BUFFER_ALLOC_EXACT:
6821 newSize = size+10;
6822 break;
6823 default:
6824 newSize = size+10;
6825 break;
6826 }
6827
6828 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006829 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006830 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006831 rebuf = (xmlChar *) xmlRealloc(buf->content,
6832 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006833 } else {
6834 /*
6835 * if we are reallocating a buffer far from being full, it's
6836 * better to make a new allocation and copy only the used range
6837 * and free the old one.
6838 */
6839 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6840 if (rebuf != NULL) {
6841 memcpy(rebuf, buf->content, buf->use);
6842 xmlFree(buf->content);
William M. Brack42331a92004-07-29 07:07:16 +00006843 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006844 }
6845 }
Owen Taylor3473f882001-02-23 17:55:21 +00006846 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006847 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006848 return 0;
6849 }
6850 buf->content = rebuf;
6851 buf->size = newSize;
6852
6853 return 1;
6854}
6855
6856/**
6857 * xmlBufferAdd:
6858 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006859 * @str: the #xmlChar string
6860 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006861 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006862 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006863 * str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006864 *
6865 * Returns 0 successful, a positive error code number otherwise
6866 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006867 */
William M. Bracka3215c72004-07-31 16:24:01 +00006868int
Owen Taylor3473f882001-02-23 17:55:21 +00006869xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6870 unsigned int needSize;
6871
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006872 if ((str == NULL) || (buf == NULL)) {
William M. Bracka3215c72004-07-31 16:24:01 +00006873 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006874 }
William M. Bracka3215c72004-07-31 16:24:01 +00006875 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006876 if (len < -1) {
6877#ifdef DEBUG_BUFFER
6878 xmlGenericError(xmlGenericErrorContext,
6879 "xmlBufferAdd: len < 0\n");
6880#endif
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 (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006884
6885 if (len < 0)
6886 len = xmlStrlen(str);
6887
William M. Bracka3215c72004-07-31 16:24:01 +00006888 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006889
6890 needSize = buf->use + len + 2;
6891 if (needSize > buf->size){
6892 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006893 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006894 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006895 }
6896 }
6897
6898 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6899 buf->use += len;
6900 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006901 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006902}
6903
6904/**
6905 * xmlBufferAddHead:
6906 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006907 * @str: the #xmlChar string
6908 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006909 *
6910 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006911 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006912 *
6913 * Returns 0 successful, a positive error code number otherwise
6914 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006915 */
William M. Bracka3215c72004-07-31 16:24:01 +00006916int
Owen Taylor3473f882001-02-23 17:55:21 +00006917xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6918 unsigned int needSize;
6919
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006920 if (buf == NULL)
6921 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00006922 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006923 if (str == NULL) {
6924#ifdef DEBUG_BUFFER
6925 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006926 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006927#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006928 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006929 }
6930 if (len < -1) {
6931#ifdef DEBUG_BUFFER
6932 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006933 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006934#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006935 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006936 }
William M. Bracka3215c72004-07-31 16:24:01 +00006937 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006938
6939 if (len < 0)
6940 len = xmlStrlen(str);
6941
William M. Bracka3215c72004-07-31 16:24:01 +00006942 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006943
6944 needSize = buf->use + len + 2;
6945 if (needSize > buf->size){
6946 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006947 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006948 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006949 }
6950 }
6951
6952 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6953 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6954 buf->use += len;
6955 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006956 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006957}
6958
6959/**
6960 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00006961 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00006962 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006963 *
6964 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00006965 *
6966 * Returns 0 successful, a positive error code number otherwise
6967 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006968 */
William M. Bracka3215c72004-07-31 16:24:01 +00006969int
Owen Taylor3473f882001-02-23 17:55:21 +00006970xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006971 if (buf == NULL)
6972 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00006973 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
6974 if (str == NULL) return -1;
6975 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00006976}
6977
6978/**
6979 * xmlBufferCCat:
6980 * @buf: the buffer to dump
6981 * @str: the C char string
6982 *
6983 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00006984 *
6985 * Returns 0 successful, a positive error code number otherwise
6986 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006987 */
William M. Bracka3215c72004-07-31 16:24:01 +00006988int
Owen Taylor3473f882001-02-23 17:55:21 +00006989xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6990 const char *cur;
6991
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006992 if (buf == NULL)
6993 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00006994 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006995 if (str == NULL) {
6996#ifdef DEBUG_BUFFER
6997 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006998 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006999#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007000 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007001 }
7002 for (cur = str;*cur != 0;cur++) {
7003 if (buf->use + 10 >= buf->size) {
7004 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007005 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007006 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007007 }
7008 }
7009 buf->content[buf->use++] = *cur;
7010 }
7011 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007012 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007013}
7014
7015/**
7016 * xmlBufferWriteCHAR:
7017 * @buf: the XML buffer
7018 * @string: the string to add
7019 *
7020 * routine which manages and grows an output buffer. This one adds
7021 * xmlChars at the end of the buffer.
7022 */
7023void
Daniel Veillard53350552003-09-18 13:35:51 +00007024xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007025 if (buf == NULL)
7026 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007027 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007028 xmlBufferCat(buf, string);
7029}
7030
7031/**
7032 * xmlBufferWriteChar:
7033 * @buf: the XML buffer output
7034 * @string: the string to add
7035 *
7036 * routine which manage and grows an output buffer. This one add
7037 * C chars at the end of the array.
7038 */
7039void
7040xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007041 if (buf == NULL)
7042 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007043 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007044 xmlBufferCCat(buf, string);
7045}
7046
7047
7048/**
7049 * xmlBufferWriteQuotedString:
7050 * @buf: the XML buffer output
7051 * @string: the string to add
7052 *
7053 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00007054 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00007055 * quote or double-quotes internally
7056 */
7057void
7058xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00007059 const xmlChar *cur, *base;
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007060 if (buf == NULL)
7061 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007062 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00007063 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00007064 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00007065#ifdef DEBUG_BUFFER
7066 xmlGenericError(xmlGenericErrorContext,
7067 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7068#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00007069 xmlBufferCCat(buf, "\"");
7070 base = cur = string;
7071 while(*cur != 0){
7072 if(*cur == '"'){
7073 if (base != cur)
7074 xmlBufferAdd(buf, base, cur - base);
7075 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7076 cur++;
7077 base = cur;
7078 }
7079 else {
7080 cur++;
7081 }
7082 }
7083 if (base != cur)
7084 xmlBufferAdd(buf, base, cur - base);
7085 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007086 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007087 else{
7088 xmlBufferCCat(buf, "\'");
7089 xmlBufferCat(buf, string);
7090 xmlBufferCCat(buf, "\'");
7091 }
Owen Taylor3473f882001-02-23 17:55:21 +00007092 } else {
7093 xmlBufferCCat(buf, "\"");
7094 xmlBufferCat(buf, string);
7095 xmlBufferCCat(buf, "\"");
7096 }
7097}
7098
7099
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007100/**
7101 * xmlGetDocCompressMode:
7102 * @doc: the document
7103 *
7104 * get the compression ratio for a document, ZLIB based
7105 * Returns 0 (uncompressed) to 9 (max compression)
7106 */
7107int
7108xmlGetDocCompressMode (xmlDocPtr doc) {
7109 if (doc == NULL) return(-1);
7110 return(doc->compression);
7111}
7112
7113/**
7114 * xmlSetDocCompressMode:
7115 * @doc: the document
7116 * @mode: the compression ratio
7117 *
7118 * set the compression ratio for a document, ZLIB based
7119 * Correct values: 0 (uncompressed) to 9 (max compression)
7120 */
7121void
7122xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7123 if (doc == NULL) return;
7124 if (mode < 0) doc->compression = 0;
7125 else if (mode > 9) doc->compression = 9;
7126 else doc->compression = mode;
7127}
7128
7129/**
7130 * xmlGetCompressMode:
7131 *
7132 * get the default compression mode used, ZLIB based.
7133 * Returns 0 (uncompressed) to 9 (max compression)
7134 */
7135int
7136xmlGetCompressMode(void)
7137{
7138 return (xmlCompressMode);
7139}
7140
7141/**
7142 * xmlSetCompressMode:
7143 * @mode: the compression ratio
7144 *
7145 * set the default compression mode used, ZLIB based
7146 * Correct values: 0 (uncompressed) to 9 (max compression)
7147 */
7148void
7149xmlSetCompressMode(int mode) {
7150 if (mode < 0) xmlCompressMode = 0;
7151 else if (mode > 9) xmlCompressMode = 9;
7152 else xmlCompressMode = mode;
7153}
7154
Kasimier T. Buchcik4d9c9482005-06-27 15:04:46 +00007155/*
7156* xmlDOMWrapNewCtxt:
7157*
7158* Allocates and initializes a new DOM-wrapper context.
7159*
7160* Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal errror.
7161*/
7162xmlDOMWrapCtxtPtr
7163xmlDOMWrapNewCtxt(void)
7164{
7165 xmlDOMWrapCtxtPtr ret;
7166
7167 ret = xmlMalloc(sizeof(xmlDOMWrapCtxt));
7168 if (ret == NULL) {
7169 xmlTreeErrMemory("allocating DOM-wrapper context");
7170 return (NULL);
7171 }
7172 memset(ret, 0, sizeof(xmlDOMWrapCtxt));
7173 return (ret);
7174}
7175
7176/*
7177* xmlDOMWrapFreeCtxt:
7178* @ctxt: the DOM-wrapper context
7179*
7180* Frees the DOM-wrapper context.
7181*/
7182void
7183xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt)
7184{
7185 if (ctxt == NULL)
7186 return;
7187 xmlFree(ctxt);
7188}
7189
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007190#define XML_TREE_NSMAP_PARENT -1
7191#define XML_TREE_NSMAP_XML -2
7192#define XML_TREE_NSMAP_DOC -3
7193#define XML_TREE_NSMAP_CUSTOM -4
7194
7195typedef struct xmlNsMapItem *xmlNsMapItemPtr;
7196struct xmlNsMapItem {
7197 xmlNsMapItemPtr next;
7198 xmlNsMapItemPtr prev;
7199 xmlNsPtr oldNs; /* old ns decl reference */
7200 xmlNsPtr newNs; /* new ns decl reference */
7201 int shadowDepth; /* Shadowed at this depth */
7202 /*
7203 * depth:
7204 * >= 0 == @node's ns-decls
7205 * -1 == @parent's ns-decls
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00007206 * -2 == the doc->oldNs XML ns-decl
7207 * -3 == the doc->oldNs storage ns-decls
7208 * -4 == ns-decls provided via custom ns-handling
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007209 */
7210 int depth;
7211};
7212
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007213typedef struct xmlNsMap *xmlNsMapPtr;
7214struct xmlNsMap {
7215 xmlNsMapItemPtr first;
7216 xmlNsMapItemPtr last;
7217 xmlNsMapItemPtr pool;
7218};
7219
7220#define XML_NSMAP_NOTEMPTY(m) (((m) != NULL) && ((m)->first != NULL))
7221#define XML_NSMAP_FOREACH(m, i) for (i = (m)->first; i != NULL; i = (i)->next)
7222#define XML_NSMAP_POP(m, i) \
7223 i = (m)->last; \
7224 (m)->last = (i)->prev; \
7225 if ((m)->last == NULL) \
7226 (m)->first = NULL; \
7227 else \
7228 (m)->last->next = NULL; \
7229 (i)->next = (m)->pool; \
7230 (m)->pool = i;
7231
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007232/*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007233* xmlDOMWrapNsMapFree:
7234* @map: the ns-map
7235*
7236* Frees the ns-map
7237*/
7238static void
7239xmlDOMWrapNsMapFree(xmlNsMapPtr nsmap)
7240{
7241 xmlNsMapItemPtr cur, tmp;
7242
7243 if (nsmap == NULL)
7244 return;
7245 cur = nsmap->pool;
7246 while (cur != NULL) {
7247 tmp = cur;
7248 cur = cur->next;
7249 xmlFree(tmp);
7250 }
7251 cur = nsmap->first;
7252 while (cur != NULL) {
7253 tmp = cur;
7254 cur = cur->next;
7255 xmlFree(tmp);
7256 }
7257 xmlFree(nsmap);
7258}
7259
7260/*
7261* xmlDOMWrapNsMapAddItem:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007262* @map: the ns-map
7263* @cur: the current map entry to append a new entry to
7264* @oldNs: the old ns-struct
7265* @newNs: the new ns-struct
7266* @depth: depth and ns-kind information
7267*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007268* Adds an ns-mapping item.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007269*/
7270static xmlNsMapItemPtr
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007271xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position, /* xmlNsMapItemPtr *cur, */
7272 xmlNsPtr oldNs, xmlNsPtr newNs, int depth)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007273{
7274 xmlNsMapItemPtr ret;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007275 xmlNsMapPtr map;
7276
7277 if (nsmap == NULL)
7278 return(NULL);
7279 if ((position != -1) && (position != 0))
7280 return(NULL);
7281 map = *nsmap;
7282
7283 if (map == NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007284 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007285 * Create the ns-map.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007286 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007287 map = (xmlNsMapPtr) xmlMalloc(sizeof(struct xmlNsMap));
7288 if (map == NULL) {
7289 xmlTreeErrMemory("allocating namespace map");
7290 return (NULL);
7291 }
7292 memset(map, 0, sizeof(struct xmlNsMap));
7293 *nsmap = map;
7294 }
7295
7296 if (map->pool != NULL) {
7297 /*
7298 * Reuse an item from the pool.
7299 */
7300 ret = map->pool;
7301 map->pool = ret->next;
7302 memset(ret, 0, sizeof(struct xmlNsMapItem));
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007303 } else {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007304 /*
7305 * Create a new item.
7306 */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007307 ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem));
7308 if (ret == NULL) {
7309 xmlTreeErrMemory("allocating namespace map item");
7310 return (NULL);
7311 }
7312 memset(ret, 0, sizeof(struct xmlNsMapItem));
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007313 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007314
7315 if (map->first == NULL) {
7316 /*
7317 * First ever.
7318 */
7319 map->first = ret;
7320 map->last = ret;
7321 } else if (position == -1) {
7322 /*
7323 * Append.
7324 */
7325 ret->prev = map->last;
7326 map->last->next = ret;
7327 map->last = ret;
7328 } else if (position == 0) {
7329 /*
7330 * Set on first position.
7331 */
7332 map->first->prev = ret;
7333 ret->next = map->first;
7334 map->first = ret;
7335 } else
7336 return(NULL);
7337
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007338 ret->oldNs = oldNs;
7339 ret->newNs = newNs;
7340 ret->shadowDepth = -1;
7341 ret->depth = depth;
7342 return (ret);
7343}
7344
7345/*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007346* xmlTreeEnsureXMLDecl:
7347* @doc: the doc
7348*
7349* Ensures that there is an XML namespace declaration on the doc.
7350*
7351* Returns the XML ns-struct or NULL on API and internal errors.
7352*/
7353static xmlNsPtr
7354xmlTreeEnsureXMLDecl(xmlDocPtr doc)
7355{
7356 if (doc == NULL)
7357 return (NULL);
7358 if (doc->oldNs != NULL)
7359 return (doc->oldNs);
7360 {
7361 xmlNsPtr ns;
7362 ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
7363 if (ns == NULL) {
7364 xmlTreeErrMemory(
7365 "allocating the XML namespace");
7366 return (NULL);
7367 }
7368 memset(ns, 0, sizeof(xmlNs));
7369 ns->type = XML_LOCAL_NAMESPACE;
7370 ns->href = xmlStrdup(XML_XML_NAMESPACE);
7371 ns->prefix = xmlStrdup((const xmlChar *)"xml");
7372 doc->oldNs = ns;
7373 return (ns);
7374 }
7375}
7376
7377/*
7378* xmlDOMWrapStoreNs:
7379* @doc: the doc
7380* @nsName: the namespace name
7381* @prefix: the prefix
7382*
7383* Creates or reuses an xmlNs struct on doc->oldNs with
7384* the given prefix and namespace name.
7385*
7386* Returns the aquired ns struct or NULL in case of an API
7387* or internal error.
7388*/
7389static xmlNsPtr
7390xmlDOMWrapStoreNs(xmlDocPtr doc,
7391 const xmlChar *nsName,
7392 const xmlChar *prefix)
7393{
7394 xmlNsPtr ns;
7395
7396 if (doc == NULL)
7397 return (NULL);
7398 ns = xmlTreeEnsureXMLDecl(doc);
7399 if (ns == NULL)
7400 return (NULL);
7401 if (ns->next != NULL) {
7402 /* Reuse. */
7403 ns = ns->next;
7404 while (ns != NULL) {
7405 if (((ns->prefix == prefix) ||
7406 xmlStrEqual(ns->prefix, prefix)) &&
7407 xmlStrEqual(ns->href, nsName)) {
7408 return (ns);
7409 }
7410 if (ns->next == NULL)
7411 break;
7412 ns = ns->next;
7413 }
7414 }
7415 /* Create. */
7416 ns->next = xmlNewNs(NULL, nsName, prefix);
7417 return (ns->next);
7418}
7419
7420/*
7421* xmlTreeLookupNsListByPrefix:
7422* @nsList: a list of ns-structs
7423* @prefix: the searched prefix
7424*
7425* Searches for a ns-decl with the given prefix in @nsList.
7426*
7427* Returns the ns-decl if found, NULL if not found and on
7428* API errors.
7429*/
7430static xmlNsPtr
7431xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix)
7432{
7433 if (nsList == NULL)
7434 return (NULL);
7435 {
7436 xmlNsPtr ns;
7437 ns = nsList;
7438 do {
7439 if ((prefix == ns->prefix) ||
7440 xmlStrEqual(prefix, ns->prefix)) {
7441 return (ns);
7442 }
7443 ns = ns->next;
7444 } while (ns != NULL);
7445 }
7446 return (NULL);
7447}
7448
7449/*
7450*
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00007451* xmlDOMWrapNSNormGatherInScopeNs:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007452* @map: the namespace map
7453* @node: the node to start with
7454*
7455* Puts in-scope namespaces into the ns-map.
7456*
7457* Returns 0 on success, -1 on API or internal errors.
7458*/
7459static int
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007460xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapPtr *map,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007461 xmlNodePtr node)
7462{
7463 xmlNodePtr cur;
7464 xmlNsPtr ns;
7465 xmlNsMapItemPtr mi;
7466 int shadowed;
7467
7468 if ((map == NULL) || (*map != NULL))
7469 return (-1);
7470 /*
7471 * Get in-scope ns-decls of @parent.
7472 */
7473 cur = node;
7474 while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) {
7475 if (cur->type == XML_ELEMENT_NODE) {
7476 if (cur->nsDef != NULL) {
7477 ns = cur->nsDef;
7478 do {
7479 shadowed = 0;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007480 if (XML_NSMAP_NOTEMPTY(*map)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007481 /*
7482 * Skip shadowed prefixes.
7483 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007484 XML_NSMAP_FOREACH(*map, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007485 if ((ns->prefix == mi->newNs->prefix) ||
7486 xmlStrEqual(ns->prefix, mi->newNs->prefix)) {
7487 shadowed = 1;
7488 break;
7489 }
7490 }
7491 }
7492 /*
7493 * Insert mapping.
7494 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007495 mi = xmlDOMWrapNsMapAddItem(map, 0, NULL,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007496 ns, XML_TREE_NSMAP_PARENT);
7497 if (mi == NULL)
7498 return (-1);
7499 if (shadowed)
7500 mi->shadowDepth = 0;
7501 ns = ns->next;
7502 } while (ns != NULL);
7503 }
7504 }
7505 cur = cur->parent;
7506 }
7507 return (0);
7508}
7509
7510/*
7511* XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict;
7512* otherwise copy it, when it was in the source-dict.
7513*/
7514#define XML_TREE_ADOPT_STR(str) \
7515 if (adoptStr && (str != NULL)) { \
7516 if (destDoc->dict) { \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00007517 const xmlChar *old = str; \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007518 str = xmlDictLookup(destDoc->dict, str, -1); \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00007519 if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \
7520 (!xmlDictOwns(sourceDoc->dict, old))) \
Daniel Veillard39e5c892005-07-03 22:48:50 +00007521 xmlFree((char *)old); \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007522 } else if ((sourceDoc) && (sourceDoc->dict) && \
7523 xmlDictOwns(sourceDoc->dict, str)) { \
7524 str = BAD_CAST xmlStrdup(str); \
7525 } \
7526 }
7527
7528/*
7529* XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then
7530* put it in dest-dict or copy it.
7531*/
7532#define XML_TREE_ADOPT_STR_2(str) \
7533 if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \
7534 (sourceDoc->dict != NULL) && \
7535 xmlDictOwns(sourceDoc->dict, cur->content)) { \
7536 if (destDoc->dict) \
7537 cur->content = (xmlChar *) \
7538 xmlDictLookup(destDoc->dict, cur->content, -1); \
7539 else \
7540 cur->content = xmlStrdup(BAD_CAST cur->content); \
7541 }
7542
7543/*
7544* xmlDOMWrapNSNormAddNsMapItem2:
7545*
7546* For internal use. Adds a ns-decl mapping.
7547*
7548* Returns 0 on success, -1 on internal errors.
7549*/
7550static int
7551xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number,
7552 xmlNsPtr oldNs, xmlNsPtr newNs)
7553{
7554 if (*list == NULL) {
7555 *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr));
7556 if (*list == NULL) {
7557 xmlTreeErrMemory("alloc ns map item");
7558 return(-1);
7559 }
7560 *size = 3;
7561 *number = 0;
7562 } else if ((*number) >= (*size)) {
7563 *size *= 2;
7564 *list = (xmlNsPtr *) xmlRealloc(*list,
7565 (*size) * 2 * sizeof(xmlNsPtr));
7566 if (*list == NULL) {
7567 xmlTreeErrMemory("realloc ns map item");
7568 return(-1);
7569 }
7570 }
7571 (*list)[2 * (*number)] = oldNs;
7572 (*list)[2 * (*number) +1] = newNs;
7573 (*number)++;
7574 return (0);
7575}
7576
7577/*
7578* xmlDOMWrapRemoveNode:
Daniel Veillard304e78c2005-07-03 16:19:41 +00007579* @ctxt: a DOM wrapper context
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007580* @doc: the doc
7581* @node: the node to be removed.
Daniel Veillard304e78c2005-07-03 16:19:41 +00007582* @options: set of options, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007583*
7584* Unlinks the given node from its owner.
7585* This will substitute ns-references to node->nsDef for
7586* ns-references to doc->oldNs, thus ensuring the removed
7587* branch to be autark wrt ns-references.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00007588* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007589*
7590* Returns 0 on success, 1 if the node is not supported,
7591* -1 on API and internal errors.
7592*/
7593int
7594xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc,
7595 xmlNodePtr node, int options ATTRIBUTE_UNUSED)
7596{
7597 xmlNsPtr *list = NULL;
7598 int sizeList, nbList, i, j;
7599 xmlNsPtr ns;
7600
7601 if ((node == NULL) || (doc == NULL) || (node->doc != doc))
7602 return (-1);
7603
7604 /* TODO: 0 or -1 ? */
7605 if (node->parent == NULL)
7606 return (0);
7607
7608 switch (node->type) {
7609 case XML_TEXT_NODE:
7610 case XML_CDATA_SECTION_NODE:
7611 case XML_ENTITY_REF_NODE:
7612 case XML_PI_NODE:
7613 case XML_COMMENT_NODE:
7614 xmlUnlinkNode(node);
7615 return (0);
7616 case XML_ELEMENT_NODE:
7617 case XML_ATTRIBUTE_NODE:
7618 break;
7619 default:
7620 return (1);
7621 }
7622 xmlUnlinkNode(node);
7623 /*
7624 * Save out-of-scope ns-references in doc->oldNs.
7625 */
7626 do {
7627 switch (node->type) {
7628 case XML_ELEMENT_NODE:
7629 if ((ctxt == NULL) && (node->nsDef != NULL)) {
7630 ns = node->nsDef;
7631 do {
7632 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
7633 &nbList, ns, ns) == -1)
7634 goto internal_error;
7635 ns = ns->next;
7636 } while (ns != NULL);
7637 }
7638 /* No break on purpose. */
7639 case XML_ATTRIBUTE_NODE:
7640 if (node->ns != NULL) {
7641 /*
7642 * Find a mapping.
7643 */
7644 if (list != NULL) {
7645 for (i = 0, j = 0; i < nbList; i++, j += 2) {
7646 if (node->ns == list[j]) {
7647 node->ns = list[++j];
7648 goto next_node;
7649 }
7650 }
7651 }
7652 ns = NULL;
7653 if (ctxt != NULL) {
7654 /*
7655 * User defined.
7656 */
7657 } else {
7658 /*
7659 * Add to doc's oldNs.
7660 */
7661 ns = xmlDOMWrapStoreNs(doc, node->ns->href,
7662 node->ns->prefix);
7663 if (ns == NULL)
7664 goto internal_error;
7665 }
7666 if (ns != NULL) {
7667 /*
7668 * Add mapping.
7669 */
7670 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
7671 &nbList, node->ns, ns) == -1)
7672 goto internal_error;
7673 }
7674 node->ns = ns;
7675 }
7676 if ((node->type == XML_ELEMENT_NODE) &&
7677 (node->properties != NULL)) {
7678 node = (xmlNodePtr) node->properties;
7679 continue;
7680 }
7681 break;
7682 default:
7683 goto next_sibling;
7684 }
7685next_node:
7686 if ((node->type == XML_ELEMENT_NODE) &&
7687 (node->children != NULL)) {
7688 node = node->children;
7689 continue;
7690 }
7691next_sibling:
7692 if (node == NULL)
7693 break;
7694 if (node->next != NULL)
7695 node = node->next;
7696 else {
7697 node = node->parent;
7698 goto next_sibling;
7699 }
7700 } while (node != NULL);
7701
7702 if (list != NULL)
7703 xmlFree(list);
7704 return (0);
7705
7706internal_error:
7707 if (list != NULL)
7708 xmlFree(list);
7709 return (-1);
7710}
7711
7712/*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007713* xmlSearchNsByNamespaceStrict:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007714* @doc: the document
7715* @node: the start node
7716* @nsName: the searched namespace name
7717* @retNs: the resulting ns-decl
7718* @prefixed: if the found ns-decl must have a prefix (for attributes)
7719*
7720* Dynamically searches for a ns-declaration which matches
7721* the given @nsName in the ancestor-or-self axis of @node.
7722*
7723* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7724* and internal errors.
7725*/
7726static int
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007727xmlSearchNsByNamespaceStrict(xmlDocPtr doc, xmlNodePtr node,
7728 const xmlChar* nsName,
7729 xmlNsPtr *retNs, int prefixed)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007730{
7731 xmlNodePtr cur, prev = NULL, out = NULL;
7732 xmlNsPtr ns, prevns;
7733
7734 if ((doc == NULL) || (nsName == NULL) || (retNs == NULL))
7735 return (-1);
7736
7737 *retNs = NULL;
7738 if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
7739 *retNs = xmlTreeEnsureXMLDecl(doc);
7740 if (*retNs == NULL)
7741 return (-1);
7742 return (1);
7743 }
7744 cur = node;
7745 do {
7746 if (cur->type == XML_ELEMENT_NODE) {
7747 if (cur->nsDef != NULL) {
7748 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
7749 if (prefixed && (ns->prefix == NULL))
7750 continue;
7751 if (prev != NULL) {
7752 /*
7753 * Check the last level of ns-decls for a
7754 * shadowing prefix.
7755 */
7756 prevns = prev->nsDef;
7757 do {
7758 if ((prevns->prefix == ns->prefix) ||
7759 ((prevns->prefix != NULL) &&
7760 (ns->prefix != NULL) &&
7761 xmlStrEqual(prevns->prefix, ns->prefix))) {
7762 /*
7763 * Shadowed.
7764 */
7765 break;
7766 }
7767 prevns = prevns->next;
7768 } while (prevns != NULL);
7769 if (prevns != NULL)
7770 continue;
7771 }
7772 /*
7773 * Ns-name comparison.
7774 */
7775 if ((nsName == ns->href) ||
7776 xmlStrEqual(nsName, ns->href)) {
7777 /*
7778 * At this point the prefix can only be shadowed,
7779 * if we are the the (at least) 3rd level of
7780 * ns-decls.
7781 */
7782 if (out) {
7783 int ret;
7784
7785 ret = xmlNsInScope(doc, node, prev, ns->prefix);
7786 if (ret < 0)
7787 return (-1);
7788 /*
7789 * TODO: Should we try to find a matching ns-name
7790 * only once? This here keeps on searching.
7791 * I think we should try further since, there might
7792 * be an other matching ns-decl with an unshadowed
7793 * prefix.
7794 */
7795 if (! ret)
7796 continue;
7797 }
7798 *retNs = ns;
7799 return (1);
7800 }
7801 }
7802 out = prev;
7803 prev = cur;
7804 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007805 } else if ((cur->type == XML_ENTITY_NODE) ||
7806 (cur->type == XML_ENTITY_DECL))
7807 return (0);
7808 cur = cur->parent;
7809 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
7810 return (0);
7811}
7812
7813/*
7814* xmlSearchNsByPrefixStrict:
7815* @doc: the document
7816* @node: the start node
7817* @prefix: the searched namespace prefix
7818* @retNs: the resulting ns-decl
7819* @prefixed: if the found ns-decl must have a prefix (for attributes)
7820*
7821* Dynamically searches for a ns-declaration which matches
7822* the given @nsName in the ancestor-or-self axis of @node.
7823*
7824* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7825* and internal errors.
7826*/
7827static int
7828xmlSearchNsByPrefixStrict(xmlDocPtr doc, xmlNodePtr node,
7829 const xmlChar* prefix,
7830 xmlNsPtr *retNs)
7831{
7832 xmlNodePtr cur;
7833 xmlNsPtr ns;
7834
7835 if ((doc == NULL) || (node == NULL))
7836 return (-1);
7837
7838 if (retNs)
7839 *retNs = NULL;
7840 if (IS_STR_XML(prefix)) {
7841 if (retNs) {
7842 *retNs = xmlTreeEnsureXMLDecl(doc);
7843 if (*retNs == NULL)
7844 return (-1);
7845 }
7846 return (1);
7847 }
7848 cur = node;
7849 do {
7850 if (cur->type == XML_ELEMENT_NODE) {
7851 if (cur->nsDef != NULL) {
7852 ns = cur->nsDef;
7853 do {
7854 if ((prefix == ns->prefix) ||
7855 xmlStrEqual(prefix, ns->prefix))
7856 {
7857 /*
7858 * Disabled namespaces, e.g. xmlns:abc="".
7859 */
7860 if (ns->href == NULL)
7861 return(0);
7862 if (retNs)
7863 *retNs = ns;
7864 return (1);
7865 }
7866 ns = ns->next;
7867 } while (ns != NULL);
7868 }
7869 } else if ((cur->type == XML_ENTITY_NODE) ||
7870 (cur->type == XML_ENTITY_DECL))
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007871 return (0);
7872 cur = cur->parent;
7873 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
7874 return (0);
7875}
7876
7877/*
7878* xmlDOMWrapNSNormDeclareNsForced:
7879* @doc: the doc
7880* @elem: the element-node to declare on
7881* @nsName: the namespace-name of the ns-decl
7882* @prefix: the preferred prefix of the ns-decl
7883* @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls
7884*
7885* Declares a new namespace on @elem. It tries to use the
7886* given @prefix; if a ns-decl with the given prefix is already existent
7887* on @elem, it will generate an other prefix.
7888*
7889* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7890* and internal errors.
7891*/
7892static xmlNsPtr
7893xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc,
7894 xmlNodePtr elem,
7895 const xmlChar *nsName,
7896 const xmlChar *prefix,
7897 int checkShadow)
7898{
7899
7900 xmlNsPtr ret;
7901 char buf[50];
7902 const xmlChar *pref;
7903 int counter = 0;
7904 /*
7905 * Create a ns-decl on @anchor.
7906 */
7907 pref = prefix;
7908 while (1) {
7909 /*
7910 * Lookup whether the prefix is unused in elem's ns-decls.
7911 */
7912 if ((elem->nsDef != NULL) &&
7913 (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL))
7914 goto ns_next_prefix;
7915 if (checkShadow && elem->parent &&
7916 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
7917 /*
7918 * Does it shadow ancestor ns-decls?
7919 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007920 if (xmlSearchNsByPrefixStrict(doc, elem->parent, pref, NULL) == 1)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007921 goto ns_next_prefix;
7922 }
7923 ret = xmlNewNs(NULL, nsName, pref);
7924 if (ret == NULL)
7925 return (NULL);
7926 if (elem->nsDef == NULL)
7927 elem->nsDef = ret;
7928 else {
7929 xmlNsPtr ns2 = elem->nsDef;
7930 while (ns2->next != NULL)
7931 ns2 = ns2->next;
7932 ns2->next = ret;
7933 }
7934 return (ret);
7935ns_next_prefix:
7936 counter++;
7937 if (counter > 1000)
7938 return (NULL);
7939 if (prefix == NULL) {
7940 snprintf((char *) buf, sizeof(buf),
7941 "default%d", counter);
7942 } else
7943 snprintf((char *) buf, sizeof(buf),
7944 "%.30s%d", (char *)prefix, counter);
7945 pref = BAD_CAST buf;
7946 }
7947}
7948
7949/*
7950* xmlDOMWrapNSNormAquireNormalizedNs:
7951* @doc: the doc
7952* @elem: the element-node to declare namespaces on
7953* @ns: the ns-struct to use for the search
7954* @retNs: the found/created ns-struct
7955* @nsMap: the ns-map
7956* @topmi: the last ns-map entry
7957* @depth: the current tree depth
7958* @ancestorsOnly: search in ancestor ns-decls only
7959* @prefixed: if the searched ns-decl must have a prefix (for attributes)
7960*
7961* Searches for a matching ns-name in the ns-decls of @nsMap, if not
7962* found it will either declare it on @elem, or store it in doc->oldNs.
7963* If a new ns-decl needs to be declared on @elem, it tries to use the
7964* @ns->prefix for it, if this prefix is already in use on @elem, it will
7965* change the prefix or the new ns-decl.
7966*
7967* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
7968*/
7969static int
7970xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc,
7971 xmlNodePtr elem,
7972 xmlNsPtr ns,
7973 xmlNsPtr *retNs,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007974 xmlNsMapPtr *nsMap,
7975
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007976 int depth,
7977 int ancestorsOnly,
7978 int prefixed)
7979{
7980 xmlNsMapItemPtr mi;
7981
7982 if ((doc == NULL) || (ns == NULL) || (retNs == NULL) ||
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007983 (nsMap == NULL))
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007984 return (-1);
7985
7986 *retNs = NULL;
7987 /*
7988 * Handle XML namespace.
7989 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007990 if (IS_STR_XML(ns->prefix)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007991 /*
7992 * Insert XML namespace mapping.
7993 */
7994 *retNs = xmlTreeEnsureXMLDecl(doc);
7995 if (*retNs == NULL)
7996 return (-1);
7997 return (0);
7998 }
7999 /*
8000 * If the search should be done in ancestors only and no
8001 * @elem (the first ancestor) was specified, then skip the search.
8002 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008003 if ((! (ancestorsOnly && (elem == NULL))) && (XML_NSMAP_NOTEMPTY(*nsMap)))
8004 {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008005 /*
8006 * Try to find an equal ns-name in in-scope ns-decls.
8007 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008008 XML_NSMAP_FOREACH(*nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008009 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8010 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008011 * ancestorsOnly: This should be turned on to gain speed,
8012 * if one knows that the branch itself was already
8013 * ns-wellformed and no stale references existed.
8014 * I.e. it searches in the ancestor axis only.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008015 */
8016 ((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) &&
8017 /* Skip shadowed prefixes. */
8018 (mi->shadowDepth == -1) &&
8019 /* Skip xmlns="" or xmlns:foo="". */
8020 ((mi->newNs->href != NULL) &&
8021 (mi->newNs->href[0] != 0)) &&
8022 /* Ensure a prefix if wanted. */
8023 ((! prefixed) || (mi->newNs->prefix != NULL)) &&
8024 /* Equal ns name */
8025 ((mi->newNs->href == ns->href) ||
8026 xmlStrEqual(mi->newNs->href, ns->href))) {
8027 /* Set the mapping. */
8028 mi->oldNs = ns;
8029 *retNs = mi->newNs;
8030 return (0);
8031 }
8032 }
8033 }
8034 /*
8035 * No luck, the namespace is out of scope or shadowed.
8036 */
8037 if (elem == NULL) {
8038 xmlNsPtr tmpns;
8039
8040 /*
8041 * Store ns-decls in "oldNs" of the document-node.
8042 */
8043 tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix);
8044 if (tmpns == NULL)
8045 return (-1);
8046 /*
8047 * Insert mapping.
8048 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008049 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008050 tmpns, XML_TREE_NSMAP_DOC) == NULL) {
8051 xmlFreeNs(tmpns);
8052 return (-1);
8053 }
8054 *retNs = tmpns;
8055 } else {
8056 xmlNsPtr tmpns;
8057
8058 tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href,
8059 ns->prefix, 0);
8060 if (tmpns == NULL)
8061 return (-1);
8062
8063 if (*nsMap != NULL) {
8064 /*
8065 * Does it shadow ancestor ns-decls?
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008066 */
8067 XML_NSMAP_FOREACH(*nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008068 if ((mi->depth < depth) &&
8069 (mi->shadowDepth == -1) &&
8070 ((ns->prefix == mi->newNs->prefix) ||
8071 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8072 /*
8073 * Shadows.
8074 */
8075 mi->shadowDepth = depth;
8076 break;
8077 }
8078 }
8079 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008080 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, depth) == NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008081 xmlFreeNs(tmpns);
8082 return (-1);
8083 }
8084 *retNs = tmpns;
8085 }
8086 return (0);
8087}
8088
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008089typedef enum {
8090 XML_DOM_RECONNS_REMOVEREDUND = 1<<0
8091} xmlDOMReconcileNSOptions;
8092
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008093/*
8094* xmlDOMWrapReconcileNamespaces:
Daniel Veillard304e78c2005-07-03 16:19:41 +00008095* @ctxt: DOM wrapper context, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008096* @elem: the element-node
8097* @options: option flags
8098*
8099* Ensures that ns-references point to ns-decls hold on element-nodes.
8100* Ensures that the tree is namespace wellformed by creating additional
8101* ns-decls where needed. Note that, since prefixes of already existent
8102* ns-decls can be shadowed by this process, it could break QNames in
8103* attribute values or element content.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00008104* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008105*
8106* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008107*/
8108
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008109int
8110xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,
8111 xmlNodePtr elem,
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008112 int options)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008113{
8114 int depth = -1, adoptns = 0, parnsdone = 0;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008115 xmlNsPtr ns, prevns;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008116 xmlDocPtr doc;
8117 xmlNodePtr cur, curElem = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008118 xmlNsMapPtr nsMap = NULL;
8119 xmlNsMapItemPtr /* topmi = NULL, */ mi;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008120 /* @ancestorsOnly should be set by an option flag. */
8121 int ancestorsOnly = 0;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008122 int optRemoveDedundantNS =
8123 ((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0;
8124 xmlNsPtr *listRedund = NULL;
8125 int sizeRedund = 0, nbRedund = 0, ret, i, j;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008126
8127 if ((elem == NULL) || (elem->doc == NULL) ||
8128 (elem->type != XML_ELEMENT_NODE))
8129 return (-1);
8130
8131 doc = elem->doc;
8132 cur = elem;
8133 do {
8134 switch (cur->type) {
8135 case XML_ELEMENT_NODE:
8136 adoptns = 1;
8137 curElem = cur;
8138 depth++;
8139 /*
8140 * Namespace declarations.
8141 */
8142 if (cur->nsDef != NULL) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008143 prevns = NULL;
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008144 ns = cur->nsDef;
8145 while (ns != NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008146 if (! parnsdone) {
8147 if ((elem->parent) &&
8148 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8149 /*
8150 * Gather ancestor in-scope ns-decls.
8151 */
8152 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8153 elem->parent) == -1)
8154 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008155 }
8156 parnsdone = 1;
8157 }
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008158
8159 /*
8160 * Lookup the ns ancestor-axis for equal ns-decls in scope.
8161 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008162 if (optRemoveDedundantNS && XML_NSMAP_NOTEMPTY(nsMap)) {
8163 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008164 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8165 (mi->shadowDepth == -1) &&
8166 ((ns->prefix == mi->newNs->prefix) ||
8167 xmlStrEqual(ns->prefix, mi->newNs->prefix)) &&
8168 ((ns->href == mi->newNs->href) ||
8169 xmlStrEqual(ns->href, mi->newNs->href)))
8170 {
8171 /*
8172 * A redundant ns-decl was found.
8173 * Add it to the list of redundant ns-decls.
8174 */
8175 if (xmlDOMWrapNSNormAddNsMapItem2(&listRedund,
8176 &sizeRedund, &nbRedund, ns, mi->newNs) == -1)
8177 goto internal_error;
8178 /*
8179 * Remove the ns-decl from the element-node.
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008180 */
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008181 if (prevns)
8182 prevns->next = ns->next;
8183 else
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008184 cur->nsDef = ns->next;
8185 goto next_ns_decl;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008186 }
8187 }
8188 }
8189
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008190 /*
8191 * Skip ns-references handling if the referenced
8192 * ns-decl is declared on the same element.
8193 */
8194 if ((cur->ns != NULL) && adoptns && (cur->ns == ns))
8195 adoptns = 0;
8196 /*
8197 * Does it shadow any ns-decl?
8198 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008199 if (XML_NSMAP_NOTEMPTY(nsMap)) {
8200 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008201 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8202 (mi->shadowDepth == -1) &&
8203 ((ns->prefix == mi->newNs->prefix) ||
8204 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8205
8206 mi->shadowDepth = depth;
8207 }
8208 }
8209 }
8210 /*
8211 * Push mapping.
8212 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008213 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008214 depth) == NULL)
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008215 goto internal_error;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008216
8217 prevns = ns;
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008218next_ns_decl:
8219 ns = ns->next;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008220 }
8221 }
8222 if (! adoptns)
8223 goto ns_end;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008224 /* No break on purpose. */
8225 case XML_ATTRIBUTE_NODE:
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008226 /* No ns, no fun. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008227 if (cur->ns == NULL)
8228 goto ns_end;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008229
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008230 if (! parnsdone) {
8231 if ((elem->parent) &&
8232 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8233 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8234 elem->parent) == -1)
8235 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008236 }
8237 parnsdone = 1;
8238 }
8239 /*
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008240 * Adjust the reference if this was a redundant ns-decl.
8241 */
8242 if (listRedund) {
8243 for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8244 if (cur->ns == listRedund[j]) {
8245 cur->ns = listRedund[++j];
8246 break;
8247 }
8248 }
8249 }
8250 /*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008251 * Adopt ns-references.
8252 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008253 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008254 /*
8255 * Search for a mapping.
8256 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008257 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008258 if ((mi->shadowDepth == -1) &&
8259 (cur->ns == mi->oldNs)) {
8260
8261 cur->ns = mi->newNs;
8262 goto ns_end;
8263 }
8264 }
8265 }
8266 /*
8267 * Aquire a normalized ns-decl and add it to the map.
8268 */
8269 if (xmlDOMWrapNSNormAquireNormalizedNs(doc, curElem,
8270 cur->ns, &ns,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008271 &nsMap, depth,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008272 ancestorsOnly,
8273 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8274 goto internal_error;
8275 cur->ns = ns;
8276
8277ns_end:
8278 if ((cur->type == XML_ELEMENT_NODE) &&
8279 (cur->properties != NULL)) {
8280 /*
8281 * Process attributes.
8282 */
8283 cur = (xmlNodePtr) cur->properties;
8284 continue;
8285 }
8286 break;
8287 default:
8288 goto next_sibling;
8289 }
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008290into_content:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008291 if ((cur->type == XML_ELEMENT_NODE) &&
8292 (cur->children != NULL)) {
8293 /*
8294 * Process content of element-nodes only.
8295 */
8296 cur = cur->children;
8297 continue;
8298 }
8299next_sibling:
8300 if (cur == elem)
8301 break;
8302 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008303 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008304 /*
8305 * Pop mappings.
8306 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008307 while ((nsMap->last != NULL) &&
8308 (nsMap->last->depth >= depth))
8309 {
8310 XML_NSMAP_POP(nsMap, mi)
8311 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008312 /*
8313 * Unshadow.
8314 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008315 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008316 if (mi->shadowDepth >= depth)
8317 mi->shadowDepth = -1;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008318 }
8319 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008320 depth--;
8321 }
8322 if (cur->next != NULL)
8323 cur = cur->next;
8324 else {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008325 if (cur->type == XML_ATTRIBUTE_NODE) {
8326 cur = cur->parent;
8327 goto into_content;
8328 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008329 cur = cur->parent;
8330 goto next_sibling;
8331 }
8332 } while (cur != NULL);
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008333
8334 ret = 0;
8335 goto exit;
8336internal_error:
8337 ret = -1;
8338exit:
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008339 if (listRedund) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008340 for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8341 xmlFreeNs(listRedund[j]);
8342 }
8343 xmlFree(listRedund);
8344 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008345 if (nsMap != NULL)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008346 xmlDOMWrapNsMapFree(nsMap);
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008347 return (ret);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008348}
8349
8350/*
8351* xmlDOMWrapAdoptBranch:
8352* @ctxt: the optional context for custom processing
8353* @sourceDoc: the optional sourceDoc
8354* @node: the element-node to start with
8355* @destDoc: the destination doc for adoption
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008356* @destParent: the optional new parent of @node in @destDoc
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008357* @options: option flags
8358*
8359* Ensures that ns-references point to @destDoc: either to
8360* elements->nsDef entries if @destParent is given, or to
8361* @destDoc->oldNs otherwise.
8362* If @destParent is given, it ensures that the tree is namespace
8363* wellformed by creating additional ns-decls where needed.
8364* Note that, since prefixes of already existent ns-decls can be
8365* shadowed by this process, it could break QNames in attribute
8366* values or element content.
8367*
8368* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8369*/
8370static int
8371xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
8372 xmlDocPtr sourceDoc,
8373 xmlNodePtr node,
8374 xmlDocPtr destDoc,
8375 xmlNodePtr destParent,
8376 int options ATTRIBUTE_UNUSED)
8377{
8378 int ret = 0;
8379 xmlNodePtr cur, curElem = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008380 xmlNsMapPtr nsMap = NULL;
8381 xmlNsMapItemPtr mi;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008382 xmlNsPtr ns;
8383 int depth = -1, adoptStr = 1;
8384 /* gather @parent's ns-decls. */
8385 int parnsdone = 0;
8386 /* @ancestorsOnly should be set per option. */
8387 int ancestorsOnly = 0;
8388
8389 /*
8390 * Optimize string adoption for equal or none dicts.
8391 */
8392 if ((sourceDoc != NULL) &&
8393 (sourceDoc->dict == destDoc->dict))
8394 adoptStr = 0;
8395 else
8396 adoptStr = 1;
8397
8398 cur = node;
8399 while (cur != NULL) {
8400 if (cur->doc != sourceDoc) {
8401 /*
8402 * We'll assume XIncluded nodes if the doc differs.
8403 * TODO: Do we need to reconciliate XIncluded nodes?
8404 * This here skips XIncluded nodes and tries to handle
8405 * broken sequences.
8406 */
8407 if (cur->next == NULL)
8408 goto leave_node;
8409 do {
8410 cur = cur->next;
8411 if ((cur->type == XML_XINCLUDE_END) ||
8412 (cur->doc == node->doc))
8413 break;
8414 } while (cur->next != NULL);
8415
8416 if (cur->doc != node->doc)
8417 goto leave_node;
8418 }
8419 cur->doc = destDoc;
8420 switch (cur->type) {
8421 case XML_XINCLUDE_START:
8422 case XML_XINCLUDE_END:
8423 /*
8424 * TODO
8425 */
8426 return (-1);
8427 case XML_ELEMENT_NODE:
8428 curElem = cur;
8429 depth++;
8430 /*
8431 * Namespace declarations.
8432 */
8433 if ((ctxt == NULL) && (cur->nsDef != NULL)) {
8434 if (! parnsdone) {
8435 if (destParent && (ctxt == NULL)) {
8436 /*
8437 * Gather @parent's in-scope ns-decls.
8438 */
8439 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8440 destParent) == -1)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008441 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008442 }
8443 parnsdone = 1;
8444 }
8445 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8446 /*
8447 * ns->prefix and ns->href seem not to be in the dict.
8448 * XML_TREE_ADOPT_STR(ns->prefix)
8449 * XML_TREE_ADOPT_STR(ns->href)
8450 */
8451 /*
8452 * Does it shadow any ns-decl?
8453 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008454 if (XML_NSMAP_NOTEMPTY(nsMap)) {
8455 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008456 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8457 (mi->shadowDepth == -1) &&
8458 ((ns->prefix == mi->newNs->prefix) ||
8459 xmlStrEqual(ns->prefix,
8460 mi->newNs->prefix))) {
8461
8462 mi->shadowDepth = depth;
8463 }
8464 }
8465 }
8466 /*
8467 * Push mapping.
8468 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008469 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008470 ns, ns, depth) == NULL)
8471 goto internal_error;
8472 }
8473 }
8474 /* No break on purpose. */
8475 case XML_ATTRIBUTE_NODE:
8476
8477 if (cur->ns == NULL)
8478 goto ns_end;
8479 if (! parnsdone) {
8480 if (destParent && (ctxt == NULL)) {
8481 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8482 destParent) == -1)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008483 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008484 }
8485 parnsdone = 1;
8486 }
8487 /*
8488 * Adopt ns-references.
8489 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008490 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008491 /*
8492 * Search for a mapping.
8493 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008494 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008495 if ((mi->shadowDepth == -1) &&
8496 (cur->ns == mi->oldNs)) {
8497
8498 cur->ns = mi->newNs;
8499 goto ns_end;
8500 }
8501 }
8502 }
8503 /*
8504 * Start searching for an in-scope ns-decl.
8505 */
8506 if (ctxt != NULL) {
8507 /*
8508 * User-defined behaviour.
8509 */
8510#if 0
8511 ctxt->aquireNsDecl(ctxt, cur->ns, &ns);
8512#endif
8513 /*
8514 * Insert mapping if ns is available; it's the users fault
8515 * if not.
8516 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008517 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008518 ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
8519 goto internal_error;
8520 cur->ns = ns;
8521 } else {
8522 /*
8523 * Aquire a normalized ns-decl and add it to the map.
8524 */
8525 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
8526 /* ns-decls on curElem or on destDoc->oldNs */
8527 destParent ? curElem : NULL,
8528 cur->ns, &ns,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008529 &nsMap, depth,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008530 ancestorsOnly,
8531 /* ns-decls must be prefixed for attributes. */
8532 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8533 goto internal_error;
8534 cur->ns = ns;
8535 }
8536ns_end:
8537 /*
8538 * Further node properties.
8539 * TODO: Is this all?
8540 */
8541 XML_TREE_ADOPT_STR(cur->name)
8542 if (cur->type == XML_ELEMENT_NODE) {
8543 cur->psvi = NULL;
8544 cur->line = 0;
8545 cur->extra = 0;
8546 /*
8547 * Walk attributes.
8548 */
8549 if (cur->properties != NULL) {
8550 /*
8551 * Process first attribute node.
8552 */
8553 cur = (xmlNodePtr) cur->properties;
8554 continue;
8555 }
8556 } else {
8557 /*
8558 * Attributes.
8559 */
8560 if ((sourceDoc != NULL) &&
8561 (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID))
8562 xmlRemoveID(sourceDoc, (xmlAttrPtr) cur);
8563 ((xmlAttrPtr) cur)->atype = 0;
8564 ((xmlAttrPtr) cur)->psvi = NULL;
8565 }
8566 break;
8567 case XML_TEXT_NODE:
8568 case XML_CDATA_SECTION_NODE:
8569 /*
8570 * This puts the content in the dest dict, only if
8571 * it was previously in the source dict.
8572 */
8573 XML_TREE_ADOPT_STR_2(cur->content)
8574 goto leave_node;
8575 case XML_ENTITY_REF_NODE:
8576 /*
8577 * Remove reference to the entitity-node.
8578 */
8579 cur->content = NULL;
8580 cur->children = NULL;
8581 cur->last = NULL;
8582 if ((destDoc->intSubset) || (destDoc->extSubset)) {
8583 xmlEntityPtr ent;
8584 /*
8585 * Assign new entity-node if available.
8586 */
8587 ent = xmlGetDocEntity(destDoc, cur->name);
8588 if (ent != NULL) {
8589 cur->content = ent->content;
8590 cur->children = (xmlNodePtr) ent;
8591 cur->last = (xmlNodePtr) ent;
8592 }
8593 }
8594 goto leave_node;
8595 case XML_PI_NODE:
8596 XML_TREE_ADOPT_STR(cur->name)
8597 XML_TREE_ADOPT_STR_2(cur->content)
8598 break;
8599 case XML_COMMENT_NODE:
8600 break;
8601 default:
8602 goto internal_error;
8603 }
8604 /*
8605 * Walk the tree.
8606 */
8607 if (cur->children != NULL) {
8608 cur = cur->children;
8609 continue;
8610 }
8611
8612leave_node:
8613 if (cur == node)
8614 break;
8615 if ((cur->type == XML_ELEMENT_NODE) ||
8616 (cur->type == XML_XINCLUDE_START) ||
8617 (cur->type == XML_XINCLUDE_END)) {
8618 /*
8619 * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
8620 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008621 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008622 /*
8623 * Pop mappings.
8624 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008625 while ((nsMap->last != NULL) &&
8626 (nsMap->last->depth >= depth))
8627 {
8628 XML_NSMAP_POP(nsMap, mi)
8629 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008630 /*
8631 * Unshadow.
8632 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008633 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008634 if (mi->shadowDepth >= depth)
8635 mi->shadowDepth = -1;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008636 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008637 }
8638 depth--;
8639 }
8640 if (cur->next != NULL)
8641 cur = cur->next;
8642 else {
8643 cur = cur->parent;
8644 goto leave_node;
8645 }
8646 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008647
8648 goto exit;
8649
8650internal_error:
8651 ret = -1;
8652
8653exit:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008654 /*
8655 * Cleanup.
8656 */
8657 if (nsMap != NULL)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008658 xmlDOMWrapNsMapFree(nsMap);
8659 return(ret);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008660}
8661
8662/*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008663* xmlDOMWrapCloneNode:
8664* @ctxt: the optional context for custom processing
8665* @sourceDoc: the optional sourceDoc
8666* @node: the node to start with
8667* @resNode: the clone of the given @node
8668* @destDoc: the destination doc
8669* @destParent: the optional new parent of @node in @destDoc
8670* @options: option flags
8671*
8672* References of out-of scope ns-decls are remapped to point to @destDoc:
8673* 1) If @destParent is given, then nsDef entries on element-nodes are used
8674* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used
8675* This is the case when you have an unliked node and just want to move it
8676* to the context of
8677*
8678* If @destParent is given, it ensures that the tree is namespace
8679* wellformed by creating additional ns-decls where needed.
8680* Note that, since prefixes of already existent ns-decls can be
8681* shadowed by this process, it could break QNames in attribute
8682* values or element content.
8683* TODO:
8684* 1) Support dicts
8685* Optimize string adoption for equal or none dicts.
8686* 2) XInclude
8687* WARNING: This function is in a experimental state and should only be currently
8688* only be used to test it.
8689*
8690* Returns 0 if the operation succeeded,
8691* 1 if a node of unsupported (or not yet supported) type was given,
8692* -1 on API/internal errors.
8693*/
8694
8695int
8696xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt,
8697 xmlDocPtr sourceDoc,
8698 xmlNodePtr node,
8699 xmlNodePtr *resNode,
8700 xmlDocPtr destDoc,
8701 xmlNodePtr destParent,
8702 int deep,
8703 int options ATTRIBUTE_UNUSED)
8704{
8705 int ret = 0;
8706 xmlNodePtr cur, curElem = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008707 xmlNsMapPtr nsMap = NULL;
8708 xmlNsMapItemPtr mi;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008709 xmlNsPtr ns;
8710 int depth = -1;
8711 /* int adoptStr = 1; */
8712 /* gather @parent's ns-decls. */
8713 int parnsdone = 0;
8714 /* @ancestorsOnly should be set per option. */
8715 int ancestorsOnly = 0;
8716 xmlNodePtr resultClone = NULL, clone = NULL, parentClone = NULL, prevClone = NULL;
8717 xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008718
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008719 if ((node == NULL) || (resNode == NULL) ||
8720 (sourceDoc == NULL) || (destDoc == NULL))
8721 return(-1);
8722 /*
8723 * TODO: Initially we support only element-nodes.
8724 */
8725 if (node->type != XML_ELEMENT_NODE)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008726 return(1);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008727 /*
8728 * Check node->doc sanity.
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008729 */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008730 if ((node->doc != NULL) && (sourceDoc != NULL) &&
8731 (node->doc != sourceDoc)) {
8732 /*
8733 * Might be an XIncluded node.
8734 */
8735 return (-1);
8736 }
8737 if (sourceDoc == NULL)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008738 sourceDoc = node->doc;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008739
8740 *resNode = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008741
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008742 cur = node;
8743 while (cur != NULL) {
8744 if (cur->doc != sourceDoc) {
8745 /*
8746 * We'll assume XIncluded nodes if the doc differs.
8747 * TODO: Do we need to reconciliate XIncluded nodes?
8748 * TODO: This here returns -1 in this case.
8749 */
8750 goto internal_error;
8751 }
8752 /*
8753 * Create a new node.
8754 */
8755 switch (cur->type) {
8756 case XML_XINCLUDE_START:
8757 case XML_XINCLUDE_END:
8758 /* TODO: What to do with XInclude? */
8759 goto internal_error;
8760 break;
8761 case XML_TEXT_NODE:
8762 case XML_CDATA_SECTION_NODE:
8763 case XML_ELEMENT_NODE:
8764 case XML_DOCUMENT_FRAG_NODE:
8765 case XML_ENTITY_REF_NODE:
8766 case XML_ENTITY_NODE:
8767 case XML_PI_NODE:
8768 case XML_COMMENT_NODE:
8769 /*
8770 * Nodes of xmlNode structure.
8771 */
8772 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
8773 if (clone == NULL) {
8774 xmlTreeErrMemory("xmlDOMWrapCloneBranch(): allocating a node");
8775 goto internal_error;
8776 }
8777 memset(clone, 0, sizeof(xmlNode));
8778 /*
8779 * Set hierachical links.
8780 */
8781 if (resultClone != NULL) {
8782 clone->parent = parentClone;
8783 if (prevClone) {
8784 prevClone->next = clone;
8785 clone->prev = prevClone;
8786 } else
8787 parentClone->children = clone;
8788 } else
8789 resultClone = clone;
8790
8791 break;
8792 case XML_ATTRIBUTE_NODE:
8793 /*
8794 * Attributes (xmlAttr).
8795 */
8796 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlAttr));
8797 if (clone == NULL) {
8798 xmlTreeErrMemory("xmlDOMWrapCloneBranch(): allocating an attr-node");
8799 goto internal_error;
8800 }
8801 memset(clone, 0, sizeof(xmlAttr));
8802 /*
8803 * Set hierachical links.
8804 */
8805 if (resultClone != NULL) {
8806 clone->parent = parentClone;
8807 if (prevClone) {
8808 prevClone->next = clone;
8809 clone->prev = prevClone;
8810 } else
8811 parentClone->properties = (xmlAttrPtr) clone;
8812 } else
8813 resultClone = clone;
8814 break;
8815 default:
8816 /* TODO */
8817 goto internal_error;
8818 }
8819
8820 clone->type = cur->type;
8821 clone->doc = destDoc;
8822
8823 if (cur->name == xmlStringText)
8824 clone->name = xmlStringText;
8825 else if (cur->name == xmlStringTextNoenc)
8826 /*
8827 * TODO: xmlStringTextNoenc is never assigned to a node
8828 * in tree.c.
8829 */
8830 clone->name = xmlStringTextNoenc;
8831 else if (cur->name == xmlStringComment)
8832 clone->name = xmlStringComment;
8833 else if (cur->name != NULL) {
8834 if ((destDoc != NULL) && (destDoc->dict != NULL))
8835 clone->name = xmlDictLookup(destDoc->dict, cur->name, -1);
8836 else
8837 clone->name = xmlStrdup(cur->name);
8838 }
8839
8840 switch (cur->type) {
8841 case XML_XINCLUDE_START:
8842 case XML_XINCLUDE_END:
8843 /*
8844 * TODO
8845 */
8846 return (-1);
8847 case XML_ELEMENT_NODE:
8848 curElem = cur;
8849 depth++;
8850 /*
8851 * Namespace declarations.
8852 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008853 if (cur->nsDef != NULL) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008854 if (! parnsdone) {
8855 if (destParent && (ctxt == NULL)) {
8856 /*
8857 * Gather @parent's in-scope ns-decls.
8858 */
8859 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8860 destParent) == -1)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008861 goto internal_error;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008862 }
8863 parnsdone = 1;
8864 }
8865 /*
8866 * Clone namespace declarations.
8867 */
8868 cloneNsDefSlot = &(clone->nsDef);
8869 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8870 /*
8871 * Create a new xmlNs.
8872 */
8873 cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
8874 if (cloneNs == NULL) {
8875 xmlTreeErrMemory("xmlDOMWrapCloneBranch(): "
8876 "allocating namespace");
8877 return(-1);
8878 }
8879 memset(cloneNs, 0, sizeof(xmlNs));
8880 cloneNs->type = XML_LOCAL_NAMESPACE;
8881
8882 if (ns->href != NULL)
8883 cloneNs->href = xmlStrdup(ns->href);
8884 if (ns->prefix != NULL)
8885 cloneNs->prefix = xmlStrdup(ns->prefix);
8886
8887 *cloneNsDefSlot = cloneNs;
8888 cloneNsDefSlot = &(cloneNs->next);
8889
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008890 if (ctxt == NULL) {
8891 /*
8892 * Does it shadow any ns-decl?
8893 */
8894 if (XML_NSMAP_NOTEMPTY(nsMap)) {
8895 XML_NSMAP_FOREACH(nsMap, mi) {
8896 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8897 (mi->shadowDepth == -1) &&
8898 ((ns->prefix == mi->newNs->prefix) ||
8899 xmlStrEqual(ns->prefix,
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008900 mi->newNs->prefix))) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008901 /*
8902 * Mark as shadowed at the current
8903 * depth.
8904 */
8905 mi->shadowDepth = depth;
8906 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008907 }
8908 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008909 /*
8910 * Push mapping.
8911 */
8912 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
8913 ns, cloneNs, depth) == NULL)
8914 goto internal_error;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008915 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008916 }
8917 }
8918 /* cur->ns will be processed further down. */
8919 break;
8920 case XML_ATTRIBUTE_NODE:
8921 /* IDs will be processed further down. */
8922 /* cur->ns will be processed further down. */
8923 break;
8924 case XML_TEXT_NODE:
8925 case XML_CDATA_SECTION_NODE:
8926 if (cur->content)
8927 clone->content = xmlStrdup(cur->content);
8928 goto leave_node;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008929 case XML_ENTITY_NODE:
8930 /* TODO: What to do here? */
8931 goto leave_node;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008932 case XML_ENTITY_REF_NODE:
8933 if (sourceDoc != destDoc) {
8934 if ((destDoc->intSubset) || (destDoc->extSubset)) {
8935 xmlEntityPtr ent;
8936 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008937 * Different doc: Assign new entity-node if available.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008938 */
8939 ent = xmlGetDocEntity(destDoc, cur->name);
8940 if (ent != NULL) {
8941 clone->content = ent->content;
8942 clone->children = (xmlNodePtr) ent;
8943 clone->last = (xmlNodePtr) ent;
8944 }
8945 }
8946 } else {
8947 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008948 * Same doc: Use the current node's entity declaration
8949 * and value.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008950 */
8951 clone->content = cur->content;
8952 clone->children = cur->children;
8953 clone->last = cur->last;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008954 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008955 goto leave_node;
8956 case XML_PI_NODE:
8957 if (cur->content)
8958 clone->content = xmlStrdup(cur->content);
8959 goto leave_node;
8960 case XML_COMMENT_NODE:
8961 if (cur->content)
8962 clone->content = xmlStrdup(cur->content);
8963 goto leave_node;
8964 default:
8965 goto internal_error;
8966 }
8967
8968 if (cur->ns == NULL)
8969 goto end_ns_reference;
8970
8971/* handle_ns_reference: */
8972 /*
8973 ** The following will take care of references to ns-decls ********
8974 ** and is intended only for element- and attribute-nodes.
8975 **
8976 */
8977 if (! parnsdone) {
8978 if (destParent && (ctxt == NULL)) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008979 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1)
8980 goto internal_error;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008981 }
8982 parnsdone = 1;
8983 }
8984 /*
8985 * Adopt ns-references.
8986 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008987 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008988 /*
8989 * Search for a mapping.
8990 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008991 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008992 if ((mi->shadowDepth == -1) &&
8993 (cur->ns == mi->oldNs)) {
8994 /*
8995 * This is the nice case: a mapping was found.
8996 */
8997 clone->ns = mi->newNs;
8998 goto end_ns_reference;
8999 }
9000 }
9001 }
9002 /*
9003 * Start searching for an in-scope ns-decl.
9004 */
9005 if (ctxt != NULL) {
9006 /*
9007 * User-defined behaviour.
9008 */
9009#if 0
9010 ctxt->aquireNsDecl(ctxt, cur->ns, &ns);
9011#endif
9012 /*
9013 * Add user's mapping.
9014 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009015 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009016 cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
9017 goto internal_error;
9018 clone->ns = ns;
9019 } else {
9020 /*
9021 * Aquire a normalized ns-decl and add it to the map.
9022 */
9023 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
9024 /* ns-decls on curElem or on destDoc->oldNs */
9025 destParent ? curElem : NULL,
9026 cur->ns, &ns,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009027 &nsMap, depth,
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009028 ancestorsOnly,
9029 /* ns-decls must be prefixed for attributes. */
9030 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
9031 goto internal_error;
9032 clone->ns = ns;
9033 }
9034
9035end_ns_reference:
9036
9037 /*
9038 * Some post-processing.
9039 *
9040 * Handle ID attributes.
9041 */
9042 if ((clone->type == XML_ATTRIBUTE_NODE) &&
9043 (clone->parent != NULL)) {
9044 if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) {
9045
9046 xmlChar *idVal;
9047
9048 idVal = xmlNodeListGetString(cur->doc, cur->children, 1);
9049 if (idVal != NULL) {
9050 if (xmlAddID(NULL, destDoc, idVal, (xmlAttrPtr) cur) == NULL) {
9051 /* TODO: error message. */
9052 xmlFree(idVal);
9053 goto internal_error;
9054 }
9055 xmlFree(idVal);
9056 }
9057 }
9058 }
9059 /*
9060 **
9061 ** The following will traversing the tree ************************
9062 **
9063 *
9064 * Walk the element's attributes before descending into child-nodes.
9065 */
9066 if ((cur->type == XML_ELEMENT_NODE) && (cur->properties != NULL)) {
9067 prevClone = NULL;
9068 parentClone = clone;
9069 cur = (xmlNodePtr) cur->properties;
9070 continue;
9071 }
9072into_content:
9073 /*
9074 * Descend into child-nodes.
9075 */
9076 if (cur->children != NULL) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009077 if (deep || (cur->type == XML_ATTRIBUTE_NODE)) {
9078 prevClone = NULL;
9079 parentClone = clone;
9080 cur = cur->children;
9081 continue;
9082 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009083 }
9084
9085leave_node:
9086 /*
9087 * At this point we are done with the node, its content
9088 * and an element-nodes's attribute-nodes.
9089 */
9090 if (cur == node)
9091 break;
9092 if ((cur->type == XML_ELEMENT_NODE) ||
9093 (cur->type == XML_XINCLUDE_START) ||
9094 (cur->type == XML_XINCLUDE_END)) {
9095 /*
9096 * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
9097 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009098 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009099 /*
9100 * Pop mappings.
9101 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009102 while ((nsMap->last != NULL) &&
9103 (nsMap->last->depth >= depth))
9104 {
9105 XML_NSMAP_POP(nsMap, mi)
9106 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009107 /*
9108 * Unshadow.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009109 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009110 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009111 if (mi->shadowDepth >= depth)
9112 mi->shadowDepth = -1;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009113 }
9114 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009115 depth--;
9116 }
9117 if (cur->next != NULL) {
9118 prevClone = clone;
9119 cur = cur->next;
9120 } else if (cur->type != XML_ATTRIBUTE_NODE) {
9121 /*
9122 * Set clone->last.
9123 */
9124 clone->parent->last = clone;
9125 clone = clone->parent;
9126 parentClone = clone->parent;
9127 /*
9128 * Process parent --> next;
9129 */
9130 cur = cur->parent;
9131 goto leave_node;
9132 } else {
9133 /* This is for attributes only. */
9134 clone = clone->parent;
9135 parentClone = clone->parent;
9136 /*
9137 * Process parent-element --> children.
9138 */
9139 cur = cur->parent;
9140 goto into_content;
9141 }
9142 }
9143 goto exit;
9144
9145internal_error:
9146 ret = -1;
9147
9148exit:
9149 /*
9150 * Cleanup.
9151 */
9152 if (nsMap != NULL)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009153 xmlDOMWrapNsMapFree(nsMap);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009154 /*
9155 * TODO: Should we try a cleanup of the cloned node in case of a
9156 * fatal error?
9157 */
9158 *resNode = resultClone;
9159 return (ret);
9160}
9161
9162/*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009163* xmlDOMWrapAdoptAttr:
9164* @ctxt: the optional context for custom processing
9165* @sourceDoc: the optional source document of attr
9166* @attr: the attribute-node to be adopted
9167* @destDoc: the destination doc for adoption
9168* @destParent: the optional new parent of @attr in @destDoc
9169* @options: option flags
9170*
9171* @attr is adopted by @destDoc.
9172* Ensures that ns-references point to @destDoc: either to
9173* elements->nsDef entries if @destParent is given, or to
9174* @destDoc->oldNs otherwise.
9175*
9176* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
9177*/
9178static int
9179xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt,
9180 xmlDocPtr sourceDoc,
9181 xmlAttrPtr attr,
9182 xmlDocPtr destDoc,
9183 xmlNodePtr destParent,
9184 int options ATTRIBUTE_UNUSED)
9185{
9186 xmlNodePtr cur;
9187 int adoptStr = 1;
9188
9189 if ((attr == NULL) || (destDoc == NULL))
9190 return (-1);
9191
9192 attr->doc = destDoc;
9193 if (attr->ns != NULL) {
9194 xmlNsPtr ns = NULL;
9195
9196 if (ctxt != NULL) {
9197 /* TODO: User defined. */
9198 }
9199 /* XML Namespace. */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009200 if (IS_STR_XML(attr->ns->prefix)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009201 ns = xmlTreeEnsureXMLDecl(destDoc);
9202 } else if (destParent == NULL) {
9203 /*
9204 * Store in @destDoc->oldNs.
9205 */
9206 ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix);
9207 } else {
9208 /*
9209 * Declare on @destParent.
9210 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009211 if (xmlSearchNsByNamespaceStrict(destDoc, destParent, attr->ns->href,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009212 &ns, 1) == -1)
9213 goto internal_error;
9214 if (ns == NULL) {
9215 ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent,
9216 attr->ns->href, attr->ns->prefix, 1);
9217 }
9218 }
9219 if (ns == NULL)
9220 goto internal_error;
9221 attr->ns = ns;
9222 }
9223
9224 XML_TREE_ADOPT_STR(attr->name);
9225 attr->atype = 0;
9226 attr->psvi = NULL;
9227 /*
9228 * Walk content.
9229 */
9230 if (attr->children == NULL)
9231 return (0);
9232 cur = attr->children;
9233 while (cur != NULL) {
9234 cur->doc = destDoc;
9235 switch (cur->type) {
9236 case XML_TEXT_NODE:
9237 case XML_CDATA_SECTION_NODE:
9238 XML_TREE_ADOPT_STR_2(cur->content)
9239 break;
9240 case XML_ENTITY_REF_NODE:
9241 /*
9242 * Remove reference to the entitity-node.
9243 */
9244 cur->content = NULL;
9245 cur->children = NULL;
9246 cur->last = NULL;
9247 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9248 xmlEntityPtr ent;
9249 /*
9250 * Assign new entity-node if available.
9251 */
9252 ent = xmlGetDocEntity(destDoc, cur->name);
9253 if (ent != NULL) {
9254 cur->content = ent->content;
9255 cur->children = (xmlNodePtr) ent;
9256 cur->last = (xmlNodePtr) ent;
9257 }
9258 }
9259 break;
9260 default:
9261 break;
9262 }
9263 if (cur->children != NULL) {
9264 cur = cur->children;
9265 continue;
9266 }
9267next_sibling:
9268 if (cur == (xmlNodePtr) attr)
9269 break;
9270 if (cur->next != NULL)
9271 cur = cur->next;
9272 else {
9273 cur = cur->parent;
9274 goto next_sibling;
9275 }
9276 }
9277 return (0);
9278internal_error:
9279 return (-1);
9280}
9281
9282/*
9283* xmlDOMWrapAdoptNode:
9284* @ctxt: the optional context for custom processing
9285* @sourceDoc: the optional sourceDoc
9286* @node: the node to start with
9287* @destDoc: the destination doc
Kasimier T. Buchcik4d9c9482005-06-27 15:04:46 +00009288* @destParent: the optional new parent of @node in @destDoc
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009289* @options: option flags
9290*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009291* References of out-of scope ns-decls are remapped to point to @destDoc:
9292* 1) If @destParent is given, then nsDef entries on element-nodes are used
9293* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used
9294* This is the case when you have an unliked node and just want to move it
9295* to the context of
9296*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009297* If @destParent is given, it ensures that the tree is namespace
9298* wellformed by creating additional ns-decls where needed.
9299* Note that, since prefixes of already existent ns-decls can be
9300* shadowed by this process, it could break QNames in attribute
9301* values or element content.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00009302* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009303*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009304* Returns 0 if the operation succeeded,
9305* 1 if a node of unsupported type was given,
9306* 2 if a node of not yet supported type was given and
9307* -1 on API/internal errors.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009308*/
9309int
9310xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt,
9311 xmlDocPtr sourceDoc,
9312 xmlNodePtr node,
9313 xmlDocPtr destDoc,
9314 xmlNodePtr destParent,
9315 int options)
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009316{
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009317 if ((node == NULL) || (destDoc == NULL) ||
9318 ((destParent != NULL) && (destParent->doc != destDoc)))
9319 return(-1);
9320 /*
9321 * Check node->doc sanity.
9322 */
9323 if ((node->doc != NULL) && (sourceDoc != NULL) &&
9324 (node->doc != sourceDoc)) {
9325 /*
9326 * Might be an XIncluded node.
9327 */
9328 return (-1);
9329 }
9330 if (sourceDoc == NULL)
9331 sourceDoc = node->doc;
9332 if (sourceDoc == destDoc)
9333 return (-1);
9334 switch (node->type) {
9335 case XML_ELEMENT_NODE:
9336 case XML_ATTRIBUTE_NODE:
9337 case XML_TEXT_NODE:
9338 case XML_CDATA_SECTION_NODE:
9339 case XML_ENTITY_REF_NODE:
9340 case XML_PI_NODE:
9341 case XML_COMMENT_NODE:
9342 break;
9343 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009344 /* TODO: Support document-fragment-nodes. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009345 return (2);
9346 default:
9347 return (1);
9348 }
9349 /*
9350 * Unlink only if @node was not already added to @destParent.
9351 */
9352 if ((node->parent != NULL) && (destParent != node->parent))
9353 xmlUnlinkNode(node);
9354
9355 if (node->type == XML_ELEMENT_NODE) {
9356 return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node,
9357 destDoc, destParent, options));
9358 } else if (node->type == XML_ATTRIBUTE_NODE) {
9359 return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc,
9360 (xmlAttrPtr) node, destDoc, destParent, options));
9361 } else {
9362 xmlNodePtr cur = node;
9363 int adoptStr = 1;
9364
9365 cur->doc = destDoc;
9366 /*
9367 * Optimize string adoption.
9368 */
9369 if ((sourceDoc != NULL) &&
9370 (sourceDoc->dict == destDoc->dict))
9371 adoptStr = 0;
9372 switch (node->type) {
9373 case XML_TEXT_NODE:
9374 case XML_CDATA_SECTION_NODE:
9375 XML_TREE_ADOPT_STR_2(node->content)
9376 break;
9377 case XML_ENTITY_REF_NODE:
9378 /*
9379 * Remove reference to the entitity-node.
9380 */
9381 node->content = NULL;
9382 node->children = NULL;
9383 node->last = NULL;
9384 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9385 xmlEntityPtr ent;
9386 /*
9387 * Assign new entity-node if available.
9388 */
9389 ent = xmlGetDocEntity(destDoc, node->name);
9390 if (ent != NULL) {
9391 node->content = ent->content;
9392 node->children = (xmlNodePtr) ent;
9393 node->last = (xmlNodePtr) ent;
9394 }
9395 }
9396 XML_TREE_ADOPT_STR(node->name)
9397 break;
Daniel Veillard7e21fd12005-07-03 21:44:07 +00009398 case XML_PI_NODE: {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009399 XML_TREE_ADOPT_STR(node->name)
9400 XML_TREE_ADOPT_STR_2(node->content)
9401 break;
Daniel Veillard7e21fd12005-07-03 21:44:07 +00009402 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009403 default:
9404 break;
9405 }
9406 }
9407 return (0);
9408}
9409
Daniel Veillard5d4644e2005-04-01 13:11:58 +00009410#define bottom_tree
9411#include "elfgcchack.h"