blob: 6bd8d4e2905fe8939456f43548e708e6cc39bbf2 [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
1136 xmlDebugCheckDocument(stderr, cur);
1137#endif
1138
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001139 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001140
Daniel Veillarda880b122003-04-21 21:36:41 +00001141 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001142 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1143
Daniel Veillard76d66f42001-05-16 21:05:17 +00001144 /*
1145 * Do this before freeing the children list to avoid ID lookups
1146 */
1147 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1148 cur->ids = NULL;
1149 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1150 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001151 extSubset = cur->extSubset;
1152 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001153 if (intSubset == extSubset)
1154 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001155 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001156 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001157 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001158 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001159 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001160 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001161 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001162 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001163 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001164 }
1165
1166 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001167 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001168
1169 DICT_FREE(cur->version)
1170 DICT_FREE(cur->name)
1171 DICT_FREE(cur->encoding)
1172 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001173 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001174 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001175}
1176
1177/**
1178 * xmlStringLenGetNodeList:
1179 * @doc: the document
1180 * @value: the value of the text
1181 * @len: the length of the string value
1182 *
1183 * Parse the value string and build the node list associated. Should
1184 * produce a flat tree with only TEXTs and ENTITY_REFs.
1185 * Returns a pointer to the first child
1186 */
1187xmlNodePtr
1188xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1189 xmlNodePtr ret = NULL, last = NULL;
1190 xmlNodePtr node;
1191 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001192 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001193 const xmlChar *q;
1194 xmlEntityPtr ent;
1195
1196 if (value == NULL) return(NULL);
1197
1198 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001199 while ((cur < end) && (*cur != 0)) {
1200 if (cur[0] == '&') {
1201 int charval = 0;
1202 xmlChar tmp;
1203
Owen Taylor3473f882001-02-23 17:55:21 +00001204 /*
1205 * Save the current text.
1206 */
1207 if (cur != q) {
1208 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1209 xmlNodeAddContentLen(last, q, cur - q);
1210 } else {
1211 node = xmlNewDocTextLen(doc, q, cur - q);
1212 if (node == NULL) return(ret);
1213 if (last == NULL)
1214 last = ret = node;
1215 else {
1216 last->next = node;
1217 node->prev = last;
1218 last = node;
1219 }
1220 }
1221 }
Owen Taylor3473f882001-02-23 17:55:21 +00001222 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001223 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1224 cur += 3;
1225 if (cur < end)
1226 tmp = *cur;
1227 else
1228 tmp = 0;
1229 while (tmp != ';') { /* Non input consuming loop */
1230 if ((tmp >= '0') && (tmp <= '9'))
1231 charval = charval * 16 + (tmp - '0');
1232 else if ((tmp >= 'a') && (tmp <= 'f'))
1233 charval = charval * 16 + (tmp - 'a') + 10;
1234 else if ((tmp >= 'A') && (tmp <= 'F'))
1235 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001236 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001237 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1238 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001239 charval = 0;
1240 break;
1241 }
1242 cur++;
1243 if (cur < end)
1244 tmp = *cur;
1245 else
1246 tmp = 0;
1247 }
1248 if (tmp == ';')
1249 cur++;
1250 q = cur;
1251 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1252 cur += 2;
1253 if (cur < end)
1254 tmp = *cur;
1255 else
1256 tmp = 0;
1257 while (tmp != ';') { /* Non input consuming loops */
1258 if ((tmp >= '0') && (tmp <= '9'))
1259 charval = charval * 10 + (tmp - '0');
1260 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001261 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1262 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001263 charval = 0;
1264 break;
1265 }
1266 cur++;
1267 if (cur < end)
1268 tmp = *cur;
1269 else
1270 tmp = 0;
1271 }
1272 if (tmp == ';')
1273 cur++;
1274 q = cur;
1275 } else {
1276 /*
1277 * Read the entity string
1278 */
1279 cur++;
1280 q = cur;
1281 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1282 if ((cur >= end) || (*cur == 0)) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001283 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1284 (const char *) q);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001285 return(ret);
1286 }
1287 if (cur != q) {
1288 /*
1289 * Predefined entities don't generate nodes
1290 */
1291 val = xmlStrndup(q, cur - q);
1292 ent = xmlGetDocEntity(doc, val);
1293 if ((ent != NULL) &&
1294 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1295 if (last == NULL) {
1296 node = xmlNewDocText(doc, ent->content);
1297 last = ret = node;
1298 } else if (last->type != XML_TEXT_NODE) {
1299 node = xmlNewDocText(doc, ent->content);
1300 last = xmlAddNextSibling(last, node);
1301 } else
1302 xmlNodeAddContent(last, ent->content);
1303
1304 } else {
1305 /*
1306 * Create a new REFERENCE_REF node
1307 */
1308 node = xmlNewReference(doc, val);
1309 if (node == NULL) {
1310 if (val != NULL) xmlFree(val);
1311 return(ret);
1312 }
1313 else if ((ent != NULL) && (ent->children == NULL)) {
1314 xmlNodePtr temp;
1315
1316 ent->children = xmlStringGetNodeList(doc,
1317 (const xmlChar*)node->content);
1318 ent->owner = 1;
1319 temp = ent->children;
1320 while (temp) {
1321 temp->parent = (xmlNodePtr)ent;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001322 ent->last = temp;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001323 temp = temp->next;
1324 }
1325 }
1326 if (last == NULL) {
1327 last = ret = node;
1328 } else {
1329 last = xmlAddNextSibling(last, node);
1330 }
1331 }
1332 xmlFree(val);
1333 }
1334 cur++;
1335 q = cur;
1336 }
1337 if (charval != 0) {
1338 xmlChar buf[10];
1339 int l;
1340
1341 l = xmlCopyCharMultiByte(buf, charval);
1342 buf[l] = 0;
1343 node = xmlNewDocText(doc, buf);
1344 if (node != NULL) {
1345 if (last == NULL) {
1346 last = ret = node;
1347 } else {
1348 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001349 }
1350 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001351 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001352 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001353 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001354 cur++;
1355 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001356 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001357 /*
1358 * Handle the last piece of text.
1359 */
1360 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1361 xmlNodeAddContentLen(last, q, cur - q);
1362 } else {
1363 node = xmlNewDocTextLen(doc, q, cur - q);
1364 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001365 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001366 last = ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001367 } else {
1368 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001369 }
1370 }
1371 }
1372 return(ret);
1373}
1374
1375/**
1376 * xmlStringGetNodeList:
1377 * @doc: the document
1378 * @value: the value of the attribute
1379 *
1380 * Parse the value string and build the node list associated. Should
1381 * produce a flat tree with only TEXTs and ENTITY_REFs.
1382 * Returns a pointer to the first child
1383 */
1384xmlNodePtr
1385xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1386 xmlNodePtr ret = NULL, last = NULL;
1387 xmlNodePtr node;
1388 xmlChar *val;
1389 const xmlChar *cur = value;
1390 const xmlChar *q;
1391 xmlEntityPtr ent;
1392
1393 if (value == NULL) return(NULL);
1394
1395 q = cur;
1396 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001397 if (cur[0] == '&') {
1398 int charval = 0;
1399 xmlChar tmp;
1400
Owen Taylor3473f882001-02-23 17:55:21 +00001401 /*
1402 * Save the current text.
1403 */
1404 if (cur != q) {
1405 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1406 xmlNodeAddContentLen(last, q, cur - q);
1407 } else {
1408 node = xmlNewDocTextLen(doc, q, cur - q);
1409 if (node == NULL) return(ret);
1410 if (last == NULL)
1411 last = ret = node;
1412 else {
1413 last->next = node;
1414 node->prev = last;
1415 last = node;
1416 }
1417 }
1418 }
Owen Taylor3473f882001-02-23 17:55:21 +00001419 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001420 if ((cur[1] == '#') && (cur[2] == 'x')) {
1421 cur += 3;
1422 tmp = *cur;
1423 while (tmp != ';') { /* Non input consuming loop */
1424 if ((tmp >= '0') && (tmp <= '9'))
1425 charval = charval * 16 + (tmp - '0');
1426 else if ((tmp >= 'a') && (tmp <= 'f'))
1427 charval = charval * 16 + (tmp - 'a') + 10;
1428 else if ((tmp >= 'A') && (tmp <= 'F'))
1429 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001430 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001431 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1432 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001433 charval = 0;
1434 break;
1435 }
1436 cur++;
1437 tmp = *cur;
1438 }
1439 if (tmp == ';')
1440 cur++;
1441 q = cur;
1442 } else if (cur[1] == '#') {
1443 cur += 2;
1444 tmp = *cur;
1445 while (tmp != ';') { /* Non input consuming loops */
1446 if ((tmp >= '0') && (tmp <= '9'))
1447 charval = charval * 10 + (tmp - '0');
1448 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001449 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1450 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001451 charval = 0;
1452 break;
1453 }
1454 cur++;
1455 tmp = *cur;
1456 }
1457 if (tmp == ';')
1458 cur++;
1459 q = cur;
1460 } else {
1461 /*
1462 * Read the entity string
1463 */
1464 cur++;
1465 q = cur;
1466 while ((*cur != 0) && (*cur != ';')) cur++;
1467 if (*cur == 0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001468 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1469 (xmlNodePtr) doc, (const char *) q);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001470 return(ret);
1471 }
1472 if (cur != q) {
1473 /*
1474 * Predefined entities don't generate nodes
1475 */
1476 val = xmlStrndup(q, cur - q);
1477 ent = xmlGetDocEntity(doc, val);
1478 if ((ent != NULL) &&
1479 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1480 if (last == NULL) {
1481 node = xmlNewDocText(doc, ent->content);
1482 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001483 } else if (last->type != XML_TEXT_NODE) {
1484 node = xmlNewDocText(doc, ent->content);
1485 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001486 } else
1487 xmlNodeAddContent(last, ent->content);
1488
1489 } else {
1490 /*
1491 * Create a new REFERENCE_REF node
1492 */
1493 node = xmlNewReference(doc, val);
1494 if (node == NULL) {
1495 if (val != NULL) xmlFree(val);
1496 return(ret);
1497 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001498 else if ((ent != NULL) && (ent->children == NULL)) {
1499 xmlNodePtr temp;
1500
1501 ent->children = xmlStringGetNodeList(doc,
1502 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001503 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001504 temp = ent->children;
1505 while (temp) {
1506 temp->parent = (xmlNodePtr)ent;
1507 temp = temp->next;
1508 }
1509 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001510 if (last == NULL) {
1511 last = ret = node;
1512 } else {
1513 last = xmlAddNextSibling(last, node);
1514 }
1515 }
1516 xmlFree(val);
1517 }
1518 cur++;
1519 q = cur;
1520 }
1521 if (charval != 0) {
1522 xmlChar buf[10];
1523 int len;
1524
1525 len = xmlCopyCharMultiByte(buf, charval);
1526 buf[len] = 0;
1527 node = xmlNewDocText(doc, buf);
1528 if (node != NULL) {
1529 if (last == NULL) {
1530 last = ret = node;
1531 } else {
1532 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001533 }
1534 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001535
1536 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001537 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001538 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001539 cur++;
1540 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001541 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001542 /*
1543 * Handle the last piece of text.
1544 */
1545 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1546 xmlNodeAddContentLen(last, q, cur - q);
1547 } else {
1548 node = xmlNewDocTextLen(doc, q, cur - q);
1549 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001550 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001551 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001552 } else {
1553 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001554 }
1555 }
1556 }
1557 return(ret);
1558}
1559
1560/**
1561 * xmlNodeListGetString:
1562 * @doc: the document
1563 * @list: a Node list
1564 * @inLine: should we replace entity contents or show their external form
1565 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001566 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001567 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001568 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001569 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001570 */
1571xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001572xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1573{
Owen Taylor3473f882001-02-23 17:55:21 +00001574 xmlNodePtr node = list;
1575 xmlChar *ret = NULL;
1576 xmlEntityPtr ent;
1577
Daniel Veillard7646b182002-04-20 06:41:40 +00001578 if (list == NULL)
1579 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001580
1581 while (node != NULL) {
1582 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001583 (node->type == XML_CDATA_SECTION_NODE)) {
1584 if (inLine) {
1585 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001586 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001587 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001588
Daniel Veillard7646b182002-04-20 06:41:40 +00001589 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1590 if (buffer != NULL) {
1591 ret = xmlStrcat(ret, buffer);
1592 xmlFree(buffer);
1593 }
1594 }
1595 } else if (node->type == XML_ENTITY_REF_NODE) {
1596 if (inLine) {
1597 ent = xmlGetDocEntity(doc, node->name);
1598 if (ent != NULL) {
1599 xmlChar *buffer;
1600
1601 /* an entity content can be any "well balanced chunk",
1602 * i.e. the result of the content [43] production:
1603 * http://www.w3.org/TR/REC-xml#NT-content.
1604 * So it can contain text, CDATA section or nested
1605 * entity reference nodes (among others).
1606 * -> we recursive call xmlNodeListGetString()
1607 * which handles these types */
1608 buffer = xmlNodeListGetString(doc, ent->children, 1);
1609 if (buffer != NULL) {
1610 ret = xmlStrcat(ret, buffer);
1611 xmlFree(buffer);
1612 }
1613 } else {
1614 ret = xmlStrcat(ret, node->content);
1615 }
1616 } else {
1617 xmlChar buf[2];
1618
1619 buf[0] = '&';
1620 buf[1] = 0;
1621 ret = xmlStrncat(ret, buf, 1);
1622 ret = xmlStrcat(ret, node->name);
1623 buf[0] = ';';
1624 buf[1] = 0;
1625 ret = xmlStrncat(ret, buf, 1);
1626 }
1627 }
1628#if 0
1629 else {
1630 xmlGenericError(xmlGenericErrorContext,
1631 "xmlGetNodeListString : invalid node type %d\n",
1632 node->type);
1633 }
1634#endif
1635 node = node->next;
1636 }
1637 return (ret);
1638}
Daniel Veillard652327a2003-09-29 18:02:38 +00001639
1640#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001641/**
1642 * xmlNodeListGetRawString:
1643 * @doc: the document
1644 * @list: a Node list
1645 * @inLine: should we replace entity contents or show their external form
1646 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001647 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001648 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1649 * this function doesn't do any character encoding handling.
1650 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001651 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001652 */
1653xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001654xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1655{
Owen Taylor3473f882001-02-23 17:55:21 +00001656 xmlNodePtr node = list;
1657 xmlChar *ret = NULL;
1658 xmlEntityPtr ent;
1659
Daniel Veillard7646b182002-04-20 06:41:40 +00001660 if (list == NULL)
1661 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001662
1663 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001664 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001665 (node->type == XML_CDATA_SECTION_NODE)) {
1666 if (inLine) {
1667 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001668 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001669 xmlChar *buffer;
1670
1671 buffer = xmlEncodeSpecialChars(doc, node->content);
1672 if (buffer != NULL) {
1673 ret = xmlStrcat(ret, buffer);
1674 xmlFree(buffer);
1675 }
1676 }
1677 } else if (node->type == XML_ENTITY_REF_NODE) {
1678 if (inLine) {
1679 ent = xmlGetDocEntity(doc, node->name);
1680 if (ent != NULL) {
1681 xmlChar *buffer;
1682
1683 /* an entity content can be any "well balanced chunk",
1684 * i.e. the result of the content [43] production:
1685 * http://www.w3.org/TR/REC-xml#NT-content.
1686 * So it can contain text, CDATA section or nested
1687 * entity reference nodes (among others).
1688 * -> we recursive call xmlNodeListGetRawString()
1689 * which handles these types */
1690 buffer =
1691 xmlNodeListGetRawString(doc, ent->children, 1);
1692 if (buffer != NULL) {
1693 ret = xmlStrcat(ret, buffer);
1694 xmlFree(buffer);
1695 }
1696 } else {
1697 ret = xmlStrcat(ret, node->content);
1698 }
1699 } else {
1700 xmlChar buf[2];
1701
1702 buf[0] = '&';
1703 buf[1] = 0;
1704 ret = xmlStrncat(ret, buf, 1);
1705 ret = xmlStrcat(ret, node->name);
1706 buf[0] = ';';
1707 buf[1] = 0;
1708 ret = xmlStrncat(ret, buf, 1);
1709 }
1710 }
Owen Taylor3473f882001-02-23 17:55:21 +00001711#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001712 else {
1713 xmlGenericError(xmlGenericErrorContext,
1714 "xmlGetNodeListString : invalid node type %d\n",
1715 node->type);
1716 }
Owen Taylor3473f882001-02-23 17:55:21 +00001717#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001718 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001719 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001720 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001721}
Daniel Veillard652327a2003-09-29 18:02:38 +00001722#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001723
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001724static xmlAttrPtr xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns,
1725 const xmlChar *name, const xmlChar *value, int eatname) {
Owen Taylor3473f882001-02-23 17:55:21 +00001726 xmlAttrPtr cur;
1727 xmlDocPtr doc = NULL;
1728
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001729 if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) {
1730 if (eatname == 1)
1731 xmlFree((xmlChar *) name);
1732 return(NULL);
1733 }
Owen Taylor3473f882001-02-23 17:55:21 +00001734
1735 /*
1736 * Allocate a new property and fill the fields.
1737 */
1738 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1739 if (cur == NULL) {
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001740 if (eatname == 1)
1741 xmlFree((xmlChar *) name);
1742 xmlTreeErrMemory("building attribute");
1743 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001744 }
1745 memset(cur, 0, sizeof(xmlAttr));
1746 cur->type = XML_ATTRIBUTE_NODE;
1747
1748 cur->parent = node;
1749 if (node != NULL) {
1750 doc = node->doc;
1751 cur->doc = doc;
1752 }
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001753 cur->ns = ns;
1754
1755 if (eatname == 0) {
1756 if ((doc != NULL) && (doc->dict != NULL))
1757 cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
1758 else
1759 cur->name = xmlStrdup(name);
1760 } else
1761 cur->name = name;
1762
Owen Taylor3473f882001-02-23 17:55:21 +00001763 if (value != NULL) {
1764 xmlChar *buffer;
1765 xmlNodePtr tmp;
1766
1767 buffer = xmlEncodeEntitiesReentrant(doc, value);
1768 cur->children = xmlStringGetNodeList(doc, buffer);
1769 cur->last = NULL;
1770 tmp = cur->children;
1771 while (tmp != NULL) {
1772 tmp->parent = (xmlNodePtr) cur;
Owen Taylor3473f882001-02-23 17:55:21 +00001773 if (tmp->next == NULL)
1774 cur->last = tmp;
1775 tmp = tmp->next;
1776 }
1777 xmlFree(buffer);
1778 }
1779
1780 /*
1781 * Add it at the end to preserve parsing order ...
1782 */
1783 if (node != NULL) {
1784 if (node->properties == NULL) {
1785 node->properties = cur;
1786 } else {
1787 xmlAttrPtr prev = node->properties;
1788
1789 while (prev->next != NULL) prev = prev->next;
1790 prev->next = cur;
1791 cur->prev = prev;
1792 }
1793 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001794
Daniel Veillarda880b122003-04-21 21:36:41 +00001795 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001796 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001797 return(cur);
1798}
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001799
1800#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
1801 defined(LIBXML_SCHEMAS_ENABLED)
1802/**
1803 * xmlNewProp:
1804 * @node: the holding node
1805 * @name: the name of the attribute
1806 * @value: the value of the attribute
1807 *
1808 * Create a new property carried by a node.
1809 * Returns a pointer to the attribute
1810 */
1811xmlAttrPtr
1812xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1813
1814 if (name == NULL) {
1815#ifdef DEBUG_TREE
1816 xmlGenericError(xmlGenericErrorContext,
1817 "xmlNewProp : name == NULL\n");
1818#endif
1819 return(NULL);
1820 }
1821
1822 return xmlNewPropInternal(node, NULL, name, value, 0);
1823}
Daniel Veillard652327a2003-09-29 18:02:38 +00001824#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001825
1826/**
1827 * xmlNewNsProp:
1828 * @node: the holding node
1829 * @ns: the namespace
1830 * @name: the name of the attribute
1831 * @value: the value of the attribute
1832 *
1833 * Create a new property tagged with a namespace and carried by a node.
1834 * Returns a pointer to the attribute
1835 */
1836xmlAttrPtr
1837xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1838 const xmlChar *value) {
Owen Taylor3473f882001-02-23 17:55:21 +00001839
1840 if (name == NULL) {
1841#ifdef DEBUG_TREE
1842 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001843 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001844#endif
1845 return(NULL);
1846 }
1847
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001848 return xmlNewPropInternal(node, ns, name, value, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001849}
1850
1851/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001852 * xmlNewNsPropEatName:
1853 * @node: the holding node
1854 * @ns: the namespace
1855 * @name: the name of the attribute
1856 * @value: the value of the attribute
1857 *
1858 * Create a new property tagged with a namespace and carried by a node.
1859 * Returns a pointer to the attribute
1860 */
1861xmlAttrPtr
1862xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1863 const xmlChar *value) {
Daniel Veillard46de64e2002-05-29 08:21:33 +00001864
1865 if (name == NULL) {
1866#ifdef DEBUG_TREE
1867 xmlGenericError(xmlGenericErrorContext,
1868 "xmlNewNsPropEatName : name == NULL\n");
1869#endif
1870 return(NULL);
1871 }
1872
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001873 return xmlNewPropInternal(node, ns, name, value, 1);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001874}
1875
1876/**
Owen Taylor3473f882001-02-23 17:55:21 +00001877 * xmlNewDocProp:
1878 * @doc: the document
1879 * @name: the name of the attribute
1880 * @value: the value of the attribute
1881 *
1882 * Create a new property carried by a document.
1883 * Returns a pointer to the attribute
1884 */
1885xmlAttrPtr
1886xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1887 xmlAttrPtr cur;
1888
1889 if (name == NULL) {
1890#ifdef DEBUG_TREE
1891 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001892 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001893#endif
1894 return(NULL);
1895 }
1896
1897 /*
1898 * Allocate a new property and fill the fields.
1899 */
1900 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1901 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001902 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001903 return(NULL);
1904 }
1905 memset(cur, 0, sizeof(xmlAttr));
1906 cur->type = XML_ATTRIBUTE_NODE;
1907
Daniel Veillard03a53c32004-10-26 16:06:51 +00001908 if ((doc != NULL) && (doc->dict != NULL))
1909 cur->name = xmlDictLookup(doc->dict, name, -1);
1910 else
1911 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00001912 cur->doc = doc;
1913 if (value != NULL) {
1914 xmlNodePtr tmp;
1915
1916 cur->children = xmlStringGetNodeList(doc, value);
1917 cur->last = NULL;
1918
1919 tmp = cur->children;
1920 while (tmp != NULL) {
1921 tmp->parent = (xmlNodePtr) cur;
1922 if (tmp->next == NULL)
1923 cur->last = tmp;
1924 tmp = tmp->next;
1925 }
1926 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001927
Daniel Veillarda880b122003-04-21 21:36:41 +00001928 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001929 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001930 return(cur);
1931}
1932
1933/**
1934 * xmlFreePropList:
1935 * @cur: the first property in the list
1936 *
1937 * Free a property and all its siblings, all the children are freed too.
1938 */
1939void
1940xmlFreePropList(xmlAttrPtr cur) {
1941 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001942 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001943 while (cur != NULL) {
1944 next = cur->next;
1945 xmlFreeProp(cur);
1946 cur = next;
1947 }
1948}
1949
1950/**
1951 * xmlFreeProp:
1952 * @cur: an attribute
1953 *
1954 * Free one attribute, all the content is freed too
1955 */
1956void
1957xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001958 xmlDictPtr dict = NULL;
1959 if (cur == NULL) return;
1960
1961 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001962
Daniel Veillarda880b122003-04-21 21:36:41 +00001963 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001964 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1965
Owen Taylor3473f882001-02-23 17:55:21 +00001966 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillardda6f4af2005-06-20 17:17:54 +00001967 if ((cur->doc != NULL) && (cur->atype == XML_ATTRIBUTE_ID)) {
1968 xmlRemoveID(cur->doc, cur);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001969 }
Owen Taylor3473f882001-02-23 17:55:21 +00001970 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001971 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00001972 xmlFree(cur);
1973}
1974
Daniel Veillard652327a2003-09-29 18:02:38 +00001975#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001976/**
1977 * xmlRemoveProp:
1978 * @cur: an attribute
1979 *
1980 * Unlink and free one attribute, all the content is freed too
1981 * Note this doesn't work for namespace definition attributes
1982 *
1983 * Returns 0 if success and -1 in case of error.
1984 */
1985int
1986xmlRemoveProp(xmlAttrPtr cur) {
1987 xmlAttrPtr tmp;
1988 if (cur == NULL) {
1989#ifdef DEBUG_TREE
1990 xmlGenericError(xmlGenericErrorContext,
1991 "xmlRemoveProp : cur == NULL\n");
1992#endif
1993 return(-1);
1994 }
1995 if (cur->parent == NULL) {
1996#ifdef DEBUG_TREE
1997 xmlGenericError(xmlGenericErrorContext,
1998 "xmlRemoveProp : cur->parent == NULL\n");
1999#endif
2000 return(-1);
2001 }
2002 tmp = cur->parent->properties;
2003 if (tmp == cur) {
2004 cur->parent->properties = cur->next;
2005 xmlFreeProp(cur);
2006 return(0);
2007 }
2008 while (tmp != NULL) {
2009 if (tmp->next == cur) {
2010 tmp->next = cur->next;
2011 if (tmp->next != NULL)
2012 tmp->next->prev = tmp;
2013 xmlFreeProp(cur);
2014 return(0);
2015 }
2016 tmp = tmp->next;
2017 }
2018#ifdef DEBUG_TREE
2019 xmlGenericError(xmlGenericErrorContext,
2020 "xmlRemoveProp : attribute not owned by its node\n");
2021#endif
2022 return(-1);
2023}
Daniel Veillard652327a2003-09-29 18:02:38 +00002024#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002025
2026/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002027 * xmlNewDocPI:
2028 * @doc: the target document
Owen Taylor3473f882001-02-23 17:55:21 +00002029 * @name: the processing instruction name
2030 * @content: the PI content
2031 *
2032 * Creation of a processing instruction element.
2033 * Returns a pointer to the new node object.
2034 */
2035xmlNodePtr
Daniel Veillard03a53c32004-10-26 16:06:51 +00002036xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
Owen Taylor3473f882001-02-23 17:55:21 +00002037 xmlNodePtr cur;
2038
2039 if (name == NULL) {
2040#ifdef DEBUG_TREE
2041 xmlGenericError(xmlGenericErrorContext,
2042 "xmlNewPI : name == NULL\n");
2043#endif
2044 return(NULL);
2045 }
2046
2047 /*
2048 * Allocate a new node and fill the fields.
2049 */
2050 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2051 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002052 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002053 return(NULL);
2054 }
2055 memset(cur, 0, sizeof(xmlNode));
2056 cur->type = XML_PI_NODE;
2057
Daniel Veillard03a53c32004-10-26 16:06:51 +00002058 if ((doc != NULL) && (doc->dict != NULL))
2059 cur->name = xmlDictLookup(doc->dict, name, -1);
2060 else
2061 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00002062 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002063 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002064 }
Daniel Veillarda03e3652004-11-02 18:45:30 +00002065 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002066
Daniel Veillarda880b122003-04-21 21:36:41 +00002067 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002068 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002069 return(cur);
2070}
2071
2072/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002073 * xmlNewPI:
2074 * @name: the processing instruction name
2075 * @content: the PI content
2076 *
2077 * Creation of a processing instruction element.
2078 * Use xmlDocNewPI preferably to get string interning
2079 *
2080 * Returns a pointer to the new node object.
2081 */
2082xmlNodePtr
2083xmlNewPI(const xmlChar *name, const xmlChar *content) {
2084 return(xmlNewDocPI(NULL, name, content));
2085}
2086
2087/**
Owen Taylor3473f882001-02-23 17:55:21 +00002088 * xmlNewNode:
2089 * @ns: namespace if any
2090 * @name: the node name
2091 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002092 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002093 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002094 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2095 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002096 */
2097xmlNodePtr
2098xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2099 xmlNodePtr cur;
2100
2101 if (name == NULL) {
2102#ifdef DEBUG_TREE
2103 xmlGenericError(xmlGenericErrorContext,
2104 "xmlNewNode : name == NULL\n");
2105#endif
2106 return(NULL);
2107 }
2108
2109 /*
2110 * Allocate a new node and fill the fields.
2111 */
2112 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2113 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002114 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002115 return(NULL);
2116 }
2117 memset(cur, 0, sizeof(xmlNode));
2118 cur->type = XML_ELEMENT_NODE;
2119
2120 cur->name = xmlStrdup(name);
2121 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002122
Daniel Veillarda880b122003-04-21 21:36:41 +00002123 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002124 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002125 return(cur);
2126}
2127
2128/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002129 * xmlNewNodeEatName:
2130 * @ns: namespace if any
2131 * @name: the node name
2132 *
2133 * Creation of a new node element. @ns is optional (NULL).
2134 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002135 * Returns a pointer to the new node object, with pointer @name as
2136 * new node's name. Use xmlNewNode() if a copy of @name string is
2137 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002138 */
2139xmlNodePtr
2140xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2141 xmlNodePtr cur;
2142
2143 if (name == NULL) {
2144#ifdef DEBUG_TREE
2145 xmlGenericError(xmlGenericErrorContext,
2146 "xmlNewNode : name == NULL\n");
2147#endif
2148 return(NULL);
2149 }
2150
2151 /*
2152 * Allocate a new node and fill the fields.
2153 */
2154 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2155 if (cur == NULL) {
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00002156 xmlFree(name);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002157 xmlTreeErrMemory("building node");
Daniel Veillard46de64e2002-05-29 08:21:33 +00002158 return(NULL);
2159 }
2160 memset(cur, 0, sizeof(xmlNode));
2161 cur->type = XML_ELEMENT_NODE;
2162
2163 cur->name = name;
2164 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002165
Daniel Veillarda880b122003-04-21 21:36:41 +00002166 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002167 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002168 return(cur);
2169}
2170
2171/**
Owen Taylor3473f882001-02-23 17:55:21 +00002172 * xmlNewDocNode:
2173 * @doc: the document
2174 * @ns: namespace if any
2175 * @name: the node name
2176 * @content: the XML text content if any
2177 *
2178 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002179 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002180 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2181 * references, but XML special chars need to be escaped first by using
2182 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2183 * need entities support.
2184 *
2185 * Returns a pointer to the new node object.
2186 */
2187xmlNodePtr
2188xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2189 const xmlChar *name, const xmlChar *content) {
2190 xmlNodePtr cur;
2191
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002192 if ((doc != NULL) && (doc->dict != NULL))
Daniel Veillard03a53c32004-10-26 16:06:51 +00002193 cur = xmlNewNodeEatName(ns, (xmlChar *)
2194 xmlDictLookup(doc->dict, name, -1));
2195 else
2196 cur = xmlNewNode(ns, name);
Owen Taylor3473f882001-02-23 17:55:21 +00002197 if (cur != NULL) {
2198 cur->doc = doc;
2199 if (content != NULL) {
2200 cur->children = xmlStringGetNodeList(doc, content);
2201 UPDATE_LAST_CHILD_AND_PARENT(cur)
2202 }
2203 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002204
Owen Taylor3473f882001-02-23 17:55:21 +00002205 return(cur);
2206}
2207
Daniel Veillard46de64e2002-05-29 08:21:33 +00002208/**
2209 * xmlNewDocNodeEatName:
2210 * @doc: the document
2211 * @ns: namespace if any
2212 * @name: the node name
2213 * @content: the XML text content if any
2214 *
2215 * Creation of a new node element within a document. @ns and @content
2216 * are optional (NULL).
2217 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2218 * references, but XML special chars need to be escaped first by using
2219 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2220 * need entities support.
2221 *
2222 * Returns a pointer to the new node object.
2223 */
2224xmlNodePtr
2225xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2226 xmlChar *name, const xmlChar *content) {
2227 xmlNodePtr cur;
2228
2229 cur = xmlNewNodeEatName(ns, name);
2230 if (cur != NULL) {
2231 cur->doc = doc;
2232 if (content != NULL) {
2233 cur->children = xmlStringGetNodeList(doc, content);
2234 UPDATE_LAST_CHILD_AND_PARENT(cur)
2235 }
2236 }
2237 return(cur);
2238}
2239
Daniel Veillard652327a2003-09-29 18:02:38 +00002240#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002241/**
2242 * xmlNewDocRawNode:
2243 * @doc: the document
2244 * @ns: namespace if any
2245 * @name: the node name
2246 * @content: the text content if any
2247 *
2248 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002249 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002250 *
2251 * Returns a pointer to the new node object.
2252 */
2253xmlNodePtr
2254xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2255 const xmlChar *name, const xmlChar *content) {
2256 xmlNodePtr cur;
2257
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002258 cur = xmlNewDocNode(doc, ns, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002259 if (cur != NULL) {
2260 cur->doc = doc;
2261 if (content != NULL) {
2262 cur->children = xmlNewDocText(doc, content);
2263 UPDATE_LAST_CHILD_AND_PARENT(cur)
2264 }
2265 }
2266 return(cur);
2267}
2268
2269/**
2270 * xmlNewDocFragment:
2271 * @doc: the document owning the fragment
2272 *
2273 * Creation of a new Fragment node.
2274 * Returns a pointer to the new node object.
2275 */
2276xmlNodePtr
2277xmlNewDocFragment(xmlDocPtr doc) {
2278 xmlNodePtr cur;
2279
2280 /*
2281 * Allocate a new DocumentFragment node and fill the fields.
2282 */
2283 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2284 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002285 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002286 return(NULL);
2287 }
2288 memset(cur, 0, sizeof(xmlNode));
2289 cur->type = XML_DOCUMENT_FRAG_NODE;
2290
2291 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002292
Daniel Veillarda880b122003-04-21 21:36:41 +00002293 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002294 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002295 return(cur);
2296}
Daniel Veillard652327a2003-09-29 18:02:38 +00002297#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002298
2299/**
2300 * xmlNewText:
2301 * @content: the text content
2302 *
2303 * Creation of a new text node.
2304 * Returns a pointer to the new node object.
2305 */
2306xmlNodePtr
2307xmlNewText(const xmlChar *content) {
2308 xmlNodePtr cur;
2309
2310 /*
2311 * Allocate a new node and fill the fields.
2312 */
2313 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2314 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002315 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002316 return(NULL);
2317 }
2318 memset(cur, 0, sizeof(xmlNode));
2319 cur->type = XML_TEXT_NODE;
2320
2321 cur->name = xmlStringText;
2322 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002323 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002324 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002325
Daniel Veillarda880b122003-04-21 21:36:41 +00002326 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002327 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002328 return(cur);
2329}
2330
Daniel Veillard652327a2003-09-29 18:02:38 +00002331#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002332/**
2333 * xmlNewTextChild:
2334 * @parent: the parent node
2335 * @ns: a namespace if any
2336 * @name: the name of the child
2337 * @content: the text content of the child if any.
2338 *
2339 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002340 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2341 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002342 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002343 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2344 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2345 * reserved XML chars that might appear in @content, such as the ampersand,
2346 * greater-than or less-than signs, are automatically replaced by their XML
2347 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002348 *
2349 * Returns a pointer to the new node object.
2350 */
2351xmlNodePtr
2352xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2353 const xmlChar *name, const xmlChar *content) {
2354 xmlNodePtr cur, prev;
2355
2356 if (parent == NULL) {
2357#ifdef DEBUG_TREE
2358 xmlGenericError(xmlGenericErrorContext,
2359 "xmlNewTextChild : parent == NULL\n");
2360#endif
2361 return(NULL);
2362 }
2363
2364 if (name == NULL) {
2365#ifdef DEBUG_TREE
2366 xmlGenericError(xmlGenericErrorContext,
2367 "xmlNewTextChild : name == NULL\n");
2368#endif
2369 return(NULL);
2370 }
2371
2372 /*
2373 * Allocate a new node
2374 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002375 if (parent->type == XML_ELEMENT_NODE) {
2376 if (ns == NULL)
2377 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2378 else
2379 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2380 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2381 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2382 if (ns == NULL)
2383 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2384 else
2385 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2386 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2387 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2388 } else {
2389 return(NULL);
2390 }
Owen Taylor3473f882001-02-23 17:55:21 +00002391 if (cur == NULL) return(NULL);
2392
2393 /*
2394 * add the new element at the end of the children list.
2395 */
2396 cur->type = XML_ELEMENT_NODE;
2397 cur->parent = parent;
2398 cur->doc = parent->doc;
2399 if (parent->children == NULL) {
2400 parent->children = cur;
2401 parent->last = cur;
2402 } else {
2403 prev = parent->last;
2404 prev->next = cur;
2405 cur->prev = prev;
2406 parent->last = cur;
2407 }
2408
2409 return(cur);
2410}
Daniel Veillard652327a2003-09-29 18:02:38 +00002411#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002412
2413/**
2414 * xmlNewCharRef:
2415 * @doc: the document
2416 * @name: the char ref string, starting with # or "&# ... ;"
2417 *
2418 * Creation of a new character reference node.
2419 * Returns a pointer to the new node object.
2420 */
2421xmlNodePtr
2422xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2423 xmlNodePtr cur;
2424
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002425 if (name == NULL)
2426 return(NULL);
2427
Owen Taylor3473f882001-02-23 17:55:21 +00002428 /*
2429 * Allocate a new node and fill the fields.
2430 */
2431 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2432 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002433 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002434 return(NULL);
2435 }
2436 memset(cur, 0, sizeof(xmlNode));
2437 cur->type = XML_ENTITY_REF_NODE;
2438
2439 cur->doc = doc;
2440 if (name[0] == '&') {
2441 int len;
2442 name++;
2443 len = xmlStrlen(name);
2444 if (name[len - 1] == ';')
2445 cur->name = xmlStrndup(name, len - 1);
2446 else
2447 cur->name = xmlStrndup(name, len);
2448 } else
2449 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002450
Daniel Veillarda880b122003-04-21 21:36:41 +00002451 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002452 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002453 return(cur);
2454}
2455
2456/**
2457 * xmlNewReference:
2458 * @doc: the document
2459 * @name: the reference name, or the reference string with & and ;
2460 *
2461 * Creation of a new reference node.
2462 * Returns a pointer to the new node object.
2463 */
2464xmlNodePtr
2465xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2466 xmlNodePtr cur;
2467 xmlEntityPtr ent;
2468
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002469 if (name == NULL)
2470 return(NULL);
2471
Owen Taylor3473f882001-02-23 17:55:21 +00002472 /*
2473 * Allocate a new node and fill the fields.
2474 */
2475 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2476 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002477 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002478 return(NULL);
2479 }
2480 memset(cur, 0, sizeof(xmlNode));
2481 cur->type = XML_ENTITY_REF_NODE;
2482
2483 cur->doc = doc;
2484 if (name[0] == '&') {
2485 int len;
2486 name++;
2487 len = xmlStrlen(name);
2488 if (name[len - 1] == ';')
2489 cur->name = xmlStrndup(name, len - 1);
2490 else
2491 cur->name = xmlStrndup(name, len);
2492 } else
2493 cur->name = xmlStrdup(name);
2494
2495 ent = xmlGetDocEntity(doc, cur->name);
2496 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002497 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002498 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002499 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002500 * updated. Not sure if this is 100% correct.
2501 * -George
2502 */
2503 cur->children = (xmlNodePtr) ent;
2504 cur->last = (xmlNodePtr) ent;
2505 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002506
Daniel Veillarda880b122003-04-21 21:36:41 +00002507 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002508 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002509 return(cur);
2510}
2511
2512/**
2513 * xmlNewDocText:
2514 * @doc: the document
2515 * @content: the text content
2516 *
2517 * Creation of a new text node within a document.
2518 * Returns a pointer to the new node object.
2519 */
2520xmlNodePtr
2521xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2522 xmlNodePtr cur;
2523
2524 cur = xmlNewText(content);
2525 if (cur != NULL) cur->doc = doc;
2526 return(cur);
2527}
2528
2529/**
2530 * xmlNewTextLen:
2531 * @content: the text content
2532 * @len: the text len.
2533 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002534 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002535 * Returns a pointer to the new node object.
2536 */
2537xmlNodePtr
2538xmlNewTextLen(const xmlChar *content, int len) {
2539 xmlNodePtr cur;
2540
2541 /*
2542 * Allocate a new node and fill the fields.
2543 */
2544 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2545 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002546 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002547 return(NULL);
2548 }
2549 memset(cur, 0, sizeof(xmlNode));
2550 cur->type = XML_TEXT_NODE;
2551
2552 cur->name = xmlStringText;
2553 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002554 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002555 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002556
Daniel Veillarda880b122003-04-21 21:36:41 +00002557 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002558 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002559 return(cur);
2560}
2561
2562/**
2563 * xmlNewDocTextLen:
2564 * @doc: the document
2565 * @content: the text content
2566 * @len: the text len.
2567 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002568 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002569 * text node pertain to a given document.
2570 * Returns a pointer to the new node object.
2571 */
2572xmlNodePtr
2573xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2574 xmlNodePtr cur;
2575
2576 cur = xmlNewTextLen(content, len);
2577 if (cur != NULL) cur->doc = doc;
2578 return(cur);
2579}
2580
2581/**
2582 * xmlNewComment:
2583 * @content: the comment content
2584 *
2585 * Creation of a new node containing a comment.
2586 * Returns a pointer to the new node object.
2587 */
2588xmlNodePtr
2589xmlNewComment(const xmlChar *content) {
2590 xmlNodePtr cur;
2591
2592 /*
2593 * Allocate a new node and fill the fields.
2594 */
2595 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2596 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002597 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002598 return(NULL);
2599 }
2600 memset(cur, 0, sizeof(xmlNode));
2601 cur->type = XML_COMMENT_NODE;
2602
2603 cur->name = xmlStringComment;
2604 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002605 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002606 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002607
Daniel Veillarda880b122003-04-21 21:36:41 +00002608 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002609 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002610 return(cur);
2611}
2612
2613/**
2614 * xmlNewCDataBlock:
2615 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002616 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002617 * @len: the length of the block
2618 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002619 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002620 * Returns a pointer to the new node object.
2621 */
2622xmlNodePtr
2623xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2624 xmlNodePtr cur;
2625
2626 /*
2627 * Allocate a new node and fill the fields.
2628 */
2629 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2630 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002631 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002632 return(NULL);
2633 }
2634 memset(cur, 0, sizeof(xmlNode));
2635 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002636 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002637
2638 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002639 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002640 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002641
Daniel Veillarda880b122003-04-21 21:36:41 +00002642 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002643 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002644 return(cur);
2645}
2646
2647/**
2648 * xmlNewDocComment:
2649 * @doc: the document
2650 * @content: the comment content
2651 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002652 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002653 * Returns a pointer to the new node object.
2654 */
2655xmlNodePtr
2656xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2657 xmlNodePtr cur;
2658
2659 cur = xmlNewComment(content);
2660 if (cur != NULL) cur->doc = doc;
2661 return(cur);
2662}
2663
2664/**
2665 * xmlSetTreeDoc:
2666 * @tree: the top element
2667 * @doc: the document
2668 *
2669 * update all nodes under the tree to point to the right document
2670 */
2671void
2672xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002673 xmlAttrPtr prop;
2674
Owen Taylor3473f882001-02-23 17:55:21 +00002675 if (tree == NULL)
2676 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002677 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002678 if(tree->type == XML_ELEMENT_NODE) {
2679 prop = tree->properties;
2680 while (prop != NULL) {
2681 prop->doc = doc;
2682 xmlSetListDoc(prop->children, doc);
2683 prop = prop->next;
2684 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002685 }
Owen Taylor3473f882001-02-23 17:55:21 +00002686 if (tree->children != NULL)
2687 xmlSetListDoc(tree->children, doc);
2688 tree->doc = doc;
2689 }
2690}
2691
2692/**
2693 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002694 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002695 * @doc: the document
2696 *
2697 * update all nodes in the list to point to the right document
2698 */
2699void
2700xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2701 xmlNodePtr cur;
2702
2703 if (list == NULL)
2704 return;
2705 cur = list;
2706 while (cur != NULL) {
2707 if (cur->doc != doc)
2708 xmlSetTreeDoc(cur, doc);
2709 cur = cur->next;
2710 }
2711}
2712
Daniel Veillard2156d432004-03-04 15:59:36 +00002713#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002714/**
2715 * xmlNewChild:
2716 * @parent: the parent node
2717 * @ns: a namespace if any
2718 * @name: the name of the child
2719 * @content: the XML content of the child if any.
2720 *
2721 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002722 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2723 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002724 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002725 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2726 * references. XML special chars must be escaped first by using
2727 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002728 *
2729 * Returns a pointer to the new node object.
2730 */
2731xmlNodePtr
2732xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2733 const xmlChar *name, const xmlChar *content) {
2734 xmlNodePtr cur, prev;
2735
2736 if (parent == NULL) {
2737#ifdef DEBUG_TREE
2738 xmlGenericError(xmlGenericErrorContext,
2739 "xmlNewChild : parent == NULL\n");
2740#endif
2741 return(NULL);
2742 }
2743
2744 if (name == NULL) {
2745#ifdef DEBUG_TREE
2746 xmlGenericError(xmlGenericErrorContext,
2747 "xmlNewChild : name == NULL\n");
2748#endif
2749 return(NULL);
2750 }
2751
2752 /*
2753 * Allocate a new node
2754 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002755 if (parent->type == XML_ELEMENT_NODE) {
2756 if (ns == NULL)
2757 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2758 else
2759 cur = xmlNewDocNode(parent->doc, ns, name, content);
2760 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2761 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2762 if (ns == NULL)
2763 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2764 else
2765 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002766 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2767 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002768 } else {
2769 return(NULL);
2770 }
Owen Taylor3473f882001-02-23 17:55:21 +00002771 if (cur == NULL) return(NULL);
2772
2773 /*
2774 * add the new element at the end of the children list.
2775 */
2776 cur->type = XML_ELEMENT_NODE;
2777 cur->parent = parent;
2778 cur->doc = parent->doc;
2779 if (parent->children == NULL) {
2780 parent->children = cur;
2781 parent->last = cur;
2782 } else {
2783 prev = parent->last;
2784 prev->next = cur;
2785 cur->prev = prev;
2786 parent->last = cur;
2787 }
2788
2789 return(cur);
2790}
Daniel Veillard652327a2003-09-29 18:02:38 +00002791#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002792
2793/**
2794 * xmlAddNextSibling:
2795 * @cur: the child node
2796 * @elem: the new node
2797 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002798 * Add a new node @elem as the next sibling of @cur
2799 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002800 * first unlinked from its existing context.
2801 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002802 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2803 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002804 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002805 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002806 */
2807xmlNodePtr
2808xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2809 if (cur == NULL) {
2810#ifdef DEBUG_TREE
2811 xmlGenericError(xmlGenericErrorContext,
2812 "xmlAddNextSibling : cur == NULL\n");
2813#endif
2814 return(NULL);
2815 }
2816 if (elem == NULL) {
2817#ifdef DEBUG_TREE
2818 xmlGenericError(xmlGenericErrorContext,
2819 "xmlAddNextSibling : elem == NULL\n");
2820#endif
2821 return(NULL);
2822 }
2823
2824 xmlUnlinkNode(elem);
2825
2826 if (elem->type == XML_TEXT_NODE) {
2827 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002828 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002829 xmlFreeNode(elem);
2830 return(cur);
2831 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002832 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2833 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002834 xmlChar *tmp;
2835
2836 tmp = xmlStrdup(elem->content);
2837 tmp = xmlStrcat(tmp, cur->next->content);
2838 xmlNodeSetContent(cur->next, tmp);
2839 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002840 xmlFreeNode(elem);
2841 return(cur->next);
2842 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002843 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2844 /* check if an attribute with the same name exists */
2845 xmlAttrPtr attr;
2846
2847 if (elem->ns == NULL)
2848 attr = xmlHasProp(cur->parent, elem->name);
2849 else
2850 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2851 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2852 /* different instance, destroy it (attributes must be unique) */
2853 xmlFreeProp(attr);
2854 }
Owen Taylor3473f882001-02-23 17:55:21 +00002855 }
2856
2857 if (elem->doc != cur->doc) {
2858 xmlSetTreeDoc(elem, cur->doc);
2859 }
2860 elem->parent = cur->parent;
2861 elem->prev = cur;
2862 elem->next = cur->next;
2863 cur->next = elem;
2864 if (elem->next != NULL)
2865 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002866 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002867 elem->parent->last = elem;
2868 return(elem);
2869}
2870
William M. Brack21e4ef22005-01-02 09:53:13 +00002871#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
2872 defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002873/**
2874 * xmlAddPrevSibling:
2875 * @cur: the child node
2876 * @elem: the new node
2877 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002878 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002879 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002880 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002881 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002882 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2883 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002884 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002885 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002886 */
2887xmlNodePtr
2888xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2889 if (cur == NULL) {
2890#ifdef DEBUG_TREE
2891 xmlGenericError(xmlGenericErrorContext,
2892 "xmlAddPrevSibling : cur == NULL\n");
2893#endif
2894 return(NULL);
2895 }
2896 if (elem == NULL) {
2897#ifdef DEBUG_TREE
2898 xmlGenericError(xmlGenericErrorContext,
2899 "xmlAddPrevSibling : elem == NULL\n");
2900#endif
2901 return(NULL);
2902 }
2903
2904 xmlUnlinkNode(elem);
2905
2906 if (elem->type == XML_TEXT_NODE) {
2907 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002908 xmlChar *tmp;
2909
2910 tmp = xmlStrdup(elem->content);
2911 tmp = xmlStrcat(tmp, cur->content);
2912 xmlNodeSetContent(cur, tmp);
2913 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002914 xmlFreeNode(elem);
2915 return(cur);
2916 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002917 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2918 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002919 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002920 xmlFreeNode(elem);
2921 return(cur->prev);
2922 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002923 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2924 /* check if an attribute with the same name exists */
2925 xmlAttrPtr attr;
2926
2927 if (elem->ns == NULL)
2928 attr = xmlHasProp(cur->parent, elem->name);
2929 else
2930 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2931 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2932 /* different instance, destroy it (attributes must be unique) */
2933 xmlFreeProp(attr);
2934 }
Owen Taylor3473f882001-02-23 17:55:21 +00002935 }
2936
2937 if (elem->doc != cur->doc) {
2938 xmlSetTreeDoc(elem, cur->doc);
2939 }
2940 elem->parent = cur->parent;
2941 elem->next = cur;
2942 elem->prev = cur->prev;
2943 cur->prev = elem;
2944 if (elem->prev != NULL)
2945 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002946 if (elem->parent != NULL) {
2947 if (elem->type == XML_ATTRIBUTE_NODE) {
2948 if (elem->parent->properties == (xmlAttrPtr) cur) {
2949 elem->parent->properties = (xmlAttrPtr) elem;
2950 }
2951 } else {
2952 if (elem->parent->children == cur) {
2953 elem->parent->children = elem;
2954 }
2955 }
2956 }
Owen Taylor3473f882001-02-23 17:55:21 +00002957 return(elem);
2958}
Daniel Veillard652327a2003-09-29 18:02:38 +00002959#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002960
2961/**
2962 * xmlAddSibling:
2963 * @cur: the child node
2964 * @elem: the new node
2965 *
2966 * Add a new element @elem to the list of siblings of @cur
2967 * merging adjacent TEXT nodes (@elem may be freed)
2968 * If the new element was already inserted in a document it is
2969 * first unlinked from its existing context.
2970 *
2971 * Returns the new element or NULL in case of error.
2972 */
2973xmlNodePtr
2974xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2975 xmlNodePtr parent;
2976
2977 if (cur == NULL) {
2978#ifdef DEBUG_TREE
2979 xmlGenericError(xmlGenericErrorContext,
2980 "xmlAddSibling : cur == NULL\n");
2981#endif
2982 return(NULL);
2983 }
2984
2985 if (elem == NULL) {
2986#ifdef DEBUG_TREE
2987 xmlGenericError(xmlGenericErrorContext,
2988 "xmlAddSibling : elem == NULL\n");
2989#endif
2990 return(NULL);
2991 }
2992
2993 /*
2994 * Constant time is we can rely on the ->parent->last to find
2995 * the last sibling.
2996 */
2997 if ((cur->parent != NULL) &&
2998 (cur->parent->children != NULL) &&
2999 (cur->parent->last != NULL) &&
3000 (cur->parent->last->next == NULL)) {
3001 cur = cur->parent->last;
3002 } else {
3003 while (cur->next != NULL) cur = cur->next;
3004 }
3005
3006 xmlUnlinkNode(elem);
3007
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003008 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3009 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003010 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003011 xmlFreeNode(elem);
3012 return(cur);
3013 }
3014
3015 if (elem->doc != cur->doc) {
3016 xmlSetTreeDoc(elem, cur->doc);
3017 }
3018 parent = cur->parent;
3019 elem->prev = cur;
3020 elem->next = NULL;
3021 elem->parent = parent;
3022 cur->next = elem;
3023 if (parent != NULL)
3024 parent->last = elem;
3025
3026 return(elem);
3027}
3028
3029/**
3030 * xmlAddChildList:
3031 * @parent: the parent node
3032 * @cur: the first node in the list
3033 *
3034 * Add a list of node at the end of the child list of the parent
3035 * merging adjacent TEXT nodes (@cur may be freed)
3036 *
3037 * Returns the last child or NULL in case of error.
3038 */
3039xmlNodePtr
3040xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3041 xmlNodePtr prev;
3042
3043 if (parent == NULL) {
3044#ifdef DEBUG_TREE
3045 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003046 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003047#endif
3048 return(NULL);
3049 }
3050
3051 if (cur == NULL) {
3052#ifdef DEBUG_TREE
3053 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003054 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003055#endif
3056 return(NULL);
3057 }
3058
3059 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3060 (cur->doc != parent->doc)) {
3061#ifdef DEBUG_TREE
3062 xmlGenericError(xmlGenericErrorContext,
3063 "Elements moved to a different document\n");
3064#endif
3065 }
3066
3067 /*
3068 * add the first element at the end of the children list.
3069 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003070
Owen Taylor3473f882001-02-23 17:55:21 +00003071 if (parent->children == NULL) {
3072 parent->children = cur;
3073 } else {
3074 /*
3075 * If cur and parent->last both are TEXT nodes, then merge them.
3076 */
3077 if ((cur->type == XML_TEXT_NODE) &&
3078 (parent->last->type == XML_TEXT_NODE) &&
3079 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003080 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003081 /*
3082 * if it's the only child, nothing more to be done.
3083 */
3084 if (cur->next == NULL) {
3085 xmlFreeNode(cur);
3086 return(parent->last);
3087 }
3088 prev = cur;
3089 cur = cur->next;
3090 xmlFreeNode(prev);
3091 }
3092 prev = parent->last;
3093 prev->next = cur;
3094 cur->prev = prev;
3095 }
3096 while (cur->next != NULL) {
3097 cur->parent = parent;
3098 if (cur->doc != parent->doc) {
3099 xmlSetTreeDoc(cur, parent->doc);
3100 }
3101 cur = cur->next;
3102 }
3103 cur->parent = parent;
3104 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3105 parent->last = cur;
3106
3107 return(cur);
3108}
3109
3110/**
3111 * xmlAddChild:
3112 * @parent: the parent node
3113 * @cur: the child node
3114 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003115 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003116 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003117 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3118 * If there is an attribute with equal name, it is first destroyed.
3119 *
Owen Taylor3473f882001-02-23 17:55:21 +00003120 * Returns the child or NULL in case of error.
3121 */
3122xmlNodePtr
3123xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3124 xmlNodePtr prev;
3125
3126 if (parent == NULL) {
3127#ifdef DEBUG_TREE
3128 xmlGenericError(xmlGenericErrorContext,
3129 "xmlAddChild : parent == NULL\n");
3130#endif
3131 return(NULL);
3132 }
3133
3134 if (cur == NULL) {
3135#ifdef DEBUG_TREE
3136 xmlGenericError(xmlGenericErrorContext,
3137 "xmlAddChild : child == NULL\n");
3138#endif
3139 return(NULL);
3140 }
3141
Owen Taylor3473f882001-02-23 17:55:21 +00003142 /*
3143 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003144 * cur is then freed.
3145 */
3146 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003147 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003148 (parent->content != NULL) &&
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003149 (parent->name == cur->name) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003150 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003151 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003152 xmlFreeNode(cur);
3153 return(parent);
3154 }
3155 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003156 (parent->last->name == cur->name) &&
3157 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003158 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003159 xmlFreeNode(cur);
3160 return(parent->last);
3161 }
3162 }
3163
3164 /*
3165 * add the new element at the end of the children list.
3166 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003167 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003168 cur->parent = parent;
3169 if (cur->doc != parent->doc) {
3170 xmlSetTreeDoc(cur, parent->doc);
3171 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003172 /* this check prevents a loop on tree-traversions if a developer
3173 * tries to add a node to its parent multiple times
3174 */
3175 if (prev == parent)
3176 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003177
3178 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003179 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003180 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003181 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003182 (parent->content != NULL) &&
3183 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003184 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003185 xmlFreeNode(cur);
3186 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003187 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003188 if (cur->type == XML_ATTRIBUTE_NODE) {
3189 if (parent->properties == NULL) {
3190 parent->properties = (xmlAttrPtr) cur;
3191 } else {
3192 /* check if an attribute with the same name exists */
3193 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003194
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003195 if (cur->ns == NULL)
3196 lastattr = xmlHasProp(parent, cur->name);
3197 else
3198 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3199 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3200 /* different instance, destroy it (attributes must be unique) */
3201 xmlFreeProp(lastattr);
3202 }
3203 /* find the end */
3204 lastattr = parent->properties;
3205 while (lastattr->next != NULL) {
3206 lastattr = lastattr->next;
3207 }
3208 lastattr->next = (xmlAttrPtr) cur;
3209 ((xmlAttrPtr) cur)->prev = lastattr;
3210 }
3211 } else {
3212 if (parent->children == NULL) {
3213 parent->children = cur;
3214 parent->last = cur;
3215 } else {
3216 prev = parent->last;
3217 prev->next = cur;
3218 cur->prev = prev;
3219 parent->last = cur;
3220 }
3221 }
Owen Taylor3473f882001-02-23 17:55:21 +00003222 return(cur);
3223}
3224
3225/**
3226 * xmlGetLastChild:
3227 * @parent: the parent node
3228 *
3229 * Search the last child of a node.
3230 * Returns the last child or NULL if none.
3231 */
3232xmlNodePtr
3233xmlGetLastChild(xmlNodePtr parent) {
3234 if (parent == NULL) {
3235#ifdef DEBUG_TREE
3236 xmlGenericError(xmlGenericErrorContext,
3237 "xmlGetLastChild : parent == NULL\n");
3238#endif
3239 return(NULL);
3240 }
3241 return(parent->last);
3242}
3243
3244/**
3245 * xmlFreeNodeList:
3246 * @cur: the first node in the list
3247 *
3248 * Free a node and all its siblings, this is a recursive behaviour, all
3249 * the children are freed too.
3250 */
3251void
3252xmlFreeNodeList(xmlNodePtr cur) {
3253 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003254 xmlDictPtr dict = NULL;
3255
3256 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003257 if (cur->type == XML_NAMESPACE_DECL) {
3258 xmlFreeNsList((xmlNsPtr) cur);
3259 return;
3260 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003261 if ((cur->type == XML_DOCUMENT_NODE) ||
3262#ifdef LIBXML_DOCB_ENABLED
3263 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003264#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003265 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003266 xmlFreeDoc((xmlDocPtr) cur);
3267 return;
3268 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003269 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003270 while (cur != NULL) {
3271 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003272 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003273
Daniel Veillarda880b122003-04-21 21:36:41 +00003274 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003275 xmlDeregisterNodeDefaultValue(cur);
3276
Daniel Veillard02141ea2001-04-30 11:46:40 +00003277 if ((cur->children != NULL) &&
3278 (cur->type != XML_ENTITY_REF_NODE))
3279 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003280 if (((cur->type == XML_ELEMENT_NODE) ||
3281 (cur->type == XML_XINCLUDE_START) ||
3282 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003283 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003284 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003285 if ((cur->type != XML_ELEMENT_NODE) &&
3286 (cur->type != XML_XINCLUDE_START) &&
3287 (cur->type != XML_XINCLUDE_END) &&
3288 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003289 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003290 }
3291 if (((cur->type == XML_ELEMENT_NODE) ||
3292 (cur->type == XML_XINCLUDE_START) ||
3293 (cur->type == XML_XINCLUDE_END)) &&
3294 (cur->nsDef != NULL))
3295 xmlFreeNsList(cur->nsDef);
3296
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003297 /*
3298 * When a node is a text node or a comment, it uses a global static
3299 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003300 * Otherwise the node name might come from the document's
3301 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003302 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003303 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003304 (cur->type != XML_TEXT_NODE) &&
3305 (cur->type != XML_COMMENT_NODE))
3306 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003307 xmlFree(cur);
3308 }
Owen Taylor3473f882001-02-23 17:55:21 +00003309 cur = next;
3310 }
3311}
3312
3313/**
3314 * xmlFreeNode:
3315 * @cur: the node
3316 *
3317 * Free a node, this is a recursive behaviour, all the children are freed too.
3318 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3319 */
3320void
3321xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003322 xmlDictPtr dict = NULL;
3323
3324 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003325
Daniel Veillard02141ea2001-04-30 11:46:40 +00003326 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003327 if (cur->type == XML_DTD_NODE) {
3328 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003329 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003330 }
3331 if (cur->type == XML_NAMESPACE_DECL) {
3332 xmlFreeNs((xmlNsPtr) cur);
3333 return;
3334 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003335 if (cur->type == XML_ATTRIBUTE_NODE) {
3336 xmlFreeProp((xmlAttrPtr) cur);
3337 return;
3338 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003339
Daniel Veillarda880b122003-04-21 21:36:41 +00003340 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003341 xmlDeregisterNodeDefaultValue(cur);
3342
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003343 if (cur->doc != NULL) dict = cur->doc->dict;
3344
Owen Taylor3473f882001-02-23 17:55:21 +00003345 if ((cur->children != NULL) &&
3346 (cur->type != XML_ENTITY_REF_NODE))
3347 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003348 if (((cur->type == XML_ELEMENT_NODE) ||
3349 (cur->type == XML_XINCLUDE_START) ||
3350 (cur->type == XML_XINCLUDE_END)) &&
3351 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003352 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003353 if ((cur->type != XML_ELEMENT_NODE) &&
3354 (cur->content != NULL) &&
3355 (cur->type != XML_ENTITY_REF_NODE) &&
3356 (cur->type != XML_XINCLUDE_END) &&
3357 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003358 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003359 }
3360
Daniel Veillardacd370f2001-06-09 17:17:51 +00003361 /*
3362 * When a node is a text node or a comment, it uses a global static
3363 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003364 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003365 */
Owen Taylor3473f882001-02-23 17:55:21 +00003366 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003367 (cur->type != XML_TEXT_NODE) &&
3368 (cur->type != XML_COMMENT_NODE))
3369 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003370
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003371 if (((cur->type == XML_ELEMENT_NODE) ||
3372 (cur->type == XML_XINCLUDE_START) ||
3373 (cur->type == XML_XINCLUDE_END)) &&
3374 (cur->nsDef != NULL))
3375 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003376 xmlFree(cur);
3377}
3378
3379/**
3380 * xmlUnlinkNode:
3381 * @cur: the node
3382 *
3383 * Unlink a node from it's current context, the node is not freed
3384 */
3385void
3386xmlUnlinkNode(xmlNodePtr cur) {
3387 if (cur == NULL) {
3388#ifdef DEBUG_TREE
3389 xmlGenericError(xmlGenericErrorContext,
3390 "xmlUnlinkNode : node == NULL\n");
3391#endif
3392 return;
3393 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003394 if (cur->type == XML_DTD_NODE) {
3395 xmlDocPtr doc;
3396 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003397 if (doc != NULL) {
3398 if (doc->intSubset == (xmlDtdPtr) cur)
3399 doc->intSubset = NULL;
3400 if (doc->extSubset == (xmlDtdPtr) cur)
3401 doc->extSubset = NULL;
3402 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003403 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003404 if (cur->parent != NULL) {
3405 xmlNodePtr parent;
3406 parent = cur->parent;
3407 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardda6f4af2005-06-20 17:17:54 +00003408 /* If attribute is an ID from subset then remove it */
3409 if ((((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID) &&
3410 xmlIsID(parent->doc, parent, (xmlAttrPtr) cur)) {
3411 xmlRemoveID(cur->doc, (xmlAttrPtr) cur);
3412 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003413 if (parent->properties == (xmlAttrPtr) cur)
3414 parent->properties = ((xmlAttrPtr) cur)->next;
3415 } else {
3416 if (parent->children == cur)
3417 parent->children = cur->next;
3418 if (parent->last == cur)
3419 parent->last = cur->prev;
3420 }
3421 cur->parent = NULL;
3422 }
Owen Taylor3473f882001-02-23 17:55:21 +00003423 if (cur->next != NULL)
3424 cur->next->prev = cur->prev;
3425 if (cur->prev != NULL)
3426 cur->prev->next = cur->next;
3427 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003428}
3429
Daniel Veillard2156d432004-03-04 15:59:36 +00003430#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003431/**
3432 * xmlReplaceNode:
3433 * @old: the old node
3434 * @cur: the node
3435 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003436 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003437 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003438 * first unlinked from its existing context.
3439 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003440 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003441 */
3442xmlNodePtr
3443xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00003444 if (old == cur) return(NULL);
Daniel Veillarda03e3652004-11-02 18:45:30 +00003445 if ((old == NULL) || (old->parent == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003446#ifdef DEBUG_TREE
3447 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda03e3652004-11-02 18:45:30 +00003448 "xmlReplaceNode : old == NULL or without parent\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003449#endif
3450 return(NULL);
3451 }
3452 if (cur == NULL) {
3453 xmlUnlinkNode(old);
3454 return(old);
3455 }
3456 if (cur == old) {
3457 return(old);
3458 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003459 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3460#ifdef DEBUG_TREE
3461 xmlGenericError(xmlGenericErrorContext,
3462 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3463#endif
3464 return(old);
3465 }
3466 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3467#ifdef DEBUG_TREE
3468 xmlGenericError(xmlGenericErrorContext,
3469 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3470#endif
3471 return(old);
3472 }
Owen Taylor3473f882001-02-23 17:55:21 +00003473 xmlUnlinkNode(cur);
Daniel Veillard64d7d122005-05-11 18:03:42 +00003474 xmlSetTreeDoc(cur, old->doc);
Owen Taylor3473f882001-02-23 17:55:21 +00003475 cur->parent = old->parent;
3476 cur->next = old->next;
3477 if (cur->next != NULL)
3478 cur->next->prev = cur;
3479 cur->prev = old->prev;
3480 if (cur->prev != NULL)
3481 cur->prev->next = cur;
3482 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003483 if (cur->type == XML_ATTRIBUTE_NODE) {
3484 if (cur->parent->properties == (xmlAttrPtr)old)
3485 cur->parent->properties = ((xmlAttrPtr) cur);
Daniel Veillardda6f4af2005-06-20 17:17:54 +00003486
3487 /* If old attribute is ID and defined in DTD then remove ID */
3488 if ((((xmlAttrPtr) old)->atype == XML_ATTRIBUTE_ID) &&
3489 xmlIsID(old->doc, old->parent, (xmlAttrPtr) old)) {
3490 xmlRemoveID(old->doc, (xmlAttrPtr) old);
3491 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003492 } else {
3493 if (cur->parent->children == old)
3494 cur->parent->children = cur;
3495 if (cur->parent->last == old)
3496 cur->parent->last = cur;
3497 }
Owen Taylor3473f882001-02-23 17:55:21 +00003498 }
3499 old->next = old->prev = NULL;
3500 old->parent = NULL;
3501 return(old);
3502}
Daniel Veillard652327a2003-09-29 18:02:38 +00003503#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003504
3505/************************************************************************
3506 * *
3507 * Copy operations *
3508 * *
3509 ************************************************************************/
3510
3511/**
3512 * xmlCopyNamespace:
3513 * @cur: the namespace
3514 *
3515 * Do a copy of the namespace.
3516 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003517 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003518 */
3519xmlNsPtr
3520xmlCopyNamespace(xmlNsPtr cur) {
3521 xmlNsPtr ret;
3522
3523 if (cur == NULL) return(NULL);
3524 switch (cur->type) {
3525 case XML_LOCAL_NAMESPACE:
3526 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3527 break;
3528 default:
3529#ifdef DEBUG_TREE
3530 xmlGenericError(xmlGenericErrorContext,
3531 "xmlCopyNamespace: invalid type %d\n", cur->type);
3532#endif
3533 return(NULL);
3534 }
3535 return(ret);
3536}
3537
3538/**
3539 * xmlCopyNamespaceList:
3540 * @cur: the first namespace
3541 *
3542 * Do a copy of an namespace list.
3543 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003544 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003545 */
3546xmlNsPtr
3547xmlCopyNamespaceList(xmlNsPtr cur) {
3548 xmlNsPtr ret = NULL;
3549 xmlNsPtr p = NULL,q;
3550
3551 while (cur != NULL) {
3552 q = xmlCopyNamespace(cur);
3553 if (p == NULL) {
3554 ret = p = q;
3555 } else {
3556 p->next = q;
3557 p = q;
3558 }
3559 cur = cur->next;
3560 }
3561 return(ret);
3562}
3563
3564static xmlNodePtr
3565xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3566/**
3567 * xmlCopyProp:
3568 * @target: the element where the attribute will be grafted
3569 * @cur: the attribute
3570 *
3571 * Do a copy of the attribute.
3572 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003573 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003574 */
3575xmlAttrPtr
3576xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3577 xmlAttrPtr ret;
3578
3579 if (cur == NULL) return(NULL);
3580 if (target != NULL)
3581 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3582 else if (cur->parent != NULL)
3583 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3584 else if (cur->children != NULL)
3585 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3586 else
3587 ret = xmlNewDocProp(NULL, cur->name, NULL);
3588 if (ret == NULL) return(NULL);
3589 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003590
Owen Taylor3473f882001-02-23 17:55:21 +00003591 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003592 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003593
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003594 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3595 if (ns == NULL) {
3596 /*
3597 * Humm, we are copying an element whose namespace is defined
3598 * out of the new tree scope. Search it in the original tree
3599 * and add it at the top of the new tree
3600 */
3601 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3602 if (ns != NULL) {
3603 xmlNodePtr root = target;
3604 xmlNodePtr pred = NULL;
3605
3606 while (root->parent != NULL) {
3607 pred = root;
3608 root = root->parent;
3609 }
3610 if (root == (xmlNodePtr) target->doc) {
3611 /* correct possibly cycling above the document elt */
3612 root = pred;
3613 }
3614 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3615 }
3616 } else {
3617 /*
3618 * we have to find something appropriate here since
3619 * we cant be sure, that the namespce we found is identified
3620 * by the prefix
3621 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003622 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003623 /* this is the nice case */
3624 ret->ns = ns;
3625 } else {
3626 /*
3627 * we are in trouble: we need a new reconcilied namespace.
3628 * This is expensive
3629 */
3630 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3631 }
3632 }
3633
Owen Taylor3473f882001-02-23 17:55:21 +00003634 } else
3635 ret->ns = NULL;
3636
3637 if (cur->children != NULL) {
3638 xmlNodePtr tmp;
3639
3640 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3641 ret->last = NULL;
3642 tmp = ret->children;
3643 while (tmp != NULL) {
3644 /* tmp->parent = (xmlNodePtr)ret; */
3645 if (tmp->next == NULL)
3646 ret->last = tmp;
3647 tmp = tmp->next;
3648 }
3649 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003650 /*
3651 * Try to handle IDs
3652 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003653 if ((target!= NULL) && (cur!= NULL) &&
3654 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003655 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3656 if (xmlIsID(cur->doc, cur->parent, cur)) {
3657 xmlChar *id;
3658
3659 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3660 if (id != NULL) {
3661 xmlAddID(NULL, target->doc, id, ret);
3662 xmlFree(id);
3663 }
3664 }
3665 }
Owen Taylor3473f882001-02-23 17:55:21 +00003666 return(ret);
3667}
3668
3669/**
3670 * xmlCopyPropList:
3671 * @target: the element where the attributes will be grafted
3672 * @cur: the first attribute
3673 *
3674 * Do a copy of an attribute list.
3675 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003676 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003677 */
3678xmlAttrPtr
3679xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3680 xmlAttrPtr ret = NULL;
3681 xmlAttrPtr p = NULL,q;
3682
3683 while (cur != NULL) {
3684 q = xmlCopyProp(target, cur);
William M. Brack13dfa872004-09-18 04:52:08 +00003685 if (q == NULL)
3686 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003687 if (p == NULL) {
3688 ret = p = q;
3689 } else {
3690 p->next = q;
3691 q->prev = p;
3692 p = q;
3693 }
3694 cur = cur->next;
3695 }
3696 return(ret);
3697}
3698
3699/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003700 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003701 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003702 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003703 * tricky reason: namespaces. Doing a direct copy of a node
3704 * say RPM:Copyright without changing the namespace pointer to
3705 * something else can produce stale links. One way to do it is
3706 * to keep a reference counter but this doesn't work as soon
3707 * as one move the element or the subtree out of the scope of
3708 * the existing namespace. The actual solution seems to add
3709 * a copy of the namespace at the top of the copied tree if
3710 * not available in the subtree.
3711 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00003712 * The argument "recursive" normally indicates a recursive copy
3713 * of the node with values 0 (no) and 1 (yes). For XInclude,
3714 * however, we allow a value of 2 to indicate copy properties and
3715 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00003716 */
3717
3718static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003719xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00003720 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003721 xmlNodePtr ret;
3722
3723 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003724 switch (node->type) {
3725 case XML_TEXT_NODE:
3726 case XML_CDATA_SECTION_NODE:
3727 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003728 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003729 case XML_ENTITY_REF_NODE:
3730 case XML_ENTITY_NODE:
3731 case XML_PI_NODE:
3732 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003733 case XML_XINCLUDE_START:
3734 case XML_XINCLUDE_END:
3735 break;
3736 case XML_ATTRIBUTE_NODE:
3737 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3738 case XML_NAMESPACE_DECL:
3739 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3740
Daniel Veillard39196eb2001-06-19 18:09:42 +00003741 case XML_DOCUMENT_NODE:
3742 case XML_HTML_DOCUMENT_NODE:
3743#ifdef LIBXML_DOCB_ENABLED
3744 case XML_DOCB_DOCUMENT_NODE:
3745#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003746#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00003747 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00003748#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003749 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003750 case XML_NOTATION_NODE:
3751 case XML_DTD_NODE:
3752 case XML_ELEMENT_DECL:
3753 case XML_ATTRIBUTE_DECL:
3754 case XML_ENTITY_DECL:
3755 return(NULL);
3756 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003757
Owen Taylor3473f882001-02-23 17:55:21 +00003758 /*
3759 * Allocate a new node and fill the fields.
3760 */
3761 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3762 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003763 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003764 return(NULL);
3765 }
3766 memset(ret, 0, sizeof(xmlNode));
3767 ret->type = node->type;
3768
3769 ret->doc = doc;
3770 ret->parent = parent;
3771 if (node->name == xmlStringText)
3772 ret->name = xmlStringText;
3773 else if (node->name == xmlStringTextNoenc)
3774 ret->name = xmlStringTextNoenc;
3775 else if (node->name == xmlStringComment)
3776 ret->name = xmlStringComment;
Daniel Veillard03a53c32004-10-26 16:06:51 +00003777 else if (node->name != NULL) {
3778 if ((doc != NULL) && (doc->dict != NULL))
3779 ret->name = xmlDictLookup(doc->dict, node->name, -1);
3780 else
3781 ret->name = xmlStrdup(node->name);
3782 }
Daniel Veillard7db37732001-07-12 01:20:08 +00003783 if ((node->type != XML_ELEMENT_NODE) &&
3784 (node->content != NULL) &&
3785 (node->type != XML_ENTITY_REF_NODE) &&
3786 (node->type != XML_XINCLUDE_END) &&
3787 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003788 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003789 }else{
3790 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003791 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003792 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003793 if (parent != NULL) {
3794 xmlNodePtr tmp;
3795
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003796 /*
3797 * this is a tricky part for the node register thing:
3798 * in case ret does get coalesced in xmlAddChild
3799 * the deregister-node callback is called; so we register ret now already
3800 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003801 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003802 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3803
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003804 tmp = xmlAddChild(parent, ret);
3805 /* node could have coalesced */
3806 if (tmp != ret)
3807 return(tmp);
3808 }
Owen Taylor3473f882001-02-23 17:55:21 +00003809
William M. Brack57e9e912004-03-09 16:19:02 +00003810 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003811 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003812 if (node->nsDef != NULL)
3813 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3814
3815 if (node->ns != NULL) {
3816 xmlNsPtr ns;
3817
3818 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3819 if (ns == NULL) {
3820 /*
3821 * Humm, we are copying an element whose namespace is defined
3822 * out of the new tree scope. Search it in the original tree
3823 * and add it at the top of the new tree
3824 */
3825 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3826 if (ns != NULL) {
3827 xmlNodePtr root = ret;
3828
3829 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003830 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003831 }
3832 } else {
3833 /*
3834 * reference the existing namespace definition in our own tree.
3835 */
3836 ret->ns = ns;
3837 }
3838 }
3839 if (node->properties != NULL)
3840 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003841 if (node->type == XML_ENTITY_REF_NODE) {
3842 if ((doc == NULL) || (node->doc != doc)) {
3843 /*
3844 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003845 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003846 * we cannot keep the reference. Try to find it in the
3847 * target document.
3848 */
3849 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3850 } else {
3851 ret->children = node->children;
3852 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003853 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00003854 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003855 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003856 UPDATE_LAST_CHILD_AND_PARENT(ret)
3857 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003858
3859out:
3860 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00003861 if ((parent == NULL) &&
3862 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003863 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003864 return(ret);
3865}
3866
3867static xmlNodePtr
3868xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3869 xmlNodePtr ret = NULL;
3870 xmlNodePtr p = NULL,q;
3871
3872 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003873#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003874 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003875 if (doc == NULL) {
3876 node = node->next;
3877 continue;
3878 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003879 if (doc->intSubset == NULL) {
3880 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3881 q->doc = doc;
3882 q->parent = parent;
3883 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003884 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003885 } else {
3886 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003887 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003888 }
3889 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003890#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003891 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003892 if (ret == NULL) {
3893 q->prev = NULL;
3894 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003895 } else if (p != q) {
3896 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003897 p->next = q;
3898 q->prev = p;
3899 p = q;
3900 }
3901 node = node->next;
3902 }
3903 return(ret);
3904}
3905
3906/**
3907 * xmlCopyNode:
3908 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00003909 * @extended: if 1 do a recursive copy (properties, namespaces and children
3910 * when applicable)
3911 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00003912 *
3913 * Do a copy of the node.
3914 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003915 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003916 */
3917xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003918xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003919 xmlNodePtr ret;
3920
William M. Brack57e9e912004-03-09 16:19:02 +00003921 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00003922 return(ret);
3923}
3924
3925/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003926 * xmlDocCopyNode:
3927 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003928 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00003929 * @extended: if 1 do a recursive copy (properties, namespaces and children
3930 * when applicable)
3931 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00003932 *
3933 * Do a copy of the node to a given document.
3934 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003935 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003936 */
3937xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003938xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003939 xmlNodePtr ret;
3940
William M. Brack57e9e912004-03-09 16:19:02 +00003941 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00003942 return(ret);
3943}
3944
3945/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00003946 * xmlDocCopyNodeList:
3947 * @doc: the target document
3948 * @node: the first node in the list.
3949 *
3950 * Do a recursive copy of the node list.
3951 *
3952 * Returns: a new #xmlNodePtr, or NULL in case of error.
3953 */
3954xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) {
3955 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
3956 return(ret);
3957}
3958
3959/**
Owen Taylor3473f882001-02-23 17:55:21 +00003960 * xmlCopyNodeList:
3961 * @node: the first node in the list.
3962 *
3963 * Do a recursive copy of the node list.
Daniel Veillard03a53c32004-10-26 16:06:51 +00003964 * Use xmlDocCopyNodeList() if possible to ensure string interning.
Owen Taylor3473f882001-02-23 17:55:21 +00003965 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003966 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003967 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003968xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003969 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3970 return(ret);
3971}
3972
Daniel Veillard2156d432004-03-04 15:59:36 +00003973#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003974/**
Owen Taylor3473f882001-02-23 17:55:21 +00003975 * xmlCopyDtd:
3976 * @dtd: the dtd
3977 *
3978 * Do a copy of the dtd.
3979 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003980 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003981 */
3982xmlDtdPtr
3983xmlCopyDtd(xmlDtdPtr dtd) {
3984 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003985 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003986
3987 if (dtd == NULL) return(NULL);
3988 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3989 if (ret == NULL) return(NULL);
3990 if (dtd->entities != NULL)
3991 ret->entities = (void *) xmlCopyEntitiesTable(
3992 (xmlEntitiesTablePtr) dtd->entities);
3993 if (dtd->notations != NULL)
3994 ret->notations = (void *) xmlCopyNotationTable(
3995 (xmlNotationTablePtr) dtd->notations);
3996 if (dtd->elements != NULL)
3997 ret->elements = (void *) xmlCopyElementTable(
3998 (xmlElementTablePtr) dtd->elements);
3999 if (dtd->attributes != NULL)
4000 ret->attributes = (void *) xmlCopyAttributeTable(
4001 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004002 if (dtd->pentities != NULL)
4003 ret->pentities = (void *) xmlCopyEntitiesTable(
4004 (xmlEntitiesTablePtr) dtd->pentities);
4005
4006 cur = dtd->children;
4007 while (cur != NULL) {
4008 q = NULL;
4009
4010 if (cur->type == XML_ENTITY_DECL) {
4011 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4012 switch (tmp->etype) {
4013 case XML_INTERNAL_GENERAL_ENTITY:
4014 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4015 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4016 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4017 break;
4018 case XML_INTERNAL_PARAMETER_ENTITY:
4019 case XML_EXTERNAL_PARAMETER_ENTITY:
4020 q = (xmlNodePtr)
4021 xmlGetParameterEntityFromDtd(ret, tmp->name);
4022 break;
4023 case XML_INTERNAL_PREDEFINED_ENTITY:
4024 break;
4025 }
4026 } else if (cur->type == XML_ELEMENT_DECL) {
4027 xmlElementPtr tmp = (xmlElementPtr) cur;
4028 q = (xmlNodePtr)
4029 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4030 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4031 xmlAttributePtr tmp = (xmlAttributePtr) cur;
4032 q = (xmlNodePtr)
4033 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4034 } else if (cur->type == XML_COMMENT_NODE) {
4035 q = xmlCopyNode(cur, 0);
4036 }
4037
4038 if (q == NULL) {
4039 cur = cur->next;
4040 continue;
4041 }
4042
4043 if (p == NULL)
4044 ret->children = q;
4045 else
4046 p->next = q;
4047
4048 q->prev = p;
4049 q->parent = (xmlNodePtr) ret;
4050 q->next = NULL;
4051 ret->last = q;
4052 p = q;
4053 cur = cur->next;
4054 }
4055
Owen Taylor3473f882001-02-23 17:55:21 +00004056 return(ret);
4057}
Daniel Veillard2156d432004-03-04 15:59:36 +00004058#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004059
Daniel Veillard2156d432004-03-04 15:59:36 +00004060#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004061/**
4062 * xmlCopyDoc:
4063 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004064 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004065 *
4066 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004067 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004068 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004069 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004070 */
4071xmlDocPtr
4072xmlCopyDoc(xmlDocPtr doc, int recursive) {
4073 xmlDocPtr ret;
4074
4075 if (doc == NULL) return(NULL);
4076 ret = xmlNewDoc(doc->version);
4077 if (ret == NULL) return(NULL);
4078 if (doc->name != NULL)
4079 ret->name = xmlMemStrdup(doc->name);
4080 if (doc->encoding != NULL)
4081 ret->encoding = xmlStrdup(doc->encoding);
Daniel Veillardf59507d2005-01-27 17:26:49 +00004082 if (doc->URL != NULL)
4083 ret->URL = xmlStrdup(doc->URL);
Owen Taylor3473f882001-02-23 17:55:21 +00004084 ret->charset = doc->charset;
4085 ret->compression = doc->compression;
4086 ret->standalone = doc->standalone;
4087 if (!recursive) return(ret);
4088
Daniel Veillardb33c2012001-04-25 12:59:04 +00004089 ret->last = NULL;
4090 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004091#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004092 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004093 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004094 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004095 ret->intSubset->parent = ret;
4096 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004097#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004098 if (doc->oldNs != NULL)
4099 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4100 if (doc->children != NULL) {
4101 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004102
4103 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4104 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004105 ret->last = NULL;
4106 tmp = ret->children;
4107 while (tmp != NULL) {
4108 if (tmp->next == NULL)
4109 ret->last = tmp;
4110 tmp = tmp->next;
4111 }
4112 }
4113 return(ret);
4114}
Daniel Veillard652327a2003-09-29 18:02:38 +00004115#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004116
4117/************************************************************************
4118 * *
4119 * Content access functions *
4120 * *
4121 ************************************************************************/
4122
4123/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004124 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004125 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004126 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004127 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004128 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004129 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004130 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004131 */
4132long
4133xmlGetLineNo(xmlNodePtr node)
4134{
4135 long result = -1;
4136
4137 if (!node)
4138 return result;
4139 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004140 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004141 else if ((node->prev != NULL) &&
4142 ((node->prev->type == XML_ELEMENT_NODE) ||
4143 (node->prev->type == XML_TEXT_NODE)))
4144 result = xmlGetLineNo(node->prev);
4145 else if ((node->parent != NULL) &&
4146 ((node->parent->type == XML_ELEMENT_NODE) ||
4147 (node->parent->type == XML_TEXT_NODE)))
4148 result = xmlGetLineNo(node->parent);
4149
4150 return result;
4151}
4152
Daniel Veillard2156d432004-03-04 15:59:36 +00004153#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004154/**
4155 * xmlGetNodePath:
4156 * @node: a node
4157 *
4158 * Build a structure based Path for the given node
4159 *
4160 * Returns the new path or NULL in case of error. The caller must free
4161 * the returned string
4162 */
4163xmlChar *
4164xmlGetNodePath(xmlNodePtr node)
4165{
4166 xmlNodePtr cur, tmp, next;
4167 xmlChar *buffer = NULL, *temp;
4168 size_t buf_len;
4169 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004170 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004171 const char *name;
4172 char nametemp[100];
4173 int occur = 0;
4174
4175 if (node == NULL)
4176 return (NULL);
4177
4178 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004179 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004180 if (buffer == NULL) {
4181 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004182 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004183 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004184 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004185 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004186 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004187 xmlFree(buffer);
4188 return (NULL);
4189 }
4190
4191 buffer[0] = 0;
4192 cur = node;
4193 do {
4194 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004195 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004196 occur = 0;
4197 if ((cur->type == XML_DOCUMENT_NODE) ||
4198 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4199 if (buffer[0] == '/')
4200 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004201 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004202 next = NULL;
4203 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004204 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004205 name = (const char *) cur->name;
4206 if (cur->ns) {
William M. Brack84d83e32003-12-23 03:45:17 +00004207 if (cur->ns->prefix != NULL)
William M. Brack13dfa872004-09-18 04:52:08 +00004208 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4209 (char *)cur->ns->prefix, (char *)cur->name);
William M. Brack84d83e32003-12-23 03:45:17 +00004210 else
William M. Brack13dfa872004-09-18 04:52:08 +00004211 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4212 (char *)cur->name);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004213 nametemp[sizeof(nametemp) - 1] = 0;
4214 name = nametemp;
4215 }
4216 next = cur->parent;
4217
4218 /*
4219 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004220 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004221 */
4222 tmp = cur->prev;
4223 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004224 if ((tmp->type == XML_ELEMENT_NODE) &&
Daniel Veillard0996a162005-02-05 14:00:10 +00004225 (xmlStrEqual(cur->name, tmp->name)) &&
4226 ((tmp->ns == cur->ns) ||
4227 ((tmp->ns != NULL) && (cur->ns != NULL) &&
4228 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004229 occur++;
4230 tmp = tmp->prev;
4231 }
4232 if (occur == 0) {
4233 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004234 while (tmp != NULL && occur == 0) {
4235 if ((tmp->type == XML_ELEMENT_NODE) &&
Daniel Veillard0996a162005-02-05 14:00:10 +00004236 (xmlStrEqual(cur->name, tmp->name)) &&
4237 ((tmp->ns == cur->ns) ||
4238 ((tmp->ns != NULL) && (cur->ns != NULL) &&
4239 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004240 occur++;
4241 tmp = tmp->next;
4242 }
4243 if (occur != 0)
4244 occur = 1;
4245 } else
4246 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004247 } else if (cur->type == XML_COMMENT_NODE) {
4248 sep = "/";
4249 name = "comment()";
4250 next = cur->parent;
4251
4252 /*
4253 * Thumbler index computation
4254 */
4255 tmp = cur->prev;
4256 while (tmp != NULL) {
4257 if (tmp->type == XML_COMMENT_NODE)
4258 occur++;
4259 tmp = tmp->prev;
4260 }
4261 if (occur == 0) {
4262 tmp = cur->next;
4263 while (tmp != NULL && occur == 0) {
4264 if (tmp->type == XML_COMMENT_NODE)
4265 occur++;
4266 tmp = tmp->next;
4267 }
4268 if (occur != 0)
4269 occur = 1;
4270 } else
4271 occur++;
4272 } else if ((cur->type == XML_TEXT_NODE) ||
4273 (cur->type == XML_CDATA_SECTION_NODE)) {
4274 sep = "/";
4275 name = "text()";
4276 next = cur->parent;
4277
4278 /*
4279 * Thumbler index computation
4280 */
4281 tmp = cur->prev;
4282 while (tmp != NULL) {
4283 if ((cur->type == XML_TEXT_NODE) ||
4284 (cur->type == XML_CDATA_SECTION_NODE))
4285 occur++;
4286 tmp = tmp->prev;
4287 }
4288 if (occur == 0) {
4289 tmp = cur->next;
4290 while (tmp != NULL && occur == 0) {
Daniel Veillard1f8658a2004-08-14 21:46:31 +00004291 if ((tmp->type == XML_TEXT_NODE) ||
4292 (tmp->type == XML_CDATA_SECTION_NODE))
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004293 occur++;
4294 tmp = tmp->next;
4295 }
4296 if (occur != 0)
4297 occur = 1;
4298 } else
4299 occur++;
4300 } else if (cur->type == XML_PI_NODE) {
4301 sep = "/";
4302 snprintf(nametemp, sizeof(nametemp) - 1,
William M. Brack13dfa872004-09-18 04:52:08 +00004303 "processing-instruction('%s')", (char *)cur->name);
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004304 nametemp[sizeof(nametemp) - 1] = 0;
4305 name = nametemp;
4306
4307 next = cur->parent;
4308
4309 /*
4310 * Thumbler index computation
4311 */
4312 tmp = cur->prev;
4313 while (tmp != NULL) {
4314 if ((tmp->type == XML_PI_NODE) &&
4315 (xmlStrEqual(cur->name, tmp->name)))
4316 occur++;
4317 tmp = tmp->prev;
4318 }
4319 if (occur == 0) {
4320 tmp = cur->next;
4321 while (tmp != NULL && occur == 0) {
4322 if ((tmp->type == XML_PI_NODE) &&
4323 (xmlStrEqual(cur->name, tmp->name)))
4324 occur++;
4325 tmp = tmp->next;
4326 }
4327 if (occur != 0)
4328 occur = 1;
4329 } else
4330 occur++;
4331
Daniel Veillard8faa7832001-11-26 15:58:08 +00004332 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004333 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004334 name = (const char *) (((xmlAttrPtr) cur)->name);
Daniel Veillard365c8062005-07-19 11:31:55 +00004335 if (cur->ns) {
4336 if (cur->ns->prefix != NULL)
4337 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4338 (char *)cur->ns->prefix, (char *)cur->name);
4339 else
4340 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4341 (char *)cur->name);
4342 nametemp[sizeof(nametemp) - 1] = 0;
4343 name = nametemp;
4344 }
Daniel Veillard8faa7832001-11-26 15:58:08 +00004345 next = ((xmlAttrPtr) cur)->parent;
4346 } else {
4347 next = cur->parent;
4348 }
4349
4350 /*
4351 * Make sure there is enough room
4352 */
4353 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4354 buf_len =
4355 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4356 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4357 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004358 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004359 xmlFree(buf);
4360 xmlFree(buffer);
4361 return (NULL);
4362 }
4363 buffer = temp;
4364 temp = (xmlChar *) xmlRealloc(buf, 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 buf = temp;
4372 }
4373 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004374 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004375 sep, name, (char *) buffer);
4376 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004377 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004378 sep, name, occur, (char *) buffer);
William M. Brack13dfa872004-09-18 04:52:08 +00004379 snprintf((char *) buffer, buf_len, "%s", (char *)buf);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004380 cur = next;
4381 } while (cur != NULL);
4382 xmlFree(buf);
4383 return (buffer);
4384}
Daniel Veillard652327a2003-09-29 18:02:38 +00004385#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004386
4387/**
Owen Taylor3473f882001-02-23 17:55:21 +00004388 * xmlDocGetRootElement:
4389 * @doc: the document
4390 *
4391 * Get the root element of the document (doc->children is a list
4392 * containing possibly comments, PIs, etc ...).
4393 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004394 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004395 */
4396xmlNodePtr
4397xmlDocGetRootElement(xmlDocPtr doc) {
4398 xmlNodePtr ret;
4399
4400 if (doc == NULL) return(NULL);
4401 ret = doc->children;
4402 while (ret != NULL) {
4403 if (ret->type == XML_ELEMENT_NODE)
4404 return(ret);
4405 ret = ret->next;
4406 }
4407 return(ret);
4408}
4409
Daniel Veillard2156d432004-03-04 15:59:36 +00004410#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004411/**
4412 * xmlDocSetRootElement:
4413 * @doc: the document
4414 * @root: the new document root element
4415 *
4416 * Set the root element of the document (doc->children is a list
4417 * containing possibly comments, PIs, etc ...).
4418 *
4419 * Returns the old root element if any was found
4420 */
4421xmlNodePtr
4422xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4423 xmlNodePtr old = NULL;
4424
4425 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004426 if (root == NULL)
4427 return(NULL);
4428 xmlUnlinkNode(root);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00004429 xmlSetTreeDoc(root, doc);
Daniel Veillardc575b992002-02-08 13:28:40 +00004430 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004431 old = doc->children;
4432 while (old != NULL) {
4433 if (old->type == XML_ELEMENT_NODE)
4434 break;
4435 old = old->next;
4436 }
4437 if (old == NULL) {
4438 if (doc->children == NULL) {
4439 doc->children = root;
4440 doc->last = root;
4441 } else {
4442 xmlAddSibling(doc->children, root);
4443 }
4444 } else {
4445 xmlReplaceNode(old, root);
4446 }
4447 return(old);
4448}
Daniel Veillard2156d432004-03-04 15:59:36 +00004449#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004450
Daniel Veillard2156d432004-03-04 15:59:36 +00004451#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004452/**
4453 * xmlNodeSetLang:
4454 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004455 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004456 *
4457 * Set the language of a node, i.e. the values of the xml:lang
4458 * attribute.
4459 */
4460void
4461xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004462 xmlNsPtr ns;
4463
Owen Taylor3473f882001-02-23 17:55:21 +00004464 if (cur == NULL) return;
4465 switch(cur->type) {
4466 case XML_TEXT_NODE:
4467 case XML_CDATA_SECTION_NODE:
4468 case XML_COMMENT_NODE:
4469 case XML_DOCUMENT_NODE:
4470 case XML_DOCUMENT_TYPE_NODE:
4471 case XML_DOCUMENT_FRAG_NODE:
4472 case XML_NOTATION_NODE:
4473 case XML_HTML_DOCUMENT_NODE:
4474 case XML_DTD_NODE:
4475 case XML_ELEMENT_DECL:
4476 case XML_ATTRIBUTE_DECL:
4477 case XML_ENTITY_DECL:
4478 case XML_PI_NODE:
4479 case XML_ENTITY_REF_NODE:
4480 case XML_ENTITY_NODE:
4481 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004482#ifdef LIBXML_DOCB_ENABLED
4483 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004484#endif
4485 case XML_XINCLUDE_START:
4486 case XML_XINCLUDE_END:
4487 return;
4488 case XML_ELEMENT_NODE:
4489 case XML_ATTRIBUTE_NODE:
4490 break;
4491 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004492 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4493 if (ns == NULL)
4494 return;
4495 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004496}
Daniel Veillard652327a2003-09-29 18:02:38 +00004497#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004498
4499/**
4500 * xmlNodeGetLang:
4501 * @cur: the node being checked
4502 *
4503 * Searches the language of a node, i.e. the values of the xml:lang
4504 * attribute or the one carried by the nearest ancestor.
4505 *
4506 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004507 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004508 */
4509xmlChar *
4510xmlNodeGetLang(xmlNodePtr cur) {
4511 xmlChar *lang;
4512
4513 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004514 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004515 if (lang != NULL)
4516 return(lang);
4517 cur = cur->parent;
4518 }
4519 return(NULL);
4520}
4521
4522
Daniel Veillard652327a2003-09-29 18:02:38 +00004523#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004524/**
4525 * xmlNodeSetSpacePreserve:
4526 * @cur: the node being changed
4527 * @val: the xml:space value ("0": default, 1: "preserve")
4528 *
4529 * Set (or reset) the space preserving behaviour of a node, i.e. the
4530 * value of the xml:space attribute.
4531 */
4532void
4533xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004534 xmlNsPtr ns;
4535
Owen Taylor3473f882001-02-23 17:55:21 +00004536 if (cur == NULL) return;
4537 switch(cur->type) {
4538 case XML_TEXT_NODE:
4539 case XML_CDATA_SECTION_NODE:
4540 case XML_COMMENT_NODE:
4541 case XML_DOCUMENT_NODE:
4542 case XML_DOCUMENT_TYPE_NODE:
4543 case XML_DOCUMENT_FRAG_NODE:
4544 case XML_NOTATION_NODE:
4545 case XML_HTML_DOCUMENT_NODE:
4546 case XML_DTD_NODE:
4547 case XML_ELEMENT_DECL:
4548 case XML_ATTRIBUTE_DECL:
4549 case XML_ENTITY_DECL:
4550 case XML_PI_NODE:
4551 case XML_ENTITY_REF_NODE:
4552 case XML_ENTITY_NODE:
4553 case XML_NAMESPACE_DECL:
4554 case XML_XINCLUDE_START:
4555 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004556#ifdef LIBXML_DOCB_ENABLED
4557 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004558#endif
4559 return;
4560 case XML_ELEMENT_NODE:
4561 case XML_ATTRIBUTE_NODE:
4562 break;
4563 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004564 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4565 if (ns == NULL)
4566 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004567 switch (val) {
4568 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004569 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004570 break;
4571 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004572 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004573 break;
4574 }
4575}
Daniel Veillard652327a2003-09-29 18:02:38 +00004576#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004577
4578/**
4579 * xmlNodeGetSpacePreserve:
4580 * @cur: the node being checked
4581 *
4582 * Searches the space preserving behaviour of a node, i.e. the values
4583 * of the xml:space attribute or the one carried by the nearest
4584 * ancestor.
4585 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004586 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004587 */
4588int
4589xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4590 xmlChar *space;
4591
4592 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004593 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004594 if (space != NULL) {
4595 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4596 xmlFree(space);
4597 return(1);
4598 }
4599 if (xmlStrEqual(space, BAD_CAST "default")) {
4600 xmlFree(space);
4601 return(0);
4602 }
4603 xmlFree(space);
4604 }
4605 cur = cur->parent;
4606 }
4607 return(-1);
4608}
4609
Daniel Veillard652327a2003-09-29 18:02:38 +00004610#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004611/**
4612 * xmlNodeSetName:
4613 * @cur: the node being changed
4614 * @name: the new tag name
4615 *
4616 * Set (or reset) the name of a node.
4617 */
4618void
4619xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00004620 xmlDocPtr doc;
4621 xmlDictPtr dict;
4622
Owen Taylor3473f882001-02-23 17:55:21 +00004623 if (cur == NULL) return;
4624 if (name == NULL) return;
4625 switch(cur->type) {
4626 case XML_TEXT_NODE:
4627 case XML_CDATA_SECTION_NODE:
4628 case XML_COMMENT_NODE:
4629 case XML_DOCUMENT_TYPE_NODE:
4630 case XML_DOCUMENT_FRAG_NODE:
4631 case XML_NOTATION_NODE:
4632 case XML_HTML_DOCUMENT_NODE:
4633 case XML_NAMESPACE_DECL:
4634 case XML_XINCLUDE_START:
4635 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004636#ifdef LIBXML_DOCB_ENABLED
4637 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004638#endif
4639 return;
4640 case XML_ELEMENT_NODE:
4641 case XML_ATTRIBUTE_NODE:
4642 case XML_PI_NODE:
4643 case XML_ENTITY_REF_NODE:
4644 case XML_ENTITY_NODE:
4645 case XML_DTD_NODE:
4646 case XML_DOCUMENT_NODE:
4647 case XML_ELEMENT_DECL:
4648 case XML_ATTRIBUTE_DECL:
4649 case XML_ENTITY_DECL:
4650 break;
4651 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00004652 doc = cur->doc;
4653 if (doc != NULL)
4654 dict = doc->dict;
4655 else
4656 dict = NULL;
4657 if (dict != NULL) {
4658 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
4659 xmlFree((xmlChar *) cur->name);
4660 cur->name = xmlDictLookup(dict, name, -1);
4661 } else {
4662 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4663 cur->name = xmlStrdup(name);
4664 }
Owen Taylor3473f882001-02-23 17:55:21 +00004665}
Daniel Veillard2156d432004-03-04 15:59:36 +00004666#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004667
Daniel Veillard2156d432004-03-04 15:59:36 +00004668#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004669/**
4670 * xmlNodeSetBase:
4671 * @cur: the node being changed
4672 * @uri: the new base URI
4673 *
4674 * Set (or reset) the base URI of a node, i.e. the value of the
4675 * xml:base attribute.
4676 */
4677void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004678xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004679 xmlNsPtr ns;
4680
Owen Taylor3473f882001-02-23 17:55:21 +00004681 if (cur == NULL) return;
4682 switch(cur->type) {
4683 case XML_TEXT_NODE:
4684 case XML_CDATA_SECTION_NODE:
4685 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004686 case XML_DOCUMENT_TYPE_NODE:
4687 case XML_DOCUMENT_FRAG_NODE:
4688 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004689 case XML_DTD_NODE:
4690 case XML_ELEMENT_DECL:
4691 case XML_ATTRIBUTE_DECL:
4692 case XML_ENTITY_DECL:
4693 case XML_PI_NODE:
4694 case XML_ENTITY_REF_NODE:
4695 case XML_ENTITY_NODE:
4696 case XML_NAMESPACE_DECL:
4697 case XML_XINCLUDE_START:
4698 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004699 return;
4700 case XML_ELEMENT_NODE:
4701 case XML_ATTRIBUTE_NODE:
4702 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004703 case XML_DOCUMENT_NODE:
4704#ifdef LIBXML_DOCB_ENABLED
4705 case XML_DOCB_DOCUMENT_NODE:
4706#endif
4707 case XML_HTML_DOCUMENT_NODE: {
4708 xmlDocPtr doc = (xmlDocPtr) cur;
4709
4710 if (doc->URL != NULL)
4711 xmlFree((xmlChar *) doc->URL);
4712 if (uri == NULL)
4713 doc->URL = NULL;
4714 else
4715 doc->URL = xmlStrdup(uri);
4716 return;
4717 }
Owen Taylor3473f882001-02-23 17:55:21 +00004718 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004719
4720 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4721 if (ns == NULL)
4722 return;
4723 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004724}
Daniel Veillard652327a2003-09-29 18:02:38 +00004725#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004726
4727/**
Owen Taylor3473f882001-02-23 17:55:21 +00004728 * xmlNodeGetBase:
4729 * @doc: the document the node pertains to
4730 * @cur: the node being checked
4731 *
4732 * Searches for the BASE URL. The code should work on both XML
4733 * and HTML document even if base mechanisms are completely different.
4734 * It returns the base as defined in RFC 2396 sections
4735 * 5.1.1. Base URI within Document Content
4736 * and
4737 * 5.1.2. Base URI from the Encapsulating Entity
4738 * However it does not return the document base (5.1.3), use
4739 * xmlDocumentGetBase() for this
4740 *
4741 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004742 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004743 */
4744xmlChar *
4745xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004746 xmlChar *oldbase = NULL;
4747 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004748
4749 if ((cur == NULL) && (doc == NULL))
4750 return(NULL);
4751 if (doc == NULL) doc = cur->doc;
4752 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4753 cur = doc->children;
4754 while ((cur != NULL) && (cur->name != NULL)) {
4755 if (cur->type != XML_ELEMENT_NODE) {
4756 cur = cur->next;
4757 continue;
4758 }
4759 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4760 cur = cur->children;
4761 continue;
4762 }
4763 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4764 cur = cur->children;
4765 continue;
4766 }
4767 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4768 return(xmlGetProp(cur, BAD_CAST "href"));
4769 }
4770 cur = cur->next;
4771 }
4772 return(NULL);
4773 }
4774 while (cur != NULL) {
4775 if (cur->type == XML_ENTITY_DECL) {
4776 xmlEntityPtr ent = (xmlEntityPtr) cur;
4777 return(xmlStrdup(ent->URI));
4778 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004779 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004780 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004781 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004782 if (oldbase != NULL) {
4783 newbase = xmlBuildURI(oldbase, base);
4784 if (newbase != NULL) {
4785 xmlFree(oldbase);
4786 xmlFree(base);
4787 oldbase = newbase;
4788 } else {
4789 xmlFree(oldbase);
4790 xmlFree(base);
4791 return(NULL);
4792 }
4793 } else {
4794 oldbase = base;
4795 }
4796 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4797 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4798 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4799 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004800 }
4801 }
Owen Taylor3473f882001-02-23 17:55:21 +00004802 cur = cur->parent;
4803 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004804 if ((doc != NULL) && (doc->URL != NULL)) {
4805 if (oldbase == NULL)
4806 return(xmlStrdup(doc->URL));
4807 newbase = xmlBuildURI(oldbase, doc->URL);
4808 xmlFree(oldbase);
4809 return(newbase);
4810 }
4811 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004812}
4813
4814/**
Daniel Veillard78697292003-10-19 20:44:43 +00004815 * xmlNodeBufGetContent:
4816 * @buffer: a buffer
4817 * @cur: the node being read
4818 *
4819 * Read the value of a node @cur, this can be either the text carried
4820 * directly by this node if it's a TEXT node or the aggregate string
4821 * of the values carried by this node child's (TEXT and ENTITY_REF).
4822 * Entity references are substituted.
4823 * Fills up the buffer @buffer with this value
4824 *
4825 * Returns 0 in case of success and -1 in case of error.
4826 */
4827int
4828xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4829{
4830 if ((cur == NULL) || (buffer == NULL)) return(-1);
4831 switch (cur->type) {
4832 case XML_CDATA_SECTION_NODE:
4833 case XML_TEXT_NODE:
4834 xmlBufferCat(buffer, cur->content);
4835 break;
4836 case XML_DOCUMENT_FRAG_NODE:
4837 case XML_ELEMENT_NODE:{
4838 xmlNodePtr tmp = cur;
4839
4840 while (tmp != NULL) {
4841 switch (tmp->type) {
4842 case XML_CDATA_SECTION_NODE:
4843 case XML_TEXT_NODE:
4844 if (tmp->content != NULL)
4845 xmlBufferCat(buffer, tmp->content);
4846 break;
4847 case XML_ENTITY_REF_NODE:
4848 xmlNodeBufGetContent(buffer, tmp->children);
4849 break;
4850 default:
4851 break;
4852 }
4853 /*
4854 * Skip to next node
4855 */
4856 if (tmp->children != NULL) {
4857 if (tmp->children->type != XML_ENTITY_DECL) {
4858 tmp = tmp->children;
4859 continue;
4860 }
4861 }
4862 if (tmp == cur)
4863 break;
4864
4865 if (tmp->next != NULL) {
4866 tmp = tmp->next;
4867 continue;
4868 }
4869
4870 do {
4871 tmp = tmp->parent;
4872 if (tmp == NULL)
4873 break;
4874 if (tmp == cur) {
4875 tmp = NULL;
4876 break;
4877 }
4878 if (tmp->next != NULL) {
4879 tmp = tmp->next;
4880 break;
4881 }
4882 } while (tmp != NULL);
4883 }
4884 break;
4885 }
4886 case XML_ATTRIBUTE_NODE:{
4887 xmlAttrPtr attr = (xmlAttrPtr) cur;
4888 xmlNodePtr tmp = attr->children;
4889
4890 while (tmp != NULL) {
4891 if (tmp->type == XML_TEXT_NODE)
4892 xmlBufferCat(buffer, tmp->content);
4893 else
4894 xmlNodeBufGetContent(buffer, tmp);
4895 tmp = tmp->next;
4896 }
4897 break;
4898 }
4899 case XML_COMMENT_NODE:
4900 case XML_PI_NODE:
4901 xmlBufferCat(buffer, cur->content);
4902 break;
4903 case XML_ENTITY_REF_NODE:{
4904 xmlEntityPtr ent;
4905 xmlNodePtr tmp;
4906
4907 /* lookup entity declaration */
4908 ent = xmlGetDocEntity(cur->doc, cur->name);
4909 if (ent == NULL)
4910 return(-1);
4911
4912 /* an entity content can be any "well balanced chunk",
4913 * i.e. the result of the content [43] production:
4914 * http://www.w3.org/TR/REC-xml#NT-content
4915 * -> we iterate through child nodes and recursive call
4916 * xmlNodeGetContent() which handles all possible node types */
4917 tmp = ent->children;
4918 while (tmp) {
4919 xmlNodeBufGetContent(buffer, tmp);
4920 tmp = tmp->next;
4921 }
4922 break;
4923 }
4924 case XML_ENTITY_NODE:
4925 case XML_DOCUMENT_TYPE_NODE:
4926 case XML_NOTATION_NODE:
4927 case XML_DTD_NODE:
4928 case XML_XINCLUDE_START:
4929 case XML_XINCLUDE_END:
4930 break;
4931 case XML_DOCUMENT_NODE:
4932#ifdef LIBXML_DOCB_ENABLED
4933 case XML_DOCB_DOCUMENT_NODE:
4934#endif
4935 case XML_HTML_DOCUMENT_NODE:
4936 cur = cur->children;
4937 while (cur!= NULL) {
4938 if ((cur->type == XML_ELEMENT_NODE) ||
4939 (cur->type == XML_TEXT_NODE) ||
4940 (cur->type == XML_CDATA_SECTION_NODE)) {
4941 xmlNodeBufGetContent(buffer, cur);
4942 }
4943 cur = cur->next;
4944 }
4945 break;
4946 case XML_NAMESPACE_DECL:
4947 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
4948 break;
4949 case XML_ELEMENT_DECL:
4950 case XML_ATTRIBUTE_DECL:
4951 case XML_ENTITY_DECL:
4952 break;
4953 }
4954 return(0);
4955}
4956/**
Owen Taylor3473f882001-02-23 17:55:21 +00004957 * xmlNodeGetContent:
4958 * @cur: the node being read
4959 *
4960 * Read the value of a node, this can be either the text carried
4961 * directly by this node if it's a TEXT node or the aggregate string
4962 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004963 * Entity references are substituted.
4964 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004965 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004966 */
4967xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004968xmlNodeGetContent(xmlNodePtr cur)
4969{
4970 if (cur == NULL)
4971 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004972 switch (cur->type) {
4973 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004974 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00004975 xmlBufferPtr buffer;
4976 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004977
Daniel Veillard814a76d2003-01-23 18:24:20 +00004978 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004979 if (buffer == NULL)
4980 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00004981 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004982 ret = buffer->content;
4983 buffer->content = NULL;
4984 xmlBufferFree(buffer);
4985 return (ret);
4986 }
4987 case XML_ATTRIBUTE_NODE:{
4988 xmlAttrPtr attr = (xmlAttrPtr) cur;
4989
4990 if (attr->parent != NULL)
4991 return (xmlNodeListGetString
4992 (attr->parent->doc, attr->children, 1));
4993 else
4994 return (xmlNodeListGetString(NULL, attr->children, 1));
4995 break;
4996 }
Owen Taylor3473f882001-02-23 17:55:21 +00004997 case XML_COMMENT_NODE:
4998 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004999 if (cur->content != NULL)
5000 return (xmlStrdup(cur->content));
5001 return (NULL);
5002 case XML_ENTITY_REF_NODE:{
5003 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00005004 xmlBufferPtr buffer;
5005 xmlChar *ret;
5006
5007 /* lookup entity declaration */
5008 ent = xmlGetDocEntity(cur->doc, cur->name);
5009 if (ent == NULL)
5010 return (NULL);
5011
5012 buffer = xmlBufferCreate();
5013 if (buffer == NULL)
5014 return (NULL);
5015
Daniel Veillardc4696922003-10-19 21:47:14 +00005016 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005017
5018 ret = buffer->content;
5019 buffer->content = NULL;
5020 xmlBufferFree(buffer);
5021 return (ret);
5022 }
Owen Taylor3473f882001-02-23 17:55:21 +00005023 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005024 case XML_DOCUMENT_TYPE_NODE:
5025 case XML_NOTATION_NODE:
5026 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005027 case XML_XINCLUDE_START:
5028 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00005029 return (NULL);
5030 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005031#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005032 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005033#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005034 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00005035 xmlBufferPtr buffer;
5036 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005037
Daniel Veillardc4696922003-10-19 21:47:14 +00005038 buffer = xmlBufferCreate();
5039 if (buffer == NULL)
5040 return (NULL);
5041
5042 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5043
5044 ret = buffer->content;
5045 buffer->content = NULL;
5046 xmlBufferFree(buffer);
5047 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005048 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005049 case XML_NAMESPACE_DECL: {
5050 xmlChar *tmp;
5051
5052 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5053 return (tmp);
5054 }
Owen Taylor3473f882001-02-23 17:55:21 +00005055 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005056 /* TODO !!! */
5057 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005058 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005059 /* TODO !!! */
5060 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005061 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005062 /* TODO !!! */
5063 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005064 case XML_CDATA_SECTION_NODE:
5065 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005066 if (cur->content != NULL)
5067 return (xmlStrdup(cur->content));
5068 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005069 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005070 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005071}
Daniel Veillard652327a2003-09-29 18:02:38 +00005072
Owen Taylor3473f882001-02-23 17:55:21 +00005073/**
5074 * xmlNodeSetContent:
5075 * @cur: the node being modified
5076 * @content: the new value of the content
5077 *
5078 * Replace the content of a node.
5079 */
5080void
5081xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5082 if (cur == NULL) {
5083#ifdef DEBUG_TREE
5084 xmlGenericError(xmlGenericErrorContext,
5085 "xmlNodeSetContent : node == NULL\n");
5086#endif
5087 return;
5088 }
5089 switch (cur->type) {
5090 case XML_DOCUMENT_FRAG_NODE:
5091 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005092 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005093 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5094 cur->children = xmlStringGetNodeList(cur->doc, content);
5095 UPDATE_LAST_CHILD_AND_PARENT(cur)
5096 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005097 case XML_TEXT_NODE:
5098 case XML_CDATA_SECTION_NODE:
5099 case XML_ENTITY_REF_NODE:
5100 case XML_ENTITY_NODE:
5101 case XML_PI_NODE:
5102 case XML_COMMENT_NODE:
5103 if (cur->content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005104 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
Daniel Veillardc587bce2005-05-10 15:28:08 +00005105 (xmlDictOwns(cur->doc->dict, cur->content))))
William M. Brack7762bb12004-01-04 14:49:01 +00005106 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005107 }
5108 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5109 cur->last = cur->children = NULL;
5110 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005111 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005112 } else
5113 cur->content = NULL;
5114 break;
5115 case XML_DOCUMENT_NODE:
5116 case XML_HTML_DOCUMENT_NODE:
5117 case XML_DOCUMENT_TYPE_NODE:
5118 case XML_XINCLUDE_START:
5119 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005120#ifdef LIBXML_DOCB_ENABLED
5121 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005122#endif
5123 break;
5124 case XML_NOTATION_NODE:
5125 break;
5126 case XML_DTD_NODE:
5127 break;
5128 case XML_NAMESPACE_DECL:
5129 break;
5130 case XML_ELEMENT_DECL:
5131 /* TODO !!! */
5132 break;
5133 case XML_ATTRIBUTE_DECL:
5134 /* TODO !!! */
5135 break;
5136 case XML_ENTITY_DECL:
5137 /* TODO !!! */
5138 break;
5139 }
5140}
5141
Daniel Veillard652327a2003-09-29 18:02:38 +00005142#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005143/**
5144 * xmlNodeSetContentLen:
5145 * @cur: the node being modified
5146 * @content: the new value of the content
5147 * @len: the size of @content
5148 *
5149 * Replace the content of a node.
5150 */
5151void
5152xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5153 if (cur == NULL) {
5154#ifdef DEBUG_TREE
5155 xmlGenericError(xmlGenericErrorContext,
5156 "xmlNodeSetContentLen : node == NULL\n");
5157#endif
5158 return;
5159 }
5160 switch (cur->type) {
5161 case XML_DOCUMENT_FRAG_NODE:
5162 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005163 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005164 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5165 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5166 UPDATE_LAST_CHILD_AND_PARENT(cur)
5167 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005168 case XML_TEXT_NODE:
5169 case XML_CDATA_SECTION_NODE:
5170 case XML_ENTITY_REF_NODE:
5171 case XML_ENTITY_NODE:
5172 case XML_PI_NODE:
5173 case XML_COMMENT_NODE:
5174 case XML_NOTATION_NODE:
5175 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005176 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005177 }
5178 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5179 cur->children = cur->last = NULL;
5180 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005181 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005182 } else
5183 cur->content = NULL;
5184 break;
5185 case XML_DOCUMENT_NODE:
5186 case XML_DTD_NODE:
5187 case XML_HTML_DOCUMENT_NODE:
5188 case XML_DOCUMENT_TYPE_NODE:
5189 case XML_NAMESPACE_DECL:
5190 case XML_XINCLUDE_START:
5191 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005192#ifdef LIBXML_DOCB_ENABLED
5193 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005194#endif
5195 break;
5196 case XML_ELEMENT_DECL:
5197 /* TODO !!! */
5198 break;
5199 case XML_ATTRIBUTE_DECL:
5200 /* TODO !!! */
5201 break;
5202 case XML_ENTITY_DECL:
5203 /* TODO !!! */
5204 break;
5205 }
5206}
Daniel Veillard652327a2003-09-29 18:02:38 +00005207#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005208
5209/**
5210 * xmlNodeAddContentLen:
5211 * @cur: the node being modified
5212 * @content: extra content
5213 * @len: the size of @content
5214 *
5215 * Append the extra substring to the node content.
5216 */
5217void
5218xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5219 if (cur == NULL) {
5220#ifdef DEBUG_TREE
5221 xmlGenericError(xmlGenericErrorContext,
5222 "xmlNodeAddContentLen : node == NULL\n");
5223#endif
5224 return;
5225 }
5226 if (len <= 0) return;
5227 switch (cur->type) {
5228 case XML_DOCUMENT_FRAG_NODE:
5229 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005230 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005231
Daniel Veillard7db37732001-07-12 01:20:08 +00005232 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005233 newNode = xmlNewTextLen(content, len);
5234 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005235 tmp = xmlAddChild(cur, newNode);
5236 if (tmp != newNode)
5237 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005238 if ((last != NULL) && (last->next == newNode)) {
5239 xmlTextMerge(last, newNode);
5240 }
5241 }
5242 break;
5243 }
5244 case XML_ATTRIBUTE_NODE:
5245 break;
5246 case XML_TEXT_NODE:
5247 case XML_CDATA_SECTION_NODE:
5248 case XML_ENTITY_REF_NODE:
5249 case XML_ENTITY_NODE:
5250 case XML_PI_NODE:
5251 case XML_COMMENT_NODE:
5252 case XML_NOTATION_NODE:
5253 if (content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005254 if ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5255 xmlDictOwns(cur->doc->dict, cur->content)) {
5256 cur->content =
5257 xmlStrncatNew(cur->content, content, len);
5258 break;
5259 }
Owen Taylor3473f882001-02-23 17:55:21 +00005260 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005261 }
5262 case XML_DOCUMENT_NODE:
5263 case XML_DTD_NODE:
5264 case XML_HTML_DOCUMENT_NODE:
5265 case XML_DOCUMENT_TYPE_NODE:
5266 case XML_NAMESPACE_DECL:
5267 case XML_XINCLUDE_START:
5268 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005269#ifdef LIBXML_DOCB_ENABLED
5270 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005271#endif
5272 break;
5273 case XML_ELEMENT_DECL:
5274 case XML_ATTRIBUTE_DECL:
5275 case XML_ENTITY_DECL:
5276 break;
5277 }
5278}
5279
5280/**
5281 * xmlNodeAddContent:
5282 * @cur: the node being modified
5283 * @content: extra content
5284 *
5285 * Append the extra substring to the node content.
5286 */
5287void
5288xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5289 int len;
5290
5291 if (cur == NULL) {
5292#ifdef DEBUG_TREE
5293 xmlGenericError(xmlGenericErrorContext,
5294 "xmlNodeAddContent : node == NULL\n");
5295#endif
5296 return;
5297 }
5298 if (content == NULL) return;
5299 len = xmlStrlen(content);
5300 xmlNodeAddContentLen(cur, content, len);
5301}
5302
5303/**
5304 * xmlTextMerge:
5305 * @first: the first text node
5306 * @second: the second text node being merged
5307 *
5308 * Merge two text nodes into one
5309 * Returns the first text node augmented
5310 */
5311xmlNodePtr
5312xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5313 if (first == NULL) return(second);
5314 if (second == NULL) return(first);
5315 if (first->type != XML_TEXT_NODE) return(first);
5316 if (second->type != XML_TEXT_NODE) return(first);
5317 if (second->name != first->name)
5318 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005319 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005320 xmlUnlinkNode(second);
5321 xmlFreeNode(second);
5322 return(first);
5323}
5324
Daniel Veillard2156d432004-03-04 15:59:36 +00005325#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005326/**
5327 * xmlGetNsList:
5328 * @doc: the document
5329 * @node: the current node
5330 *
5331 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005332 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005333 * that need to be freed by the caller or NULL if no
5334 * namespace if defined
5335 */
5336xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005337xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5338{
Owen Taylor3473f882001-02-23 17:55:21 +00005339 xmlNsPtr cur;
5340 xmlNsPtr *ret = NULL;
5341 int nbns = 0;
5342 int maxns = 10;
5343 int i;
5344
5345 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005346 if (node->type == XML_ELEMENT_NODE) {
5347 cur = node->nsDef;
5348 while (cur != NULL) {
5349 if (ret == NULL) {
5350 ret =
5351 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5352 sizeof(xmlNsPtr));
5353 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005354 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005355 return (NULL);
5356 }
5357 ret[nbns] = NULL;
5358 }
5359 for (i = 0; i < nbns; i++) {
5360 if ((cur->prefix == ret[i]->prefix) ||
5361 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5362 break;
5363 }
5364 if (i >= nbns) {
5365 if (nbns >= maxns) {
5366 maxns *= 2;
5367 ret = (xmlNsPtr *) xmlRealloc(ret,
5368 (maxns +
5369 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 }
5376 ret[nbns++] = cur;
5377 ret[nbns] = NULL;
5378 }
Owen Taylor3473f882001-02-23 17:55:21 +00005379
Daniel Veillard77044732001-06-29 21:31:07 +00005380 cur = cur->next;
5381 }
5382 }
5383 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005384 }
Daniel Veillard77044732001-06-29 21:31:07 +00005385 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005386}
Daniel Veillard652327a2003-09-29 18:02:38 +00005387#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005388
5389/**
5390 * xmlSearchNs:
5391 * @doc: the document
5392 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005393 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005394 *
5395 * Search a Ns registered under a given name space for a document.
5396 * recurse on the parents until it finds the defined namespace
5397 * or return NULL otherwise.
5398 * @nameSpace can be NULL, this is a search for the default namespace.
5399 * We don't allow to cross entities boundaries. If you don't declare
5400 * the namespace within those you will be in troubles !!! A warning
5401 * is generated to cover this case.
5402 *
5403 * Returns the namespace pointer or NULL.
5404 */
5405xmlNsPtr
5406xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005407
Owen Taylor3473f882001-02-23 17:55:21 +00005408 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005409 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005410
5411 if (node == NULL) return(NULL);
5412 if ((nameSpace != NULL) &&
5413 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005414 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5415 /*
5416 * The XML-1.0 namespace is normally held on the root
5417 * element. In this case exceptionally create it on the
5418 * node element.
5419 */
5420 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5421 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005422 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005423 return(NULL);
5424 }
5425 memset(cur, 0, sizeof(xmlNs));
5426 cur->type = XML_LOCAL_NAMESPACE;
5427 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5428 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5429 cur->next = node->nsDef;
5430 node->nsDef = cur;
5431 return(cur);
5432 }
Owen Taylor3473f882001-02-23 17:55:21 +00005433 if (doc->oldNs == NULL) {
5434 /*
5435 * Allocate a new Namespace and fill the fields.
5436 */
5437 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5438 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005439 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005440 return(NULL);
5441 }
5442 memset(doc->oldNs, 0, sizeof(xmlNs));
5443 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5444
5445 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5446 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5447 }
5448 return(doc->oldNs);
5449 }
5450 while (node != NULL) {
5451 if ((node->type == XML_ENTITY_REF_NODE) ||
5452 (node->type == XML_ENTITY_NODE) ||
5453 (node->type == XML_ENTITY_DECL))
5454 return(NULL);
5455 if (node->type == XML_ELEMENT_NODE) {
5456 cur = node->nsDef;
5457 while (cur != NULL) {
5458 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5459 (cur->href != NULL))
5460 return(cur);
5461 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5462 (cur->href != NULL) &&
5463 (xmlStrEqual(cur->prefix, nameSpace)))
5464 return(cur);
5465 cur = cur->next;
5466 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005467 if (orig != node) {
5468 cur = node->ns;
5469 if (cur != NULL) {
5470 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5471 (cur->href != NULL))
5472 return(cur);
5473 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5474 (cur->href != NULL) &&
5475 (xmlStrEqual(cur->prefix, nameSpace)))
5476 return(cur);
5477 }
5478 }
Owen Taylor3473f882001-02-23 17:55:21 +00005479 }
5480 node = node->parent;
5481 }
5482 return(NULL);
5483}
5484
5485/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005486 * xmlNsInScope:
5487 * @doc: the document
5488 * @node: the current node
5489 * @ancestor: the ancestor carrying the namespace
5490 * @prefix: the namespace prefix
5491 *
5492 * Verify that the given namespace held on @ancestor is still in scope
5493 * on node.
5494 *
5495 * Returns 1 if true, 0 if false and -1 in case of error.
5496 */
5497static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005498xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5499 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005500{
5501 xmlNsPtr tst;
5502
5503 while ((node != NULL) && (node != ancestor)) {
5504 if ((node->type == XML_ENTITY_REF_NODE) ||
5505 (node->type == XML_ENTITY_NODE) ||
5506 (node->type == XML_ENTITY_DECL))
5507 return (-1);
5508 if (node->type == XML_ELEMENT_NODE) {
5509 tst = node->nsDef;
5510 while (tst != NULL) {
5511 if ((tst->prefix == NULL)
5512 && (prefix == NULL))
5513 return (0);
5514 if ((tst->prefix != NULL)
5515 && (prefix != NULL)
5516 && (xmlStrEqual(tst->prefix, prefix)))
5517 return (0);
5518 tst = tst->next;
5519 }
5520 }
5521 node = node->parent;
5522 }
5523 if (node != ancestor)
5524 return (-1);
5525 return (1);
5526}
5527
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005528/**
Owen Taylor3473f882001-02-23 17:55:21 +00005529 * xmlSearchNsByHref:
5530 * @doc: the document
5531 * @node: the current node
5532 * @href: the namespace value
5533 *
5534 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5535 * the defined namespace or return NULL otherwise.
5536 * Returns the namespace pointer or NULL.
5537 */
5538xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005539xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5540{
Owen Taylor3473f882001-02-23 17:55:21 +00005541 xmlNsPtr cur;
5542 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005543 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005544
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005545 if ((node == NULL) || (href == NULL))
5546 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005547 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005548 /*
5549 * Only the document can hold the XML spec namespace.
5550 */
5551 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5552 /*
5553 * The XML-1.0 namespace is normally held on the root
5554 * element. In this case exceptionally create it on the
5555 * node element.
5556 */
5557 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5558 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005559 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005560 return (NULL);
5561 }
5562 memset(cur, 0, sizeof(xmlNs));
5563 cur->type = XML_LOCAL_NAMESPACE;
5564 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5565 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5566 cur->next = node->nsDef;
5567 node->nsDef = cur;
5568 return (cur);
5569 }
5570 if (doc->oldNs == NULL) {
5571 /*
5572 * Allocate a new Namespace and fill the fields.
5573 */
5574 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5575 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005576 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005577 return (NULL);
5578 }
5579 memset(doc->oldNs, 0, sizeof(xmlNs));
5580 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005581
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005582 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5583 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5584 }
5585 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005586 }
Daniel Veillard62040be2004-05-17 03:17:26 +00005587 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00005588 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005589 if ((node->type == XML_ENTITY_REF_NODE) ||
5590 (node->type == XML_ENTITY_NODE) ||
5591 (node->type == XML_ENTITY_DECL))
5592 return (NULL);
5593 if (node->type == XML_ELEMENT_NODE) {
5594 cur = node->nsDef;
5595 while (cur != NULL) {
5596 if ((cur->href != NULL) && (href != NULL) &&
5597 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005598 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00005599 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005600 return (cur);
5601 }
5602 cur = cur->next;
5603 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005604 if (orig != node) {
5605 cur = node->ns;
5606 if (cur != NULL) {
5607 if ((cur->href != NULL) && (href != NULL) &&
5608 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005609 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00005610 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00005611 return (cur);
5612 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005613 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005614 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005615 }
5616 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005617 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005618 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005619}
5620
5621/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005622 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005623 * @doc: the document
5624 * @tree: a node expected to hold the new namespace
5625 * @ns: the original namespace
5626 *
5627 * This function tries to locate a namespace definition in a tree
5628 * ancestors, or create a new namespace definition node similar to
5629 * @ns trying to reuse the same prefix. However if the given prefix is
5630 * null (default namespace) or reused within the subtree defined by
5631 * @tree or on one of its ancestors then a new prefix is generated.
5632 * Returns the (new) namespace definition or NULL in case of error
5633 */
5634xmlNsPtr
5635xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5636 xmlNsPtr def;
5637 xmlChar prefix[50];
5638 int counter = 1;
5639
5640 if (tree == NULL) {
5641#ifdef DEBUG_TREE
5642 xmlGenericError(xmlGenericErrorContext,
5643 "xmlNewReconciliedNs : tree == NULL\n");
5644#endif
5645 return(NULL);
5646 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00005647 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005648#ifdef DEBUG_TREE
5649 xmlGenericError(xmlGenericErrorContext,
5650 "xmlNewReconciliedNs : ns == NULL\n");
5651#endif
5652 return(NULL);
5653 }
5654 /*
5655 * Search an existing namespace definition inherited.
5656 */
5657 def = xmlSearchNsByHref(doc, tree, ns->href);
5658 if (def != NULL)
5659 return(def);
5660
5661 /*
5662 * Find a close prefix which is not already in use.
5663 * Let's strip namespace prefixes longer than 20 chars !
5664 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005665 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005666 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005667 else
William M. Brack13dfa872004-09-18 04:52:08 +00005668 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005669
Owen Taylor3473f882001-02-23 17:55:21 +00005670 def = xmlSearchNs(doc, tree, prefix);
5671 while (def != NULL) {
5672 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005673 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005674 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005675 else
William M. Brack13dfa872004-09-18 04:52:08 +00005676 snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
5677 (char *)ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005678 def = xmlSearchNs(doc, tree, prefix);
5679 }
5680
5681 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005682 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005683 */
5684 def = xmlNewNs(tree, ns->href, prefix);
5685 return(def);
5686}
5687
Daniel Veillard652327a2003-09-29 18:02:38 +00005688#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005689/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005690 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005691 * @doc: the document
5692 * @tree: a node defining the subtree to reconciliate
5693 *
5694 * This function checks that all the namespaces declared within the given
5695 * tree are properly declared. This is needed for example after Copy or Cut
5696 * and then paste operations. The subtree may still hold pointers to
5697 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005698 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005699 * the new environment. If not possible the new namespaces are redeclared
5700 * on @tree at the top of the given subtree.
5701 * Returns the number of namespace declarations created or -1 in case of error.
5702 */
5703int
5704xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5705 xmlNsPtr *oldNs = NULL;
5706 xmlNsPtr *newNs = NULL;
5707 int sizeCache = 0;
5708 int nbCache = 0;
5709
5710 xmlNsPtr n;
5711 xmlNodePtr node = tree;
5712 xmlAttrPtr attr;
5713 int ret = 0, i;
5714
Daniel Veillardce244ad2004-11-05 10:03:46 +00005715 if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1);
5716 if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1);
5717 if (node->doc != doc) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005718 while (node != NULL) {
5719 /*
5720 * Reconciliate the node namespace
5721 */
5722 if (node->ns != NULL) {
5723 /*
5724 * initialize the cache if needed
5725 */
5726 if (sizeCache == 0) {
5727 sizeCache = 10;
5728 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5729 sizeof(xmlNsPtr));
5730 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005731 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005732 return(-1);
5733 }
5734 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5735 sizeof(xmlNsPtr));
5736 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005737 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005738 xmlFree(oldNs);
5739 return(-1);
5740 }
5741 }
5742 for (i = 0;i < nbCache;i++) {
5743 if (oldNs[i] == node->ns) {
5744 node->ns = newNs[i];
5745 break;
5746 }
5747 }
5748 if (i == nbCache) {
5749 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005750 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005751 */
5752 n = xmlNewReconciliedNs(doc, tree, node->ns);
5753 if (n != NULL) { /* :-( what if else ??? */
5754 /*
5755 * check if we need to grow the cache buffers.
5756 */
5757 if (sizeCache <= nbCache) {
5758 sizeCache *= 2;
5759 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5760 sizeof(xmlNsPtr));
5761 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005762 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005763 xmlFree(newNs);
5764 return(-1);
5765 }
5766 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5767 sizeof(xmlNsPtr));
5768 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005769 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005770 xmlFree(oldNs);
5771 return(-1);
5772 }
5773 }
5774 newNs[nbCache] = n;
5775 oldNs[nbCache++] = node->ns;
5776 node->ns = n;
5777 }
5778 }
5779 }
5780 /*
5781 * now check for namespace hold by attributes on the node.
5782 */
5783 attr = node->properties;
5784 while (attr != NULL) {
5785 if (attr->ns != NULL) {
5786 /*
5787 * initialize the cache if needed
5788 */
5789 if (sizeCache == 0) {
5790 sizeCache = 10;
5791 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5792 sizeof(xmlNsPtr));
5793 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005794 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005795 return(-1);
5796 }
5797 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5798 sizeof(xmlNsPtr));
5799 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005800 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005801 xmlFree(oldNs);
5802 return(-1);
5803 }
5804 }
5805 for (i = 0;i < nbCache;i++) {
5806 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005807 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005808 break;
5809 }
5810 }
5811 if (i == nbCache) {
5812 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005813 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005814 */
5815 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5816 if (n != NULL) { /* :-( what if else ??? */
5817 /*
5818 * check if we need to grow the cache buffers.
5819 */
5820 if (sizeCache <= nbCache) {
5821 sizeCache *= 2;
5822 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5823 sizeof(xmlNsPtr));
5824 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005825 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005826 xmlFree(newNs);
5827 return(-1);
5828 }
5829 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5830 sizeof(xmlNsPtr));
5831 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005832 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005833 xmlFree(oldNs);
5834 return(-1);
5835 }
5836 }
5837 newNs[nbCache] = n;
5838 oldNs[nbCache++] = attr->ns;
5839 attr->ns = n;
5840 }
5841 }
5842 }
5843 attr = attr->next;
5844 }
5845
5846 /*
5847 * Browse the full subtree, deep first
5848 */
Daniel Veillardac996a12004-07-30 12:02:58 +00005849 if (node->children != NULL && node->type != XML_ENTITY_REF_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00005850 /* deep first */
5851 node = node->children;
5852 } else if ((node != tree) && (node->next != NULL)) {
5853 /* then siblings */
5854 node = node->next;
5855 } else if (node != tree) {
5856 /* go up to parents->next if needed */
5857 while (node != tree) {
5858 if (node->parent != NULL)
5859 node = node->parent;
5860 if ((node != tree) && (node->next != NULL)) {
5861 node = node->next;
5862 break;
5863 }
5864 if (node->parent == NULL) {
5865 node = NULL;
5866 break;
5867 }
5868 }
5869 /* exit condition */
5870 if (node == tree)
5871 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005872 } else
5873 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005874 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005875 if (oldNs != NULL)
5876 xmlFree(oldNs);
5877 if (newNs != NULL)
5878 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005879 return(ret);
5880}
Daniel Veillard652327a2003-09-29 18:02:38 +00005881#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005882
5883/**
5884 * xmlHasProp:
5885 * @node: the node
5886 * @name: the attribute name
5887 *
5888 * Search an attribute associated to a node
5889 * This function also looks in DTD attribute declaration for #FIXED or
5890 * default declaration values unless DTD use has been turned off.
5891 *
5892 * Returns the attribute or the attribute declaration or NULL if
5893 * neither was found.
5894 */
5895xmlAttrPtr
5896xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5897 xmlAttrPtr prop;
5898 xmlDocPtr doc;
5899
5900 if ((node == NULL) || (name == NULL)) return(NULL);
5901 /*
5902 * Check on the properties attached to the node
5903 */
5904 prop = node->properties;
5905 while (prop != NULL) {
5906 if (xmlStrEqual(prop->name, name)) {
5907 return(prop);
5908 }
5909 prop = prop->next;
5910 }
5911 if (!xmlCheckDTD) return(NULL);
5912
5913 /*
5914 * Check if there is a default declaration in the internal
5915 * or external subsets
5916 */
5917 doc = node->doc;
5918 if (doc != NULL) {
5919 xmlAttributePtr attrDecl;
5920 if (doc->intSubset != NULL) {
5921 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5922 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5923 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005924 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5925 /* return attribute declaration only if a default value is given
5926 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005927 return((xmlAttrPtr) attrDecl);
5928 }
5929 }
5930 return(NULL);
5931}
5932
5933/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005934 * xmlHasNsProp:
5935 * @node: the node
5936 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005937 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005938 *
5939 * Search for an attribute associated to a node
5940 * This attribute has to be anchored in the namespace specified.
5941 * This does the entity substitution.
5942 * This function looks in DTD attribute declaration for #FIXED or
5943 * default declaration values unless DTD use has been turned off.
William M. Brack2c228442004-10-03 04:10:00 +00005944 * Note that a namespace of NULL indicates to use the default namespace.
Daniel Veillarde95e2392001-06-06 10:46:28 +00005945 *
5946 * Returns the attribute or the attribute declaration or NULL
5947 * if neither was found.
5948 */
5949xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005950xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005951 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00005952#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005953 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00005954#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005955
5956 if (node == NULL)
5957 return(NULL);
5958
5959 prop = node->properties;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005960 while (prop != NULL) {
5961 /*
5962 * One need to have
5963 * - same attribute names
5964 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005965 */
William M. Brack2c228442004-10-03 04:10:00 +00005966 if (xmlStrEqual(prop->name, name)) {
5967 if (((prop->ns != NULL) &&
5968 (xmlStrEqual(prop->ns->href, nameSpace))) ||
5969 ((prop->ns == NULL) && (nameSpace == NULL))) {
5970 return(prop);
5971 }
Daniel Veillarde95e2392001-06-06 10:46:28 +00005972 }
5973 prop = prop->next;
5974 }
5975 if (!xmlCheckDTD) return(NULL);
5976
Daniel Veillard652327a2003-09-29 18:02:38 +00005977#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005978 /*
5979 * Check if there is a default declaration in the internal
5980 * or external subsets
5981 */
5982 doc = node->doc;
5983 if (doc != NULL) {
5984 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005985 xmlAttributePtr attrDecl = NULL;
5986 xmlNsPtr *nsList, *cur;
5987 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005988
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005989 nsList = xmlGetNsList(node->doc, node);
5990 if (nsList == NULL)
5991 return(NULL);
5992 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5993 ename = xmlStrdup(node->ns->prefix);
5994 ename = xmlStrcat(ename, BAD_CAST ":");
5995 ename = xmlStrcat(ename, node->name);
5996 } else {
5997 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005998 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005999 if (ename == NULL) {
6000 xmlFree(nsList);
6001 return(NULL);
6002 }
6003
William M. Brack2c228442004-10-03 04:10:00 +00006004 if (nameSpace == NULL) {
6005 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
6006 name, NULL);
6007 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
6008 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6009 name, NULL);
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006010 }
William M. Brack2c228442004-10-03 04:10:00 +00006011 } else {
6012 cur = nsList;
6013 while (*cur != NULL) {
6014 if (xmlStrEqual((*cur)->href, nameSpace)) {
6015 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
6016 name, (*cur)->prefix);
6017 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6018 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6019 name, (*cur)->prefix);
6020 }
6021 cur++;
6022 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006023 }
6024 xmlFree(nsList);
6025 xmlFree(ename);
6026 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006027 }
6028 }
Daniel Veillard652327a2003-09-29 18:02:38 +00006029#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00006030 return(NULL);
6031}
6032
6033/**
Owen Taylor3473f882001-02-23 17:55:21 +00006034 * xmlGetProp:
6035 * @node: the node
6036 * @name: the attribute name
6037 *
6038 * Search and get the value of an attribute associated to a node
6039 * This does the entity substitution.
6040 * This function looks in DTD attribute declaration for #FIXED or
6041 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00006042 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00006043 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6044 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00006045 *
6046 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006047 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006048 */
6049xmlChar *
6050xmlGetProp(xmlNodePtr node, const xmlChar *name) {
6051 xmlAttrPtr prop;
6052 xmlDocPtr doc;
6053
6054 if ((node == NULL) || (name == NULL)) return(NULL);
6055 /*
6056 * Check on the properties attached to the node
6057 */
6058 prop = node->properties;
6059 while (prop != NULL) {
6060 if (xmlStrEqual(prop->name, name)) {
6061 xmlChar *ret;
6062
6063 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6064 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6065 return(ret);
6066 }
6067 prop = prop->next;
6068 }
6069 if (!xmlCheckDTD) return(NULL);
6070
6071 /*
6072 * Check if there is a default declaration in the internal
6073 * or external subsets
6074 */
6075 doc = node->doc;
6076 if (doc != NULL) {
6077 xmlAttributePtr attrDecl;
6078 if (doc->intSubset != NULL) {
6079 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6080 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6081 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006082 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6083 /* return attribute declaration only if a default value is given
6084 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006085 return(xmlStrdup(attrDecl->defaultValue));
6086 }
6087 }
6088 return(NULL);
6089}
6090
6091/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006092 * xmlGetNoNsProp:
6093 * @node: the node
6094 * @name: the attribute name
6095 *
6096 * Search and get the value of an attribute associated to a node
6097 * This does the entity substitution.
6098 * This function looks in DTD attribute declaration for #FIXED or
6099 * default declaration values unless DTD use has been turned off.
6100 * This function is similar to xmlGetProp except it will accept only
6101 * an attribute in no namespace.
6102 *
6103 * Returns the attribute value or NULL if not found.
6104 * It's up to the caller to free the memory with xmlFree().
6105 */
6106xmlChar *
6107xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6108 xmlAttrPtr prop;
6109 xmlDocPtr doc;
6110
6111 if ((node == NULL) || (name == NULL)) return(NULL);
6112 /*
6113 * Check on the properties attached to the node
6114 */
6115 prop = node->properties;
6116 while (prop != NULL) {
6117 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6118 xmlChar *ret;
6119
6120 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6121 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6122 return(ret);
6123 }
6124 prop = prop->next;
6125 }
6126 if (!xmlCheckDTD) return(NULL);
6127
6128 /*
6129 * Check if there is a default declaration in the internal
6130 * or external subsets
6131 */
6132 doc = node->doc;
6133 if (doc != NULL) {
6134 xmlAttributePtr attrDecl;
6135 if (doc->intSubset != NULL) {
6136 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6137 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6138 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006139 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6140 /* return attribute declaration only if a default value is given
6141 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006142 return(xmlStrdup(attrDecl->defaultValue));
6143 }
6144 }
6145 return(NULL);
6146}
6147
6148/**
Owen Taylor3473f882001-02-23 17:55:21 +00006149 * xmlGetNsProp:
6150 * @node: the node
6151 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006152 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006153 *
6154 * Search and get the value of an attribute associated to a node
6155 * This attribute has to be anchored in the namespace specified.
6156 * This does the entity substitution.
6157 * This function looks in DTD attribute declaration for #FIXED or
6158 * default declaration values unless DTD use has been turned off.
6159 *
6160 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006161 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006162 */
6163xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006164xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006165 xmlAttrPtr prop;
6166 xmlDocPtr doc;
6167 xmlNsPtr ns;
6168
6169 if (node == NULL)
6170 return(NULL);
6171
6172 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006173 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006174 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006175 while (prop != NULL) {
6176 /*
6177 * One need to have
6178 * - same attribute names
6179 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006180 */
6181 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006182 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006183 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006184 xmlChar *ret;
6185
6186 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6187 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6188 return(ret);
6189 }
6190 prop = prop->next;
6191 }
6192 if (!xmlCheckDTD) return(NULL);
6193
6194 /*
6195 * Check if there is a default declaration in the internal
6196 * or external subsets
6197 */
6198 doc = node->doc;
6199 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006200 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006201 xmlAttributePtr attrDecl;
6202
Owen Taylor3473f882001-02-23 17:55:21 +00006203 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6204 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6205 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6206
6207 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6208 /*
6209 * The DTD declaration only allows a prefix search
6210 */
6211 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006212 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006213 return(xmlStrdup(attrDecl->defaultValue));
6214 }
6215 }
6216 }
6217 return(NULL);
6218}
6219
Daniel Veillard2156d432004-03-04 15:59:36 +00006220#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6221/**
6222 * xmlUnsetProp:
6223 * @node: the node
6224 * @name: the attribute name
6225 *
6226 * Remove an attribute carried by a node.
6227 * Returns 0 if successful, -1 if not found
6228 */
6229int
6230xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
6231 xmlAttrPtr prop, prev = NULL;;
6232
6233 if ((node == NULL) || (name == NULL))
6234 return(-1);
6235 prop = node->properties;
6236 while (prop != NULL) {
6237 if ((xmlStrEqual(prop->name, name)) &&
6238 (prop->ns == NULL)) {
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00006239 xmlUnlinkNode((xmlNodePtr) prop);
Daniel Veillard2156d432004-03-04 15:59:36 +00006240 xmlFreeProp(prop);
6241 return(0);
6242 }
6243 prev = prop;
6244 prop = prop->next;
6245 }
6246 return(-1);
6247}
6248
6249/**
6250 * xmlUnsetNsProp:
6251 * @node: the node
6252 * @ns: the namespace definition
6253 * @name: the attribute name
6254 *
6255 * Remove an attribute carried by a node.
6256 * Returns 0 if successful, -1 if not found
6257 */
6258int
6259xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
Daniel Veillard27f20102004-11-05 11:50:11 +00006260 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard2156d432004-03-04 15:59:36 +00006261
6262 if ((node == NULL) || (name == NULL))
6263 return(-1);
Daniel Veillard27f20102004-11-05 11:50:11 +00006264 prop = node->properties;
Daniel Veillard2156d432004-03-04 15:59:36 +00006265 if (ns == NULL)
6266 return(xmlUnsetProp(node, name));
6267 if (ns->href == NULL)
6268 return(-1);
6269 while (prop != NULL) {
6270 if ((xmlStrEqual(prop->name, name)) &&
6271 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00006272 xmlUnlinkNode((xmlNodePtr) prop);
Daniel Veillard2156d432004-03-04 15:59:36 +00006273 xmlFreeProp(prop);
6274 return(0);
6275 }
6276 prev = prop;
6277 prop = prop->next;
6278 }
6279 return(-1);
6280}
6281#endif
6282
6283#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006284/**
6285 * xmlSetProp:
6286 * @node: the node
6287 * @name: the attribute name
6288 * @value: the attribute value
6289 *
6290 * Set (or reset) an attribute carried by a node.
6291 * Returns the attribute pointer.
6292 */
6293xmlAttrPtr
6294xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006295 xmlAttrPtr prop;
6296 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006297
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006298 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006299 return(NULL);
6300 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006301 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006302 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006303 if ((xmlStrEqual(prop->name, name)) &&
6304 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006305 xmlNodePtr oldprop = prop->children;
6306
Owen Taylor3473f882001-02-23 17:55:21 +00006307 prop->children = NULL;
6308 prop->last = NULL;
6309 if (value != NULL) {
6310 xmlChar *buffer;
6311 xmlNodePtr tmp;
6312
6313 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6314 prop->children = xmlStringGetNodeList(node->doc, buffer);
6315 prop->last = NULL;
6316 prop->doc = doc;
6317 tmp = prop->children;
6318 while (tmp != NULL) {
6319 tmp->parent = (xmlNodePtr) prop;
6320 tmp->doc = doc;
6321 if (tmp->next == NULL)
6322 prop->last = tmp;
6323 tmp = tmp->next;
6324 }
6325 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006326 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006327 if (oldprop != NULL)
6328 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006329 return(prop);
6330 }
6331 prop = prop->next;
6332 }
6333 prop = xmlNewProp(node, name, value);
6334 return(prop);
6335}
6336
6337/**
6338 * xmlSetNsProp:
6339 * @node: the node
6340 * @ns: the namespace definition
6341 * @name: the attribute name
6342 * @value: the attribute value
6343 *
6344 * Set (or reset) an attribute carried by a node.
6345 * The ns structure must be in scope, this is not checked.
6346 *
6347 * Returns the attribute pointer.
6348 */
6349xmlAttrPtr
6350xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6351 const xmlChar *value) {
6352 xmlAttrPtr prop;
6353
Daniel Veillardb6b36d32005-02-09 16:48:53 +00006354 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006355 return(NULL);
6356
6357 if (ns == NULL)
6358 return(xmlSetProp(node, name, value));
6359 if (ns->href == NULL)
6360 return(NULL);
6361 prop = node->properties;
6362
6363 while (prop != NULL) {
6364 /*
6365 * One need to have
6366 * - same attribute names
6367 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006368 */
6369 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006370 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006371 if (prop->children != NULL)
6372 xmlFreeNodeList(prop->children);
6373 prop->children = NULL;
6374 prop->last = NULL;
6375 prop->ns = ns;
6376 if (value != NULL) {
6377 xmlChar *buffer;
6378 xmlNodePtr tmp;
6379
6380 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6381 prop->children = xmlStringGetNodeList(node->doc, buffer);
6382 prop->last = NULL;
6383 tmp = prop->children;
6384 while (tmp != NULL) {
6385 tmp->parent = (xmlNodePtr) prop;
6386 if (tmp->next == NULL)
6387 prop->last = tmp;
6388 tmp = tmp->next;
6389 }
6390 xmlFree(buffer);
6391 }
6392 return(prop);
6393 }
6394 prop = prop->next;
6395 }
6396 prop = xmlNewNsProp(node, ns, name, value);
6397 return(prop);
6398}
6399
Daniel Veillard652327a2003-09-29 18:02:38 +00006400#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006401
6402/**
Owen Taylor3473f882001-02-23 17:55:21 +00006403 * xmlNodeIsText:
6404 * @node: the node
6405 *
6406 * Is this node a Text node ?
6407 * Returns 1 yes, 0 no
6408 */
6409int
6410xmlNodeIsText(xmlNodePtr node) {
6411 if (node == NULL) return(0);
6412
6413 if (node->type == XML_TEXT_NODE) return(1);
6414 return(0);
6415}
6416
6417/**
6418 * xmlIsBlankNode:
6419 * @node: the node
6420 *
6421 * Checks whether this node is an empty or whitespace only
6422 * (and possibly ignorable) text-node.
6423 *
6424 * Returns 1 yes, 0 no
6425 */
6426int
6427xmlIsBlankNode(xmlNodePtr node) {
6428 const xmlChar *cur;
6429 if (node == NULL) return(0);
6430
Daniel Veillard7db37732001-07-12 01:20:08 +00006431 if ((node->type != XML_TEXT_NODE) &&
6432 (node->type != XML_CDATA_SECTION_NODE))
6433 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006434 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006435 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006436 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006437 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006438 cur++;
6439 }
6440
6441 return(1);
6442}
6443
6444/**
6445 * xmlTextConcat:
6446 * @node: the node
6447 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006448 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006449 *
6450 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006451 *
6452 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006453 */
6454
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006455int
Owen Taylor3473f882001-02-23 17:55:21 +00006456xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006457 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006458
6459 if ((node->type != XML_TEXT_NODE) &&
6460 (node->type != XML_CDATA_SECTION_NODE)) {
6461#ifdef DEBUG_TREE
6462 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006463 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006464#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006465 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006466 }
William M. Brack7762bb12004-01-04 14:49:01 +00006467 /* need to check if content is currently in the dictionary */
6468 if ((node->doc != NULL) && (node->doc->dict != NULL) &&
6469 xmlDictOwns(node->doc->dict, node->content)) {
6470 node->content = xmlStrncatNew(node->content, content, len);
6471 } else {
6472 node->content = xmlStrncat(node->content, content, len);
6473 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006474 if (node->content == NULL)
6475 return(-1);
6476 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006477}
6478
6479/************************************************************************
6480 * *
6481 * Output : to a FILE or in memory *
6482 * *
6483 ************************************************************************/
6484
Owen Taylor3473f882001-02-23 17:55:21 +00006485/**
6486 * xmlBufferCreate:
6487 *
6488 * routine to create an XML buffer.
6489 * returns the new structure.
6490 */
6491xmlBufferPtr
6492xmlBufferCreate(void) {
6493 xmlBufferPtr ret;
6494
6495 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6496 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006497 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006498 return(NULL);
6499 }
6500 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006501 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006502 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006503 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006504 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006505 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006506 xmlFree(ret);
6507 return(NULL);
6508 }
6509 ret->content[0] = 0;
6510 return(ret);
6511}
6512
6513/**
6514 * xmlBufferCreateSize:
6515 * @size: initial size of buffer
6516 *
6517 * routine to create an XML buffer.
6518 * returns the new structure.
6519 */
6520xmlBufferPtr
6521xmlBufferCreateSize(size_t size) {
6522 xmlBufferPtr ret;
6523
6524 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6525 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006526 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006527 return(NULL);
6528 }
6529 ret->use = 0;
6530 ret->alloc = xmlBufferAllocScheme;
6531 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6532 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006533 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006534 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006535 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006536 xmlFree(ret);
6537 return(NULL);
6538 }
6539 ret->content[0] = 0;
6540 } else
6541 ret->content = NULL;
6542 return(ret);
6543}
6544
6545/**
Daniel Veillard53350552003-09-18 13:35:51 +00006546 * xmlBufferCreateStatic:
6547 * @mem: the memory area
6548 * @size: the size in byte
6549 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006550 * routine to create an XML buffer from an immutable memory area.
6551 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006552 * present until the end of the buffer lifetime.
6553 *
6554 * returns the new structure.
6555 */
6556xmlBufferPtr
6557xmlBufferCreateStatic(void *mem, size_t size) {
6558 xmlBufferPtr ret;
6559
6560 if ((mem == NULL) || (size == 0))
6561 return(NULL);
6562
6563 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6564 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006565 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006566 return(NULL);
6567 }
6568 ret->use = size;
6569 ret->size = size;
6570 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6571 ret->content = (xmlChar *) mem;
6572 return(ret);
6573}
6574
6575/**
Owen Taylor3473f882001-02-23 17:55:21 +00006576 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006577 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006578 * @scheme: allocation scheme to use
6579 *
6580 * Sets the allocation scheme for this buffer
6581 */
6582void
6583xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6584 xmlBufferAllocationScheme scheme) {
6585 if (buf == NULL) {
6586#ifdef DEBUG_BUFFER
6587 xmlGenericError(xmlGenericErrorContext,
6588 "xmlBufferSetAllocationScheme: buf == NULL\n");
6589#endif
6590 return;
6591 }
Daniel Veillard53350552003-09-18 13:35:51 +00006592 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006593
6594 buf->alloc = scheme;
6595}
6596
6597/**
6598 * xmlBufferFree:
6599 * @buf: the buffer to free
6600 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006601 * Frees an XML buffer. It frees both the content and the structure which
6602 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006603 */
6604void
6605xmlBufferFree(xmlBufferPtr buf) {
6606 if (buf == NULL) {
6607#ifdef DEBUG_BUFFER
6608 xmlGenericError(xmlGenericErrorContext,
6609 "xmlBufferFree: buf == NULL\n");
6610#endif
6611 return;
6612 }
Daniel Veillard53350552003-09-18 13:35:51 +00006613
6614 if ((buf->content != NULL) &&
6615 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006616 xmlFree(buf->content);
6617 }
Owen Taylor3473f882001-02-23 17:55:21 +00006618 xmlFree(buf);
6619}
6620
6621/**
6622 * xmlBufferEmpty:
6623 * @buf: the buffer
6624 *
6625 * empty a buffer.
6626 */
6627void
6628xmlBufferEmpty(xmlBufferPtr buf) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006629 if (buf == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006630 if (buf->content == NULL) return;
6631 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006632 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006633 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006634 } else {
6635 memset(buf->content, 0, buf->size);
6636 }
Owen Taylor3473f882001-02-23 17:55:21 +00006637}
6638
6639/**
6640 * xmlBufferShrink:
6641 * @buf: the buffer to dump
6642 * @len: the number of xmlChar to remove
6643 *
6644 * Remove the beginning of an XML buffer.
6645 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006646 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006647 */
6648int
6649xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
Daniel Veillard3d97e662004-11-04 10:49:00 +00006650 if (buf == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006651 if (len == 0) return(0);
6652 if (len > buf->use) return(-1);
6653
6654 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006655 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6656 buf->content += len;
6657 } else {
6658 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6659 buf->content[buf->use] = 0;
6660 }
Owen Taylor3473f882001-02-23 17:55:21 +00006661 return(len);
6662}
6663
6664/**
6665 * xmlBufferGrow:
6666 * @buf: the buffer
6667 * @len: the minimum free size to allocate
6668 *
6669 * Grow the available space of an XML buffer.
6670 *
6671 * Returns the new available space or -1 in case of error
6672 */
6673int
6674xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6675 int size;
6676 xmlChar *newbuf;
6677
Daniel Veillard3d97e662004-11-04 10:49:00 +00006678 if (buf == NULL) return(-1);
6679
Daniel Veillard53350552003-09-18 13:35:51 +00006680 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006681 if (len + buf->use < buf->size) return(0);
6682
William M. Brack30fe43f2004-07-26 18:00:58 +00006683/*
6684 * Windows has a BIG problem on realloc timing, so we try to double
6685 * the buffer size (if that's enough) (bug 146697)
6686 */
6687#ifdef WIN32
6688 if (buf->size > len)
6689 size = buf->size * 2;
6690 else
6691 size = buf->use + len + 100;
6692#else
Owen Taylor3473f882001-02-23 17:55:21 +00006693 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00006694#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006695
6696 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006697 if (newbuf == NULL) {
6698 xmlTreeErrMemory("growing buffer");
6699 return(-1);
6700 }
Owen Taylor3473f882001-02-23 17:55:21 +00006701 buf->content = newbuf;
6702 buf->size = size;
6703 return(buf->size - buf->use);
6704}
6705
6706/**
6707 * xmlBufferDump:
6708 * @file: the file output
6709 * @buf: the buffer to dump
6710 *
6711 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006712 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006713 */
6714int
6715xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6716 int ret;
6717
6718 if (buf == NULL) {
6719#ifdef DEBUG_BUFFER
6720 xmlGenericError(xmlGenericErrorContext,
6721 "xmlBufferDump: buf == NULL\n");
6722#endif
6723 return(0);
6724 }
6725 if (buf->content == NULL) {
6726#ifdef DEBUG_BUFFER
6727 xmlGenericError(xmlGenericErrorContext,
6728 "xmlBufferDump: buf->content == NULL\n");
6729#endif
6730 return(0);
6731 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006732 if (file == NULL)
6733 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006734 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6735 return(ret);
6736}
6737
6738/**
6739 * xmlBufferContent:
6740 * @buf: the buffer
6741 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006742 * Function to extract the content of a buffer
6743 *
Owen Taylor3473f882001-02-23 17:55:21 +00006744 * Returns the internal content
6745 */
6746
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006747const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006748xmlBufferContent(const xmlBufferPtr buf)
6749{
6750 if(!buf)
6751 return NULL;
6752
6753 return buf->content;
6754}
6755
6756/**
6757 * xmlBufferLength:
6758 * @buf: the buffer
6759 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006760 * Function to get the length of a buffer
6761 *
Owen Taylor3473f882001-02-23 17:55:21 +00006762 * Returns the length of data in the internal content
6763 */
6764
6765int
6766xmlBufferLength(const xmlBufferPtr buf)
6767{
6768 if(!buf)
6769 return 0;
6770
6771 return buf->use;
6772}
6773
6774/**
6775 * xmlBufferResize:
6776 * @buf: the buffer to resize
6777 * @size: the desired size
6778 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006779 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006780 *
6781 * Returns 0 in case of problems, 1 otherwise
6782 */
6783int
6784xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6785{
6786 unsigned int newSize;
6787 xmlChar* rebuf = NULL;
6788
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006789 if (buf == NULL)
6790 return(0);
6791
Daniel Veillard53350552003-09-18 13:35:51 +00006792 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6793
Owen Taylor3473f882001-02-23 17:55:21 +00006794 /* Don't resize if we don't have to */
6795 if (size < buf->size)
6796 return 1;
6797
6798 /* figure out new size */
6799 switch (buf->alloc){
6800 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillardbf629492004-04-20 22:20:59 +00006801 /*take care of empty case*/
6802 newSize = (buf->size ? buf->size*2 : size + 10);
Owen Taylor3473f882001-02-23 17:55:21 +00006803 while (size > newSize) newSize *= 2;
6804 break;
6805 case XML_BUFFER_ALLOC_EXACT:
6806 newSize = size+10;
6807 break;
6808 default:
6809 newSize = size+10;
6810 break;
6811 }
6812
6813 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006814 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006815 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006816 rebuf = (xmlChar *) xmlRealloc(buf->content,
6817 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006818 } else {
6819 /*
6820 * if we are reallocating a buffer far from being full, it's
6821 * better to make a new allocation and copy only the used range
6822 * and free the old one.
6823 */
6824 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6825 if (rebuf != NULL) {
6826 memcpy(rebuf, buf->content, buf->use);
6827 xmlFree(buf->content);
William M. Brack42331a92004-07-29 07:07:16 +00006828 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006829 }
6830 }
Owen Taylor3473f882001-02-23 17:55:21 +00006831 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006832 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006833 return 0;
6834 }
6835 buf->content = rebuf;
6836 buf->size = newSize;
6837
6838 return 1;
6839}
6840
6841/**
6842 * xmlBufferAdd:
6843 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006844 * @str: the #xmlChar string
6845 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006846 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006847 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006848 * str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006849 *
6850 * Returns 0 successful, a positive error code number otherwise
6851 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006852 */
William M. Bracka3215c72004-07-31 16:24:01 +00006853int
Owen Taylor3473f882001-02-23 17:55:21 +00006854xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6855 unsigned int needSize;
6856
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006857 if ((str == NULL) || (buf == NULL)) {
William M. Bracka3215c72004-07-31 16:24:01 +00006858 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006859 }
William M. Bracka3215c72004-07-31 16:24:01 +00006860 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006861 if (len < -1) {
6862#ifdef DEBUG_BUFFER
6863 xmlGenericError(xmlGenericErrorContext,
6864 "xmlBufferAdd: len < 0\n");
6865#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006866 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006867 }
William M. Bracka3215c72004-07-31 16:24:01 +00006868 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006869
6870 if (len < 0)
6871 len = xmlStrlen(str);
6872
William M. Bracka3215c72004-07-31 16:24:01 +00006873 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006874
6875 needSize = buf->use + len + 2;
6876 if (needSize > buf->size){
6877 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006878 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006879 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006880 }
6881 }
6882
6883 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6884 buf->use += len;
6885 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006886 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006887}
6888
6889/**
6890 * xmlBufferAddHead:
6891 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006892 * @str: the #xmlChar string
6893 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006894 *
6895 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006896 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006897 *
6898 * Returns 0 successful, a positive error code number otherwise
6899 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006900 */
William M. Bracka3215c72004-07-31 16:24:01 +00006901int
Owen Taylor3473f882001-02-23 17:55:21 +00006902xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6903 unsigned int needSize;
6904
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006905 if (buf == NULL)
6906 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00006907 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006908 if (str == NULL) {
6909#ifdef DEBUG_BUFFER
6910 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006911 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006912#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006913 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006914 }
6915 if (len < -1) {
6916#ifdef DEBUG_BUFFER
6917 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006918 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006919#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006920 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006921 }
William M. Bracka3215c72004-07-31 16:24:01 +00006922 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006923
6924 if (len < 0)
6925 len = xmlStrlen(str);
6926
William M. Bracka3215c72004-07-31 16:24:01 +00006927 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006928
6929 needSize = buf->use + len + 2;
6930 if (needSize > buf->size){
6931 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006932 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006933 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006934 }
6935 }
6936
6937 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6938 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6939 buf->use += len;
6940 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006941 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006942}
6943
6944/**
6945 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00006946 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00006947 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006948 *
6949 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00006950 *
6951 * Returns 0 successful, a positive error code number otherwise
6952 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006953 */
William M. Bracka3215c72004-07-31 16:24:01 +00006954int
Owen Taylor3473f882001-02-23 17:55:21 +00006955xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006956 if (buf == NULL)
6957 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00006958 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
6959 if (str == NULL) return -1;
6960 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00006961}
6962
6963/**
6964 * xmlBufferCCat:
6965 * @buf: the buffer to dump
6966 * @str: the C char string
6967 *
6968 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00006969 *
6970 * Returns 0 successful, a positive error code number otherwise
6971 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006972 */
William M. Bracka3215c72004-07-31 16:24:01 +00006973int
Owen Taylor3473f882001-02-23 17:55:21 +00006974xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6975 const char *cur;
6976
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006977 if (buf == NULL)
6978 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00006979 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006980 if (str == NULL) {
6981#ifdef DEBUG_BUFFER
6982 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006983 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006984#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006985 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006986 }
6987 for (cur = str;*cur != 0;cur++) {
6988 if (buf->use + 10 >= buf->size) {
6989 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006990 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006991 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006992 }
6993 }
6994 buf->content[buf->use++] = *cur;
6995 }
6996 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006997 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006998}
6999
7000/**
7001 * xmlBufferWriteCHAR:
7002 * @buf: the XML buffer
7003 * @string: the string to add
7004 *
7005 * routine which manages and grows an output buffer. This one adds
7006 * xmlChars at the end of the buffer.
7007 */
7008void
Daniel Veillard53350552003-09-18 13:35:51 +00007009xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007010 if (buf == NULL)
7011 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007012 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007013 xmlBufferCat(buf, string);
7014}
7015
7016/**
7017 * xmlBufferWriteChar:
7018 * @buf: the XML buffer output
7019 * @string: the string to add
7020 *
7021 * routine which manage and grows an output buffer. This one add
7022 * C chars at the end of the array.
7023 */
7024void
7025xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007026 if (buf == NULL)
7027 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007028 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007029 xmlBufferCCat(buf, string);
7030}
7031
7032
7033/**
7034 * xmlBufferWriteQuotedString:
7035 * @buf: the XML buffer output
7036 * @string: the string to add
7037 *
7038 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00007039 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00007040 * quote or double-quotes internally
7041 */
7042void
7043xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00007044 const xmlChar *cur, *base;
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007045 if (buf == NULL)
7046 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007047 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00007048 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00007049 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00007050#ifdef DEBUG_BUFFER
7051 xmlGenericError(xmlGenericErrorContext,
7052 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7053#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00007054 xmlBufferCCat(buf, "\"");
7055 base = cur = string;
7056 while(*cur != 0){
7057 if(*cur == '"'){
7058 if (base != cur)
7059 xmlBufferAdd(buf, base, cur - base);
7060 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7061 cur++;
7062 base = cur;
7063 }
7064 else {
7065 cur++;
7066 }
7067 }
7068 if (base != cur)
7069 xmlBufferAdd(buf, base, cur - base);
7070 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007071 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007072 else{
7073 xmlBufferCCat(buf, "\'");
7074 xmlBufferCat(buf, string);
7075 xmlBufferCCat(buf, "\'");
7076 }
Owen Taylor3473f882001-02-23 17:55:21 +00007077 } else {
7078 xmlBufferCCat(buf, "\"");
7079 xmlBufferCat(buf, string);
7080 xmlBufferCCat(buf, "\"");
7081 }
7082}
7083
7084
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007085/**
7086 * xmlGetDocCompressMode:
7087 * @doc: the document
7088 *
7089 * get the compression ratio for a document, ZLIB based
7090 * Returns 0 (uncompressed) to 9 (max compression)
7091 */
7092int
7093xmlGetDocCompressMode (xmlDocPtr doc) {
7094 if (doc == NULL) return(-1);
7095 return(doc->compression);
7096}
7097
7098/**
7099 * xmlSetDocCompressMode:
7100 * @doc: the document
7101 * @mode: the compression ratio
7102 *
7103 * set the compression ratio for a document, ZLIB based
7104 * Correct values: 0 (uncompressed) to 9 (max compression)
7105 */
7106void
7107xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7108 if (doc == NULL) return;
7109 if (mode < 0) doc->compression = 0;
7110 else if (mode > 9) doc->compression = 9;
7111 else doc->compression = mode;
7112}
7113
7114/**
7115 * xmlGetCompressMode:
7116 *
7117 * get the default compression mode used, ZLIB based.
7118 * Returns 0 (uncompressed) to 9 (max compression)
7119 */
7120int
7121xmlGetCompressMode(void)
7122{
7123 return (xmlCompressMode);
7124}
7125
7126/**
7127 * xmlSetCompressMode:
7128 * @mode: the compression ratio
7129 *
7130 * set the default compression mode used, ZLIB based
7131 * Correct values: 0 (uncompressed) to 9 (max compression)
7132 */
7133void
7134xmlSetCompressMode(int mode) {
7135 if (mode < 0) xmlCompressMode = 0;
7136 else if (mode > 9) xmlCompressMode = 9;
7137 else xmlCompressMode = mode;
7138}
7139
Kasimier T. Buchcik4d9c9482005-06-27 15:04:46 +00007140/*
7141* xmlDOMWrapNewCtxt:
7142*
7143* Allocates and initializes a new DOM-wrapper context.
7144*
7145* Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal errror.
7146*/
7147xmlDOMWrapCtxtPtr
7148xmlDOMWrapNewCtxt(void)
7149{
7150 xmlDOMWrapCtxtPtr ret;
7151
7152 ret = xmlMalloc(sizeof(xmlDOMWrapCtxt));
7153 if (ret == NULL) {
7154 xmlTreeErrMemory("allocating DOM-wrapper context");
7155 return (NULL);
7156 }
7157 memset(ret, 0, sizeof(xmlDOMWrapCtxt));
7158 return (ret);
7159}
7160
7161/*
7162* xmlDOMWrapFreeCtxt:
7163* @ctxt: the DOM-wrapper context
7164*
7165* Frees the DOM-wrapper context.
7166*/
7167void
7168xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt)
7169{
7170 if (ctxt == NULL)
7171 return;
7172 xmlFree(ctxt);
7173}
7174
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007175#define XML_TREE_NSMAP_PARENT -1
7176#define XML_TREE_NSMAP_XML -2
7177#define XML_TREE_NSMAP_DOC -3
7178#define XML_TREE_NSMAP_CUSTOM -4
7179
7180typedef struct xmlNsMapItem *xmlNsMapItemPtr;
7181struct xmlNsMapItem {
7182 xmlNsMapItemPtr next;
7183 xmlNsMapItemPtr prev;
7184 xmlNsPtr oldNs; /* old ns decl reference */
7185 xmlNsPtr newNs; /* new ns decl reference */
7186 int shadowDepth; /* Shadowed at this depth */
7187 /*
7188 * depth:
7189 * >= 0 == @node's ns-decls
7190 * -1 == @parent's ns-decls
7191 * -2 == @parent's out-of-scope ns-decls
7192 * -3 == the doc->oldNs XML ns-decl
7193 * -4 == the doc->oldNs storage ns-decls
7194 */
7195 int depth;
7196};
7197
7198/*
7199* xmlTreeAddNsMapItem:
7200* @map: the ns-map
7201* @cur: the current map entry to append a new entry to
7202* @oldNs: the old ns-struct
7203* @newNs: the new ns-struct
7204* @depth: depth and ns-kind information
7205*
7206* Frees the ns-map
7207*/
7208static xmlNsMapItemPtr
7209xmlDOMWrapNSNormAddNsMapItem(xmlNsMapItemPtr *map,
7210 xmlNsMapItemPtr *cur,
7211 xmlNsPtr oldNs,
7212 xmlNsPtr newNs,
7213 int depth)
7214{
7215 xmlNsMapItemPtr ret;
7216
7217 if ((cur != NULL) && (*cur != NULL) && ((*cur)->next != NULL)) {
7218 /*
7219 * Reuse.
7220 */
7221 ret = (*cur)->next;
7222 *cur = ret;
7223 } else {
7224 ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem));
7225 if (ret == NULL) {
7226 xmlTreeErrMemory("allocating namespace map item");
7227 return (NULL);
7228 }
7229 memset(ret, 0, sizeof(struct xmlNsMapItem));
7230 if (*map == NULL) {
7231 /*
7232 * First ever.
7233 */
7234 *map = ret;
7235 ret->prev = ret;
7236 if (cur != NULL)
7237 *cur = ret;
7238 } else {
7239 if (cur) {
7240 /*
7241 * Append.
7242 */
7243 (*cur)->next = ret;
7244 ret->prev = *cur;
7245 *cur = ret;
7246 } else {
7247 /*
7248 * Set on first position.
7249 */
7250 ret->next = (*map);
7251 ret->prev = (*map)->prev;
7252 (*map)->prev = ret;
7253 *map = ret;
7254 }
7255 }
7256 }
7257 ret->oldNs = oldNs;
7258 ret->newNs = newNs;
7259 ret->shadowDepth = -1;
7260 ret->depth = depth;
7261 return (ret);
7262}
7263
7264/*
7265* xmlTreeFreeNsMap:
7266* @map: the ns-map
7267*
7268* Frees the ns-map
7269*/
7270static void
7271xmlDOMWrapNSNormFreeNsMap(xmlNsMapItemPtr map)
7272{
7273 xmlNsMapItemPtr mi = map, miprev;
7274
7275 while (mi != NULL) {
7276 miprev = mi;
7277 mi = mi->next;
7278 xmlFree(miprev);
7279 }
7280}
7281
7282/*
7283* xmlTreeEnsureXMLDecl:
7284* @doc: the doc
7285*
7286* Ensures that there is an XML namespace declaration on the doc.
7287*
7288* Returns the XML ns-struct or NULL on API and internal errors.
7289*/
7290static xmlNsPtr
7291xmlTreeEnsureXMLDecl(xmlDocPtr doc)
7292{
7293 if (doc == NULL)
7294 return (NULL);
7295 if (doc->oldNs != NULL)
7296 return (doc->oldNs);
7297 {
7298 xmlNsPtr ns;
7299 ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
7300 if (ns == NULL) {
7301 xmlTreeErrMemory(
7302 "allocating the XML namespace");
7303 return (NULL);
7304 }
7305 memset(ns, 0, sizeof(xmlNs));
7306 ns->type = XML_LOCAL_NAMESPACE;
7307 ns->href = xmlStrdup(XML_XML_NAMESPACE);
7308 ns->prefix = xmlStrdup((const xmlChar *)"xml");
7309 doc->oldNs = ns;
7310 return (ns);
7311 }
7312}
7313
7314/*
7315* xmlDOMWrapStoreNs:
7316* @doc: the doc
7317* @nsName: the namespace name
7318* @prefix: the prefix
7319*
7320* Creates or reuses an xmlNs struct on doc->oldNs with
7321* the given prefix and namespace name.
7322*
7323* Returns the aquired ns struct or NULL in case of an API
7324* or internal error.
7325*/
7326static xmlNsPtr
7327xmlDOMWrapStoreNs(xmlDocPtr doc,
7328 const xmlChar *nsName,
7329 const xmlChar *prefix)
7330{
7331 xmlNsPtr ns;
7332
7333 if (doc == NULL)
7334 return (NULL);
7335 ns = xmlTreeEnsureXMLDecl(doc);
7336 if (ns == NULL)
7337 return (NULL);
7338 if (ns->next != NULL) {
7339 /* Reuse. */
7340 ns = ns->next;
7341 while (ns != NULL) {
7342 if (((ns->prefix == prefix) ||
7343 xmlStrEqual(ns->prefix, prefix)) &&
7344 xmlStrEqual(ns->href, nsName)) {
7345 return (ns);
7346 }
7347 if (ns->next == NULL)
7348 break;
7349 ns = ns->next;
7350 }
7351 }
7352 /* Create. */
7353 ns->next = xmlNewNs(NULL, nsName, prefix);
7354 return (ns->next);
7355}
7356
7357/*
7358* xmlTreeLookupNsListByPrefix:
7359* @nsList: a list of ns-structs
7360* @prefix: the searched prefix
7361*
7362* Searches for a ns-decl with the given prefix in @nsList.
7363*
7364* Returns the ns-decl if found, NULL if not found and on
7365* API errors.
7366*/
7367static xmlNsPtr
7368xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix)
7369{
7370 if (nsList == NULL)
7371 return (NULL);
7372 {
7373 xmlNsPtr ns;
7374 ns = nsList;
7375 do {
7376 if ((prefix == ns->prefix) ||
7377 xmlStrEqual(prefix, ns->prefix)) {
7378 return (ns);
7379 }
7380 ns = ns->next;
7381 } while (ns != NULL);
7382 }
7383 return (NULL);
7384}
7385
7386/*
7387*
7388* xmlTreeGetInScopeNamespaces:
7389* @map: the namespace map
7390* @node: the node to start with
7391*
7392* Puts in-scope namespaces into the ns-map.
7393*
7394* Returns 0 on success, -1 on API or internal errors.
7395*/
7396static int
7397xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapItemPtr *map,
7398 xmlNodePtr node)
7399{
7400 xmlNodePtr cur;
7401 xmlNsPtr ns;
7402 xmlNsMapItemPtr mi;
7403 int shadowed;
7404
7405 if ((map == NULL) || (*map != NULL))
7406 return (-1);
7407 /*
7408 * Get in-scope ns-decls of @parent.
7409 */
7410 cur = node;
7411 while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) {
7412 if (cur->type == XML_ELEMENT_NODE) {
7413 if (cur->nsDef != NULL) {
7414 ns = cur->nsDef;
7415 do {
7416 shadowed = 0;
7417 if (*map != NULL) {
7418 /*
7419 * Skip shadowed prefixes.
7420 */
7421 for (mi = *map; mi != NULL; mi = mi->next) {
7422 if ((ns->prefix == mi->newNs->prefix) ||
7423 xmlStrEqual(ns->prefix, mi->newNs->prefix)) {
7424 shadowed = 1;
7425 break;
7426 }
7427 }
7428 }
7429 /*
7430 * Insert mapping.
7431 */
7432 mi = xmlDOMWrapNSNormAddNsMapItem(map, NULL, NULL,
7433 ns, XML_TREE_NSMAP_PARENT);
7434 if (mi == NULL)
7435 return (-1);
7436 if (shadowed)
7437 mi->shadowDepth = 0;
7438 ns = ns->next;
7439 } while (ns != NULL);
7440 }
7441 }
7442 cur = cur->parent;
7443 }
7444 return (0);
7445}
7446
7447/*
7448* XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict;
7449* otherwise copy it, when it was in the source-dict.
7450*/
7451#define XML_TREE_ADOPT_STR(str) \
7452 if (adoptStr && (str != NULL)) { \
7453 if (destDoc->dict) { \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00007454 const xmlChar *old = str; \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007455 str = xmlDictLookup(destDoc->dict, str, -1); \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00007456 if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \
7457 (!xmlDictOwns(sourceDoc->dict, old))) \
Daniel Veillard39e5c892005-07-03 22:48:50 +00007458 xmlFree((char *)old); \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007459 } else if ((sourceDoc) && (sourceDoc->dict) && \
7460 xmlDictOwns(sourceDoc->dict, str)) { \
7461 str = BAD_CAST xmlStrdup(str); \
7462 } \
7463 }
7464
7465/*
7466* XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then
7467* put it in dest-dict or copy it.
7468*/
7469#define XML_TREE_ADOPT_STR_2(str) \
7470 if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \
7471 (sourceDoc->dict != NULL) && \
7472 xmlDictOwns(sourceDoc->dict, cur->content)) { \
7473 if (destDoc->dict) \
7474 cur->content = (xmlChar *) \
7475 xmlDictLookup(destDoc->dict, cur->content, -1); \
7476 else \
7477 cur->content = xmlStrdup(BAD_CAST cur->content); \
7478 }
7479
7480/*
7481* xmlDOMWrapNSNormAddNsMapItem2:
7482*
7483* For internal use. Adds a ns-decl mapping.
7484*
7485* Returns 0 on success, -1 on internal errors.
7486*/
7487static int
7488xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number,
7489 xmlNsPtr oldNs, xmlNsPtr newNs)
7490{
7491 if (*list == NULL) {
7492 *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr));
7493 if (*list == NULL) {
7494 xmlTreeErrMemory("alloc ns map item");
7495 return(-1);
7496 }
7497 *size = 3;
7498 *number = 0;
7499 } else if ((*number) >= (*size)) {
7500 *size *= 2;
7501 *list = (xmlNsPtr *) xmlRealloc(*list,
7502 (*size) * 2 * sizeof(xmlNsPtr));
7503 if (*list == NULL) {
7504 xmlTreeErrMemory("realloc ns map item");
7505 return(-1);
7506 }
7507 }
7508 (*list)[2 * (*number)] = oldNs;
7509 (*list)[2 * (*number) +1] = newNs;
7510 (*number)++;
7511 return (0);
7512}
7513
7514/*
7515* xmlDOMWrapRemoveNode:
Daniel Veillard304e78c2005-07-03 16:19:41 +00007516* @ctxt: a DOM wrapper context
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007517* @doc: the doc
7518* @node: the node to be removed.
Daniel Veillard304e78c2005-07-03 16:19:41 +00007519* @options: set of options, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007520*
7521* Unlinks the given node from its owner.
7522* This will substitute ns-references to node->nsDef for
7523* ns-references to doc->oldNs, thus ensuring the removed
7524* branch to be autark wrt ns-references.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00007525* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007526*
7527* Returns 0 on success, 1 if the node is not supported,
7528* -1 on API and internal errors.
7529*/
7530int
7531xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc,
7532 xmlNodePtr node, int options ATTRIBUTE_UNUSED)
7533{
7534 xmlNsPtr *list = NULL;
7535 int sizeList, nbList, i, j;
7536 xmlNsPtr ns;
7537
7538 if ((node == NULL) || (doc == NULL) || (node->doc != doc))
7539 return (-1);
7540
7541 /* TODO: 0 or -1 ? */
7542 if (node->parent == NULL)
7543 return (0);
7544
7545 switch (node->type) {
7546 case XML_TEXT_NODE:
7547 case XML_CDATA_SECTION_NODE:
7548 case XML_ENTITY_REF_NODE:
7549 case XML_PI_NODE:
7550 case XML_COMMENT_NODE:
7551 xmlUnlinkNode(node);
7552 return (0);
7553 case XML_ELEMENT_NODE:
7554 case XML_ATTRIBUTE_NODE:
7555 break;
7556 default:
7557 return (1);
7558 }
7559 xmlUnlinkNode(node);
7560 /*
7561 * Save out-of-scope ns-references in doc->oldNs.
7562 */
7563 do {
7564 switch (node->type) {
7565 case XML_ELEMENT_NODE:
7566 if ((ctxt == NULL) && (node->nsDef != NULL)) {
7567 ns = node->nsDef;
7568 do {
7569 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
7570 &nbList, ns, ns) == -1)
7571 goto internal_error;
7572 ns = ns->next;
7573 } while (ns != NULL);
7574 }
7575 /* No break on purpose. */
7576 case XML_ATTRIBUTE_NODE:
7577 if (node->ns != NULL) {
7578 /*
7579 * Find a mapping.
7580 */
7581 if (list != NULL) {
7582 for (i = 0, j = 0; i < nbList; i++, j += 2) {
7583 if (node->ns == list[j]) {
7584 node->ns = list[++j];
7585 goto next_node;
7586 }
7587 }
7588 }
7589 ns = NULL;
7590 if (ctxt != NULL) {
7591 /*
7592 * User defined.
7593 */
7594 } else {
7595 /*
7596 * Add to doc's oldNs.
7597 */
7598 ns = xmlDOMWrapStoreNs(doc, node->ns->href,
7599 node->ns->prefix);
7600 if (ns == NULL)
7601 goto internal_error;
7602 }
7603 if (ns != NULL) {
7604 /*
7605 * Add mapping.
7606 */
7607 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
7608 &nbList, node->ns, ns) == -1)
7609 goto internal_error;
7610 }
7611 node->ns = ns;
7612 }
7613 if ((node->type == XML_ELEMENT_NODE) &&
7614 (node->properties != NULL)) {
7615 node = (xmlNodePtr) node->properties;
7616 continue;
7617 }
7618 break;
7619 default:
7620 goto next_sibling;
7621 }
7622next_node:
7623 if ((node->type == XML_ELEMENT_NODE) &&
7624 (node->children != NULL)) {
7625 node = node->children;
7626 continue;
7627 }
7628next_sibling:
7629 if (node == NULL)
7630 break;
7631 if (node->next != NULL)
7632 node = node->next;
7633 else {
7634 node = node->parent;
7635 goto next_sibling;
7636 }
7637 } while (node != NULL);
7638
7639 if (list != NULL)
7640 xmlFree(list);
7641 return (0);
7642
7643internal_error:
7644 if (list != NULL)
7645 xmlFree(list);
7646 return (-1);
7647}
7648
7649/*
7650* xmlSearchNsByHrefStrict:
7651* @doc: the document
7652* @node: the start node
7653* @nsName: the searched namespace name
7654* @retNs: the resulting ns-decl
7655* @prefixed: if the found ns-decl must have a prefix (for attributes)
7656*
7657* Dynamically searches for a ns-declaration which matches
7658* the given @nsName in the ancestor-or-self axis of @node.
7659*
7660* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7661* and internal errors.
7662*/
7663static int
7664xmlSearchNsByHrefStrict(xmlDocPtr doc, xmlNodePtr node, const xmlChar* nsName,
7665 xmlNsPtr *retNs, int prefixed)
7666{
7667 xmlNodePtr cur, prev = NULL, out = NULL;
7668 xmlNsPtr ns, prevns;
7669
7670 if ((doc == NULL) || (nsName == NULL) || (retNs == NULL))
7671 return (-1);
7672
7673 *retNs = NULL;
7674 if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
7675 *retNs = xmlTreeEnsureXMLDecl(doc);
7676 if (*retNs == NULL)
7677 return (-1);
7678 return (1);
7679 }
7680 cur = node;
7681 do {
7682 if (cur->type == XML_ELEMENT_NODE) {
7683 if (cur->nsDef != NULL) {
7684 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
7685 if (prefixed && (ns->prefix == NULL))
7686 continue;
7687 if (prev != NULL) {
7688 /*
7689 * Check the last level of ns-decls for a
7690 * shadowing prefix.
7691 */
7692 prevns = prev->nsDef;
7693 do {
7694 if ((prevns->prefix == ns->prefix) ||
7695 ((prevns->prefix != NULL) &&
7696 (ns->prefix != NULL) &&
7697 xmlStrEqual(prevns->prefix, ns->prefix))) {
7698 /*
7699 * Shadowed.
7700 */
7701 break;
7702 }
7703 prevns = prevns->next;
7704 } while (prevns != NULL);
7705 if (prevns != NULL)
7706 continue;
7707 }
7708 /*
7709 * Ns-name comparison.
7710 */
7711 if ((nsName == ns->href) ||
7712 xmlStrEqual(nsName, ns->href)) {
7713 /*
7714 * At this point the prefix can only be shadowed,
7715 * if we are the the (at least) 3rd level of
7716 * ns-decls.
7717 */
7718 if (out) {
7719 int ret;
7720
7721 ret = xmlNsInScope(doc, node, prev, ns->prefix);
7722 if (ret < 0)
7723 return (-1);
7724 /*
7725 * TODO: Should we try to find a matching ns-name
7726 * only once? This here keeps on searching.
7727 * I think we should try further since, there might
7728 * be an other matching ns-decl with an unshadowed
7729 * prefix.
7730 */
7731 if (! ret)
7732 continue;
7733 }
7734 *retNs = ns;
7735 return (1);
7736 }
7737 }
7738 out = prev;
7739 prev = cur;
7740 }
7741 } else if ((node->type == XML_ENTITY_REF_NODE) ||
7742 (node->type == XML_ENTITY_NODE) ||
7743 (node->type == XML_ENTITY_DECL))
7744 return (0);
7745 cur = cur->parent;
7746 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
7747 return (0);
7748}
7749
7750/*
7751* xmlDOMWrapNSNormDeclareNsForced:
7752* @doc: the doc
7753* @elem: the element-node to declare on
7754* @nsName: the namespace-name of the ns-decl
7755* @prefix: the preferred prefix of the ns-decl
7756* @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls
7757*
7758* Declares a new namespace on @elem. It tries to use the
7759* given @prefix; if a ns-decl with the given prefix is already existent
7760* on @elem, it will generate an other prefix.
7761*
7762* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7763* and internal errors.
7764*/
7765static xmlNsPtr
7766xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc,
7767 xmlNodePtr elem,
7768 const xmlChar *nsName,
7769 const xmlChar *prefix,
7770 int checkShadow)
7771{
7772
7773 xmlNsPtr ret;
7774 char buf[50];
7775 const xmlChar *pref;
7776 int counter = 0;
7777 /*
7778 * Create a ns-decl on @anchor.
7779 */
7780 pref = prefix;
7781 while (1) {
7782 /*
7783 * Lookup whether the prefix is unused in elem's ns-decls.
7784 */
7785 if ((elem->nsDef != NULL) &&
7786 (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL))
7787 goto ns_next_prefix;
7788 if (checkShadow && elem->parent &&
7789 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
7790 /*
7791 * Does it shadow ancestor ns-decls?
7792 */
7793 if (xmlSearchNs(doc, elem->parent, pref) != NULL)
7794 goto ns_next_prefix;
7795 }
7796 ret = xmlNewNs(NULL, nsName, pref);
7797 if (ret == NULL)
7798 return (NULL);
7799 if (elem->nsDef == NULL)
7800 elem->nsDef = ret;
7801 else {
7802 xmlNsPtr ns2 = elem->nsDef;
7803 while (ns2->next != NULL)
7804 ns2 = ns2->next;
7805 ns2->next = ret;
7806 }
7807 return (ret);
7808ns_next_prefix:
7809 counter++;
7810 if (counter > 1000)
7811 return (NULL);
7812 if (prefix == NULL) {
7813 snprintf((char *) buf, sizeof(buf),
7814 "default%d", counter);
7815 } else
7816 snprintf((char *) buf, sizeof(buf),
7817 "%.30s%d", (char *)prefix, counter);
7818 pref = BAD_CAST buf;
7819 }
7820}
7821
7822/*
7823* xmlDOMWrapNSNormAquireNormalizedNs:
7824* @doc: the doc
7825* @elem: the element-node to declare namespaces on
7826* @ns: the ns-struct to use for the search
7827* @retNs: the found/created ns-struct
7828* @nsMap: the ns-map
7829* @topmi: the last ns-map entry
7830* @depth: the current tree depth
7831* @ancestorsOnly: search in ancestor ns-decls only
7832* @prefixed: if the searched ns-decl must have a prefix (for attributes)
7833*
7834* Searches for a matching ns-name in the ns-decls of @nsMap, if not
7835* found it will either declare it on @elem, or store it in doc->oldNs.
7836* If a new ns-decl needs to be declared on @elem, it tries to use the
7837* @ns->prefix for it, if this prefix is already in use on @elem, it will
7838* change the prefix or the new ns-decl.
7839*
7840* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
7841*/
7842static int
7843xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc,
7844 xmlNodePtr elem,
7845 xmlNsPtr ns,
7846 xmlNsPtr *retNs,
7847 xmlNsMapItemPtr *nsMap,
7848 xmlNsMapItemPtr *topmi,
7849 int depth,
7850 int ancestorsOnly,
7851 int prefixed)
7852{
7853 xmlNsMapItemPtr mi;
7854
7855 if ((doc == NULL) || (ns == NULL) || (retNs == NULL) ||
7856 (nsMap == NULL) || (topmi == NULL))
7857 return (-1);
7858
7859 *retNs = NULL;
7860 /*
7861 * Handle XML namespace.
7862 */
7863 if ((ns->prefix) &&
7864 (ns->prefix[0] == 'x') &&
7865 (ns->prefix[1] == 'm') &&
7866 (ns->prefix[2] == 'l') &&
7867 (ns->prefix[3] == 0)) {
7868 /*
7869 * Insert XML namespace mapping.
7870 */
7871 *retNs = xmlTreeEnsureXMLDecl(doc);
7872 if (*retNs == NULL)
7873 return (-1);
7874 return (0);
7875 }
7876 /*
7877 * If the search should be done in ancestors only and no
7878 * @elem (the first ancestor) was specified, then skip the search.
7879 */
7880 if ((! (ancestorsOnly && (elem == NULL))) &&
7881 (*nsMap != NULL)) {
7882
7883 /*
7884 * Try to find an equal ns-name in in-scope ns-decls.
7885 */
7886 for (mi = *nsMap; mi != (*topmi)->next; mi = mi->next) {
7887
7888 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
7889 /*
7890 * This should be turned on to gain speed, if one knows
7891 * that the branch itself was already ns-wellformed and no
7892 * stale references existed. I.e. it searches in the ancestor
7893 * axis only.
7894 */
7895 ((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) &&
7896 /* Skip shadowed prefixes. */
7897 (mi->shadowDepth == -1) &&
7898 /* Skip xmlns="" or xmlns:foo="". */
7899 ((mi->newNs->href != NULL) &&
7900 (mi->newNs->href[0] != 0)) &&
7901 /* Ensure a prefix if wanted. */
7902 ((! prefixed) || (mi->newNs->prefix != NULL)) &&
7903 /* Equal ns name */
7904 ((mi->newNs->href == ns->href) ||
7905 xmlStrEqual(mi->newNs->href, ns->href))) {
7906 /* Set the mapping. */
7907 mi->oldNs = ns;
7908 *retNs = mi->newNs;
7909 return (0);
7910 }
7911 }
7912 }
7913 /*
7914 * No luck, the namespace is out of scope or shadowed.
7915 */
7916 if (elem == NULL) {
7917 xmlNsPtr tmpns;
7918
7919 /*
7920 * Store ns-decls in "oldNs" of the document-node.
7921 */
7922 tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix);
7923 if (tmpns == NULL)
7924 return (-1);
7925 /*
7926 * Insert mapping.
7927 */
7928 if (xmlDOMWrapNSNormAddNsMapItem(nsMap, NULL, ns,
7929 tmpns, XML_TREE_NSMAP_DOC) == NULL) {
7930 xmlFreeNs(tmpns);
7931 return (-1);
7932 }
7933 *retNs = tmpns;
7934 } else {
7935 xmlNsPtr tmpns;
7936
7937 tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href,
7938 ns->prefix, 0);
7939 if (tmpns == NULL)
7940 return (-1);
7941
7942 if (*nsMap != NULL) {
7943 /*
7944 * Does it shadow ancestor ns-decls?
7945 */
7946 for (mi = *nsMap; mi != (*topmi)->next; mi = mi->next) {
7947 if ((mi->depth < depth) &&
7948 (mi->shadowDepth == -1) &&
7949 ((ns->prefix == mi->newNs->prefix) ||
7950 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
7951 /*
7952 * Shadows.
7953 */
7954 mi->shadowDepth = depth;
7955 break;
7956 }
7957 }
7958 }
7959 if (xmlDOMWrapNSNormAddNsMapItem(nsMap, topmi, ns,
7960 tmpns, depth) == NULL) {
7961 xmlFreeNs(tmpns);
7962 return (-1);
7963 }
7964 *retNs = tmpns;
7965 }
7966 return (0);
7967}
7968
7969/*
7970* xmlDOMWrapReconcileNamespaces:
Daniel Veillard304e78c2005-07-03 16:19:41 +00007971* @ctxt: DOM wrapper context, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007972* @elem: the element-node
7973* @options: option flags
7974*
7975* Ensures that ns-references point to ns-decls hold on element-nodes.
7976* Ensures that the tree is namespace wellformed by creating additional
7977* ns-decls where needed. Note that, since prefixes of already existent
7978* ns-decls can be shadowed by this process, it could break QNames in
7979* attribute values or element content.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00007980* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007981*
7982* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
7983*/
7984int
7985xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,
7986 xmlNodePtr elem,
7987 int options ATTRIBUTE_UNUSED)
7988{
7989 int depth = -1, adoptns = 0, parnsdone = 0;
7990 xmlNsPtr ns;
7991 xmlDocPtr doc;
7992 xmlNodePtr cur, curElem = NULL;
7993 xmlNsMapItemPtr nsMap = NULL, topmi = NULL, mi;
7994 /* @ancestorsOnly should be set by an option flag. */
7995 int ancestorsOnly = 0;
7996
7997 if ((elem == NULL) || (elem->doc == NULL) ||
7998 (elem->type != XML_ELEMENT_NODE))
7999 return (-1);
8000
8001 doc = elem->doc;
8002 cur = elem;
8003 do {
8004 switch (cur->type) {
8005 case XML_ELEMENT_NODE:
8006 adoptns = 1;
8007 curElem = cur;
8008 depth++;
8009 /*
8010 * Namespace declarations.
8011 */
8012 if (cur->nsDef != NULL) {
8013 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8014 if (! parnsdone) {
8015 if ((elem->parent) &&
8016 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8017 /*
8018 * Gather ancestor in-scope ns-decls.
8019 */
8020 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8021 elem->parent) == -1)
8022 goto internal_error;
8023 if (nsMap != NULL)
8024 topmi = nsMap->prev;
8025 }
8026 parnsdone = 1;
8027 }
8028 /*
8029 * Skip ns-references handling if the referenced
8030 * ns-decl is declared on the same element.
8031 */
8032 if ((cur->ns != NULL) && adoptns && (cur->ns == ns))
8033 adoptns = 0;
8034 /*
8035 * Does it shadow any ns-decl?
8036 */
8037 if (nsMap) {
8038 for (mi = nsMap; mi != topmi->next; mi = mi->next) {
8039 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8040 (mi->shadowDepth == -1) &&
8041 ((ns->prefix == mi->newNs->prefix) ||
8042 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8043
8044 mi->shadowDepth = depth;
8045 }
8046 }
8047 }
8048 /*
8049 * Push mapping.
8050 */
8051 if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi, ns, ns,
8052 depth) == NULL)
8053 goto internal_error;
8054 }
8055 }
8056 if (! adoptns)
8057 goto ns_end;
8058
8059 /* No break on purpose. */
8060 case XML_ATTRIBUTE_NODE:
8061 if (cur->ns == NULL)
8062 goto ns_end;
8063 if (! parnsdone) {
8064 if ((elem->parent) &&
8065 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8066 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8067 elem->parent) == -1)
8068 goto internal_error;
8069 if (nsMap != NULL)
8070 topmi = nsMap->prev;
8071 }
8072 parnsdone = 1;
8073 }
8074 /*
8075 * Adopt ns-references.
8076 */
8077 if (nsMap != NULL) {
8078 /*
8079 * Search for a mapping.
8080 */
8081 for (mi = nsMap; mi != topmi->next; mi = mi->next) {
8082 if ((mi->shadowDepth == -1) &&
8083 (cur->ns == mi->oldNs)) {
8084
8085 cur->ns = mi->newNs;
8086 goto ns_end;
8087 }
8088 }
8089 }
8090 /*
8091 * Aquire a normalized ns-decl and add it to the map.
8092 */
8093 if (xmlDOMWrapNSNormAquireNormalizedNs(doc, curElem,
8094 cur->ns, &ns,
8095 &nsMap, &topmi, depth,
8096 ancestorsOnly,
8097 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8098 goto internal_error;
8099 cur->ns = ns;
8100
8101ns_end:
8102 if ((cur->type == XML_ELEMENT_NODE) &&
8103 (cur->properties != NULL)) {
8104 /*
8105 * Process attributes.
8106 */
8107 cur = (xmlNodePtr) cur->properties;
8108 continue;
8109 }
8110 break;
8111 default:
8112 goto next_sibling;
8113 }
8114 if ((cur->type == XML_ELEMENT_NODE) &&
8115 (cur->children != NULL)) {
8116 /*
8117 * Process content of element-nodes only.
8118 */
8119 cur = cur->children;
8120 continue;
8121 }
8122next_sibling:
8123 if (cur == elem)
8124 break;
8125 if (cur->type == XML_ELEMENT_NODE) {
8126 if (nsMap != NULL) {
8127 /*
8128 * Pop mappings.
8129 */
8130 while ((topmi->depth >= 0) && (topmi->depth >= depth))
8131 topmi = topmi->prev;
8132 /*
8133 * Unshadow.
8134 */
8135 for (mi = nsMap; mi != topmi->next; mi = mi->next)
8136 if (mi->shadowDepth >= depth)
8137 mi->shadowDepth = -1;
8138 }
8139 depth--;
8140 }
8141 if (cur->next != NULL)
8142 cur = cur->next;
8143 else {
8144 cur = cur->parent;
8145 goto next_sibling;
8146 }
8147 } while (cur != NULL);
8148
8149 if (nsMap != NULL)
8150 xmlDOMWrapNSNormFreeNsMap(nsMap);
8151 return (0);
8152internal_error:
8153 if (nsMap != NULL)
8154 xmlDOMWrapNSNormFreeNsMap(nsMap);
8155 return (-1);
8156}
8157
8158/*
8159* xmlDOMWrapAdoptBranch:
8160* @ctxt: the optional context for custom processing
8161* @sourceDoc: the optional sourceDoc
8162* @node: the element-node to start with
8163* @destDoc: the destination doc for adoption
8164* @parent: the optional new parent of @node in @destDoc
8165* @options: option flags
8166*
8167* Ensures that ns-references point to @destDoc: either to
8168* elements->nsDef entries if @destParent is given, or to
8169* @destDoc->oldNs otherwise.
8170* If @destParent is given, it ensures that the tree is namespace
8171* wellformed by creating additional ns-decls where needed.
8172* Note that, since prefixes of already existent ns-decls can be
8173* shadowed by this process, it could break QNames in attribute
8174* values or element content.
8175*
8176* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8177*/
8178static int
8179xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
8180 xmlDocPtr sourceDoc,
8181 xmlNodePtr node,
8182 xmlDocPtr destDoc,
8183 xmlNodePtr destParent,
8184 int options ATTRIBUTE_UNUSED)
8185{
8186 int ret = 0;
8187 xmlNodePtr cur, curElem = NULL;
8188 xmlNsMapItemPtr nsMap = NULL, topmi = NULL, mi;
8189 xmlNsPtr ns;
8190 int depth = -1, adoptStr = 1;
8191 /* gather @parent's ns-decls. */
8192 int parnsdone = 0;
8193 /* @ancestorsOnly should be set per option. */
8194 int ancestorsOnly = 0;
8195
8196 /*
8197 * Optimize string adoption for equal or none dicts.
8198 */
8199 if ((sourceDoc != NULL) &&
8200 (sourceDoc->dict == destDoc->dict))
8201 adoptStr = 0;
8202 else
8203 adoptStr = 1;
8204
8205 cur = node;
8206 while (cur != NULL) {
8207 if (cur->doc != sourceDoc) {
8208 /*
8209 * We'll assume XIncluded nodes if the doc differs.
8210 * TODO: Do we need to reconciliate XIncluded nodes?
8211 * This here skips XIncluded nodes and tries to handle
8212 * broken sequences.
8213 */
8214 if (cur->next == NULL)
8215 goto leave_node;
8216 do {
8217 cur = cur->next;
8218 if ((cur->type == XML_XINCLUDE_END) ||
8219 (cur->doc == node->doc))
8220 break;
8221 } while (cur->next != NULL);
8222
8223 if (cur->doc != node->doc)
8224 goto leave_node;
8225 }
8226 cur->doc = destDoc;
8227 switch (cur->type) {
8228 case XML_XINCLUDE_START:
8229 case XML_XINCLUDE_END:
8230 /*
8231 * TODO
8232 */
8233 return (-1);
8234 case XML_ELEMENT_NODE:
8235 curElem = cur;
8236 depth++;
8237 /*
8238 * Namespace declarations.
8239 */
8240 if ((ctxt == NULL) && (cur->nsDef != NULL)) {
8241 if (! parnsdone) {
8242 if (destParent && (ctxt == NULL)) {
8243 /*
8244 * Gather @parent's in-scope ns-decls.
8245 */
8246 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8247 destParent) == -1)
8248 goto internal_error;
8249 if (nsMap != NULL)
8250 topmi = nsMap->prev;
8251 }
8252 parnsdone = 1;
8253 }
8254 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8255 /*
8256 * ns->prefix and ns->href seem not to be in the dict.
8257 * XML_TREE_ADOPT_STR(ns->prefix)
8258 * XML_TREE_ADOPT_STR(ns->href)
8259 */
8260 /*
8261 * Does it shadow any ns-decl?
8262 */
8263 if (nsMap) {
8264 for (mi = nsMap; mi != topmi->next;
8265 mi = mi->next) {
8266 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8267 (mi->shadowDepth == -1) &&
8268 ((ns->prefix == mi->newNs->prefix) ||
8269 xmlStrEqual(ns->prefix,
8270 mi->newNs->prefix))) {
8271
8272 mi->shadowDepth = depth;
8273 }
8274 }
8275 }
8276 /*
8277 * Push mapping.
8278 */
8279 if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi,
8280 ns, ns, depth) == NULL)
8281 goto internal_error;
8282 }
8283 }
8284 /* No break on purpose. */
8285 case XML_ATTRIBUTE_NODE:
8286
8287 if (cur->ns == NULL)
8288 goto ns_end;
8289 if (! parnsdone) {
8290 if (destParent && (ctxt == NULL)) {
8291 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8292 destParent) == -1)
8293 goto internal_error;
8294 if (nsMap != NULL)
8295 topmi = nsMap->prev;
8296 }
8297 parnsdone = 1;
8298 }
8299 /*
8300 * Adopt ns-references.
8301 */
8302 if (nsMap != NULL) {
8303 /*
8304 * Search for a mapping.
8305 */
8306 for (mi = nsMap; mi != topmi->next; mi = mi->next) {
8307 if ((mi->shadowDepth == -1) &&
8308 (cur->ns == mi->oldNs)) {
8309
8310 cur->ns = mi->newNs;
8311 goto ns_end;
8312 }
8313 }
8314 }
8315 /*
8316 * Start searching for an in-scope ns-decl.
8317 */
8318 if (ctxt != NULL) {
8319 /*
8320 * User-defined behaviour.
8321 */
8322#if 0
8323 ctxt->aquireNsDecl(ctxt, cur->ns, &ns);
8324#endif
8325 /*
8326 * Insert mapping if ns is available; it's the users fault
8327 * if not.
8328 */
8329 if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi,
8330 ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
8331 goto internal_error;
8332 cur->ns = ns;
8333 } else {
8334 /*
8335 * Aquire a normalized ns-decl and add it to the map.
8336 */
8337 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
8338 /* ns-decls on curElem or on destDoc->oldNs */
8339 destParent ? curElem : NULL,
8340 cur->ns, &ns,
8341 &nsMap, &topmi, depth,
8342 ancestorsOnly,
8343 /* ns-decls must be prefixed for attributes. */
8344 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8345 goto internal_error;
8346 cur->ns = ns;
8347 }
8348ns_end:
8349 /*
8350 * Further node properties.
8351 * TODO: Is this all?
8352 */
8353 XML_TREE_ADOPT_STR(cur->name)
8354 if (cur->type == XML_ELEMENT_NODE) {
8355 cur->psvi = NULL;
8356 cur->line = 0;
8357 cur->extra = 0;
8358 /*
8359 * Walk attributes.
8360 */
8361 if (cur->properties != NULL) {
8362 /*
8363 * Process first attribute node.
8364 */
8365 cur = (xmlNodePtr) cur->properties;
8366 continue;
8367 }
8368 } else {
8369 /*
8370 * Attributes.
8371 */
8372 if ((sourceDoc != NULL) &&
8373 (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID))
8374 xmlRemoveID(sourceDoc, (xmlAttrPtr) cur);
8375 ((xmlAttrPtr) cur)->atype = 0;
8376 ((xmlAttrPtr) cur)->psvi = NULL;
8377 }
8378 break;
8379 case XML_TEXT_NODE:
8380 case XML_CDATA_SECTION_NODE:
8381 /*
8382 * This puts the content in the dest dict, only if
8383 * it was previously in the source dict.
8384 */
8385 XML_TREE_ADOPT_STR_2(cur->content)
8386 goto leave_node;
8387 case XML_ENTITY_REF_NODE:
8388 /*
8389 * Remove reference to the entitity-node.
8390 */
8391 cur->content = NULL;
8392 cur->children = NULL;
8393 cur->last = NULL;
8394 if ((destDoc->intSubset) || (destDoc->extSubset)) {
8395 xmlEntityPtr ent;
8396 /*
8397 * Assign new entity-node if available.
8398 */
8399 ent = xmlGetDocEntity(destDoc, cur->name);
8400 if (ent != NULL) {
8401 cur->content = ent->content;
8402 cur->children = (xmlNodePtr) ent;
8403 cur->last = (xmlNodePtr) ent;
8404 }
8405 }
8406 goto leave_node;
8407 case XML_PI_NODE:
8408 XML_TREE_ADOPT_STR(cur->name)
8409 XML_TREE_ADOPT_STR_2(cur->content)
8410 break;
8411 case XML_COMMENT_NODE:
8412 break;
8413 default:
8414 goto internal_error;
8415 }
8416 /*
8417 * Walk the tree.
8418 */
8419 if (cur->children != NULL) {
8420 cur = cur->children;
8421 continue;
8422 }
8423
8424leave_node:
8425 if (cur == node)
8426 break;
8427 if ((cur->type == XML_ELEMENT_NODE) ||
8428 (cur->type == XML_XINCLUDE_START) ||
8429 (cur->type == XML_XINCLUDE_END)) {
8430 /*
8431 * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
8432 */
8433 if (nsMap != NULL) {
8434 /*
8435 * Pop mappings.
8436 */
8437 while (topmi->depth >= depth)
8438 topmi = topmi->prev;
8439 /*
8440 * Unshadow.
8441 */
8442 for (mi = nsMap; mi != topmi->next; mi = mi->next)
8443 if (mi->shadowDepth >= depth)
8444 mi->shadowDepth = -1;
8445 }
8446 depth--;
8447 }
8448 if (cur->next != NULL)
8449 cur = cur->next;
8450 else {
8451 cur = cur->parent;
8452 goto leave_node;
8453 }
8454 }
8455 /*
8456 * Cleanup.
8457 */
8458 if (nsMap != NULL)
8459 xmlDOMWrapNSNormFreeNsMap(nsMap);
8460 return (ret);
8461internal_error:
8462 if (nsMap != NULL)
8463 xmlDOMWrapNSNormFreeNsMap(nsMap);
8464 return (-1);
8465}
8466
8467/*
8468* xmlDOMWrapAdoptAttr:
8469* @ctxt: the optional context for custom processing
8470* @sourceDoc: the optional source document of attr
8471* @attr: the attribute-node to be adopted
8472* @destDoc: the destination doc for adoption
8473* @destParent: the optional new parent of @attr in @destDoc
8474* @options: option flags
8475*
8476* @attr is adopted by @destDoc.
8477* Ensures that ns-references point to @destDoc: either to
8478* elements->nsDef entries if @destParent is given, or to
8479* @destDoc->oldNs otherwise.
8480*
8481* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8482*/
8483static int
8484xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt,
8485 xmlDocPtr sourceDoc,
8486 xmlAttrPtr attr,
8487 xmlDocPtr destDoc,
8488 xmlNodePtr destParent,
8489 int options ATTRIBUTE_UNUSED)
8490{
8491 xmlNodePtr cur;
8492 int adoptStr = 1;
8493
8494 if ((attr == NULL) || (destDoc == NULL))
8495 return (-1);
8496
8497 attr->doc = destDoc;
8498 if (attr->ns != NULL) {
8499 xmlNsPtr ns = NULL;
8500
8501 if (ctxt != NULL) {
8502 /* TODO: User defined. */
8503 }
8504 /* XML Namespace. */
8505 if ((attr->ns->prefix[0] == 'x') && (attr->ns->prefix[1] == 'm') &&
8506 (attr->ns->prefix[2] == 'l') && (attr->ns->prefix[3] == 0)) {
8507 ns = xmlTreeEnsureXMLDecl(destDoc);
8508 } else if (destParent == NULL) {
8509 /*
8510 * Store in @destDoc->oldNs.
8511 */
8512 ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix);
8513 } else {
8514 /*
8515 * Declare on @destParent.
8516 */
8517 if (xmlSearchNsByHrefStrict(destDoc, destParent, attr->ns->href,
8518 &ns, 1) == -1)
8519 goto internal_error;
8520 if (ns == NULL) {
8521 ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent,
8522 attr->ns->href, attr->ns->prefix, 1);
8523 }
8524 }
8525 if (ns == NULL)
8526 goto internal_error;
8527 attr->ns = ns;
8528 }
8529
8530 XML_TREE_ADOPT_STR(attr->name);
8531 attr->atype = 0;
8532 attr->psvi = NULL;
8533 /*
8534 * Walk content.
8535 */
8536 if (attr->children == NULL)
8537 return (0);
8538 cur = attr->children;
8539 while (cur != NULL) {
8540 cur->doc = destDoc;
8541 switch (cur->type) {
8542 case XML_TEXT_NODE:
8543 case XML_CDATA_SECTION_NODE:
8544 XML_TREE_ADOPT_STR_2(cur->content)
8545 break;
8546 case XML_ENTITY_REF_NODE:
8547 /*
8548 * Remove reference to the entitity-node.
8549 */
8550 cur->content = NULL;
8551 cur->children = NULL;
8552 cur->last = NULL;
8553 if ((destDoc->intSubset) || (destDoc->extSubset)) {
8554 xmlEntityPtr ent;
8555 /*
8556 * Assign new entity-node if available.
8557 */
8558 ent = xmlGetDocEntity(destDoc, cur->name);
8559 if (ent != NULL) {
8560 cur->content = ent->content;
8561 cur->children = (xmlNodePtr) ent;
8562 cur->last = (xmlNodePtr) ent;
8563 }
8564 }
8565 break;
8566 default:
8567 break;
8568 }
8569 if (cur->children != NULL) {
8570 cur = cur->children;
8571 continue;
8572 }
8573next_sibling:
8574 if (cur == (xmlNodePtr) attr)
8575 break;
8576 if (cur->next != NULL)
8577 cur = cur->next;
8578 else {
8579 cur = cur->parent;
8580 goto next_sibling;
8581 }
8582 }
8583 return (0);
8584internal_error:
8585 return (-1);
8586}
8587
8588/*
8589* xmlDOMWrapAdoptNode:
8590* @ctxt: the optional context for custom processing
8591* @sourceDoc: the optional sourceDoc
8592* @node: the node to start with
8593* @destDoc: the destination doc
Kasimier T. Buchcik4d9c9482005-06-27 15:04:46 +00008594* @destParent: the optional new parent of @node in @destDoc
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008595* @options: option flags
8596*
8597* Ensures that ns-references point to @destDoc: either to
8598* elements->nsDef entries if @destParent is given, or to
8599* @destDoc->oldNs otherwise.
8600* If @destParent is given, it ensures that the tree is namespace
8601* wellformed by creating additional ns-decls where needed.
8602* Note that, since prefixes of already existent ns-decls can be
8603* shadowed by this process, it could break QNames in attribute
8604* values or element content.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00008605* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008606*
8607* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8608*/
8609int
8610xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt,
8611 xmlDocPtr sourceDoc,
8612 xmlNodePtr node,
8613 xmlDocPtr destDoc,
8614 xmlNodePtr destParent,
8615 int options)
8616{
8617 if ((node == NULL) || (destDoc == NULL) ||
8618 ((destParent != NULL) && (destParent->doc != destDoc)))
8619 return(-1);
8620 /*
8621 * Check node->doc sanity.
8622 */
8623 if ((node->doc != NULL) && (sourceDoc != NULL) &&
8624 (node->doc != sourceDoc)) {
8625 /*
8626 * Might be an XIncluded node.
8627 */
8628 return (-1);
8629 }
8630 if (sourceDoc == NULL)
8631 sourceDoc = node->doc;
8632 if (sourceDoc == destDoc)
8633 return (-1);
8634 switch (node->type) {
8635 case XML_ELEMENT_NODE:
8636 case XML_ATTRIBUTE_NODE:
8637 case XML_TEXT_NODE:
8638 case XML_CDATA_SECTION_NODE:
8639 case XML_ENTITY_REF_NODE:
8640 case XML_PI_NODE:
8641 case XML_COMMENT_NODE:
8642 break;
8643 case XML_DOCUMENT_FRAG_NODE:
8644 return (2);
8645 default:
8646 return (1);
8647 }
8648 /*
8649 * Unlink only if @node was not already added to @destParent.
8650 */
8651 if ((node->parent != NULL) && (destParent != node->parent))
8652 xmlUnlinkNode(node);
8653
8654 if (node->type == XML_ELEMENT_NODE) {
8655 return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node,
8656 destDoc, destParent, options));
8657 } else if (node->type == XML_ATTRIBUTE_NODE) {
8658 return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc,
8659 (xmlAttrPtr) node, destDoc, destParent, options));
8660 } else {
8661 xmlNodePtr cur = node;
8662 int adoptStr = 1;
8663
8664 cur->doc = destDoc;
8665 /*
8666 * Optimize string adoption.
8667 */
8668 if ((sourceDoc != NULL) &&
8669 (sourceDoc->dict == destDoc->dict))
8670 adoptStr = 0;
8671 switch (node->type) {
8672 case XML_TEXT_NODE:
8673 case XML_CDATA_SECTION_NODE:
8674 XML_TREE_ADOPT_STR_2(node->content)
8675 break;
8676 case XML_ENTITY_REF_NODE:
8677 /*
8678 * Remove reference to the entitity-node.
8679 */
8680 node->content = NULL;
8681 node->children = NULL;
8682 node->last = NULL;
8683 if ((destDoc->intSubset) || (destDoc->extSubset)) {
8684 xmlEntityPtr ent;
8685 /*
8686 * Assign new entity-node if available.
8687 */
8688 ent = xmlGetDocEntity(destDoc, node->name);
8689 if (ent != NULL) {
8690 node->content = ent->content;
8691 node->children = (xmlNodePtr) ent;
8692 node->last = (xmlNodePtr) ent;
8693 }
8694 }
8695 XML_TREE_ADOPT_STR(node->name)
8696 break;
Daniel Veillard7e21fd12005-07-03 21:44:07 +00008697 case XML_PI_NODE: {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008698 XML_TREE_ADOPT_STR(node->name)
8699 XML_TREE_ADOPT_STR_2(node->content)
8700 break;
Daniel Veillard7e21fd12005-07-03 21:44:07 +00008701 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008702 default:
8703 break;
8704 }
8705 }
8706 return (0);
8707}
8708
8709
Daniel Veillard5d4644e2005-04-01 13:11:58 +00008710#define bottom_tree
8711#include "elfgcchack.h"