blob: 1da8400cf071df044c995b4ea293511bb707f8a2 [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
122/* #define DEBUG_BUFFER */
123/* #define DEBUG_TREE */
124
125/************************************************************************
126 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000127 * Functions to move to entities.c once the *
128 * API freeze is smoothen and they can be made public. *
129 * *
130 ************************************************************************/
131#include <libxml/hash.h>
132
Daniel Veillard652327a2003-09-29 18:02:38 +0000133#ifdef LIBXML_TREE_ENABLED
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000134/**
135 * xmlGetEntityFromDtd:
136 * @dtd: A pointer to the DTD to search
137 * @name: The entity name
138 *
139 * Do an entity lookup in the DTD entity hash table and
140 * return the corresponding entity, if found.
141 *
142 * Returns A pointer to the entity structure or NULL if not found.
143 */
144static xmlEntityPtr
145xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
146 xmlEntitiesTablePtr table;
147
148 if((dtd != NULL) && (dtd->entities != NULL)) {
149 table = (xmlEntitiesTablePtr) dtd->entities;
150 return((xmlEntityPtr) xmlHashLookup(table, name));
151 /* return(xmlGetEntityFromTable(table, name)); */
152 }
153 return(NULL);
154}
155/**
156 * xmlGetParameterEntityFromDtd:
157 * @dtd: A pointer to the DTD to search
158 * @name: The entity name
159 *
160 * Do an entity lookup in the DTD pararmeter entity hash table and
161 * return the corresponding entity, if found.
162 *
163 * Returns A pointer to the entity structure or NULL if not found.
164 */
165static xmlEntityPtr
166xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
167 xmlEntitiesTablePtr table;
168
169 if ((dtd != NULL) && (dtd->pentities != NULL)) {
170 table = (xmlEntitiesTablePtr) dtd->pentities;
171 return((xmlEntityPtr) xmlHashLookup(table, name));
172 /* return(xmlGetEntityFromTable(table, name)); */
173 }
174 return(NULL);
175}
Daniel Veillard652327a2003-09-29 18:02:38 +0000176#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000177
178/************************************************************************
179 * *
Daniel Veillardc00cda82003-04-07 10:22:39 +0000180 * QName handling helper *
181 * *
182 ************************************************************************/
183
184/**
185 * xmlBuildQName:
186 * @ncname: the Name
187 * @prefix: the prefix
188 * @memory: preallocated memory
189 * @len: preallocated memory length
190 *
191 * Builds the QName @prefix:@ncname in @memory if there is enough space
192 * and prefix is not NULL nor empty, otherwise allocate a new string.
193 * If prefix is NULL or empty it returns ncname.
194 *
195 * Returns the new string which must be freed by the caller if different from
196 * @memory and @ncname or NULL in case of error
197 */
198xmlChar *
199xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
200 xmlChar *memory, int len) {
201 int lenn, lenp;
202 xmlChar *ret;
203
Daniel Veillard3b7840c2003-09-11 23:42:01 +0000204 if (ncname == NULL) return(NULL);
205 if (prefix == NULL) return((xmlChar *) ncname);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000206
207 lenn = strlen((char *) ncname);
208 lenp = strlen((char *) prefix);
209
210 if ((memory == NULL) || (len < lenn + lenp + 2)) {
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000211 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000212 if (ret == NULL) {
213 xmlTreeErrMemory("building QName");
214 return(NULL);
215 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000216 } else {
217 ret = memory;
218 }
219 memcpy(&ret[0], prefix, lenp);
220 ret[lenp] = ':';
221 memcpy(&ret[lenp + 1], ncname, lenn);
222 ret[lenn + lenp + 1] = 0;
223 return(ret);
224}
225
226/**
227 * xmlSplitQName2:
228 * @name: the full QName
229 * @prefix: a xmlChar **
230 *
231 * parse an XML qualified name string
232 *
233 * [NS 5] QName ::= (Prefix ':')? LocalPart
234 *
235 * [NS 6] Prefix ::= NCName
236 *
237 * [NS 7] LocalPart ::= NCName
238 *
239 * Returns NULL if not a QName, otherwise the local part, and prefix
240 * is updated to get the Prefix if any.
241 */
242
243xmlChar *
244xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
245 int len = 0;
246 xmlChar *ret = NULL;
247
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000248 if (prefix == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000249 *prefix = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000250 if (name == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000251
252#ifndef XML_XML_NAMESPACE
253 /* xml: prefix is not really a namespace */
254 if ((name[0] == 'x') && (name[1] == 'm') &&
255 (name[2] == 'l') && (name[3] == ':'))
256 return(NULL);
257#endif
258
259 /* nasty but valid */
260 if (name[0] == ':')
261 return(NULL);
262
263 /*
264 * we are not trying to validate but just to cut, and yes it will
265 * work even if this is as set of UTF-8 encoded chars
266 */
267 while ((name[len] != 0) && (name[len] != ':'))
268 len++;
269
270 if (name[len] == 0)
271 return(NULL);
272
273 *prefix = xmlStrndup(name, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000274 if (*prefix == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000275 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000276 return(NULL);
277 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000278 ret = xmlStrdup(&name[len + 1]);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000279 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000280 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000281 if (*prefix != NULL) {
282 xmlFree(*prefix);
283 *prefix = NULL;
284 }
285 return(NULL);
286 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000287
288 return(ret);
289}
290
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000291/**
292 * xmlSplitQName3:
293 * @name: the full QName
294 * @len: an int *
295 *
296 * parse an XML qualified name string,i
297 *
298 * returns NULL if it is not a Qualified Name, otherwise, update len
299 * with the lenght in byte of the prefix and return a pointer
300 */
301
302const xmlChar *
303xmlSplitQName3(const xmlChar *name, int *len) {
304 int l = 0;
305
306 if (name == NULL) return(NULL);
307 if (len == NULL) return(NULL);
308
309 /* nasty but valid */
310 if (name[0] == ':')
311 return(NULL);
312
313 /*
314 * we are not trying to validate but just to cut, and yes it will
315 * work even if this is as set of UTF-8 encoded chars
316 */
317 while ((name[l] != 0) && (name[l] != ':'))
318 l++;
319
320 if (name[l] == 0)
321 return(NULL);
322
323 *len = l;
324
325 return(&name[l+1]);
326}
327
Daniel Veillardc00cda82003-04-07 10:22:39 +0000328/************************************************************************
329 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000330 * Check Name, NCName and QName strings *
331 * *
332 ************************************************************************/
333
334#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
335
Daniel Veillard6b6d6802005-07-03 21:00:34 +0000336#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 +0000337/**
338 * xmlValidateNCName:
339 * @value: the value to check
340 * @space: allow spaces in front and end of the string
341 *
342 * Check that a value conforms to the lexical space of NCName
343 *
344 * Returns 0 if this validates, a positive error code number otherwise
345 * and -1 in case of internal or API error.
346 */
347int
348xmlValidateNCName(const xmlChar *value, int space) {
349 const xmlChar *cur = value;
350 int c,l;
351
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000352 if (value == NULL)
353 return(-1);
354
Daniel Veillardd2298792003-02-14 16:54:11 +0000355 /*
356 * First quick algorithm for ASCII range
357 */
358 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000359 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000360 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
361 (*cur == '_'))
362 cur++;
363 else
364 goto try_complex;
365 while (((*cur >= 'a') && (*cur <= 'z')) ||
366 ((*cur >= 'A') && (*cur <= 'Z')) ||
367 ((*cur >= '0') && (*cur <= '9')) ||
368 (*cur == '_') || (*cur == '-') || (*cur == '.'))
369 cur++;
370 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000371 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000372 if (*cur == 0)
373 return(0);
374
375try_complex:
376 /*
377 * Second check for chars outside the ASCII range
378 */
379 cur = value;
380 c = CUR_SCHAR(cur, l);
381 if (space) {
382 while (IS_BLANK(c)) {
383 cur += l;
384 c = CUR_SCHAR(cur, l);
385 }
386 }
William M. Brack871611b2003-10-18 04:53:14 +0000387 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000388 return(1);
389 cur += l;
390 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000391 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
392 (c == '-') || (c == '_') || IS_COMBINING(c) ||
393 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000394 cur += l;
395 c = CUR_SCHAR(cur, l);
396 }
397 if (space) {
398 while (IS_BLANK(c)) {
399 cur += l;
400 c = CUR_SCHAR(cur, l);
401 }
402 }
403 if (c != 0)
404 return(1);
405
406 return(0);
407}
Daniel Veillard2156d432004-03-04 15:59:36 +0000408#endif
Daniel Veillardd2298792003-02-14 16:54:11 +0000409
Daniel Veillard2156d432004-03-04 15:59:36 +0000410#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000411/**
412 * xmlValidateQName:
413 * @value: the value to check
414 * @space: allow spaces in front and end of the string
415 *
416 * Check that a value conforms to the lexical space of QName
417 *
418 * Returns 0 if this validates, a positive error code number otherwise
419 * and -1 in case of internal or API error.
420 */
421int
422xmlValidateQName(const xmlChar *value, int space) {
423 const xmlChar *cur = value;
424 int c,l;
425
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000426 if (value == NULL)
427 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +0000428 /*
429 * First quick algorithm for ASCII range
430 */
431 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000432 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000433 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
434 (*cur == '_'))
435 cur++;
436 else
437 goto try_complex;
438 while (((*cur >= 'a') && (*cur <= 'z')) ||
439 ((*cur >= 'A') && (*cur <= 'Z')) ||
440 ((*cur >= '0') && (*cur <= '9')) ||
441 (*cur == '_') || (*cur == '-') || (*cur == '.'))
442 cur++;
443 if (*cur == ':') {
444 cur++;
445 if (((*cur >= 'a') && (*cur <= 'z')) ||
446 ((*cur >= 'A') && (*cur <= 'Z')) ||
447 (*cur == '_'))
448 cur++;
449 else
450 goto try_complex;
451 while (((*cur >= 'a') && (*cur <= 'z')) ||
452 ((*cur >= 'A') && (*cur <= 'Z')) ||
453 ((*cur >= '0') && (*cur <= '9')) ||
454 (*cur == '_') || (*cur == '-') || (*cur == '.'))
455 cur++;
456 }
457 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000458 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000459 if (*cur == 0)
460 return(0);
461
462try_complex:
463 /*
464 * Second check for chars outside the ASCII range
465 */
466 cur = value;
467 c = CUR_SCHAR(cur, l);
468 if (space) {
469 while (IS_BLANK(c)) {
470 cur += l;
471 c = CUR_SCHAR(cur, l);
472 }
473 }
William M. Brack871611b2003-10-18 04:53:14 +0000474 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000475 return(1);
476 cur += l;
477 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000478 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
479 (c == '-') || (c == '_') || IS_COMBINING(c) ||
480 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000481 cur += l;
482 c = CUR_SCHAR(cur, l);
483 }
484 if (c == ':') {
485 cur += l;
486 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000487 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000488 return(1);
489 cur += l;
490 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000491 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
492 (c == '-') || (c == '_') || IS_COMBINING(c) ||
493 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000494 cur += l;
495 c = CUR_SCHAR(cur, l);
496 }
497 }
498 if (space) {
499 while (IS_BLANK(c)) {
500 cur += l;
501 c = CUR_SCHAR(cur, l);
502 }
503 }
504 if (c != 0)
505 return(1);
506 return(0);
507}
508
509/**
510 * xmlValidateName:
511 * @value: the value to check
512 * @space: allow spaces in front and end of the string
513 *
514 * Check that a value conforms to the lexical space of Name
515 *
516 * Returns 0 if this validates, a positive error code number otherwise
517 * and -1 in case of internal or API error.
518 */
519int
520xmlValidateName(const xmlChar *value, int space) {
521 const xmlChar *cur = value;
522 int c,l;
523
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000524 if (value == NULL)
525 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +0000526 /*
527 * First quick algorithm for ASCII range
528 */
529 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000530 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000531 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
532 (*cur == '_') || (*cur == ':'))
533 cur++;
534 else
535 goto try_complex;
536 while (((*cur >= 'a') && (*cur <= 'z')) ||
537 ((*cur >= 'A') && (*cur <= 'Z')) ||
538 ((*cur >= '0') && (*cur <= '9')) ||
539 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
540 cur++;
541 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000542 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000543 if (*cur == 0)
544 return(0);
545
546try_complex:
547 /*
548 * Second check for chars outside the ASCII range
549 */
550 cur = value;
551 c = CUR_SCHAR(cur, l);
552 if (space) {
553 while (IS_BLANK(c)) {
554 cur += l;
555 c = CUR_SCHAR(cur, l);
556 }
557 }
William M. Brack871611b2003-10-18 04:53:14 +0000558 if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000559 return(1);
560 cur += l;
561 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000562 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
563 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000564 cur += l;
565 c = CUR_SCHAR(cur, l);
566 }
567 if (space) {
568 while (IS_BLANK(c)) {
569 cur += l;
570 c = CUR_SCHAR(cur, l);
571 }
572 }
573 if (c != 0)
574 return(1);
575 return(0);
576}
577
Daniel Veillardd4310742003-02-18 21:12:46 +0000578/**
579 * xmlValidateNMToken:
580 * @value: the value to check
581 * @space: allow spaces in front and end of the string
582 *
583 * Check that a value conforms to the lexical space of NMToken
584 *
585 * Returns 0 if this validates, a positive error code number otherwise
586 * and -1 in case of internal or API error.
587 */
588int
589xmlValidateNMToken(const xmlChar *value, int space) {
590 const xmlChar *cur = value;
591 int c,l;
592
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000593 if (value == NULL)
594 return(-1);
Daniel Veillardd4310742003-02-18 21:12:46 +0000595 /*
596 * First quick algorithm for ASCII range
597 */
598 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000599 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000600 if (((*cur >= 'a') && (*cur <= 'z')) ||
601 ((*cur >= 'A') && (*cur <= 'Z')) ||
602 ((*cur >= '0') && (*cur <= '9')) ||
603 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
604 cur++;
605 else
606 goto try_complex;
607 while (((*cur >= 'a') && (*cur <= 'z')) ||
608 ((*cur >= 'A') && (*cur <= 'Z')) ||
609 ((*cur >= '0') && (*cur <= '9')) ||
610 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
611 cur++;
612 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000613 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000614 if (*cur == 0)
615 return(0);
616
617try_complex:
618 /*
619 * Second check for chars outside the ASCII range
620 */
621 cur = value;
622 c = CUR_SCHAR(cur, l);
623 if (space) {
624 while (IS_BLANK(c)) {
625 cur += l;
626 c = CUR_SCHAR(cur, l);
627 }
628 }
William M. Brack871611b2003-10-18 04:53:14 +0000629 if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
630 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
Daniel Veillardd4310742003-02-18 21:12:46 +0000631 return(1);
632 cur += l;
633 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000634 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
635 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd4310742003-02-18 21:12:46 +0000636 cur += l;
637 c = CUR_SCHAR(cur, l);
638 }
639 if (space) {
640 while (IS_BLANK(c)) {
641 cur += l;
642 c = CUR_SCHAR(cur, l);
643 }
644 }
645 if (c != 0)
646 return(1);
647 return(0);
648}
Daniel Veillard652327a2003-09-29 18:02:38 +0000649#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardd4310742003-02-18 21:12:46 +0000650
Daniel Veillardd2298792003-02-14 16:54:11 +0000651/************************************************************************
652 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000653 * Allocation and deallocation of basic structures *
654 * *
655 ************************************************************************/
656
657/**
658 * xmlSetBufferAllocationScheme:
659 * @scheme: allocation method to use
660 *
661 * Set the buffer allocation method. Types are
662 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
663 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
664 * improves performance
665 */
666void
667xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
668 xmlBufferAllocScheme = scheme;
669}
670
671/**
672 * xmlGetBufferAllocationScheme:
673 *
674 * Types are
675 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
676 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
677 * improves performance
678 *
679 * Returns the current allocation scheme
680 */
681xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000682xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000683 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000684}
685
686/**
687 * xmlNewNs:
688 * @node: the element carrying the namespace
689 * @href: the URI associated
690 * @prefix: the prefix for the namespace
691 *
692 * Creation of a new Namespace. This function will refuse to create
693 * a namespace with a similar prefix than an existing one present on this
694 * node.
695 * We use href==NULL in the case of an element creation where the namespace
696 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000697 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000698 */
699xmlNsPtr
700xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
701 xmlNsPtr cur;
702
703 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
704 return(NULL);
705
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000706 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
707 return(NULL);
708
Owen Taylor3473f882001-02-23 17:55:21 +0000709 /*
710 * Allocate a new Namespace and fill the fields.
711 */
712 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
713 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000714 xmlTreeErrMemory("building namespace");
Owen Taylor3473f882001-02-23 17:55:21 +0000715 return(NULL);
716 }
717 memset(cur, 0, sizeof(xmlNs));
718 cur->type = XML_LOCAL_NAMESPACE;
719
720 if (href != NULL)
721 cur->href = xmlStrdup(href);
722 if (prefix != NULL)
723 cur->prefix = xmlStrdup(prefix);
724
725 /*
726 * Add it at the end to preserve parsing order ...
727 * and checks for existing use of the prefix
728 */
729 if (node != NULL) {
730 if (node->nsDef == NULL) {
731 node->nsDef = cur;
732 } else {
733 xmlNsPtr prev = node->nsDef;
734
735 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
736 (xmlStrEqual(prev->prefix, cur->prefix))) {
737 xmlFreeNs(cur);
738 return(NULL);
739 }
740 while (prev->next != NULL) {
741 prev = prev->next;
742 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
743 (xmlStrEqual(prev->prefix, cur->prefix))) {
744 xmlFreeNs(cur);
745 return(NULL);
746 }
747 }
748 prev->next = cur;
749 }
750 }
751 return(cur);
752}
753
754/**
755 * xmlSetNs:
756 * @node: a node in the document
757 * @ns: a namespace pointer
758 *
759 * Associate a namespace to a node, a posteriori.
760 */
761void
762xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
763 if (node == NULL) {
764#ifdef DEBUG_TREE
765 xmlGenericError(xmlGenericErrorContext,
766 "xmlSetNs: node == NULL\n");
767#endif
768 return;
769 }
770 node->ns = ns;
771}
772
773/**
774 * xmlFreeNs:
775 * @cur: the namespace pointer
776 *
777 * Free up the structures associated to a namespace
778 */
779void
780xmlFreeNs(xmlNsPtr cur) {
781 if (cur == NULL) {
782#ifdef DEBUG_TREE
783 xmlGenericError(xmlGenericErrorContext,
784 "xmlFreeNs : ns == NULL\n");
785#endif
786 return;
787 }
788 if (cur->href != NULL) xmlFree((char *) cur->href);
789 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000790 xmlFree(cur);
791}
792
793/**
794 * xmlFreeNsList:
795 * @cur: the first namespace pointer
796 *
797 * Free up all the structures associated to the chained namespaces.
798 */
799void
800xmlFreeNsList(xmlNsPtr cur) {
801 xmlNsPtr next;
802 if (cur == NULL) {
803#ifdef DEBUG_TREE
804 xmlGenericError(xmlGenericErrorContext,
805 "xmlFreeNsList : ns == NULL\n");
806#endif
807 return;
808 }
809 while (cur != NULL) {
810 next = cur->next;
811 xmlFreeNs(cur);
812 cur = next;
813 }
814}
815
816/**
817 * xmlNewDtd:
818 * @doc: the document pointer
819 * @name: the DTD name
820 * @ExternalID: the external ID
821 * @SystemID: the system ID
822 *
823 * Creation of a new DTD for the external subset. To create an
824 * internal subset, use xmlCreateIntSubset().
825 *
826 * Returns a pointer to the new DTD structure
827 */
828xmlDtdPtr
829xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
830 const xmlChar *ExternalID, const xmlChar *SystemID) {
831 xmlDtdPtr cur;
832
833 if ((doc != NULL) && (doc->extSubset != NULL)) {
834#ifdef DEBUG_TREE
835 xmlGenericError(xmlGenericErrorContext,
836 "xmlNewDtd(%s): document %s already have a DTD %s\n",
837 /* !!! */ (char *) name, doc->name,
838 /* !!! */ (char *)doc->extSubset->name);
839#endif
840 return(NULL);
841 }
842
843 /*
844 * Allocate a new DTD and fill the fields.
845 */
846 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
847 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000848 xmlTreeErrMemory("building DTD");
Owen Taylor3473f882001-02-23 17:55:21 +0000849 return(NULL);
850 }
851 memset(cur, 0 , sizeof(xmlDtd));
852 cur->type = XML_DTD_NODE;
853
854 if (name != NULL)
855 cur->name = xmlStrdup(name);
856 if (ExternalID != NULL)
857 cur->ExternalID = xmlStrdup(ExternalID);
858 if (SystemID != NULL)
859 cur->SystemID = xmlStrdup(SystemID);
860 if (doc != NULL)
861 doc->extSubset = cur;
862 cur->doc = doc;
863
Daniel Veillarda880b122003-04-21 21:36:41 +0000864 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000865 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000866 return(cur);
867}
868
869/**
870 * xmlGetIntSubset:
871 * @doc: the document pointer
872 *
873 * Get the internal subset of a document
874 * Returns a pointer to the DTD structure or NULL if not found
875 */
876
877xmlDtdPtr
878xmlGetIntSubset(xmlDocPtr doc) {
879 xmlNodePtr cur;
880
881 if (doc == NULL)
882 return(NULL);
883 cur = doc->children;
884 while (cur != NULL) {
885 if (cur->type == XML_DTD_NODE)
886 return((xmlDtdPtr) cur);
887 cur = cur->next;
888 }
889 return((xmlDtdPtr) doc->intSubset);
890}
891
892/**
893 * xmlCreateIntSubset:
894 * @doc: the document pointer
895 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000896 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000897 * @SystemID: the system ID
898 *
899 * Create the internal subset of a document
900 * Returns a pointer to the new DTD structure
901 */
902xmlDtdPtr
903xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
904 const xmlChar *ExternalID, const xmlChar *SystemID) {
905 xmlDtdPtr cur;
906
907 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
908#ifdef DEBUG_TREE
909 xmlGenericError(xmlGenericErrorContext,
910
911 "xmlCreateIntSubset(): document %s already have an internal subset\n",
912 doc->name);
913#endif
914 return(NULL);
915 }
916
917 /*
918 * Allocate a new DTD and fill the fields.
919 */
920 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
921 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000922 xmlTreeErrMemory("building internal subset");
Owen Taylor3473f882001-02-23 17:55:21 +0000923 return(NULL);
924 }
925 memset(cur, 0, sizeof(xmlDtd));
926 cur->type = XML_DTD_NODE;
927
William M. Bracka3215c72004-07-31 16:24:01 +0000928 if (name != NULL) {
929 cur->name = xmlStrdup(name);
930 if (cur->name == NULL) {
931 xmlTreeErrMemory("building internal subset");
932 xmlFree(cur);
933 return(NULL);
934 }
935 }
936 if (ExternalID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000937 cur->ExternalID = xmlStrdup(ExternalID);
William M. Bracka3215c72004-07-31 16:24:01 +0000938 if (cur->ExternalID == NULL) {
939 xmlTreeErrMemory("building internal subset");
940 if (cur->name != NULL)
941 xmlFree((char *)cur->name);
942 xmlFree(cur);
943 return(NULL);
944 }
945 }
946 if (SystemID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000947 cur->SystemID = xmlStrdup(SystemID);
William M. Bracka3215c72004-07-31 16:24:01 +0000948 if (cur->SystemID == NULL) {
949 xmlTreeErrMemory("building internal subset");
950 if (cur->name != NULL)
951 xmlFree((char *)cur->name);
952 if (cur->ExternalID != NULL)
953 xmlFree((char *)cur->ExternalID);
954 xmlFree(cur);
955 return(NULL);
956 }
957 }
Owen Taylor3473f882001-02-23 17:55:21 +0000958 if (doc != NULL) {
959 doc->intSubset = cur;
960 cur->parent = doc;
961 cur->doc = doc;
962 if (doc->children == NULL) {
963 doc->children = (xmlNodePtr) cur;
964 doc->last = (xmlNodePtr) cur;
965 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000966 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000967 xmlNodePtr prev;
968
Owen Taylor3473f882001-02-23 17:55:21 +0000969 prev = doc->children;
970 prev->prev = (xmlNodePtr) cur;
971 cur->next = prev;
972 doc->children = (xmlNodePtr) cur;
973 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000974 xmlNodePtr next;
975
976 next = doc->children;
977 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
978 next = next->next;
979 if (next == NULL) {
980 cur->prev = doc->last;
981 cur->prev->next = (xmlNodePtr) cur;
982 cur->next = NULL;
983 doc->last = (xmlNodePtr) cur;
984 } else {
985 cur->next = next;
986 cur->prev = next->prev;
987 if (cur->prev == NULL)
988 doc->children = (xmlNodePtr) cur;
989 else
990 cur->prev->next = (xmlNodePtr) cur;
991 next->prev = (xmlNodePtr) cur;
992 }
Owen Taylor3473f882001-02-23 17:55:21 +0000993 }
994 }
995 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000996
Daniel Veillarda880b122003-04-21 21:36:41 +0000997 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000998 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000999 return(cur);
1000}
1001
1002/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001003 * DICT_FREE:
1004 * @str: a string
1005 *
1006 * Free a string if it is not owned by the "dict" dictionnary in the
1007 * current scope
1008 */
1009#define DICT_FREE(str) \
1010 if ((str) && ((!dict) || \
1011 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
1012 xmlFree((char *)(str));
1013
1014/**
Owen Taylor3473f882001-02-23 17:55:21 +00001015 * xmlFreeDtd:
1016 * @cur: the DTD structure to free up
1017 *
1018 * Free a DTD structure.
1019 */
1020void
1021xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001022 xmlDictPtr dict = NULL;
1023
Owen Taylor3473f882001-02-23 17:55:21 +00001024 if (cur == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001025 return;
1026 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001027 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001028
Daniel Veillarda880b122003-04-21 21:36:41 +00001029 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001030 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1031
Owen Taylor3473f882001-02-23 17:55:21 +00001032 if (cur->children != NULL) {
1033 xmlNodePtr next, c = cur->children;
1034
1035 /*
William M. Brack18a04f22004-08-03 16:42:37 +00001036 * Cleanup all nodes which are not part of the specific lists
1037 * of notations, elements, attributes and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00001038 */
1039 while (c != NULL) {
1040 next = c->next;
William M. Brack18a04f22004-08-03 16:42:37 +00001041 if ((c->type != XML_NOTATION_NODE) &&
1042 (c->type != XML_ELEMENT_DECL) &&
1043 (c->type != XML_ATTRIBUTE_DECL) &&
1044 (c->type != XML_ENTITY_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001045 xmlUnlinkNode(c);
1046 xmlFreeNode(c);
1047 }
1048 c = next;
1049 }
1050 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001051 DICT_FREE(cur->name)
1052 DICT_FREE(cur->SystemID)
1053 DICT_FREE(cur->ExternalID)
Owen Taylor3473f882001-02-23 17:55:21 +00001054 /* TODO !!! */
1055 if (cur->notations != NULL)
1056 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1057
1058 if (cur->elements != NULL)
1059 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1060 if (cur->attributes != NULL)
1061 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1062 if (cur->entities != NULL)
1063 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1064 if (cur->pentities != NULL)
1065 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1066
Owen Taylor3473f882001-02-23 17:55:21 +00001067 xmlFree(cur);
1068}
1069
1070/**
1071 * xmlNewDoc:
1072 * @version: xmlChar string giving the version of XML "1.0"
1073 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001074 * Creates a new XML document
1075 *
Owen Taylor3473f882001-02-23 17:55:21 +00001076 * Returns a new document
1077 */
1078xmlDocPtr
1079xmlNewDoc(const xmlChar *version) {
1080 xmlDocPtr cur;
1081
1082 if (version == NULL)
1083 version = (const xmlChar *) "1.0";
1084
1085 /*
1086 * Allocate a new document and fill the fields.
1087 */
1088 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1089 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001090 xmlTreeErrMemory("building doc");
Owen Taylor3473f882001-02-23 17:55:21 +00001091 return(NULL);
1092 }
1093 memset(cur, 0, sizeof(xmlDoc));
1094 cur->type = XML_DOCUMENT_NODE;
1095
1096 cur->version = xmlStrdup(version);
William M. Bracka3215c72004-07-31 16:24:01 +00001097 if (cur->version == NULL) {
1098 xmlTreeErrMemory("building doc");
1099 xmlFree(cur);
1100 return(NULL);
1101 }
Owen Taylor3473f882001-02-23 17:55:21 +00001102 cur->standalone = -1;
1103 cur->compression = -1; /* not initialized */
1104 cur->doc = cur;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001105 /*
1106 * The in memory encoding is always UTF8
1107 * This field will never change and would
1108 * be obsolete if not for binary compatibility.
1109 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001110 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001111
Daniel Veillarda880b122003-04-21 21:36:41 +00001112 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001113 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001114 return(cur);
1115}
1116
1117/**
1118 * xmlFreeDoc:
1119 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001120 *
1121 * Free up all the structures used by a document, tree included.
1122 */
1123void
1124xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001125 xmlDtdPtr extSubset, intSubset;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001126 xmlDictPtr dict = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001127
Owen Taylor3473f882001-02-23 17:55:21 +00001128 if (cur == NULL) {
1129#ifdef DEBUG_TREE
1130 xmlGenericError(xmlGenericErrorContext,
1131 "xmlFreeDoc : document == NULL\n");
1132#endif
1133 return;
1134 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001135#ifdef LIBXML_DEBUG_RUNTIME
Daniel Veillardbca3ad22005-08-23 22:14:02 +00001136#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001137 xmlDebugCheckDocument(stderr, cur);
1138#endif
Daniel Veillardbca3ad22005-08-23 22:14:02 +00001139#endif
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001140
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001141 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001142
Daniel Veillarda880b122003-04-21 21:36:41 +00001143 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001144 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1145
Daniel Veillard76d66f42001-05-16 21:05:17 +00001146 /*
1147 * Do this before freeing the children list to avoid ID lookups
1148 */
1149 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1150 cur->ids = NULL;
1151 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1152 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001153 extSubset = cur->extSubset;
1154 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001155 if (intSubset == extSubset)
1156 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001157 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001158 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001159 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001160 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001161 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001162 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001163 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001164 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001165 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001166 }
1167
1168 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001169 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001170
1171 DICT_FREE(cur->version)
1172 DICT_FREE(cur->name)
1173 DICT_FREE(cur->encoding)
1174 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001175 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001176 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001177}
1178
1179/**
1180 * xmlStringLenGetNodeList:
1181 * @doc: the document
1182 * @value: the value of the text
1183 * @len: the length of the string value
1184 *
1185 * Parse the value string and build the node list associated. Should
1186 * produce a flat tree with only TEXTs and ENTITY_REFs.
1187 * Returns a pointer to the first child
1188 */
1189xmlNodePtr
1190xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1191 xmlNodePtr ret = NULL, last = NULL;
1192 xmlNodePtr node;
1193 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001194 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001195 const xmlChar *q;
1196 xmlEntityPtr ent;
1197
1198 if (value == NULL) return(NULL);
1199
1200 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001201 while ((cur < end) && (*cur != 0)) {
1202 if (cur[0] == '&') {
1203 int charval = 0;
1204 xmlChar tmp;
1205
Owen Taylor3473f882001-02-23 17:55:21 +00001206 /*
1207 * Save the current text.
1208 */
1209 if (cur != q) {
1210 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1211 xmlNodeAddContentLen(last, q, cur - q);
1212 } else {
1213 node = xmlNewDocTextLen(doc, q, cur - q);
1214 if (node == NULL) return(ret);
1215 if (last == NULL)
1216 last = ret = node;
1217 else {
1218 last->next = node;
1219 node->prev = last;
1220 last = node;
1221 }
1222 }
1223 }
Owen Taylor3473f882001-02-23 17:55:21 +00001224 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001225 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1226 cur += 3;
1227 if (cur < end)
1228 tmp = *cur;
1229 else
1230 tmp = 0;
1231 while (tmp != ';') { /* Non input consuming loop */
1232 if ((tmp >= '0') && (tmp <= '9'))
1233 charval = charval * 16 + (tmp - '0');
1234 else if ((tmp >= 'a') && (tmp <= 'f'))
1235 charval = charval * 16 + (tmp - 'a') + 10;
1236 else if ((tmp >= 'A') && (tmp <= 'F'))
1237 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001238 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001239 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1240 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001241 charval = 0;
1242 break;
1243 }
1244 cur++;
1245 if (cur < end)
1246 tmp = *cur;
1247 else
1248 tmp = 0;
1249 }
1250 if (tmp == ';')
1251 cur++;
1252 q = cur;
1253 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1254 cur += 2;
1255 if (cur < end)
1256 tmp = *cur;
1257 else
1258 tmp = 0;
1259 while (tmp != ';') { /* Non input consuming loops */
1260 if ((tmp >= '0') && (tmp <= '9'))
1261 charval = charval * 10 + (tmp - '0');
1262 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001263 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1264 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001265 charval = 0;
1266 break;
1267 }
1268 cur++;
1269 if (cur < end)
1270 tmp = *cur;
1271 else
1272 tmp = 0;
1273 }
1274 if (tmp == ';')
1275 cur++;
1276 q = cur;
1277 } else {
1278 /*
1279 * Read the entity string
1280 */
1281 cur++;
1282 q = cur;
1283 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1284 if ((cur >= end) || (*cur == 0)) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001285 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1286 (const char *) q);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001287 return(ret);
1288 }
1289 if (cur != q) {
1290 /*
1291 * Predefined entities don't generate nodes
1292 */
1293 val = xmlStrndup(q, cur - q);
1294 ent = xmlGetDocEntity(doc, val);
1295 if ((ent != NULL) &&
1296 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1297 if (last == NULL) {
1298 node = xmlNewDocText(doc, ent->content);
1299 last = ret = node;
1300 } else if (last->type != XML_TEXT_NODE) {
1301 node = xmlNewDocText(doc, ent->content);
1302 last = xmlAddNextSibling(last, node);
1303 } else
1304 xmlNodeAddContent(last, ent->content);
1305
1306 } else {
1307 /*
1308 * Create a new REFERENCE_REF node
1309 */
1310 node = xmlNewReference(doc, val);
1311 if (node == NULL) {
1312 if (val != NULL) xmlFree(val);
1313 return(ret);
1314 }
1315 else if ((ent != NULL) && (ent->children == NULL)) {
1316 xmlNodePtr temp;
1317
1318 ent->children = xmlStringGetNodeList(doc,
1319 (const xmlChar*)node->content);
1320 ent->owner = 1;
1321 temp = ent->children;
1322 while (temp) {
1323 temp->parent = (xmlNodePtr)ent;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001324 ent->last = temp;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001325 temp = temp->next;
1326 }
1327 }
1328 if (last == NULL) {
1329 last = ret = node;
1330 } else {
1331 last = xmlAddNextSibling(last, node);
1332 }
1333 }
1334 xmlFree(val);
1335 }
1336 cur++;
1337 q = cur;
1338 }
1339 if (charval != 0) {
1340 xmlChar buf[10];
1341 int l;
1342
1343 l = xmlCopyCharMultiByte(buf, charval);
1344 buf[l] = 0;
1345 node = xmlNewDocText(doc, buf);
1346 if (node != NULL) {
1347 if (last == NULL) {
1348 last = ret = node;
1349 } else {
1350 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001351 }
1352 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001353 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001354 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001355 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001356 cur++;
1357 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001358 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001359 /*
1360 * Handle the last piece of text.
1361 */
1362 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1363 xmlNodeAddContentLen(last, q, cur - q);
1364 } else {
1365 node = xmlNewDocTextLen(doc, q, cur - q);
1366 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001367 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001368 last = ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001369 } else {
1370 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001371 }
1372 }
1373 }
1374 return(ret);
1375}
1376
1377/**
1378 * xmlStringGetNodeList:
1379 * @doc: the document
1380 * @value: the value of the attribute
1381 *
1382 * Parse the value string and build the node list associated. Should
1383 * produce a flat tree with only TEXTs and ENTITY_REFs.
1384 * Returns a pointer to the first child
1385 */
1386xmlNodePtr
1387xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1388 xmlNodePtr ret = NULL, last = NULL;
1389 xmlNodePtr node;
1390 xmlChar *val;
1391 const xmlChar *cur = value;
1392 const xmlChar *q;
1393 xmlEntityPtr ent;
1394
1395 if (value == NULL) return(NULL);
1396
1397 q = cur;
1398 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001399 if (cur[0] == '&') {
1400 int charval = 0;
1401 xmlChar tmp;
1402
Owen Taylor3473f882001-02-23 17:55:21 +00001403 /*
1404 * Save the current text.
1405 */
1406 if (cur != q) {
1407 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1408 xmlNodeAddContentLen(last, q, cur - q);
1409 } else {
1410 node = xmlNewDocTextLen(doc, q, cur - q);
1411 if (node == NULL) return(ret);
1412 if (last == NULL)
1413 last = ret = node;
1414 else {
1415 last->next = node;
1416 node->prev = last;
1417 last = node;
1418 }
1419 }
1420 }
Owen Taylor3473f882001-02-23 17:55:21 +00001421 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001422 if ((cur[1] == '#') && (cur[2] == 'x')) {
1423 cur += 3;
1424 tmp = *cur;
1425 while (tmp != ';') { /* Non input consuming loop */
1426 if ((tmp >= '0') && (tmp <= '9'))
1427 charval = charval * 16 + (tmp - '0');
1428 else if ((tmp >= 'a') && (tmp <= 'f'))
1429 charval = charval * 16 + (tmp - 'a') + 10;
1430 else if ((tmp >= 'A') && (tmp <= 'F'))
1431 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001432 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001433 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1434 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001435 charval = 0;
1436 break;
1437 }
1438 cur++;
1439 tmp = *cur;
1440 }
1441 if (tmp == ';')
1442 cur++;
1443 q = cur;
1444 } else if (cur[1] == '#') {
1445 cur += 2;
1446 tmp = *cur;
1447 while (tmp != ';') { /* Non input consuming loops */
1448 if ((tmp >= '0') && (tmp <= '9'))
1449 charval = charval * 10 + (tmp - '0');
1450 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001451 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1452 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001453 charval = 0;
1454 break;
1455 }
1456 cur++;
1457 tmp = *cur;
1458 }
1459 if (tmp == ';')
1460 cur++;
1461 q = cur;
1462 } else {
1463 /*
1464 * Read the entity string
1465 */
1466 cur++;
1467 q = cur;
1468 while ((*cur != 0) && (*cur != ';')) cur++;
1469 if (*cur == 0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001470 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1471 (xmlNodePtr) doc, (const char *) q);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001472 return(ret);
1473 }
1474 if (cur != q) {
1475 /*
1476 * Predefined entities don't generate nodes
1477 */
1478 val = xmlStrndup(q, cur - q);
1479 ent = xmlGetDocEntity(doc, val);
1480 if ((ent != NULL) &&
1481 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1482 if (last == NULL) {
1483 node = xmlNewDocText(doc, ent->content);
1484 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001485 } else if (last->type != XML_TEXT_NODE) {
1486 node = xmlNewDocText(doc, ent->content);
1487 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001488 } else
1489 xmlNodeAddContent(last, ent->content);
1490
1491 } else {
1492 /*
1493 * Create a new REFERENCE_REF node
1494 */
1495 node = xmlNewReference(doc, val);
1496 if (node == NULL) {
1497 if (val != NULL) xmlFree(val);
1498 return(ret);
1499 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001500 else if ((ent != NULL) && (ent->children == NULL)) {
1501 xmlNodePtr temp;
1502
1503 ent->children = xmlStringGetNodeList(doc,
1504 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001505 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001506 temp = ent->children;
1507 while (temp) {
1508 temp->parent = (xmlNodePtr)ent;
1509 temp = temp->next;
1510 }
1511 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001512 if (last == NULL) {
1513 last = ret = node;
1514 } else {
1515 last = xmlAddNextSibling(last, node);
1516 }
1517 }
1518 xmlFree(val);
1519 }
1520 cur++;
1521 q = cur;
1522 }
1523 if (charval != 0) {
1524 xmlChar buf[10];
1525 int len;
1526
1527 len = xmlCopyCharMultiByte(buf, charval);
1528 buf[len] = 0;
1529 node = xmlNewDocText(doc, buf);
1530 if (node != NULL) {
1531 if (last == NULL) {
1532 last = ret = node;
1533 } else {
1534 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001535 }
1536 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001537
1538 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001539 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001540 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001541 cur++;
1542 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001543 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001544 /*
1545 * Handle the last piece of text.
1546 */
1547 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1548 xmlNodeAddContentLen(last, q, cur - q);
1549 } else {
1550 node = xmlNewDocTextLen(doc, q, cur - q);
1551 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001552 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001553 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001554 } else {
1555 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001556 }
1557 }
1558 }
1559 return(ret);
1560}
1561
1562/**
1563 * xmlNodeListGetString:
1564 * @doc: the document
1565 * @list: a Node list
1566 * @inLine: should we replace entity contents or show their external form
1567 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001568 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001569 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001570 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001571 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001572 */
1573xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001574xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1575{
Owen Taylor3473f882001-02-23 17:55:21 +00001576 xmlNodePtr node = list;
1577 xmlChar *ret = NULL;
1578 xmlEntityPtr ent;
1579
Daniel Veillard7646b182002-04-20 06:41:40 +00001580 if (list == NULL)
1581 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001582
1583 while (node != NULL) {
1584 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001585 (node->type == XML_CDATA_SECTION_NODE)) {
1586 if (inLine) {
1587 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001588 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001589 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001590
Daniel Veillard7646b182002-04-20 06:41:40 +00001591 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1592 if (buffer != NULL) {
1593 ret = xmlStrcat(ret, buffer);
1594 xmlFree(buffer);
1595 }
1596 }
1597 } else if (node->type == XML_ENTITY_REF_NODE) {
1598 if (inLine) {
1599 ent = xmlGetDocEntity(doc, node->name);
1600 if (ent != NULL) {
1601 xmlChar *buffer;
1602
1603 /* an entity content can be any "well balanced chunk",
1604 * i.e. the result of the content [43] production:
1605 * http://www.w3.org/TR/REC-xml#NT-content.
1606 * So it can contain text, CDATA section or nested
1607 * entity reference nodes (among others).
1608 * -> we recursive call xmlNodeListGetString()
1609 * which handles these types */
1610 buffer = xmlNodeListGetString(doc, ent->children, 1);
1611 if (buffer != NULL) {
1612 ret = xmlStrcat(ret, buffer);
1613 xmlFree(buffer);
1614 }
1615 } else {
1616 ret = xmlStrcat(ret, node->content);
1617 }
1618 } else {
1619 xmlChar buf[2];
1620
1621 buf[0] = '&';
1622 buf[1] = 0;
1623 ret = xmlStrncat(ret, buf, 1);
1624 ret = xmlStrcat(ret, node->name);
1625 buf[0] = ';';
1626 buf[1] = 0;
1627 ret = xmlStrncat(ret, buf, 1);
1628 }
1629 }
1630#if 0
1631 else {
1632 xmlGenericError(xmlGenericErrorContext,
1633 "xmlGetNodeListString : invalid node type %d\n",
1634 node->type);
1635 }
1636#endif
1637 node = node->next;
1638 }
1639 return (ret);
1640}
Daniel Veillard652327a2003-09-29 18:02:38 +00001641
1642#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001643/**
1644 * xmlNodeListGetRawString:
1645 * @doc: the document
1646 * @list: a Node list
1647 * @inLine: should we replace entity contents or show their external form
1648 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001649 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001650 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1651 * this function doesn't do any character encoding handling.
1652 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001653 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001654 */
1655xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001656xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1657{
Owen Taylor3473f882001-02-23 17:55:21 +00001658 xmlNodePtr node = list;
1659 xmlChar *ret = NULL;
1660 xmlEntityPtr ent;
1661
Daniel Veillard7646b182002-04-20 06:41:40 +00001662 if (list == NULL)
1663 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001664
1665 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001666 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001667 (node->type == XML_CDATA_SECTION_NODE)) {
1668 if (inLine) {
1669 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001670 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001671 xmlChar *buffer;
1672
1673 buffer = xmlEncodeSpecialChars(doc, node->content);
1674 if (buffer != NULL) {
1675 ret = xmlStrcat(ret, buffer);
1676 xmlFree(buffer);
1677 }
1678 }
1679 } else if (node->type == XML_ENTITY_REF_NODE) {
1680 if (inLine) {
1681 ent = xmlGetDocEntity(doc, node->name);
1682 if (ent != NULL) {
1683 xmlChar *buffer;
1684
1685 /* an entity content can be any "well balanced chunk",
1686 * i.e. the result of the content [43] production:
1687 * http://www.w3.org/TR/REC-xml#NT-content.
1688 * So it can contain text, CDATA section or nested
1689 * entity reference nodes (among others).
1690 * -> we recursive call xmlNodeListGetRawString()
1691 * which handles these types */
1692 buffer =
1693 xmlNodeListGetRawString(doc, ent->children, 1);
1694 if (buffer != NULL) {
1695 ret = xmlStrcat(ret, buffer);
1696 xmlFree(buffer);
1697 }
1698 } else {
1699 ret = xmlStrcat(ret, node->content);
1700 }
1701 } else {
1702 xmlChar buf[2];
1703
1704 buf[0] = '&';
1705 buf[1] = 0;
1706 ret = xmlStrncat(ret, buf, 1);
1707 ret = xmlStrcat(ret, node->name);
1708 buf[0] = ';';
1709 buf[1] = 0;
1710 ret = xmlStrncat(ret, buf, 1);
1711 }
1712 }
Owen Taylor3473f882001-02-23 17:55:21 +00001713#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001714 else {
1715 xmlGenericError(xmlGenericErrorContext,
1716 "xmlGetNodeListString : invalid node type %d\n",
1717 node->type);
1718 }
Owen Taylor3473f882001-02-23 17:55:21 +00001719#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001720 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001721 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001722 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001723}
Daniel Veillard652327a2003-09-29 18:02:38 +00001724#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001725
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001726static xmlAttrPtr xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns,
1727 const xmlChar *name, const xmlChar *value, int eatname) {
Owen Taylor3473f882001-02-23 17:55:21 +00001728 xmlAttrPtr cur;
1729 xmlDocPtr doc = NULL;
1730
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001731 if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) {
1732 if (eatname == 1)
1733 xmlFree((xmlChar *) name);
1734 return(NULL);
1735 }
Owen Taylor3473f882001-02-23 17:55:21 +00001736
1737 /*
1738 * Allocate a new property and fill the fields.
1739 */
1740 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1741 if (cur == NULL) {
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001742 if (eatname == 1)
1743 xmlFree((xmlChar *) name);
1744 xmlTreeErrMemory("building attribute");
1745 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001746 }
1747 memset(cur, 0, sizeof(xmlAttr));
1748 cur->type = XML_ATTRIBUTE_NODE;
1749
1750 cur->parent = node;
1751 if (node != NULL) {
1752 doc = node->doc;
1753 cur->doc = doc;
1754 }
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001755 cur->ns = ns;
1756
1757 if (eatname == 0) {
1758 if ((doc != NULL) && (doc->dict != NULL))
1759 cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
1760 else
1761 cur->name = xmlStrdup(name);
1762 } else
1763 cur->name = name;
1764
Owen Taylor3473f882001-02-23 17:55:21 +00001765 if (value != NULL) {
1766 xmlChar *buffer;
1767 xmlNodePtr tmp;
1768
1769 buffer = xmlEncodeEntitiesReentrant(doc, value);
1770 cur->children = xmlStringGetNodeList(doc, buffer);
1771 cur->last = NULL;
1772 tmp = cur->children;
1773 while (tmp != NULL) {
1774 tmp->parent = (xmlNodePtr) cur;
Owen Taylor3473f882001-02-23 17:55:21 +00001775 if (tmp->next == NULL)
1776 cur->last = tmp;
1777 tmp = tmp->next;
1778 }
1779 xmlFree(buffer);
1780 }
1781
1782 /*
1783 * Add it at the end to preserve parsing order ...
1784 */
1785 if (node != NULL) {
1786 if (node->properties == NULL) {
1787 node->properties = cur;
1788 } else {
1789 xmlAttrPtr prev = node->properties;
1790
1791 while (prev->next != NULL) prev = prev->next;
1792 prev->next = cur;
1793 cur->prev = prev;
1794 }
1795 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001796
Daniel Veillarda880b122003-04-21 21:36:41 +00001797 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001798 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001799 return(cur);
1800}
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001801
1802#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
1803 defined(LIBXML_SCHEMAS_ENABLED)
1804/**
1805 * xmlNewProp:
1806 * @node: the holding node
1807 * @name: the name of the attribute
1808 * @value: the value of the attribute
1809 *
1810 * Create a new property carried by a node.
1811 * Returns a pointer to the attribute
1812 */
1813xmlAttrPtr
1814xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1815
1816 if (name == NULL) {
1817#ifdef DEBUG_TREE
1818 xmlGenericError(xmlGenericErrorContext,
1819 "xmlNewProp : name == NULL\n");
1820#endif
1821 return(NULL);
1822 }
1823
1824 return xmlNewPropInternal(node, NULL, name, value, 0);
1825}
Daniel Veillard652327a2003-09-29 18:02:38 +00001826#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001827
1828/**
1829 * xmlNewNsProp:
1830 * @node: the holding node
1831 * @ns: the namespace
1832 * @name: the name of the attribute
1833 * @value: the value of the attribute
1834 *
1835 * Create a new property tagged with a namespace and carried by a node.
1836 * Returns a pointer to the attribute
1837 */
1838xmlAttrPtr
1839xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1840 const xmlChar *value) {
Owen Taylor3473f882001-02-23 17:55:21 +00001841
1842 if (name == NULL) {
1843#ifdef DEBUG_TREE
1844 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001845 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001846#endif
1847 return(NULL);
1848 }
1849
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001850 return xmlNewPropInternal(node, ns, name, value, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001851}
1852
1853/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001854 * xmlNewNsPropEatName:
1855 * @node: the holding node
1856 * @ns: the namespace
1857 * @name: the name of the attribute
1858 * @value: the value of the attribute
1859 *
1860 * Create a new property tagged with a namespace and carried by a node.
1861 * Returns a pointer to the attribute
1862 */
1863xmlAttrPtr
1864xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1865 const xmlChar *value) {
Daniel Veillard46de64e2002-05-29 08:21:33 +00001866
1867 if (name == NULL) {
1868#ifdef DEBUG_TREE
1869 xmlGenericError(xmlGenericErrorContext,
1870 "xmlNewNsPropEatName : name == NULL\n");
1871#endif
1872 return(NULL);
1873 }
1874
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001875 return xmlNewPropInternal(node, ns, name, value, 1);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001876}
1877
1878/**
Owen Taylor3473f882001-02-23 17:55:21 +00001879 * xmlNewDocProp:
1880 * @doc: the document
1881 * @name: the name of the attribute
1882 * @value: the value of the attribute
1883 *
1884 * Create a new property carried by a document.
1885 * Returns a pointer to the attribute
1886 */
1887xmlAttrPtr
1888xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1889 xmlAttrPtr cur;
1890
1891 if (name == NULL) {
1892#ifdef DEBUG_TREE
1893 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001894 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001895#endif
1896 return(NULL);
1897 }
1898
1899 /*
1900 * Allocate a new property and fill the fields.
1901 */
1902 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1903 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001904 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001905 return(NULL);
1906 }
1907 memset(cur, 0, sizeof(xmlAttr));
1908 cur->type = XML_ATTRIBUTE_NODE;
1909
Daniel Veillard03a53c32004-10-26 16:06:51 +00001910 if ((doc != NULL) && (doc->dict != NULL))
1911 cur->name = xmlDictLookup(doc->dict, name, -1);
1912 else
1913 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00001914 cur->doc = doc;
1915 if (value != NULL) {
1916 xmlNodePtr tmp;
1917
1918 cur->children = xmlStringGetNodeList(doc, value);
1919 cur->last = NULL;
1920
1921 tmp = cur->children;
1922 while (tmp != NULL) {
1923 tmp->parent = (xmlNodePtr) cur;
1924 if (tmp->next == NULL)
1925 cur->last = tmp;
1926 tmp = tmp->next;
1927 }
1928 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001929
Daniel Veillarda880b122003-04-21 21:36:41 +00001930 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001931 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001932 return(cur);
1933}
1934
1935/**
1936 * xmlFreePropList:
1937 * @cur: the first property in the list
1938 *
1939 * Free a property and all its siblings, all the children are freed too.
1940 */
1941void
1942xmlFreePropList(xmlAttrPtr cur) {
1943 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001944 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001945 while (cur != NULL) {
1946 next = cur->next;
1947 xmlFreeProp(cur);
1948 cur = next;
1949 }
1950}
1951
1952/**
1953 * xmlFreeProp:
1954 * @cur: an attribute
1955 *
1956 * Free one attribute, all the content is freed too
1957 */
1958void
1959xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001960 xmlDictPtr dict = NULL;
1961 if (cur == NULL) return;
1962
1963 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001964
Daniel Veillarda880b122003-04-21 21:36:41 +00001965 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001966 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1967
Owen Taylor3473f882001-02-23 17:55:21 +00001968 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillardda6f4af2005-06-20 17:17:54 +00001969 if ((cur->doc != NULL) && (cur->atype == XML_ATTRIBUTE_ID)) {
1970 xmlRemoveID(cur->doc, cur);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001971 }
Owen Taylor3473f882001-02-23 17:55:21 +00001972 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001973 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00001974 xmlFree(cur);
1975}
1976
Daniel Veillard652327a2003-09-29 18:02:38 +00001977#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001978/**
1979 * xmlRemoveProp:
1980 * @cur: an attribute
1981 *
1982 * Unlink and free one attribute, all the content is freed too
1983 * Note this doesn't work for namespace definition attributes
1984 *
1985 * Returns 0 if success and -1 in case of error.
1986 */
1987int
1988xmlRemoveProp(xmlAttrPtr cur) {
1989 xmlAttrPtr tmp;
1990 if (cur == NULL) {
1991#ifdef DEBUG_TREE
1992 xmlGenericError(xmlGenericErrorContext,
1993 "xmlRemoveProp : cur == NULL\n");
1994#endif
1995 return(-1);
1996 }
1997 if (cur->parent == NULL) {
1998#ifdef DEBUG_TREE
1999 xmlGenericError(xmlGenericErrorContext,
2000 "xmlRemoveProp : cur->parent == NULL\n");
2001#endif
2002 return(-1);
2003 }
2004 tmp = cur->parent->properties;
2005 if (tmp == cur) {
2006 cur->parent->properties = cur->next;
2007 xmlFreeProp(cur);
2008 return(0);
2009 }
2010 while (tmp != NULL) {
2011 if (tmp->next == cur) {
2012 tmp->next = cur->next;
2013 if (tmp->next != NULL)
2014 tmp->next->prev = tmp;
2015 xmlFreeProp(cur);
2016 return(0);
2017 }
2018 tmp = tmp->next;
2019 }
2020#ifdef DEBUG_TREE
2021 xmlGenericError(xmlGenericErrorContext,
2022 "xmlRemoveProp : attribute not owned by its node\n");
2023#endif
2024 return(-1);
2025}
Daniel Veillard652327a2003-09-29 18:02:38 +00002026#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002027
2028/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002029 * xmlNewDocPI:
2030 * @doc: the target document
Owen Taylor3473f882001-02-23 17:55:21 +00002031 * @name: the processing instruction name
2032 * @content: the PI content
2033 *
2034 * Creation of a processing instruction element.
2035 * Returns a pointer to the new node object.
2036 */
2037xmlNodePtr
Daniel Veillard03a53c32004-10-26 16:06:51 +00002038xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
Owen Taylor3473f882001-02-23 17:55:21 +00002039 xmlNodePtr cur;
2040
2041 if (name == NULL) {
2042#ifdef DEBUG_TREE
2043 xmlGenericError(xmlGenericErrorContext,
2044 "xmlNewPI : name == NULL\n");
2045#endif
2046 return(NULL);
2047 }
2048
2049 /*
2050 * Allocate a new node and fill the fields.
2051 */
2052 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2053 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002054 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002055 return(NULL);
2056 }
2057 memset(cur, 0, sizeof(xmlNode));
2058 cur->type = XML_PI_NODE;
2059
Daniel Veillard03a53c32004-10-26 16:06:51 +00002060 if ((doc != NULL) && (doc->dict != NULL))
2061 cur->name = xmlDictLookup(doc->dict, name, -1);
2062 else
2063 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00002064 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002065 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002066 }
Daniel Veillarda03e3652004-11-02 18:45:30 +00002067 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002068
Daniel Veillarda880b122003-04-21 21:36:41 +00002069 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002070 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002071 return(cur);
2072}
2073
2074/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002075 * xmlNewPI:
2076 * @name: the processing instruction name
2077 * @content: the PI content
2078 *
2079 * Creation of a processing instruction element.
2080 * Use xmlDocNewPI preferably to get string interning
2081 *
2082 * Returns a pointer to the new node object.
2083 */
2084xmlNodePtr
2085xmlNewPI(const xmlChar *name, const xmlChar *content) {
2086 return(xmlNewDocPI(NULL, name, content));
2087}
2088
2089/**
Owen Taylor3473f882001-02-23 17:55:21 +00002090 * xmlNewNode:
2091 * @ns: namespace if any
2092 * @name: the node name
2093 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002094 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002095 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002096 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2097 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002098 */
2099xmlNodePtr
2100xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2101 xmlNodePtr cur;
2102
2103 if (name == NULL) {
2104#ifdef DEBUG_TREE
2105 xmlGenericError(xmlGenericErrorContext,
2106 "xmlNewNode : name == NULL\n");
2107#endif
2108 return(NULL);
2109 }
2110
2111 /*
2112 * Allocate a new node and fill the fields.
2113 */
2114 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2115 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002116 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002117 return(NULL);
2118 }
2119 memset(cur, 0, sizeof(xmlNode));
2120 cur->type = XML_ELEMENT_NODE;
2121
2122 cur->name = xmlStrdup(name);
2123 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002124
Daniel Veillarda880b122003-04-21 21:36:41 +00002125 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002126 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002127 return(cur);
2128}
2129
2130/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002131 * xmlNewNodeEatName:
2132 * @ns: namespace if any
2133 * @name: the node name
2134 *
2135 * Creation of a new node element. @ns is optional (NULL).
2136 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002137 * Returns a pointer to the new node object, with pointer @name as
2138 * new node's name. Use xmlNewNode() if a copy of @name string is
2139 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002140 */
2141xmlNodePtr
2142xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2143 xmlNodePtr cur;
2144
2145 if (name == NULL) {
2146#ifdef DEBUG_TREE
2147 xmlGenericError(xmlGenericErrorContext,
2148 "xmlNewNode : name == NULL\n");
2149#endif
2150 return(NULL);
2151 }
2152
2153 /*
2154 * Allocate a new node and fill the fields.
2155 */
2156 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2157 if (cur == NULL) {
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00002158 xmlFree(name);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002159 xmlTreeErrMemory("building node");
Daniel Veillard46de64e2002-05-29 08:21:33 +00002160 return(NULL);
2161 }
2162 memset(cur, 0, sizeof(xmlNode));
2163 cur->type = XML_ELEMENT_NODE;
2164
2165 cur->name = name;
2166 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002167
Daniel Veillarda880b122003-04-21 21:36:41 +00002168 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002169 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002170 return(cur);
2171}
2172
2173/**
Owen Taylor3473f882001-02-23 17:55:21 +00002174 * xmlNewDocNode:
2175 * @doc: the document
2176 * @ns: namespace if any
2177 * @name: the node name
2178 * @content: the XML text content if any
2179 *
2180 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002181 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002182 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2183 * references, but XML special chars need to be escaped first by using
2184 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2185 * need entities support.
2186 *
2187 * Returns a pointer to the new node object.
2188 */
2189xmlNodePtr
2190xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2191 const xmlChar *name, const xmlChar *content) {
2192 xmlNodePtr cur;
2193
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002194 if ((doc != NULL) && (doc->dict != NULL))
Daniel Veillard03a53c32004-10-26 16:06:51 +00002195 cur = xmlNewNodeEatName(ns, (xmlChar *)
2196 xmlDictLookup(doc->dict, name, -1));
2197 else
2198 cur = xmlNewNode(ns, name);
Owen Taylor3473f882001-02-23 17:55:21 +00002199 if (cur != NULL) {
2200 cur->doc = doc;
2201 if (content != NULL) {
2202 cur->children = xmlStringGetNodeList(doc, content);
2203 UPDATE_LAST_CHILD_AND_PARENT(cur)
2204 }
2205 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002206
Owen Taylor3473f882001-02-23 17:55:21 +00002207 return(cur);
2208}
2209
Daniel Veillard46de64e2002-05-29 08:21:33 +00002210/**
2211 * xmlNewDocNodeEatName:
2212 * @doc: the document
2213 * @ns: namespace if any
2214 * @name: the node name
2215 * @content: the XML text content if any
2216 *
2217 * Creation of a new node element within a document. @ns and @content
2218 * are optional (NULL).
2219 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2220 * references, but XML special chars need to be escaped first by using
2221 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2222 * need entities support.
2223 *
2224 * Returns a pointer to the new node object.
2225 */
2226xmlNodePtr
2227xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2228 xmlChar *name, const xmlChar *content) {
2229 xmlNodePtr cur;
2230
2231 cur = xmlNewNodeEatName(ns, name);
2232 if (cur != NULL) {
2233 cur->doc = doc;
2234 if (content != NULL) {
2235 cur->children = xmlStringGetNodeList(doc, content);
2236 UPDATE_LAST_CHILD_AND_PARENT(cur)
2237 }
2238 }
2239 return(cur);
2240}
2241
Daniel Veillard652327a2003-09-29 18:02:38 +00002242#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002243/**
2244 * xmlNewDocRawNode:
2245 * @doc: the document
2246 * @ns: namespace if any
2247 * @name: the node name
2248 * @content: the text content if any
2249 *
2250 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002251 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002252 *
2253 * Returns a pointer to the new node object.
2254 */
2255xmlNodePtr
2256xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2257 const xmlChar *name, const xmlChar *content) {
2258 xmlNodePtr cur;
2259
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002260 cur = xmlNewDocNode(doc, ns, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002261 if (cur != NULL) {
2262 cur->doc = doc;
2263 if (content != NULL) {
2264 cur->children = xmlNewDocText(doc, content);
2265 UPDATE_LAST_CHILD_AND_PARENT(cur)
2266 }
2267 }
2268 return(cur);
2269}
2270
2271/**
2272 * xmlNewDocFragment:
2273 * @doc: the document owning the fragment
2274 *
2275 * Creation of a new Fragment node.
2276 * Returns a pointer to the new node object.
2277 */
2278xmlNodePtr
2279xmlNewDocFragment(xmlDocPtr doc) {
2280 xmlNodePtr cur;
2281
2282 /*
2283 * Allocate a new DocumentFragment node and fill the fields.
2284 */
2285 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2286 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002287 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002288 return(NULL);
2289 }
2290 memset(cur, 0, sizeof(xmlNode));
2291 cur->type = XML_DOCUMENT_FRAG_NODE;
2292
2293 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002294
Daniel Veillarda880b122003-04-21 21:36:41 +00002295 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002296 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002297 return(cur);
2298}
Daniel Veillard652327a2003-09-29 18:02:38 +00002299#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002300
2301/**
2302 * xmlNewText:
2303 * @content: the text content
2304 *
2305 * Creation of a new text node.
2306 * Returns a pointer to the new node object.
2307 */
2308xmlNodePtr
2309xmlNewText(const xmlChar *content) {
2310 xmlNodePtr cur;
2311
2312 /*
2313 * Allocate a new node and fill the fields.
2314 */
2315 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2316 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002317 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002318 return(NULL);
2319 }
2320 memset(cur, 0, sizeof(xmlNode));
2321 cur->type = XML_TEXT_NODE;
2322
2323 cur->name = xmlStringText;
2324 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002325 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002326 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002327
Daniel Veillarda880b122003-04-21 21:36:41 +00002328 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002329 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002330 return(cur);
2331}
2332
Daniel Veillard652327a2003-09-29 18:02:38 +00002333#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002334/**
2335 * xmlNewTextChild:
2336 * @parent: the parent node
2337 * @ns: a namespace if any
2338 * @name: the name of the child
2339 * @content: the text content of the child if any.
2340 *
2341 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002342 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2343 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002344 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002345 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2346 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2347 * reserved XML chars that might appear in @content, such as the ampersand,
2348 * greater-than or less-than signs, are automatically replaced by their XML
2349 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002350 *
2351 * Returns a pointer to the new node object.
2352 */
2353xmlNodePtr
2354xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2355 const xmlChar *name, const xmlChar *content) {
2356 xmlNodePtr cur, prev;
2357
2358 if (parent == NULL) {
2359#ifdef DEBUG_TREE
2360 xmlGenericError(xmlGenericErrorContext,
2361 "xmlNewTextChild : parent == NULL\n");
2362#endif
2363 return(NULL);
2364 }
2365
2366 if (name == NULL) {
2367#ifdef DEBUG_TREE
2368 xmlGenericError(xmlGenericErrorContext,
2369 "xmlNewTextChild : name == NULL\n");
2370#endif
2371 return(NULL);
2372 }
2373
2374 /*
2375 * Allocate a new node
2376 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002377 if (parent->type == XML_ELEMENT_NODE) {
2378 if (ns == NULL)
2379 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2380 else
2381 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2382 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2383 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2384 if (ns == NULL)
2385 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2386 else
2387 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2388 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2389 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2390 } else {
2391 return(NULL);
2392 }
Owen Taylor3473f882001-02-23 17:55:21 +00002393 if (cur == NULL) return(NULL);
2394
2395 /*
2396 * add the new element at the end of the children list.
2397 */
2398 cur->type = XML_ELEMENT_NODE;
2399 cur->parent = parent;
2400 cur->doc = parent->doc;
2401 if (parent->children == NULL) {
2402 parent->children = cur;
2403 parent->last = cur;
2404 } else {
2405 prev = parent->last;
2406 prev->next = cur;
2407 cur->prev = prev;
2408 parent->last = cur;
2409 }
2410
2411 return(cur);
2412}
Daniel Veillard652327a2003-09-29 18:02:38 +00002413#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002414
2415/**
2416 * xmlNewCharRef:
2417 * @doc: the document
2418 * @name: the char ref string, starting with # or "&# ... ;"
2419 *
2420 * Creation of a new character reference node.
2421 * Returns a pointer to the new node object.
2422 */
2423xmlNodePtr
2424xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2425 xmlNodePtr cur;
2426
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002427 if (name == NULL)
2428 return(NULL);
2429
Owen Taylor3473f882001-02-23 17:55:21 +00002430 /*
2431 * Allocate a new node and fill the fields.
2432 */
2433 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2434 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002435 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002436 return(NULL);
2437 }
2438 memset(cur, 0, sizeof(xmlNode));
2439 cur->type = XML_ENTITY_REF_NODE;
2440
2441 cur->doc = doc;
2442 if (name[0] == '&') {
2443 int len;
2444 name++;
2445 len = xmlStrlen(name);
2446 if (name[len - 1] == ';')
2447 cur->name = xmlStrndup(name, len - 1);
2448 else
2449 cur->name = xmlStrndup(name, len);
2450 } else
2451 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002452
Daniel Veillarda880b122003-04-21 21:36:41 +00002453 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002454 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002455 return(cur);
2456}
2457
2458/**
2459 * xmlNewReference:
2460 * @doc: the document
2461 * @name: the reference name, or the reference string with & and ;
2462 *
2463 * Creation of a new reference node.
2464 * Returns a pointer to the new node object.
2465 */
2466xmlNodePtr
2467xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2468 xmlNodePtr cur;
2469 xmlEntityPtr ent;
2470
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002471 if (name == NULL)
2472 return(NULL);
2473
Owen Taylor3473f882001-02-23 17:55:21 +00002474 /*
2475 * Allocate a new node and fill the fields.
2476 */
2477 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2478 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002479 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002480 return(NULL);
2481 }
2482 memset(cur, 0, sizeof(xmlNode));
2483 cur->type = XML_ENTITY_REF_NODE;
2484
2485 cur->doc = doc;
2486 if (name[0] == '&') {
2487 int len;
2488 name++;
2489 len = xmlStrlen(name);
2490 if (name[len - 1] == ';')
2491 cur->name = xmlStrndup(name, len - 1);
2492 else
2493 cur->name = xmlStrndup(name, len);
2494 } else
2495 cur->name = xmlStrdup(name);
2496
2497 ent = xmlGetDocEntity(doc, cur->name);
2498 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002499 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002500 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002501 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002502 * updated. Not sure if this is 100% correct.
2503 * -George
2504 */
2505 cur->children = (xmlNodePtr) ent;
2506 cur->last = (xmlNodePtr) ent;
2507 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002508
Daniel Veillarda880b122003-04-21 21:36:41 +00002509 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002510 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002511 return(cur);
2512}
2513
2514/**
2515 * xmlNewDocText:
2516 * @doc: the document
2517 * @content: the text content
2518 *
2519 * Creation of a new text node within a document.
2520 * Returns a pointer to the new node object.
2521 */
2522xmlNodePtr
2523xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2524 xmlNodePtr cur;
2525
2526 cur = xmlNewText(content);
2527 if (cur != NULL) cur->doc = doc;
2528 return(cur);
2529}
2530
2531/**
2532 * xmlNewTextLen:
2533 * @content: the text content
2534 * @len: the text len.
2535 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002536 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002537 * Returns a pointer to the new node object.
2538 */
2539xmlNodePtr
2540xmlNewTextLen(const xmlChar *content, int len) {
2541 xmlNodePtr cur;
2542
2543 /*
2544 * Allocate a new node and fill the fields.
2545 */
2546 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2547 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002548 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002549 return(NULL);
2550 }
2551 memset(cur, 0, sizeof(xmlNode));
2552 cur->type = XML_TEXT_NODE;
2553
2554 cur->name = xmlStringText;
2555 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002556 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002557 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002558
Daniel Veillarda880b122003-04-21 21:36:41 +00002559 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002560 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002561 return(cur);
2562}
2563
2564/**
2565 * xmlNewDocTextLen:
2566 * @doc: the document
2567 * @content: the text content
2568 * @len: the text len.
2569 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002570 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002571 * text node pertain to a given document.
2572 * Returns a pointer to the new node object.
2573 */
2574xmlNodePtr
2575xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2576 xmlNodePtr cur;
2577
2578 cur = xmlNewTextLen(content, len);
2579 if (cur != NULL) cur->doc = doc;
2580 return(cur);
2581}
2582
2583/**
2584 * xmlNewComment:
2585 * @content: the comment content
2586 *
2587 * Creation of a new node containing a comment.
2588 * Returns a pointer to the new node object.
2589 */
2590xmlNodePtr
2591xmlNewComment(const xmlChar *content) {
2592 xmlNodePtr cur;
2593
2594 /*
2595 * Allocate a new node and fill the fields.
2596 */
2597 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2598 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002599 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002600 return(NULL);
2601 }
2602 memset(cur, 0, sizeof(xmlNode));
2603 cur->type = XML_COMMENT_NODE;
2604
2605 cur->name = xmlStringComment;
2606 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002607 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002608 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002609
Daniel Veillarda880b122003-04-21 21:36:41 +00002610 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002611 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002612 return(cur);
2613}
2614
2615/**
2616 * xmlNewCDataBlock:
2617 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002618 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002619 * @len: the length of the block
2620 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002621 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002622 * Returns a pointer to the new node object.
2623 */
2624xmlNodePtr
2625xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2626 xmlNodePtr cur;
2627
2628 /*
2629 * Allocate a new node and fill the fields.
2630 */
2631 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2632 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002633 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002634 return(NULL);
2635 }
2636 memset(cur, 0, sizeof(xmlNode));
2637 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002638 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002639
2640 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002641 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002642 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002643
Daniel Veillarda880b122003-04-21 21:36:41 +00002644 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002645 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002646 return(cur);
2647}
2648
2649/**
2650 * xmlNewDocComment:
2651 * @doc: the document
2652 * @content: the comment content
2653 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002654 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002655 * Returns a pointer to the new node object.
2656 */
2657xmlNodePtr
2658xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2659 xmlNodePtr cur;
2660
2661 cur = xmlNewComment(content);
2662 if (cur != NULL) cur->doc = doc;
2663 return(cur);
2664}
2665
2666/**
2667 * xmlSetTreeDoc:
2668 * @tree: the top element
2669 * @doc: the document
2670 *
2671 * update all nodes under the tree to point to the right document
2672 */
2673void
2674xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002675 xmlAttrPtr prop;
2676
Owen Taylor3473f882001-02-23 17:55:21 +00002677 if (tree == NULL)
2678 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002679 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002680 if(tree->type == XML_ELEMENT_NODE) {
2681 prop = tree->properties;
2682 while (prop != NULL) {
2683 prop->doc = doc;
2684 xmlSetListDoc(prop->children, doc);
2685 prop = prop->next;
2686 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002687 }
Owen Taylor3473f882001-02-23 17:55:21 +00002688 if (tree->children != NULL)
2689 xmlSetListDoc(tree->children, doc);
2690 tree->doc = doc;
2691 }
2692}
2693
2694/**
2695 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002696 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002697 * @doc: the document
2698 *
2699 * update all nodes in the list to point to the right document
2700 */
2701void
2702xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2703 xmlNodePtr cur;
2704
2705 if (list == NULL)
2706 return;
2707 cur = list;
2708 while (cur != NULL) {
2709 if (cur->doc != doc)
2710 xmlSetTreeDoc(cur, doc);
2711 cur = cur->next;
2712 }
2713}
2714
Daniel Veillard2156d432004-03-04 15:59:36 +00002715#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002716/**
2717 * xmlNewChild:
2718 * @parent: the parent node
2719 * @ns: a namespace if any
2720 * @name: the name of the child
2721 * @content: the XML content of the child if any.
2722 *
2723 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002724 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2725 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002726 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002727 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2728 * references. XML special chars must be escaped first by using
2729 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002730 *
2731 * Returns a pointer to the new node object.
2732 */
2733xmlNodePtr
2734xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2735 const xmlChar *name, const xmlChar *content) {
2736 xmlNodePtr cur, prev;
2737
2738 if (parent == NULL) {
2739#ifdef DEBUG_TREE
2740 xmlGenericError(xmlGenericErrorContext,
2741 "xmlNewChild : parent == NULL\n");
2742#endif
2743 return(NULL);
2744 }
2745
2746 if (name == NULL) {
2747#ifdef DEBUG_TREE
2748 xmlGenericError(xmlGenericErrorContext,
2749 "xmlNewChild : name == NULL\n");
2750#endif
2751 return(NULL);
2752 }
2753
2754 /*
2755 * Allocate a new node
2756 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002757 if (parent->type == XML_ELEMENT_NODE) {
2758 if (ns == NULL)
2759 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2760 else
2761 cur = xmlNewDocNode(parent->doc, ns, name, content);
2762 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2763 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2764 if (ns == NULL)
2765 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2766 else
2767 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002768 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2769 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002770 } else {
2771 return(NULL);
2772 }
Owen Taylor3473f882001-02-23 17:55:21 +00002773 if (cur == NULL) return(NULL);
2774
2775 /*
2776 * add the new element at the end of the children list.
2777 */
2778 cur->type = XML_ELEMENT_NODE;
2779 cur->parent = parent;
2780 cur->doc = parent->doc;
2781 if (parent->children == NULL) {
2782 parent->children = cur;
2783 parent->last = cur;
2784 } else {
2785 prev = parent->last;
2786 prev->next = cur;
2787 cur->prev = prev;
2788 parent->last = cur;
2789 }
2790
2791 return(cur);
2792}
Daniel Veillard652327a2003-09-29 18:02:38 +00002793#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002794
2795/**
2796 * xmlAddNextSibling:
2797 * @cur: the child node
2798 * @elem: the new node
2799 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002800 * Add a new node @elem as the next sibling of @cur
2801 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002802 * first unlinked from its existing context.
2803 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002804 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2805 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002806 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002807 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002808 */
2809xmlNodePtr
2810xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2811 if (cur == NULL) {
2812#ifdef DEBUG_TREE
2813 xmlGenericError(xmlGenericErrorContext,
2814 "xmlAddNextSibling : cur == NULL\n");
2815#endif
2816 return(NULL);
2817 }
2818 if (elem == NULL) {
2819#ifdef DEBUG_TREE
2820 xmlGenericError(xmlGenericErrorContext,
2821 "xmlAddNextSibling : elem == NULL\n");
2822#endif
2823 return(NULL);
2824 }
2825
2826 xmlUnlinkNode(elem);
2827
2828 if (elem->type == XML_TEXT_NODE) {
2829 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002830 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002831 xmlFreeNode(elem);
2832 return(cur);
2833 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002834 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2835 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002836 xmlChar *tmp;
2837
2838 tmp = xmlStrdup(elem->content);
2839 tmp = xmlStrcat(tmp, cur->next->content);
2840 xmlNodeSetContent(cur->next, tmp);
2841 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002842 xmlFreeNode(elem);
2843 return(cur->next);
2844 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002845 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2846 /* check if an attribute with the same name exists */
2847 xmlAttrPtr attr;
2848
2849 if (elem->ns == NULL)
2850 attr = xmlHasProp(cur->parent, elem->name);
2851 else
2852 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2853 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2854 /* different instance, destroy it (attributes must be unique) */
2855 xmlFreeProp(attr);
2856 }
Owen Taylor3473f882001-02-23 17:55:21 +00002857 }
2858
2859 if (elem->doc != cur->doc) {
2860 xmlSetTreeDoc(elem, cur->doc);
2861 }
2862 elem->parent = cur->parent;
2863 elem->prev = cur;
2864 elem->next = cur->next;
2865 cur->next = elem;
2866 if (elem->next != NULL)
2867 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002868 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002869 elem->parent->last = elem;
2870 return(elem);
2871}
2872
William M. Brack21e4ef22005-01-02 09:53:13 +00002873#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
2874 defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002875/**
2876 * xmlAddPrevSibling:
2877 * @cur: the child node
2878 * @elem: the new node
2879 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002880 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002881 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002882 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002883 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002884 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2885 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002886 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002887 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002888 */
2889xmlNodePtr
2890xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2891 if (cur == NULL) {
2892#ifdef DEBUG_TREE
2893 xmlGenericError(xmlGenericErrorContext,
2894 "xmlAddPrevSibling : cur == NULL\n");
2895#endif
2896 return(NULL);
2897 }
2898 if (elem == NULL) {
2899#ifdef DEBUG_TREE
2900 xmlGenericError(xmlGenericErrorContext,
2901 "xmlAddPrevSibling : elem == NULL\n");
2902#endif
2903 return(NULL);
2904 }
2905
2906 xmlUnlinkNode(elem);
2907
2908 if (elem->type == XML_TEXT_NODE) {
2909 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002910 xmlChar *tmp;
2911
2912 tmp = xmlStrdup(elem->content);
2913 tmp = xmlStrcat(tmp, cur->content);
2914 xmlNodeSetContent(cur, tmp);
2915 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002916 xmlFreeNode(elem);
2917 return(cur);
2918 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002919 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2920 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002921 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002922 xmlFreeNode(elem);
2923 return(cur->prev);
2924 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002925 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2926 /* check if an attribute with the same name exists */
2927 xmlAttrPtr attr;
2928
2929 if (elem->ns == NULL)
2930 attr = xmlHasProp(cur->parent, elem->name);
2931 else
2932 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2933 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2934 /* different instance, destroy it (attributes must be unique) */
2935 xmlFreeProp(attr);
2936 }
Owen Taylor3473f882001-02-23 17:55:21 +00002937 }
2938
2939 if (elem->doc != cur->doc) {
2940 xmlSetTreeDoc(elem, cur->doc);
2941 }
2942 elem->parent = cur->parent;
2943 elem->next = cur;
2944 elem->prev = cur->prev;
2945 cur->prev = elem;
2946 if (elem->prev != NULL)
2947 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002948 if (elem->parent != NULL) {
2949 if (elem->type == XML_ATTRIBUTE_NODE) {
2950 if (elem->parent->properties == (xmlAttrPtr) cur) {
2951 elem->parent->properties = (xmlAttrPtr) elem;
2952 }
2953 } else {
2954 if (elem->parent->children == cur) {
2955 elem->parent->children = elem;
2956 }
2957 }
2958 }
Owen Taylor3473f882001-02-23 17:55:21 +00002959 return(elem);
2960}
Daniel Veillard652327a2003-09-29 18:02:38 +00002961#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002962
2963/**
2964 * xmlAddSibling:
2965 * @cur: the child node
2966 * @elem: the new node
2967 *
2968 * Add a new element @elem to the list of siblings of @cur
2969 * merging adjacent TEXT nodes (@elem may be freed)
2970 * If the new element was already inserted in a document it is
2971 * first unlinked from its existing context.
2972 *
2973 * Returns the new element or NULL in case of error.
2974 */
2975xmlNodePtr
2976xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2977 xmlNodePtr parent;
2978
2979 if (cur == NULL) {
2980#ifdef DEBUG_TREE
2981 xmlGenericError(xmlGenericErrorContext,
2982 "xmlAddSibling : cur == NULL\n");
2983#endif
2984 return(NULL);
2985 }
2986
2987 if (elem == NULL) {
2988#ifdef DEBUG_TREE
2989 xmlGenericError(xmlGenericErrorContext,
2990 "xmlAddSibling : elem == NULL\n");
2991#endif
2992 return(NULL);
2993 }
2994
2995 /*
2996 * Constant time is we can rely on the ->parent->last to find
2997 * the last sibling.
2998 */
2999 if ((cur->parent != NULL) &&
3000 (cur->parent->children != NULL) &&
3001 (cur->parent->last != NULL) &&
3002 (cur->parent->last->next == NULL)) {
3003 cur = cur->parent->last;
3004 } else {
3005 while (cur->next != NULL) cur = cur->next;
3006 }
3007
3008 xmlUnlinkNode(elem);
3009
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003010 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3011 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003012 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003013 xmlFreeNode(elem);
3014 return(cur);
3015 }
3016
3017 if (elem->doc != cur->doc) {
3018 xmlSetTreeDoc(elem, cur->doc);
3019 }
3020 parent = cur->parent;
3021 elem->prev = cur;
3022 elem->next = NULL;
3023 elem->parent = parent;
3024 cur->next = elem;
3025 if (parent != NULL)
3026 parent->last = elem;
3027
3028 return(elem);
3029}
3030
3031/**
3032 * xmlAddChildList:
3033 * @parent: the parent node
3034 * @cur: the first node in the list
3035 *
3036 * Add a list of node at the end of the child list of the parent
3037 * merging adjacent TEXT nodes (@cur may be freed)
3038 *
3039 * Returns the last child or NULL in case of error.
3040 */
3041xmlNodePtr
3042xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3043 xmlNodePtr prev;
3044
3045 if (parent == NULL) {
3046#ifdef DEBUG_TREE
3047 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003048 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003049#endif
3050 return(NULL);
3051 }
3052
3053 if (cur == NULL) {
3054#ifdef DEBUG_TREE
3055 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003056 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003057#endif
3058 return(NULL);
3059 }
3060
3061 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3062 (cur->doc != parent->doc)) {
3063#ifdef DEBUG_TREE
3064 xmlGenericError(xmlGenericErrorContext,
3065 "Elements moved to a different document\n");
3066#endif
3067 }
3068
3069 /*
3070 * add the first element at the end of the children list.
3071 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003072
Owen Taylor3473f882001-02-23 17:55:21 +00003073 if (parent->children == NULL) {
3074 parent->children = cur;
3075 } else {
3076 /*
3077 * If cur and parent->last both are TEXT nodes, then merge them.
3078 */
3079 if ((cur->type == XML_TEXT_NODE) &&
3080 (parent->last->type == XML_TEXT_NODE) &&
3081 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003082 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003083 /*
3084 * if it's the only child, nothing more to be done.
3085 */
3086 if (cur->next == NULL) {
3087 xmlFreeNode(cur);
3088 return(parent->last);
3089 }
3090 prev = cur;
3091 cur = cur->next;
3092 xmlFreeNode(prev);
3093 }
3094 prev = parent->last;
3095 prev->next = cur;
3096 cur->prev = prev;
3097 }
3098 while (cur->next != NULL) {
3099 cur->parent = parent;
3100 if (cur->doc != parent->doc) {
3101 xmlSetTreeDoc(cur, parent->doc);
3102 }
3103 cur = cur->next;
3104 }
3105 cur->parent = parent;
3106 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3107 parent->last = cur;
3108
3109 return(cur);
3110}
3111
3112/**
3113 * xmlAddChild:
3114 * @parent: the parent node
3115 * @cur: the child node
3116 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003117 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003118 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003119 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3120 * If there is an attribute with equal name, it is first destroyed.
3121 *
Owen Taylor3473f882001-02-23 17:55:21 +00003122 * Returns the child or NULL in case of error.
3123 */
3124xmlNodePtr
3125xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3126 xmlNodePtr prev;
3127
3128 if (parent == NULL) {
3129#ifdef DEBUG_TREE
3130 xmlGenericError(xmlGenericErrorContext,
3131 "xmlAddChild : parent == NULL\n");
3132#endif
3133 return(NULL);
3134 }
3135
3136 if (cur == NULL) {
3137#ifdef DEBUG_TREE
3138 xmlGenericError(xmlGenericErrorContext,
3139 "xmlAddChild : child == NULL\n");
3140#endif
3141 return(NULL);
3142 }
3143
Owen Taylor3473f882001-02-23 17:55:21 +00003144 /*
3145 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003146 * cur is then freed.
3147 */
3148 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003149 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003150 (parent->content != NULL) &&
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003151 (parent->name == cur->name) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003152 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003153 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003154 xmlFreeNode(cur);
3155 return(parent);
3156 }
3157 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003158 (parent->last->name == cur->name) &&
3159 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003160 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003161 xmlFreeNode(cur);
3162 return(parent->last);
3163 }
3164 }
3165
3166 /*
3167 * add the new element at the end of the children list.
3168 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003169 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003170 cur->parent = parent;
3171 if (cur->doc != parent->doc) {
3172 xmlSetTreeDoc(cur, parent->doc);
3173 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003174 /* this check prevents a loop on tree-traversions if a developer
3175 * tries to add a node to its parent multiple times
3176 */
3177 if (prev == parent)
3178 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003179
3180 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003181 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003182 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003183 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003184 (parent->content != NULL) &&
3185 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003186 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003187 xmlFreeNode(cur);
3188 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003189 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003190 if (cur->type == XML_ATTRIBUTE_NODE) {
3191 if (parent->properties == NULL) {
3192 parent->properties = (xmlAttrPtr) cur;
3193 } else {
3194 /* check if an attribute with the same name exists */
3195 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003196
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003197 if (cur->ns == NULL)
3198 lastattr = xmlHasProp(parent, cur->name);
3199 else
3200 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3201 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3202 /* different instance, destroy it (attributes must be unique) */
3203 xmlFreeProp(lastattr);
3204 }
3205 /* find the end */
3206 lastattr = parent->properties;
3207 while (lastattr->next != NULL) {
3208 lastattr = lastattr->next;
3209 }
3210 lastattr->next = (xmlAttrPtr) cur;
3211 ((xmlAttrPtr) cur)->prev = lastattr;
3212 }
3213 } else {
3214 if (parent->children == NULL) {
3215 parent->children = cur;
3216 parent->last = cur;
3217 } else {
3218 prev = parent->last;
3219 prev->next = cur;
3220 cur->prev = prev;
3221 parent->last = cur;
3222 }
3223 }
Owen Taylor3473f882001-02-23 17:55:21 +00003224 return(cur);
3225}
3226
3227/**
3228 * xmlGetLastChild:
3229 * @parent: the parent node
3230 *
3231 * Search the last child of a node.
3232 * Returns the last child or NULL if none.
3233 */
3234xmlNodePtr
3235xmlGetLastChild(xmlNodePtr parent) {
3236 if (parent == NULL) {
3237#ifdef DEBUG_TREE
3238 xmlGenericError(xmlGenericErrorContext,
3239 "xmlGetLastChild : parent == NULL\n");
3240#endif
3241 return(NULL);
3242 }
3243 return(parent->last);
3244}
3245
3246/**
3247 * xmlFreeNodeList:
3248 * @cur: the first node in the list
3249 *
3250 * Free a node and all its siblings, this is a recursive behaviour, all
3251 * the children are freed too.
3252 */
3253void
3254xmlFreeNodeList(xmlNodePtr cur) {
3255 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003256 xmlDictPtr dict = NULL;
3257
3258 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003259 if (cur->type == XML_NAMESPACE_DECL) {
3260 xmlFreeNsList((xmlNsPtr) cur);
3261 return;
3262 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003263 if ((cur->type == XML_DOCUMENT_NODE) ||
3264#ifdef LIBXML_DOCB_ENABLED
3265 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003266#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003267 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003268 xmlFreeDoc((xmlDocPtr) cur);
3269 return;
3270 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003271 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003272 while (cur != NULL) {
3273 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003274 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003275
Daniel Veillarda880b122003-04-21 21:36:41 +00003276 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003277 xmlDeregisterNodeDefaultValue(cur);
3278
Daniel Veillard02141ea2001-04-30 11:46:40 +00003279 if ((cur->children != NULL) &&
3280 (cur->type != XML_ENTITY_REF_NODE))
3281 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003282 if (((cur->type == XML_ELEMENT_NODE) ||
3283 (cur->type == XML_XINCLUDE_START) ||
3284 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003285 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003286 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003287 if ((cur->type != XML_ELEMENT_NODE) &&
3288 (cur->type != XML_XINCLUDE_START) &&
3289 (cur->type != XML_XINCLUDE_END) &&
Daniel Veillard8874b942005-08-25 13:19:21 +00003290 (cur->type != XML_ENTITY_REF_NODE) &&
3291 (cur->content != (xmlChar *) &(cur->properties))) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003292 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003293 }
3294 if (((cur->type == XML_ELEMENT_NODE) ||
3295 (cur->type == XML_XINCLUDE_START) ||
3296 (cur->type == XML_XINCLUDE_END)) &&
3297 (cur->nsDef != NULL))
3298 xmlFreeNsList(cur->nsDef);
3299
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003300 /*
3301 * When a node is a text node or a comment, it uses a global static
3302 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003303 * Otherwise the node name might come from the document's
3304 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003305 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003306 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003307 (cur->type != XML_TEXT_NODE) &&
3308 (cur->type != XML_COMMENT_NODE))
3309 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003310 xmlFree(cur);
3311 }
Owen Taylor3473f882001-02-23 17:55:21 +00003312 cur = next;
3313 }
3314}
3315
3316/**
3317 * xmlFreeNode:
3318 * @cur: the node
3319 *
3320 * Free a node, this is a recursive behaviour, all the children are freed too.
3321 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3322 */
3323void
3324xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003325 xmlDictPtr dict = NULL;
3326
3327 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003328
Daniel Veillard02141ea2001-04-30 11:46:40 +00003329 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003330 if (cur->type == XML_DTD_NODE) {
3331 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003332 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003333 }
3334 if (cur->type == XML_NAMESPACE_DECL) {
3335 xmlFreeNs((xmlNsPtr) cur);
3336 return;
3337 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003338 if (cur->type == XML_ATTRIBUTE_NODE) {
3339 xmlFreeProp((xmlAttrPtr) cur);
3340 return;
3341 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003342
Daniel Veillarda880b122003-04-21 21:36:41 +00003343 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003344 xmlDeregisterNodeDefaultValue(cur);
3345
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003346 if (cur->doc != NULL) dict = cur->doc->dict;
3347
Owen Taylor3473f882001-02-23 17:55:21 +00003348 if ((cur->children != NULL) &&
3349 (cur->type != XML_ENTITY_REF_NODE))
3350 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003351 if (((cur->type == XML_ELEMENT_NODE) ||
3352 (cur->type == XML_XINCLUDE_START) ||
3353 (cur->type == XML_XINCLUDE_END)) &&
3354 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003355 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003356 if ((cur->type != XML_ELEMENT_NODE) &&
3357 (cur->content != NULL) &&
3358 (cur->type != XML_ENTITY_REF_NODE) &&
3359 (cur->type != XML_XINCLUDE_END) &&
Daniel Veillard8874b942005-08-25 13:19:21 +00003360 (cur->type != XML_XINCLUDE_START) &&
3361 (cur->content != (xmlChar *) &(cur->properties))) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003362 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003363 }
3364
Daniel Veillardacd370f2001-06-09 17:17:51 +00003365 /*
3366 * When a node is a text node or a comment, it uses a global static
3367 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003368 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003369 */
Owen Taylor3473f882001-02-23 17:55:21 +00003370 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003371 (cur->type != XML_TEXT_NODE) &&
3372 (cur->type != XML_COMMENT_NODE))
3373 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003374
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003375 if (((cur->type == XML_ELEMENT_NODE) ||
3376 (cur->type == XML_XINCLUDE_START) ||
3377 (cur->type == XML_XINCLUDE_END)) &&
3378 (cur->nsDef != NULL))
3379 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003380 xmlFree(cur);
3381}
3382
3383/**
3384 * xmlUnlinkNode:
3385 * @cur: the node
3386 *
3387 * Unlink a node from it's current context, the node is not freed
3388 */
3389void
3390xmlUnlinkNode(xmlNodePtr cur) {
3391 if (cur == NULL) {
3392#ifdef DEBUG_TREE
3393 xmlGenericError(xmlGenericErrorContext,
3394 "xmlUnlinkNode : node == NULL\n");
3395#endif
3396 return;
3397 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003398 if (cur->type == XML_DTD_NODE) {
3399 xmlDocPtr doc;
3400 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003401 if (doc != NULL) {
3402 if (doc->intSubset == (xmlDtdPtr) cur)
3403 doc->intSubset = NULL;
3404 if (doc->extSubset == (xmlDtdPtr) cur)
3405 doc->extSubset = NULL;
3406 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003407 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003408 if (cur->parent != NULL) {
3409 xmlNodePtr parent;
3410 parent = cur->parent;
3411 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardda6f4af2005-06-20 17:17:54 +00003412 /* If attribute is an ID from subset then remove it */
3413 if ((((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID) &&
3414 xmlIsID(parent->doc, parent, (xmlAttrPtr) cur)) {
3415 xmlRemoveID(cur->doc, (xmlAttrPtr) cur);
3416 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003417 if (parent->properties == (xmlAttrPtr) cur)
3418 parent->properties = ((xmlAttrPtr) cur)->next;
3419 } else {
3420 if (parent->children == cur)
3421 parent->children = cur->next;
3422 if (parent->last == cur)
3423 parent->last = cur->prev;
3424 }
3425 cur->parent = NULL;
3426 }
Owen Taylor3473f882001-02-23 17:55:21 +00003427 if (cur->next != NULL)
3428 cur->next->prev = cur->prev;
3429 if (cur->prev != NULL)
3430 cur->prev->next = cur->next;
3431 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003432}
3433
Daniel Veillard2156d432004-03-04 15:59:36 +00003434#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003435/**
3436 * xmlReplaceNode:
3437 * @old: the old node
3438 * @cur: the node
3439 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003440 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003441 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003442 * first unlinked from its existing context.
3443 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003444 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003445 */
3446xmlNodePtr
3447xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00003448 if (old == cur) return(NULL);
Daniel Veillarda03e3652004-11-02 18:45:30 +00003449 if ((old == NULL) || (old->parent == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003450#ifdef DEBUG_TREE
3451 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda03e3652004-11-02 18:45:30 +00003452 "xmlReplaceNode : old == NULL or without parent\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003453#endif
3454 return(NULL);
3455 }
3456 if (cur == NULL) {
3457 xmlUnlinkNode(old);
3458 return(old);
3459 }
3460 if (cur == old) {
3461 return(old);
3462 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003463 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3464#ifdef DEBUG_TREE
3465 xmlGenericError(xmlGenericErrorContext,
3466 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3467#endif
3468 return(old);
3469 }
3470 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3471#ifdef DEBUG_TREE
3472 xmlGenericError(xmlGenericErrorContext,
3473 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3474#endif
3475 return(old);
3476 }
Owen Taylor3473f882001-02-23 17:55:21 +00003477 xmlUnlinkNode(cur);
Daniel Veillard64d7d122005-05-11 18:03:42 +00003478 xmlSetTreeDoc(cur, old->doc);
Owen Taylor3473f882001-02-23 17:55:21 +00003479 cur->parent = old->parent;
3480 cur->next = old->next;
3481 if (cur->next != NULL)
3482 cur->next->prev = cur;
3483 cur->prev = old->prev;
3484 if (cur->prev != NULL)
3485 cur->prev->next = cur;
3486 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003487 if (cur->type == XML_ATTRIBUTE_NODE) {
3488 if (cur->parent->properties == (xmlAttrPtr)old)
3489 cur->parent->properties = ((xmlAttrPtr) cur);
Daniel Veillardda6f4af2005-06-20 17:17:54 +00003490
3491 /* If old attribute is ID and defined in DTD then remove ID */
3492 if ((((xmlAttrPtr) old)->atype == XML_ATTRIBUTE_ID) &&
3493 xmlIsID(old->doc, old->parent, (xmlAttrPtr) old)) {
3494 xmlRemoveID(old->doc, (xmlAttrPtr) old);
3495 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003496 } else {
3497 if (cur->parent->children == old)
3498 cur->parent->children = cur;
3499 if (cur->parent->last == old)
3500 cur->parent->last = cur;
3501 }
Owen Taylor3473f882001-02-23 17:55:21 +00003502 }
3503 old->next = old->prev = NULL;
3504 old->parent = NULL;
3505 return(old);
3506}
Daniel Veillard652327a2003-09-29 18:02:38 +00003507#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003508
3509/************************************************************************
3510 * *
3511 * Copy operations *
3512 * *
3513 ************************************************************************/
3514
3515/**
3516 * xmlCopyNamespace:
3517 * @cur: the namespace
3518 *
3519 * Do a copy of the namespace.
3520 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003521 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003522 */
3523xmlNsPtr
3524xmlCopyNamespace(xmlNsPtr cur) {
3525 xmlNsPtr ret;
3526
3527 if (cur == NULL) return(NULL);
3528 switch (cur->type) {
3529 case XML_LOCAL_NAMESPACE:
3530 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3531 break;
3532 default:
3533#ifdef DEBUG_TREE
3534 xmlGenericError(xmlGenericErrorContext,
3535 "xmlCopyNamespace: invalid type %d\n", cur->type);
3536#endif
3537 return(NULL);
3538 }
3539 return(ret);
3540}
3541
3542/**
3543 * xmlCopyNamespaceList:
3544 * @cur: the first namespace
3545 *
3546 * Do a copy of an namespace list.
3547 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003548 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003549 */
3550xmlNsPtr
3551xmlCopyNamespaceList(xmlNsPtr cur) {
3552 xmlNsPtr ret = NULL;
3553 xmlNsPtr p = NULL,q;
3554
3555 while (cur != NULL) {
3556 q = xmlCopyNamespace(cur);
3557 if (p == NULL) {
3558 ret = p = q;
3559 } else {
3560 p->next = q;
3561 p = q;
3562 }
3563 cur = cur->next;
3564 }
3565 return(ret);
3566}
3567
3568static xmlNodePtr
3569xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3570/**
3571 * xmlCopyProp:
3572 * @target: the element where the attribute will be grafted
3573 * @cur: the attribute
3574 *
3575 * Do a copy of the attribute.
3576 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003577 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003578 */
3579xmlAttrPtr
3580xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3581 xmlAttrPtr ret;
3582
3583 if (cur == NULL) return(NULL);
3584 if (target != NULL)
3585 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3586 else if (cur->parent != NULL)
3587 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3588 else if (cur->children != NULL)
3589 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3590 else
3591 ret = xmlNewDocProp(NULL, cur->name, NULL);
3592 if (ret == NULL) return(NULL);
3593 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003594
Owen Taylor3473f882001-02-23 17:55:21 +00003595 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003596 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003597
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003598 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3599 if (ns == NULL) {
3600 /*
3601 * Humm, we are copying an element whose namespace is defined
3602 * out of the new tree scope. Search it in the original tree
3603 * and add it at the top of the new tree
3604 */
3605 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3606 if (ns != NULL) {
3607 xmlNodePtr root = target;
3608 xmlNodePtr pred = NULL;
3609
3610 while (root->parent != NULL) {
3611 pred = root;
3612 root = root->parent;
3613 }
3614 if (root == (xmlNodePtr) target->doc) {
3615 /* correct possibly cycling above the document elt */
3616 root = pred;
3617 }
3618 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3619 }
3620 } else {
3621 /*
3622 * we have to find something appropriate here since
3623 * we cant be sure, that the namespce we found is identified
3624 * by the prefix
3625 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003626 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003627 /* this is the nice case */
3628 ret->ns = ns;
3629 } else {
3630 /*
3631 * we are in trouble: we need a new reconcilied namespace.
3632 * This is expensive
3633 */
3634 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3635 }
3636 }
3637
Owen Taylor3473f882001-02-23 17:55:21 +00003638 } else
3639 ret->ns = NULL;
3640
3641 if (cur->children != NULL) {
3642 xmlNodePtr tmp;
3643
3644 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3645 ret->last = NULL;
3646 tmp = ret->children;
3647 while (tmp != NULL) {
3648 /* tmp->parent = (xmlNodePtr)ret; */
3649 if (tmp->next == NULL)
3650 ret->last = tmp;
3651 tmp = tmp->next;
3652 }
3653 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003654 /*
3655 * Try to handle IDs
3656 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003657 if ((target!= NULL) && (cur!= NULL) &&
3658 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003659 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3660 if (xmlIsID(cur->doc, cur->parent, cur)) {
3661 xmlChar *id;
3662
3663 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3664 if (id != NULL) {
3665 xmlAddID(NULL, target->doc, id, ret);
3666 xmlFree(id);
3667 }
3668 }
3669 }
Owen Taylor3473f882001-02-23 17:55:21 +00003670 return(ret);
3671}
3672
3673/**
3674 * xmlCopyPropList:
3675 * @target: the element where the attributes will be grafted
3676 * @cur: the first attribute
3677 *
3678 * Do a copy of an attribute list.
3679 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003680 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003681 */
3682xmlAttrPtr
3683xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3684 xmlAttrPtr ret = NULL;
3685 xmlAttrPtr p = NULL,q;
3686
3687 while (cur != NULL) {
3688 q = xmlCopyProp(target, cur);
William M. Brack13dfa872004-09-18 04:52:08 +00003689 if (q == NULL)
3690 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003691 if (p == NULL) {
3692 ret = p = q;
3693 } else {
3694 p->next = q;
3695 q->prev = p;
3696 p = q;
3697 }
3698 cur = cur->next;
3699 }
3700 return(ret);
3701}
3702
3703/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003704 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003705 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003706 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003707 * tricky reason: namespaces. Doing a direct copy of a node
3708 * say RPM:Copyright without changing the namespace pointer to
3709 * something else can produce stale links. One way to do it is
3710 * to keep a reference counter but this doesn't work as soon
3711 * as one move the element or the subtree out of the scope of
3712 * the existing namespace. The actual solution seems to add
3713 * a copy of the namespace at the top of the copied tree if
3714 * not available in the subtree.
3715 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00003716 * The argument "recursive" normally indicates a recursive copy
3717 * of the node with values 0 (no) and 1 (yes). For XInclude,
3718 * however, we allow a value of 2 to indicate copy properties and
3719 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00003720 */
3721
3722static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003723xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00003724 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003725 xmlNodePtr ret;
3726
3727 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003728 switch (node->type) {
3729 case XML_TEXT_NODE:
3730 case XML_CDATA_SECTION_NODE:
3731 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003732 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003733 case XML_ENTITY_REF_NODE:
3734 case XML_ENTITY_NODE:
3735 case XML_PI_NODE:
3736 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003737 case XML_XINCLUDE_START:
3738 case XML_XINCLUDE_END:
3739 break;
3740 case XML_ATTRIBUTE_NODE:
3741 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3742 case XML_NAMESPACE_DECL:
3743 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3744
Daniel Veillard39196eb2001-06-19 18:09:42 +00003745 case XML_DOCUMENT_NODE:
3746 case XML_HTML_DOCUMENT_NODE:
3747#ifdef LIBXML_DOCB_ENABLED
3748 case XML_DOCB_DOCUMENT_NODE:
3749#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003750#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00003751 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00003752#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003753 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003754 case XML_NOTATION_NODE:
3755 case XML_DTD_NODE:
3756 case XML_ELEMENT_DECL:
3757 case XML_ATTRIBUTE_DECL:
3758 case XML_ENTITY_DECL:
3759 return(NULL);
3760 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003761
Owen Taylor3473f882001-02-23 17:55:21 +00003762 /*
3763 * Allocate a new node and fill the fields.
3764 */
3765 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3766 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003767 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003768 return(NULL);
3769 }
3770 memset(ret, 0, sizeof(xmlNode));
3771 ret->type = node->type;
3772
3773 ret->doc = doc;
3774 ret->parent = parent;
3775 if (node->name == xmlStringText)
3776 ret->name = xmlStringText;
3777 else if (node->name == xmlStringTextNoenc)
3778 ret->name = xmlStringTextNoenc;
3779 else if (node->name == xmlStringComment)
3780 ret->name = xmlStringComment;
Daniel Veillard03a53c32004-10-26 16:06:51 +00003781 else if (node->name != NULL) {
3782 if ((doc != NULL) && (doc->dict != NULL))
3783 ret->name = xmlDictLookup(doc->dict, node->name, -1);
3784 else
3785 ret->name = xmlStrdup(node->name);
3786 }
Daniel Veillard7db37732001-07-12 01:20:08 +00003787 if ((node->type != XML_ELEMENT_NODE) &&
3788 (node->content != NULL) &&
3789 (node->type != XML_ENTITY_REF_NODE) &&
3790 (node->type != XML_XINCLUDE_END) &&
3791 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003792 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003793 }else{
3794 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003795 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003796 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003797 if (parent != NULL) {
3798 xmlNodePtr tmp;
3799
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003800 /*
3801 * this is a tricky part for the node register thing:
3802 * in case ret does get coalesced in xmlAddChild
3803 * the deregister-node callback is called; so we register ret now already
3804 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003805 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003806 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3807
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003808 tmp = xmlAddChild(parent, ret);
3809 /* node could have coalesced */
3810 if (tmp != ret)
3811 return(tmp);
3812 }
Owen Taylor3473f882001-02-23 17:55:21 +00003813
William M. Brack57e9e912004-03-09 16:19:02 +00003814 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003815 goto out;
Daniel Veillard8874b942005-08-25 13:19:21 +00003816 if ((node->type == XML_ELEMENT_NODE) && (node->nsDef != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00003817 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3818
3819 if (node->ns != NULL) {
3820 xmlNsPtr ns;
3821
3822 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3823 if (ns == NULL) {
3824 /*
3825 * Humm, we are copying an element whose namespace is defined
3826 * out of the new tree scope. Search it in the original tree
3827 * and add it at the top of the new tree
3828 */
3829 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3830 if (ns != NULL) {
3831 xmlNodePtr root = ret;
3832
3833 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003834 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003835 }
3836 } else {
3837 /*
3838 * reference the existing namespace definition in our own tree.
3839 */
3840 ret->ns = ns;
3841 }
3842 }
Daniel Veillard8874b942005-08-25 13:19:21 +00003843 if ((node->type == XML_ELEMENT_NODE) && (node->properties != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00003844 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003845 if (node->type == XML_ENTITY_REF_NODE) {
3846 if ((doc == NULL) || (node->doc != doc)) {
3847 /*
3848 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003849 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003850 * we cannot keep the reference. Try to find it in the
3851 * target document.
3852 */
3853 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3854 } else {
3855 ret->children = node->children;
3856 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003857 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00003858 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003859 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003860 UPDATE_LAST_CHILD_AND_PARENT(ret)
3861 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003862
3863out:
3864 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00003865 if ((parent == NULL) &&
3866 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003867 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003868 return(ret);
3869}
3870
3871static xmlNodePtr
3872xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3873 xmlNodePtr ret = NULL;
3874 xmlNodePtr p = NULL,q;
3875
3876 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003877#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003878 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003879 if (doc == NULL) {
3880 node = node->next;
3881 continue;
3882 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003883 if (doc->intSubset == NULL) {
3884 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3885 q->doc = doc;
3886 q->parent = parent;
3887 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003888 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003889 } else {
3890 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003891 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003892 }
3893 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003894#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003895 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003896 if (ret == NULL) {
3897 q->prev = NULL;
3898 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003899 } else if (p != q) {
3900 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003901 p->next = q;
3902 q->prev = p;
3903 p = q;
3904 }
3905 node = node->next;
3906 }
3907 return(ret);
3908}
3909
3910/**
3911 * xmlCopyNode:
3912 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00003913 * @extended: if 1 do a recursive copy (properties, namespaces and children
3914 * when applicable)
3915 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00003916 *
3917 * Do a copy of the node.
3918 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003919 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003920 */
3921xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003922xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003923 xmlNodePtr ret;
3924
William M. Brack57e9e912004-03-09 16:19:02 +00003925 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00003926 return(ret);
3927}
3928
3929/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003930 * xmlDocCopyNode:
3931 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003932 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00003933 * @extended: if 1 do a recursive copy (properties, namespaces and children
3934 * when applicable)
3935 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00003936 *
3937 * Do a copy of the node to a given document.
3938 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003939 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003940 */
3941xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003942xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003943 xmlNodePtr ret;
3944
William M. Brack57e9e912004-03-09 16:19:02 +00003945 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00003946 return(ret);
3947}
3948
3949/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00003950 * xmlDocCopyNodeList:
3951 * @doc: the target document
3952 * @node: the first node in the list.
3953 *
3954 * Do a recursive copy of the node list.
3955 *
3956 * Returns: a new #xmlNodePtr, or NULL in case of error.
3957 */
3958xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) {
3959 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
3960 return(ret);
3961}
3962
3963/**
Owen Taylor3473f882001-02-23 17:55:21 +00003964 * xmlCopyNodeList:
3965 * @node: the first node in the list.
3966 *
3967 * Do a recursive copy of the node list.
Daniel Veillard03a53c32004-10-26 16:06:51 +00003968 * Use xmlDocCopyNodeList() if possible to ensure string interning.
Owen Taylor3473f882001-02-23 17:55:21 +00003969 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003970 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003971 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003972xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003973 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3974 return(ret);
3975}
3976
Daniel Veillard2156d432004-03-04 15:59:36 +00003977#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003978/**
Owen Taylor3473f882001-02-23 17:55:21 +00003979 * xmlCopyDtd:
3980 * @dtd: the dtd
3981 *
3982 * Do a copy of the dtd.
3983 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003984 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003985 */
3986xmlDtdPtr
3987xmlCopyDtd(xmlDtdPtr dtd) {
3988 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003989 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003990
3991 if (dtd == NULL) return(NULL);
3992 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3993 if (ret == NULL) return(NULL);
3994 if (dtd->entities != NULL)
3995 ret->entities = (void *) xmlCopyEntitiesTable(
3996 (xmlEntitiesTablePtr) dtd->entities);
3997 if (dtd->notations != NULL)
3998 ret->notations = (void *) xmlCopyNotationTable(
3999 (xmlNotationTablePtr) dtd->notations);
4000 if (dtd->elements != NULL)
4001 ret->elements = (void *) xmlCopyElementTable(
4002 (xmlElementTablePtr) dtd->elements);
4003 if (dtd->attributes != NULL)
4004 ret->attributes = (void *) xmlCopyAttributeTable(
4005 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004006 if (dtd->pentities != NULL)
4007 ret->pentities = (void *) xmlCopyEntitiesTable(
4008 (xmlEntitiesTablePtr) dtd->pentities);
4009
4010 cur = dtd->children;
4011 while (cur != NULL) {
4012 q = NULL;
4013
4014 if (cur->type == XML_ENTITY_DECL) {
4015 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4016 switch (tmp->etype) {
4017 case XML_INTERNAL_GENERAL_ENTITY:
4018 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4019 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4020 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4021 break;
4022 case XML_INTERNAL_PARAMETER_ENTITY:
4023 case XML_EXTERNAL_PARAMETER_ENTITY:
4024 q = (xmlNodePtr)
4025 xmlGetParameterEntityFromDtd(ret, tmp->name);
4026 break;
4027 case XML_INTERNAL_PREDEFINED_ENTITY:
4028 break;
4029 }
4030 } else if (cur->type == XML_ELEMENT_DECL) {
4031 xmlElementPtr tmp = (xmlElementPtr) cur;
4032 q = (xmlNodePtr)
4033 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4034 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4035 xmlAttributePtr tmp = (xmlAttributePtr) cur;
4036 q = (xmlNodePtr)
4037 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4038 } else if (cur->type == XML_COMMENT_NODE) {
4039 q = xmlCopyNode(cur, 0);
4040 }
4041
4042 if (q == NULL) {
4043 cur = cur->next;
4044 continue;
4045 }
4046
4047 if (p == NULL)
4048 ret->children = q;
4049 else
4050 p->next = q;
4051
4052 q->prev = p;
4053 q->parent = (xmlNodePtr) ret;
4054 q->next = NULL;
4055 ret->last = q;
4056 p = q;
4057 cur = cur->next;
4058 }
4059
Owen Taylor3473f882001-02-23 17:55:21 +00004060 return(ret);
4061}
Daniel Veillard2156d432004-03-04 15:59:36 +00004062#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004063
Daniel Veillard2156d432004-03-04 15:59:36 +00004064#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004065/**
4066 * xmlCopyDoc:
4067 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004068 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004069 *
4070 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004071 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004072 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004073 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004074 */
4075xmlDocPtr
4076xmlCopyDoc(xmlDocPtr doc, int recursive) {
4077 xmlDocPtr ret;
4078
4079 if (doc == NULL) return(NULL);
4080 ret = xmlNewDoc(doc->version);
4081 if (ret == NULL) return(NULL);
4082 if (doc->name != NULL)
4083 ret->name = xmlMemStrdup(doc->name);
4084 if (doc->encoding != NULL)
4085 ret->encoding = xmlStrdup(doc->encoding);
Daniel Veillardf59507d2005-01-27 17:26:49 +00004086 if (doc->URL != NULL)
4087 ret->URL = xmlStrdup(doc->URL);
Owen Taylor3473f882001-02-23 17:55:21 +00004088 ret->charset = doc->charset;
4089 ret->compression = doc->compression;
4090 ret->standalone = doc->standalone;
4091 if (!recursive) return(ret);
4092
Daniel Veillardb33c2012001-04-25 12:59:04 +00004093 ret->last = NULL;
4094 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004095#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004096 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004097 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004098 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004099 ret->intSubset->parent = ret;
4100 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004101#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004102 if (doc->oldNs != NULL)
4103 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4104 if (doc->children != NULL) {
4105 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004106
4107 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4108 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004109 ret->last = NULL;
4110 tmp = ret->children;
4111 while (tmp != NULL) {
4112 if (tmp->next == NULL)
4113 ret->last = tmp;
4114 tmp = tmp->next;
4115 }
4116 }
4117 return(ret);
4118}
Daniel Veillard652327a2003-09-29 18:02:38 +00004119#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004120
4121/************************************************************************
4122 * *
4123 * Content access functions *
4124 * *
4125 ************************************************************************/
4126
4127/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004128 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004129 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004130 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004131 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004132 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004133 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004134 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004135 */
4136long
4137xmlGetLineNo(xmlNodePtr node)
4138{
4139 long result = -1;
4140
4141 if (!node)
4142 return result;
Daniel Veillard73da77e2005-08-24 14:05:37 +00004143 if ((node->type == XML_ELEMENT_NODE) ||
4144 (node->type == XML_TEXT_NODE) ||
4145 (node->type == XML_COMMENT_NODE) ||
4146 (node->type == XML_PI_NODE))
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004147 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004148 else if ((node->prev != NULL) &&
4149 ((node->prev->type == XML_ELEMENT_NODE) ||
Daniel Veillard73da77e2005-08-24 14:05:37 +00004150 (node->prev->type == XML_TEXT_NODE) ||
4151 (node->prev->type == XML_COMMENT_NODE) ||
4152 (node->prev->type == XML_PI_NODE)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004153 result = xmlGetLineNo(node->prev);
4154 else if ((node->parent != NULL) &&
Daniel Veillard73da77e2005-08-24 14:05:37 +00004155 (node->parent->type == XML_ELEMENT_NODE))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004156 result = xmlGetLineNo(node->parent);
4157
4158 return result;
4159}
4160
Daniel Veillard2156d432004-03-04 15:59:36 +00004161#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004162/**
4163 * xmlGetNodePath:
4164 * @node: a node
4165 *
4166 * Build a structure based Path for the given node
4167 *
4168 * Returns the new path or NULL in case of error. The caller must free
4169 * the returned string
4170 */
4171xmlChar *
4172xmlGetNodePath(xmlNodePtr node)
4173{
4174 xmlNodePtr cur, tmp, next;
4175 xmlChar *buffer = NULL, *temp;
4176 size_t buf_len;
4177 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004178 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004179 const char *name;
4180 char nametemp[100];
4181 int occur = 0;
4182
4183 if (node == NULL)
4184 return (NULL);
4185
4186 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004187 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004188 if (buffer == NULL) {
4189 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004190 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004191 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004192 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004193 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004194 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004195 xmlFree(buffer);
4196 return (NULL);
4197 }
4198
4199 buffer[0] = 0;
4200 cur = node;
4201 do {
4202 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004203 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004204 occur = 0;
4205 if ((cur->type == XML_DOCUMENT_NODE) ||
4206 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4207 if (buffer[0] == '/')
4208 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004209 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004210 next = NULL;
4211 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004212 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004213 name = (const char *) cur->name;
4214 if (cur->ns) {
William M. Brack84d83e32003-12-23 03:45:17 +00004215 if (cur->ns->prefix != NULL)
William M. Brack13dfa872004-09-18 04:52:08 +00004216 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4217 (char *)cur->ns->prefix, (char *)cur->name);
William M. Brack84d83e32003-12-23 03:45:17 +00004218 else
William M. Brack13dfa872004-09-18 04:52:08 +00004219 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4220 (char *)cur->name);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004221 nametemp[sizeof(nametemp) - 1] = 0;
4222 name = nametemp;
4223 }
4224 next = cur->parent;
4225
4226 /*
4227 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004228 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004229 */
4230 tmp = cur->prev;
4231 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004232 if ((tmp->type == XML_ELEMENT_NODE) &&
Daniel Veillard0996a162005-02-05 14:00:10 +00004233 (xmlStrEqual(cur->name, tmp->name)) &&
4234 ((tmp->ns == cur->ns) ||
4235 ((tmp->ns != NULL) && (cur->ns != NULL) &&
4236 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004237 occur++;
4238 tmp = tmp->prev;
4239 }
4240 if (occur == 0) {
4241 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004242 while (tmp != NULL && occur == 0) {
4243 if ((tmp->type == XML_ELEMENT_NODE) &&
Daniel Veillard0996a162005-02-05 14:00:10 +00004244 (xmlStrEqual(cur->name, tmp->name)) &&
4245 ((tmp->ns == cur->ns) ||
4246 ((tmp->ns != NULL) && (cur->ns != NULL) &&
4247 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004248 occur++;
4249 tmp = tmp->next;
4250 }
4251 if (occur != 0)
4252 occur = 1;
4253 } else
4254 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004255 } else if (cur->type == XML_COMMENT_NODE) {
4256 sep = "/";
4257 name = "comment()";
4258 next = cur->parent;
4259
4260 /*
4261 * Thumbler index computation
4262 */
4263 tmp = cur->prev;
4264 while (tmp != NULL) {
4265 if (tmp->type == XML_COMMENT_NODE)
4266 occur++;
4267 tmp = tmp->prev;
4268 }
4269 if (occur == 0) {
4270 tmp = cur->next;
4271 while (tmp != NULL && occur == 0) {
4272 if (tmp->type == XML_COMMENT_NODE)
4273 occur++;
4274 tmp = tmp->next;
4275 }
4276 if (occur != 0)
4277 occur = 1;
4278 } else
4279 occur++;
4280 } else if ((cur->type == XML_TEXT_NODE) ||
4281 (cur->type == XML_CDATA_SECTION_NODE)) {
4282 sep = "/";
4283 name = "text()";
4284 next = cur->parent;
4285
4286 /*
4287 * Thumbler index computation
4288 */
4289 tmp = cur->prev;
4290 while (tmp != NULL) {
4291 if ((cur->type == XML_TEXT_NODE) ||
4292 (cur->type == XML_CDATA_SECTION_NODE))
4293 occur++;
4294 tmp = tmp->prev;
4295 }
4296 if (occur == 0) {
4297 tmp = cur->next;
4298 while (tmp != NULL && occur == 0) {
Daniel Veillard1f8658a2004-08-14 21:46:31 +00004299 if ((tmp->type == XML_TEXT_NODE) ||
4300 (tmp->type == XML_CDATA_SECTION_NODE))
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004301 occur++;
4302 tmp = tmp->next;
4303 }
4304 if (occur != 0)
4305 occur = 1;
4306 } else
4307 occur++;
4308 } else if (cur->type == XML_PI_NODE) {
4309 sep = "/";
4310 snprintf(nametemp, sizeof(nametemp) - 1,
William M. Brack13dfa872004-09-18 04:52:08 +00004311 "processing-instruction('%s')", (char *)cur->name);
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004312 nametemp[sizeof(nametemp) - 1] = 0;
4313 name = nametemp;
4314
4315 next = cur->parent;
4316
4317 /*
4318 * Thumbler index computation
4319 */
4320 tmp = cur->prev;
4321 while (tmp != NULL) {
4322 if ((tmp->type == XML_PI_NODE) &&
4323 (xmlStrEqual(cur->name, tmp->name)))
4324 occur++;
4325 tmp = tmp->prev;
4326 }
4327 if (occur == 0) {
4328 tmp = cur->next;
4329 while (tmp != NULL && occur == 0) {
4330 if ((tmp->type == XML_PI_NODE) &&
4331 (xmlStrEqual(cur->name, tmp->name)))
4332 occur++;
4333 tmp = tmp->next;
4334 }
4335 if (occur != 0)
4336 occur = 1;
4337 } else
4338 occur++;
4339
Daniel Veillard8faa7832001-11-26 15:58:08 +00004340 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004341 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004342 name = (const char *) (((xmlAttrPtr) cur)->name);
Daniel Veillard365c8062005-07-19 11:31:55 +00004343 if (cur->ns) {
4344 if (cur->ns->prefix != NULL)
4345 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4346 (char *)cur->ns->prefix, (char *)cur->name);
4347 else
4348 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4349 (char *)cur->name);
4350 nametemp[sizeof(nametemp) - 1] = 0;
4351 name = nametemp;
4352 }
Daniel Veillard8faa7832001-11-26 15:58:08 +00004353 next = ((xmlAttrPtr) cur)->parent;
4354 } else {
4355 next = cur->parent;
4356 }
4357
4358 /*
4359 * Make sure there is enough room
4360 */
4361 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4362 buf_len =
4363 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4364 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4365 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004366 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004367 xmlFree(buf);
4368 xmlFree(buffer);
4369 return (NULL);
4370 }
4371 buffer = temp;
4372 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4373 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004374 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004375 xmlFree(buf);
4376 xmlFree(buffer);
4377 return (NULL);
4378 }
4379 buf = temp;
4380 }
4381 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004382 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004383 sep, name, (char *) buffer);
4384 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004385 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004386 sep, name, occur, (char *) buffer);
William M. Brack13dfa872004-09-18 04:52:08 +00004387 snprintf((char *) buffer, buf_len, "%s", (char *)buf);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004388 cur = next;
4389 } while (cur != NULL);
4390 xmlFree(buf);
4391 return (buffer);
4392}
Daniel Veillard652327a2003-09-29 18:02:38 +00004393#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004394
4395/**
Owen Taylor3473f882001-02-23 17:55:21 +00004396 * xmlDocGetRootElement:
4397 * @doc: the document
4398 *
4399 * Get the root element of the document (doc->children is a list
4400 * containing possibly comments, PIs, etc ...).
4401 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004402 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004403 */
4404xmlNodePtr
4405xmlDocGetRootElement(xmlDocPtr doc) {
4406 xmlNodePtr ret;
4407
4408 if (doc == NULL) return(NULL);
4409 ret = doc->children;
4410 while (ret != NULL) {
4411 if (ret->type == XML_ELEMENT_NODE)
4412 return(ret);
4413 ret = ret->next;
4414 }
4415 return(ret);
4416}
4417
Daniel Veillard2156d432004-03-04 15:59:36 +00004418#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004419/**
4420 * xmlDocSetRootElement:
4421 * @doc: the document
4422 * @root: the new document root element
4423 *
4424 * Set the root element of the document (doc->children is a list
4425 * containing possibly comments, PIs, etc ...).
4426 *
4427 * Returns the old root element if any was found
4428 */
4429xmlNodePtr
4430xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4431 xmlNodePtr old = NULL;
4432
4433 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004434 if (root == NULL)
4435 return(NULL);
4436 xmlUnlinkNode(root);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00004437 xmlSetTreeDoc(root, doc);
Daniel Veillardc575b992002-02-08 13:28:40 +00004438 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004439 old = doc->children;
4440 while (old != NULL) {
4441 if (old->type == XML_ELEMENT_NODE)
4442 break;
4443 old = old->next;
4444 }
4445 if (old == NULL) {
4446 if (doc->children == NULL) {
4447 doc->children = root;
4448 doc->last = root;
4449 } else {
4450 xmlAddSibling(doc->children, root);
4451 }
4452 } else {
4453 xmlReplaceNode(old, root);
4454 }
4455 return(old);
4456}
Daniel Veillard2156d432004-03-04 15:59:36 +00004457#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004458
Daniel Veillard2156d432004-03-04 15:59:36 +00004459#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004460/**
4461 * xmlNodeSetLang:
4462 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004463 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004464 *
4465 * Set the language of a node, i.e. the values of the xml:lang
4466 * attribute.
4467 */
4468void
4469xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004470 xmlNsPtr ns;
4471
Owen Taylor3473f882001-02-23 17:55:21 +00004472 if (cur == NULL) return;
4473 switch(cur->type) {
4474 case XML_TEXT_NODE:
4475 case XML_CDATA_SECTION_NODE:
4476 case XML_COMMENT_NODE:
4477 case XML_DOCUMENT_NODE:
4478 case XML_DOCUMENT_TYPE_NODE:
4479 case XML_DOCUMENT_FRAG_NODE:
4480 case XML_NOTATION_NODE:
4481 case XML_HTML_DOCUMENT_NODE:
4482 case XML_DTD_NODE:
4483 case XML_ELEMENT_DECL:
4484 case XML_ATTRIBUTE_DECL:
4485 case XML_ENTITY_DECL:
4486 case XML_PI_NODE:
4487 case XML_ENTITY_REF_NODE:
4488 case XML_ENTITY_NODE:
4489 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004490#ifdef LIBXML_DOCB_ENABLED
4491 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004492#endif
4493 case XML_XINCLUDE_START:
4494 case XML_XINCLUDE_END:
4495 return;
4496 case XML_ELEMENT_NODE:
4497 case XML_ATTRIBUTE_NODE:
4498 break;
4499 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004500 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4501 if (ns == NULL)
4502 return;
4503 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004504}
Daniel Veillard652327a2003-09-29 18:02:38 +00004505#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004506
4507/**
4508 * xmlNodeGetLang:
4509 * @cur: the node being checked
4510 *
4511 * Searches the language of a node, i.e. the values of the xml:lang
4512 * attribute or the one carried by the nearest ancestor.
4513 *
4514 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004515 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004516 */
4517xmlChar *
4518xmlNodeGetLang(xmlNodePtr cur) {
4519 xmlChar *lang;
4520
4521 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004522 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004523 if (lang != NULL)
4524 return(lang);
4525 cur = cur->parent;
4526 }
4527 return(NULL);
4528}
4529
4530
Daniel Veillard652327a2003-09-29 18:02:38 +00004531#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004532/**
4533 * xmlNodeSetSpacePreserve:
4534 * @cur: the node being changed
4535 * @val: the xml:space value ("0": default, 1: "preserve")
4536 *
4537 * Set (or reset) the space preserving behaviour of a node, i.e. the
4538 * value of the xml:space attribute.
4539 */
4540void
4541xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004542 xmlNsPtr ns;
4543
Owen Taylor3473f882001-02-23 17:55:21 +00004544 if (cur == NULL) return;
4545 switch(cur->type) {
4546 case XML_TEXT_NODE:
4547 case XML_CDATA_SECTION_NODE:
4548 case XML_COMMENT_NODE:
4549 case XML_DOCUMENT_NODE:
4550 case XML_DOCUMENT_TYPE_NODE:
4551 case XML_DOCUMENT_FRAG_NODE:
4552 case XML_NOTATION_NODE:
4553 case XML_HTML_DOCUMENT_NODE:
4554 case XML_DTD_NODE:
4555 case XML_ELEMENT_DECL:
4556 case XML_ATTRIBUTE_DECL:
4557 case XML_ENTITY_DECL:
4558 case XML_PI_NODE:
4559 case XML_ENTITY_REF_NODE:
4560 case XML_ENTITY_NODE:
4561 case XML_NAMESPACE_DECL:
4562 case XML_XINCLUDE_START:
4563 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004564#ifdef LIBXML_DOCB_ENABLED
4565 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004566#endif
4567 return;
4568 case XML_ELEMENT_NODE:
4569 case XML_ATTRIBUTE_NODE:
4570 break;
4571 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004572 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4573 if (ns == NULL)
4574 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004575 switch (val) {
4576 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004577 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004578 break;
4579 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004580 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004581 break;
4582 }
4583}
Daniel Veillard652327a2003-09-29 18:02:38 +00004584#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004585
4586/**
4587 * xmlNodeGetSpacePreserve:
4588 * @cur: the node being checked
4589 *
4590 * Searches the space preserving behaviour of a node, i.e. the values
4591 * of the xml:space attribute or the one carried by the nearest
4592 * ancestor.
4593 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004594 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004595 */
4596int
4597xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4598 xmlChar *space;
4599
4600 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004601 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004602 if (space != NULL) {
4603 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4604 xmlFree(space);
4605 return(1);
4606 }
4607 if (xmlStrEqual(space, BAD_CAST "default")) {
4608 xmlFree(space);
4609 return(0);
4610 }
4611 xmlFree(space);
4612 }
4613 cur = cur->parent;
4614 }
4615 return(-1);
4616}
4617
Daniel Veillard652327a2003-09-29 18:02:38 +00004618#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004619/**
4620 * xmlNodeSetName:
4621 * @cur: the node being changed
4622 * @name: the new tag name
4623 *
4624 * Set (or reset) the name of a node.
4625 */
4626void
4627xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00004628 xmlDocPtr doc;
4629 xmlDictPtr dict;
4630
Owen Taylor3473f882001-02-23 17:55:21 +00004631 if (cur == NULL) return;
4632 if (name == NULL) return;
4633 switch(cur->type) {
4634 case XML_TEXT_NODE:
4635 case XML_CDATA_SECTION_NODE:
4636 case XML_COMMENT_NODE:
4637 case XML_DOCUMENT_TYPE_NODE:
4638 case XML_DOCUMENT_FRAG_NODE:
4639 case XML_NOTATION_NODE:
4640 case XML_HTML_DOCUMENT_NODE:
4641 case XML_NAMESPACE_DECL:
4642 case XML_XINCLUDE_START:
4643 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004644#ifdef LIBXML_DOCB_ENABLED
4645 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004646#endif
4647 return;
4648 case XML_ELEMENT_NODE:
4649 case XML_ATTRIBUTE_NODE:
4650 case XML_PI_NODE:
4651 case XML_ENTITY_REF_NODE:
4652 case XML_ENTITY_NODE:
4653 case XML_DTD_NODE:
4654 case XML_DOCUMENT_NODE:
4655 case XML_ELEMENT_DECL:
4656 case XML_ATTRIBUTE_DECL:
4657 case XML_ENTITY_DECL:
4658 break;
4659 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00004660 doc = cur->doc;
4661 if (doc != NULL)
4662 dict = doc->dict;
4663 else
4664 dict = NULL;
4665 if (dict != NULL) {
4666 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
4667 xmlFree((xmlChar *) cur->name);
4668 cur->name = xmlDictLookup(dict, name, -1);
4669 } else {
4670 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4671 cur->name = xmlStrdup(name);
4672 }
Owen Taylor3473f882001-02-23 17:55:21 +00004673}
Daniel Veillard2156d432004-03-04 15:59:36 +00004674#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004675
Daniel Veillard2156d432004-03-04 15:59:36 +00004676#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004677/**
4678 * xmlNodeSetBase:
4679 * @cur: the node being changed
4680 * @uri: the new base URI
4681 *
4682 * Set (or reset) the base URI of a node, i.e. the value of the
4683 * xml:base attribute.
4684 */
4685void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004686xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004687 xmlNsPtr ns;
4688
Owen Taylor3473f882001-02-23 17:55:21 +00004689 if (cur == NULL) return;
4690 switch(cur->type) {
4691 case XML_TEXT_NODE:
4692 case XML_CDATA_SECTION_NODE:
4693 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004694 case XML_DOCUMENT_TYPE_NODE:
4695 case XML_DOCUMENT_FRAG_NODE:
4696 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004697 case XML_DTD_NODE:
4698 case XML_ELEMENT_DECL:
4699 case XML_ATTRIBUTE_DECL:
4700 case XML_ENTITY_DECL:
4701 case XML_PI_NODE:
4702 case XML_ENTITY_REF_NODE:
4703 case XML_ENTITY_NODE:
4704 case XML_NAMESPACE_DECL:
4705 case XML_XINCLUDE_START:
4706 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004707 return;
4708 case XML_ELEMENT_NODE:
4709 case XML_ATTRIBUTE_NODE:
4710 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004711 case XML_DOCUMENT_NODE:
4712#ifdef LIBXML_DOCB_ENABLED
4713 case XML_DOCB_DOCUMENT_NODE:
4714#endif
4715 case XML_HTML_DOCUMENT_NODE: {
4716 xmlDocPtr doc = (xmlDocPtr) cur;
4717
4718 if (doc->URL != NULL)
4719 xmlFree((xmlChar *) doc->URL);
4720 if (uri == NULL)
4721 doc->URL = NULL;
4722 else
4723 doc->URL = xmlStrdup(uri);
4724 return;
4725 }
Owen Taylor3473f882001-02-23 17:55:21 +00004726 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004727
4728 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4729 if (ns == NULL)
4730 return;
4731 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004732}
Daniel Veillard652327a2003-09-29 18:02:38 +00004733#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004734
4735/**
Owen Taylor3473f882001-02-23 17:55:21 +00004736 * xmlNodeGetBase:
4737 * @doc: the document the node pertains to
4738 * @cur: the node being checked
4739 *
4740 * Searches for the BASE URL. The code should work on both XML
4741 * and HTML document even if base mechanisms are completely different.
4742 * It returns the base as defined in RFC 2396 sections
4743 * 5.1.1. Base URI within Document Content
4744 * and
4745 * 5.1.2. Base URI from the Encapsulating Entity
4746 * However it does not return the document base (5.1.3), use
4747 * xmlDocumentGetBase() for this
4748 *
4749 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004750 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004751 */
4752xmlChar *
4753xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004754 xmlChar *oldbase = NULL;
4755 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004756
4757 if ((cur == NULL) && (doc == NULL))
4758 return(NULL);
4759 if (doc == NULL) doc = cur->doc;
4760 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4761 cur = doc->children;
4762 while ((cur != NULL) && (cur->name != NULL)) {
4763 if (cur->type != XML_ELEMENT_NODE) {
4764 cur = cur->next;
4765 continue;
4766 }
4767 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4768 cur = cur->children;
4769 continue;
4770 }
4771 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4772 cur = cur->children;
4773 continue;
4774 }
4775 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4776 return(xmlGetProp(cur, BAD_CAST "href"));
4777 }
4778 cur = cur->next;
4779 }
4780 return(NULL);
4781 }
4782 while (cur != NULL) {
4783 if (cur->type == XML_ENTITY_DECL) {
4784 xmlEntityPtr ent = (xmlEntityPtr) cur;
4785 return(xmlStrdup(ent->URI));
4786 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004787 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004788 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004789 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004790 if (oldbase != NULL) {
4791 newbase = xmlBuildURI(oldbase, base);
4792 if (newbase != NULL) {
4793 xmlFree(oldbase);
4794 xmlFree(base);
4795 oldbase = newbase;
4796 } else {
4797 xmlFree(oldbase);
4798 xmlFree(base);
4799 return(NULL);
4800 }
4801 } else {
4802 oldbase = base;
4803 }
4804 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4805 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4806 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4807 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004808 }
4809 }
Owen Taylor3473f882001-02-23 17:55:21 +00004810 cur = cur->parent;
4811 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004812 if ((doc != NULL) && (doc->URL != NULL)) {
4813 if (oldbase == NULL)
4814 return(xmlStrdup(doc->URL));
4815 newbase = xmlBuildURI(oldbase, doc->URL);
4816 xmlFree(oldbase);
4817 return(newbase);
4818 }
4819 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004820}
4821
4822/**
Daniel Veillard78697292003-10-19 20:44:43 +00004823 * xmlNodeBufGetContent:
4824 * @buffer: a buffer
4825 * @cur: the node being read
4826 *
4827 * Read the value of a node @cur, this can be either the text carried
4828 * directly by this node if it's a TEXT node or the aggregate string
4829 * of the values carried by this node child's (TEXT and ENTITY_REF).
4830 * Entity references are substituted.
4831 * Fills up the buffer @buffer with this value
4832 *
4833 * Returns 0 in case of success and -1 in case of error.
4834 */
4835int
4836xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4837{
4838 if ((cur == NULL) || (buffer == NULL)) return(-1);
4839 switch (cur->type) {
4840 case XML_CDATA_SECTION_NODE:
4841 case XML_TEXT_NODE:
4842 xmlBufferCat(buffer, cur->content);
4843 break;
4844 case XML_DOCUMENT_FRAG_NODE:
4845 case XML_ELEMENT_NODE:{
4846 xmlNodePtr tmp = cur;
4847
4848 while (tmp != NULL) {
4849 switch (tmp->type) {
4850 case XML_CDATA_SECTION_NODE:
4851 case XML_TEXT_NODE:
4852 if (tmp->content != NULL)
4853 xmlBufferCat(buffer, tmp->content);
4854 break;
4855 case XML_ENTITY_REF_NODE:
4856 xmlNodeBufGetContent(buffer, tmp->children);
4857 break;
4858 default:
4859 break;
4860 }
4861 /*
4862 * Skip to next node
4863 */
4864 if (tmp->children != NULL) {
4865 if (tmp->children->type != XML_ENTITY_DECL) {
4866 tmp = tmp->children;
4867 continue;
4868 }
4869 }
4870 if (tmp == cur)
4871 break;
4872
4873 if (tmp->next != NULL) {
4874 tmp = tmp->next;
4875 continue;
4876 }
4877
4878 do {
4879 tmp = tmp->parent;
4880 if (tmp == NULL)
4881 break;
4882 if (tmp == cur) {
4883 tmp = NULL;
4884 break;
4885 }
4886 if (tmp->next != NULL) {
4887 tmp = tmp->next;
4888 break;
4889 }
4890 } while (tmp != NULL);
4891 }
4892 break;
4893 }
4894 case XML_ATTRIBUTE_NODE:{
4895 xmlAttrPtr attr = (xmlAttrPtr) cur;
4896 xmlNodePtr tmp = attr->children;
4897
4898 while (tmp != NULL) {
4899 if (tmp->type == XML_TEXT_NODE)
4900 xmlBufferCat(buffer, tmp->content);
4901 else
4902 xmlNodeBufGetContent(buffer, tmp);
4903 tmp = tmp->next;
4904 }
4905 break;
4906 }
4907 case XML_COMMENT_NODE:
4908 case XML_PI_NODE:
4909 xmlBufferCat(buffer, cur->content);
4910 break;
4911 case XML_ENTITY_REF_NODE:{
4912 xmlEntityPtr ent;
4913 xmlNodePtr tmp;
4914
4915 /* lookup entity declaration */
4916 ent = xmlGetDocEntity(cur->doc, cur->name);
4917 if (ent == NULL)
4918 return(-1);
4919
4920 /* an entity content can be any "well balanced chunk",
4921 * i.e. the result of the content [43] production:
4922 * http://www.w3.org/TR/REC-xml#NT-content
4923 * -> we iterate through child nodes and recursive call
4924 * xmlNodeGetContent() which handles all possible node types */
4925 tmp = ent->children;
4926 while (tmp) {
4927 xmlNodeBufGetContent(buffer, tmp);
4928 tmp = tmp->next;
4929 }
4930 break;
4931 }
4932 case XML_ENTITY_NODE:
4933 case XML_DOCUMENT_TYPE_NODE:
4934 case XML_NOTATION_NODE:
4935 case XML_DTD_NODE:
4936 case XML_XINCLUDE_START:
4937 case XML_XINCLUDE_END:
4938 break;
4939 case XML_DOCUMENT_NODE:
4940#ifdef LIBXML_DOCB_ENABLED
4941 case XML_DOCB_DOCUMENT_NODE:
4942#endif
4943 case XML_HTML_DOCUMENT_NODE:
4944 cur = cur->children;
4945 while (cur!= NULL) {
4946 if ((cur->type == XML_ELEMENT_NODE) ||
4947 (cur->type == XML_TEXT_NODE) ||
4948 (cur->type == XML_CDATA_SECTION_NODE)) {
4949 xmlNodeBufGetContent(buffer, cur);
4950 }
4951 cur = cur->next;
4952 }
4953 break;
4954 case XML_NAMESPACE_DECL:
4955 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
4956 break;
4957 case XML_ELEMENT_DECL:
4958 case XML_ATTRIBUTE_DECL:
4959 case XML_ENTITY_DECL:
4960 break;
4961 }
4962 return(0);
4963}
4964/**
Owen Taylor3473f882001-02-23 17:55:21 +00004965 * xmlNodeGetContent:
4966 * @cur: the node being read
4967 *
4968 * Read the value of a node, this can be either the text carried
4969 * directly by this node if it's a TEXT node or the aggregate string
4970 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004971 * Entity references are substituted.
4972 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004973 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004974 */
4975xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004976xmlNodeGetContent(xmlNodePtr cur)
4977{
4978 if (cur == NULL)
4979 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004980 switch (cur->type) {
4981 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004982 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00004983 xmlBufferPtr buffer;
4984 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004985
Daniel Veillard814a76d2003-01-23 18:24:20 +00004986 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004987 if (buffer == NULL)
4988 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00004989 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004990 ret = buffer->content;
4991 buffer->content = NULL;
4992 xmlBufferFree(buffer);
4993 return (ret);
4994 }
4995 case XML_ATTRIBUTE_NODE:{
4996 xmlAttrPtr attr = (xmlAttrPtr) cur;
4997
4998 if (attr->parent != NULL)
4999 return (xmlNodeListGetString
5000 (attr->parent->doc, attr->children, 1));
5001 else
5002 return (xmlNodeListGetString(NULL, attr->children, 1));
5003 break;
5004 }
Owen Taylor3473f882001-02-23 17:55:21 +00005005 case XML_COMMENT_NODE:
5006 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005007 if (cur->content != NULL)
5008 return (xmlStrdup(cur->content));
5009 return (NULL);
5010 case XML_ENTITY_REF_NODE:{
5011 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00005012 xmlBufferPtr buffer;
5013 xmlChar *ret;
5014
5015 /* lookup entity declaration */
5016 ent = xmlGetDocEntity(cur->doc, cur->name);
5017 if (ent == NULL)
5018 return (NULL);
5019
5020 buffer = xmlBufferCreate();
5021 if (buffer == NULL)
5022 return (NULL);
5023
Daniel Veillardc4696922003-10-19 21:47:14 +00005024 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005025
5026 ret = buffer->content;
5027 buffer->content = NULL;
5028 xmlBufferFree(buffer);
5029 return (ret);
5030 }
Owen Taylor3473f882001-02-23 17:55:21 +00005031 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005032 case XML_DOCUMENT_TYPE_NODE:
5033 case XML_NOTATION_NODE:
5034 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005035 case XML_XINCLUDE_START:
5036 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00005037 return (NULL);
5038 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005039#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005040 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005041#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005042 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00005043 xmlBufferPtr buffer;
5044 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005045
Daniel Veillardc4696922003-10-19 21:47:14 +00005046 buffer = xmlBufferCreate();
5047 if (buffer == NULL)
5048 return (NULL);
5049
5050 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5051
5052 ret = buffer->content;
5053 buffer->content = NULL;
5054 xmlBufferFree(buffer);
5055 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005056 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005057 case XML_NAMESPACE_DECL: {
5058 xmlChar *tmp;
5059
5060 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5061 return (tmp);
5062 }
Owen Taylor3473f882001-02-23 17:55:21 +00005063 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005064 /* TODO !!! */
5065 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005066 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005067 /* TODO !!! */
5068 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005069 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005070 /* TODO !!! */
5071 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005072 case XML_CDATA_SECTION_NODE:
5073 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005074 if (cur->content != NULL)
5075 return (xmlStrdup(cur->content));
5076 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005077 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005078 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005079}
Daniel Veillard652327a2003-09-29 18:02:38 +00005080
Owen Taylor3473f882001-02-23 17:55:21 +00005081/**
5082 * xmlNodeSetContent:
5083 * @cur: the node being modified
5084 * @content: the new value of the content
5085 *
5086 * Replace the content of a node.
5087 */
5088void
5089xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5090 if (cur == NULL) {
5091#ifdef DEBUG_TREE
5092 xmlGenericError(xmlGenericErrorContext,
5093 "xmlNodeSetContent : node == NULL\n");
5094#endif
5095 return;
5096 }
5097 switch (cur->type) {
5098 case XML_DOCUMENT_FRAG_NODE:
5099 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005100 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005101 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5102 cur->children = xmlStringGetNodeList(cur->doc, content);
5103 UPDATE_LAST_CHILD_AND_PARENT(cur)
5104 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005105 case XML_TEXT_NODE:
5106 case XML_CDATA_SECTION_NODE:
5107 case XML_ENTITY_REF_NODE:
5108 case XML_ENTITY_NODE:
5109 case XML_PI_NODE:
5110 case XML_COMMENT_NODE:
Daniel Veillard8874b942005-08-25 13:19:21 +00005111 if ((cur->content != NULL) &&
5112 (cur->content != (xmlChar *) &(cur->properties))) {
William M. Brack7762bb12004-01-04 14:49:01 +00005113 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
Daniel Veillardc587bce2005-05-10 15:28:08 +00005114 (xmlDictOwns(cur->doc->dict, cur->content))))
William M. Brack7762bb12004-01-04 14:49:01 +00005115 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005116 }
5117 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5118 cur->last = cur->children = NULL;
5119 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005120 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005121 } else
5122 cur->content = NULL;
Daniel Veillard8874b942005-08-25 13:19:21 +00005123 cur->properties = NULL;
5124 cur->nsDef = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00005125 break;
5126 case XML_DOCUMENT_NODE:
5127 case XML_HTML_DOCUMENT_NODE:
5128 case XML_DOCUMENT_TYPE_NODE:
5129 case XML_XINCLUDE_START:
5130 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005131#ifdef LIBXML_DOCB_ENABLED
5132 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005133#endif
5134 break;
5135 case XML_NOTATION_NODE:
5136 break;
5137 case XML_DTD_NODE:
5138 break;
5139 case XML_NAMESPACE_DECL:
5140 break;
5141 case XML_ELEMENT_DECL:
5142 /* TODO !!! */
5143 break;
5144 case XML_ATTRIBUTE_DECL:
5145 /* TODO !!! */
5146 break;
5147 case XML_ENTITY_DECL:
5148 /* TODO !!! */
5149 break;
5150 }
5151}
5152
Daniel Veillard652327a2003-09-29 18:02:38 +00005153#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005154/**
5155 * xmlNodeSetContentLen:
5156 * @cur: the node being modified
5157 * @content: the new value of the content
5158 * @len: the size of @content
5159 *
5160 * Replace the content of a node.
5161 */
5162void
5163xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5164 if (cur == NULL) {
5165#ifdef DEBUG_TREE
5166 xmlGenericError(xmlGenericErrorContext,
5167 "xmlNodeSetContentLen : node == NULL\n");
5168#endif
5169 return;
5170 }
5171 switch (cur->type) {
5172 case XML_DOCUMENT_FRAG_NODE:
5173 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005174 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005175 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5176 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5177 UPDATE_LAST_CHILD_AND_PARENT(cur)
5178 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005179 case XML_TEXT_NODE:
5180 case XML_CDATA_SECTION_NODE:
5181 case XML_ENTITY_REF_NODE:
5182 case XML_ENTITY_NODE:
5183 case XML_PI_NODE:
5184 case XML_COMMENT_NODE:
5185 case XML_NOTATION_NODE:
Daniel Veillard8874b942005-08-25 13:19:21 +00005186 if ((cur->content != NULL) &&
5187 (cur->content != (xmlChar *) &(cur->properties))) {
5188 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5189 (xmlDictOwns(cur->doc->dict, cur->content))))
5190 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005191 }
5192 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5193 cur->children = cur->last = NULL;
5194 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005195 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005196 } else
5197 cur->content = NULL;
Daniel Veillard8874b942005-08-25 13:19:21 +00005198 cur->properties = NULL;
5199 cur->nsDef = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00005200 break;
5201 case XML_DOCUMENT_NODE:
5202 case XML_DTD_NODE:
5203 case XML_HTML_DOCUMENT_NODE:
5204 case XML_DOCUMENT_TYPE_NODE:
5205 case XML_NAMESPACE_DECL:
5206 case XML_XINCLUDE_START:
5207 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005208#ifdef LIBXML_DOCB_ENABLED
5209 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005210#endif
5211 break;
5212 case XML_ELEMENT_DECL:
5213 /* TODO !!! */
5214 break;
5215 case XML_ATTRIBUTE_DECL:
5216 /* TODO !!! */
5217 break;
5218 case XML_ENTITY_DECL:
5219 /* TODO !!! */
5220 break;
5221 }
5222}
Daniel Veillard652327a2003-09-29 18:02:38 +00005223#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005224
5225/**
5226 * xmlNodeAddContentLen:
5227 * @cur: the node being modified
5228 * @content: extra content
5229 * @len: the size of @content
5230 *
5231 * Append the extra substring to the node content.
5232 */
5233void
5234xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5235 if (cur == NULL) {
5236#ifdef DEBUG_TREE
5237 xmlGenericError(xmlGenericErrorContext,
5238 "xmlNodeAddContentLen : node == NULL\n");
5239#endif
5240 return;
5241 }
5242 if (len <= 0) return;
5243 switch (cur->type) {
5244 case XML_DOCUMENT_FRAG_NODE:
5245 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005246 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005247
Daniel Veillard7db37732001-07-12 01:20:08 +00005248 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005249 newNode = xmlNewTextLen(content, len);
5250 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005251 tmp = xmlAddChild(cur, newNode);
5252 if (tmp != newNode)
5253 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005254 if ((last != NULL) && (last->next == newNode)) {
5255 xmlTextMerge(last, newNode);
5256 }
5257 }
5258 break;
5259 }
5260 case XML_ATTRIBUTE_NODE:
5261 break;
5262 case XML_TEXT_NODE:
5263 case XML_CDATA_SECTION_NODE:
5264 case XML_ENTITY_REF_NODE:
5265 case XML_ENTITY_NODE:
5266 case XML_PI_NODE:
5267 case XML_COMMENT_NODE:
5268 case XML_NOTATION_NODE:
5269 if (content != NULL) {
Daniel Veillard8874b942005-08-25 13:19:21 +00005270 if ((cur->content == (xmlChar *) &(cur->properties)) ||
5271 ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5272 xmlDictOwns(cur->doc->dict, cur->content))) {
5273 cur->content = xmlStrncatNew(cur->content, content, len);
5274 cur->properties = NULL;
5275 cur->nsDef = NULL;
William M. Brack7762bb12004-01-04 14:49:01 +00005276 break;
5277 }
Owen Taylor3473f882001-02-23 17:55:21 +00005278 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005279 }
5280 case XML_DOCUMENT_NODE:
5281 case XML_DTD_NODE:
5282 case XML_HTML_DOCUMENT_NODE:
5283 case XML_DOCUMENT_TYPE_NODE:
5284 case XML_NAMESPACE_DECL:
5285 case XML_XINCLUDE_START:
5286 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005287#ifdef LIBXML_DOCB_ENABLED
5288 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005289#endif
5290 break;
5291 case XML_ELEMENT_DECL:
5292 case XML_ATTRIBUTE_DECL:
5293 case XML_ENTITY_DECL:
5294 break;
5295 }
5296}
5297
5298/**
5299 * xmlNodeAddContent:
5300 * @cur: the node being modified
5301 * @content: extra content
5302 *
5303 * Append the extra substring to the node content.
5304 */
5305void
5306xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5307 int len;
5308
5309 if (cur == NULL) {
5310#ifdef DEBUG_TREE
5311 xmlGenericError(xmlGenericErrorContext,
5312 "xmlNodeAddContent : node == NULL\n");
5313#endif
5314 return;
5315 }
5316 if (content == NULL) return;
5317 len = xmlStrlen(content);
5318 xmlNodeAddContentLen(cur, content, len);
5319}
5320
5321/**
5322 * xmlTextMerge:
5323 * @first: the first text node
5324 * @second: the second text node being merged
5325 *
5326 * Merge two text nodes into one
5327 * Returns the first text node augmented
5328 */
5329xmlNodePtr
5330xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5331 if (first == NULL) return(second);
5332 if (second == NULL) return(first);
5333 if (first->type != XML_TEXT_NODE) return(first);
5334 if (second->type != XML_TEXT_NODE) return(first);
5335 if (second->name != first->name)
5336 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005337 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005338 xmlUnlinkNode(second);
5339 xmlFreeNode(second);
5340 return(first);
5341}
5342
Daniel Veillard2156d432004-03-04 15:59:36 +00005343#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005344/**
5345 * xmlGetNsList:
5346 * @doc: the document
5347 * @node: the current node
5348 *
5349 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005350 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005351 * that need to be freed by the caller or NULL if no
5352 * namespace if defined
5353 */
5354xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005355xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5356{
Owen Taylor3473f882001-02-23 17:55:21 +00005357 xmlNsPtr cur;
5358 xmlNsPtr *ret = NULL;
5359 int nbns = 0;
5360 int maxns = 10;
5361 int i;
5362
5363 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005364 if (node->type == XML_ELEMENT_NODE) {
5365 cur = node->nsDef;
5366 while (cur != NULL) {
5367 if (ret == NULL) {
5368 ret =
5369 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5370 sizeof(xmlNsPtr));
5371 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005372 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005373 return (NULL);
5374 }
5375 ret[nbns] = NULL;
5376 }
5377 for (i = 0; i < nbns; i++) {
5378 if ((cur->prefix == ret[i]->prefix) ||
5379 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5380 break;
5381 }
5382 if (i >= nbns) {
5383 if (nbns >= maxns) {
5384 maxns *= 2;
5385 ret = (xmlNsPtr *) xmlRealloc(ret,
5386 (maxns +
5387 1) *
5388 sizeof(xmlNsPtr));
5389 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005390 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005391 return (NULL);
5392 }
5393 }
5394 ret[nbns++] = cur;
5395 ret[nbns] = NULL;
5396 }
Owen Taylor3473f882001-02-23 17:55:21 +00005397
Daniel Veillard77044732001-06-29 21:31:07 +00005398 cur = cur->next;
5399 }
5400 }
5401 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005402 }
Daniel Veillard77044732001-06-29 21:31:07 +00005403 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005404}
Daniel Veillard652327a2003-09-29 18:02:38 +00005405#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005406
5407/**
5408 * xmlSearchNs:
5409 * @doc: the document
5410 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005411 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005412 *
5413 * Search a Ns registered under a given name space for a document.
5414 * recurse on the parents until it finds the defined namespace
5415 * or return NULL otherwise.
5416 * @nameSpace can be NULL, this is a search for the default namespace.
5417 * We don't allow to cross entities boundaries. If you don't declare
5418 * the namespace within those you will be in troubles !!! A warning
5419 * is generated to cover this case.
5420 *
5421 * Returns the namespace pointer or NULL.
5422 */
5423xmlNsPtr
5424xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005425
Owen Taylor3473f882001-02-23 17:55:21 +00005426 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005427 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005428
5429 if (node == NULL) return(NULL);
5430 if ((nameSpace != NULL) &&
5431 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005432 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5433 /*
5434 * The XML-1.0 namespace is normally held on the root
5435 * element. In this case exceptionally create it on the
5436 * node element.
5437 */
5438 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5439 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005440 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005441 return(NULL);
5442 }
5443 memset(cur, 0, sizeof(xmlNs));
5444 cur->type = XML_LOCAL_NAMESPACE;
5445 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5446 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5447 cur->next = node->nsDef;
5448 node->nsDef = cur;
5449 return(cur);
5450 }
Owen Taylor3473f882001-02-23 17:55:21 +00005451 if (doc->oldNs == NULL) {
5452 /*
5453 * Allocate a new Namespace and fill the fields.
5454 */
5455 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5456 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005457 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005458 return(NULL);
5459 }
5460 memset(doc->oldNs, 0, sizeof(xmlNs));
5461 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5462
5463 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5464 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5465 }
5466 return(doc->oldNs);
5467 }
5468 while (node != NULL) {
5469 if ((node->type == XML_ENTITY_REF_NODE) ||
5470 (node->type == XML_ENTITY_NODE) ||
5471 (node->type == XML_ENTITY_DECL))
5472 return(NULL);
5473 if (node->type == XML_ELEMENT_NODE) {
5474 cur = node->nsDef;
5475 while (cur != NULL) {
5476 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5477 (cur->href != NULL))
5478 return(cur);
5479 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5480 (cur->href != NULL) &&
5481 (xmlStrEqual(cur->prefix, nameSpace)))
5482 return(cur);
5483 cur = cur->next;
5484 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005485 if (orig != node) {
5486 cur = node->ns;
5487 if (cur != NULL) {
5488 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5489 (cur->href != NULL))
5490 return(cur);
5491 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5492 (cur->href != NULL) &&
5493 (xmlStrEqual(cur->prefix, nameSpace)))
5494 return(cur);
5495 }
5496 }
Owen Taylor3473f882001-02-23 17:55:21 +00005497 }
5498 node = node->parent;
5499 }
5500 return(NULL);
5501}
5502
5503/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005504 * xmlNsInScope:
5505 * @doc: the document
5506 * @node: the current node
5507 * @ancestor: the ancestor carrying the namespace
5508 * @prefix: the namespace prefix
5509 *
5510 * Verify that the given namespace held on @ancestor is still in scope
5511 * on node.
5512 *
5513 * Returns 1 if true, 0 if false and -1 in case of error.
5514 */
5515static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005516xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5517 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005518{
5519 xmlNsPtr tst;
5520
5521 while ((node != NULL) && (node != ancestor)) {
5522 if ((node->type == XML_ENTITY_REF_NODE) ||
5523 (node->type == XML_ENTITY_NODE) ||
5524 (node->type == XML_ENTITY_DECL))
5525 return (-1);
5526 if (node->type == XML_ELEMENT_NODE) {
5527 tst = node->nsDef;
5528 while (tst != NULL) {
5529 if ((tst->prefix == NULL)
5530 && (prefix == NULL))
5531 return (0);
5532 if ((tst->prefix != NULL)
5533 && (prefix != NULL)
5534 && (xmlStrEqual(tst->prefix, prefix)))
5535 return (0);
5536 tst = tst->next;
5537 }
5538 }
5539 node = node->parent;
5540 }
5541 if (node != ancestor)
5542 return (-1);
5543 return (1);
5544}
5545
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005546/**
Owen Taylor3473f882001-02-23 17:55:21 +00005547 * xmlSearchNsByHref:
5548 * @doc: the document
5549 * @node: the current node
5550 * @href: the namespace value
5551 *
5552 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5553 * the defined namespace or return NULL otherwise.
5554 * Returns the namespace pointer or NULL.
5555 */
5556xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005557xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5558{
Owen Taylor3473f882001-02-23 17:55:21 +00005559 xmlNsPtr cur;
5560 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005561 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005562
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005563 if ((node == NULL) || (href == NULL))
5564 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005565 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005566 /*
5567 * Only the document can hold the XML spec namespace.
5568 */
5569 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5570 /*
5571 * The XML-1.0 namespace is normally held on the root
5572 * element. In this case exceptionally create it on the
5573 * node element.
5574 */
5575 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5576 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005577 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005578 return (NULL);
5579 }
5580 memset(cur, 0, sizeof(xmlNs));
5581 cur->type = XML_LOCAL_NAMESPACE;
5582 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5583 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5584 cur->next = node->nsDef;
5585 node->nsDef = cur;
5586 return (cur);
5587 }
5588 if (doc->oldNs == NULL) {
5589 /*
5590 * Allocate a new Namespace and fill the fields.
5591 */
5592 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5593 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005594 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005595 return (NULL);
5596 }
5597 memset(doc->oldNs, 0, sizeof(xmlNs));
5598 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005599
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005600 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5601 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5602 }
5603 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005604 }
Daniel Veillard62040be2004-05-17 03:17:26 +00005605 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00005606 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005607 if ((node->type == XML_ENTITY_REF_NODE) ||
5608 (node->type == XML_ENTITY_NODE) ||
5609 (node->type == XML_ENTITY_DECL))
5610 return (NULL);
5611 if (node->type == XML_ELEMENT_NODE) {
5612 cur = node->nsDef;
5613 while (cur != NULL) {
5614 if ((cur->href != NULL) && (href != NULL) &&
5615 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005616 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00005617 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005618 return (cur);
5619 }
5620 cur = cur->next;
5621 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005622 if (orig != node) {
5623 cur = node->ns;
5624 if (cur != NULL) {
5625 if ((cur->href != NULL) && (href != NULL) &&
5626 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005627 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00005628 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00005629 return (cur);
5630 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005631 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005632 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005633 }
5634 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005635 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005636 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005637}
5638
5639/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005640 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005641 * @doc: the document
5642 * @tree: a node expected to hold the new namespace
5643 * @ns: the original namespace
5644 *
5645 * This function tries to locate a namespace definition in a tree
5646 * ancestors, or create a new namespace definition node similar to
5647 * @ns trying to reuse the same prefix. However if the given prefix is
5648 * null (default namespace) or reused within the subtree defined by
5649 * @tree or on one of its ancestors then a new prefix is generated.
5650 * Returns the (new) namespace definition or NULL in case of error
5651 */
5652xmlNsPtr
5653xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5654 xmlNsPtr def;
5655 xmlChar prefix[50];
5656 int counter = 1;
5657
5658 if (tree == NULL) {
5659#ifdef DEBUG_TREE
5660 xmlGenericError(xmlGenericErrorContext,
5661 "xmlNewReconciliedNs : tree == NULL\n");
5662#endif
5663 return(NULL);
5664 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00005665 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005666#ifdef DEBUG_TREE
5667 xmlGenericError(xmlGenericErrorContext,
5668 "xmlNewReconciliedNs : ns == NULL\n");
5669#endif
5670 return(NULL);
5671 }
5672 /*
5673 * Search an existing namespace definition inherited.
5674 */
5675 def = xmlSearchNsByHref(doc, tree, ns->href);
5676 if (def != NULL)
5677 return(def);
5678
5679 /*
5680 * Find a close prefix which is not already in use.
5681 * Let's strip namespace prefixes longer than 20 chars !
5682 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005683 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005684 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005685 else
William M. Brack13dfa872004-09-18 04:52:08 +00005686 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005687
Owen Taylor3473f882001-02-23 17:55:21 +00005688 def = xmlSearchNs(doc, tree, prefix);
5689 while (def != NULL) {
5690 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005691 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005692 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005693 else
William M. Brack13dfa872004-09-18 04:52:08 +00005694 snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
5695 (char *)ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005696 def = xmlSearchNs(doc, tree, prefix);
5697 }
5698
5699 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005700 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005701 */
5702 def = xmlNewNs(tree, ns->href, prefix);
5703 return(def);
5704}
5705
Daniel Veillard652327a2003-09-29 18:02:38 +00005706#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005707/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005708 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005709 * @doc: the document
5710 * @tree: a node defining the subtree to reconciliate
5711 *
5712 * This function checks that all the namespaces declared within the given
5713 * tree are properly declared. This is needed for example after Copy or Cut
5714 * and then paste operations. The subtree may still hold pointers to
5715 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005716 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005717 * the new environment. If not possible the new namespaces are redeclared
5718 * on @tree at the top of the given subtree.
5719 * Returns the number of namespace declarations created or -1 in case of error.
5720 */
5721int
5722xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5723 xmlNsPtr *oldNs = NULL;
5724 xmlNsPtr *newNs = NULL;
5725 int sizeCache = 0;
5726 int nbCache = 0;
5727
5728 xmlNsPtr n;
5729 xmlNodePtr node = tree;
5730 xmlAttrPtr attr;
5731 int ret = 0, i;
5732
Daniel Veillardce244ad2004-11-05 10:03:46 +00005733 if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1);
5734 if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1);
5735 if (node->doc != doc) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005736 while (node != NULL) {
5737 /*
5738 * Reconciliate the node namespace
5739 */
5740 if (node->ns != NULL) {
5741 /*
5742 * initialize the cache if needed
5743 */
5744 if (sizeCache == 0) {
5745 sizeCache = 10;
5746 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5747 sizeof(xmlNsPtr));
5748 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005749 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005750 return(-1);
5751 }
5752 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5753 sizeof(xmlNsPtr));
5754 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005755 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005756 xmlFree(oldNs);
5757 return(-1);
5758 }
5759 }
5760 for (i = 0;i < nbCache;i++) {
5761 if (oldNs[i] == node->ns) {
5762 node->ns = newNs[i];
5763 break;
5764 }
5765 }
5766 if (i == nbCache) {
5767 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005768 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005769 */
5770 n = xmlNewReconciliedNs(doc, tree, node->ns);
5771 if (n != NULL) { /* :-( what if else ??? */
5772 /*
5773 * check if we need to grow the cache buffers.
5774 */
5775 if (sizeCache <= nbCache) {
5776 sizeCache *= 2;
5777 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5778 sizeof(xmlNsPtr));
5779 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005780 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005781 xmlFree(newNs);
5782 return(-1);
5783 }
5784 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5785 sizeof(xmlNsPtr));
5786 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005787 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005788 xmlFree(oldNs);
5789 return(-1);
5790 }
5791 }
5792 newNs[nbCache] = n;
5793 oldNs[nbCache++] = node->ns;
5794 node->ns = n;
5795 }
5796 }
5797 }
5798 /*
5799 * now check for namespace hold by attributes on the node.
5800 */
5801 attr = node->properties;
5802 while (attr != NULL) {
5803 if (attr->ns != NULL) {
5804 /*
5805 * initialize the cache if needed
5806 */
5807 if (sizeCache == 0) {
5808 sizeCache = 10;
5809 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5810 sizeof(xmlNsPtr));
5811 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005812 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005813 return(-1);
5814 }
5815 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5816 sizeof(xmlNsPtr));
5817 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005818 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005819 xmlFree(oldNs);
5820 return(-1);
5821 }
5822 }
5823 for (i = 0;i < nbCache;i++) {
5824 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005825 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005826 break;
5827 }
5828 }
5829 if (i == nbCache) {
5830 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005831 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005832 */
5833 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5834 if (n != NULL) { /* :-( what if else ??? */
5835 /*
5836 * check if we need to grow the cache buffers.
5837 */
5838 if (sizeCache <= nbCache) {
5839 sizeCache *= 2;
5840 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5841 sizeof(xmlNsPtr));
5842 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005843 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005844 xmlFree(newNs);
5845 return(-1);
5846 }
5847 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5848 sizeof(xmlNsPtr));
5849 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005850 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005851 xmlFree(oldNs);
5852 return(-1);
5853 }
5854 }
5855 newNs[nbCache] = n;
5856 oldNs[nbCache++] = attr->ns;
5857 attr->ns = n;
5858 }
5859 }
5860 }
5861 attr = attr->next;
5862 }
5863
5864 /*
5865 * Browse the full subtree, deep first
5866 */
Daniel Veillardac996a12004-07-30 12:02:58 +00005867 if (node->children != NULL && node->type != XML_ENTITY_REF_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00005868 /* deep first */
5869 node = node->children;
5870 } else if ((node != tree) && (node->next != NULL)) {
5871 /* then siblings */
5872 node = node->next;
5873 } else if (node != tree) {
5874 /* go up to parents->next if needed */
5875 while (node != tree) {
5876 if (node->parent != NULL)
5877 node = node->parent;
5878 if ((node != tree) && (node->next != NULL)) {
5879 node = node->next;
5880 break;
5881 }
5882 if (node->parent == NULL) {
5883 node = NULL;
5884 break;
5885 }
5886 }
5887 /* exit condition */
5888 if (node == tree)
5889 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005890 } else
5891 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005892 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005893 if (oldNs != NULL)
5894 xmlFree(oldNs);
5895 if (newNs != NULL)
5896 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005897 return(ret);
5898}
Daniel Veillard652327a2003-09-29 18:02:38 +00005899#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005900
5901/**
5902 * xmlHasProp:
5903 * @node: the node
5904 * @name: the attribute name
5905 *
5906 * Search an attribute associated to a node
5907 * This function also looks in DTD attribute declaration for #FIXED or
5908 * default declaration values unless DTD use has been turned off.
5909 *
5910 * Returns the attribute or the attribute declaration or NULL if
5911 * neither was found.
5912 */
5913xmlAttrPtr
5914xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5915 xmlAttrPtr prop;
5916 xmlDocPtr doc;
5917
Daniel Veillard8874b942005-08-25 13:19:21 +00005918 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
5919 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005920 /*
5921 * Check on the properties attached to the node
5922 */
5923 prop = node->properties;
5924 while (prop != NULL) {
5925 if (xmlStrEqual(prop->name, name)) {
5926 return(prop);
5927 }
5928 prop = prop->next;
5929 }
5930 if (!xmlCheckDTD) return(NULL);
5931
5932 /*
5933 * Check if there is a default declaration in the internal
5934 * or external subsets
5935 */
5936 doc = node->doc;
5937 if (doc != NULL) {
5938 xmlAttributePtr attrDecl;
5939 if (doc->intSubset != NULL) {
5940 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5941 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5942 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005943 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5944 /* return attribute declaration only if a default value is given
5945 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005946 return((xmlAttrPtr) attrDecl);
5947 }
5948 }
5949 return(NULL);
5950}
5951
5952/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005953 * xmlHasNsProp:
5954 * @node: the node
5955 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005956 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005957 *
5958 * Search for an attribute associated to a node
5959 * This attribute has to be anchored in the namespace specified.
5960 * This does the entity substitution.
5961 * This function looks in DTD attribute declaration for #FIXED or
5962 * default declaration values unless DTD use has been turned off.
William M. Brack2c228442004-10-03 04:10:00 +00005963 * Note that a namespace of NULL indicates to use the default namespace.
Daniel Veillarde95e2392001-06-06 10:46:28 +00005964 *
5965 * Returns the attribute or the attribute declaration or NULL
5966 * if neither was found.
5967 */
5968xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005969xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005970 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00005971#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005972 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00005973#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005974
Daniel Veillard8874b942005-08-25 13:19:21 +00005975 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
Daniel Veillarde95e2392001-06-06 10:46:28 +00005976 return(NULL);
5977
5978 prop = node->properties;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005979 while (prop != NULL) {
5980 /*
5981 * One need to have
5982 * - same attribute names
5983 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005984 */
William M. Brack2c228442004-10-03 04:10:00 +00005985 if (xmlStrEqual(prop->name, name)) {
5986 if (((prop->ns != NULL) &&
5987 (xmlStrEqual(prop->ns->href, nameSpace))) ||
5988 ((prop->ns == NULL) && (nameSpace == NULL))) {
5989 return(prop);
5990 }
Daniel Veillarde95e2392001-06-06 10:46:28 +00005991 }
5992 prop = prop->next;
5993 }
5994 if (!xmlCheckDTD) return(NULL);
5995
Daniel Veillard652327a2003-09-29 18:02:38 +00005996#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005997 /*
5998 * Check if there is a default declaration in the internal
5999 * or external subsets
6000 */
6001 doc = node->doc;
6002 if (doc != NULL) {
6003 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006004 xmlAttributePtr attrDecl = NULL;
6005 xmlNsPtr *nsList, *cur;
6006 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00006007
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006008 nsList = xmlGetNsList(node->doc, node);
6009 if (nsList == NULL)
6010 return(NULL);
6011 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
6012 ename = xmlStrdup(node->ns->prefix);
6013 ename = xmlStrcat(ename, BAD_CAST ":");
6014 ename = xmlStrcat(ename, node->name);
6015 } else {
6016 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006017 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006018 if (ename == NULL) {
6019 xmlFree(nsList);
6020 return(NULL);
6021 }
6022
William M. Brack2c228442004-10-03 04:10:00 +00006023 if (nameSpace == NULL) {
6024 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
6025 name, NULL);
6026 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
6027 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6028 name, NULL);
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006029 }
William M. Brack2c228442004-10-03 04:10:00 +00006030 } else {
6031 cur = nsList;
6032 while (*cur != NULL) {
6033 if (xmlStrEqual((*cur)->href, nameSpace)) {
6034 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
6035 name, (*cur)->prefix);
6036 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6037 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6038 name, (*cur)->prefix);
6039 }
6040 cur++;
6041 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006042 }
6043 xmlFree(nsList);
6044 xmlFree(ename);
6045 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006046 }
6047 }
Daniel Veillard652327a2003-09-29 18:02:38 +00006048#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00006049 return(NULL);
6050}
6051
6052/**
Owen Taylor3473f882001-02-23 17:55:21 +00006053 * xmlGetProp:
6054 * @node: the node
6055 * @name: the attribute name
6056 *
6057 * Search and get the value of an attribute associated to a node
6058 * This does the entity substitution.
6059 * This function looks in DTD attribute declaration for #FIXED or
6060 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00006061 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00006062 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6063 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00006064 *
6065 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006066 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006067 */
6068xmlChar *
6069xmlGetProp(xmlNodePtr node, const xmlChar *name) {
6070 xmlAttrPtr prop;
6071 xmlDocPtr doc;
6072
Daniel Veillard8874b942005-08-25 13:19:21 +00006073 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6074 return(NULL);
6075
Owen Taylor3473f882001-02-23 17:55:21 +00006076 /*
6077 * Check on the properties attached to the node
6078 */
6079 prop = node->properties;
6080 while (prop != NULL) {
6081 if (xmlStrEqual(prop->name, name)) {
6082 xmlChar *ret;
6083
6084 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6085 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6086 return(ret);
6087 }
6088 prop = prop->next;
6089 }
6090 if (!xmlCheckDTD) return(NULL);
6091
6092 /*
6093 * Check if there is a default declaration in the internal
6094 * or external subsets
6095 */
6096 doc = node->doc;
6097 if (doc != NULL) {
6098 xmlAttributePtr attrDecl;
6099 if (doc->intSubset != NULL) {
6100 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6101 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6102 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006103 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6104 /* return attribute declaration only if a default value is given
6105 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006106 return(xmlStrdup(attrDecl->defaultValue));
6107 }
6108 }
6109 return(NULL);
6110}
6111
6112/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006113 * xmlGetNoNsProp:
6114 * @node: the node
6115 * @name: the attribute name
6116 *
6117 * Search and get the value of an attribute associated to a node
6118 * This does the entity substitution.
6119 * This function looks in DTD attribute declaration for #FIXED or
6120 * default declaration values unless DTD use has been turned off.
6121 * This function is similar to xmlGetProp except it will accept only
6122 * an attribute in no namespace.
6123 *
6124 * Returns the attribute value or NULL if not found.
6125 * It's up to the caller to free the memory with xmlFree().
6126 */
6127xmlChar *
6128xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6129 xmlAttrPtr prop;
6130 xmlDocPtr doc;
6131
Daniel Veillard8874b942005-08-25 13:19:21 +00006132 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6133 return(NULL);
Daniel Veillard71531f32003-02-05 13:19:53 +00006134 /*
6135 * Check on the properties attached to the node
6136 */
6137 prop = node->properties;
6138 while (prop != NULL) {
6139 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6140 xmlChar *ret;
6141
6142 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6143 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6144 return(ret);
6145 }
6146 prop = prop->next;
6147 }
6148 if (!xmlCheckDTD) return(NULL);
6149
6150 /*
6151 * Check if there is a default declaration in the internal
6152 * or external subsets
6153 */
6154 doc = node->doc;
6155 if (doc != NULL) {
6156 xmlAttributePtr attrDecl;
6157 if (doc->intSubset != NULL) {
6158 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6159 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6160 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006161 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6162 /* return attribute declaration only if a default value is given
6163 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006164 return(xmlStrdup(attrDecl->defaultValue));
6165 }
6166 }
6167 return(NULL);
6168}
6169
6170/**
Owen Taylor3473f882001-02-23 17:55:21 +00006171 * xmlGetNsProp:
6172 * @node: the node
6173 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006174 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006175 *
6176 * Search and get the value of an attribute associated to a node
6177 * This attribute has to be anchored in the namespace specified.
6178 * This does the entity substitution.
6179 * This function looks in DTD attribute declaration for #FIXED or
6180 * default declaration values unless DTD use has been turned off.
6181 *
6182 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006183 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006184 */
6185xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006186xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006187 xmlAttrPtr prop;
6188 xmlDocPtr doc;
6189 xmlNsPtr ns;
6190
Daniel Veillard8874b942005-08-25 13:19:21 +00006191 if ((node == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006192 return(NULL);
6193
6194 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006195 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006196 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006197 while (prop != NULL) {
6198 /*
6199 * One need to have
6200 * - same attribute names
6201 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006202 */
6203 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006204 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006205 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006206 xmlChar *ret;
6207
6208 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6209 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6210 return(ret);
6211 }
6212 prop = prop->next;
6213 }
6214 if (!xmlCheckDTD) return(NULL);
6215
6216 /*
6217 * Check if there is a default declaration in the internal
6218 * or external subsets
6219 */
6220 doc = node->doc;
6221 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006222 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006223 xmlAttributePtr attrDecl;
6224
Owen Taylor3473f882001-02-23 17:55:21 +00006225 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6226 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6227 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6228
6229 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6230 /*
6231 * The DTD declaration only allows a prefix search
6232 */
6233 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006234 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006235 return(xmlStrdup(attrDecl->defaultValue));
6236 }
6237 }
6238 }
6239 return(NULL);
6240}
6241
Daniel Veillard2156d432004-03-04 15:59:36 +00006242#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6243/**
6244 * xmlUnsetProp:
6245 * @node: the node
6246 * @name: the attribute name
6247 *
6248 * Remove an attribute carried by a node.
6249 * Returns 0 if successful, -1 if not found
6250 */
6251int
6252xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
6253 xmlAttrPtr prop, prev = NULL;;
6254
Daniel Veillard8874b942005-08-25 13:19:21 +00006255 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
Daniel Veillard2156d432004-03-04 15:59:36 +00006256 return(-1);
6257 prop = node->properties;
6258 while (prop != NULL) {
6259 if ((xmlStrEqual(prop->name, name)) &&
6260 (prop->ns == NULL)) {
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00006261 xmlUnlinkNode((xmlNodePtr) prop);
Daniel Veillard2156d432004-03-04 15:59:36 +00006262 xmlFreeProp(prop);
6263 return(0);
6264 }
6265 prev = prop;
6266 prop = prop->next;
6267 }
6268 return(-1);
6269}
6270
6271/**
6272 * xmlUnsetNsProp:
6273 * @node: the node
6274 * @ns: the namespace definition
6275 * @name: the attribute name
6276 *
6277 * Remove an attribute carried by a node.
6278 * Returns 0 if successful, -1 if not found
6279 */
6280int
6281xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
Daniel Veillard27f20102004-11-05 11:50:11 +00006282 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard2156d432004-03-04 15:59:36 +00006283
Daniel Veillard8874b942005-08-25 13:19:21 +00006284 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
Daniel Veillard2156d432004-03-04 15:59:36 +00006285 return(-1);
Daniel Veillard27f20102004-11-05 11:50:11 +00006286 prop = node->properties;
Daniel Veillard2156d432004-03-04 15:59:36 +00006287 if (ns == NULL)
6288 return(xmlUnsetProp(node, name));
6289 if (ns->href == NULL)
6290 return(-1);
6291 while (prop != NULL) {
6292 if ((xmlStrEqual(prop->name, name)) &&
6293 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00006294 xmlUnlinkNode((xmlNodePtr) prop);
Daniel Veillard2156d432004-03-04 15:59:36 +00006295 xmlFreeProp(prop);
6296 return(0);
6297 }
6298 prev = prop;
6299 prop = prop->next;
6300 }
6301 return(-1);
6302}
6303#endif
6304
6305#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006306/**
6307 * xmlSetProp:
6308 * @node: the node
6309 * @name: the attribute name
6310 * @value: the attribute value
6311 *
6312 * Set (or reset) an attribute carried by a node.
6313 * Returns the attribute pointer.
6314 */
6315xmlAttrPtr
6316xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006317 xmlAttrPtr prop;
6318 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006319
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006320 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006321 return(NULL);
6322 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006323 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006324 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006325 if ((xmlStrEqual(prop->name, name)) &&
6326 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006327 xmlNodePtr oldprop = prop->children;
6328
Owen Taylor3473f882001-02-23 17:55:21 +00006329 prop->children = NULL;
6330 prop->last = NULL;
6331 if (value != NULL) {
6332 xmlChar *buffer;
6333 xmlNodePtr tmp;
6334
6335 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6336 prop->children = xmlStringGetNodeList(node->doc, buffer);
6337 prop->last = NULL;
6338 prop->doc = doc;
6339 tmp = prop->children;
6340 while (tmp != NULL) {
6341 tmp->parent = (xmlNodePtr) prop;
6342 tmp->doc = doc;
6343 if (tmp->next == NULL)
6344 prop->last = tmp;
6345 tmp = tmp->next;
6346 }
6347 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006348 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006349 if (oldprop != NULL)
6350 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006351 return(prop);
6352 }
6353 prop = prop->next;
6354 }
6355 prop = xmlNewProp(node, name, value);
6356 return(prop);
6357}
6358
6359/**
6360 * xmlSetNsProp:
6361 * @node: the node
6362 * @ns: the namespace definition
6363 * @name: the attribute name
6364 * @value: the attribute value
6365 *
6366 * Set (or reset) an attribute carried by a node.
6367 * The ns structure must be in scope, this is not checked.
6368 *
6369 * Returns the attribute pointer.
6370 */
6371xmlAttrPtr
6372xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6373 const xmlChar *value) {
6374 xmlAttrPtr prop;
6375
Daniel Veillardb6b36d32005-02-09 16:48:53 +00006376 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006377 return(NULL);
6378
6379 if (ns == NULL)
6380 return(xmlSetProp(node, name, value));
6381 if (ns->href == NULL)
6382 return(NULL);
6383 prop = node->properties;
6384
6385 while (prop != NULL) {
6386 /*
6387 * One need to have
6388 * - same attribute names
6389 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006390 */
6391 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006392 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006393 if (prop->children != NULL)
6394 xmlFreeNodeList(prop->children);
6395 prop->children = NULL;
6396 prop->last = NULL;
6397 prop->ns = ns;
6398 if (value != NULL) {
6399 xmlChar *buffer;
6400 xmlNodePtr tmp;
6401
6402 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6403 prop->children = xmlStringGetNodeList(node->doc, buffer);
6404 prop->last = NULL;
6405 tmp = prop->children;
6406 while (tmp != NULL) {
6407 tmp->parent = (xmlNodePtr) prop;
6408 if (tmp->next == NULL)
6409 prop->last = tmp;
6410 tmp = tmp->next;
6411 }
6412 xmlFree(buffer);
6413 }
6414 return(prop);
6415 }
6416 prop = prop->next;
6417 }
6418 prop = xmlNewNsProp(node, ns, name, value);
6419 return(prop);
6420}
6421
Daniel Veillard652327a2003-09-29 18:02:38 +00006422#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006423
6424/**
Owen Taylor3473f882001-02-23 17:55:21 +00006425 * xmlNodeIsText:
6426 * @node: the node
6427 *
6428 * Is this node a Text node ?
6429 * Returns 1 yes, 0 no
6430 */
6431int
6432xmlNodeIsText(xmlNodePtr node) {
6433 if (node == NULL) return(0);
6434
6435 if (node->type == XML_TEXT_NODE) return(1);
6436 return(0);
6437}
6438
6439/**
6440 * xmlIsBlankNode:
6441 * @node: the node
6442 *
6443 * Checks whether this node is an empty or whitespace only
6444 * (and possibly ignorable) text-node.
6445 *
6446 * Returns 1 yes, 0 no
6447 */
6448int
6449xmlIsBlankNode(xmlNodePtr node) {
6450 const xmlChar *cur;
6451 if (node == NULL) return(0);
6452
Daniel Veillard7db37732001-07-12 01:20:08 +00006453 if ((node->type != XML_TEXT_NODE) &&
6454 (node->type != XML_CDATA_SECTION_NODE))
6455 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006456 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006457 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006458 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006459 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006460 cur++;
6461 }
6462
6463 return(1);
6464}
6465
6466/**
6467 * xmlTextConcat:
6468 * @node: the node
6469 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006470 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006471 *
6472 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006473 *
6474 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006475 */
6476
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006477int
Owen Taylor3473f882001-02-23 17:55:21 +00006478xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006479 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006480
6481 if ((node->type != XML_TEXT_NODE) &&
6482 (node->type != XML_CDATA_SECTION_NODE)) {
6483#ifdef DEBUG_TREE
6484 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006485 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006486#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006487 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006488 }
William M. Brack7762bb12004-01-04 14:49:01 +00006489 /* need to check if content is currently in the dictionary */
Daniel Veillard8874b942005-08-25 13:19:21 +00006490 if ((node->content == (xmlChar *) &(node->properties)) ||
6491 ((node->doc != NULL) && (node->doc->dict != NULL) &&
6492 xmlDictOwns(node->doc->dict, node->content))) {
William M. Brack7762bb12004-01-04 14:49:01 +00006493 node->content = xmlStrncatNew(node->content, content, len);
6494 } else {
6495 node->content = xmlStrncat(node->content, content, len);
6496 }
Daniel Veillard8874b942005-08-25 13:19:21 +00006497 node->properties = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006498 if (node->content == NULL)
6499 return(-1);
6500 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006501}
6502
6503/************************************************************************
6504 * *
6505 * Output : to a FILE or in memory *
6506 * *
6507 ************************************************************************/
6508
Owen Taylor3473f882001-02-23 17:55:21 +00006509/**
6510 * xmlBufferCreate:
6511 *
6512 * routine to create an XML buffer.
6513 * returns the new structure.
6514 */
6515xmlBufferPtr
6516xmlBufferCreate(void) {
6517 xmlBufferPtr ret;
6518
6519 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6520 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006521 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006522 return(NULL);
6523 }
6524 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006525 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006526 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006527 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006528 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006529 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006530 xmlFree(ret);
6531 return(NULL);
6532 }
6533 ret->content[0] = 0;
6534 return(ret);
6535}
6536
6537/**
6538 * xmlBufferCreateSize:
6539 * @size: initial size of buffer
6540 *
6541 * routine to create an XML buffer.
6542 * returns the new structure.
6543 */
6544xmlBufferPtr
6545xmlBufferCreateSize(size_t size) {
6546 xmlBufferPtr ret;
6547
6548 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6549 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006550 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006551 return(NULL);
6552 }
6553 ret->use = 0;
6554 ret->alloc = xmlBufferAllocScheme;
6555 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6556 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006557 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006558 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006559 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006560 xmlFree(ret);
6561 return(NULL);
6562 }
6563 ret->content[0] = 0;
6564 } else
6565 ret->content = NULL;
6566 return(ret);
6567}
6568
6569/**
Daniel Veillard53350552003-09-18 13:35:51 +00006570 * xmlBufferCreateStatic:
6571 * @mem: the memory area
6572 * @size: the size in byte
6573 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006574 * routine to create an XML buffer from an immutable memory area.
6575 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006576 * present until the end of the buffer lifetime.
6577 *
6578 * returns the new structure.
6579 */
6580xmlBufferPtr
6581xmlBufferCreateStatic(void *mem, size_t size) {
6582 xmlBufferPtr ret;
6583
6584 if ((mem == NULL) || (size == 0))
6585 return(NULL);
6586
6587 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6588 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006589 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006590 return(NULL);
6591 }
6592 ret->use = size;
6593 ret->size = size;
6594 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6595 ret->content = (xmlChar *) mem;
6596 return(ret);
6597}
6598
6599/**
Owen Taylor3473f882001-02-23 17:55:21 +00006600 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006601 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006602 * @scheme: allocation scheme to use
6603 *
6604 * Sets the allocation scheme for this buffer
6605 */
6606void
6607xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6608 xmlBufferAllocationScheme scheme) {
6609 if (buf == NULL) {
6610#ifdef DEBUG_BUFFER
6611 xmlGenericError(xmlGenericErrorContext,
6612 "xmlBufferSetAllocationScheme: buf == NULL\n");
6613#endif
6614 return;
6615 }
Daniel Veillard53350552003-09-18 13:35:51 +00006616 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006617
6618 buf->alloc = scheme;
6619}
6620
6621/**
6622 * xmlBufferFree:
6623 * @buf: the buffer to free
6624 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006625 * Frees an XML buffer. It frees both the content and the structure which
6626 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006627 */
6628void
6629xmlBufferFree(xmlBufferPtr buf) {
6630 if (buf == NULL) {
6631#ifdef DEBUG_BUFFER
6632 xmlGenericError(xmlGenericErrorContext,
6633 "xmlBufferFree: buf == NULL\n");
6634#endif
6635 return;
6636 }
Daniel Veillard53350552003-09-18 13:35:51 +00006637
6638 if ((buf->content != NULL) &&
6639 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006640 xmlFree(buf->content);
6641 }
Owen Taylor3473f882001-02-23 17:55:21 +00006642 xmlFree(buf);
6643}
6644
6645/**
6646 * xmlBufferEmpty:
6647 * @buf: the buffer
6648 *
6649 * empty a buffer.
6650 */
6651void
6652xmlBufferEmpty(xmlBufferPtr buf) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006653 if (buf == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006654 if (buf->content == NULL) return;
6655 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006656 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006657 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006658 } else {
6659 memset(buf->content, 0, buf->size);
6660 }
Owen Taylor3473f882001-02-23 17:55:21 +00006661}
6662
6663/**
6664 * xmlBufferShrink:
6665 * @buf: the buffer to dump
6666 * @len: the number of xmlChar to remove
6667 *
6668 * Remove the beginning of an XML buffer.
6669 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006670 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006671 */
6672int
6673xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
Daniel Veillard3d97e662004-11-04 10:49:00 +00006674 if (buf == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006675 if (len == 0) return(0);
6676 if (len > buf->use) return(-1);
6677
6678 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006679 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6680 buf->content += len;
6681 } else {
6682 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6683 buf->content[buf->use] = 0;
6684 }
Owen Taylor3473f882001-02-23 17:55:21 +00006685 return(len);
6686}
6687
6688/**
6689 * xmlBufferGrow:
6690 * @buf: the buffer
6691 * @len: the minimum free size to allocate
6692 *
6693 * Grow the available space of an XML buffer.
6694 *
6695 * Returns the new available space or -1 in case of error
6696 */
6697int
6698xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6699 int size;
6700 xmlChar *newbuf;
6701
Daniel Veillard3d97e662004-11-04 10:49:00 +00006702 if (buf == NULL) return(-1);
6703
Daniel Veillard53350552003-09-18 13:35:51 +00006704 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006705 if (len + buf->use < buf->size) return(0);
6706
William M. Brack30fe43f2004-07-26 18:00:58 +00006707/*
6708 * Windows has a BIG problem on realloc timing, so we try to double
6709 * the buffer size (if that's enough) (bug 146697)
6710 */
6711#ifdef WIN32
6712 if (buf->size > len)
6713 size = buf->size * 2;
6714 else
6715 size = buf->use + len + 100;
6716#else
Owen Taylor3473f882001-02-23 17:55:21 +00006717 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00006718#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006719
6720 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006721 if (newbuf == NULL) {
6722 xmlTreeErrMemory("growing buffer");
6723 return(-1);
6724 }
Owen Taylor3473f882001-02-23 17:55:21 +00006725 buf->content = newbuf;
6726 buf->size = size;
6727 return(buf->size - buf->use);
6728}
6729
6730/**
6731 * xmlBufferDump:
6732 * @file: the file output
6733 * @buf: the buffer to dump
6734 *
6735 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006736 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006737 */
6738int
6739xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6740 int ret;
6741
6742 if (buf == NULL) {
6743#ifdef DEBUG_BUFFER
6744 xmlGenericError(xmlGenericErrorContext,
6745 "xmlBufferDump: buf == NULL\n");
6746#endif
6747 return(0);
6748 }
6749 if (buf->content == NULL) {
6750#ifdef DEBUG_BUFFER
6751 xmlGenericError(xmlGenericErrorContext,
6752 "xmlBufferDump: buf->content == NULL\n");
6753#endif
6754 return(0);
6755 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006756 if (file == NULL)
6757 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006758 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6759 return(ret);
6760}
6761
6762/**
6763 * xmlBufferContent:
6764 * @buf: the buffer
6765 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006766 * Function to extract the content of a buffer
6767 *
Owen Taylor3473f882001-02-23 17:55:21 +00006768 * Returns the internal content
6769 */
6770
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006771const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006772xmlBufferContent(const xmlBufferPtr buf)
6773{
6774 if(!buf)
6775 return NULL;
6776
6777 return buf->content;
6778}
6779
6780/**
6781 * xmlBufferLength:
6782 * @buf: the buffer
6783 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006784 * Function to get the length of a buffer
6785 *
Owen Taylor3473f882001-02-23 17:55:21 +00006786 * Returns the length of data in the internal content
6787 */
6788
6789int
6790xmlBufferLength(const xmlBufferPtr buf)
6791{
6792 if(!buf)
6793 return 0;
6794
6795 return buf->use;
6796}
6797
6798/**
6799 * xmlBufferResize:
6800 * @buf: the buffer to resize
6801 * @size: the desired size
6802 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006803 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006804 *
6805 * Returns 0 in case of problems, 1 otherwise
6806 */
6807int
6808xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6809{
6810 unsigned int newSize;
6811 xmlChar* rebuf = NULL;
6812
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006813 if (buf == NULL)
6814 return(0);
6815
Daniel Veillard53350552003-09-18 13:35:51 +00006816 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6817
Owen Taylor3473f882001-02-23 17:55:21 +00006818 /* Don't resize if we don't have to */
6819 if (size < buf->size)
6820 return 1;
6821
6822 /* figure out new size */
6823 switch (buf->alloc){
6824 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillardbf629492004-04-20 22:20:59 +00006825 /*take care of empty case*/
6826 newSize = (buf->size ? buf->size*2 : size + 10);
Owen Taylor3473f882001-02-23 17:55:21 +00006827 while (size > newSize) newSize *= 2;
6828 break;
6829 case XML_BUFFER_ALLOC_EXACT:
6830 newSize = size+10;
6831 break;
6832 default:
6833 newSize = size+10;
6834 break;
6835 }
6836
6837 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006838 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006839 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006840 rebuf = (xmlChar *) xmlRealloc(buf->content,
6841 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006842 } else {
6843 /*
6844 * if we are reallocating a buffer far from being full, it's
6845 * better to make a new allocation and copy only the used range
6846 * and free the old one.
6847 */
6848 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6849 if (rebuf != NULL) {
6850 memcpy(rebuf, buf->content, buf->use);
6851 xmlFree(buf->content);
William M. Brack42331a92004-07-29 07:07:16 +00006852 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006853 }
6854 }
Owen Taylor3473f882001-02-23 17:55:21 +00006855 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006856 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006857 return 0;
6858 }
6859 buf->content = rebuf;
6860 buf->size = newSize;
6861
6862 return 1;
6863}
6864
6865/**
6866 * xmlBufferAdd:
6867 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006868 * @str: the #xmlChar string
6869 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006870 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006871 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006872 * str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006873 *
6874 * Returns 0 successful, a positive error code number otherwise
6875 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006876 */
William M. Bracka3215c72004-07-31 16:24:01 +00006877int
Owen Taylor3473f882001-02-23 17:55:21 +00006878xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6879 unsigned int needSize;
6880
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006881 if ((str == NULL) || (buf == NULL)) {
William M. Bracka3215c72004-07-31 16:24:01 +00006882 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006883 }
William M. Bracka3215c72004-07-31 16:24:01 +00006884 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006885 if (len < -1) {
6886#ifdef DEBUG_BUFFER
6887 xmlGenericError(xmlGenericErrorContext,
6888 "xmlBufferAdd: len < 0\n");
6889#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006890 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006891 }
William M. Bracka3215c72004-07-31 16:24:01 +00006892 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006893
6894 if (len < 0)
6895 len = xmlStrlen(str);
6896
William M. Bracka3215c72004-07-31 16:24:01 +00006897 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006898
6899 needSize = buf->use + len + 2;
6900 if (needSize > buf->size){
6901 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006902 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006903 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006904 }
6905 }
6906
6907 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6908 buf->use += len;
6909 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006910 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006911}
6912
6913/**
6914 * xmlBufferAddHead:
6915 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006916 * @str: the #xmlChar string
6917 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006918 *
6919 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006920 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006921 *
6922 * Returns 0 successful, a positive error code number otherwise
6923 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006924 */
William M. Bracka3215c72004-07-31 16:24:01 +00006925int
Owen Taylor3473f882001-02-23 17:55:21 +00006926xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6927 unsigned int needSize;
6928
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006929 if (buf == NULL)
6930 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00006931 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006932 if (str == NULL) {
6933#ifdef DEBUG_BUFFER
6934 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006935 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006936#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006937 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006938 }
6939 if (len < -1) {
6940#ifdef DEBUG_BUFFER
6941 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006942 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006943#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006944 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006945 }
William M. Bracka3215c72004-07-31 16:24:01 +00006946 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006947
6948 if (len < 0)
6949 len = xmlStrlen(str);
6950
William M. Bracka3215c72004-07-31 16:24:01 +00006951 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006952
6953 needSize = buf->use + len + 2;
6954 if (needSize > buf->size){
6955 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006956 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006957 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006958 }
6959 }
6960
6961 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6962 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6963 buf->use += len;
6964 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006965 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006966}
6967
6968/**
6969 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00006970 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00006971 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006972 *
6973 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00006974 *
6975 * Returns 0 successful, a positive error code number otherwise
6976 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006977 */
William M. Bracka3215c72004-07-31 16:24:01 +00006978int
Owen Taylor3473f882001-02-23 17:55:21 +00006979xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006980 if (buf == NULL)
6981 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00006982 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
6983 if (str == NULL) return -1;
6984 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00006985}
6986
6987/**
6988 * xmlBufferCCat:
6989 * @buf: the buffer to dump
6990 * @str: the C char string
6991 *
6992 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00006993 *
6994 * Returns 0 successful, a positive error code number otherwise
6995 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006996 */
William M. Bracka3215c72004-07-31 16:24:01 +00006997int
Owen Taylor3473f882001-02-23 17:55:21 +00006998xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6999 const char *cur;
7000
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007001 if (buf == NULL)
7002 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007003 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007004 if (str == NULL) {
7005#ifdef DEBUG_BUFFER
7006 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007007 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007008#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007009 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007010 }
7011 for (cur = str;*cur != 0;cur++) {
7012 if (buf->use + 10 >= buf->size) {
7013 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007014 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007015 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007016 }
7017 }
7018 buf->content[buf->use++] = *cur;
7019 }
7020 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007021 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007022}
7023
7024/**
7025 * xmlBufferWriteCHAR:
7026 * @buf: the XML buffer
7027 * @string: the string to add
7028 *
7029 * routine which manages and grows an output buffer. This one adds
7030 * xmlChars at the end of the buffer.
7031 */
7032void
Daniel Veillard53350552003-09-18 13:35:51 +00007033xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007034 if (buf == NULL)
7035 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007036 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007037 xmlBufferCat(buf, string);
7038}
7039
7040/**
7041 * xmlBufferWriteChar:
7042 * @buf: the XML buffer output
7043 * @string: the string to add
7044 *
7045 * routine which manage and grows an output buffer. This one add
7046 * C chars at the end of the array.
7047 */
7048void
7049xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007050 if (buf == NULL)
7051 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007052 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007053 xmlBufferCCat(buf, string);
7054}
7055
7056
7057/**
7058 * xmlBufferWriteQuotedString:
7059 * @buf: the XML buffer output
7060 * @string: the string to add
7061 *
7062 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00007063 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00007064 * quote or double-quotes internally
7065 */
7066void
7067xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00007068 const xmlChar *cur, *base;
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007069 if (buf == NULL)
7070 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007071 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00007072 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00007073 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00007074#ifdef DEBUG_BUFFER
7075 xmlGenericError(xmlGenericErrorContext,
7076 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7077#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00007078 xmlBufferCCat(buf, "\"");
7079 base = cur = string;
7080 while(*cur != 0){
7081 if(*cur == '"'){
7082 if (base != cur)
7083 xmlBufferAdd(buf, base, cur - base);
7084 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7085 cur++;
7086 base = cur;
7087 }
7088 else {
7089 cur++;
7090 }
7091 }
7092 if (base != cur)
7093 xmlBufferAdd(buf, base, cur - base);
7094 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007095 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007096 else{
7097 xmlBufferCCat(buf, "\'");
7098 xmlBufferCat(buf, string);
7099 xmlBufferCCat(buf, "\'");
7100 }
Owen Taylor3473f882001-02-23 17:55:21 +00007101 } else {
7102 xmlBufferCCat(buf, "\"");
7103 xmlBufferCat(buf, string);
7104 xmlBufferCCat(buf, "\"");
7105 }
7106}
7107
7108
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007109/**
7110 * xmlGetDocCompressMode:
7111 * @doc: the document
7112 *
7113 * get the compression ratio for a document, ZLIB based
7114 * Returns 0 (uncompressed) to 9 (max compression)
7115 */
7116int
7117xmlGetDocCompressMode (xmlDocPtr doc) {
7118 if (doc == NULL) return(-1);
7119 return(doc->compression);
7120}
7121
7122/**
7123 * xmlSetDocCompressMode:
7124 * @doc: the document
7125 * @mode: the compression ratio
7126 *
7127 * set the compression ratio for a document, ZLIB based
7128 * Correct values: 0 (uncompressed) to 9 (max compression)
7129 */
7130void
7131xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7132 if (doc == NULL) return;
7133 if (mode < 0) doc->compression = 0;
7134 else if (mode > 9) doc->compression = 9;
7135 else doc->compression = mode;
7136}
7137
7138/**
7139 * xmlGetCompressMode:
7140 *
7141 * get the default compression mode used, ZLIB based.
7142 * Returns 0 (uncompressed) to 9 (max compression)
7143 */
7144int
7145xmlGetCompressMode(void)
7146{
7147 return (xmlCompressMode);
7148}
7149
7150/**
7151 * xmlSetCompressMode:
7152 * @mode: the compression ratio
7153 *
7154 * set the default compression mode used, ZLIB based
7155 * Correct values: 0 (uncompressed) to 9 (max compression)
7156 */
7157void
7158xmlSetCompressMode(int mode) {
7159 if (mode < 0) xmlCompressMode = 0;
7160 else if (mode > 9) xmlCompressMode = 9;
7161 else xmlCompressMode = mode;
7162}
7163
Kasimier T. Buchcik4d9c9482005-06-27 15:04:46 +00007164/*
7165* xmlDOMWrapNewCtxt:
7166*
7167* Allocates and initializes a new DOM-wrapper context.
7168*
7169* Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal errror.
7170*/
7171xmlDOMWrapCtxtPtr
7172xmlDOMWrapNewCtxt(void)
7173{
7174 xmlDOMWrapCtxtPtr ret;
7175
7176 ret = xmlMalloc(sizeof(xmlDOMWrapCtxt));
7177 if (ret == NULL) {
7178 xmlTreeErrMemory("allocating DOM-wrapper context");
7179 return (NULL);
7180 }
7181 memset(ret, 0, sizeof(xmlDOMWrapCtxt));
7182 return (ret);
7183}
7184
7185/*
7186* xmlDOMWrapFreeCtxt:
7187* @ctxt: the DOM-wrapper context
7188*
7189* Frees the DOM-wrapper context.
7190*/
7191void
7192xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt)
7193{
7194 if (ctxt == NULL)
7195 return;
7196 xmlFree(ctxt);
7197}
7198
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007199#define XML_TREE_NSMAP_PARENT -1
7200#define XML_TREE_NSMAP_XML -2
7201#define XML_TREE_NSMAP_DOC -3
7202#define XML_TREE_NSMAP_CUSTOM -4
7203
7204typedef struct xmlNsMapItem *xmlNsMapItemPtr;
7205struct xmlNsMapItem {
7206 xmlNsMapItemPtr next;
7207 xmlNsMapItemPtr prev;
7208 xmlNsPtr oldNs; /* old ns decl reference */
7209 xmlNsPtr newNs; /* new ns decl reference */
7210 int shadowDepth; /* Shadowed at this depth */
7211 /*
7212 * depth:
7213 * >= 0 == @node's ns-decls
7214 * -1 == @parent's ns-decls
7215 * -2 == @parent's out-of-scope ns-decls
7216 * -3 == the doc->oldNs XML ns-decl
7217 * -4 == the doc->oldNs storage ns-decls
7218 */
7219 int depth;
7220};
7221
7222/*
7223* xmlTreeAddNsMapItem:
7224* @map: the ns-map
7225* @cur: the current map entry to append a new entry to
7226* @oldNs: the old ns-struct
7227* @newNs: the new ns-struct
7228* @depth: depth and ns-kind information
7229*
7230* Frees the ns-map
7231*/
7232static xmlNsMapItemPtr
7233xmlDOMWrapNSNormAddNsMapItem(xmlNsMapItemPtr *map,
7234 xmlNsMapItemPtr *cur,
7235 xmlNsPtr oldNs,
7236 xmlNsPtr newNs,
7237 int depth)
7238{
7239 xmlNsMapItemPtr ret;
7240
7241 if ((cur != NULL) && (*cur != NULL) && ((*cur)->next != NULL)) {
7242 /*
7243 * Reuse.
7244 */
7245 ret = (*cur)->next;
7246 *cur = ret;
7247 } else {
7248 ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem));
7249 if (ret == NULL) {
7250 xmlTreeErrMemory("allocating namespace map item");
7251 return (NULL);
7252 }
7253 memset(ret, 0, sizeof(struct xmlNsMapItem));
7254 if (*map == NULL) {
7255 /*
7256 * First ever.
7257 */
7258 *map = ret;
7259 ret->prev = ret;
7260 if (cur != NULL)
7261 *cur = ret;
7262 } else {
7263 if (cur) {
7264 /*
7265 * Append.
7266 */
7267 (*cur)->next = ret;
7268 ret->prev = *cur;
7269 *cur = ret;
7270 } else {
7271 /*
7272 * Set on first position.
7273 */
7274 ret->next = (*map);
7275 ret->prev = (*map)->prev;
7276 (*map)->prev = ret;
7277 *map = ret;
7278 }
7279 }
7280 }
7281 ret->oldNs = oldNs;
7282 ret->newNs = newNs;
7283 ret->shadowDepth = -1;
7284 ret->depth = depth;
7285 return (ret);
7286}
7287
7288/*
7289* xmlTreeFreeNsMap:
7290* @map: the ns-map
7291*
7292* Frees the ns-map
7293*/
7294static void
7295xmlDOMWrapNSNormFreeNsMap(xmlNsMapItemPtr map)
7296{
7297 xmlNsMapItemPtr mi = map, miprev;
7298
7299 while (mi != NULL) {
7300 miprev = mi;
7301 mi = mi->next;
7302 xmlFree(miprev);
7303 }
7304}
7305
7306/*
7307* xmlTreeEnsureXMLDecl:
7308* @doc: the doc
7309*
7310* Ensures that there is an XML namespace declaration on the doc.
7311*
7312* Returns the XML ns-struct or NULL on API and internal errors.
7313*/
7314static xmlNsPtr
7315xmlTreeEnsureXMLDecl(xmlDocPtr doc)
7316{
7317 if (doc == NULL)
7318 return (NULL);
7319 if (doc->oldNs != NULL)
7320 return (doc->oldNs);
7321 {
7322 xmlNsPtr ns;
7323 ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
7324 if (ns == NULL) {
7325 xmlTreeErrMemory(
7326 "allocating the XML namespace");
7327 return (NULL);
7328 }
7329 memset(ns, 0, sizeof(xmlNs));
7330 ns->type = XML_LOCAL_NAMESPACE;
7331 ns->href = xmlStrdup(XML_XML_NAMESPACE);
7332 ns->prefix = xmlStrdup((const xmlChar *)"xml");
7333 doc->oldNs = ns;
7334 return (ns);
7335 }
7336}
7337
7338/*
7339* xmlDOMWrapStoreNs:
7340* @doc: the doc
7341* @nsName: the namespace name
7342* @prefix: the prefix
7343*
7344* Creates or reuses an xmlNs struct on doc->oldNs with
7345* the given prefix and namespace name.
7346*
7347* Returns the aquired ns struct or NULL in case of an API
7348* or internal error.
7349*/
7350static xmlNsPtr
7351xmlDOMWrapStoreNs(xmlDocPtr doc,
7352 const xmlChar *nsName,
7353 const xmlChar *prefix)
7354{
7355 xmlNsPtr ns;
7356
7357 if (doc == NULL)
7358 return (NULL);
7359 ns = xmlTreeEnsureXMLDecl(doc);
7360 if (ns == NULL)
7361 return (NULL);
7362 if (ns->next != NULL) {
7363 /* Reuse. */
7364 ns = ns->next;
7365 while (ns != NULL) {
7366 if (((ns->prefix == prefix) ||
7367 xmlStrEqual(ns->prefix, prefix)) &&
7368 xmlStrEqual(ns->href, nsName)) {
7369 return (ns);
7370 }
7371 if (ns->next == NULL)
7372 break;
7373 ns = ns->next;
7374 }
7375 }
7376 /* Create. */
7377 ns->next = xmlNewNs(NULL, nsName, prefix);
7378 return (ns->next);
7379}
7380
7381/*
7382* xmlTreeLookupNsListByPrefix:
7383* @nsList: a list of ns-structs
7384* @prefix: the searched prefix
7385*
7386* Searches for a ns-decl with the given prefix in @nsList.
7387*
7388* Returns the ns-decl if found, NULL if not found and on
7389* API errors.
7390*/
7391static xmlNsPtr
7392xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix)
7393{
7394 if (nsList == NULL)
7395 return (NULL);
7396 {
7397 xmlNsPtr ns;
7398 ns = nsList;
7399 do {
7400 if ((prefix == ns->prefix) ||
7401 xmlStrEqual(prefix, ns->prefix)) {
7402 return (ns);
7403 }
7404 ns = ns->next;
7405 } while (ns != NULL);
7406 }
7407 return (NULL);
7408}
7409
7410/*
7411*
7412* xmlTreeGetInScopeNamespaces:
7413* @map: the namespace map
7414* @node: the node to start with
7415*
7416* Puts in-scope namespaces into the ns-map.
7417*
7418* Returns 0 on success, -1 on API or internal errors.
7419*/
7420static int
7421xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapItemPtr *map,
7422 xmlNodePtr node)
7423{
7424 xmlNodePtr cur;
7425 xmlNsPtr ns;
7426 xmlNsMapItemPtr mi;
7427 int shadowed;
7428
7429 if ((map == NULL) || (*map != NULL))
7430 return (-1);
7431 /*
7432 * Get in-scope ns-decls of @parent.
7433 */
7434 cur = node;
7435 while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) {
7436 if (cur->type == XML_ELEMENT_NODE) {
7437 if (cur->nsDef != NULL) {
7438 ns = cur->nsDef;
7439 do {
7440 shadowed = 0;
7441 if (*map != NULL) {
7442 /*
7443 * Skip shadowed prefixes.
7444 */
7445 for (mi = *map; mi != NULL; mi = mi->next) {
7446 if ((ns->prefix == mi->newNs->prefix) ||
7447 xmlStrEqual(ns->prefix, mi->newNs->prefix)) {
7448 shadowed = 1;
7449 break;
7450 }
7451 }
7452 }
7453 /*
7454 * Insert mapping.
7455 */
7456 mi = xmlDOMWrapNSNormAddNsMapItem(map, NULL, NULL,
7457 ns, XML_TREE_NSMAP_PARENT);
7458 if (mi == NULL)
7459 return (-1);
7460 if (shadowed)
7461 mi->shadowDepth = 0;
7462 ns = ns->next;
7463 } while (ns != NULL);
7464 }
7465 }
7466 cur = cur->parent;
7467 }
7468 return (0);
7469}
7470
7471/*
7472* XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict;
7473* otherwise copy it, when it was in the source-dict.
7474*/
7475#define XML_TREE_ADOPT_STR(str) \
7476 if (adoptStr && (str != NULL)) { \
7477 if (destDoc->dict) { \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00007478 const xmlChar *old = str; \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007479 str = xmlDictLookup(destDoc->dict, str, -1); \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00007480 if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \
7481 (!xmlDictOwns(sourceDoc->dict, old))) \
Daniel Veillard39e5c892005-07-03 22:48:50 +00007482 xmlFree((char *)old); \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007483 } else if ((sourceDoc) && (sourceDoc->dict) && \
7484 xmlDictOwns(sourceDoc->dict, str)) { \
7485 str = BAD_CAST xmlStrdup(str); \
7486 } \
7487 }
7488
7489/*
7490* XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then
7491* put it in dest-dict or copy it.
7492*/
7493#define XML_TREE_ADOPT_STR_2(str) \
7494 if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \
7495 (sourceDoc->dict != NULL) && \
7496 xmlDictOwns(sourceDoc->dict, cur->content)) { \
7497 if (destDoc->dict) \
7498 cur->content = (xmlChar *) \
7499 xmlDictLookup(destDoc->dict, cur->content, -1); \
7500 else \
7501 cur->content = xmlStrdup(BAD_CAST cur->content); \
7502 }
7503
7504/*
7505* xmlDOMWrapNSNormAddNsMapItem2:
7506*
7507* For internal use. Adds a ns-decl mapping.
7508*
7509* Returns 0 on success, -1 on internal errors.
7510*/
7511static int
7512xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number,
7513 xmlNsPtr oldNs, xmlNsPtr newNs)
7514{
7515 if (*list == NULL) {
7516 *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr));
7517 if (*list == NULL) {
7518 xmlTreeErrMemory("alloc ns map item");
7519 return(-1);
7520 }
7521 *size = 3;
7522 *number = 0;
7523 } else if ((*number) >= (*size)) {
7524 *size *= 2;
7525 *list = (xmlNsPtr *) xmlRealloc(*list,
7526 (*size) * 2 * sizeof(xmlNsPtr));
7527 if (*list == NULL) {
7528 xmlTreeErrMemory("realloc ns map item");
7529 return(-1);
7530 }
7531 }
7532 (*list)[2 * (*number)] = oldNs;
7533 (*list)[2 * (*number) +1] = newNs;
7534 (*number)++;
7535 return (0);
7536}
7537
7538/*
7539* xmlDOMWrapRemoveNode:
Daniel Veillard304e78c2005-07-03 16:19:41 +00007540* @ctxt: a DOM wrapper context
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007541* @doc: the doc
7542* @node: the node to be removed.
Daniel Veillard304e78c2005-07-03 16:19:41 +00007543* @options: set of options, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007544*
7545* Unlinks the given node from its owner.
7546* This will substitute ns-references to node->nsDef for
7547* ns-references to doc->oldNs, thus ensuring the removed
7548* branch to be autark wrt ns-references.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00007549* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007550*
7551* Returns 0 on success, 1 if the node is not supported,
7552* -1 on API and internal errors.
7553*/
7554int
7555xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc,
7556 xmlNodePtr node, int options ATTRIBUTE_UNUSED)
7557{
7558 xmlNsPtr *list = NULL;
7559 int sizeList, nbList, i, j;
7560 xmlNsPtr ns;
7561
7562 if ((node == NULL) || (doc == NULL) || (node->doc != doc))
7563 return (-1);
7564
7565 /* TODO: 0 or -1 ? */
7566 if (node->parent == NULL)
7567 return (0);
7568
7569 switch (node->type) {
7570 case XML_TEXT_NODE:
7571 case XML_CDATA_SECTION_NODE:
7572 case XML_ENTITY_REF_NODE:
7573 case XML_PI_NODE:
7574 case XML_COMMENT_NODE:
7575 xmlUnlinkNode(node);
7576 return (0);
7577 case XML_ELEMENT_NODE:
7578 case XML_ATTRIBUTE_NODE:
7579 break;
7580 default:
7581 return (1);
7582 }
7583 xmlUnlinkNode(node);
7584 /*
7585 * Save out-of-scope ns-references in doc->oldNs.
7586 */
7587 do {
7588 switch (node->type) {
7589 case XML_ELEMENT_NODE:
7590 if ((ctxt == NULL) && (node->nsDef != NULL)) {
7591 ns = node->nsDef;
7592 do {
7593 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
7594 &nbList, ns, ns) == -1)
7595 goto internal_error;
7596 ns = ns->next;
7597 } while (ns != NULL);
7598 }
7599 /* No break on purpose. */
7600 case XML_ATTRIBUTE_NODE:
7601 if (node->ns != NULL) {
7602 /*
7603 * Find a mapping.
7604 */
7605 if (list != NULL) {
7606 for (i = 0, j = 0; i < nbList; i++, j += 2) {
7607 if (node->ns == list[j]) {
7608 node->ns = list[++j];
7609 goto next_node;
7610 }
7611 }
7612 }
7613 ns = NULL;
7614 if (ctxt != NULL) {
7615 /*
7616 * User defined.
7617 */
7618 } else {
7619 /*
7620 * Add to doc's oldNs.
7621 */
7622 ns = xmlDOMWrapStoreNs(doc, node->ns->href,
7623 node->ns->prefix);
7624 if (ns == NULL)
7625 goto internal_error;
7626 }
7627 if (ns != NULL) {
7628 /*
7629 * Add mapping.
7630 */
7631 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
7632 &nbList, node->ns, ns) == -1)
7633 goto internal_error;
7634 }
7635 node->ns = ns;
7636 }
7637 if ((node->type == XML_ELEMENT_NODE) &&
7638 (node->properties != NULL)) {
7639 node = (xmlNodePtr) node->properties;
7640 continue;
7641 }
7642 break;
7643 default:
7644 goto next_sibling;
7645 }
7646next_node:
7647 if ((node->type == XML_ELEMENT_NODE) &&
7648 (node->children != NULL)) {
7649 node = node->children;
7650 continue;
7651 }
7652next_sibling:
7653 if (node == NULL)
7654 break;
7655 if (node->next != NULL)
7656 node = node->next;
7657 else {
7658 node = node->parent;
7659 goto next_sibling;
7660 }
7661 } while (node != NULL);
7662
7663 if (list != NULL)
7664 xmlFree(list);
7665 return (0);
7666
7667internal_error:
7668 if (list != NULL)
7669 xmlFree(list);
7670 return (-1);
7671}
7672
7673/*
7674* xmlSearchNsByHrefStrict:
7675* @doc: the document
7676* @node: the start node
7677* @nsName: the searched namespace name
7678* @retNs: the resulting ns-decl
7679* @prefixed: if the found ns-decl must have a prefix (for attributes)
7680*
7681* Dynamically searches for a ns-declaration which matches
7682* the given @nsName in the ancestor-or-self axis of @node.
7683*
7684* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7685* and internal errors.
7686*/
7687static int
7688xmlSearchNsByHrefStrict(xmlDocPtr doc, xmlNodePtr node, const xmlChar* nsName,
7689 xmlNsPtr *retNs, int prefixed)
7690{
7691 xmlNodePtr cur, prev = NULL, out = NULL;
7692 xmlNsPtr ns, prevns;
7693
7694 if ((doc == NULL) || (nsName == NULL) || (retNs == NULL))
7695 return (-1);
7696
7697 *retNs = NULL;
7698 if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
7699 *retNs = xmlTreeEnsureXMLDecl(doc);
7700 if (*retNs == NULL)
7701 return (-1);
7702 return (1);
7703 }
7704 cur = node;
7705 do {
7706 if (cur->type == XML_ELEMENT_NODE) {
7707 if (cur->nsDef != NULL) {
7708 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
7709 if (prefixed && (ns->prefix == NULL))
7710 continue;
7711 if (prev != NULL) {
7712 /*
7713 * Check the last level of ns-decls for a
7714 * shadowing prefix.
7715 */
7716 prevns = prev->nsDef;
7717 do {
7718 if ((prevns->prefix == ns->prefix) ||
7719 ((prevns->prefix != NULL) &&
7720 (ns->prefix != NULL) &&
7721 xmlStrEqual(prevns->prefix, ns->prefix))) {
7722 /*
7723 * Shadowed.
7724 */
7725 break;
7726 }
7727 prevns = prevns->next;
7728 } while (prevns != NULL);
7729 if (prevns != NULL)
7730 continue;
7731 }
7732 /*
7733 * Ns-name comparison.
7734 */
7735 if ((nsName == ns->href) ||
7736 xmlStrEqual(nsName, ns->href)) {
7737 /*
7738 * At this point the prefix can only be shadowed,
7739 * if we are the the (at least) 3rd level of
7740 * ns-decls.
7741 */
7742 if (out) {
7743 int ret;
7744
7745 ret = xmlNsInScope(doc, node, prev, ns->prefix);
7746 if (ret < 0)
7747 return (-1);
7748 /*
7749 * TODO: Should we try to find a matching ns-name
7750 * only once? This here keeps on searching.
7751 * I think we should try further since, there might
7752 * be an other matching ns-decl with an unshadowed
7753 * prefix.
7754 */
7755 if (! ret)
7756 continue;
7757 }
7758 *retNs = ns;
7759 return (1);
7760 }
7761 }
7762 out = prev;
7763 prev = cur;
7764 }
7765 } else if ((node->type == XML_ENTITY_REF_NODE) ||
7766 (node->type == XML_ENTITY_NODE) ||
7767 (node->type == XML_ENTITY_DECL))
7768 return (0);
7769 cur = cur->parent;
7770 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
7771 return (0);
7772}
7773
7774/*
7775* xmlDOMWrapNSNormDeclareNsForced:
7776* @doc: the doc
7777* @elem: the element-node to declare on
7778* @nsName: the namespace-name of the ns-decl
7779* @prefix: the preferred prefix of the ns-decl
7780* @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls
7781*
7782* Declares a new namespace on @elem. It tries to use the
7783* given @prefix; if a ns-decl with the given prefix is already existent
7784* on @elem, it will generate an other prefix.
7785*
7786* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7787* and internal errors.
7788*/
7789static xmlNsPtr
7790xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc,
7791 xmlNodePtr elem,
7792 const xmlChar *nsName,
7793 const xmlChar *prefix,
7794 int checkShadow)
7795{
7796
7797 xmlNsPtr ret;
7798 char buf[50];
7799 const xmlChar *pref;
7800 int counter = 0;
7801 /*
7802 * Create a ns-decl on @anchor.
7803 */
7804 pref = prefix;
7805 while (1) {
7806 /*
7807 * Lookup whether the prefix is unused in elem's ns-decls.
7808 */
7809 if ((elem->nsDef != NULL) &&
7810 (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL))
7811 goto ns_next_prefix;
7812 if (checkShadow && elem->parent &&
7813 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
7814 /*
7815 * Does it shadow ancestor ns-decls?
7816 */
7817 if (xmlSearchNs(doc, elem->parent, pref) != NULL)
7818 goto ns_next_prefix;
7819 }
7820 ret = xmlNewNs(NULL, nsName, pref);
7821 if (ret == NULL)
7822 return (NULL);
7823 if (elem->nsDef == NULL)
7824 elem->nsDef = ret;
7825 else {
7826 xmlNsPtr ns2 = elem->nsDef;
7827 while (ns2->next != NULL)
7828 ns2 = ns2->next;
7829 ns2->next = ret;
7830 }
7831 return (ret);
7832ns_next_prefix:
7833 counter++;
7834 if (counter > 1000)
7835 return (NULL);
7836 if (prefix == NULL) {
7837 snprintf((char *) buf, sizeof(buf),
7838 "default%d", counter);
7839 } else
7840 snprintf((char *) buf, sizeof(buf),
7841 "%.30s%d", (char *)prefix, counter);
7842 pref = BAD_CAST buf;
7843 }
7844}
7845
7846/*
7847* xmlDOMWrapNSNormAquireNormalizedNs:
7848* @doc: the doc
7849* @elem: the element-node to declare namespaces on
7850* @ns: the ns-struct to use for the search
7851* @retNs: the found/created ns-struct
7852* @nsMap: the ns-map
7853* @topmi: the last ns-map entry
7854* @depth: the current tree depth
7855* @ancestorsOnly: search in ancestor ns-decls only
7856* @prefixed: if the searched ns-decl must have a prefix (for attributes)
7857*
7858* Searches for a matching ns-name in the ns-decls of @nsMap, if not
7859* found it will either declare it on @elem, or store it in doc->oldNs.
7860* If a new ns-decl needs to be declared on @elem, it tries to use the
7861* @ns->prefix for it, if this prefix is already in use on @elem, it will
7862* change the prefix or the new ns-decl.
7863*
7864* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
7865*/
7866static int
7867xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc,
7868 xmlNodePtr elem,
7869 xmlNsPtr ns,
7870 xmlNsPtr *retNs,
7871 xmlNsMapItemPtr *nsMap,
7872 xmlNsMapItemPtr *topmi,
7873 int depth,
7874 int ancestorsOnly,
7875 int prefixed)
7876{
7877 xmlNsMapItemPtr mi;
7878
7879 if ((doc == NULL) || (ns == NULL) || (retNs == NULL) ||
7880 (nsMap == NULL) || (topmi == NULL))
7881 return (-1);
7882
7883 *retNs = NULL;
7884 /*
7885 * Handle XML namespace.
7886 */
7887 if ((ns->prefix) &&
7888 (ns->prefix[0] == 'x') &&
7889 (ns->prefix[1] == 'm') &&
7890 (ns->prefix[2] == 'l') &&
7891 (ns->prefix[3] == 0)) {
7892 /*
7893 * Insert XML namespace mapping.
7894 */
7895 *retNs = xmlTreeEnsureXMLDecl(doc);
7896 if (*retNs == NULL)
7897 return (-1);
7898 return (0);
7899 }
7900 /*
7901 * If the search should be done in ancestors only and no
7902 * @elem (the first ancestor) was specified, then skip the search.
7903 */
7904 if ((! (ancestorsOnly && (elem == NULL))) &&
7905 (*nsMap != NULL)) {
7906
7907 /*
7908 * Try to find an equal ns-name in in-scope ns-decls.
7909 */
7910 for (mi = *nsMap; mi != (*topmi)->next; mi = mi->next) {
7911
7912 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
7913 /*
7914 * This should be turned on to gain speed, if one knows
7915 * that the branch itself was already ns-wellformed and no
7916 * stale references existed. I.e. it searches in the ancestor
7917 * axis only.
7918 */
7919 ((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) &&
7920 /* Skip shadowed prefixes. */
7921 (mi->shadowDepth == -1) &&
7922 /* Skip xmlns="" or xmlns:foo="". */
7923 ((mi->newNs->href != NULL) &&
7924 (mi->newNs->href[0] != 0)) &&
7925 /* Ensure a prefix if wanted. */
7926 ((! prefixed) || (mi->newNs->prefix != NULL)) &&
7927 /* Equal ns name */
7928 ((mi->newNs->href == ns->href) ||
7929 xmlStrEqual(mi->newNs->href, ns->href))) {
7930 /* Set the mapping. */
7931 mi->oldNs = ns;
7932 *retNs = mi->newNs;
7933 return (0);
7934 }
7935 }
7936 }
7937 /*
7938 * No luck, the namespace is out of scope or shadowed.
7939 */
7940 if (elem == NULL) {
7941 xmlNsPtr tmpns;
7942
7943 /*
7944 * Store ns-decls in "oldNs" of the document-node.
7945 */
7946 tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix);
7947 if (tmpns == NULL)
7948 return (-1);
7949 /*
7950 * Insert mapping.
7951 */
7952 if (xmlDOMWrapNSNormAddNsMapItem(nsMap, NULL, ns,
7953 tmpns, XML_TREE_NSMAP_DOC) == NULL) {
7954 xmlFreeNs(tmpns);
7955 return (-1);
7956 }
7957 *retNs = tmpns;
7958 } else {
7959 xmlNsPtr tmpns;
7960
7961 tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href,
7962 ns->prefix, 0);
7963 if (tmpns == NULL)
7964 return (-1);
7965
7966 if (*nsMap != NULL) {
7967 /*
7968 * Does it shadow ancestor ns-decls?
7969 */
7970 for (mi = *nsMap; mi != (*topmi)->next; mi = mi->next) {
7971 if ((mi->depth < depth) &&
7972 (mi->shadowDepth == -1) &&
7973 ((ns->prefix == mi->newNs->prefix) ||
7974 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
7975 /*
7976 * Shadows.
7977 */
7978 mi->shadowDepth = depth;
7979 break;
7980 }
7981 }
7982 }
7983 if (xmlDOMWrapNSNormAddNsMapItem(nsMap, topmi, ns,
7984 tmpns, depth) == NULL) {
7985 xmlFreeNs(tmpns);
7986 return (-1);
7987 }
7988 *retNs = tmpns;
7989 }
7990 return (0);
7991}
7992
7993/*
7994* xmlDOMWrapReconcileNamespaces:
Daniel Veillard304e78c2005-07-03 16:19:41 +00007995* @ctxt: DOM wrapper context, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007996* @elem: the element-node
7997* @options: option flags
7998*
7999* Ensures that ns-references point to ns-decls hold on element-nodes.
8000* Ensures that the tree is namespace wellformed by creating additional
8001* ns-decls where needed. Note that, since prefixes of already existent
8002* ns-decls can be shadowed by this process, it could break QNames in
8003* attribute values or element content.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00008004* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008005*
8006* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8007*/
8008int
8009xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,
8010 xmlNodePtr elem,
8011 int options ATTRIBUTE_UNUSED)
8012{
8013 int depth = -1, adoptns = 0, parnsdone = 0;
8014 xmlNsPtr ns;
8015 xmlDocPtr doc;
8016 xmlNodePtr cur, curElem = NULL;
8017 xmlNsMapItemPtr nsMap = NULL, topmi = NULL, mi;
8018 /* @ancestorsOnly should be set by an option flag. */
8019 int ancestorsOnly = 0;
8020
8021 if ((elem == NULL) || (elem->doc == NULL) ||
8022 (elem->type != XML_ELEMENT_NODE))
8023 return (-1);
8024
8025 doc = elem->doc;
8026 cur = elem;
8027 do {
8028 switch (cur->type) {
8029 case XML_ELEMENT_NODE:
8030 adoptns = 1;
8031 curElem = cur;
8032 depth++;
8033 /*
8034 * Namespace declarations.
8035 */
8036 if (cur->nsDef != NULL) {
8037 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8038 if (! parnsdone) {
8039 if ((elem->parent) &&
8040 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8041 /*
8042 * Gather ancestor in-scope ns-decls.
8043 */
8044 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8045 elem->parent) == -1)
8046 goto internal_error;
8047 if (nsMap != NULL)
8048 topmi = nsMap->prev;
8049 }
8050 parnsdone = 1;
8051 }
8052 /*
8053 * Skip ns-references handling if the referenced
8054 * ns-decl is declared on the same element.
8055 */
8056 if ((cur->ns != NULL) && adoptns && (cur->ns == ns))
8057 adoptns = 0;
8058 /*
8059 * Does it shadow any ns-decl?
8060 */
8061 if (nsMap) {
8062 for (mi = nsMap; mi != topmi->next; mi = mi->next) {
8063 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8064 (mi->shadowDepth == -1) &&
8065 ((ns->prefix == mi->newNs->prefix) ||
8066 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8067
8068 mi->shadowDepth = depth;
8069 }
8070 }
8071 }
8072 /*
8073 * Push mapping.
8074 */
8075 if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi, ns, ns,
8076 depth) == NULL)
8077 goto internal_error;
8078 }
8079 }
8080 if (! adoptns)
8081 goto ns_end;
8082
8083 /* No break on purpose. */
8084 case XML_ATTRIBUTE_NODE:
8085 if (cur->ns == NULL)
8086 goto ns_end;
8087 if (! parnsdone) {
8088 if ((elem->parent) &&
8089 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8090 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8091 elem->parent) == -1)
8092 goto internal_error;
8093 if (nsMap != NULL)
8094 topmi = nsMap->prev;
8095 }
8096 parnsdone = 1;
8097 }
8098 /*
8099 * Adopt ns-references.
8100 */
8101 if (nsMap != NULL) {
8102 /*
8103 * Search for a mapping.
8104 */
8105 for (mi = nsMap; mi != topmi->next; mi = mi->next) {
8106 if ((mi->shadowDepth == -1) &&
8107 (cur->ns == mi->oldNs)) {
8108
8109 cur->ns = mi->newNs;
8110 goto ns_end;
8111 }
8112 }
8113 }
8114 /*
8115 * Aquire a normalized ns-decl and add it to the map.
8116 */
8117 if (xmlDOMWrapNSNormAquireNormalizedNs(doc, curElem,
8118 cur->ns, &ns,
8119 &nsMap, &topmi, depth,
8120 ancestorsOnly,
8121 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8122 goto internal_error;
8123 cur->ns = ns;
8124
8125ns_end:
8126 if ((cur->type == XML_ELEMENT_NODE) &&
8127 (cur->properties != NULL)) {
8128 /*
8129 * Process attributes.
8130 */
8131 cur = (xmlNodePtr) cur->properties;
8132 continue;
8133 }
8134 break;
8135 default:
8136 goto next_sibling;
8137 }
8138 if ((cur->type == XML_ELEMENT_NODE) &&
8139 (cur->children != NULL)) {
8140 /*
8141 * Process content of element-nodes only.
8142 */
8143 cur = cur->children;
8144 continue;
8145 }
8146next_sibling:
8147 if (cur == elem)
8148 break;
8149 if (cur->type == XML_ELEMENT_NODE) {
8150 if (nsMap != NULL) {
8151 /*
8152 * Pop mappings.
8153 */
8154 while ((topmi->depth >= 0) && (topmi->depth >= depth))
8155 topmi = topmi->prev;
8156 /*
8157 * Unshadow.
8158 */
8159 for (mi = nsMap; mi != topmi->next; mi = mi->next)
8160 if (mi->shadowDepth >= depth)
8161 mi->shadowDepth = -1;
8162 }
8163 depth--;
8164 }
8165 if (cur->next != NULL)
8166 cur = cur->next;
8167 else {
8168 cur = cur->parent;
8169 goto next_sibling;
8170 }
8171 } while (cur != NULL);
8172
8173 if (nsMap != NULL)
8174 xmlDOMWrapNSNormFreeNsMap(nsMap);
8175 return (0);
8176internal_error:
8177 if (nsMap != NULL)
8178 xmlDOMWrapNSNormFreeNsMap(nsMap);
8179 return (-1);
8180}
8181
8182/*
8183* xmlDOMWrapAdoptBranch:
8184* @ctxt: the optional context for custom processing
8185* @sourceDoc: the optional sourceDoc
8186* @node: the element-node to start with
8187* @destDoc: the destination doc for adoption
8188* @parent: the optional new parent of @node in @destDoc
8189* @options: option flags
8190*
8191* Ensures that ns-references point to @destDoc: either to
8192* elements->nsDef entries if @destParent is given, or to
8193* @destDoc->oldNs otherwise.
8194* If @destParent is given, it ensures that the tree is namespace
8195* wellformed by creating additional ns-decls where needed.
8196* Note that, since prefixes of already existent ns-decls can be
8197* shadowed by this process, it could break QNames in attribute
8198* values or element content.
8199*
8200* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8201*/
8202static int
8203xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
8204 xmlDocPtr sourceDoc,
8205 xmlNodePtr node,
8206 xmlDocPtr destDoc,
8207 xmlNodePtr destParent,
8208 int options ATTRIBUTE_UNUSED)
8209{
8210 int ret = 0;
8211 xmlNodePtr cur, curElem = NULL;
8212 xmlNsMapItemPtr nsMap = NULL, topmi = NULL, mi;
8213 xmlNsPtr ns;
8214 int depth = -1, adoptStr = 1;
8215 /* gather @parent's ns-decls. */
8216 int parnsdone = 0;
8217 /* @ancestorsOnly should be set per option. */
8218 int ancestorsOnly = 0;
8219
8220 /*
8221 * Optimize string adoption for equal or none dicts.
8222 */
8223 if ((sourceDoc != NULL) &&
8224 (sourceDoc->dict == destDoc->dict))
8225 adoptStr = 0;
8226 else
8227 adoptStr = 1;
8228
8229 cur = node;
8230 while (cur != NULL) {
8231 if (cur->doc != sourceDoc) {
8232 /*
8233 * We'll assume XIncluded nodes if the doc differs.
8234 * TODO: Do we need to reconciliate XIncluded nodes?
8235 * This here skips XIncluded nodes and tries to handle
8236 * broken sequences.
8237 */
8238 if (cur->next == NULL)
8239 goto leave_node;
8240 do {
8241 cur = cur->next;
8242 if ((cur->type == XML_XINCLUDE_END) ||
8243 (cur->doc == node->doc))
8244 break;
8245 } while (cur->next != NULL);
8246
8247 if (cur->doc != node->doc)
8248 goto leave_node;
8249 }
8250 cur->doc = destDoc;
8251 switch (cur->type) {
8252 case XML_XINCLUDE_START:
8253 case XML_XINCLUDE_END:
8254 /*
8255 * TODO
8256 */
8257 return (-1);
8258 case XML_ELEMENT_NODE:
8259 curElem = cur;
8260 depth++;
8261 /*
8262 * Namespace declarations.
8263 */
8264 if ((ctxt == NULL) && (cur->nsDef != NULL)) {
8265 if (! parnsdone) {
8266 if (destParent && (ctxt == NULL)) {
8267 /*
8268 * Gather @parent's in-scope ns-decls.
8269 */
8270 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8271 destParent) == -1)
8272 goto internal_error;
8273 if (nsMap != NULL)
8274 topmi = nsMap->prev;
8275 }
8276 parnsdone = 1;
8277 }
8278 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8279 /*
8280 * ns->prefix and ns->href seem not to be in the dict.
8281 * XML_TREE_ADOPT_STR(ns->prefix)
8282 * XML_TREE_ADOPT_STR(ns->href)
8283 */
8284 /*
8285 * Does it shadow any ns-decl?
8286 */
8287 if (nsMap) {
8288 for (mi = nsMap; mi != topmi->next;
8289 mi = mi->next) {
8290 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8291 (mi->shadowDepth == -1) &&
8292 ((ns->prefix == mi->newNs->prefix) ||
8293 xmlStrEqual(ns->prefix,
8294 mi->newNs->prefix))) {
8295
8296 mi->shadowDepth = depth;
8297 }
8298 }
8299 }
8300 /*
8301 * Push mapping.
8302 */
8303 if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi,
8304 ns, ns, depth) == NULL)
8305 goto internal_error;
8306 }
8307 }
8308 /* No break on purpose. */
8309 case XML_ATTRIBUTE_NODE:
8310
8311 if (cur->ns == NULL)
8312 goto ns_end;
8313 if (! parnsdone) {
8314 if (destParent && (ctxt == NULL)) {
8315 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8316 destParent) == -1)
8317 goto internal_error;
8318 if (nsMap != NULL)
8319 topmi = nsMap->prev;
8320 }
8321 parnsdone = 1;
8322 }
8323 /*
8324 * Adopt ns-references.
8325 */
8326 if (nsMap != NULL) {
8327 /*
8328 * Search for a mapping.
8329 */
8330 for (mi = nsMap; mi != topmi->next; mi = mi->next) {
8331 if ((mi->shadowDepth == -1) &&
8332 (cur->ns == mi->oldNs)) {
8333
8334 cur->ns = mi->newNs;
8335 goto ns_end;
8336 }
8337 }
8338 }
8339 /*
8340 * Start searching for an in-scope ns-decl.
8341 */
8342 if (ctxt != NULL) {
8343 /*
8344 * User-defined behaviour.
8345 */
8346#if 0
8347 ctxt->aquireNsDecl(ctxt, cur->ns, &ns);
8348#endif
8349 /*
8350 * Insert mapping if ns is available; it's the users fault
8351 * if not.
8352 */
8353 if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi,
8354 ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
8355 goto internal_error;
8356 cur->ns = ns;
8357 } else {
8358 /*
8359 * Aquire a normalized ns-decl and add it to the map.
8360 */
8361 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
8362 /* ns-decls on curElem or on destDoc->oldNs */
8363 destParent ? curElem : NULL,
8364 cur->ns, &ns,
8365 &nsMap, &topmi, depth,
8366 ancestorsOnly,
8367 /* ns-decls must be prefixed for attributes. */
8368 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8369 goto internal_error;
8370 cur->ns = ns;
8371 }
8372ns_end:
8373 /*
8374 * Further node properties.
8375 * TODO: Is this all?
8376 */
8377 XML_TREE_ADOPT_STR(cur->name)
8378 if (cur->type == XML_ELEMENT_NODE) {
8379 cur->psvi = NULL;
8380 cur->line = 0;
8381 cur->extra = 0;
8382 /*
8383 * Walk attributes.
8384 */
8385 if (cur->properties != NULL) {
8386 /*
8387 * Process first attribute node.
8388 */
8389 cur = (xmlNodePtr) cur->properties;
8390 continue;
8391 }
8392 } else {
8393 /*
8394 * Attributes.
8395 */
8396 if ((sourceDoc != NULL) &&
8397 (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID))
8398 xmlRemoveID(sourceDoc, (xmlAttrPtr) cur);
8399 ((xmlAttrPtr) cur)->atype = 0;
8400 ((xmlAttrPtr) cur)->psvi = NULL;
8401 }
8402 break;
8403 case XML_TEXT_NODE:
8404 case XML_CDATA_SECTION_NODE:
8405 /*
8406 * This puts the content in the dest dict, only if
8407 * it was previously in the source dict.
8408 */
8409 XML_TREE_ADOPT_STR_2(cur->content)
8410 goto leave_node;
8411 case XML_ENTITY_REF_NODE:
8412 /*
8413 * Remove reference to the entitity-node.
8414 */
8415 cur->content = NULL;
8416 cur->children = NULL;
8417 cur->last = NULL;
8418 if ((destDoc->intSubset) || (destDoc->extSubset)) {
8419 xmlEntityPtr ent;
8420 /*
8421 * Assign new entity-node if available.
8422 */
8423 ent = xmlGetDocEntity(destDoc, cur->name);
8424 if (ent != NULL) {
8425 cur->content = ent->content;
8426 cur->children = (xmlNodePtr) ent;
8427 cur->last = (xmlNodePtr) ent;
8428 }
8429 }
8430 goto leave_node;
8431 case XML_PI_NODE:
8432 XML_TREE_ADOPT_STR(cur->name)
8433 XML_TREE_ADOPT_STR_2(cur->content)
8434 break;
8435 case XML_COMMENT_NODE:
8436 break;
8437 default:
8438 goto internal_error;
8439 }
8440 /*
8441 * Walk the tree.
8442 */
8443 if (cur->children != NULL) {
8444 cur = cur->children;
8445 continue;
8446 }
8447
8448leave_node:
8449 if (cur == node)
8450 break;
8451 if ((cur->type == XML_ELEMENT_NODE) ||
8452 (cur->type == XML_XINCLUDE_START) ||
8453 (cur->type == XML_XINCLUDE_END)) {
8454 /*
8455 * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
8456 */
8457 if (nsMap != NULL) {
8458 /*
8459 * Pop mappings.
8460 */
8461 while (topmi->depth >= depth)
8462 topmi = topmi->prev;
8463 /*
8464 * Unshadow.
8465 */
8466 for (mi = nsMap; mi != topmi->next; mi = mi->next)
8467 if (mi->shadowDepth >= depth)
8468 mi->shadowDepth = -1;
8469 }
8470 depth--;
8471 }
8472 if (cur->next != NULL)
8473 cur = cur->next;
8474 else {
8475 cur = cur->parent;
8476 goto leave_node;
8477 }
8478 }
8479 /*
8480 * Cleanup.
8481 */
8482 if (nsMap != NULL)
8483 xmlDOMWrapNSNormFreeNsMap(nsMap);
8484 return (ret);
8485internal_error:
8486 if (nsMap != NULL)
8487 xmlDOMWrapNSNormFreeNsMap(nsMap);
8488 return (-1);
8489}
8490
8491/*
8492* xmlDOMWrapAdoptAttr:
8493* @ctxt: the optional context for custom processing
8494* @sourceDoc: the optional source document of attr
8495* @attr: the attribute-node to be adopted
8496* @destDoc: the destination doc for adoption
8497* @destParent: the optional new parent of @attr in @destDoc
8498* @options: option flags
8499*
8500* @attr is adopted by @destDoc.
8501* Ensures that ns-references point to @destDoc: either to
8502* elements->nsDef entries if @destParent is given, or to
8503* @destDoc->oldNs otherwise.
8504*
8505* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8506*/
8507static int
8508xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt,
8509 xmlDocPtr sourceDoc,
8510 xmlAttrPtr attr,
8511 xmlDocPtr destDoc,
8512 xmlNodePtr destParent,
8513 int options ATTRIBUTE_UNUSED)
8514{
8515 xmlNodePtr cur;
8516 int adoptStr = 1;
8517
8518 if ((attr == NULL) || (destDoc == NULL))
8519 return (-1);
8520
8521 attr->doc = destDoc;
8522 if (attr->ns != NULL) {
8523 xmlNsPtr ns = NULL;
8524
8525 if (ctxt != NULL) {
8526 /* TODO: User defined. */
8527 }
8528 /* XML Namespace. */
8529 if ((attr->ns->prefix[0] == 'x') && (attr->ns->prefix[1] == 'm') &&
8530 (attr->ns->prefix[2] == 'l') && (attr->ns->prefix[3] == 0)) {
8531 ns = xmlTreeEnsureXMLDecl(destDoc);
8532 } else if (destParent == NULL) {
8533 /*
8534 * Store in @destDoc->oldNs.
8535 */
8536 ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix);
8537 } else {
8538 /*
8539 * Declare on @destParent.
8540 */
8541 if (xmlSearchNsByHrefStrict(destDoc, destParent, attr->ns->href,
8542 &ns, 1) == -1)
8543 goto internal_error;
8544 if (ns == NULL) {
8545 ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent,
8546 attr->ns->href, attr->ns->prefix, 1);
8547 }
8548 }
8549 if (ns == NULL)
8550 goto internal_error;
8551 attr->ns = ns;
8552 }
8553
8554 XML_TREE_ADOPT_STR(attr->name);
8555 attr->atype = 0;
8556 attr->psvi = NULL;
8557 /*
8558 * Walk content.
8559 */
8560 if (attr->children == NULL)
8561 return (0);
8562 cur = attr->children;
8563 while (cur != NULL) {
8564 cur->doc = destDoc;
8565 switch (cur->type) {
8566 case XML_TEXT_NODE:
8567 case XML_CDATA_SECTION_NODE:
8568 XML_TREE_ADOPT_STR_2(cur->content)
8569 break;
8570 case XML_ENTITY_REF_NODE:
8571 /*
8572 * Remove reference to the entitity-node.
8573 */
8574 cur->content = NULL;
8575 cur->children = NULL;
8576 cur->last = NULL;
8577 if ((destDoc->intSubset) || (destDoc->extSubset)) {
8578 xmlEntityPtr ent;
8579 /*
8580 * Assign new entity-node if available.
8581 */
8582 ent = xmlGetDocEntity(destDoc, cur->name);
8583 if (ent != NULL) {
8584 cur->content = ent->content;
8585 cur->children = (xmlNodePtr) ent;
8586 cur->last = (xmlNodePtr) ent;
8587 }
8588 }
8589 break;
8590 default:
8591 break;
8592 }
8593 if (cur->children != NULL) {
8594 cur = cur->children;
8595 continue;
8596 }
8597next_sibling:
8598 if (cur == (xmlNodePtr) attr)
8599 break;
8600 if (cur->next != NULL)
8601 cur = cur->next;
8602 else {
8603 cur = cur->parent;
8604 goto next_sibling;
8605 }
8606 }
8607 return (0);
8608internal_error:
8609 return (-1);
8610}
8611
8612/*
8613* xmlDOMWrapAdoptNode:
8614* @ctxt: the optional context for custom processing
8615* @sourceDoc: the optional sourceDoc
8616* @node: the node to start with
8617* @destDoc: the destination doc
Kasimier T. Buchcik4d9c9482005-06-27 15:04:46 +00008618* @destParent: the optional new parent of @node in @destDoc
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008619* @options: option flags
8620*
8621* Ensures that ns-references point to @destDoc: either to
8622* elements->nsDef entries if @destParent is given, or to
8623* @destDoc->oldNs otherwise.
8624* If @destParent is given, it ensures that the tree is namespace
8625* wellformed by creating additional ns-decls where needed.
8626* Note that, since prefixes of already existent ns-decls can be
8627* shadowed by this process, it could break QNames in attribute
8628* values or element content.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00008629* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008630*
8631* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8632*/
8633int
8634xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt,
8635 xmlDocPtr sourceDoc,
8636 xmlNodePtr node,
8637 xmlDocPtr destDoc,
8638 xmlNodePtr destParent,
8639 int options)
8640{
8641 if ((node == NULL) || (destDoc == NULL) ||
8642 ((destParent != NULL) && (destParent->doc != destDoc)))
8643 return(-1);
8644 /*
8645 * Check node->doc sanity.
8646 */
8647 if ((node->doc != NULL) && (sourceDoc != NULL) &&
8648 (node->doc != sourceDoc)) {
8649 /*
8650 * Might be an XIncluded node.
8651 */
8652 return (-1);
8653 }
8654 if (sourceDoc == NULL)
8655 sourceDoc = node->doc;
8656 if (sourceDoc == destDoc)
8657 return (-1);
8658 switch (node->type) {
8659 case XML_ELEMENT_NODE:
8660 case XML_ATTRIBUTE_NODE:
8661 case XML_TEXT_NODE:
8662 case XML_CDATA_SECTION_NODE:
8663 case XML_ENTITY_REF_NODE:
8664 case XML_PI_NODE:
8665 case XML_COMMENT_NODE:
8666 break;
8667 case XML_DOCUMENT_FRAG_NODE:
8668 return (2);
8669 default:
8670 return (1);
8671 }
8672 /*
8673 * Unlink only if @node was not already added to @destParent.
8674 */
8675 if ((node->parent != NULL) && (destParent != node->parent))
8676 xmlUnlinkNode(node);
8677
8678 if (node->type == XML_ELEMENT_NODE) {
8679 return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node,
8680 destDoc, destParent, options));
8681 } else if (node->type == XML_ATTRIBUTE_NODE) {
8682 return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc,
8683 (xmlAttrPtr) node, destDoc, destParent, options));
8684 } else {
8685 xmlNodePtr cur = node;
8686 int adoptStr = 1;
8687
8688 cur->doc = destDoc;
8689 /*
8690 * Optimize string adoption.
8691 */
8692 if ((sourceDoc != NULL) &&
8693 (sourceDoc->dict == destDoc->dict))
8694 adoptStr = 0;
8695 switch (node->type) {
8696 case XML_TEXT_NODE:
8697 case XML_CDATA_SECTION_NODE:
8698 XML_TREE_ADOPT_STR_2(node->content)
8699 break;
8700 case XML_ENTITY_REF_NODE:
8701 /*
8702 * Remove reference to the entitity-node.
8703 */
8704 node->content = NULL;
8705 node->children = NULL;
8706 node->last = NULL;
8707 if ((destDoc->intSubset) || (destDoc->extSubset)) {
8708 xmlEntityPtr ent;
8709 /*
8710 * Assign new entity-node if available.
8711 */
8712 ent = xmlGetDocEntity(destDoc, node->name);
8713 if (ent != NULL) {
8714 node->content = ent->content;
8715 node->children = (xmlNodePtr) ent;
8716 node->last = (xmlNodePtr) ent;
8717 }
8718 }
8719 XML_TREE_ADOPT_STR(node->name)
8720 break;
Daniel Veillard7e21fd12005-07-03 21:44:07 +00008721 case XML_PI_NODE: {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008722 XML_TREE_ADOPT_STR(node->name)
8723 XML_TREE_ADOPT_STR_2(node->content)
8724 break;
Daniel Veillard7e21fd12005-07-03 21:44:07 +00008725 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008726 default:
8727 break;
8728 }
8729 }
8730 return (0);
8731}
8732
8733
Daniel Veillard5d4644e2005-04-01 13:11:58 +00008734#define bottom_tree
8735#include "elfgcchack.h"