blob: fa7785b43e8b1fc56e1bf5757894be1f3ba86aa7 [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
Daniel Veillard54f9a4f2005-09-03 13:28:24 +0000300 * to the start of the name without the prefix
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000301 */
302
303const xmlChar *
304xmlSplitQName3(const xmlChar *name, int *len) {
305 int l = 0;
306
307 if (name == NULL) return(NULL);
308 if (len == NULL) return(NULL);
309
310 /* nasty but valid */
311 if (name[0] == ':')
312 return(NULL);
313
314 /*
315 * we are not trying to validate but just to cut, and yes it will
316 * work even if this is as set of UTF-8 encoded chars
317 */
318 while ((name[l] != 0) && (name[l] != ':'))
319 l++;
320
321 if (name[l] == 0)
322 return(NULL);
323
324 *len = l;
325
326 return(&name[l+1]);
327}
328
Daniel Veillardc00cda82003-04-07 10:22:39 +0000329/************************************************************************
330 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000331 * Check Name, NCName and QName strings *
332 * *
333 ************************************************************************/
334
335#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
336
Daniel Veillard6b6d6802005-07-03 21:00:34 +0000337#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 +0000338/**
339 * xmlValidateNCName:
340 * @value: the value to check
341 * @space: allow spaces in front and end of the string
342 *
343 * Check that a value conforms to the lexical space of NCName
344 *
345 * Returns 0 if this validates, a positive error code number otherwise
346 * and -1 in case of internal or API error.
347 */
348int
349xmlValidateNCName(const xmlChar *value, int space) {
350 const xmlChar *cur = value;
351 int c,l;
352
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000353 if (value == NULL)
354 return(-1);
355
Daniel Veillardd2298792003-02-14 16:54:11 +0000356 /*
357 * First quick algorithm for ASCII range
358 */
359 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000360 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000361 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
362 (*cur == '_'))
363 cur++;
364 else
365 goto try_complex;
366 while (((*cur >= 'a') && (*cur <= 'z')) ||
367 ((*cur >= 'A') && (*cur <= 'Z')) ||
368 ((*cur >= '0') && (*cur <= '9')) ||
369 (*cur == '_') || (*cur == '-') || (*cur == '.'))
370 cur++;
371 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000372 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000373 if (*cur == 0)
374 return(0);
375
376try_complex:
377 /*
378 * Second check for chars outside the ASCII range
379 */
380 cur = value;
381 c = CUR_SCHAR(cur, l);
382 if (space) {
383 while (IS_BLANK(c)) {
384 cur += l;
385 c = CUR_SCHAR(cur, l);
386 }
387 }
William M. Brack871611b2003-10-18 04:53:14 +0000388 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000389 return(1);
390 cur += l;
391 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000392 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
393 (c == '-') || (c == '_') || IS_COMBINING(c) ||
394 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000395 cur += l;
396 c = CUR_SCHAR(cur, l);
397 }
398 if (space) {
399 while (IS_BLANK(c)) {
400 cur += l;
401 c = CUR_SCHAR(cur, l);
402 }
403 }
404 if (c != 0)
405 return(1);
406
407 return(0);
408}
Daniel Veillard2156d432004-03-04 15:59:36 +0000409#endif
Daniel Veillardd2298792003-02-14 16:54:11 +0000410
Daniel Veillard2156d432004-03-04 15:59:36 +0000411#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000412/**
413 * xmlValidateQName:
414 * @value: the value to check
415 * @space: allow spaces in front and end of the string
416 *
417 * Check that a value conforms to the lexical space of QName
418 *
419 * Returns 0 if this validates, a positive error code number otherwise
420 * and -1 in case of internal or API error.
421 */
422int
423xmlValidateQName(const xmlChar *value, int space) {
424 const xmlChar *cur = value;
425 int c,l;
426
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000427 if (value == NULL)
428 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +0000429 /*
430 * First quick algorithm for ASCII range
431 */
432 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000433 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000434 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
435 (*cur == '_'))
436 cur++;
437 else
438 goto try_complex;
439 while (((*cur >= 'a') && (*cur <= 'z')) ||
440 ((*cur >= 'A') && (*cur <= 'Z')) ||
441 ((*cur >= '0') && (*cur <= '9')) ||
442 (*cur == '_') || (*cur == '-') || (*cur == '.'))
443 cur++;
444 if (*cur == ':') {
445 cur++;
446 if (((*cur >= 'a') && (*cur <= 'z')) ||
447 ((*cur >= 'A') && (*cur <= 'Z')) ||
448 (*cur == '_'))
449 cur++;
450 else
451 goto try_complex;
452 while (((*cur >= 'a') && (*cur <= 'z')) ||
453 ((*cur >= 'A') && (*cur <= 'Z')) ||
454 ((*cur >= '0') && (*cur <= '9')) ||
455 (*cur == '_') || (*cur == '-') || (*cur == '.'))
456 cur++;
457 }
458 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000459 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000460 if (*cur == 0)
461 return(0);
462
463try_complex:
464 /*
465 * Second check for chars outside the ASCII range
466 */
467 cur = value;
468 c = CUR_SCHAR(cur, l);
469 if (space) {
470 while (IS_BLANK(c)) {
471 cur += l;
472 c = CUR_SCHAR(cur, l);
473 }
474 }
William M. Brack871611b2003-10-18 04:53:14 +0000475 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000476 return(1);
477 cur += l;
478 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000479 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
480 (c == '-') || (c == '_') || IS_COMBINING(c) ||
481 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000482 cur += l;
483 c = CUR_SCHAR(cur, l);
484 }
485 if (c == ':') {
486 cur += l;
487 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000488 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000489 return(1);
490 cur += l;
491 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000492 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
493 (c == '-') || (c == '_') || IS_COMBINING(c) ||
494 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000495 cur += l;
496 c = CUR_SCHAR(cur, l);
497 }
498 }
499 if (space) {
500 while (IS_BLANK(c)) {
501 cur += l;
502 c = CUR_SCHAR(cur, l);
503 }
504 }
505 if (c != 0)
506 return(1);
507 return(0);
508}
509
510/**
511 * xmlValidateName:
512 * @value: the value to check
513 * @space: allow spaces in front and end of the string
514 *
515 * Check that a value conforms to the lexical space of Name
516 *
517 * Returns 0 if this validates, a positive error code number otherwise
518 * and -1 in case of internal or API error.
519 */
520int
521xmlValidateName(const xmlChar *value, int space) {
522 const xmlChar *cur = value;
523 int c,l;
524
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000525 if (value == NULL)
526 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +0000527 /*
528 * First quick algorithm for ASCII range
529 */
530 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000531 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000532 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
533 (*cur == '_') || (*cur == ':'))
534 cur++;
535 else
536 goto try_complex;
537 while (((*cur >= 'a') && (*cur <= 'z')) ||
538 ((*cur >= 'A') && (*cur <= 'Z')) ||
539 ((*cur >= '0') && (*cur <= '9')) ||
540 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
541 cur++;
542 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000543 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000544 if (*cur == 0)
545 return(0);
546
547try_complex:
548 /*
549 * Second check for chars outside the ASCII range
550 */
551 cur = value;
552 c = CUR_SCHAR(cur, l);
553 if (space) {
554 while (IS_BLANK(c)) {
555 cur += l;
556 c = CUR_SCHAR(cur, l);
557 }
558 }
William M. Brack871611b2003-10-18 04:53:14 +0000559 if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000560 return(1);
561 cur += l;
562 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000563 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
564 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000565 cur += l;
566 c = CUR_SCHAR(cur, l);
567 }
568 if (space) {
569 while (IS_BLANK(c)) {
570 cur += l;
571 c = CUR_SCHAR(cur, l);
572 }
573 }
574 if (c != 0)
575 return(1);
576 return(0);
577}
578
Daniel Veillardd4310742003-02-18 21:12:46 +0000579/**
580 * xmlValidateNMToken:
581 * @value: the value to check
582 * @space: allow spaces in front and end of the string
583 *
584 * Check that a value conforms to the lexical space of NMToken
585 *
586 * Returns 0 if this validates, a positive error code number otherwise
587 * and -1 in case of internal or API error.
588 */
589int
590xmlValidateNMToken(const xmlChar *value, int space) {
591 const xmlChar *cur = value;
592 int c,l;
593
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000594 if (value == NULL)
595 return(-1);
Daniel Veillardd4310742003-02-18 21:12:46 +0000596 /*
597 * First quick algorithm for ASCII range
598 */
599 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000600 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000601 if (((*cur >= 'a') && (*cur <= 'z')) ||
602 ((*cur >= 'A') && (*cur <= 'Z')) ||
603 ((*cur >= '0') && (*cur <= '9')) ||
604 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
605 cur++;
606 else
607 goto try_complex;
608 while (((*cur >= 'a') && (*cur <= 'z')) ||
609 ((*cur >= 'A') && (*cur <= 'Z')) ||
610 ((*cur >= '0') && (*cur <= '9')) ||
611 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
612 cur++;
613 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000614 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000615 if (*cur == 0)
616 return(0);
617
618try_complex:
619 /*
620 * Second check for chars outside the ASCII range
621 */
622 cur = value;
623 c = CUR_SCHAR(cur, l);
624 if (space) {
625 while (IS_BLANK(c)) {
626 cur += l;
627 c = CUR_SCHAR(cur, l);
628 }
629 }
William M. Brack871611b2003-10-18 04:53:14 +0000630 if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
631 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
Daniel Veillardd4310742003-02-18 21:12:46 +0000632 return(1);
633 cur += l;
634 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000635 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
636 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd4310742003-02-18 21:12:46 +0000637 cur += l;
638 c = CUR_SCHAR(cur, l);
639 }
640 if (space) {
641 while (IS_BLANK(c)) {
642 cur += l;
643 c = CUR_SCHAR(cur, l);
644 }
645 }
646 if (c != 0)
647 return(1);
648 return(0);
649}
Daniel Veillard652327a2003-09-29 18:02:38 +0000650#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardd4310742003-02-18 21:12:46 +0000651
Daniel Veillardd2298792003-02-14 16:54:11 +0000652/************************************************************************
653 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000654 * Allocation and deallocation of basic structures *
655 * *
656 ************************************************************************/
657
658/**
659 * xmlSetBufferAllocationScheme:
660 * @scheme: allocation method to use
661 *
662 * Set the buffer allocation method. Types are
663 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
664 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
665 * improves performance
666 */
667void
668xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
669 xmlBufferAllocScheme = scheme;
670}
671
672/**
673 * xmlGetBufferAllocationScheme:
674 *
675 * Types are
676 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
677 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
678 * improves performance
679 *
680 * Returns the current allocation scheme
681 */
682xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000683xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000684 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000685}
686
687/**
688 * xmlNewNs:
689 * @node: the element carrying the namespace
690 * @href: the URI associated
691 * @prefix: the prefix for the namespace
692 *
693 * Creation of a new Namespace. This function will refuse to create
694 * a namespace with a similar prefix than an existing one present on this
695 * node.
696 * We use href==NULL in the case of an element creation where the namespace
697 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000698 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000699 */
700xmlNsPtr
701xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
702 xmlNsPtr cur;
703
704 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
705 return(NULL);
706
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000707 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
708 return(NULL);
709
Owen Taylor3473f882001-02-23 17:55:21 +0000710 /*
711 * Allocate a new Namespace and fill the fields.
712 */
713 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
714 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000715 xmlTreeErrMemory("building namespace");
Owen Taylor3473f882001-02-23 17:55:21 +0000716 return(NULL);
717 }
718 memset(cur, 0, sizeof(xmlNs));
719 cur->type = XML_LOCAL_NAMESPACE;
720
721 if (href != NULL)
722 cur->href = xmlStrdup(href);
723 if (prefix != NULL)
724 cur->prefix = xmlStrdup(prefix);
725
726 /*
727 * Add it at the end to preserve parsing order ...
728 * and checks for existing use of the prefix
729 */
730 if (node != NULL) {
731 if (node->nsDef == NULL) {
732 node->nsDef = cur;
733 } else {
734 xmlNsPtr prev = node->nsDef;
735
736 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
737 (xmlStrEqual(prev->prefix, cur->prefix))) {
738 xmlFreeNs(cur);
739 return(NULL);
740 }
741 while (prev->next != NULL) {
742 prev = prev->next;
743 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
744 (xmlStrEqual(prev->prefix, cur->prefix))) {
745 xmlFreeNs(cur);
746 return(NULL);
747 }
748 }
749 prev->next = cur;
750 }
751 }
752 return(cur);
753}
754
755/**
756 * xmlSetNs:
757 * @node: a node in the document
758 * @ns: a namespace pointer
759 *
760 * Associate a namespace to a node, a posteriori.
761 */
762void
763xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
764 if (node == NULL) {
765#ifdef DEBUG_TREE
766 xmlGenericError(xmlGenericErrorContext,
767 "xmlSetNs: node == NULL\n");
768#endif
769 return;
770 }
771 node->ns = ns;
772}
773
774/**
775 * xmlFreeNs:
776 * @cur: the namespace pointer
777 *
778 * Free up the structures associated to a namespace
779 */
780void
781xmlFreeNs(xmlNsPtr cur) {
782 if (cur == NULL) {
783#ifdef DEBUG_TREE
784 xmlGenericError(xmlGenericErrorContext,
785 "xmlFreeNs : ns == NULL\n");
786#endif
787 return;
788 }
789 if (cur->href != NULL) xmlFree((char *) cur->href);
790 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000791 xmlFree(cur);
792}
793
794/**
795 * xmlFreeNsList:
796 * @cur: the first namespace pointer
797 *
798 * Free up all the structures associated to the chained namespaces.
799 */
800void
801xmlFreeNsList(xmlNsPtr cur) {
802 xmlNsPtr next;
803 if (cur == NULL) {
804#ifdef DEBUG_TREE
805 xmlGenericError(xmlGenericErrorContext,
806 "xmlFreeNsList : ns == NULL\n");
807#endif
808 return;
809 }
810 while (cur != NULL) {
811 next = cur->next;
812 xmlFreeNs(cur);
813 cur = next;
814 }
815}
816
817/**
818 * xmlNewDtd:
819 * @doc: the document pointer
820 * @name: the DTD name
821 * @ExternalID: the external ID
822 * @SystemID: the system ID
823 *
824 * Creation of a new DTD for the external subset. To create an
825 * internal subset, use xmlCreateIntSubset().
826 *
827 * Returns a pointer to the new DTD structure
828 */
829xmlDtdPtr
830xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
831 const xmlChar *ExternalID, const xmlChar *SystemID) {
832 xmlDtdPtr cur;
833
834 if ((doc != NULL) && (doc->extSubset != NULL)) {
835#ifdef DEBUG_TREE
836 xmlGenericError(xmlGenericErrorContext,
837 "xmlNewDtd(%s): document %s already have a DTD %s\n",
838 /* !!! */ (char *) name, doc->name,
839 /* !!! */ (char *)doc->extSubset->name);
840#endif
841 return(NULL);
842 }
843
844 /*
845 * Allocate a new DTD and fill the fields.
846 */
847 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
848 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000849 xmlTreeErrMemory("building DTD");
Owen Taylor3473f882001-02-23 17:55:21 +0000850 return(NULL);
851 }
852 memset(cur, 0 , sizeof(xmlDtd));
853 cur->type = XML_DTD_NODE;
854
855 if (name != NULL)
856 cur->name = xmlStrdup(name);
857 if (ExternalID != NULL)
858 cur->ExternalID = xmlStrdup(ExternalID);
859 if (SystemID != NULL)
860 cur->SystemID = xmlStrdup(SystemID);
861 if (doc != NULL)
862 doc->extSubset = cur;
863 cur->doc = doc;
864
Daniel Veillarda880b122003-04-21 21:36:41 +0000865 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000866 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000867 return(cur);
868}
869
870/**
871 * xmlGetIntSubset:
872 * @doc: the document pointer
873 *
874 * Get the internal subset of a document
875 * Returns a pointer to the DTD structure or NULL if not found
876 */
877
878xmlDtdPtr
879xmlGetIntSubset(xmlDocPtr doc) {
880 xmlNodePtr cur;
881
882 if (doc == NULL)
883 return(NULL);
884 cur = doc->children;
885 while (cur != NULL) {
886 if (cur->type == XML_DTD_NODE)
887 return((xmlDtdPtr) cur);
888 cur = cur->next;
889 }
890 return((xmlDtdPtr) doc->intSubset);
891}
892
893/**
894 * xmlCreateIntSubset:
895 * @doc: the document pointer
896 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000897 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000898 * @SystemID: the system ID
899 *
900 * Create the internal subset of a document
901 * Returns a pointer to the new DTD structure
902 */
903xmlDtdPtr
904xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
905 const xmlChar *ExternalID, const xmlChar *SystemID) {
906 xmlDtdPtr cur;
907
908 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
909#ifdef DEBUG_TREE
910 xmlGenericError(xmlGenericErrorContext,
911
912 "xmlCreateIntSubset(): document %s already have an internal subset\n",
913 doc->name);
914#endif
915 return(NULL);
916 }
917
918 /*
919 * Allocate a new DTD and fill the fields.
920 */
921 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
922 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000923 xmlTreeErrMemory("building internal subset");
Owen Taylor3473f882001-02-23 17:55:21 +0000924 return(NULL);
925 }
926 memset(cur, 0, sizeof(xmlDtd));
927 cur->type = XML_DTD_NODE;
928
William M. Bracka3215c72004-07-31 16:24:01 +0000929 if (name != NULL) {
930 cur->name = xmlStrdup(name);
931 if (cur->name == NULL) {
932 xmlTreeErrMemory("building internal subset");
933 xmlFree(cur);
934 return(NULL);
935 }
936 }
937 if (ExternalID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000938 cur->ExternalID = xmlStrdup(ExternalID);
William M. Bracka3215c72004-07-31 16:24:01 +0000939 if (cur->ExternalID == NULL) {
940 xmlTreeErrMemory("building internal subset");
941 if (cur->name != NULL)
942 xmlFree((char *)cur->name);
943 xmlFree(cur);
944 return(NULL);
945 }
946 }
947 if (SystemID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000948 cur->SystemID = xmlStrdup(SystemID);
William M. Bracka3215c72004-07-31 16:24:01 +0000949 if (cur->SystemID == NULL) {
950 xmlTreeErrMemory("building internal subset");
951 if (cur->name != NULL)
952 xmlFree((char *)cur->name);
953 if (cur->ExternalID != NULL)
954 xmlFree((char *)cur->ExternalID);
955 xmlFree(cur);
956 return(NULL);
957 }
958 }
Owen Taylor3473f882001-02-23 17:55:21 +0000959 if (doc != NULL) {
960 doc->intSubset = cur;
961 cur->parent = doc;
962 cur->doc = doc;
963 if (doc->children == NULL) {
964 doc->children = (xmlNodePtr) cur;
965 doc->last = (xmlNodePtr) cur;
966 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000967 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000968 xmlNodePtr prev;
969
Owen Taylor3473f882001-02-23 17:55:21 +0000970 prev = doc->children;
971 prev->prev = (xmlNodePtr) cur;
972 cur->next = prev;
973 doc->children = (xmlNodePtr) cur;
974 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000975 xmlNodePtr next;
976
977 next = doc->children;
978 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
979 next = next->next;
980 if (next == NULL) {
981 cur->prev = doc->last;
982 cur->prev->next = (xmlNodePtr) cur;
983 cur->next = NULL;
984 doc->last = (xmlNodePtr) cur;
985 } else {
986 cur->next = next;
987 cur->prev = next->prev;
988 if (cur->prev == NULL)
989 doc->children = (xmlNodePtr) cur;
990 else
991 cur->prev->next = (xmlNodePtr) cur;
992 next->prev = (xmlNodePtr) cur;
993 }
Owen Taylor3473f882001-02-23 17:55:21 +0000994 }
995 }
996 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000997
Daniel Veillarda880b122003-04-21 21:36:41 +0000998 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000999 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001000 return(cur);
1001}
1002
1003/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001004 * DICT_FREE:
1005 * @str: a string
1006 *
1007 * Free a string if it is not owned by the "dict" dictionnary in the
1008 * current scope
1009 */
1010#define DICT_FREE(str) \
1011 if ((str) && ((!dict) || \
1012 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
1013 xmlFree((char *)(str));
1014
1015/**
Owen Taylor3473f882001-02-23 17:55:21 +00001016 * xmlFreeDtd:
1017 * @cur: the DTD structure to free up
1018 *
1019 * Free a DTD structure.
1020 */
1021void
1022xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001023 xmlDictPtr dict = NULL;
1024
Owen Taylor3473f882001-02-23 17:55:21 +00001025 if (cur == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001026 return;
1027 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001028 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001029
Daniel Veillarda880b122003-04-21 21:36:41 +00001030 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001031 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1032
Owen Taylor3473f882001-02-23 17:55:21 +00001033 if (cur->children != NULL) {
1034 xmlNodePtr next, c = cur->children;
1035
1036 /*
William M. Brack18a04f22004-08-03 16:42:37 +00001037 * Cleanup all nodes which are not part of the specific lists
1038 * of notations, elements, attributes and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00001039 */
1040 while (c != NULL) {
1041 next = c->next;
William M. Brack18a04f22004-08-03 16:42:37 +00001042 if ((c->type != XML_NOTATION_NODE) &&
1043 (c->type != XML_ELEMENT_DECL) &&
1044 (c->type != XML_ATTRIBUTE_DECL) &&
1045 (c->type != XML_ENTITY_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001046 xmlUnlinkNode(c);
1047 xmlFreeNode(c);
1048 }
1049 c = next;
1050 }
1051 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001052 DICT_FREE(cur->name)
1053 DICT_FREE(cur->SystemID)
1054 DICT_FREE(cur->ExternalID)
Owen Taylor3473f882001-02-23 17:55:21 +00001055 /* TODO !!! */
1056 if (cur->notations != NULL)
1057 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1058
1059 if (cur->elements != NULL)
1060 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1061 if (cur->attributes != NULL)
1062 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1063 if (cur->entities != NULL)
1064 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1065 if (cur->pentities != NULL)
1066 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1067
Owen Taylor3473f882001-02-23 17:55:21 +00001068 xmlFree(cur);
1069}
1070
1071/**
1072 * xmlNewDoc:
1073 * @version: xmlChar string giving the version of XML "1.0"
1074 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001075 * Creates a new XML document
1076 *
Owen Taylor3473f882001-02-23 17:55:21 +00001077 * Returns a new document
1078 */
1079xmlDocPtr
1080xmlNewDoc(const xmlChar *version) {
1081 xmlDocPtr cur;
1082
1083 if (version == NULL)
1084 version = (const xmlChar *) "1.0";
1085
1086 /*
1087 * Allocate a new document and fill the fields.
1088 */
1089 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1090 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001091 xmlTreeErrMemory("building doc");
Owen Taylor3473f882001-02-23 17:55:21 +00001092 return(NULL);
1093 }
1094 memset(cur, 0, sizeof(xmlDoc));
1095 cur->type = XML_DOCUMENT_NODE;
1096
1097 cur->version = xmlStrdup(version);
William M. Bracka3215c72004-07-31 16:24:01 +00001098 if (cur->version == NULL) {
1099 xmlTreeErrMemory("building doc");
1100 xmlFree(cur);
1101 return(NULL);
1102 }
Owen Taylor3473f882001-02-23 17:55:21 +00001103 cur->standalone = -1;
1104 cur->compression = -1; /* not initialized */
1105 cur->doc = cur;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001106 /*
1107 * The in memory encoding is always UTF8
1108 * This field will never change and would
1109 * be obsolete if not for binary compatibility.
1110 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001111 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001112
Daniel Veillarda880b122003-04-21 21:36:41 +00001113 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001114 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001115 return(cur);
1116}
1117
1118/**
1119 * xmlFreeDoc:
1120 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001121 *
1122 * Free up all the structures used by a document, tree included.
1123 */
1124void
1125xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001126 xmlDtdPtr extSubset, intSubset;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001127 xmlDictPtr dict = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001128
Owen Taylor3473f882001-02-23 17:55:21 +00001129 if (cur == NULL) {
1130#ifdef DEBUG_TREE
1131 xmlGenericError(xmlGenericErrorContext,
1132 "xmlFreeDoc : document == NULL\n");
1133#endif
1134 return;
1135 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001136#ifdef LIBXML_DEBUG_RUNTIME
Daniel Veillardbca3ad22005-08-23 22:14:02 +00001137#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001138 xmlDebugCheckDocument(stderr, cur);
1139#endif
Daniel Veillardbca3ad22005-08-23 22:14:02 +00001140#endif
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001141
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001142 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001143
Daniel Veillarda880b122003-04-21 21:36:41 +00001144 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001145 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1146
Daniel Veillard76d66f42001-05-16 21:05:17 +00001147 /*
1148 * Do this before freeing the children list to avoid ID lookups
1149 */
1150 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1151 cur->ids = NULL;
1152 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1153 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001154 extSubset = cur->extSubset;
1155 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001156 if (intSubset == extSubset)
1157 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001158 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001159 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001160 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001161 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001162 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001163 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001164 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001165 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001166 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001167 }
1168
1169 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001170 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001171
1172 DICT_FREE(cur->version)
1173 DICT_FREE(cur->name)
1174 DICT_FREE(cur->encoding)
1175 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001176 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001177 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001178}
1179
1180/**
1181 * xmlStringLenGetNodeList:
1182 * @doc: the document
1183 * @value: the value of the text
1184 * @len: the length of the string value
1185 *
1186 * Parse the value string and build the node list associated. Should
1187 * produce a flat tree with only TEXTs and ENTITY_REFs.
1188 * Returns a pointer to the first child
1189 */
1190xmlNodePtr
1191xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1192 xmlNodePtr ret = NULL, last = NULL;
1193 xmlNodePtr node;
1194 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001195 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001196 const xmlChar *q;
1197 xmlEntityPtr ent;
1198
1199 if (value == NULL) return(NULL);
1200
1201 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001202 while ((cur < end) && (*cur != 0)) {
1203 if (cur[0] == '&') {
1204 int charval = 0;
1205 xmlChar tmp;
1206
Owen Taylor3473f882001-02-23 17:55:21 +00001207 /*
1208 * Save the current text.
1209 */
1210 if (cur != q) {
1211 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1212 xmlNodeAddContentLen(last, q, cur - q);
1213 } else {
1214 node = xmlNewDocTextLen(doc, q, cur - q);
1215 if (node == NULL) return(ret);
1216 if (last == NULL)
1217 last = ret = node;
1218 else {
1219 last->next = node;
1220 node->prev = last;
1221 last = node;
1222 }
1223 }
1224 }
Owen Taylor3473f882001-02-23 17:55:21 +00001225 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001226 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1227 cur += 3;
1228 if (cur < end)
1229 tmp = *cur;
1230 else
1231 tmp = 0;
1232 while (tmp != ';') { /* Non input consuming loop */
1233 if ((tmp >= '0') && (tmp <= '9'))
1234 charval = charval * 16 + (tmp - '0');
1235 else if ((tmp >= 'a') && (tmp <= 'f'))
1236 charval = charval * 16 + (tmp - 'a') + 10;
1237 else if ((tmp >= 'A') && (tmp <= 'F'))
1238 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001239 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001240 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1241 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001242 charval = 0;
1243 break;
1244 }
1245 cur++;
1246 if (cur < end)
1247 tmp = *cur;
1248 else
1249 tmp = 0;
1250 }
1251 if (tmp == ';')
1252 cur++;
1253 q = cur;
1254 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1255 cur += 2;
1256 if (cur < end)
1257 tmp = *cur;
1258 else
1259 tmp = 0;
1260 while (tmp != ';') { /* Non input consuming loops */
1261 if ((tmp >= '0') && (tmp <= '9'))
1262 charval = charval * 10 + (tmp - '0');
1263 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001264 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1265 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001266 charval = 0;
1267 break;
1268 }
1269 cur++;
1270 if (cur < end)
1271 tmp = *cur;
1272 else
1273 tmp = 0;
1274 }
1275 if (tmp == ';')
1276 cur++;
1277 q = cur;
1278 } else {
1279 /*
1280 * Read the entity string
1281 */
1282 cur++;
1283 q = cur;
1284 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1285 if ((cur >= end) || (*cur == 0)) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001286 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1287 (const char *) q);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001288 return(ret);
1289 }
1290 if (cur != q) {
1291 /*
1292 * Predefined entities don't generate nodes
1293 */
1294 val = xmlStrndup(q, cur - q);
1295 ent = xmlGetDocEntity(doc, val);
1296 if ((ent != NULL) &&
1297 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1298 if (last == NULL) {
1299 node = xmlNewDocText(doc, ent->content);
1300 last = ret = node;
1301 } else if (last->type != XML_TEXT_NODE) {
1302 node = xmlNewDocText(doc, ent->content);
1303 last = xmlAddNextSibling(last, node);
1304 } else
1305 xmlNodeAddContent(last, ent->content);
1306
1307 } else {
1308 /*
1309 * Create a new REFERENCE_REF node
1310 */
1311 node = xmlNewReference(doc, val);
1312 if (node == NULL) {
1313 if (val != NULL) xmlFree(val);
1314 return(ret);
1315 }
1316 else if ((ent != NULL) && (ent->children == NULL)) {
1317 xmlNodePtr temp;
1318
1319 ent->children = xmlStringGetNodeList(doc,
1320 (const xmlChar*)node->content);
1321 ent->owner = 1;
1322 temp = ent->children;
1323 while (temp) {
1324 temp->parent = (xmlNodePtr)ent;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001325 ent->last = temp;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001326 temp = temp->next;
1327 }
1328 }
1329 if (last == NULL) {
1330 last = ret = node;
1331 } else {
1332 last = xmlAddNextSibling(last, node);
1333 }
1334 }
1335 xmlFree(val);
1336 }
1337 cur++;
1338 q = cur;
1339 }
1340 if (charval != 0) {
1341 xmlChar buf[10];
1342 int l;
1343
1344 l = xmlCopyCharMultiByte(buf, charval);
1345 buf[l] = 0;
1346 node = xmlNewDocText(doc, buf);
1347 if (node != NULL) {
1348 if (last == NULL) {
1349 last = ret = node;
1350 } else {
1351 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001352 }
1353 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001354 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001355 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001356 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001357 cur++;
1358 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001359 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001360 /*
1361 * Handle the last piece of text.
1362 */
1363 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1364 xmlNodeAddContentLen(last, q, cur - q);
1365 } else {
1366 node = xmlNewDocTextLen(doc, q, cur - q);
1367 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001368 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001369 last = ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001370 } else {
1371 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001372 }
1373 }
1374 }
1375 return(ret);
1376}
1377
1378/**
1379 * xmlStringGetNodeList:
1380 * @doc: the document
1381 * @value: the value of the attribute
1382 *
1383 * Parse the value string and build the node list associated. Should
1384 * produce a flat tree with only TEXTs and ENTITY_REFs.
1385 * Returns a pointer to the first child
1386 */
1387xmlNodePtr
1388xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1389 xmlNodePtr ret = NULL, last = NULL;
1390 xmlNodePtr node;
1391 xmlChar *val;
1392 const xmlChar *cur = value;
1393 const xmlChar *q;
1394 xmlEntityPtr ent;
1395
1396 if (value == NULL) return(NULL);
1397
1398 q = cur;
1399 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001400 if (cur[0] == '&') {
1401 int charval = 0;
1402 xmlChar tmp;
1403
Owen Taylor3473f882001-02-23 17:55:21 +00001404 /*
1405 * Save the current text.
1406 */
1407 if (cur != q) {
1408 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1409 xmlNodeAddContentLen(last, q, cur - q);
1410 } else {
1411 node = xmlNewDocTextLen(doc, q, cur - q);
1412 if (node == NULL) return(ret);
1413 if (last == NULL)
1414 last = ret = node;
1415 else {
1416 last->next = node;
1417 node->prev = last;
1418 last = node;
1419 }
1420 }
1421 }
Owen Taylor3473f882001-02-23 17:55:21 +00001422 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001423 if ((cur[1] == '#') && (cur[2] == 'x')) {
1424 cur += 3;
1425 tmp = *cur;
1426 while (tmp != ';') { /* Non input consuming loop */
1427 if ((tmp >= '0') && (tmp <= '9'))
1428 charval = charval * 16 + (tmp - '0');
1429 else if ((tmp >= 'a') && (tmp <= 'f'))
1430 charval = charval * 16 + (tmp - 'a') + 10;
1431 else if ((tmp >= 'A') && (tmp <= 'F'))
1432 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001433 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001434 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1435 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001436 charval = 0;
1437 break;
1438 }
1439 cur++;
1440 tmp = *cur;
1441 }
1442 if (tmp == ';')
1443 cur++;
1444 q = cur;
1445 } else if (cur[1] == '#') {
1446 cur += 2;
1447 tmp = *cur;
1448 while (tmp != ';') { /* Non input consuming loops */
1449 if ((tmp >= '0') && (tmp <= '9'))
1450 charval = charval * 10 + (tmp - '0');
1451 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001452 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1453 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001454 charval = 0;
1455 break;
1456 }
1457 cur++;
1458 tmp = *cur;
1459 }
1460 if (tmp == ';')
1461 cur++;
1462 q = cur;
1463 } else {
1464 /*
1465 * Read the entity string
1466 */
1467 cur++;
1468 q = cur;
1469 while ((*cur != 0) && (*cur != ';')) cur++;
1470 if (*cur == 0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001471 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1472 (xmlNodePtr) doc, (const char *) q);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001473 return(ret);
1474 }
1475 if (cur != q) {
1476 /*
1477 * Predefined entities don't generate nodes
1478 */
1479 val = xmlStrndup(q, cur - q);
1480 ent = xmlGetDocEntity(doc, val);
1481 if ((ent != NULL) &&
1482 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1483 if (last == NULL) {
1484 node = xmlNewDocText(doc, ent->content);
1485 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001486 } else if (last->type != XML_TEXT_NODE) {
1487 node = xmlNewDocText(doc, ent->content);
1488 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001489 } else
1490 xmlNodeAddContent(last, ent->content);
1491
1492 } else {
1493 /*
1494 * Create a new REFERENCE_REF node
1495 */
1496 node = xmlNewReference(doc, val);
1497 if (node == NULL) {
1498 if (val != NULL) xmlFree(val);
1499 return(ret);
1500 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001501 else if ((ent != NULL) && (ent->children == NULL)) {
1502 xmlNodePtr temp;
1503
1504 ent->children = xmlStringGetNodeList(doc,
1505 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001506 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001507 temp = ent->children;
1508 while (temp) {
1509 temp->parent = (xmlNodePtr)ent;
1510 temp = temp->next;
1511 }
1512 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001513 if (last == NULL) {
1514 last = ret = node;
1515 } else {
1516 last = xmlAddNextSibling(last, node);
1517 }
1518 }
1519 xmlFree(val);
1520 }
1521 cur++;
1522 q = cur;
1523 }
1524 if (charval != 0) {
1525 xmlChar buf[10];
1526 int len;
1527
1528 len = xmlCopyCharMultiByte(buf, charval);
1529 buf[len] = 0;
1530 node = xmlNewDocText(doc, buf);
1531 if (node != NULL) {
1532 if (last == NULL) {
1533 last = ret = node;
1534 } else {
1535 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001536 }
1537 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001538
1539 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001540 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001541 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001542 cur++;
1543 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001544 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001545 /*
1546 * Handle the last piece of text.
1547 */
1548 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1549 xmlNodeAddContentLen(last, q, cur - q);
1550 } else {
1551 node = xmlNewDocTextLen(doc, q, cur - q);
1552 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001553 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001554 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001555 } else {
1556 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001557 }
1558 }
1559 }
1560 return(ret);
1561}
1562
1563/**
1564 * xmlNodeListGetString:
1565 * @doc: the document
1566 * @list: a Node list
1567 * @inLine: should we replace entity contents or show their external form
1568 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001569 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001570 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001571 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001572 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001573 */
1574xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001575xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1576{
Owen Taylor3473f882001-02-23 17:55:21 +00001577 xmlNodePtr node = list;
1578 xmlChar *ret = NULL;
1579 xmlEntityPtr ent;
1580
Daniel Veillard7646b182002-04-20 06:41:40 +00001581 if (list == NULL)
1582 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001583
1584 while (node != NULL) {
1585 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001586 (node->type == XML_CDATA_SECTION_NODE)) {
1587 if (inLine) {
1588 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001589 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001590 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001591
Daniel Veillard7646b182002-04-20 06:41:40 +00001592 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1593 if (buffer != NULL) {
1594 ret = xmlStrcat(ret, buffer);
1595 xmlFree(buffer);
1596 }
1597 }
1598 } else if (node->type == XML_ENTITY_REF_NODE) {
1599 if (inLine) {
1600 ent = xmlGetDocEntity(doc, node->name);
1601 if (ent != NULL) {
1602 xmlChar *buffer;
1603
1604 /* an entity content can be any "well balanced chunk",
1605 * i.e. the result of the content [43] production:
1606 * http://www.w3.org/TR/REC-xml#NT-content.
1607 * So it can contain text, CDATA section or nested
1608 * entity reference nodes (among others).
1609 * -> we recursive call xmlNodeListGetString()
1610 * which handles these types */
1611 buffer = xmlNodeListGetString(doc, ent->children, 1);
1612 if (buffer != NULL) {
1613 ret = xmlStrcat(ret, buffer);
1614 xmlFree(buffer);
1615 }
1616 } else {
1617 ret = xmlStrcat(ret, node->content);
1618 }
1619 } else {
1620 xmlChar buf[2];
1621
1622 buf[0] = '&';
1623 buf[1] = 0;
1624 ret = xmlStrncat(ret, buf, 1);
1625 ret = xmlStrcat(ret, node->name);
1626 buf[0] = ';';
1627 buf[1] = 0;
1628 ret = xmlStrncat(ret, buf, 1);
1629 }
1630 }
1631#if 0
1632 else {
1633 xmlGenericError(xmlGenericErrorContext,
1634 "xmlGetNodeListString : invalid node type %d\n",
1635 node->type);
1636 }
1637#endif
1638 node = node->next;
1639 }
1640 return (ret);
1641}
Daniel Veillard652327a2003-09-29 18:02:38 +00001642
1643#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001644/**
1645 * xmlNodeListGetRawString:
1646 * @doc: the document
1647 * @list: a Node list
1648 * @inLine: should we replace entity contents or show their external form
1649 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001650 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001651 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1652 * this function doesn't do any character encoding handling.
1653 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001654 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001655 */
1656xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001657xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1658{
Owen Taylor3473f882001-02-23 17:55:21 +00001659 xmlNodePtr node = list;
1660 xmlChar *ret = NULL;
1661 xmlEntityPtr ent;
1662
Daniel Veillard7646b182002-04-20 06:41:40 +00001663 if (list == NULL)
1664 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001665
1666 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001667 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001668 (node->type == XML_CDATA_SECTION_NODE)) {
1669 if (inLine) {
1670 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001671 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001672 xmlChar *buffer;
1673
1674 buffer = xmlEncodeSpecialChars(doc, node->content);
1675 if (buffer != NULL) {
1676 ret = xmlStrcat(ret, buffer);
1677 xmlFree(buffer);
1678 }
1679 }
1680 } else if (node->type == XML_ENTITY_REF_NODE) {
1681 if (inLine) {
1682 ent = xmlGetDocEntity(doc, node->name);
1683 if (ent != NULL) {
1684 xmlChar *buffer;
1685
1686 /* an entity content can be any "well balanced chunk",
1687 * i.e. the result of the content [43] production:
1688 * http://www.w3.org/TR/REC-xml#NT-content.
1689 * So it can contain text, CDATA section or nested
1690 * entity reference nodes (among others).
1691 * -> we recursive call xmlNodeListGetRawString()
1692 * which handles these types */
1693 buffer =
1694 xmlNodeListGetRawString(doc, ent->children, 1);
1695 if (buffer != NULL) {
1696 ret = xmlStrcat(ret, buffer);
1697 xmlFree(buffer);
1698 }
1699 } else {
1700 ret = xmlStrcat(ret, node->content);
1701 }
1702 } else {
1703 xmlChar buf[2];
1704
1705 buf[0] = '&';
1706 buf[1] = 0;
1707 ret = xmlStrncat(ret, buf, 1);
1708 ret = xmlStrcat(ret, node->name);
1709 buf[0] = ';';
1710 buf[1] = 0;
1711 ret = xmlStrncat(ret, buf, 1);
1712 }
1713 }
Owen Taylor3473f882001-02-23 17:55:21 +00001714#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001715 else {
1716 xmlGenericError(xmlGenericErrorContext,
1717 "xmlGetNodeListString : invalid node type %d\n",
1718 node->type);
1719 }
Owen Taylor3473f882001-02-23 17:55:21 +00001720#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001721 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001722 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001723 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001724}
Daniel Veillard652327a2003-09-29 18:02:38 +00001725#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001726
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001727static xmlAttrPtr
1728xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns,
1729 const xmlChar * name, const xmlChar * value,
1730 int eatname)
1731{
Owen Taylor3473f882001-02-23 17:55:21 +00001732 xmlAttrPtr cur;
1733 xmlDocPtr doc = NULL;
1734
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001735 if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001736 if (eatname == 1)
1737 xmlFree((xmlChar *) name);
1738 return (NULL);
1739 }
Owen Taylor3473f882001-02-23 17:55:21 +00001740
1741 /*
1742 * Allocate a new property and fill the fields.
1743 */
1744 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1745 if (cur == NULL) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001746 if (eatname == 1)
1747 xmlFree((xmlChar *) name);
1748 xmlTreeErrMemory("building attribute");
1749 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001750 }
1751 memset(cur, 0, sizeof(xmlAttr));
1752 cur->type = XML_ATTRIBUTE_NODE;
1753
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001754 cur->parent = node;
Owen Taylor3473f882001-02-23 17:55:21 +00001755 if (node != NULL) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001756 doc = node->doc;
1757 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001758 }
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001759 cur->ns = ns;
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001760
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001761 if (eatname == 0) {
1762 if ((doc != NULL) && (doc->dict != NULL))
1763 cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
1764 else
1765 cur->name = xmlStrdup(name);
1766 } else
1767 cur->name = name;
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001768
Owen Taylor3473f882001-02-23 17:55:21 +00001769 if (value != NULL) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001770 xmlChar *buffer;
1771 xmlNodePtr tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00001772
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001773 buffer = xmlEncodeEntitiesReentrant(doc, value);
1774 cur->children = xmlStringGetNodeList(doc, buffer);
1775 cur->last = NULL;
1776 tmp = cur->children;
1777 while (tmp != NULL) {
1778 tmp->parent = (xmlNodePtr) cur;
1779 if (tmp->next == NULL)
1780 cur->last = tmp;
1781 tmp = tmp->next;
1782 }
1783 xmlFree(buffer);
1784 }
Owen Taylor3473f882001-02-23 17:55:21 +00001785
1786 /*
1787 * Add it at the end to preserve parsing order ...
1788 */
1789 if (node != NULL) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001790 if (node->properties == NULL) {
1791 node->properties = cur;
1792 } else {
1793 xmlAttrPtr prev = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00001794
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001795 while (prev->next != NULL)
1796 prev = prev->next;
1797 prev->next = cur;
1798 cur->prev = prev;
1799 }
Owen Taylor3473f882001-02-23 17:55:21 +00001800 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001801
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001802 if (xmlIsID((node == NULL) ? NULL : node->doc, node, cur) == 1)
1803 xmlAddID(NULL, node->doc, value, cur);
1804
Daniel Veillarda880b122003-04-21 21:36:41 +00001805 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001806 xmlRegisterNodeDefaultValue((xmlNodePtr) cur);
1807 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001808}
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001809
1810#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
1811 defined(LIBXML_SCHEMAS_ENABLED)
1812/**
1813 * xmlNewProp:
1814 * @node: the holding node
1815 * @name: the name of the attribute
1816 * @value: the value of the attribute
1817 *
1818 * Create a new property carried by a node.
1819 * Returns a pointer to the attribute
1820 */
1821xmlAttrPtr
1822xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1823
1824 if (name == NULL) {
1825#ifdef DEBUG_TREE
1826 xmlGenericError(xmlGenericErrorContext,
1827 "xmlNewProp : name == NULL\n");
1828#endif
1829 return(NULL);
1830 }
1831
1832 return xmlNewPropInternal(node, NULL, name, value, 0);
1833}
Daniel Veillard652327a2003-09-29 18:02:38 +00001834#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001835
1836/**
1837 * xmlNewNsProp:
1838 * @node: the holding node
1839 * @ns: the namespace
1840 * @name: the name of the attribute
1841 * @value: the value of the attribute
1842 *
1843 * Create a new property tagged with a namespace and carried by a node.
1844 * Returns a pointer to the attribute
1845 */
1846xmlAttrPtr
1847xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1848 const xmlChar *value) {
Owen Taylor3473f882001-02-23 17:55:21 +00001849
1850 if (name == NULL) {
1851#ifdef DEBUG_TREE
1852 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001853 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001854#endif
1855 return(NULL);
1856 }
1857
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001858 return xmlNewPropInternal(node, ns, name, value, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001859}
1860
1861/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001862 * xmlNewNsPropEatName:
1863 * @node: the holding node
1864 * @ns: the namespace
1865 * @name: the name of the attribute
1866 * @value: the value of the attribute
1867 *
1868 * Create a new property tagged with a namespace and carried by a node.
1869 * Returns a pointer to the attribute
1870 */
1871xmlAttrPtr
1872xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1873 const xmlChar *value) {
Daniel Veillard46de64e2002-05-29 08:21:33 +00001874
1875 if (name == NULL) {
1876#ifdef DEBUG_TREE
1877 xmlGenericError(xmlGenericErrorContext,
1878 "xmlNewNsPropEatName : name == NULL\n");
1879#endif
1880 return(NULL);
1881 }
1882
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001883 return xmlNewPropInternal(node, ns, name, value, 1);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001884}
1885
1886/**
Owen Taylor3473f882001-02-23 17:55:21 +00001887 * xmlNewDocProp:
1888 * @doc: the document
1889 * @name: the name of the attribute
1890 * @value: the value of the attribute
1891 *
1892 * Create a new property carried by a document.
1893 * Returns a pointer to the attribute
1894 */
1895xmlAttrPtr
1896xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1897 xmlAttrPtr cur;
1898
1899 if (name == NULL) {
1900#ifdef DEBUG_TREE
1901 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001902 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001903#endif
1904 return(NULL);
1905 }
1906
1907 /*
1908 * Allocate a new property and fill the fields.
1909 */
1910 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1911 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001912 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001913 return(NULL);
1914 }
1915 memset(cur, 0, sizeof(xmlAttr));
1916 cur->type = XML_ATTRIBUTE_NODE;
1917
Daniel Veillard03a53c32004-10-26 16:06:51 +00001918 if ((doc != NULL) && (doc->dict != NULL))
1919 cur->name = xmlDictLookup(doc->dict, name, -1);
1920 else
1921 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00001922 cur->doc = doc;
1923 if (value != NULL) {
1924 xmlNodePtr tmp;
1925
1926 cur->children = xmlStringGetNodeList(doc, value);
1927 cur->last = NULL;
1928
1929 tmp = cur->children;
1930 while (tmp != NULL) {
1931 tmp->parent = (xmlNodePtr) cur;
1932 if (tmp->next == NULL)
1933 cur->last = tmp;
1934 tmp = tmp->next;
1935 }
1936 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001937
Daniel Veillarda880b122003-04-21 21:36:41 +00001938 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001939 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001940 return(cur);
1941}
1942
1943/**
1944 * xmlFreePropList:
1945 * @cur: the first property in the list
1946 *
1947 * Free a property and all its siblings, all the children are freed too.
1948 */
1949void
1950xmlFreePropList(xmlAttrPtr cur) {
1951 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001952 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001953 while (cur != NULL) {
1954 next = cur->next;
1955 xmlFreeProp(cur);
1956 cur = next;
1957 }
1958}
1959
1960/**
1961 * xmlFreeProp:
1962 * @cur: an attribute
1963 *
1964 * Free one attribute, all the content is freed too
1965 */
1966void
1967xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001968 xmlDictPtr dict = NULL;
1969 if (cur == NULL) return;
1970
1971 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001972
Daniel Veillarda880b122003-04-21 21:36:41 +00001973 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001974 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1975
Owen Taylor3473f882001-02-23 17:55:21 +00001976 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillardda6f4af2005-06-20 17:17:54 +00001977 if ((cur->doc != NULL) && (cur->atype == XML_ATTRIBUTE_ID)) {
1978 xmlRemoveID(cur->doc, cur);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001979 }
Owen Taylor3473f882001-02-23 17:55:21 +00001980 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001981 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00001982 xmlFree(cur);
1983}
1984
Daniel Veillard652327a2003-09-29 18:02:38 +00001985#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001986/**
1987 * xmlRemoveProp:
1988 * @cur: an attribute
1989 *
1990 * Unlink and free one attribute, all the content is freed too
1991 * Note this doesn't work for namespace definition attributes
1992 *
1993 * Returns 0 if success and -1 in case of error.
1994 */
1995int
1996xmlRemoveProp(xmlAttrPtr cur) {
1997 xmlAttrPtr tmp;
1998 if (cur == NULL) {
1999#ifdef DEBUG_TREE
2000 xmlGenericError(xmlGenericErrorContext,
2001 "xmlRemoveProp : cur == NULL\n");
2002#endif
2003 return(-1);
2004 }
2005 if (cur->parent == NULL) {
2006#ifdef DEBUG_TREE
2007 xmlGenericError(xmlGenericErrorContext,
2008 "xmlRemoveProp : cur->parent == NULL\n");
2009#endif
2010 return(-1);
2011 }
2012 tmp = cur->parent->properties;
2013 if (tmp == cur) {
2014 cur->parent->properties = cur->next;
2015 xmlFreeProp(cur);
2016 return(0);
2017 }
2018 while (tmp != NULL) {
2019 if (tmp->next == cur) {
2020 tmp->next = cur->next;
2021 if (tmp->next != NULL)
2022 tmp->next->prev = tmp;
2023 xmlFreeProp(cur);
2024 return(0);
2025 }
2026 tmp = tmp->next;
2027 }
2028#ifdef DEBUG_TREE
2029 xmlGenericError(xmlGenericErrorContext,
2030 "xmlRemoveProp : attribute not owned by its node\n");
2031#endif
2032 return(-1);
2033}
Daniel Veillard652327a2003-09-29 18:02:38 +00002034#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002035
2036/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002037 * xmlNewDocPI:
2038 * @doc: the target document
Owen Taylor3473f882001-02-23 17:55:21 +00002039 * @name: the processing instruction name
2040 * @content: the PI content
2041 *
2042 * Creation of a processing instruction element.
2043 * Returns a pointer to the new node object.
2044 */
2045xmlNodePtr
Daniel Veillard03a53c32004-10-26 16:06:51 +00002046xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
Owen Taylor3473f882001-02-23 17:55:21 +00002047 xmlNodePtr cur;
2048
2049 if (name == NULL) {
2050#ifdef DEBUG_TREE
2051 xmlGenericError(xmlGenericErrorContext,
2052 "xmlNewPI : name == NULL\n");
2053#endif
2054 return(NULL);
2055 }
2056
2057 /*
2058 * Allocate a new node and fill the fields.
2059 */
2060 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2061 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002062 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002063 return(NULL);
2064 }
2065 memset(cur, 0, sizeof(xmlNode));
2066 cur->type = XML_PI_NODE;
2067
Daniel Veillard03a53c32004-10-26 16:06:51 +00002068 if ((doc != NULL) && (doc->dict != NULL))
2069 cur->name = xmlDictLookup(doc->dict, name, -1);
2070 else
2071 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00002072 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002073 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002074 }
Daniel Veillarda03e3652004-11-02 18:45:30 +00002075 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002076
Daniel Veillarda880b122003-04-21 21:36:41 +00002077 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002078 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002079 return(cur);
2080}
2081
2082/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002083 * xmlNewPI:
2084 * @name: the processing instruction name
2085 * @content: the PI content
2086 *
2087 * Creation of a processing instruction element.
2088 * Use xmlDocNewPI preferably to get string interning
2089 *
2090 * Returns a pointer to the new node object.
2091 */
2092xmlNodePtr
2093xmlNewPI(const xmlChar *name, const xmlChar *content) {
2094 return(xmlNewDocPI(NULL, name, content));
2095}
2096
2097/**
Owen Taylor3473f882001-02-23 17:55:21 +00002098 * xmlNewNode:
2099 * @ns: namespace if any
2100 * @name: the node name
2101 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002102 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002103 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002104 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2105 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002106 */
2107xmlNodePtr
2108xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2109 xmlNodePtr cur;
2110
2111 if (name == NULL) {
2112#ifdef DEBUG_TREE
2113 xmlGenericError(xmlGenericErrorContext,
2114 "xmlNewNode : name == NULL\n");
2115#endif
2116 return(NULL);
2117 }
2118
2119 /*
2120 * Allocate a new node and fill the fields.
2121 */
2122 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2123 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002124 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002125 return(NULL);
2126 }
2127 memset(cur, 0, sizeof(xmlNode));
2128 cur->type = XML_ELEMENT_NODE;
2129
2130 cur->name = xmlStrdup(name);
2131 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002132
Daniel Veillarda880b122003-04-21 21:36:41 +00002133 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002134 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002135 return(cur);
2136}
2137
2138/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002139 * xmlNewNodeEatName:
2140 * @ns: namespace if any
2141 * @name: the node name
2142 *
2143 * Creation of a new node element. @ns is optional (NULL).
2144 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002145 * Returns a pointer to the new node object, with pointer @name as
2146 * new node's name. Use xmlNewNode() if a copy of @name string is
2147 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002148 */
2149xmlNodePtr
2150xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2151 xmlNodePtr cur;
2152
2153 if (name == NULL) {
2154#ifdef DEBUG_TREE
2155 xmlGenericError(xmlGenericErrorContext,
2156 "xmlNewNode : name == NULL\n");
2157#endif
2158 return(NULL);
2159 }
2160
2161 /*
2162 * Allocate a new node and fill the fields.
2163 */
2164 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2165 if (cur == NULL) {
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00002166 xmlFree(name);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002167 xmlTreeErrMemory("building node");
Daniel Veillard46de64e2002-05-29 08:21:33 +00002168 return(NULL);
2169 }
2170 memset(cur, 0, sizeof(xmlNode));
2171 cur->type = XML_ELEMENT_NODE;
2172
2173 cur->name = name;
2174 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002175
Daniel Veillarda880b122003-04-21 21:36:41 +00002176 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002177 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002178 return(cur);
2179}
2180
2181/**
Owen Taylor3473f882001-02-23 17:55:21 +00002182 * xmlNewDocNode:
2183 * @doc: the document
2184 * @ns: namespace if any
2185 * @name: the node name
2186 * @content: the XML text content if any
2187 *
2188 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002189 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002190 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2191 * references, but XML special chars need to be escaped first by using
2192 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2193 * need entities support.
2194 *
2195 * Returns a pointer to the new node object.
2196 */
2197xmlNodePtr
2198xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2199 const xmlChar *name, const xmlChar *content) {
2200 xmlNodePtr cur;
2201
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002202 if ((doc != NULL) && (doc->dict != NULL))
Daniel Veillard03a53c32004-10-26 16:06:51 +00002203 cur = xmlNewNodeEatName(ns, (xmlChar *)
2204 xmlDictLookup(doc->dict, name, -1));
2205 else
2206 cur = xmlNewNode(ns, name);
Owen Taylor3473f882001-02-23 17:55:21 +00002207 if (cur != NULL) {
2208 cur->doc = doc;
2209 if (content != NULL) {
2210 cur->children = xmlStringGetNodeList(doc, content);
2211 UPDATE_LAST_CHILD_AND_PARENT(cur)
2212 }
2213 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002214
Owen Taylor3473f882001-02-23 17:55:21 +00002215 return(cur);
2216}
2217
Daniel Veillard46de64e2002-05-29 08:21:33 +00002218/**
2219 * xmlNewDocNodeEatName:
2220 * @doc: the document
2221 * @ns: namespace if any
2222 * @name: the node name
2223 * @content: the XML text content if any
2224 *
2225 * Creation of a new node element within a document. @ns and @content
2226 * are optional (NULL).
2227 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2228 * references, but XML special chars need to be escaped first by using
2229 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2230 * need entities support.
2231 *
2232 * Returns a pointer to the new node object.
2233 */
2234xmlNodePtr
2235xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2236 xmlChar *name, const xmlChar *content) {
2237 xmlNodePtr cur;
2238
2239 cur = xmlNewNodeEatName(ns, name);
2240 if (cur != NULL) {
2241 cur->doc = doc;
2242 if (content != NULL) {
2243 cur->children = xmlStringGetNodeList(doc, content);
2244 UPDATE_LAST_CHILD_AND_PARENT(cur)
2245 }
2246 }
2247 return(cur);
2248}
2249
Daniel Veillard652327a2003-09-29 18:02:38 +00002250#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002251/**
2252 * xmlNewDocRawNode:
2253 * @doc: the document
2254 * @ns: namespace if any
2255 * @name: the node name
2256 * @content: the text content if any
2257 *
2258 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002259 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002260 *
2261 * Returns a pointer to the new node object.
2262 */
2263xmlNodePtr
2264xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2265 const xmlChar *name, const xmlChar *content) {
2266 xmlNodePtr cur;
2267
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002268 cur = xmlNewDocNode(doc, ns, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002269 if (cur != NULL) {
2270 cur->doc = doc;
2271 if (content != NULL) {
2272 cur->children = xmlNewDocText(doc, content);
2273 UPDATE_LAST_CHILD_AND_PARENT(cur)
2274 }
2275 }
2276 return(cur);
2277}
2278
2279/**
2280 * xmlNewDocFragment:
2281 * @doc: the document owning the fragment
2282 *
2283 * Creation of a new Fragment node.
2284 * Returns a pointer to the new node object.
2285 */
2286xmlNodePtr
2287xmlNewDocFragment(xmlDocPtr doc) {
2288 xmlNodePtr cur;
2289
2290 /*
2291 * Allocate a new DocumentFragment node and fill the fields.
2292 */
2293 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2294 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002295 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002296 return(NULL);
2297 }
2298 memset(cur, 0, sizeof(xmlNode));
2299 cur->type = XML_DOCUMENT_FRAG_NODE;
2300
2301 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002302
Daniel Veillarda880b122003-04-21 21:36:41 +00002303 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002304 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002305 return(cur);
2306}
Daniel Veillard652327a2003-09-29 18:02:38 +00002307#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002308
2309/**
2310 * xmlNewText:
2311 * @content: the text content
2312 *
2313 * Creation of a new text node.
2314 * Returns a pointer to the new node object.
2315 */
2316xmlNodePtr
2317xmlNewText(const xmlChar *content) {
2318 xmlNodePtr cur;
2319
2320 /*
2321 * Allocate a new node and fill the fields.
2322 */
2323 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2324 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002325 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002326 return(NULL);
2327 }
2328 memset(cur, 0, sizeof(xmlNode));
2329 cur->type = XML_TEXT_NODE;
2330
2331 cur->name = xmlStringText;
2332 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002333 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002334 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002335
Daniel Veillarda880b122003-04-21 21:36:41 +00002336 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002337 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002338 return(cur);
2339}
2340
Daniel Veillard652327a2003-09-29 18:02:38 +00002341#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002342/**
2343 * xmlNewTextChild:
2344 * @parent: the parent node
2345 * @ns: a namespace if any
2346 * @name: the name of the child
2347 * @content: the text content of the child if any.
2348 *
2349 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002350 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2351 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002352 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002353 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2354 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2355 * reserved XML chars that might appear in @content, such as the ampersand,
2356 * greater-than or less-than signs, are automatically replaced by their XML
2357 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002358 *
2359 * Returns a pointer to the new node object.
2360 */
2361xmlNodePtr
2362xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2363 const xmlChar *name, const xmlChar *content) {
2364 xmlNodePtr cur, prev;
2365
2366 if (parent == NULL) {
2367#ifdef DEBUG_TREE
2368 xmlGenericError(xmlGenericErrorContext,
2369 "xmlNewTextChild : parent == NULL\n");
2370#endif
2371 return(NULL);
2372 }
2373
2374 if (name == NULL) {
2375#ifdef DEBUG_TREE
2376 xmlGenericError(xmlGenericErrorContext,
2377 "xmlNewTextChild : name == NULL\n");
2378#endif
2379 return(NULL);
2380 }
2381
2382 /*
2383 * Allocate a new node
2384 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002385 if (parent->type == XML_ELEMENT_NODE) {
2386 if (ns == NULL)
2387 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2388 else
2389 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2390 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2391 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2392 if (ns == NULL)
2393 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2394 else
2395 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2396 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2397 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2398 } else {
2399 return(NULL);
2400 }
Owen Taylor3473f882001-02-23 17:55:21 +00002401 if (cur == NULL) return(NULL);
2402
2403 /*
2404 * add the new element at the end of the children list.
2405 */
2406 cur->type = XML_ELEMENT_NODE;
2407 cur->parent = parent;
2408 cur->doc = parent->doc;
2409 if (parent->children == NULL) {
2410 parent->children = cur;
2411 parent->last = cur;
2412 } else {
2413 prev = parent->last;
2414 prev->next = cur;
2415 cur->prev = prev;
2416 parent->last = cur;
2417 }
2418
2419 return(cur);
2420}
Daniel Veillard652327a2003-09-29 18:02:38 +00002421#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002422
2423/**
2424 * xmlNewCharRef:
2425 * @doc: the document
2426 * @name: the char ref string, starting with # or "&# ... ;"
2427 *
2428 * Creation of a new character reference node.
2429 * Returns a pointer to the new node object.
2430 */
2431xmlNodePtr
2432xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2433 xmlNodePtr cur;
2434
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002435 if (name == NULL)
2436 return(NULL);
2437
Owen Taylor3473f882001-02-23 17:55:21 +00002438 /*
2439 * Allocate a new node and fill the fields.
2440 */
2441 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2442 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002443 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002444 return(NULL);
2445 }
2446 memset(cur, 0, sizeof(xmlNode));
2447 cur->type = XML_ENTITY_REF_NODE;
2448
2449 cur->doc = doc;
2450 if (name[0] == '&') {
2451 int len;
2452 name++;
2453 len = xmlStrlen(name);
2454 if (name[len - 1] == ';')
2455 cur->name = xmlStrndup(name, len - 1);
2456 else
2457 cur->name = xmlStrndup(name, len);
2458 } else
2459 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002460
Daniel Veillarda880b122003-04-21 21:36:41 +00002461 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002462 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002463 return(cur);
2464}
2465
2466/**
2467 * xmlNewReference:
2468 * @doc: the document
2469 * @name: the reference name, or the reference string with & and ;
2470 *
2471 * Creation of a new reference node.
2472 * Returns a pointer to the new node object.
2473 */
2474xmlNodePtr
2475xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2476 xmlNodePtr cur;
2477 xmlEntityPtr ent;
2478
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002479 if (name == NULL)
2480 return(NULL);
2481
Owen Taylor3473f882001-02-23 17:55:21 +00002482 /*
2483 * Allocate a new node and fill the fields.
2484 */
2485 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2486 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002487 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002488 return(NULL);
2489 }
2490 memset(cur, 0, sizeof(xmlNode));
2491 cur->type = XML_ENTITY_REF_NODE;
2492
2493 cur->doc = doc;
2494 if (name[0] == '&') {
2495 int len;
2496 name++;
2497 len = xmlStrlen(name);
2498 if (name[len - 1] == ';')
2499 cur->name = xmlStrndup(name, len - 1);
2500 else
2501 cur->name = xmlStrndup(name, len);
2502 } else
2503 cur->name = xmlStrdup(name);
2504
2505 ent = xmlGetDocEntity(doc, cur->name);
2506 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002507 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002508 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002509 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002510 * updated. Not sure if this is 100% correct.
2511 * -George
2512 */
2513 cur->children = (xmlNodePtr) ent;
2514 cur->last = (xmlNodePtr) ent;
2515 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002516
Daniel Veillarda880b122003-04-21 21:36:41 +00002517 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002518 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002519 return(cur);
2520}
2521
2522/**
2523 * xmlNewDocText:
2524 * @doc: the document
2525 * @content: the text content
2526 *
2527 * Creation of a new text node within a document.
2528 * Returns a pointer to the new node object.
2529 */
2530xmlNodePtr
2531xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2532 xmlNodePtr cur;
2533
2534 cur = xmlNewText(content);
2535 if (cur != NULL) cur->doc = doc;
2536 return(cur);
2537}
2538
2539/**
2540 * xmlNewTextLen:
2541 * @content: the text content
2542 * @len: the text len.
2543 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002544 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002545 * Returns a pointer to the new node object.
2546 */
2547xmlNodePtr
2548xmlNewTextLen(const xmlChar *content, int len) {
2549 xmlNodePtr cur;
2550
2551 /*
2552 * Allocate a new node and fill the fields.
2553 */
2554 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2555 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002556 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002557 return(NULL);
2558 }
2559 memset(cur, 0, sizeof(xmlNode));
2560 cur->type = XML_TEXT_NODE;
2561
2562 cur->name = xmlStringText;
2563 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002564 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002565 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002566
Daniel Veillarda880b122003-04-21 21:36:41 +00002567 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002568 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002569 return(cur);
2570}
2571
2572/**
2573 * xmlNewDocTextLen:
2574 * @doc: the document
2575 * @content: the text content
2576 * @len: the text len.
2577 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002578 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002579 * text node pertain to a given document.
2580 * Returns a pointer to the new node object.
2581 */
2582xmlNodePtr
2583xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2584 xmlNodePtr cur;
2585
2586 cur = xmlNewTextLen(content, len);
2587 if (cur != NULL) cur->doc = doc;
2588 return(cur);
2589}
2590
2591/**
2592 * xmlNewComment:
2593 * @content: the comment content
2594 *
2595 * Creation of a new node containing a comment.
2596 * Returns a pointer to the new node object.
2597 */
2598xmlNodePtr
2599xmlNewComment(const xmlChar *content) {
2600 xmlNodePtr cur;
2601
2602 /*
2603 * Allocate a new node and fill the fields.
2604 */
2605 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2606 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002607 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002608 return(NULL);
2609 }
2610 memset(cur, 0, sizeof(xmlNode));
2611 cur->type = XML_COMMENT_NODE;
2612
2613 cur->name = xmlStringComment;
2614 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002615 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002616 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002617
Daniel Veillarda880b122003-04-21 21:36:41 +00002618 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002619 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002620 return(cur);
2621}
2622
2623/**
2624 * xmlNewCDataBlock:
2625 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002626 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002627 * @len: the length of the block
2628 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002629 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002630 * Returns a pointer to the new node object.
2631 */
2632xmlNodePtr
2633xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2634 xmlNodePtr cur;
2635
2636 /*
2637 * Allocate a new node and fill the fields.
2638 */
2639 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2640 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002641 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002642 return(NULL);
2643 }
2644 memset(cur, 0, sizeof(xmlNode));
2645 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002646 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002647
2648 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002649 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002650 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002651
Daniel Veillarda880b122003-04-21 21:36:41 +00002652 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002653 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002654 return(cur);
2655}
2656
2657/**
2658 * xmlNewDocComment:
2659 * @doc: the document
2660 * @content: the comment content
2661 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002662 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002663 * Returns a pointer to the new node object.
2664 */
2665xmlNodePtr
2666xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2667 xmlNodePtr cur;
2668
2669 cur = xmlNewComment(content);
2670 if (cur != NULL) cur->doc = doc;
2671 return(cur);
2672}
2673
2674/**
2675 * xmlSetTreeDoc:
2676 * @tree: the top element
2677 * @doc: the document
2678 *
2679 * update all nodes under the tree to point to the right document
2680 */
2681void
2682xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002683 xmlAttrPtr prop;
2684
Owen Taylor3473f882001-02-23 17:55:21 +00002685 if (tree == NULL)
2686 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002687 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002688 if(tree->type == XML_ELEMENT_NODE) {
2689 prop = tree->properties;
2690 while (prop != NULL) {
2691 prop->doc = doc;
2692 xmlSetListDoc(prop->children, doc);
2693 prop = prop->next;
2694 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002695 }
Owen Taylor3473f882001-02-23 17:55:21 +00002696 if (tree->children != NULL)
2697 xmlSetListDoc(tree->children, doc);
2698 tree->doc = doc;
2699 }
2700}
2701
2702/**
2703 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002704 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002705 * @doc: the document
2706 *
2707 * update all nodes in the list to point to the right document
2708 */
2709void
2710xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2711 xmlNodePtr cur;
2712
2713 if (list == NULL)
2714 return;
2715 cur = list;
2716 while (cur != NULL) {
2717 if (cur->doc != doc)
2718 xmlSetTreeDoc(cur, doc);
2719 cur = cur->next;
2720 }
2721}
2722
Daniel Veillard2156d432004-03-04 15:59:36 +00002723#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002724/**
2725 * xmlNewChild:
2726 * @parent: the parent node
2727 * @ns: a namespace if any
2728 * @name: the name of the child
2729 * @content: the XML content of the child if any.
2730 *
2731 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002732 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2733 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002734 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002735 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2736 * references. XML special chars must be escaped first by using
2737 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002738 *
2739 * Returns a pointer to the new node object.
2740 */
2741xmlNodePtr
2742xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2743 const xmlChar *name, const xmlChar *content) {
2744 xmlNodePtr cur, prev;
2745
2746 if (parent == NULL) {
2747#ifdef DEBUG_TREE
2748 xmlGenericError(xmlGenericErrorContext,
2749 "xmlNewChild : parent == NULL\n");
2750#endif
2751 return(NULL);
2752 }
2753
2754 if (name == NULL) {
2755#ifdef DEBUG_TREE
2756 xmlGenericError(xmlGenericErrorContext,
2757 "xmlNewChild : name == NULL\n");
2758#endif
2759 return(NULL);
2760 }
2761
2762 /*
2763 * Allocate a new node
2764 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002765 if (parent->type == XML_ELEMENT_NODE) {
2766 if (ns == NULL)
2767 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2768 else
2769 cur = xmlNewDocNode(parent->doc, ns, name, content);
2770 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2771 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2772 if (ns == NULL)
2773 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2774 else
2775 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002776 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2777 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002778 } else {
2779 return(NULL);
2780 }
Owen Taylor3473f882001-02-23 17:55:21 +00002781 if (cur == NULL) return(NULL);
2782
2783 /*
2784 * add the new element at the end of the children list.
2785 */
2786 cur->type = XML_ELEMENT_NODE;
2787 cur->parent = parent;
2788 cur->doc = parent->doc;
2789 if (parent->children == NULL) {
2790 parent->children = cur;
2791 parent->last = cur;
2792 } else {
2793 prev = parent->last;
2794 prev->next = cur;
2795 cur->prev = prev;
2796 parent->last = cur;
2797 }
2798
2799 return(cur);
2800}
Daniel Veillard652327a2003-09-29 18:02:38 +00002801#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002802
2803/**
2804 * xmlAddNextSibling:
2805 * @cur: the child node
2806 * @elem: the new node
2807 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002808 * Add a new node @elem as the next sibling of @cur
2809 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002810 * first unlinked from its existing context.
2811 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002812 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2813 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002814 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002815 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002816 */
2817xmlNodePtr
2818xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2819 if (cur == NULL) {
2820#ifdef DEBUG_TREE
2821 xmlGenericError(xmlGenericErrorContext,
2822 "xmlAddNextSibling : cur == NULL\n");
2823#endif
2824 return(NULL);
2825 }
2826 if (elem == NULL) {
2827#ifdef DEBUG_TREE
2828 xmlGenericError(xmlGenericErrorContext,
2829 "xmlAddNextSibling : elem == NULL\n");
2830#endif
2831 return(NULL);
2832 }
2833
2834 xmlUnlinkNode(elem);
2835
2836 if (elem->type == XML_TEXT_NODE) {
2837 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002838 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002839 xmlFreeNode(elem);
2840 return(cur);
2841 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002842 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2843 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002844 xmlChar *tmp;
2845
2846 tmp = xmlStrdup(elem->content);
2847 tmp = xmlStrcat(tmp, cur->next->content);
2848 xmlNodeSetContent(cur->next, tmp);
2849 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002850 xmlFreeNode(elem);
2851 return(cur->next);
2852 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002853 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2854 /* check if an attribute with the same name exists */
2855 xmlAttrPtr attr;
2856
2857 if (elem->ns == NULL)
2858 attr = xmlHasProp(cur->parent, elem->name);
2859 else
2860 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2861 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2862 /* different instance, destroy it (attributes must be unique) */
2863 xmlFreeProp(attr);
2864 }
Owen Taylor3473f882001-02-23 17:55:21 +00002865 }
2866
2867 if (elem->doc != cur->doc) {
2868 xmlSetTreeDoc(elem, cur->doc);
2869 }
2870 elem->parent = cur->parent;
2871 elem->prev = cur;
2872 elem->next = cur->next;
2873 cur->next = elem;
2874 if (elem->next != NULL)
2875 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002876 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002877 elem->parent->last = elem;
2878 return(elem);
2879}
2880
William M. Brack21e4ef22005-01-02 09:53:13 +00002881#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
2882 defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002883/**
2884 * xmlAddPrevSibling:
2885 * @cur: the child node
2886 * @elem: the new node
2887 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002888 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002889 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002890 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002891 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002892 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2893 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002894 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002895 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002896 */
2897xmlNodePtr
2898xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2899 if (cur == NULL) {
2900#ifdef DEBUG_TREE
2901 xmlGenericError(xmlGenericErrorContext,
2902 "xmlAddPrevSibling : cur == NULL\n");
2903#endif
2904 return(NULL);
2905 }
2906 if (elem == NULL) {
2907#ifdef DEBUG_TREE
2908 xmlGenericError(xmlGenericErrorContext,
2909 "xmlAddPrevSibling : elem == NULL\n");
2910#endif
2911 return(NULL);
2912 }
2913
2914 xmlUnlinkNode(elem);
2915
2916 if (elem->type == XML_TEXT_NODE) {
2917 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002918 xmlChar *tmp;
2919
2920 tmp = xmlStrdup(elem->content);
2921 tmp = xmlStrcat(tmp, cur->content);
2922 xmlNodeSetContent(cur, tmp);
2923 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002924 xmlFreeNode(elem);
2925 return(cur);
2926 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002927 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2928 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002929 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002930 xmlFreeNode(elem);
2931 return(cur->prev);
2932 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002933 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2934 /* check if an attribute with the same name exists */
2935 xmlAttrPtr attr;
2936
2937 if (elem->ns == NULL)
2938 attr = xmlHasProp(cur->parent, elem->name);
2939 else
2940 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2941 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2942 /* different instance, destroy it (attributes must be unique) */
2943 xmlFreeProp(attr);
2944 }
Owen Taylor3473f882001-02-23 17:55:21 +00002945 }
2946
2947 if (elem->doc != cur->doc) {
2948 xmlSetTreeDoc(elem, cur->doc);
2949 }
2950 elem->parent = cur->parent;
2951 elem->next = cur;
2952 elem->prev = cur->prev;
2953 cur->prev = elem;
2954 if (elem->prev != NULL)
2955 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002956 if (elem->parent != NULL) {
2957 if (elem->type == XML_ATTRIBUTE_NODE) {
2958 if (elem->parent->properties == (xmlAttrPtr) cur) {
2959 elem->parent->properties = (xmlAttrPtr) elem;
2960 }
2961 } else {
2962 if (elem->parent->children == cur) {
2963 elem->parent->children = elem;
2964 }
2965 }
2966 }
Owen Taylor3473f882001-02-23 17:55:21 +00002967 return(elem);
2968}
Daniel Veillard652327a2003-09-29 18:02:38 +00002969#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002970
2971/**
2972 * xmlAddSibling:
2973 * @cur: the child node
2974 * @elem: the new node
2975 *
2976 * Add a new element @elem to the list of siblings of @cur
2977 * merging adjacent TEXT nodes (@elem may be freed)
2978 * If the new element was already inserted in a document it is
2979 * first unlinked from its existing context.
2980 *
2981 * Returns the new element or NULL in case of error.
2982 */
2983xmlNodePtr
2984xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2985 xmlNodePtr parent;
2986
2987 if (cur == NULL) {
2988#ifdef DEBUG_TREE
2989 xmlGenericError(xmlGenericErrorContext,
2990 "xmlAddSibling : cur == NULL\n");
2991#endif
2992 return(NULL);
2993 }
2994
2995 if (elem == NULL) {
2996#ifdef DEBUG_TREE
2997 xmlGenericError(xmlGenericErrorContext,
2998 "xmlAddSibling : elem == NULL\n");
2999#endif
3000 return(NULL);
3001 }
3002
3003 /*
3004 * Constant time is we can rely on the ->parent->last to find
3005 * the last sibling.
3006 */
3007 if ((cur->parent != NULL) &&
3008 (cur->parent->children != NULL) &&
3009 (cur->parent->last != NULL) &&
3010 (cur->parent->last->next == NULL)) {
3011 cur = cur->parent->last;
3012 } else {
3013 while (cur->next != NULL) cur = cur->next;
3014 }
3015
3016 xmlUnlinkNode(elem);
3017
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003018 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3019 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003020 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003021 xmlFreeNode(elem);
3022 return(cur);
3023 }
3024
3025 if (elem->doc != cur->doc) {
3026 xmlSetTreeDoc(elem, cur->doc);
3027 }
3028 parent = cur->parent;
3029 elem->prev = cur;
3030 elem->next = NULL;
3031 elem->parent = parent;
3032 cur->next = elem;
3033 if (parent != NULL)
3034 parent->last = elem;
3035
3036 return(elem);
3037}
3038
3039/**
3040 * xmlAddChildList:
3041 * @parent: the parent node
3042 * @cur: the first node in the list
3043 *
3044 * Add a list of node at the end of the child list of the parent
3045 * merging adjacent TEXT nodes (@cur may be freed)
3046 *
3047 * Returns the last child or NULL in case of error.
3048 */
3049xmlNodePtr
3050xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3051 xmlNodePtr prev;
3052
3053 if (parent == NULL) {
3054#ifdef DEBUG_TREE
3055 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003056 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003057#endif
3058 return(NULL);
3059 }
3060
3061 if (cur == NULL) {
3062#ifdef DEBUG_TREE
3063 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003064 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003065#endif
3066 return(NULL);
3067 }
3068
3069 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3070 (cur->doc != parent->doc)) {
3071#ifdef DEBUG_TREE
3072 xmlGenericError(xmlGenericErrorContext,
3073 "Elements moved to a different document\n");
3074#endif
3075 }
3076
3077 /*
3078 * add the first element at the end of the children list.
3079 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003080
Owen Taylor3473f882001-02-23 17:55:21 +00003081 if (parent->children == NULL) {
3082 parent->children = cur;
3083 } else {
3084 /*
3085 * If cur and parent->last both are TEXT nodes, then merge them.
3086 */
3087 if ((cur->type == XML_TEXT_NODE) &&
3088 (parent->last->type == XML_TEXT_NODE) &&
3089 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003090 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003091 /*
3092 * if it's the only child, nothing more to be done.
3093 */
3094 if (cur->next == NULL) {
3095 xmlFreeNode(cur);
3096 return(parent->last);
3097 }
3098 prev = cur;
3099 cur = cur->next;
3100 xmlFreeNode(prev);
3101 }
3102 prev = parent->last;
3103 prev->next = cur;
3104 cur->prev = prev;
3105 }
3106 while (cur->next != NULL) {
3107 cur->parent = parent;
3108 if (cur->doc != parent->doc) {
3109 xmlSetTreeDoc(cur, parent->doc);
3110 }
3111 cur = cur->next;
3112 }
3113 cur->parent = parent;
3114 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3115 parent->last = cur;
3116
3117 return(cur);
3118}
3119
3120/**
3121 * xmlAddChild:
3122 * @parent: the parent node
3123 * @cur: the child node
3124 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003125 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003126 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003127 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3128 * If there is an attribute with equal name, it is first destroyed.
3129 *
Owen Taylor3473f882001-02-23 17:55:21 +00003130 * Returns the child or NULL in case of error.
3131 */
3132xmlNodePtr
3133xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3134 xmlNodePtr prev;
3135
3136 if (parent == NULL) {
3137#ifdef DEBUG_TREE
3138 xmlGenericError(xmlGenericErrorContext,
3139 "xmlAddChild : parent == NULL\n");
3140#endif
3141 return(NULL);
3142 }
3143
3144 if (cur == NULL) {
3145#ifdef DEBUG_TREE
3146 xmlGenericError(xmlGenericErrorContext,
3147 "xmlAddChild : child == NULL\n");
3148#endif
3149 return(NULL);
3150 }
3151
Owen Taylor3473f882001-02-23 17:55:21 +00003152 /*
3153 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003154 * cur is then freed.
3155 */
3156 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003157 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003158 (parent->content != NULL) &&
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003159 (parent->name == cur->name) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003160 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003161 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003162 xmlFreeNode(cur);
3163 return(parent);
3164 }
3165 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003166 (parent->last->name == cur->name) &&
3167 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003168 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003169 xmlFreeNode(cur);
3170 return(parent->last);
3171 }
3172 }
3173
3174 /*
3175 * add the new element at the end of the children list.
3176 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003177 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003178 cur->parent = parent;
3179 if (cur->doc != parent->doc) {
3180 xmlSetTreeDoc(cur, parent->doc);
3181 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003182 /* this check prevents a loop on tree-traversions if a developer
3183 * tries to add a node to its parent multiple times
3184 */
3185 if (prev == parent)
3186 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003187
3188 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003189 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003190 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003191 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003192 (parent->content != NULL) &&
3193 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003194 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003195 xmlFreeNode(cur);
3196 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003197 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003198 if (cur->type == XML_ATTRIBUTE_NODE) {
3199 if (parent->properties == NULL) {
3200 parent->properties = (xmlAttrPtr) cur;
3201 } else {
3202 /* check if an attribute with the same name exists */
3203 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003204
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003205 if (cur->ns == NULL)
3206 lastattr = xmlHasProp(parent, cur->name);
3207 else
3208 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3209 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3210 /* different instance, destroy it (attributes must be unique) */
3211 xmlFreeProp(lastattr);
3212 }
3213 /* find the end */
3214 lastattr = parent->properties;
3215 while (lastattr->next != NULL) {
3216 lastattr = lastattr->next;
3217 }
3218 lastattr->next = (xmlAttrPtr) cur;
3219 ((xmlAttrPtr) cur)->prev = lastattr;
3220 }
3221 } else {
3222 if (parent->children == NULL) {
3223 parent->children = cur;
3224 parent->last = cur;
3225 } else {
3226 prev = parent->last;
3227 prev->next = cur;
3228 cur->prev = prev;
3229 parent->last = cur;
3230 }
3231 }
Owen Taylor3473f882001-02-23 17:55:21 +00003232 return(cur);
3233}
3234
3235/**
3236 * xmlGetLastChild:
3237 * @parent: the parent node
3238 *
3239 * Search the last child of a node.
3240 * Returns the last child or NULL if none.
3241 */
3242xmlNodePtr
3243xmlGetLastChild(xmlNodePtr parent) {
3244 if (parent == NULL) {
3245#ifdef DEBUG_TREE
3246 xmlGenericError(xmlGenericErrorContext,
3247 "xmlGetLastChild : parent == NULL\n");
3248#endif
3249 return(NULL);
3250 }
3251 return(parent->last);
3252}
3253
3254/**
3255 * xmlFreeNodeList:
3256 * @cur: the first node in the list
3257 *
3258 * Free a node and all its siblings, this is a recursive behaviour, all
3259 * the children are freed too.
3260 */
3261void
3262xmlFreeNodeList(xmlNodePtr cur) {
3263 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003264 xmlDictPtr dict = NULL;
3265
3266 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003267 if (cur->type == XML_NAMESPACE_DECL) {
3268 xmlFreeNsList((xmlNsPtr) cur);
3269 return;
3270 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003271 if ((cur->type == XML_DOCUMENT_NODE) ||
3272#ifdef LIBXML_DOCB_ENABLED
3273 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003274#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003275 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003276 xmlFreeDoc((xmlDocPtr) cur);
3277 return;
3278 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003279 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003280 while (cur != NULL) {
3281 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003282 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003283
Daniel Veillarda880b122003-04-21 21:36:41 +00003284 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003285 xmlDeregisterNodeDefaultValue(cur);
3286
Daniel Veillard02141ea2001-04-30 11:46:40 +00003287 if ((cur->children != NULL) &&
3288 (cur->type != XML_ENTITY_REF_NODE))
3289 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003290 if (((cur->type == XML_ELEMENT_NODE) ||
3291 (cur->type == XML_XINCLUDE_START) ||
3292 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003293 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003294 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003295 if ((cur->type != XML_ELEMENT_NODE) &&
3296 (cur->type != XML_XINCLUDE_START) &&
3297 (cur->type != XML_XINCLUDE_END) &&
Daniel Veillard8874b942005-08-25 13:19:21 +00003298 (cur->type != XML_ENTITY_REF_NODE) &&
3299 (cur->content != (xmlChar *) &(cur->properties))) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003300 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003301 }
3302 if (((cur->type == XML_ELEMENT_NODE) ||
3303 (cur->type == XML_XINCLUDE_START) ||
3304 (cur->type == XML_XINCLUDE_END)) &&
3305 (cur->nsDef != NULL))
3306 xmlFreeNsList(cur->nsDef);
3307
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003308 /*
3309 * When a node is a text node or a comment, it uses a global static
3310 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003311 * Otherwise the node name might come from the document's
3312 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003313 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003314 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003315 (cur->type != XML_TEXT_NODE) &&
3316 (cur->type != XML_COMMENT_NODE))
3317 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003318 xmlFree(cur);
3319 }
Owen Taylor3473f882001-02-23 17:55:21 +00003320 cur = next;
3321 }
3322}
3323
3324/**
3325 * xmlFreeNode:
3326 * @cur: the node
3327 *
3328 * Free a node, this is a recursive behaviour, all the children are freed too.
3329 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3330 */
3331void
3332xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003333 xmlDictPtr dict = NULL;
3334
3335 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003336
Daniel Veillard02141ea2001-04-30 11:46:40 +00003337 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003338 if (cur->type == XML_DTD_NODE) {
3339 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003340 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003341 }
3342 if (cur->type == XML_NAMESPACE_DECL) {
3343 xmlFreeNs((xmlNsPtr) cur);
3344 return;
3345 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003346 if (cur->type == XML_ATTRIBUTE_NODE) {
3347 xmlFreeProp((xmlAttrPtr) cur);
3348 return;
3349 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003350
Daniel Veillarda880b122003-04-21 21:36:41 +00003351 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003352 xmlDeregisterNodeDefaultValue(cur);
3353
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003354 if (cur->doc != NULL) dict = cur->doc->dict;
3355
Owen Taylor3473f882001-02-23 17:55:21 +00003356 if ((cur->children != NULL) &&
3357 (cur->type != XML_ENTITY_REF_NODE))
3358 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003359 if (((cur->type == XML_ELEMENT_NODE) ||
3360 (cur->type == XML_XINCLUDE_START) ||
3361 (cur->type == XML_XINCLUDE_END)) &&
3362 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003363 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003364 if ((cur->type != XML_ELEMENT_NODE) &&
3365 (cur->content != NULL) &&
3366 (cur->type != XML_ENTITY_REF_NODE) &&
3367 (cur->type != XML_XINCLUDE_END) &&
Daniel Veillard8874b942005-08-25 13:19:21 +00003368 (cur->type != XML_XINCLUDE_START) &&
3369 (cur->content != (xmlChar *) &(cur->properties))) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003370 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003371 }
3372
Daniel Veillardacd370f2001-06-09 17:17:51 +00003373 /*
3374 * When a node is a text node or a comment, it uses a global static
3375 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003376 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003377 */
Owen Taylor3473f882001-02-23 17:55:21 +00003378 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003379 (cur->type != XML_TEXT_NODE) &&
3380 (cur->type != XML_COMMENT_NODE))
3381 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003382
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003383 if (((cur->type == XML_ELEMENT_NODE) ||
3384 (cur->type == XML_XINCLUDE_START) ||
3385 (cur->type == XML_XINCLUDE_END)) &&
3386 (cur->nsDef != NULL))
3387 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003388 xmlFree(cur);
3389}
3390
3391/**
3392 * xmlUnlinkNode:
3393 * @cur: the node
3394 *
3395 * Unlink a node from it's current context, the node is not freed
3396 */
3397void
3398xmlUnlinkNode(xmlNodePtr cur) {
3399 if (cur == NULL) {
3400#ifdef DEBUG_TREE
3401 xmlGenericError(xmlGenericErrorContext,
3402 "xmlUnlinkNode : node == NULL\n");
3403#endif
3404 return;
3405 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003406 if (cur->type == XML_DTD_NODE) {
3407 xmlDocPtr doc;
3408 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003409 if (doc != NULL) {
3410 if (doc->intSubset == (xmlDtdPtr) cur)
3411 doc->intSubset = NULL;
3412 if (doc->extSubset == (xmlDtdPtr) cur)
3413 doc->extSubset = NULL;
3414 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003415 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003416 if (cur->parent != NULL) {
3417 xmlNodePtr parent;
3418 parent = cur->parent;
3419 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardda6f4af2005-06-20 17:17:54 +00003420 /* If attribute is an ID from subset then remove it */
3421 if ((((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID) &&
3422 xmlIsID(parent->doc, parent, (xmlAttrPtr) cur)) {
3423 xmlRemoveID(cur->doc, (xmlAttrPtr) cur);
3424 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003425 if (parent->properties == (xmlAttrPtr) cur)
3426 parent->properties = ((xmlAttrPtr) cur)->next;
3427 } else {
3428 if (parent->children == cur)
3429 parent->children = cur->next;
3430 if (parent->last == cur)
3431 parent->last = cur->prev;
3432 }
3433 cur->parent = NULL;
3434 }
Owen Taylor3473f882001-02-23 17:55:21 +00003435 if (cur->next != NULL)
3436 cur->next->prev = cur->prev;
3437 if (cur->prev != NULL)
3438 cur->prev->next = cur->next;
3439 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003440}
3441
Daniel Veillard2156d432004-03-04 15:59:36 +00003442#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003443/**
3444 * xmlReplaceNode:
3445 * @old: the old node
3446 * @cur: the node
3447 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003448 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003449 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003450 * first unlinked from its existing context.
3451 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003452 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003453 */
3454xmlNodePtr
3455xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00003456 if (old == cur) return(NULL);
Daniel Veillarda03e3652004-11-02 18:45:30 +00003457 if ((old == NULL) || (old->parent == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003458#ifdef DEBUG_TREE
3459 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda03e3652004-11-02 18:45:30 +00003460 "xmlReplaceNode : old == NULL or without parent\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003461#endif
3462 return(NULL);
3463 }
3464 if (cur == NULL) {
3465 xmlUnlinkNode(old);
3466 return(old);
3467 }
3468 if (cur == old) {
3469 return(old);
3470 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003471 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3472#ifdef DEBUG_TREE
3473 xmlGenericError(xmlGenericErrorContext,
3474 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3475#endif
3476 return(old);
3477 }
3478 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3479#ifdef DEBUG_TREE
3480 xmlGenericError(xmlGenericErrorContext,
3481 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3482#endif
3483 return(old);
3484 }
Owen Taylor3473f882001-02-23 17:55:21 +00003485 xmlUnlinkNode(cur);
Daniel Veillard64d7d122005-05-11 18:03:42 +00003486 xmlSetTreeDoc(cur, old->doc);
Owen Taylor3473f882001-02-23 17:55:21 +00003487 cur->parent = old->parent;
3488 cur->next = old->next;
3489 if (cur->next != NULL)
3490 cur->next->prev = cur;
3491 cur->prev = old->prev;
3492 if (cur->prev != NULL)
3493 cur->prev->next = cur;
3494 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003495 if (cur->type == XML_ATTRIBUTE_NODE) {
3496 if (cur->parent->properties == (xmlAttrPtr)old)
3497 cur->parent->properties = ((xmlAttrPtr) cur);
Daniel Veillardda6f4af2005-06-20 17:17:54 +00003498
3499 /* If old attribute is ID and defined in DTD then remove ID */
3500 if ((((xmlAttrPtr) old)->atype == XML_ATTRIBUTE_ID) &&
3501 xmlIsID(old->doc, old->parent, (xmlAttrPtr) old)) {
3502 xmlRemoveID(old->doc, (xmlAttrPtr) old);
3503 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003504 } else {
3505 if (cur->parent->children == old)
3506 cur->parent->children = cur;
3507 if (cur->parent->last == old)
3508 cur->parent->last = cur;
3509 }
Owen Taylor3473f882001-02-23 17:55:21 +00003510 }
3511 old->next = old->prev = NULL;
3512 old->parent = NULL;
3513 return(old);
3514}
Daniel Veillard652327a2003-09-29 18:02:38 +00003515#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003516
3517/************************************************************************
3518 * *
3519 * Copy operations *
3520 * *
3521 ************************************************************************/
3522
3523/**
3524 * xmlCopyNamespace:
3525 * @cur: the namespace
3526 *
3527 * Do a copy of the namespace.
3528 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003529 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003530 */
3531xmlNsPtr
3532xmlCopyNamespace(xmlNsPtr cur) {
3533 xmlNsPtr ret;
3534
3535 if (cur == NULL) return(NULL);
3536 switch (cur->type) {
3537 case XML_LOCAL_NAMESPACE:
3538 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3539 break;
3540 default:
3541#ifdef DEBUG_TREE
3542 xmlGenericError(xmlGenericErrorContext,
3543 "xmlCopyNamespace: invalid type %d\n", cur->type);
3544#endif
3545 return(NULL);
3546 }
3547 return(ret);
3548}
3549
3550/**
3551 * xmlCopyNamespaceList:
3552 * @cur: the first namespace
3553 *
3554 * Do a copy of an namespace list.
3555 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003556 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003557 */
3558xmlNsPtr
3559xmlCopyNamespaceList(xmlNsPtr cur) {
3560 xmlNsPtr ret = NULL;
3561 xmlNsPtr p = NULL,q;
3562
3563 while (cur != NULL) {
3564 q = xmlCopyNamespace(cur);
3565 if (p == NULL) {
3566 ret = p = q;
3567 } else {
3568 p->next = q;
3569 p = q;
3570 }
3571 cur = cur->next;
3572 }
3573 return(ret);
3574}
3575
3576static xmlNodePtr
3577xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3578/**
3579 * xmlCopyProp:
3580 * @target: the element where the attribute will be grafted
3581 * @cur: the attribute
3582 *
3583 * Do a copy of the attribute.
3584 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003585 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003586 */
3587xmlAttrPtr
3588xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3589 xmlAttrPtr ret;
3590
3591 if (cur == NULL) return(NULL);
3592 if (target != NULL)
3593 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3594 else if (cur->parent != NULL)
3595 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3596 else if (cur->children != NULL)
3597 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3598 else
3599 ret = xmlNewDocProp(NULL, cur->name, NULL);
3600 if (ret == NULL) return(NULL);
3601 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003602
Owen Taylor3473f882001-02-23 17:55:21 +00003603 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003604 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003605
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003606 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3607 if (ns == NULL) {
3608 /*
3609 * Humm, we are copying an element whose namespace is defined
3610 * out of the new tree scope. Search it in the original tree
3611 * and add it at the top of the new tree
3612 */
3613 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3614 if (ns != NULL) {
3615 xmlNodePtr root = target;
3616 xmlNodePtr pred = NULL;
3617
3618 while (root->parent != NULL) {
3619 pred = root;
3620 root = root->parent;
3621 }
3622 if (root == (xmlNodePtr) target->doc) {
3623 /* correct possibly cycling above the document elt */
3624 root = pred;
3625 }
3626 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3627 }
3628 } else {
3629 /*
3630 * we have to find something appropriate here since
3631 * we cant be sure, that the namespce we found is identified
3632 * by the prefix
3633 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003634 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003635 /* this is the nice case */
3636 ret->ns = ns;
3637 } else {
3638 /*
3639 * we are in trouble: we need a new reconcilied namespace.
3640 * This is expensive
3641 */
3642 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3643 }
3644 }
3645
Owen Taylor3473f882001-02-23 17:55:21 +00003646 } else
3647 ret->ns = NULL;
3648
3649 if (cur->children != NULL) {
3650 xmlNodePtr tmp;
3651
3652 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3653 ret->last = NULL;
3654 tmp = ret->children;
3655 while (tmp != NULL) {
3656 /* tmp->parent = (xmlNodePtr)ret; */
3657 if (tmp->next == NULL)
3658 ret->last = tmp;
3659 tmp = tmp->next;
3660 }
3661 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003662 /*
3663 * Try to handle IDs
3664 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003665 if ((target!= NULL) && (cur!= NULL) &&
3666 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003667 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3668 if (xmlIsID(cur->doc, cur->parent, cur)) {
3669 xmlChar *id;
3670
3671 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3672 if (id != NULL) {
3673 xmlAddID(NULL, target->doc, id, ret);
3674 xmlFree(id);
3675 }
3676 }
3677 }
Owen Taylor3473f882001-02-23 17:55:21 +00003678 return(ret);
3679}
3680
3681/**
3682 * xmlCopyPropList:
3683 * @target: the element where the attributes will be grafted
3684 * @cur: the first attribute
3685 *
3686 * Do a copy of an attribute list.
3687 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003688 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003689 */
3690xmlAttrPtr
3691xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3692 xmlAttrPtr ret = NULL;
3693 xmlAttrPtr p = NULL,q;
3694
3695 while (cur != NULL) {
3696 q = xmlCopyProp(target, cur);
William M. Brack13dfa872004-09-18 04:52:08 +00003697 if (q == NULL)
3698 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003699 if (p == NULL) {
3700 ret = p = q;
3701 } else {
3702 p->next = q;
3703 q->prev = p;
3704 p = q;
3705 }
3706 cur = cur->next;
3707 }
3708 return(ret);
3709}
3710
3711/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003712 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003713 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003714 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003715 * tricky reason: namespaces. Doing a direct copy of a node
3716 * say RPM:Copyright without changing the namespace pointer to
3717 * something else can produce stale links. One way to do it is
3718 * to keep a reference counter but this doesn't work as soon
3719 * as one move the element or the subtree out of the scope of
3720 * the existing namespace. The actual solution seems to add
3721 * a copy of the namespace at the top of the copied tree if
3722 * not available in the subtree.
3723 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00003724 * The argument "recursive" normally indicates a recursive copy
3725 * of the node with values 0 (no) and 1 (yes). For XInclude,
3726 * however, we allow a value of 2 to indicate copy properties and
3727 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00003728 */
3729
3730static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003731xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00003732 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003733 xmlNodePtr ret;
3734
3735 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003736 switch (node->type) {
3737 case XML_TEXT_NODE:
3738 case XML_CDATA_SECTION_NODE:
3739 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003740 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003741 case XML_ENTITY_REF_NODE:
3742 case XML_ENTITY_NODE:
3743 case XML_PI_NODE:
3744 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003745 case XML_XINCLUDE_START:
3746 case XML_XINCLUDE_END:
3747 break;
3748 case XML_ATTRIBUTE_NODE:
3749 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3750 case XML_NAMESPACE_DECL:
3751 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3752
Daniel Veillard39196eb2001-06-19 18:09:42 +00003753 case XML_DOCUMENT_NODE:
3754 case XML_HTML_DOCUMENT_NODE:
3755#ifdef LIBXML_DOCB_ENABLED
3756 case XML_DOCB_DOCUMENT_NODE:
3757#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003758#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00003759 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00003760#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003761 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003762 case XML_NOTATION_NODE:
3763 case XML_DTD_NODE:
3764 case XML_ELEMENT_DECL:
3765 case XML_ATTRIBUTE_DECL:
3766 case XML_ENTITY_DECL:
3767 return(NULL);
3768 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003769
Owen Taylor3473f882001-02-23 17:55:21 +00003770 /*
3771 * Allocate a new node and fill the fields.
3772 */
3773 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3774 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003775 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003776 return(NULL);
3777 }
3778 memset(ret, 0, sizeof(xmlNode));
3779 ret->type = node->type;
3780
3781 ret->doc = doc;
3782 ret->parent = parent;
3783 if (node->name == xmlStringText)
3784 ret->name = xmlStringText;
3785 else if (node->name == xmlStringTextNoenc)
3786 ret->name = xmlStringTextNoenc;
3787 else if (node->name == xmlStringComment)
3788 ret->name = xmlStringComment;
Daniel Veillard03a53c32004-10-26 16:06:51 +00003789 else if (node->name != NULL) {
3790 if ((doc != NULL) && (doc->dict != NULL))
3791 ret->name = xmlDictLookup(doc->dict, node->name, -1);
3792 else
3793 ret->name = xmlStrdup(node->name);
3794 }
Daniel Veillard7db37732001-07-12 01:20:08 +00003795 if ((node->type != XML_ELEMENT_NODE) &&
3796 (node->content != NULL) &&
3797 (node->type != XML_ENTITY_REF_NODE) &&
3798 (node->type != XML_XINCLUDE_END) &&
3799 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003800 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003801 }else{
3802 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003803 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003804 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003805 if (parent != NULL) {
3806 xmlNodePtr tmp;
3807
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003808 /*
3809 * this is a tricky part for the node register thing:
3810 * in case ret does get coalesced in xmlAddChild
3811 * the deregister-node callback is called; so we register ret now already
3812 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003813 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003814 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3815
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003816 tmp = xmlAddChild(parent, ret);
3817 /* node could have coalesced */
3818 if (tmp != ret)
3819 return(tmp);
3820 }
Owen Taylor3473f882001-02-23 17:55:21 +00003821
William M. Brack57e9e912004-03-09 16:19:02 +00003822 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003823 goto out;
Daniel Veillard8874b942005-08-25 13:19:21 +00003824 if ((node->type == XML_ELEMENT_NODE) && (node->nsDef != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00003825 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3826
3827 if (node->ns != NULL) {
3828 xmlNsPtr ns;
3829
3830 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3831 if (ns == NULL) {
3832 /*
3833 * Humm, we are copying an element whose namespace is defined
3834 * out of the new tree scope. Search it in the original tree
3835 * and add it at the top of the new tree
3836 */
3837 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3838 if (ns != NULL) {
3839 xmlNodePtr root = ret;
3840
3841 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003842 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003843 }
3844 } else {
3845 /*
3846 * reference the existing namespace definition in our own tree.
3847 */
3848 ret->ns = ns;
3849 }
3850 }
Daniel Veillard8874b942005-08-25 13:19:21 +00003851 if ((node->type == XML_ELEMENT_NODE) && (node->properties != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00003852 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003853 if (node->type == XML_ENTITY_REF_NODE) {
3854 if ((doc == NULL) || (node->doc != doc)) {
3855 /*
3856 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003857 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003858 * we cannot keep the reference. Try to find it in the
3859 * target document.
3860 */
3861 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3862 } else {
3863 ret->children = node->children;
3864 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003865 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00003866 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003867 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003868 UPDATE_LAST_CHILD_AND_PARENT(ret)
3869 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003870
3871out:
3872 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00003873 if ((parent == NULL) &&
3874 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003875 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003876 return(ret);
3877}
3878
3879static xmlNodePtr
3880xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3881 xmlNodePtr ret = NULL;
3882 xmlNodePtr p = NULL,q;
3883
3884 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003885#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003886 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003887 if (doc == NULL) {
3888 node = node->next;
3889 continue;
3890 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003891 if (doc->intSubset == NULL) {
3892 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3893 q->doc = doc;
3894 q->parent = parent;
3895 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003896 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003897 } else {
3898 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003899 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003900 }
3901 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003902#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003903 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003904 if (ret == NULL) {
3905 q->prev = NULL;
3906 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003907 } else if (p != q) {
3908 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003909 p->next = q;
3910 q->prev = p;
3911 p = q;
3912 }
3913 node = node->next;
3914 }
3915 return(ret);
3916}
3917
3918/**
3919 * xmlCopyNode:
3920 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00003921 * @extended: if 1 do a recursive copy (properties, namespaces and children
3922 * when applicable)
3923 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00003924 *
3925 * Do a copy of the node.
3926 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003927 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003928 */
3929xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003930xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003931 xmlNodePtr ret;
3932
William M. Brack57e9e912004-03-09 16:19:02 +00003933 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00003934 return(ret);
3935}
3936
3937/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003938 * xmlDocCopyNode:
3939 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003940 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00003941 * @extended: if 1 do a recursive copy (properties, namespaces and children
3942 * when applicable)
3943 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00003944 *
3945 * Do a copy of the node to a given document.
3946 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003947 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003948 */
3949xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003950xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003951 xmlNodePtr ret;
3952
William M. Brack57e9e912004-03-09 16:19:02 +00003953 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00003954 return(ret);
3955}
3956
3957/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00003958 * xmlDocCopyNodeList:
3959 * @doc: the target document
3960 * @node: the first node in the list.
3961 *
3962 * Do a recursive copy of the node list.
3963 *
3964 * Returns: a new #xmlNodePtr, or NULL in case of error.
3965 */
3966xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) {
3967 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
3968 return(ret);
3969}
3970
3971/**
Owen Taylor3473f882001-02-23 17:55:21 +00003972 * xmlCopyNodeList:
3973 * @node: the first node in the list.
3974 *
3975 * Do a recursive copy of the node list.
Daniel Veillard03a53c32004-10-26 16:06:51 +00003976 * Use xmlDocCopyNodeList() if possible to ensure string interning.
Owen Taylor3473f882001-02-23 17:55:21 +00003977 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003978 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003979 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003980xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003981 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3982 return(ret);
3983}
3984
Daniel Veillard2156d432004-03-04 15:59:36 +00003985#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003986/**
Owen Taylor3473f882001-02-23 17:55:21 +00003987 * xmlCopyDtd:
3988 * @dtd: the dtd
3989 *
3990 * Do a copy of the dtd.
3991 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003992 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003993 */
3994xmlDtdPtr
3995xmlCopyDtd(xmlDtdPtr dtd) {
3996 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003997 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003998
3999 if (dtd == NULL) return(NULL);
4000 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4001 if (ret == NULL) return(NULL);
4002 if (dtd->entities != NULL)
4003 ret->entities = (void *) xmlCopyEntitiesTable(
4004 (xmlEntitiesTablePtr) dtd->entities);
4005 if (dtd->notations != NULL)
4006 ret->notations = (void *) xmlCopyNotationTable(
4007 (xmlNotationTablePtr) dtd->notations);
4008 if (dtd->elements != NULL)
4009 ret->elements = (void *) xmlCopyElementTable(
4010 (xmlElementTablePtr) dtd->elements);
4011 if (dtd->attributes != NULL)
4012 ret->attributes = (void *) xmlCopyAttributeTable(
4013 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004014 if (dtd->pentities != NULL)
4015 ret->pentities = (void *) xmlCopyEntitiesTable(
4016 (xmlEntitiesTablePtr) dtd->pentities);
4017
4018 cur = dtd->children;
4019 while (cur != NULL) {
4020 q = NULL;
4021
4022 if (cur->type == XML_ENTITY_DECL) {
4023 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4024 switch (tmp->etype) {
4025 case XML_INTERNAL_GENERAL_ENTITY:
4026 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4027 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4028 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4029 break;
4030 case XML_INTERNAL_PARAMETER_ENTITY:
4031 case XML_EXTERNAL_PARAMETER_ENTITY:
4032 q = (xmlNodePtr)
4033 xmlGetParameterEntityFromDtd(ret, tmp->name);
4034 break;
4035 case XML_INTERNAL_PREDEFINED_ENTITY:
4036 break;
4037 }
4038 } else if (cur->type == XML_ELEMENT_DECL) {
4039 xmlElementPtr tmp = (xmlElementPtr) cur;
4040 q = (xmlNodePtr)
4041 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4042 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4043 xmlAttributePtr tmp = (xmlAttributePtr) cur;
4044 q = (xmlNodePtr)
4045 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4046 } else if (cur->type == XML_COMMENT_NODE) {
4047 q = xmlCopyNode(cur, 0);
4048 }
4049
4050 if (q == NULL) {
4051 cur = cur->next;
4052 continue;
4053 }
4054
4055 if (p == NULL)
4056 ret->children = q;
4057 else
4058 p->next = q;
4059
4060 q->prev = p;
4061 q->parent = (xmlNodePtr) ret;
4062 q->next = NULL;
4063 ret->last = q;
4064 p = q;
4065 cur = cur->next;
4066 }
4067
Owen Taylor3473f882001-02-23 17:55:21 +00004068 return(ret);
4069}
Daniel Veillard2156d432004-03-04 15:59:36 +00004070#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004071
Daniel Veillard2156d432004-03-04 15:59:36 +00004072#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004073/**
4074 * xmlCopyDoc:
4075 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004076 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004077 *
4078 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004079 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004080 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004081 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004082 */
4083xmlDocPtr
4084xmlCopyDoc(xmlDocPtr doc, int recursive) {
4085 xmlDocPtr ret;
4086
4087 if (doc == NULL) return(NULL);
4088 ret = xmlNewDoc(doc->version);
4089 if (ret == NULL) return(NULL);
4090 if (doc->name != NULL)
4091 ret->name = xmlMemStrdup(doc->name);
4092 if (doc->encoding != NULL)
4093 ret->encoding = xmlStrdup(doc->encoding);
Daniel Veillardf59507d2005-01-27 17:26:49 +00004094 if (doc->URL != NULL)
4095 ret->URL = xmlStrdup(doc->URL);
Owen Taylor3473f882001-02-23 17:55:21 +00004096 ret->charset = doc->charset;
4097 ret->compression = doc->compression;
4098 ret->standalone = doc->standalone;
4099 if (!recursive) return(ret);
4100
Daniel Veillardb33c2012001-04-25 12:59:04 +00004101 ret->last = NULL;
4102 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004103#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004104 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004105 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004106 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004107 ret->intSubset->parent = ret;
4108 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004109#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004110 if (doc->oldNs != NULL)
4111 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4112 if (doc->children != NULL) {
4113 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004114
4115 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4116 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004117 ret->last = NULL;
4118 tmp = ret->children;
4119 while (tmp != NULL) {
4120 if (tmp->next == NULL)
4121 ret->last = tmp;
4122 tmp = tmp->next;
4123 }
4124 }
4125 return(ret);
4126}
Daniel Veillard652327a2003-09-29 18:02:38 +00004127#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004128
4129/************************************************************************
4130 * *
4131 * Content access functions *
4132 * *
4133 ************************************************************************/
4134
4135/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004136 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004137 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004138 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004139 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004140 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004141 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004142 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004143 */
4144long
4145xmlGetLineNo(xmlNodePtr node)
4146{
4147 long result = -1;
4148
4149 if (!node)
4150 return result;
Daniel Veillard73da77e2005-08-24 14:05:37 +00004151 if ((node->type == XML_ELEMENT_NODE) ||
4152 (node->type == XML_TEXT_NODE) ||
4153 (node->type == XML_COMMENT_NODE) ||
4154 (node->type == XML_PI_NODE))
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004155 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004156 else if ((node->prev != NULL) &&
4157 ((node->prev->type == XML_ELEMENT_NODE) ||
Daniel Veillard73da77e2005-08-24 14:05:37 +00004158 (node->prev->type == XML_TEXT_NODE) ||
4159 (node->prev->type == XML_COMMENT_NODE) ||
4160 (node->prev->type == XML_PI_NODE)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004161 result = xmlGetLineNo(node->prev);
4162 else if ((node->parent != NULL) &&
Daniel Veillard73da77e2005-08-24 14:05:37 +00004163 (node->parent->type == XML_ELEMENT_NODE))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004164 result = xmlGetLineNo(node->parent);
4165
4166 return result;
4167}
4168
Daniel Veillard2156d432004-03-04 15:59:36 +00004169#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004170/**
4171 * xmlGetNodePath:
4172 * @node: a node
4173 *
4174 * Build a structure based Path for the given node
4175 *
4176 * Returns the new path or NULL in case of error. The caller must free
4177 * the returned string
4178 */
4179xmlChar *
4180xmlGetNodePath(xmlNodePtr node)
4181{
4182 xmlNodePtr cur, tmp, next;
4183 xmlChar *buffer = NULL, *temp;
4184 size_t buf_len;
4185 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004186 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004187 const char *name;
4188 char nametemp[100];
4189 int occur = 0;
4190
4191 if (node == NULL)
4192 return (NULL);
4193
4194 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004195 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004196 if (buffer == NULL) {
4197 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004198 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004199 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004200 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004201 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004202 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004203 xmlFree(buffer);
4204 return (NULL);
4205 }
4206
4207 buffer[0] = 0;
4208 cur = node;
4209 do {
4210 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004211 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004212 occur = 0;
4213 if ((cur->type == XML_DOCUMENT_NODE) ||
4214 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4215 if (buffer[0] == '/')
4216 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004217 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004218 next = NULL;
4219 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004220 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004221 name = (const char *) cur->name;
4222 if (cur->ns) {
William M. Brack84d83e32003-12-23 03:45:17 +00004223 if (cur->ns->prefix != NULL)
William M. Brack13dfa872004-09-18 04:52:08 +00004224 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4225 (char *)cur->ns->prefix, (char *)cur->name);
William M. Brack84d83e32003-12-23 03:45:17 +00004226 else
William M. Brack13dfa872004-09-18 04:52:08 +00004227 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4228 (char *)cur->name);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004229 nametemp[sizeof(nametemp) - 1] = 0;
4230 name = nametemp;
4231 }
4232 next = cur->parent;
4233
4234 /*
4235 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004236 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004237 */
4238 tmp = cur->prev;
4239 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004240 if ((tmp->type == XML_ELEMENT_NODE) &&
Daniel Veillard0996a162005-02-05 14:00:10 +00004241 (xmlStrEqual(cur->name, tmp->name)) &&
4242 ((tmp->ns == cur->ns) ||
4243 ((tmp->ns != NULL) && (cur->ns != NULL) &&
4244 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004245 occur++;
4246 tmp = tmp->prev;
4247 }
4248 if (occur == 0) {
4249 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004250 while (tmp != NULL && occur == 0) {
4251 if ((tmp->type == XML_ELEMENT_NODE) &&
Daniel Veillard0996a162005-02-05 14:00:10 +00004252 (xmlStrEqual(cur->name, tmp->name)) &&
4253 ((tmp->ns == cur->ns) ||
4254 ((tmp->ns != NULL) && (cur->ns != NULL) &&
4255 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004256 occur++;
4257 tmp = tmp->next;
4258 }
4259 if (occur != 0)
4260 occur = 1;
4261 } else
4262 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004263 } else if (cur->type == XML_COMMENT_NODE) {
4264 sep = "/";
4265 name = "comment()";
4266 next = cur->parent;
4267
4268 /*
4269 * Thumbler index computation
4270 */
4271 tmp = cur->prev;
4272 while (tmp != NULL) {
4273 if (tmp->type == XML_COMMENT_NODE)
4274 occur++;
4275 tmp = tmp->prev;
4276 }
4277 if (occur == 0) {
4278 tmp = cur->next;
4279 while (tmp != NULL && occur == 0) {
4280 if (tmp->type == XML_COMMENT_NODE)
4281 occur++;
4282 tmp = tmp->next;
4283 }
4284 if (occur != 0)
4285 occur = 1;
4286 } else
4287 occur++;
4288 } else if ((cur->type == XML_TEXT_NODE) ||
4289 (cur->type == XML_CDATA_SECTION_NODE)) {
4290 sep = "/";
4291 name = "text()";
4292 next = cur->parent;
4293
4294 /*
4295 * Thumbler index computation
4296 */
4297 tmp = cur->prev;
4298 while (tmp != NULL) {
4299 if ((cur->type == XML_TEXT_NODE) ||
4300 (cur->type == XML_CDATA_SECTION_NODE))
4301 occur++;
4302 tmp = tmp->prev;
4303 }
4304 if (occur == 0) {
4305 tmp = cur->next;
4306 while (tmp != NULL && occur == 0) {
Daniel Veillard1f8658a2004-08-14 21:46:31 +00004307 if ((tmp->type == XML_TEXT_NODE) ||
4308 (tmp->type == XML_CDATA_SECTION_NODE))
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004309 occur++;
4310 tmp = tmp->next;
4311 }
4312 if (occur != 0)
4313 occur = 1;
4314 } else
4315 occur++;
4316 } else if (cur->type == XML_PI_NODE) {
4317 sep = "/";
4318 snprintf(nametemp, sizeof(nametemp) - 1,
William M. Brack13dfa872004-09-18 04:52:08 +00004319 "processing-instruction('%s')", (char *)cur->name);
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004320 nametemp[sizeof(nametemp) - 1] = 0;
4321 name = nametemp;
4322
4323 next = cur->parent;
4324
4325 /*
4326 * Thumbler index computation
4327 */
4328 tmp = cur->prev;
4329 while (tmp != NULL) {
4330 if ((tmp->type == XML_PI_NODE) &&
4331 (xmlStrEqual(cur->name, tmp->name)))
4332 occur++;
4333 tmp = tmp->prev;
4334 }
4335 if (occur == 0) {
4336 tmp = cur->next;
4337 while (tmp != NULL && occur == 0) {
4338 if ((tmp->type == XML_PI_NODE) &&
4339 (xmlStrEqual(cur->name, tmp->name)))
4340 occur++;
4341 tmp = tmp->next;
4342 }
4343 if (occur != 0)
4344 occur = 1;
4345 } else
4346 occur++;
4347
Daniel Veillard8faa7832001-11-26 15:58:08 +00004348 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004349 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004350 name = (const char *) (((xmlAttrPtr) cur)->name);
Daniel Veillard365c8062005-07-19 11:31:55 +00004351 if (cur->ns) {
4352 if (cur->ns->prefix != NULL)
4353 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4354 (char *)cur->ns->prefix, (char *)cur->name);
4355 else
4356 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4357 (char *)cur->name);
4358 nametemp[sizeof(nametemp) - 1] = 0;
4359 name = nametemp;
4360 }
Daniel Veillard8faa7832001-11-26 15:58:08 +00004361 next = ((xmlAttrPtr) cur)->parent;
4362 } else {
4363 next = cur->parent;
4364 }
4365
4366 /*
4367 * Make sure there is enough room
4368 */
4369 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4370 buf_len =
4371 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4372 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4373 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004374 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004375 xmlFree(buf);
4376 xmlFree(buffer);
4377 return (NULL);
4378 }
4379 buffer = temp;
4380 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4381 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004382 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004383 xmlFree(buf);
4384 xmlFree(buffer);
4385 return (NULL);
4386 }
4387 buf = temp;
4388 }
4389 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004390 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004391 sep, name, (char *) buffer);
4392 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004393 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004394 sep, name, occur, (char *) buffer);
William M. Brack13dfa872004-09-18 04:52:08 +00004395 snprintf((char *) buffer, buf_len, "%s", (char *)buf);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004396 cur = next;
4397 } while (cur != NULL);
4398 xmlFree(buf);
4399 return (buffer);
4400}
Daniel Veillard652327a2003-09-29 18:02:38 +00004401#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004402
4403/**
Owen Taylor3473f882001-02-23 17:55:21 +00004404 * xmlDocGetRootElement:
4405 * @doc: the document
4406 *
4407 * Get the root element of the document (doc->children is a list
4408 * containing possibly comments, PIs, etc ...).
4409 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004410 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004411 */
4412xmlNodePtr
4413xmlDocGetRootElement(xmlDocPtr doc) {
4414 xmlNodePtr ret;
4415
4416 if (doc == NULL) return(NULL);
4417 ret = doc->children;
4418 while (ret != NULL) {
4419 if (ret->type == XML_ELEMENT_NODE)
4420 return(ret);
4421 ret = ret->next;
4422 }
4423 return(ret);
4424}
4425
Daniel Veillard2156d432004-03-04 15:59:36 +00004426#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004427/**
4428 * xmlDocSetRootElement:
4429 * @doc: the document
4430 * @root: the new document root element
4431 *
4432 * Set the root element of the document (doc->children is a list
4433 * containing possibly comments, PIs, etc ...).
4434 *
4435 * Returns the old root element if any was found
4436 */
4437xmlNodePtr
4438xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4439 xmlNodePtr old = NULL;
4440
4441 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004442 if (root == NULL)
4443 return(NULL);
4444 xmlUnlinkNode(root);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00004445 xmlSetTreeDoc(root, doc);
Daniel Veillardc575b992002-02-08 13:28:40 +00004446 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004447 old = doc->children;
4448 while (old != NULL) {
4449 if (old->type == XML_ELEMENT_NODE)
4450 break;
4451 old = old->next;
4452 }
4453 if (old == NULL) {
4454 if (doc->children == NULL) {
4455 doc->children = root;
4456 doc->last = root;
4457 } else {
4458 xmlAddSibling(doc->children, root);
4459 }
4460 } else {
4461 xmlReplaceNode(old, root);
4462 }
4463 return(old);
4464}
Daniel Veillard2156d432004-03-04 15:59:36 +00004465#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004466
Daniel Veillard2156d432004-03-04 15:59:36 +00004467#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004468/**
4469 * xmlNodeSetLang:
4470 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004471 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004472 *
4473 * Set the language of a node, i.e. the values of the xml:lang
4474 * attribute.
4475 */
4476void
4477xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004478 xmlNsPtr ns;
4479
Owen Taylor3473f882001-02-23 17:55:21 +00004480 if (cur == NULL) return;
4481 switch(cur->type) {
4482 case XML_TEXT_NODE:
4483 case XML_CDATA_SECTION_NODE:
4484 case XML_COMMENT_NODE:
4485 case XML_DOCUMENT_NODE:
4486 case XML_DOCUMENT_TYPE_NODE:
4487 case XML_DOCUMENT_FRAG_NODE:
4488 case XML_NOTATION_NODE:
4489 case XML_HTML_DOCUMENT_NODE:
4490 case XML_DTD_NODE:
4491 case XML_ELEMENT_DECL:
4492 case XML_ATTRIBUTE_DECL:
4493 case XML_ENTITY_DECL:
4494 case XML_PI_NODE:
4495 case XML_ENTITY_REF_NODE:
4496 case XML_ENTITY_NODE:
4497 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004498#ifdef LIBXML_DOCB_ENABLED
4499 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004500#endif
4501 case XML_XINCLUDE_START:
4502 case XML_XINCLUDE_END:
4503 return;
4504 case XML_ELEMENT_NODE:
4505 case XML_ATTRIBUTE_NODE:
4506 break;
4507 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004508 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4509 if (ns == NULL)
4510 return;
4511 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004512}
Daniel Veillard652327a2003-09-29 18:02:38 +00004513#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004514
4515/**
4516 * xmlNodeGetLang:
4517 * @cur: the node being checked
4518 *
4519 * Searches the language of a node, i.e. the values of the xml:lang
4520 * attribute or the one carried by the nearest ancestor.
4521 *
4522 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004523 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004524 */
4525xmlChar *
4526xmlNodeGetLang(xmlNodePtr cur) {
4527 xmlChar *lang;
4528
4529 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004530 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004531 if (lang != NULL)
4532 return(lang);
4533 cur = cur->parent;
4534 }
4535 return(NULL);
4536}
4537
4538
Daniel Veillard652327a2003-09-29 18:02:38 +00004539#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004540/**
4541 * xmlNodeSetSpacePreserve:
4542 * @cur: the node being changed
4543 * @val: the xml:space value ("0": default, 1: "preserve")
4544 *
4545 * Set (or reset) the space preserving behaviour of a node, i.e. the
4546 * value of the xml:space attribute.
4547 */
4548void
4549xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004550 xmlNsPtr ns;
4551
Owen Taylor3473f882001-02-23 17:55:21 +00004552 if (cur == NULL) return;
4553 switch(cur->type) {
4554 case XML_TEXT_NODE:
4555 case XML_CDATA_SECTION_NODE:
4556 case XML_COMMENT_NODE:
4557 case XML_DOCUMENT_NODE:
4558 case XML_DOCUMENT_TYPE_NODE:
4559 case XML_DOCUMENT_FRAG_NODE:
4560 case XML_NOTATION_NODE:
4561 case XML_HTML_DOCUMENT_NODE:
4562 case XML_DTD_NODE:
4563 case XML_ELEMENT_DECL:
4564 case XML_ATTRIBUTE_DECL:
4565 case XML_ENTITY_DECL:
4566 case XML_PI_NODE:
4567 case XML_ENTITY_REF_NODE:
4568 case XML_ENTITY_NODE:
4569 case XML_NAMESPACE_DECL:
4570 case XML_XINCLUDE_START:
4571 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004572#ifdef LIBXML_DOCB_ENABLED
4573 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004574#endif
4575 return;
4576 case XML_ELEMENT_NODE:
4577 case XML_ATTRIBUTE_NODE:
4578 break;
4579 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004580 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4581 if (ns == NULL)
4582 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004583 switch (val) {
4584 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004585 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004586 break;
4587 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004588 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004589 break;
4590 }
4591}
Daniel Veillard652327a2003-09-29 18:02:38 +00004592#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004593
4594/**
4595 * xmlNodeGetSpacePreserve:
4596 * @cur: the node being checked
4597 *
4598 * Searches the space preserving behaviour of a node, i.e. the values
4599 * of the xml:space attribute or the one carried by the nearest
4600 * ancestor.
4601 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004602 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004603 */
4604int
4605xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4606 xmlChar *space;
4607
4608 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004609 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004610 if (space != NULL) {
4611 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4612 xmlFree(space);
4613 return(1);
4614 }
4615 if (xmlStrEqual(space, BAD_CAST "default")) {
4616 xmlFree(space);
4617 return(0);
4618 }
4619 xmlFree(space);
4620 }
4621 cur = cur->parent;
4622 }
4623 return(-1);
4624}
4625
Daniel Veillard652327a2003-09-29 18:02:38 +00004626#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004627/**
4628 * xmlNodeSetName:
4629 * @cur: the node being changed
4630 * @name: the new tag name
4631 *
4632 * Set (or reset) the name of a node.
4633 */
4634void
4635xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00004636 xmlDocPtr doc;
4637 xmlDictPtr dict;
4638
Owen Taylor3473f882001-02-23 17:55:21 +00004639 if (cur == NULL) return;
4640 if (name == NULL) return;
4641 switch(cur->type) {
4642 case XML_TEXT_NODE:
4643 case XML_CDATA_SECTION_NODE:
4644 case XML_COMMENT_NODE:
4645 case XML_DOCUMENT_TYPE_NODE:
4646 case XML_DOCUMENT_FRAG_NODE:
4647 case XML_NOTATION_NODE:
4648 case XML_HTML_DOCUMENT_NODE:
4649 case XML_NAMESPACE_DECL:
4650 case XML_XINCLUDE_START:
4651 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004652#ifdef LIBXML_DOCB_ENABLED
4653 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004654#endif
4655 return;
4656 case XML_ELEMENT_NODE:
4657 case XML_ATTRIBUTE_NODE:
4658 case XML_PI_NODE:
4659 case XML_ENTITY_REF_NODE:
4660 case XML_ENTITY_NODE:
4661 case XML_DTD_NODE:
4662 case XML_DOCUMENT_NODE:
4663 case XML_ELEMENT_DECL:
4664 case XML_ATTRIBUTE_DECL:
4665 case XML_ENTITY_DECL:
4666 break;
4667 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00004668 doc = cur->doc;
4669 if (doc != NULL)
4670 dict = doc->dict;
4671 else
4672 dict = NULL;
4673 if (dict != NULL) {
4674 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
4675 xmlFree((xmlChar *) cur->name);
4676 cur->name = xmlDictLookup(dict, name, -1);
4677 } else {
4678 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4679 cur->name = xmlStrdup(name);
4680 }
Owen Taylor3473f882001-02-23 17:55:21 +00004681}
Daniel Veillard2156d432004-03-04 15:59:36 +00004682#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004683
Daniel Veillard2156d432004-03-04 15:59:36 +00004684#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004685/**
4686 * xmlNodeSetBase:
4687 * @cur: the node being changed
4688 * @uri: the new base URI
4689 *
4690 * Set (or reset) the base URI of a node, i.e. the value of the
4691 * xml:base attribute.
4692 */
4693void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004694xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004695 xmlNsPtr ns;
4696
Owen Taylor3473f882001-02-23 17:55:21 +00004697 if (cur == NULL) return;
4698 switch(cur->type) {
4699 case XML_TEXT_NODE:
4700 case XML_CDATA_SECTION_NODE:
4701 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004702 case XML_DOCUMENT_TYPE_NODE:
4703 case XML_DOCUMENT_FRAG_NODE:
4704 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004705 case XML_DTD_NODE:
4706 case XML_ELEMENT_DECL:
4707 case XML_ATTRIBUTE_DECL:
4708 case XML_ENTITY_DECL:
4709 case XML_PI_NODE:
4710 case XML_ENTITY_REF_NODE:
4711 case XML_ENTITY_NODE:
4712 case XML_NAMESPACE_DECL:
4713 case XML_XINCLUDE_START:
4714 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004715 return;
4716 case XML_ELEMENT_NODE:
4717 case XML_ATTRIBUTE_NODE:
4718 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004719 case XML_DOCUMENT_NODE:
4720#ifdef LIBXML_DOCB_ENABLED
4721 case XML_DOCB_DOCUMENT_NODE:
4722#endif
4723 case XML_HTML_DOCUMENT_NODE: {
4724 xmlDocPtr doc = (xmlDocPtr) cur;
4725
4726 if (doc->URL != NULL)
4727 xmlFree((xmlChar *) doc->URL);
4728 if (uri == NULL)
4729 doc->URL = NULL;
4730 else
4731 doc->URL = xmlStrdup(uri);
4732 return;
4733 }
Owen Taylor3473f882001-02-23 17:55:21 +00004734 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004735
4736 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4737 if (ns == NULL)
4738 return;
4739 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004740}
Daniel Veillard652327a2003-09-29 18:02:38 +00004741#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004742
4743/**
Owen Taylor3473f882001-02-23 17:55:21 +00004744 * xmlNodeGetBase:
4745 * @doc: the document the node pertains to
4746 * @cur: the node being checked
4747 *
4748 * Searches for the BASE URL. The code should work on both XML
4749 * and HTML document even if base mechanisms are completely different.
4750 * It returns the base as defined in RFC 2396 sections
4751 * 5.1.1. Base URI within Document Content
4752 * and
4753 * 5.1.2. Base URI from the Encapsulating Entity
4754 * However it does not return the document base (5.1.3), use
4755 * xmlDocumentGetBase() for this
4756 *
4757 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004758 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004759 */
4760xmlChar *
4761xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004762 xmlChar *oldbase = NULL;
4763 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004764
4765 if ((cur == NULL) && (doc == NULL))
4766 return(NULL);
4767 if (doc == NULL) doc = cur->doc;
4768 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4769 cur = doc->children;
4770 while ((cur != NULL) && (cur->name != NULL)) {
4771 if (cur->type != XML_ELEMENT_NODE) {
4772 cur = cur->next;
4773 continue;
4774 }
4775 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4776 cur = cur->children;
4777 continue;
4778 }
4779 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4780 cur = cur->children;
4781 continue;
4782 }
4783 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4784 return(xmlGetProp(cur, BAD_CAST "href"));
4785 }
4786 cur = cur->next;
4787 }
4788 return(NULL);
4789 }
4790 while (cur != NULL) {
4791 if (cur->type == XML_ENTITY_DECL) {
4792 xmlEntityPtr ent = (xmlEntityPtr) cur;
4793 return(xmlStrdup(ent->URI));
4794 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004795 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004796 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004797 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004798 if (oldbase != NULL) {
4799 newbase = xmlBuildURI(oldbase, base);
4800 if (newbase != NULL) {
4801 xmlFree(oldbase);
4802 xmlFree(base);
4803 oldbase = newbase;
4804 } else {
4805 xmlFree(oldbase);
4806 xmlFree(base);
4807 return(NULL);
4808 }
4809 } else {
4810 oldbase = base;
4811 }
4812 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4813 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4814 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4815 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004816 }
4817 }
Owen Taylor3473f882001-02-23 17:55:21 +00004818 cur = cur->parent;
4819 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004820 if ((doc != NULL) && (doc->URL != NULL)) {
4821 if (oldbase == NULL)
4822 return(xmlStrdup(doc->URL));
4823 newbase = xmlBuildURI(oldbase, doc->URL);
4824 xmlFree(oldbase);
4825 return(newbase);
4826 }
4827 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004828}
4829
4830/**
Daniel Veillard78697292003-10-19 20:44:43 +00004831 * xmlNodeBufGetContent:
4832 * @buffer: a buffer
4833 * @cur: the node being read
4834 *
4835 * Read the value of a node @cur, this can be either the text carried
4836 * directly by this node if it's a TEXT node or the aggregate string
4837 * of the values carried by this node child's (TEXT and ENTITY_REF).
4838 * Entity references are substituted.
4839 * Fills up the buffer @buffer with this value
4840 *
4841 * Returns 0 in case of success and -1 in case of error.
4842 */
4843int
4844xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4845{
4846 if ((cur == NULL) || (buffer == NULL)) return(-1);
4847 switch (cur->type) {
4848 case XML_CDATA_SECTION_NODE:
4849 case XML_TEXT_NODE:
4850 xmlBufferCat(buffer, cur->content);
4851 break;
4852 case XML_DOCUMENT_FRAG_NODE:
4853 case XML_ELEMENT_NODE:{
4854 xmlNodePtr tmp = cur;
4855
4856 while (tmp != NULL) {
4857 switch (tmp->type) {
4858 case XML_CDATA_SECTION_NODE:
4859 case XML_TEXT_NODE:
4860 if (tmp->content != NULL)
4861 xmlBufferCat(buffer, tmp->content);
4862 break;
4863 case XML_ENTITY_REF_NODE:
4864 xmlNodeBufGetContent(buffer, tmp->children);
4865 break;
4866 default:
4867 break;
4868 }
4869 /*
4870 * Skip to next node
4871 */
4872 if (tmp->children != NULL) {
4873 if (tmp->children->type != XML_ENTITY_DECL) {
4874 tmp = tmp->children;
4875 continue;
4876 }
4877 }
4878 if (tmp == cur)
4879 break;
4880
4881 if (tmp->next != NULL) {
4882 tmp = tmp->next;
4883 continue;
4884 }
4885
4886 do {
4887 tmp = tmp->parent;
4888 if (tmp == NULL)
4889 break;
4890 if (tmp == cur) {
4891 tmp = NULL;
4892 break;
4893 }
4894 if (tmp->next != NULL) {
4895 tmp = tmp->next;
4896 break;
4897 }
4898 } while (tmp != NULL);
4899 }
4900 break;
4901 }
4902 case XML_ATTRIBUTE_NODE:{
4903 xmlAttrPtr attr = (xmlAttrPtr) cur;
4904 xmlNodePtr tmp = attr->children;
4905
4906 while (tmp != NULL) {
4907 if (tmp->type == XML_TEXT_NODE)
4908 xmlBufferCat(buffer, tmp->content);
4909 else
4910 xmlNodeBufGetContent(buffer, tmp);
4911 tmp = tmp->next;
4912 }
4913 break;
4914 }
4915 case XML_COMMENT_NODE:
4916 case XML_PI_NODE:
4917 xmlBufferCat(buffer, cur->content);
4918 break;
4919 case XML_ENTITY_REF_NODE:{
4920 xmlEntityPtr ent;
4921 xmlNodePtr tmp;
4922
4923 /* lookup entity declaration */
4924 ent = xmlGetDocEntity(cur->doc, cur->name);
4925 if (ent == NULL)
4926 return(-1);
4927
4928 /* an entity content can be any "well balanced chunk",
4929 * i.e. the result of the content [43] production:
4930 * http://www.w3.org/TR/REC-xml#NT-content
4931 * -> we iterate through child nodes and recursive call
4932 * xmlNodeGetContent() which handles all possible node types */
4933 tmp = ent->children;
4934 while (tmp) {
4935 xmlNodeBufGetContent(buffer, tmp);
4936 tmp = tmp->next;
4937 }
4938 break;
4939 }
4940 case XML_ENTITY_NODE:
4941 case XML_DOCUMENT_TYPE_NODE:
4942 case XML_NOTATION_NODE:
4943 case XML_DTD_NODE:
4944 case XML_XINCLUDE_START:
4945 case XML_XINCLUDE_END:
4946 break;
4947 case XML_DOCUMENT_NODE:
4948#ifdef LIBXML_DOCB_ENABLED
4949 case XML_DOCB_DOCUMENT_NODE:
4950#endif
4951 case XML_HTML_DOCUMENT_NODE:
4952 cur = cur->children;
4953 while (cur!= NULL) {
4954 if ((cur->type == XML_ELEMENT_NODE) ||
4955 (cur->type == XML_TEXT_NODE) ||
4956 (cur->type == XML_CDATA_SECTION_NODE)) {
4957 xmlNodeBufGetContent(buffer, cur);
4958 }
4959 cur = cur->next;
4960 }
4961 break;
4962 case XML_NAMESPACE_DECL:
4963 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
4964 break;
4965 case XML_ELEMENT_DECL:
4966 case XML_ATTRIBUTE_DECL:
4967 case XML_ENTITY_DECL:
4968 break;
4969 }
4970 return(0);
4971}
4972/**
Owen Taylor3473f882001-02-23 17:55:21 +00004973 * xmlNodeGetContent:
4974 * @cur: the node being read
4975 *
4976 * Read the value of a node, this can be either the text carried
4977 * directly by this node if it's a TEXT node or the aggregate string
4978 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004979 * Entity references are substituted.
4980 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004981 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004982 */
4983xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004984xmlNodeGetContent(xmlNodePtr cur)
4985{
4986 if (cur == NULL)
4987 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004988 switch (cur->type) {
4989 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004990 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00004991 xmlBufferPtr buffer;
4992 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004993
Daniel Veillard814a76d2003-01-23 18:24:20 +00004994 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004995 if (buffer == NULL)
4996 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00004997 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004998 ret = buffer->content;
4999 buffer->content = NULL;
5000 xmlBufferFree(buffer);
5001 return (ret);
5002 }
5003 case XML_ATTRIBUTE_NODE:{
5004 xmlAttrPtr attr = (xmlAttrPtr) cur;
5005
5006 if (attr->parent != NULL)
5007 return (xmlNodeListGetString
5008 (attr->parent->doc, attr->children, 1));
5009 else
5010 return (xmlNodeListGetString(NULL, attr->children, 1));
5011 break;
5012 }
Owen Taylor3473f882001-02-23 17:55:21 +00005013 case XML_COMMENT_NODE:
5014 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005015 if (cur->content != NULL)
5016 return (xmlStrdup(cur->content));
5017 return (NULL);
5018 case XML_ENTITY_REF_NODE:{
5019 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00005020 xmlBufferPtr buffer;
5021 xmlChar *ret;
5022
5023 /* lookup entity declaration */
5024 ent = xmlGetDocEntity(cur->doc, cur->name);
5025 if (ent == NULL)
5026 return (NULL);
5027
5028 buffer = xmlBufferCreate();
5029 if (buffer == NULL)
5030 return (NULL);
5031
Daniel Veillardc4696922003-10-19 21:47:14 +00005032 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005033
5034 ret = buffer->content;
5035 buffer->content = NULL;
5036 xmlBufferFree(buffer);
5037 return (ret);
5038 }
Owen Taylor3473f882001-02-23 17:55:21 +00005039 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005040 case XML_DOCUMENT_TYPE_NODE:
5041 case XML_NOTATION_NODE:
5042 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005043 case XML_XINCLUDE_START:
5044 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00005045 return (NULL);
5046 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005047#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005048 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005049#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005050 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00005051 xmlBufferPtr buffer;
5052 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005053
Daniel Veillardc4696922003-10-19 21:47:14 +00005054 buffer = xmlBufferCreate();
5055 if (buffer == NULL)
5056 return (NULL);
5057
5058 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5059
5060 ret = buffer->content;
5061 buffer->content = NULL;
5062 xmlBufferFree(buffer);
5063 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005064 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005065 case XML_NAMESPACE_DECL: {
5066 xmlChar *tmp;
5067
5068 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5069 return (tmp);
5070 }
Owen Taylor3473f882001-02-23 17:55:21 +00005071 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005072 /* TODO !!! */
5073 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005074 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005075 /* TODO !!! */
5076 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005077 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005078 /* TODO !!! */
5079 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005080 case XML_CDATA_SECTION_NODE:
5081 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005082 if (cur->content != NULL)
5083 return (xmlStrdup(cur->content));
5084 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005085 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005086 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005087}
Daniel Veillard652327a2003-09-29 18:02:38 +00005088
Owen Taylor3473f882001-02-23 17:55:21 +00005089/**
5090 * xmlNodeSetContent:
5091 * @cur: the node being modified
5092 * @content: the new value of the content
5093 *
5094 * Replace the content of a node.
5095 */
5096void
5097xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5098 if (cur == NULL) {
5099#ifdef DEBUG_TREE
5100 xmlGenericError(xmlGenericErrorContext,
5101 "xmlNodeSetContent : node == NULL\n");
5102#endif
5103 return;
5104 }
5105 switch (cur->type) {
5106 case XML_DOCUMENT_FRAG_NODE:
5107 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005108 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005109 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5110 cur->children = xmlStringGetNodeList(cur->doc, content);
5111 UPDATE_LAST_CHILD_AND_PARENT(cur)
5112 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005113 case XML_TEXT_NODE:
5114 case XML_CDATA_SECTION_NODE:
5115 case XML_ENTITY_REF_NODE:
5116 case XML_ENTITY_NODE:
5117 case XML_PI_NODE:
5118 case XML_COMMENT_NODE:
Daniel Veillard8874b942005-08-25 13:19:21 +00005119 if ((cur->content != NULL) &&
5120 (cur->content != (xmlChar *) &(cur->properties))) {
William M. Brack7762bb12004-01-04 14:49:01 +00005121 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
Daniel Veillardc587bce2005-05-10 15:28:08 +00005122 (xmlDictOwns(cur->doc->dict, cur->content))))
William M. Brack7762bb12004-01-04 14:49:01 +00005123 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005124 }
5125 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5126 cur->last = cur->children = NULL;
5127 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005128 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005129 } else
5130 cur->content = NULL;
Daniel Veillard8874b942005-08-25 13:19:21 +00005131 cur->properties = NULL;
5132 cur->nsDef = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00005133 break;
5134 case XML_DOCUMENT_NODE:
5135 case XML_HTML_DOCUMENT_NODE:
5136 case XML_DOCUMENT_TYPE_NODE:
5137 case XML_XINCLUDE_START:
5138 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005139#ifdef LIBXML_DOCB_ENABLED
5140 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005141#endif
5142 break;
5143 case XML_NOTATION_NODE:
5144 break;
5145 case XML_DTD_NODE:
5146 break;
5147 case XML_NAMESPACE_DECL:
5148 break;
5149 case XML_ELEMENT_DECL:
5150 /* TODO !!! */
5151 break;
5152 case XML_ATTRIBUTE_DECL:
5153 /* TODO !!! */
5154 break;
5155 case XML_ENTITY_DECL:
5156 /* TODO !!! */
5157 break;
5158 }
5159}
5160
Daniel Veillard652327a2003-09-29 18:02:38 +00005161#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005162/**
5163 * xmlNodeSetContentLen:
5164 * @cur: the node being modified
5165 * @content: the new value of the content
5166 * @len: the size of @content
5167 *
5168 * Replace the content of a node.
5169 */
5170void
5171xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5172 if (cur == NULL) {
5173#ifdef DEBUG_TREE
5174 xmlGenericError(xmlGenericErrorContext,
5175 "xmlNodeSetContentLen : node == NULL\n");
5176#endif
5177 return;
5178 }
5179 switch (cur->type) {
5180 case XML_DOCUMENT_FRAG_NODE:
5181 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005182 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005183 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5184 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5185 UPDATE_LAST_CHILD_AND_PARENT(cur)
5186 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005187 case XML_TEXT_NODE:
5188 case XML_CDATA_SECTION_NODE:
5189 case XML_ENTITY_REF_NODE:
5190 case XML_ENTITY_NODE:
5191 case XML_PI_NODE:
5192 case XML_COMMENT_NODE:
5193 case XML_NOTATION_NODE:
Daniel Veillard8874b942005-08-25 13:19:21 +00005194 if ((cur->content != NULL) &&
5195 (cur->content != (xmlChar *) &(cur->properties))) {
5196 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5197 (xmlDictOwns(cur->doc->dict, cur->content))))
5198 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005199 }
5200 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5201 cur->children = cur->last = NULL;
5202 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005203 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005204 } else
5205 cur->content = NULL;
Daniel Veillard8874b942005-08-25 13:19:21 +00005206 cur->properties = NULL;
5207 cur->nsDef = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00005208 break;
5209 case XML_DOCUMENT_NODE:
5210 case XML_DTD_NODE:
5211 case XML_HTML_DOCUMENT_NODE:
5212 case XML_DOCUMENT_TYPE_NODE:
5213 case XML_NAMESPACE_DECL:
5214 case XML_XINCLUDE_START:
5215 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005216#ifdef LIBXML_DOCB_ENABLED
5217 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005218#endif
5219 break;
5220 case XML_ELEMENT_DECL:
5221 /* TODO !!! */
5222 break;
5223 case XML_ATTRIBUTE_DECL:
5224 /* TODO !!! */
5225 break;
5226 case XML_ENTITY_DECL:
5227 /* TODO !!! */
5228 break;
5229 }
5230}
Daniel Veillard652327a2003-09-29 18:02:38 +00005231#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005232
5233/**
5234 * xmlNodeAddContentLen:
5235 * @cur: the node being modified
5236 * @content: extra content
5237 * @len: the size of @content
5238 *
5239 * Append the extra substring to the node content.
5240 */
5241void
5242xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5243 if (cur == NULL) {
5244#ifdef DEBUG_TREE
5245 xmlGenericError(xmlGenericErrorContext,
5246 "xmlNodeAddContentLen : node == NULL\n");
5247#endif
5248 return;
5249 }
5250 if (len <= 0) return;
5251 switch (cur->type) {
5252 case XML_DOCUMENT_FRAG_NODE:
5253 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005254 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005255
Daniel Veillard7db37732001-07-12 01:20:08 +00005256 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005257 newNode = xmlNewTextLen(content, len);
5258 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005259 tmp = xmlAddChild(cur, newNode);
5260 if (tmp != newNode)
5261 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005262 if ((last != NULL) && (last->next == newNode)) {
5263 xmlTextMerge(last, newNode);
5264 }
5265 }
5266 break;
5267 }
5268 case XML_ATTRIBUTE_NODE:
5269 break;
5270 case XML_TEXT_NODE:
5271 case XML_CDATA_SECTION_NODE:
5272 case XML_ENTITY_REF_NODE:
5273 case XML_ENTITY_NODE:
5274 case XML_PI_NODE:
5275 case XML_COMMENT_NODE:
5276 case XML_NOTATION_NODE:
5277 if (content != NULL) {
Daniel Veillard8874b942005-08-25 13:19:21 +00005278 if ((cur->content == (xmlChar *) &(cur->properties)) ||
5279 ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5280 xmlDictOwns(cur->doc->dict, cur->content))) {
5281 cur->content = xmlStrncatNew(cur->content, content, len);
5282 cur->properties = NULL;
5283 cur->nsDef = NULL;
William M. Brack7762bb12004-01-04 14:49:01 +00005284 break;
5285 }
Owen Taylor3473f882001-02-23 17:55:21 +00005286 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005287 }
5288 case XML_DOCUMENT_NODE:
5289 case XML_DTD_NODE:
5290 case XML_HTML_DOCUMENT_NODE:
5291 case XML_DOCUMENT_TYPE_NODE:
5292 case XML_NAMESPACE_DECL:
5293 case XML_XINCLUDE_START:
5294 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005295#ifdef LIBXML_DOCB_ENABLED
5296 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005297#endif
5298 break;
5299 case XML_ELEMENT_DECL:
5300 case XML_ATTRIBUTE_DECL:
5301 case XML_ENTITY_DECL:
5302 break;
5303 }
5304}
5305
5306/**
5307 * xmlNodeAddContent:
5308 * @cur: the node being modified
5309 * @content: extra content
5310 *
5311 * Append the extra substring to the node content.
5312 */
5313void
5314xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5315 int len;
5316
5317 if (cur == NULL) {
5318#ifdef DEBUG_TREE
5319 xmlGenericError(xmlGenericErrorContext,
5320 "xmlNodeAddContent : node == NULL\n");
5321#endif
5322 return;
5323 }
5324 if (content == NULL) return;
5325 len = xmlStrlen(content);
5326 xmlNodeAddContentLen(cur, content, len);
5327}
5328
5329/**
5330 * xmlTextMerge:
5331 * @first: the first text node
5332 * @second: the second text node being merged
5333 *
5334 * Merge two text nodes into one
5335 * Returns the first text node augmented
5336 */
5337xmlNodePtr
5338xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5339 if (first == NULL) return(second);
5340 if (second == NULL) return(first);
5341 if (first->type != XML_TEXT_NODE) return(first);
5342 if (second->type != XML_TEXT_NODE) return(first);
5343 if (second->name != first->name)
5344 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005345 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005346 xmlUnlinkNode(second);
5347 xmlFreeNode(second);
5348 return(first);
5349}
5350
Daniel Veillard2156d432004-03-04 15:59:36 +00005351#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005352/**
5353 * xmlGetNsList:
5354 * @doc: the document
5355 * @node: the current node
5356 *
5357 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005358 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005359 * that need to be freed by the caller or NULL if no
5360 * namespace if defined
5361 */
5362xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005363xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5364{
Owen Taylor3473f882001-02-23 17:55:21 +00005365 xmlNsPtr cur;
5366 xmlNsPtr *ret = NULL;
5367 int nbns = 0;
5368 int maxns = 10;
5369 int i;
5370
5371 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005372 if (node->type == XML_ELEMENT_NODE) {
5373 cur = node->nsDef;
5374 while (cur != NULL) {
5375 if (ret == NULL) {
5376 ret =
5377 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5378 sizeof(xmlNsPtr));
5379 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005380 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005381 return (NULL);
5382 }
5383 ret[nbns] = NULL;
5384 }
5385 for (i = 0; i < nbns; i++) {
5386 if ((cur->prefix == ret[i]->prefix) ||
5387 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5388 break;
5389 }
5390 if (i >= nbns) {
5391 if (nbns >= maxns) {
5392 maxns *= 2;
5393 ret = (xmlNsPtr *) xmlRealloc(ret,
5394 (maxns +
5395 1) *
5396 sizeof(xmlNsPtr));
5397 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005398 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005399 return (NULL);
5400 }
5401 }
5402 ret[nbns++] = cur;
5403 ret[nbns] = NULL;
5404 }
Owen Taylor3473f882001-02-23 17:55:21 +00005405
Daniel Veillard77044732001-06-29 21:31:07 +00005406 cur = cur->next;
5407 }
5408 }
5409 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005410 }
Daniel Veillard77044732001-06-29 21:31:07 +00005411 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005412}
Daniel Veillard652327a2003-09-29 18:02:38 +00005413#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005414
5415/**
5416 * xmlSearchNs:
5417 * @doc: the document
5418 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005419 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005420 *
5421 * Search a Ns registered under a given name space for a document.
5422 * recurse on the parents until it finds the defined namespace
5423 * or return NULL otherwise.
5424 * @nameSpace can be NULL, this is a search for the default namespace.
5425 * We don't allow to cross entities boundaries. If you don't declare
5426 * the namespace within those you will be in troubles !!! A warning
5427 * is generated to cover this case.
5428 *
5429 * Returns the namespace pointer or NULL.
5430 */
5431xmlNsPtr
5432xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005433
Owen Taylor3473f882001-02-23 17:55:21 +00005434 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005435 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005436
5437 if (node == NULL) return(NULL);
5438 if ((nameSpace != NULL) &&
5439 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005440 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5441 /*
5442 * The XML-1.0 namespace is normally held on the root
5443 * element. In this case exceptionally create it on the
5444 * node element.
5445 */
5446 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5447 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005448 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005449 return(NULL);
5450 }
5451 memset(cur, 0, sizeof(xmlNs));
5452 cur->type = XML_LOCAL_NAMESPACE;
5453 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5454 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5455 cur->next = node->nsDef;
5456 node->nsDef = cur;
5457 return(cur);
5458 }
Owen Taylor3473f882001-02-23 17:55:21 +00005459 if (doc->oldNs == NULL) {
5460 /*
5461 * Allocate a new Namespace and fill the fields.
5462 */
5463 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5464 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005465 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005466 return(NULL);
5467 }
5468 memset(doc->oldNs, 0, sizeof(xmlNs));
5469 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5470
5471 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5472 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5473 }
5474 return(doc->oldNs);
5475 }
5476 while (node != NULL) {
5477 if ((node->type == XML_ENTITY_REF_NODE) ||
5478 (node->type == XML_ENTITY_NODE) ||
5479 (node->type == XML_ENTITY_DECL))
5480 return(NULL);
5481 if (node->type == XML_ELEMENT_NODE) {
5482 cur = node->nsDef;
5483 while (cur != NULL) {
5484 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5485 (cur->href != NULL))
5486 return(cur);
5487 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5488 (cur->href != NULL) &&
5489 (xmlStrEqual(cur->prefix, nameSpace)))
5490 return(cur);
5491 cur = cur->next;
5492 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005493 if (orig != node) {
5494 cur = node->ns;
5495 if (cur != NULL) {
5496 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5497 (cur->href != NULL))
5498 return(cur);
5499 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5500 (cur->href != NULL) &&
5501 (xmlStrEqual(cur->prefix, nameSpace)))
5502 return(cur);
5503 }
5504 }
Owen Taylor3473f882001-02-23 17:55:21 +00005505 }
5506 node = node->parent;
5507 }
5508 return(NULL);
5509}
5510
5511/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005512 * xmlNsInScope:
5513 * @doc: the document
5514 * @node: the current node
5515 * @ancestor: the ancestor carrying the namespace
5516 * @prefix: the namespace prefix
5517 *
5518 * Verify that the given namespace held on @ancestor is still in scope
5519 * on node.
5520 *
5521 * Returns 1 if true, 0 if false and -1 in case of error.
5522 */
5523static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005524xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5525 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005526{
5527 xmlNsPtr tst;
5528
5529 while ((node != NULL) && (node != ancestor)) {
5530 if ((node->type == XML_ENTITY_REF_NODE) ||
5531 (node->type == XML_ENTITY_NODE) ||
5532 (node->type == XML_ENTITY_DECL))
5533 return (-1);
5534 if (node->type == XML_ELEMENT_NODE) {
5535 tst = node->nsDef;
5536 while (tst != NULL) {
5537 if ((tst->prefix == NULL)
5538 && (prefix == NULL))
5539 return (0);
5540 if ((tst->prefix != NULL)
5541 && (prefix != NULL)
5542 && (xmlStrEqual(tst->prefix, prefix)))
5543 return (0);
5544 tst = tst->next;
5545 }
5546 }
5547 node = node->parent;
5548 }
5549 if (node != ancestor)
5550 return (-1);
5551 return (1);
5552}
5553
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005554/**
Owen Taylor3473f882001-02-23 17:55:21 +00005555 * xmlSearchNsByHref:
5556 * @doc: the document
5557 * @node: the current node
5558 * @href: the namespace value
5559 *
5560 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5561 * the defined namespace or return NULL otherwise.
5562 * Returns the namespace pointer or NULL.
5563 */
5564xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005565xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5566{
Owen Taylor3473f882001-02-23 17:55:21 +00005567 xmlNsPtr cur;
5568 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005569 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005570
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005571 if ((node == NULL) || (href == NULL))
5572 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005573 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005574 /*
5575 * Only the document can hold the XML spec namespace.
5576 */
5577 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5578 /*
5579 * The XML-1.0 namespace is normally held on the root
5580 * element. In this case exceptionally create it on the
5581 * node element.
5582 */
5583 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5584 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005585 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005586 return (NULL);
5587 }
5588 memset(cur, 0, sizeof(xmlNs));
5589 cur->type = XML_LOCAL_NAMESPACE;
5590 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5591 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5592 cur->next = node->nsDef;
5593 node->nsDef = cur;
5594 return (cur);
5595 }
5596 if (doc->oldNs == NULL) {
5597 /*
5598 * Allocate a new Namespace and fill the fields.
5599 */
5600 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5601 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005602 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005603 return (NULL);
5604 }
5605 memset(doc->oldNs, 0, sizeof(xmlNs));
5606 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005607
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005608 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5609 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5610 }
5611 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005612 }
Daniel Veillard62040be2004-05-17 03:17:26 +00005613 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00005614 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005615 if ((node->type == XML_ENTITY_REF_NODE) ||
5616 (node->type == XML_ENTITY_NODE) ||
5617 (node->type == XML_ENTITY_DECL))
5618 return (NULL);
5619 if (node->type == XML_ELEMENT_NODE) {
5620 cur = node->nsDef;
5621 while (cur != NULL) {
5622 if ((cur->href != NULL) && (href != NULL) &&
5623 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005624 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00005625 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005626 return (cur);
5627 }
5628 cur = cur->next;
5629 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005630 if (orig != node) {
5631 cur = node->ns;
5632 if (cur != NULL) {
5633 if ((cur->href != NULL) && (href != NULL) &&
5634 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005635 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00005636 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00005637 return (cur);
5638 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005639 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005640 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005641 }
5642 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005643 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005644 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005645}
5646
5647/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005648 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005649 * @doc: the document
5650 * @tree: a node expected to hold the new namespace
5651 * @ns: the original namespace
5652 *
5653 * This function tries to locate a namespace definition in a tree
5654 * ancestors, or create a new namespace definition node similar to
5655 * @ns trying to reuse the same prefix. However if the given prefix is
5656 * null (default namespace) or reused within the subtree defined by
5657 * @tree or on one of its ancestors then a new prefix is generated.
5658 * Returns the (new) namespace definition or NULL in case of error
5659 */
5660xmlNsPtr
5661xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5662 xmlNsPtr def;
5663 xmlChar prefix[50];
5664 int counter = 1;
5665
5666 if (tree == NULL) {
5667#ifdef DEBUG_TREE
5668 xmlGenericError(xmlGenericErrorContext,
5669 "xmlNewReconciliedNs : tree == NULL\n");
5670#endif
5671 return(NULL);
5672 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00005673 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005674#ifdef DEBUG_TREE
5675 xmlGenericError(xmlGenericErrorContext,
5676 "xmlNewReconciliedNs : ns == NULL\n");
5677#endif
5678 return(NULL);
5679 }
5680 /*
5681 * Search an existing namespace definition inherited.
5682 */
5683 def = xmlSearchNsByHref(doc, tree, ns->href);
5684 if (def != NULL)
5685 return(def);
5686
5687 /*
5688 * Find a close prefix which is not already in use.
5689 * Let's strip namespace prefixes longer than 20 chars !
5690 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005691 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005692 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005693 else
William M. Brack13dfa872004-09-18 04:52:08 +00005694 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005695
Owen Taylor3473f882001-02-23 17:55:21 +00005696 def = xmlSearchNs(doc, tree, prefix);
5697 while (def != NULL) {
5698 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005699 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005700 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005701 else
William M. Brack13dfa872004-09-18 04:52:08 +00005702 snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
5703 (char *)ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005704 def = xmlSearchNs(doc, tree, prefix);
5705 }
5706
5707 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005708 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005709 */
5710 def = xmlNewNs(tree, ns->href, prefix);
5711 return(def);
5712}
5713
Daniel Veillard652327a2003-09-29 18:02:38 +00005714#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005715/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005716 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005717 * @doc: the document
5718 * @tree: a node defining the subtree to reconciliate
5719 *
5720 * This function checks that all the namespaces declared within the given
5721 * tree are properly declared. This is needed for example after Copy or Cut
5722 * and then paste operations. The subtree may still hold pointers to
5723 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005724 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005725 * the new environment. If not possible the new namespaces are redeclared
5726 * on @tree at the top of the given subtree.
5727 * Returns the number of namespace declarations created or -1 in case of error.
5728 */
5729int
5730xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5731 xmlNsPtr *oldNs = NULL;
5732 xmlNsPtr *newNs = NULL;
5733 int sizeCache = 0;
5734 int nbCache = 0;
5735
5736 xmlNsPtr n;
5737 xmlNodePtr node = tree;
5738 xmlAttrPtr attr;
5739 int ret = 0, i;
5740
Daniel Veillardce244ad2004-11-05 10:03:46 +00005741 if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1);
5742 if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1);
5743 if (node->doc != doc) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005744 while (node != NULL) {
5745 /*
5746 * Reconciliate the node namespace
5747 */
5748 if (node->ns != NULL) {
5749 /*
5750 * initialize the cache if needed
5751 */
5752 if (sizeCache == 0) {
5753 sizeCache = 10;
5754 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5755 sizeof(xmlNsPtr));
5756 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005757 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005758 return(-1);
5759 }
5760 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5761 sizeof(xmlNsPtr));
5762 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005763 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005764 xmlFree(oldNs);
5765 return(-1);
5766 }
5767 }
5768 for (i = 0;i < nbCache;i++) {
5769 if (oldNs[i] == node->ns) {
5770 node->ns = newNs[i];
5771 break;
5772 }
5773 }
5774 if (i == nbCache) {
5775 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005776 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005777 */
5778 n = xmlNewReconciliedNs(doc, tree, node->ns);
5779 if (n != NULL) { /* :-( what if else ??? */
5780 /*
5781 * check if we need to grow the cache buffers.
5782 */
5783 if (sizeCache <= nbCache) {
5784 sizeCache *= 2;
5785 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5786 sizeof(xmlNsPtr));
5787 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005788 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005789 xmlFree(newNs);
5790 return(-1);
5791 }
5792 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5793 sizeof(xmlNsPtr));
5794 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005795 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005796 xmlFree(oldNs);
5797 return(-1);
5798 }
5799 }
5800 newNs[nbCache] = n;
5801 oldNs[nbCache++] = node->ns;
5802 node->ns = n;
5803 }
5804 }
5805 }
5806 /*
5807 * now check for namespace hold by attributes on the node.
5808 */
5809 attr = node->properties;
5810 while (attr != NULL) {
5811 if (attr->ns != NULL) {
5812 /*
5813 * initialize the cache if needed
5814 */
5815 if (sizeCache == 0) {
5816 sizeCache = 10;
5817 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5818 sizeof(xmlNsPtr));
5819 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005820 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005821 return(-1);
5822 }
5823 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5824 sizeof(xmlNsPtr));
5825 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005826 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005827 xmlFree(oldNs);
5828 return(-1);
5829 }
5830 }
5831 for (i = 0;i < nbCache;i++) {
5832 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005833 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005834 break;
5835 }
5836 }
5837 if (i == nbCache) {
5838 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005839 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005840 */
5841 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5842 if (n != NULL) { /* :-( what if else ??? */
5843 /*
5844 * check if we need to grow the cache buffers.
5845 */
5846 if (sizeCache <= nbCache) {
5847 sizeCache *= 2;
5848 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5849 sizeof(xmlNsPtr));
5850 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005851 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005852 xmlFree(newNs);
5853 return(-1);
5854 }
5855 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5856 sizeof(xmlNsPtr));
5857 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005858 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005859 xmlFree(oldNs);
5860 return(-1);
5861 }
5862 }
5863 newNs[nbCache] = n;
5864 oldNs[nbCache++] = attr->ns;
5865 attr->ns = n;
5866 }
5867 }
5868 }
5869 attr = attr->next;
5870 }
5871
5872 /*
5873 * Browse the full subtree, deep first
5874 */
Daniel Veillardac996a12004-07-30 12:02:58 +00005875 if (node->children != NULL && node->type != XML_ENTITY_REF_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00005876 /* deep first */
5877 node = node->children;
5878 } else if ((node != tree) && (node->next != NULL)) {
5879 /* then siblings */
5880 node = node->next;
5881 } else if (node != tree) {
5882 /* go up to parents->next if needed */
5883 while (node != tree) {
5884 if (node->parent != NULL)
5885 node = node->parent;
5886 if ((node != tree) && (node->next != NULL)) {
5887 node = node->next;
5888 break;
5889 }
5890 if (node->parent == NULL) {
5891 node = NULL;
5892 break;
5893 }
5894 }
5895 /* exit condition */
5896 if (node == tree)
5897 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005898 } else
5899 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005900 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005901 if (oldNs != NULL)
5902 xmlFree(oldNs);
5903 if (newNs != NULL)
5904 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005905 return(ret);
5906}
Daniel Veillard652327a2003-09-29 18:02:38 +00005907#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005908
5909/**
5910 * xmlHasProp:
5911 * @node: the node
5912 * @name: the attribute name
5913 *
5914 * Search an attribute associated to a node
5915 * This function also looks in DTD attribute declaration for #FIXED or
5916 * default declaration values unless DTD use has been turned off.
5917 *
5918 * Returns the attribute or the attribute declaration or NULL if
5919 * neither was found.
5920 */
5921xmlAttrPtr
5922xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5923 xmlAttrPtr prop;
5924 xmlDocPtr doc;
5925
Daniel Veillard8874b942005-08-25 13:19:21 +00005926 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
5927 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005928 /*
5929 * Check on the properties attached to the node
5930 */
5931 prop = node->properties;
5932 while (prop != NULL) {
5933 if (xmlStrEqual(prop->name, name)) {
5934 return(prop);
5935 }
5936 prop = prop->next;
5937 }
5938 if (!xmlCheckDTD) return(NULL);
5939
5940 /*
5941 * Check if there is a default declaration in the internal
5942 * or external subsets
5943 */
5944 doc = node->doc;
5945 if (doc != NULL) {
5946 xmlAttributePtr attrDecl;
5947 if (doc->intSubset != NULL) {
5948 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5949 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5950 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005951 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5952 /* return attribute declaration only if a default value is given
5953 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005954 return((xmlAttrPtr) attrDecl);
5955 }
5956 }
5957 return(NULL);
5958}
5959
5960/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005961 * xmlHasNsProp:
5962 * @node: the node
5963 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005964 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005965 *
5966 * Search for an attribute associated to a node
5967 * This attribute has to be anchored in the namespace specified.
5968 * This does the entity substitution.
5969 * This function looks in DTD attribute declaration for #FIXED or
5970 * default declaration values unless DTD use has been turned off.
William M. Brack2c228442004-10-03 04:10:00 +00005971 * Note that a namespace of NULL indicates to use the default namespace.
Daniel Veillarde95e2392001-06-06 10:46:28 +00005972 *
5973 * Returns the attribute or the attribute declaration or NULL
5974 * if neither was found.
5975 */
5976xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005977xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005978 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00005979#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005980 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00005981#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005982
Daniel Veillard8874b942005-08-25 13:19:21 +00005983 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
Daniel Veillarde95e2392001-06-06 10:46:28 +00005984 return(NULL);
5985
5986 prop = node->properties;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005987 while (prop != NULL) {
5988 /*
5989 * One need to have
5990 * - same attribute names
5991 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005992 */
William M. Brack2c228442004-10-03 04:10:00 +00005993 if (xmlStrEqual(prop->name, name)) {
5994 if (((prop->ns != NULL) &&
5995 (xmlStrEqual(prop->ns->href, nameSpace))) ||
5996 ((prop->ns == NULL) && (nameSpace == NULL))) {
5997 return(prop);
5998 }
Daniel Veillarde95e2392001-06-06 10:46:28 +00005999 }
6000 prop = prop->next;
6001 }
6002 if (!xmlCheckDTD) return(NULL);
6003
Daniel Veillard652327a2003-09-29 18:02:38 +00006004#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00006005 /*
6006 * Check if there is a default declaration in the internal
6007 * or external subsets
6008 */
6009 doc = node->doc;
6010 if (doc != NULL) {
6011 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006012 xmlAttributePtr attrDecl = NULL;
6013 xmlNsPtr *nsList, *cur;
6014 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00006015
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006016 nsList = xmlGetNsList(node->doc, node);
6017 if (nsList == NULL)
6018 return(NULL);
6019 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
6020 ename = xmlStrdup(node->ns->prefix);
6021 ename = xmlStrcat(ename, BAD_CAST ":");
6022 ename = xmlStrcat(ename, node->name);
6023 } else {
6024 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006025 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006026 if (ename == NULL) {
6027 xmlFree(nsList);
6028 return(NULL);
6029 }
6030
William M. Brack2c228442004-10-03 04:10:00 +00006031 if (nameSpace == NULL) {
6032 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
6033 name, NULL);
6034 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
6035 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6036 name, NULL);
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006037 }
William M. Brack2c228442004-10-03 04:10:00 +00006038 } else {
6039 cur = nsList;
6040 while (*cur != NULL) {
6041 if (xmlStrEqual((*cur)->href, nameSpace)) {
6042 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
6043 name, (*cur)->prefix);
6044 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6045 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6046 name, (*cur)->prefix);
6047 }
6048 cur++;
6049 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006050 }
6051 xmlFree(nsList);
6052 xmlFree(ename);
6053 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006054 }
6055 }
Daniel Veillard652327a2003-09-29 18:02:38 +00006056#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00006057 return(NULL);
6058}
6059
6060/**
Owen Taylor3473f882001-02-23 17:55:21 +00006061 * xmlGetProp:
6062 * @node: the node
6063 * @name: the attribute name
6064 *
6065 * Search and get the value of an attribute associated to a node
6066 * This does the entity substitution.
6067 * This function looks in DTD attribute declaration for #FIXED or
6068 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00006069 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00006070 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6071 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00006072 *
6073 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006074 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006075 */
6076xmlChar *
6077xmlGetProp(xmlNodePtr node, const xmlChar *name) {
6078 xmlAttrPtr prop;
6079 xmlDocPtr doc;
6080
Daniel Veillard8874b942005-08-25 13:19:21 +00006081 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6082 return(NULL);
6083
Owen Taylor3473f882001-02-23 17:55:21 +00006084 /*
6085 * Check on the properties attached to the node
6086 */
6087 prop = node->properties;
6088 while (prop != NULL) {
6089 if (xmlStrEqual(prop->name, name)) {
6090 xmlChar *ret;
6091
6092 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6093 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6094 return(ret);
6095 }
6096 prop = prop->next;
6097 }
6098 if (!xmlCheckDTD) return(NULL);
6099
6100 /*
6101 * Check if there is a default declaration in the internal
6102 * or external subsets
6103 */
6104 doc = node->doc;
6105 if (doc != NULL) {
6106 xmlAttributePtr attrDecl;
6107 if (doc->intSubset != NULL) {
6108 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6109 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6110 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006111 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6112 /* return attribute declaration only if a default value is given
6113 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006114 return(xmlStrdup(attrDecl->defaultValue));
6115 }
6116 }
6117 return(NULL);
6118}
6119
6120/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006121 * xmlGetNoNsProp:
6122 * @node: the node
6123 * @name: the attribute name
6124 *
6125 * Search and get the value of an attribute associated to a node
6126 * This does the entity substitution.
6127 * This function looks in DTD attribute declaration for #FIXED or
6128 * default declaration values unless DTD use has been turned off.
6129 * This function is similar to xmlGetProp except it will accept only
6130 * an attribute in no namespace.
6131 *
6132 * Returns the attribute value or NULL if not found.
6133 * It's up to the caller to free the memory with xmlFree().
6134 */
6135xmlChar *
6136xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6137 xmlAttrPtr prop;
6138 xmlDocPtr doc;
6139
Daniel Veillard8874b942005-08-25 13:19:21 +00006140 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6141 return(NULL);
Daniel Veillard71531f32003-02-05 13:19:53 +00006142 /*
6143 * Check on the properties attached to the node
6144 */
6145 prop = node->properties;
6146 while (prop != NULL) {
6147 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6148 xmlChar *ret;
6149
6150 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6151 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6152 return(ret);
6153 }
6154 prop = prop->next;
6155 }
6156 if (!xmlCheckDTD) return(NULL);
6157
6158 /*
6159 * Check if there is a default declaration in the internal
6160 * or external subsets
6161 */
6162 doc = node->doc;
6163 if (doc != NULL) {
6164 xmlAttributePtr attrDecl;
6165 if (doc->intSubset != NULL) {
6166 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6167 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6168 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006169 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6170 /* return attribute declaration only if a default value is given
6171 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006172 return(xmlStrdup(attrDecl->defaultValue));
6173 }
6174 }
6175 return(NULL);
6176}
6177
6178/**
Owen Taylor3473f882001-02-23 17:55:21 +00006179 * xmlGetNsProp:
6180 * @node: the node
6181 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006182 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006183 *
6184 * Search and get the value of an attribute associated to a node
6185 * This attribute has to be anchored in the namespace specified.
6186 * This does the entity substitution.
6187 * This function looks in DTD attribute declaration for #FIXED or
6188 * default declaration values unless DTD use has been turned off.
6189 *
6190 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006191 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006192 */
6193xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006194xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006195 xmlAttrPtr prop;
6196 xmlDocPtr doc;
6197 xmlNsPtr ns;
6198
Daniel Veillard8874b942005-08-25 13:19:21 +00006199 if ((node == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006200 return(NULL);
6201
6202 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006203 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006204 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006205 while (prop != NULL) {
6206 /*
6207 * One need to have
6208 * - same attribute names
6209 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006210 */
6211 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006212 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006213 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006214 xmlChar *ret;
6215
6216 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6217 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6218 return(ret);
6219 }
6220 prop = prop->next;
6221 }
6222 if (!xmlCheckDTD) return(NULL);
6223
6224 /*
6225 * Check if there is a default declaration in the internal
6226 * or external subsets
6227 */
6228 doc = node->doc;
6229 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006230 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006231 xmlAttributePtr attrDecl;
6232
Owen Taylor3473f882001-02-23 17:55:21 +00006233 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6234 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6235 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6236
6237 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6238 /*
6239 * The DTD declaration only allows a prefix search
6240 */
6241 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006242 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006243 return(xmlStrdup(attrDecl->defaultValue));
6244 }
6245 }
6246 }
6247 return(NULL);
6248}
6249
Daniel Veillard2156d432004-03-04 15:59:36 +00006250#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6251/**
6252 * xmlUnsetProp:
6253 * @node: the node
6254 * @name: the attribute name
6255 *
6256 * Remove an attribute carried by a node.
6257 * Returns 0 if successful, -1 if not found
6258 */
6259int
6260xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Kasimier T. Buchcik65c2f1d2005-10-17 12:39:58 +00006261 xmlAttrPtr prop;
Daniel Veillard2156d432004-03-04 15:59:36 +00006262
Daniel Veillard8874b942005-08-25 13:19:21 +00006263 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
Daniel Veillard2156d432004-03-04 15:59:36 +00006264 return(-1);
6265 prop = node->properties;
6266 while (prop != NULL) {
6267 if ((xmlStrEqual(prop->name, name)) &&
6268 (prop->ns == NULL)) {
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00006269 xmlUnlinkNode((xmlNodePtr) prop);
Daniel Veillard2156d432004-03-04 15:59:36 +00006270 xmlFreeProp(prop);
6271 return(0);
6272 }
Daniel Veillard2156d432004-03-04 15:59:36 +00006273 prop = prop->next;
6274 }
6275 return(-1);
6276}
6277
6278/**
6279 * xmlUnsetNsProp:
6280 * @node: the node
6281 * @ns: the namespace definition
6282 * @name: the attribute name
6283 *
6284 * Remove an attribute carried by a node.
6285 * Returns 0 if successful, -1 if not found
6286 */
6287int
6288xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
Kasimier T. Buchcik65c2f1d2005-10-17 12:39:58 +00006289 xmlAttrPtr prop;
Daniel Veillard2156d432004-03-04 15:59:36 +00006290
Daniel Veillard8874b942005-08-25 13:19:21 +00006291 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
Daniel Veillard2156d432004-03-04 15:59:36 +00006292 return(-1);
Daniel Veillard27f20102004-11-05 11:50:11 +00006293 prop = node->properties;
Daniel Veillard2156d432004-03-04 15:59:36 +00006294 if (ns == NULL)
6295 return(xmlUnsetProp(node, name));
6296 if (ns->href == NULL)
6297 return(-1);
6298 while (prop != NULL) {
6299 if ((xmlStrEqual(prop->name, name)) &&
6300 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00006301 xmlUnlinkNode((xmlNodePtr) prop);
Daniel Veillard2156d432004-03-04 15:59:36 +00006302 xmlFreeProp(prop);
6303 return(0);
6304 }
Daniel Veillard2156d432004-03-04 15:59:36 +00006305 prop = prop->next;
6306 }
6307 return(-1);
6308}
6309#endif
6310
6311#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006312/**
6313 * xmlSetProp:
6314 * @node: the node
6315 * @name: the attribute name
6316 * @value: the attribute value
6317 *
6318 * Set (or reset) an attribute carried by a node.
6319 * Returns the attribute pointer.
6320 */
6321xmlAttrPtr
6322xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006323 xmlAttrPtr prop;
6324 xmlDocPtr doc;
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006325 int len;
6326 const xmlChar *nqname;
Owen Taylor3473f882001-02-23 17:55:21 +00006327
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006328 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006329 return(NULL);
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006330
6331 /*
6332 * handle QNames
6333 */
6334 nqname = xmlSplitQName3(name, &len);
6335 if (nqname != NULL) {
6336 xmlNsPtr ns;
6337 xmlChar *prefix = xmlStrndup(name, len);
6338 ns = xmlSearchNs(node->doc, node, prefix);
6339 if (prefix != NULL)
6340 xmlFree(prefix);
6341 if (ns != NULL)
6342 return(xmlSetNsProp(node, ns, nqname, value));
6343 }
6344
Owen Taylor3473f882001-02-23 17:55:21 +00006345 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006346 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006347 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006348 if ((xmlStrEqual(prop->name, name)) &&
6349 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006350 xmlNodePtr oldprop = prop->children;
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006351 int id = xmlIsID(node->doc, node, prop);
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006352
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006353 if (id == 1)
6354 xmlRemoveID(node->doc, prop);
Owen Taylor3473f882001-02-23 17:55:21 +00006355 prop->children = NULL;
6356 prop->last = NULL;
6357 if (value != NULL) {
6358 xmlChar *buffer;
6359 xmlNodePtr tmp;
6360
6361 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6362 prop->children = xmlStringGetNodeList(node->doc, buffer);
6363 prop->last = NULL;
6364 prop->doc = doc;
6365 tmp = prop->children;
6366 while (tmp != NULL) {
6367 tmp->parent = (xmlNodePtr) prop;
6368 tmp->doc = doc;
6369 if (tmp->next == NULL)
6370 prop->last = tmp;
6371 tmp = tmp->next;
6372 }
6373 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006374 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006375 if (oldprop != NULL)
6376 xmlFreeNodeList(oldprop);
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006377 if (id)
6378 xmlAddID(NULL, node->doc, value, prop);
Owen Taylor3473f882001-02-23 17:55:21 +00006379 return(prop);
6380 }
6381 prop = prop->next;
6382 }
6383 prop = xmlNewProp(node, name, value);
6384 return(prop);
6385}
6386
6387/**
6388 * xmlSetNsProp:
6389 * @node: the node
6390 * @ns: the namespace definition
6391 * @name: the attribute name
6392 * @value: the attribute value
6393 *
6394 * Set (or reset) an attribute carried by a node.
6395 * The ns structure must be in scope, this is not checked.
6396 *
6397 * Returns the attribute pointer.
6398 */
6399xmlAttrPtr
6400xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6401 const xmlChar *value) {
6402 xmlAttrPtr prop;
6403
Daniel Veillardb6b36d32005-02-09 16:48:53 +00006404 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006405 return(NULL);
6406
6407 if (ns == NULL)
6408 return(xmlSetProp(node, name, value));
6409 if (ns->href == NULL)
6410 return(NULL);
6411 prop = node->properties;
6412
6413 while (prop != NULL) {
6414 /*
6415 * One need to have
6416 * - same attribute names
6417 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006418 */
6419 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006420 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006421 int id = xmlIsID(node->doc, node, prop);
6422
6423 if (id == 1)
6424 xmlRemoveID(node->doc, prop);
Owen Taylor3473f882001-02-23 17:55:21 +00006425 if (prop->children != NULL)
6426 xmlFreeNodeList(prop->children);
6427 prop->children = NULL;
6428 prop->last = NULL;
6429 prop->ns = ns;
6430 if (value != NULL) {
6431 xmlChar *buffer;
6432 xmlNodePtr tmp;
6433
6434 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6435 prop->children = xmlStringGetNodeList(node->doc, buffer);
6436 prop->last = NULL;
6437 tmp = prop->children;
6438 while (tmp != NULL) {
6439 tmp->parent = (xmlNodePtr) prop;
6440 if (tmp->next == NULL)
6441 prop->last = tmp;
6442 tmp = tmp->next;
6443 }
6444 xmlFree(buffer);
6445 }
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006446 if (id)
6447 xmlAddID(NULL, node->doc, value, prop);
Owen Taylor3473f882001-02-23 17:55:21 +00006448 return(prop);
6449 }
6450 prop = prop->next;
6451 }
6452 prop = xmlNewNsProp(node, ns, name, value);
6453 return(prop);
6454}
6455
Daniel Veillard652327a2003-09-29 18:02:38 +00006456#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006457
6458/**
Owen Taylor3473f882001-02-23 17:55:21 +00006459 * xmlNodeIsText:
6460 * @node: the node
6461 *
6462 * Is this node a Text node ?
6463 * Returns 1 yes, 0 no
6464 */
6465int
6466xmlNodeIsText(xmlNodePtr node) {
6467 if (node == NULL) return(0);
6468
6469 if (node->type == XML_TEXT_NODE) return(1);
6470 return(0);
6471}
6472
6473/**
6474 * xmlIsBlankNode:
6475 * @node: the node
6476 *
6477 * Checks whether this node is an empty or whitespace only
6478 * (and possibly ignorable) text-node.
6479 *
6480 * Returns 1 yes, 0 no
6481 */
6482int
6483xmlIsBlankNode(xmlNodePtr node) {
6484 const xmlChar *cur;
6485 if (node == NULL) return(0);
6486
Daniel Veillard7db37732001-07-12 01:20:08 +00006487 if ((node->type != XML_TEXT_NODE) &&
6488 (node->type != XML_CDATA_SECTION_NODE))
6489 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006490 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006491 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006492 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006493 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006494 cur++;
6495 }
6496
6497 return(1);
6498}
6499
6500/**
6501 * xmlTextConcat:
6502 * @node: the node
6503 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006504 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006505 *
6506 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006507 *
6508 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006509 */
6510
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006511int
Owen Taylor3473f882001-02-23 17:55:21 +00006512xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006513 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006514
6515 if ((node->type != XML_TEXT_NODE) &&
6516 (node->type != XML_CDATA_SECTION_NODE)) {
6517#ifdef DEBUG_TREE
6518 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006519 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006520#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006521 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006522 }
William M. Brack7762bb12004-01-04 14:49:01 +00006523 /* need to check if content is currently in the dictionary */
Daniel Veillard8874b942005-08-25 13:19:21 +00006524 if ((node->content == (xmlChar *) &(node->properties)) ||
6525 ((node->doc != NULL) && (node->doc->dict != NULL) &&
6526 xmlDictOwns(node->doc->dict, node->content))) {
William M. Brack7762bb12004-01-04 14:49:01 +00006527 node->content = xmlStrncatNew(node->content, content, len);
6528 } else {
6529 node->content = xmlStrncat(node->content, content, len);
6530 }
Daniel Veillard8874b942005-08-25 13:19:21 +00006531 node->properties = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006532 if (node->content == NULL)
6533 return(-1);
6534 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006535}
6536
6537/************************************************************************
6538 * *
6539 * Output : to a FILE or in memory *
6540 * *
6541 ************************************************************************/
6542
Owen Taylor3473f882001-02-23 17:55:21 +00006543/**
6544 * xmlBufferCreate:
6545 *
6546 * routine to create an XML buffer.
6547 * returns the new structure.
6548 */
6549xmlBufferPtr
6550xmlBufferCreate(void) {
6551 xmlBufferPtr ret;
6552
6553 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6554 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006555 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006556 return(NULL);
6557 }
6558 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006559 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006560 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006561 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006562 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006563 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006564 xmlFree(ret);
6565 return(NULL);
6566 }
6567 ret->content[0] = 0;
6568 return(ret);
6569}
6570
6571/**
6572 * xmlBufferCreateSize:
6573 * @size: initial size of buffer
6574 *
6575 * routine to create an XML buffer.
6576 * returns the new structure.
6577 */
6578xmlBufferPtr
6579xmlBufferCreateSize(size_t size) {
6580 xmlBufferPtr ret;
6581
6582 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6583 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006584 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006585 return(NULL);
6586 }
6587 ret->use = 0;
6588 ret->alloc = xmlBufferAllocScheme;
6589 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6590 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006591 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006592 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006593 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006594 xmlFree(ret);
6595 return(NULL);
6596 }
6597 ret->content[0] = 0;
6598 } else
6599 ret->content = NULL;
6600 return(ret);
6601}
6602
6603/**
Daniel Veillard53350552003-09-18 13:35:51 +00006604 * xmlBufferCreateStatic:
6605 * @mem: the memory area
6606 * @size: the size in byte
6607 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006608 * routine to create an XML buffer from an immutable memory area.
6609 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006610 * present until the end of the buffer lifetime.
6611 *
6612 * returns the new structure.
6613 */
6614xmlBufferPtr
6615xmlBufferCreateStatic(void *mem, size_t size) {
6616 xmlBufferPtr ret;
6617
6618 if ((mem == NULL) || (size == 0))
6619 return(NULL);
6620
6621 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6622 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006623 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006624 return(NULL);
6625 }
6626 ret->use = size;
6627 ret->size = size;
6628 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6629 ret->content = (xmlChar *) mem;
6630 return(ret);
6631}
6632
6633/**
Owen Taylor3473f882001-02-23 17:55:21 +00006634 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006635 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006636 * @scheme: allocation scheme to use
6637 *
6638 * Sets the allocation scheme for this buffer
6639 */
6640void
6641xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6642 xmlBufferAllocationScheme scheme) {
6643 if (buf == NULL) {
6644#ifdef DEBUG_BUFFER
6645 xmlGenericError(xmlGenericErrorContext,
6646 "xmlBufferSetAllocationScheme: buf == NULL\n");
6647#endif
6648 return;
6649 }
Daniel Veillard53350552003-09-18 13:35:51 +00006650 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006651
6652 buf->alloc = scheme;
6653}
6654
6655/**
6656 * xmlBufferFree:
6657 * @buf: the buffer to free
6658 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006659 * Frees an XML buffer. It frees both the content and the structure which
6660 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006661 */
6662void
6663xmlBufferFree(xmlBufferPtr buf) {
6664 if (buf == NULL) {
6665#ifdef DEBUG_BUFFER
6666 xmlGenericError(xmlGenericErrorContext,
6667 "xmlBufferFree: buf == NULL\n");
6668#endif
6669 return;
6670 }
Daniel Veillard53350552003-09-18 13:35:51 +00006671
6672 if ((buf->content != NULL) &&
6673 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006674 xmlFree(buf->content);
6675 }
Owen Taylor3473f882001-02-23 17:55:21 +00006676 xmlFree(buf);
6677}
6678
6679/**
6680 * xmlBufferEmpty:
6681 * @buf: the buffer
6682 *
6683 * empty a buffer.
6684 */
6685void
6686xmlBufferEmpty(xmlBufferPtr buf) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006687 if (buf == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006688 if (buf->content == NULL) return;
6689 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006690 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006691 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006692 } else {
6693 memset(buf->content, 0, buf->size);
6694 }
Owen Taylor3473f882001-02-23 17:55:21 +00006695}
6696
6697/**
6698 * xmlBufferShrink:
6699 * @buf: the buffer to dump
6700 * @len: the number of xmlChar to remove
6701 *
6702 * Remove the beginning of an XML buffer.
6703 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006704 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006705 */
6706int
6707xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
Daniel Veillard3d97e662004-11-04 10:49:00 +00006708 if (buf == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006709 if (len == 0) return(0);
6710 if (len > buf->use) return(-1);
6711
6712 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006713 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6714 buf->content += len;
6715 } else {
6716 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6717 buf->content[buf->use] = 0;
6718 }
Owen Taylor3473f882001-02-23 17:55:21 +00006719 return(len);
6720}
6721
6722/**
6723 * xmlBufferGrow:
6724 * @buf: the buffer
6725 * @len: the minimum free size to allocate
6726 *
6727 * Grow the available space of an XML buffer.
6728 *
6729 * Returns the new available space or -1 in case of error
6730 */
6731int
6732xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6733 int size;
6734 xmlChar *newbuf;
6735
Daniel Veillard3d97e662004-11-04 10:49:00 +00006736 if (buf == NULL) return(-1);
6737
Daniel Veillard53350552003-09-18 13:35:51 +00006738 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006739 if (len + buf->use < buf->size) return(0);
6740
William M. Brack30fe43f2004-07-26 18:00:58 +00006741/*
6742 * Windows has a BIG problem on realloc timing, so we try to double
6743 * the buffer size (if that's enough) (bug 146697)
6744 */
6745#ifdef WIN32
6746 if (buf->size > len)
6747 size = buf->size * 2;
6748 else
6749 size = buf->use + len + 100;
6750#else
Owen Taylor3473f882001-02-23 17:55:21 +00006751 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00006752#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006753
6754 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006755 if (newbuf == NULL) {
6756 xmlTreeErrMemory("growing buffer");
6757 return(-1);
6758 }
Owen Taylor3473f882001-02-23 17:55:21 +00006759 buf->content = newbuf;
6760 buf->size = size;
6761 return(buf->size - buf->use);
6762}
6763
6764/**
6765 * xmlBufferDump:
6766 * @file: the file output
6767 * @buf: the buffer to dump
6768 *
6769 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006770 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006771 */
6772int
6773xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6774 int ret;
6775
6776 if (buf == NULL) {
6777#ifdef DEBUG_BUFFER
6778 xmlGenericError(xmlGenericErrorContext,
6779 "xmlBufferDump: buf == NULL\n");
6780#endif
6781 return(0);
6782 }
6783 if (buf->content == NULL) {
6784#ifdef DEBUG_BUFFER
6785 xmlGenericError(xmlGenericErrorContext,
6786 "xmlBufferDump: buf->content == NULL\n");
6787#endif
6788 return(0);
6789 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006790 if (file == NULL)
6791 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006792 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6793 return(ret);
6794}
6795
6796/**
6797 * xmlBufferContent:
6798 * @buf: the buffer
6799 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006800 * Function to extract the content of a buffer
6801 *
Owen Taylor3473f882001-02-23 17:55:21 +00006802 * Returns the internal content
6803 */
6804
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006805const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006806xmlBufferContent(const xmlBufferPtr buf)
6807{
6808 if(!buf)
6809 return NULL;
6810
6811 return buf->content;
6812}
6813
6814/**
6815 * xmlBufferLength:
6816 * @buf: the buffer
6817 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006818 * Function to get the length of a buffer
6819 *
Owen Taylor3473f882001-02-23 17:55:21 +00006820 * Returns the length of data in the internal content
6821 */
6822
6823int
6824xmlBufferLength(const xmlBufferPtr buf)
6825{
6826 if(!buf)
6827 return 0;
6828
6829 return buf->use;
6830}
6831
6832/**
6833 * xmlBufferResize:
6834 * @buf: the buffer to resize
6835 * @size: the desired size
6836 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006837 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006838 *
6839 * Returns 0 in case of problems, 1 otherwise
6840 */
6841int
6842xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6843{
6844 unsigned int newSize;
6845 xmlChar* rebuf = NULL;
6846
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006847 if (buf == NULL)
6848 return(0);
6849
Daniel Veillard53350552003-09-18 13:35:51 +00006850 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6851
Owen Taylor3473f882001-02-23 17:55:21 +00006852 /* Don't resize if we don't have to */
6853 if (size < buf->size)
6854 return 1;
6855
6856 /* figure out new size */
6857 switch (buf->alloc){
6858 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillardbf629492004-04-20 22:20:59 +00006859 /*take care of empty case*/
6860 newSize = (buf->size ? buf->size*2 : size + 10);
Owen Taylor3473f882001-02-23 17:55:21 +00006861 while (size > newSize) newSize *= 2;
6862 break;
6863 case XML_BUFFER_ALLOC_EXACT:
6864 newSize = size+10;
6865 break;
6866 default:
6867 newSize = size+10;
6868 break;
6869 }
6870
6871 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006872 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006873 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006874 rebuf = (xmlChar *) xmlRealloc(buf->content,
6875 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006876 } else {
6877 /*
6878 * if we are reallocating a buffer far from being full, it's
6879 * better to make a new allocation and copy only the used range
6880 * and free the old one.
6881 */
6882 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6883 if (rebuf != NULL) {
6884 memcpy(rebuf, buf->content, buf->use);
6885 xmlFree(buf->content);
William M. Brack42331a92004-07-29 07:07:16 +00006886 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006887 }
6888 }
Owen Taylor3473f882001-02-23 17:55:21 +00006889 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006890 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006891 return 0;
6892 }
6893 buf->content = rebuf;
6894 buf->size = newSize;
6895
6896 return 1;
6897}
6898
6899/**
6900 * xmlBufferAdd:
6901 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006902 * @str: the #xmlChar string
6903 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006904 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006905 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006906 * str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006907 *
6908 * Returns 0 successful, a positive error code number otherwise
6909 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006910 */
William M. Bracka3215c72004-07-31 16:24:01 +00006911int
Owen Taylor3473f882001-02-23 17:55:21 +00006912xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6913 unsigned int needSize;
6914
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006915 if ((str == NULL) || (buf == NULL)) {
William M. Bracka3215c72004-07-31 16:24:01 +00006916 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006917 }
William M. Bracka3215c72004-07-31 16:24:01 +00006918 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006919 if (len < -1) {
6920#ifdef DEBUG_BUFFER
6921 xmlGenericError(xmlGenericErrorContext,
6922 "xmlBufferAdd: len < 0\n");
6923#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006924 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006925 }
William M. Bracka3215c72004-07-31 16:24:01 +00006926 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006927
6928 if (len < 0)
6929 len = xmlStrlen(str);
6930
William M. Bracka3215c72004-07-31 16:24:01 +00006931 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006932
6933 needSize = buf->use + len + 2;
6934 if (needSize > buf->size){
6935 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006936 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006937 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006938 }
6939 }
6940
6941 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6942 buf->use += len;
6943 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006944 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006945}
6946
6947/**
6948 * xmlBufferAddHead:
6949 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006950 * @str: the #xmlChar string
6951 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006952 *
6953 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006954 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006955 *
6956 * Returns 0 successful, a positive error code number otherwise
6957 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006958 */
William M. Bracka3215c72004-07-31 16:24:01 +00006959int
Owen Taylor3473f882001-02-23 17:55:21 +00006960xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6961 unsigned int needSize;
6962
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006963 if (buf == NULL)
6964 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00006965 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006966 if (str == NULL) {
6967#ifdef DEBUG_BUFFER
6968 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006969 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006970#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006971 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006972 }
6973 if (len < -1) {
6974#ifdef DEBUG_BUFFER
6975 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006976 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006977#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006978 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006979 }
William M. Bracka3215c72004-07-31 16:24:01 +00006980 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006981
6982 if (len < 0)
6983 len = xmlStrlen(str);
6984
William M. Bracka3215c72004-07-31 16:24:01 +00006985 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006986
6987 needSize = buf->use + len + 2;
6988 if (needSize > buf->size){
6989 if (!xmlBufferResize(buf, needSize)){
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
6995 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6996 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6997 buf->use += len;
6998 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006999 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007000}
7001
7002/**
7003 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00007004 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00007005 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00007006 *
7007 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007008 *
7009 * Returns 0 successful, a positive error code number otherwise
7010 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007011 */
William M. Bracka3215c72004-07-31 16:24:01 +00007012int
Owen Taylor3473f882001-02-23 17:55:21 +00007013xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007014 if (buf == NULL)
7015 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007016 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
7017 if (str == NULL) return -1;
7018 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00007019}
7020
7021/**
7022 * xmlBufferCCat:
7023 * @buf: the buffer to dump
7024 * @str: the C char string
7025 *
7026 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007027 *
7028 * Returns 0 successful, a positive error code number otherwise
7029 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007030 */
William M. Bracka3215c72004-07-31 16:24:01 +00007031int
Owen Taylor3473f882001-02-23 17:55:21 +00007032xmlBufferCCat(xmlBufferPtr buf, const char *str) {
7033 const char *cur;
7034
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007035 if (buf == NULL)
7036 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007037 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007038 if (str == NULL) {
7039#ifdef DEBUG_BUFFER
7040 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007041 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007042#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007043 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007044 }
7045 for (cur = str;*cur != 0;cur++) {
7046 if (buf->use + 10 >= buf->size) {
7047 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007048 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007049 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007050 }
7051 }
7052 buf->content[buf->use++] = *cur;
7053 }
7054 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007055 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007056}
7057
7058/**
7059 * xmlBufferWriteCHAR:
7060 * @buf: the XML buffer
7061 * @string: the string to add
7062 *
7063 * routine which manages and grows an output buffer. This one adds
7064 * xmlChars at the end of the buffer.
7065 */
7066void
Daniel Veillard53350552003-09-18 13:35:51 +00007067xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007068 if (buf == NULL)
7069 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007070 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007071 xmlBufferCat(buf, string);
7072}
7073
7074/**
7075 * xmlBufferWriteChar:
7076 * @buf: the XML buffer output
7077 * @string: the string to add
7078 *
7079 * routine which manage and grows an output buffer. This one add
7080 * C chars at the end of the array.
7081 */
7082void
7083xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007084 if (buf == NULL)
7085 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007086 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007087 xmlBufferCCat(buf, string);
7088}
7089
7090
7091/**
7092 * xmlBufferWriteQuotedString:
7093 * @buf: the XML buffer output
7094 * @string: the string to add
7095 *
7096 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00007097 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00007098 * quote or double-quotes internally
7099 */
7100void
7101xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00007102 const xmlChar *cur, *base;
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007103 if (buf == NULL)
7104 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007105 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00007106 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00007107 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00007108#ifdef DEBUG_BUFFER
7109 xmlGenericError(xmlGenericErrorContext,
7110 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7111#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00007112 xmlBufferCCat(buf, "\"");
7113 base = cur = string;
7114 while(*cur != 0){
7115 if(*cur == '"'){
7116 if (base != cur)
7117 xmlBufferAdd(buf, base, cur - base);
7118 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7119 cur++;
7120 base = cur;
7121 }
7122 else {
7123 cur++;
7124 }
7125 }
7126 if (base != cur)
7127 xmlBufferAdd(buf, base, cur - base);
7128 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007129 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007130 else{
7131 xmlBufferCCat(buf, "\'");
7132 xmlBufferCat(buf, string);
7133 xmlBufferCCat(buf, "\'");
7134 }
Owen Taylor3473f882001-02-23 17:55:21 +00007135 } else {
7136 xmlBufferCCat(buf, "\"");
7137 xmlBufferCat(buf, string);
7138 xmlBufferCCat(buf, "\"");
7139 }
7140}
7141
7142
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007143/**
7144 * xmlGetDocCompressMode:
7145 * @doc: the document
7146 *
7147 * get the compression ratio for a document, ZLIB based
7148 * Returns 0 (uncompressed) to 9 (max compression)
7149 */
7150int
7151xmlGetDocCompressMode (xmlDocPtr doc) {
7152 if (doc == NULL) return(-1);
7153 return(doc->compression);
7154}
7155
7156/**
7157 * xmlSetDocCompressMode:
7158 * @doc: the document
7159 * @mode: the compression ratio
7160 *
7161 * set the compression ratio for a document, ZLIB based
7162 * Correct values: 0 (uncompressed) to 9 (max compression)
7163 */
7164void
7165xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7166 if (doc == NULL) return;
7167 if (mode < 0) doc->compression = 0;
7168 else if (mode > 9) doc->compression = 9;
7169 else doc->compression = mode;
7170}
7171
7172/**
7173 * xmlGetCompressMode:
7174 *
7175 * get the default compression mode used, ZLIB based.
7176 * Returns 0 (uncompressed) to 9 (max compression)
7177 */
7178int
7179xmlGetCompressMode(void)
7180{
7181 return (xmlCompressMode);
7182}
7183
7184/**
7185 * xmlSetCompressMode:
7186 * @mode: the compression ratio
7187 *
7188 * set the default compression mode used, ZLIB based
7189 * Correct values: 0 (uncompressed) to 9 (max compression)
7190 */
7191void
7192xmlSetCompressMode(int mode) {
7193 if (mode < 0) xmlCompressMode = 0;
7194 else if (mode > 9) xmlCompressMode = 9;
7195 else xmlCompressMode = mode;
7196}
7197
Kasimier T. Buchcik4d9c9482005-06-27 15:04:46 +00007198/*
7199* xmlDOMWrapNewCtxt:
7200*
7201* Allocates and initializes a new DOM-wrapper context.
7202*
7203* Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal errror.
7204*/
7205xmlDOMWrapCtxtPtr
7206xmlDOMWrapNewCtxt(void)
7207{
7208 xmlDOMWrapCtxtPtr ret;
7209
7210 ret = xmlMalloc(sizeof(xmlDOMWrapCtxt));
7211 if (ret == NULL) {
7212 xmlTreeErrMemory("allocating DOM-wrapper context");
7213 return (NULL);
7214 }
7215 memset(ret, 0, sizeof(xmlDOMWrapCtxt));
7216 return (ret);
7217}
7218
7219/*
7220* xmlDOMWrapFreeCtxt:
7221* @ctxt: the DOM-wrapper context
7222*
7223* Frees the DOM-wrapper context.
7224*/
7225void
7226xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt)
7227{
7228 if (ctxt == NULL)
7229 return;
7230 xmlFree(ctxt);
7231}
7232
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007233#define XML_TREE_NSMAP_PARENT -1
7234#define XML_TREE_NSMAP_XML -2
7235#define XML_TREE_NSMAP_DOC -3
7236#define XML_TREE_NSMAP_CUSTOM -4
7237
7238typedef struct xmlNsMapItem *xmlNsMapItemPtr;
7239struct xmlNsMapItem {
7240 xmlNsMapItemPtr next;
7241 xmlNsMapItemPtr prev;
7242 xmlNsPtr oldNs; /* old ns decl reference */
7243 xmlNsPtr newNs; /* new ns decl reference */
7244 int shadowDepth; /* Shadowed at this depth */
7245 /*
7246 * depth:
7247 * >= 0 == @node's ns-decls
7248 * -1 == @parent's ns-decls
7249 * -2 == @parent's out-of-scope ns-decls
7250 * -3 == the doc->oldNs XML ns-decl
7251 * -4 == the doc->oldNs storage ns-decls
7252 */
7253 int depth;
7254};
7255
7256/*
7257* xmlTreeAddNsMapItem:
7258* @map: the ns-map
7259* @cur: the current map entry to append a new entry to
7260* @oldNs: the old ns-struct
7261* @newNs: the new ns-struct
7262* @depth: depth and ns-kind information
7263*
7264* Frees the ns-map
7265*/
7266static xmlNsMapItemPtr
7267xmlDOMWrapNSNormAddNsMapItem(xmlNsMapItemPtr *map,
7268 xmlNsMapItemPtr *cur,
7269 xmlNsPtr oldNs,
7270 xmlNsPtr newNs,
7271 int depth)
7272{
7273 xmlNsMapItemPtr ret;
7274
7275 if ((cur != NULL) && (*cur != NULL) && ((*cur)->next != NULL)) {
7276 /*
7277 * Reuse.
7278 */
7279 ret = (*cur)->next;
7280 *cur = ret;
7281 } else {
7282 ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem));
7283 if (ret == NULL) {
7284 xmlTreeErrMemory("allocating namespace map item");
7285 return (NULL);
7286 }
7287 memset(ret, 0, sizeof(struct xmlNsMapItem));
7288 if (*map == NULL) {
7289 /*
7290 * First ever.
7291 */
7292 *map = ret;
7293 ret->prev = ret;
7294 if (cur != NULL)
7295 *cur = ret;
7296 } else {
7297 if (cur) {
7298 /*
7299 * Append.
7300 */
7301 (*cur)->next = ret;
7302 ret->prev = *cur;
7303 *cur = ret;
7304 } else {
7305 /*
7306 * Set on first position.
7307 */
7308 ret->next = (*map);
7309 ret->prev = (*map)->prev;
7310 (*map)->prev = ret;
7311 *map = ret;
7312 }
7313 }
7314 }
7315 ret->oldNs = oldNs;
7316 ret->newNs = newNs;
7317 ret->shadowDepth = -1;
7318 ret->depth = depth;
7319 return (ret);
7320}
7321
7322/*
7323* xmlTreeFreeNsMap:
7324* @map: the ns-map
7325*
7326* Frees the ns-map
7327*/
7328static void
7329xmlDOMWrapNSNormFreeNsMap(xmlNsMapItemPtr map)
7330{
7331 xmlNsMapItemPtr mi = map, miprev;
7332
7333 while (mi != NULL) {
7334 miprev = mi;
7335 mi = mi->next;
7336 xmlFree(miprev);
7337 }
7338}
7339
7340/*
7341* xmlTreeEnsureXMLDecl:
7342* @doc: the doc
7343*
7344* Ensures that there is an XML namespace declaration on the doc.
7345*
7346* Returns the XML ns-struct or NULL on API and internal errors.
7347*/
7348static xmlNsPtr
7349xmlTreeEnsureXMLDecl(xmlDocPtr doc)
7350{
7351 if (doc == NULL)
7352 return (NULL);
7353 if (doc->oldNs != NULL)
7354 return (doc->oldNs);
7355 {
7356 xmlNsPtr ns;
7357 ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
7358 if (ns == NULL) {
7359 xmlTreeErrMemory(
7360 "allocating the XML namespace");
7361 return (NULL);
7362 }
7363 memset(ns, 0, sizeof(xmlNs));
7364 ns->type = XML_LOCAL_NAMESPACE;
7365 ns->href = xmlStrdup(XML_XML_NAMESPACE);
7366 ns->prefix = xmlStrdup((const xmlChar *)"xml");
7367 doc->oldNs = ns;
7368 return (ns);
7369 }
7370}
7371
7372/*
7373* xmlDOMWrapStoreNs:
7374* @doc: the doc
7375* @nsName: the namespace name
7376* @prefix: the prefix
7377*
7378* Creates or reuses an xmlNs struct on doc->oldNs with
7379* the given prefix and namespace name.
7380*
7381* Returns the aquired ns struct or NULL in case of an API
7382* or internal error.
7383*/
7384static xmlNsPtr
7385xmlDOMWrapStoreNs(xmlDocPtr doc,
7386 const xmlChar *nsName,
7387 const xmlChar *prefix)
7388{
7389 xmlNsPtr ns;
7390
7391 if (doc == NULL)
7392 return (NULL);
7393 ns = xmlTreeEnsureXMLDecl(doc);
7394 if (ns == NULL)
7395 return (NULL);
7396 if (ns->next != NULL) {
7397 /* Reuse. */
7398 ns = ns->next;
7399 while (ns != NULL) {
7400 if (((ns->prefix == prefix) ||
7401 xmlStrEqual(ns->prefix, prefix)) &&
7402 xmlStrEqual(ns->href, nsName)) {
7403 return (ns);
7404 }
7405 if (ns->next == NULL)
7406 break;
7407 ns = ns->next;
7408 }
7409 }
7410 /* Create. */
7411 ns->next = xmlNewNs(NULL, nsName, prefix);
7412 return (ns->next);
7413}
7414
7415/*
7416* xmlTreeLookupNsListByPrefix:
7417* @nsList: a list of ns-structs
7418* @prefix: the searched prefix
7419*
7420* Searches for a ns-decl with the given prefix in @nsList.
7421*
7422* Returns the ns-decl if found, NULL if not found and on
7423* API errors.
7424*/
7425static xmlNsPtr
7426xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix)
7427{
7428 if (nsList == NULL)
7429 return (NULL);
7430 {
7431 xmlNsPtr ns;
7432 ns = nsList;
7433 do {
7434 if ((prefix == ns->prefix) ||
7435 xmlStrEqual(prefix, ns->prefix)) {
7436 return (ns);
7437 }
7438 ns = ns->next;
7439 } while (ns != NULL);
7440 }
7441 return (NULL);
7442}
7443
7444/*
7445*
7446* xmlTreeGetInScopeNamespaces:
7447* @map: the namespace map
7448* @node: the node to start with
7449*
7450* Puts in-scope namespaces into the ns-map.
7451*
7452* Returns 0 on success, -1 on API or internal errors.
7453*/
7454static int
7455xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapItemPtr *map,
7456 xmlNodePtr node)
7457{
7458 xmlNodePtr cur;
7459 xmlNsPtr ns;
7460 xmlNsMapItemPtr mi;
7461 int shadowed;
7462
7463 if ((map == NULL) || (*map != NULL))
7464 return (-1);
7465 /*
7466 * Get in-scope ns-decls of @parent.
7467 */
7468 cur = node;
7469 while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) {
7470 if (cur->type == XML_ELEMENT_NODE) {
7471 if (cur->nsDef != NULL) {
7472 ns = cur->nsDef;
7473 do {
7474 shadowed = 0;
7475 if (*map != NULL) {
7476 /*
7477 * Skip shadowed prefixes.
7478 */
7479 for (mi = *map; mi != NULL; mi = mi->next) {
7480 if ((ns->prefix == mi->newNs->prefix) ||
7481 xmlStrEqual(ns->prefix, mi->newNs->prefix)) {
7482 shadowed = 1;
7483 break;
7484 }
7485 }
7486 }
7487 /*
7488 * Insert mapping.
7489 */
7490 mi = xmlDOMWrapNSNormAddNsMapItem(map, NULL, NULL,
7491 ns, XML_TREE_NSMAP_PARENT);
7492 if (mi == NULL)
7493 return (-1);
7494 if (shadowed)
7495 mi->shadowDepth = 0;
7496 ns = ns->next;
7497 } while (ns != NULL);
7498 }
7499 }
7500 cur = cur->parent;
7501 }
7502 return (0);
7503}
7504
7505/*
7506* XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict;
7507* otherwise copy it, when it was in the source-dict.
7508*/
7509#define XML_TREE_ADOPT_STR(str) \
7510 if (adoptStr && (str != NULL)) { \
7511 if (destDoc->dict) { \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00007512 const xmlChar *old = str; \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007513 str = xmlDictLookup(destDoc->dict, str, -1); \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00007514 if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \
7515 (!xmlDictOwns(sourceDoc->dict, old))) \
Daniel Veillard39e5c892005-07-03 22:48:50 +00007516 xmlFree((char *)old); \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007517 } else if ((sourceDoc) && (sourceDoc->dict) && \
7518 xmlDictOwns(sourceDoc->dict, str)) { \
7519 str = BAD_CAST xmlStrdup(str); \
7520 } \
7521 }
7522
7523/*
7524* XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then
7525* put it in dest-dict or copy it.
7526*/
7527#define XML_TREE_ADOPT_STR_2(str) \
7528 if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \
7529 (sourceDoc->dict != NULL) && \
7530 xmlDictOwns(sourceDoc->dict, cur->content)) { \
7531 if (destDoc->dict) \
7532 cur->content = (xmlChar *) \
7533 xmlDictLookup(destDoc->dict, cur->content, -1); \
7534 else \
7535 cur->content = xmlStrdup(BAD_CAST cur->content); \
7536 }
7537
7538/*
7539* xmlDOMWrapNSNormAddNsMapItem2:
7540*
7541* For internal use. Adds a ns-decl mapping.
7542*
7543* Returns 0 on success, -1 on internal errors.
7544*/
7545static int
7546xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number,
7547 xmlNsPtr oldNs, xmlNsPtr newNs)
7548{
7549 if (*list == NULL) {
7550 *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr));
7551 if (*list == NULL) {
7552 xmlTreeErrMemory("alloc ns map item");
7553 return(-1);
7554 }
7555 *size = 3;
7556 *number = 0;
7557 } else if ((*number) >= (*size)) {
7558 *size *= 2;
7559 *list = (xmlNsPtr *) xmlRealloc(*list,
7560 (*size) * 2 * sizeof(xmlNsPtr));
7561 if (*list == NULL) {
7562 xmlTreeErrMemory("realloc ns map item");
7563 return(-1);
7564 }
7565 }
7566 (*list)[2 * (*number)] = oldNs;
7567 (*list)[2 * (*number) +1] = newNs;
7568 (*number)++;
7569 return (0);
7570}
7571
7572/*
7573* xmlDOMWrapRemoveNode:
Daniel Veillard304e78c2005-07-03 16:19:41 +00007574* @ctxt: a DOM wrapper context
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007575* @doc: the doc
7576* @node: the node to be removed.
Daniel Veillard304e78c2005-07-03 16:19:41 +00007577* @options: set of options, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007578*
7579* Unlinks the given node from its owner.
7580* This will substitute ns-references to node->nsDef for
7581* ns-references to doc->oldNs, thus ensuring the removed
7582* branch to be autark wrt ns-references.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00007583* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007584*
7585* Returns 0 on success, 1 if the node is not supported,
7586* -1 on API and internal errors.
7587*/
7588int
7589xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc,
7590 xmlNodePtr node, int options ATTRIBUTE_UNUSED)
7591{
7592 xmlNsPtr *list = NULL;
7593 int sizeList, nbList, i, j;
7594 xmlNsPtr ns;
7595
7596 if ((node == NULL) || (doc == NULL) || (node->doc != doc))
7597 return (-1);
7598
7599 /* TODO: 0 or -1 ? */
7600 if (node->parent == NULL)
7601 return (0);
7602
7603 switch (node->type) {
7604 case XML_TEXT_NODE:
7605 case XML_CDATA_SECTION_NODE:
7606 case XML_ENTITY_REF_NODE:
7607 case XML_PI_NODE:
7608 case XML_COMMENT_NODE:
7609 xmlUnlinkNode(node);
7610 return (0);
7611 case XML_ELEMENT_NODE:
7612 case XML_ATTRIBUTE_NODE:
7613 break;
7614 default:
7615 return (1);
7616 }
7617 xmlUnlinkNode(node);
7618 /*
7619 * Save out-of-scope ns-references in doc->oldNs.
7620 */
7621 do {
7622 switch (node->type) {
7623 case XML_ELEMENT_NODE:
7624 if ((ctxt == NULL) && (node->nsDef != NULL)) {
7625 ns = node->nsDef;
7626 do {
7627 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
7628 &nbList, ns, ns) == -1)
7629 goto internal_error;
7630 ns = ns->next;
7631 } while (ns != NULL);
7632 }
7633 /* No break on purpose. */
7634 case XML_ATTRIBUTE_NODE:
7635 if (node->ns != NULL) {
7636 /*
7637 * Find a mapping.
7638 */
7639 if (list != NULL) {
7640 for (i = 0, j = 0; i < nbList; i++, j += 2) {
7641 if (node->ns == list[j]) {
7642 node->ns = list[++j];
7643 goto next_node;
7644 }
7645 }
7646 }
7647 ns = NULL;
7648 if (ctxt != NULL) {
7649 /*
7650 * User defined.
7651 */
7652 } else {
7653 /*
7654 * Add to doc's oldNs.
7655 */
7656 ns = xmlDOMWrapStoreNs(doc, node->ns->href,
7657 node->ns->prefix);
7658 if (ns == NULL)
7659 goto internal_error;
7660 }
7661 if (ns != NULL) {
7662 /*
7663 * Add mapping.
7664 */
7665 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
7666 &nbList, node->ns, ns) == -1)
7667 goto internal_error;
7668 }
7669 node->ns = ns;
7670 }
7671 if ((node->type == XML_ELEMENT_NODE) &&
7672 (node->properties != NULL)) {
7673 node = (xmlNodePtr) node->properties;
7674 continue;
7675 }
7676 break;
7677 default:
7678 goto next_sibling;
7679 }
7680next_node:
7681 if ((node->type == XML_ELEMENT_NODE) &&
7682 (node->children != NULL)) {
7683 node = node->children;
7684 continue;
7685 }
7686next_sibling:
7687 if (node == NULL)
7688 break;
7689 if (node->next != NULL)
7690 node = node->next;
7691 else {
7692 node = node->parent;
7693 goto next_sibling;
7694 }
7695 } while (node != NULL);
7696
7697 if (list != NULL)
7698 xmlFree(list);
7699 return (0);
7700
7701internal_error:
7702 if (list != NULL)
7703 xmlFree(list);
7704 return (-1);
7705}
7706
7707/*
7708* xmlSearchNsByHrefStrict:
7709* @doc: the document
7710* @node: the start node
7711* @nsName: the searched namespace name
7712* @retNs: the resulting ns-decl
7713* @prefixed: if the found ns-decl must have a prefix (for attributes)
7714*
7715* Dynamically searches for a ns-declaration which matches
7716* the given @nsName in the ancestor-or-self axis of @node.
7717*
7718* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7719* and internal errors.
7720*/
7721static int
7722xmlSearchNsByHrefStrict(xmlDocPtr doc, xmlNodePtr node, const xmlChar* nsName,
7723 xmlNsPtr *retNs, int prefixed)
7724{
7725 xmlNodePtr cur, prev = NULL, out = NULL;
7726 xmlNsPtr ns, prevns;
7727
7728 if ((doc == NULL) || (nsName == NULL) || (retNs == NULL))
7729 return (-1);
7730
7731 *retNs = NULL;
7732 if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
7733 *retNs = xmlTreeEnsureXMLDecl(doc);
7734 if (*retNs == NULL)
7735 return (-1);
7736 return (1);
7737 }
7738 cur = node;
7739 do {
7740 if (cur->type == XML_ELEMENT_NODE) {
7741 if (cur->nsDef != NULL) {
7742 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
7743 if (prefixed && (ns->prefix == NULL))
7744 continue;
7745 if (prev != NULL) {
7746 /*
7747 * Check the last level of ns-decls for a
7748 * shadowing prefix.
7749 */
7750 prevns = prev->nsDef;
7751 do {
7752 if ((prevns->prefix == ns->prefix) ||
7753 ((prevns->prefix != NULL) &&
7754 (ns->prefix != NULL) &&
7755 xmlStrEqual(prevns->prefix, ns->prefix))) {
7756 /*
7757 * Shadowed.
7758 */
7759 break;
7760 }
7761 prevns = prevns->next;
7762 } while (prevns != NULL);
7763 if (prevns != NULL)
7764 continue;
7765 }
7766 /*
7767 * Ns-name comparison.
7768 */
7769 if ((nsName == ns->href) ||
7770 xmlStrEqual(nsName, ns->href)) {
7771 /*
7772 * At this point the prefix can only be shadowed,
7773 * if we are the the (at least) 3rd level of
7774 * ns-decls.
7775 */
7776 if (out) {
7777 int ret;
7778
7779 ret = xmlNsInScope(doc, node, prev, ns->prefix);
7780 if (ret < 0)
7781 return (-1);
7782 /*
7783 * TODO: Should we try to find a matching ns-name
7784 * only once? This here keeps on searching.
7785 * I think we should try further since, there might
7786 * be an other matching ns-decl with an unshadowed
7787 * prefix.
7788 */
7789 if (! ret)
7790 continue;
7791 }
7792 *retNs = ns;
7793 return (1);
7794 }
7795 }
7796 out = prev;
7797 prev = cur;
7798 }
7799 } else if ((node->type == XML_ENTITY_REF_NODE) ||
7800 (node->type == XML_ENTITY_NODE) ||
7801 (node->type == XML_ENTITY_DECL))
7802 return (0);
7803 cur = cur->parent;
7804 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
7805 return (0);
7806}
7807
7808/*
7809* xmlDOMWrapNSNormDeclareNsForced:
7810* @doc: the doc
7811* @elem: the element-node to declare on
7812* @nsName: the namespace-name of the ns-decl
7813* @prefix: the preferred prefix of the ns-decl
7814* @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls
7815*
7816* Declares a new namespace on @elem. It tries to use the
7817* given @prefix; if a ns-decl with the given prefix is already existent
7818* on @elem, it will generate an other prefix.
7819*
7820* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7821* and internal errors.
7822*/
7823static xmlNsPtr
7824xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc,
7825 xmlNodePtr elem,
7826 const xmlChar *nsName,
7827 const xmlChar *prefix,
7828 int checkShadow)
7829{
7830
7831 xmlNsPtr ret;
7832 char buf[50];
7833 const xmlChar *pref;
7834 int counter = 0;
7835 /*
7836 * Create a ns-decl on @anchor.
7837 */
7838 pref = prefix;
7839 while (1) {
7840 /*
7841 * Lookup whether the prefix is unused in elem's ns-decls.
7842 */
7843 if ((elem->nsDef != NULL) &&
7844 (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL))
7845 goto ns_next_prefix;
7846 if (checkShadow && elem->parent &&
7847 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
7848 /*
7849 * Does it shadow ancestor ns-decls?
7850 */
7851 if (xmlSearchNs(doc, elem->parent, pref) != NULL)
7852 goto ns_next_prefix;
7853 }
7854 ret = xmlNewNs(NULL, nsName, pref);
7855 if (ret == NULL)
7856 return (NULL);
7857 if (elem->nsDef == NULL)
7858 elem->nsDef = ret;
7859 else {
7860 xmlNsPtr ns2 = elem->nsDef;
7861 while (ns2->next != NULL)
7862 ns2 = ns2->next;
7863 ns2->next = ret;
7864 }
7865 return (ret);
7866ns_next_prefix:
7867 counter++;
7868 if (counter > 1000)
7869 return (NULL);
7870 if (prefix == NULL) {
7871 snprintf((char *) buf, sizeof(buf),
7872 "default%d", counter);
7873 } else
7874 snprintf((char *) buf, sizeof(buf),
7875 "%.30s%d", (char *)prefix, counter);
7876 pref = BAD_CAST buf;
7877 }
7878}
7879
7880/*
7881* xmlDOMWrapNSNormAquireNormalizedNs:
7882* @doc: the doc
7883* @elem: the element-node to declare namespaces on
7884* @ns: the ns-struct to use for the search
7885* @retNs: the found/created ns-struct
7886* @nsMap: the ns-map
7887* @topmi: the last ns-map entry
7888* @depth: the current tree depth
7889* @ancestorsOnly: search in ancestor ns-decls only
7890* @prefixed: if the searched ns-decl must have a prefix (for attributes)
7891*
7892* Searches for a matching ns-name in the ns-decls of @nsMap, if not
7893* found it will either declare it on @elem, or store it in doc->oldNs.
7894* If a new ns-decl needs to be declared on @elem, it tries to use the
7895* @ns->prefix for it, if this prefix is already in use on @elem, it will
7896* change the prefix or the new ns-decl.
7897*
7898* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
7899*/
7900static int
7901xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc,
7902 xmlNodePtr elem,
7903 xmlNsPtr ns,
7904 xmlNsPtr *retNs,
7905 xmlNsMapItemPtr *nsMap,
7906 xmlNsMapItemPtr *topmi,
7907 int depth,
7908 int ancestorsOnly,
7909 int prefixed)
7910{
7911 xmlNsMapItemPtr mi;
7912
7913 if ((doc == NULL) || (ns == NULL) || (retNs == NULL) ||
7914 (nsMap == NULL) || (topmi == NULL))
7915 return (-1);
7916
7917 *retNs = NULL;
7918 /*
7919 * Handle XML namespace.
7920 */
7921 if ((ns->prefix) &&
7922 (ns->prefix[0] == 'x') &&
7923 (ns->prefix[1] == 'm') &&
7924 (ns->prefix[2] == 'l') &&
7925 (ns->prefix[3] == 0)) {
7926 /*
7927 * Insert XML namespace mapping.
7928 */
7929 *retNs = xmlTreeEnsureXMLDecl(doc);
7930 if (*retNs == NULL)
7931 return (-1);
7932 return (0);
7933 }
7934 /*
7935 * If the search should be done in ancestors only and no
7936 * @elem (the first ancestor) was specified, then skip the search.
7937 */
7938 if ((! (ancestorsOnly && (elem == NULL))) &&
7939 (*nsMap != NULL)) {
7940
7941 /*
7942 * Try to find an equal ns-name in in-scope ns-decls.
7943 */
7944 for (mi = *nsMap; mi != (*topmi)->next; mi = mi->next) {
7945
7946 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
7947 /*
7948 * This should be turned on to gain speed, if one knows
7949 * that the branch itself was already ns-wellformed and no
7950 * stale references existed. I.e. it searches in the ancestor
7951 * axis only.
7952 */
7953 ((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) &&
7954 /* Skip shadowed prefixes. */
7955 (mi->shadowDepth == -1) &&
7956 /* Skip xmlns="" or xmlns:foo="". */
7957 ((mi->newNs->href != NULL) &&
7958 (mi->newNs->href[0] != 0)) &&
7959 /* Ensure a prefix if wanted. */
7960 ((! prefixed) || (mi->newNs->prefix != NULL)) &&
7961 /* Equal ns name */
7962 ((mi->newNs->href == ns->href) ||
7963 xmlStrEqual(mi->newNs->href, ns->href))) {
7964 /* Set the mapping. */
7965 mi->oldNs = ns;
7966 *retNs = mi->newNs;
7967 return (0);
7968 }
7969 }
7970 }
7971 /*
7972 * No luck, the namespace is out of scope or shadowed.
7973 */
7974 if (elem == NULL) {
7975 xmlNsPtr tmpns;
7976
7977 /*
7978 * Store ns-decls in "oldNs" of the document-node.
7979 */
7980 tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix);
7981 if (tmpns == NULL)
7982 return (-1);
7983 /*
7984 * Insert mapping.
7985 */
7986 if (xmlDOMWrapNSNormAddNsMapItem(nsMap, NULL, ns,
7987 tmpns, XML_TREE_NSMAP_DOC) == NULL) {
7988 xmlFreeNs(tmpns);
7989 return (-1);
7990 }
7991 *retNs = tmpns;
7992 } else {
7993 xmlNsPtr tmpns;
7994
7995 tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href,
7996 ns->prefix, 0);
7997 if (tmpns == NULL)
7998 return (-1);
7999
8000 if (*nsMap != NULL) {
8001 /*
8002 * Does it shadow ancestor ns-decls?
8003 */
8004 for (mi = *nsMap; mi != (*topmi)->next; mi = mi->next) {
8005 if ((mi->depth < depth) &&
8006 (mi->shadowDepth == -1) &&
8007 ((ns->prefix == mi->newNs->prefix) ||
8008 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8009 /*
8010 * Shadows.
8011 */
8012 mi->shadowDepth = depth;
8013 break;
8014 }
8015 }
8016 }
8017 if (xmlDOMWrapNSNormAddNsMapItem(nsMap, topmi, ns,
8018 tmpns, depth) == NULL) {
8019 xmlFreeNs(tmpns);
8020 return (-1);
8021 }
8022 *retNs = tmpns;
8023 }
8024 return (0);
8025}
8026
8027/*
8028* xmlDOMWrapReconcileNamespaces:
Daniel Veillard304e78c2005-07-03 16:19:41 +00008029* @ctxt: DOM wrapper context, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008030* @elem: the element-node
8031* @options: option flags
8032*
8033* Ensures that ns-references point to ns-decls hold on element-nodes.
8034* Ensures that the tree is namespace wellformed by creating additional
8035* ns-decls where needed. Note that, since prefixes of already existent
8036* ns-decls can be shadowed by this process, it could break QNames in
8037* attribute values or element content.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00008038* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008039*
8040* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8041*/
8042int
8043xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,
8044 xmlNodePtr elem,
8045 int options ATTRIBUTE_UNUSED)
8046{
8047 int depth = -1, adoptns = 0, parnsdone = 0;
8048 xmlNsPtr ns;
8049 xmlDocPtr doc;
8050 xmlNodePtr cur, curElem = NULL;
8051 xmlNsMapItemPtr nsMap = NULL, topmi = NULL, mi;
8052 /* @ancestorsOnly should be set by an option flag. */
8053 int ancestorsOnly = 0;
8054
8055 if ((elem == NULL) || (elem->doc == NULL) ||
8056 (elem->type != XML_ELEMENT_NODE))
8057 return (-1);
8058
8059 doc = elem->doc;
8060 cur = elem;
8061 do {
8062 switch (cur->type) {
8063 case XML_ELEMENT_NODE:
8064 adoptns = 1;
8065 curElem = cur;
8066 depth++;
8067 /*
8068 * Namespace declarations.
8069 */
8070 if (cur->nsDef != NULL) {
8071 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8072 if (! parnsdone) {
8073 if ((elem->parent) &&
8074 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8075 /*
8076 * Gather ancestor in-scope ns-decls.
8077 */
8078 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8079 elem->parent) == -1)
8080 goto internal_error;
8081 if (nsMap != NULL)
8082 topmi = nsMap->prev;
8083 }
8084 parnsdone = 1;
8085 }
8086 /*
8087 * Skip ns-references handling if the referenced
8088 * ns-decl is declared on the same element.
8089 */
8090 if ((cur->ns != NULL) && adoptns && (cur->ns == ns))
8091 adoptns = 0;
8092 /*
8093 * Does it shadow any ns-decl?
8094 */
8095 if (nsMap) {
8096 for (mi = nsMap; mi != topmi->next; mi = mi->next) {
8097 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8098 (mi->shadowDepth == -1) &&
8099 ((ns->prefix == mi->newNs->prefix) ||
8100 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8101
8102 mi->shadowDepth = depth;
8103 }
8104 }
8105 }
8106 /*
8107 * Push mapping.
8108 */
8109 if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi, ns, ns,
8110 depth) == NULL)
8111 goto internal_error;
8112 }
8113 }
8114 if (! adoptns)
8115 goto ns_end;
8116
8117 /* No break on purpose. */
8118 case XML_ATTRIBUTE_NODE:
8119 if (cur->ns == NULL)
8120 goto ns_end;
8121 if (! parnsdone) {
8122 if ((elem->parent) &&
8123 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8124 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8125 elem->parent) == -1)
8126 goto internal_error;
8127 if (nsMap != NULL)
8128 topmi = nsMap->prev;
8129 }
8130 parnsdone = 1;
8131 }
8132 /*
8133 * Adopt ns-references.
8134 */
8135 if (nsMap != NULL) {
8136 /*
8137 * Search for a mapping.
8138 */
8139 for (mi = nsMap; mi != topmi->next; mi = mi->next) {
8140 if ((mi->shadowDepth == -1) &&
8141 (cur->ns == mi->oldNs)) {
8142
8143 cur->ns = mi->newNs;
8144 goto ns_end;
8145 }
8146 }
8147 }
8148 /*
8149 * Aquire a normalized ns-decl and add it to the map.
8150 */
8151 if (xmlDOMWrapNSNormAquireNormalizedNs(doc, curElem,
8152 cur->ns, &ns,
8153 &nsMap, &topmi, depth,
8154 ancestorsOnly,
8155 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8156 goto internal_error;
8157 cur->ns = ns;
8158
8159ns_end:
8160 if ((cur->type == XML_ELEMENT_NODE) &&
8161 (cur->properties != NULL)) {
8162 /*
8163 * Process attributes.
8164 */
8165 cur = (xmlNodePtr) cur->properties;
8166 continue;
8167 }
8168 break;
8169 default:
8170 goto next_sibling;
8171 }
8172 if ((cur->type == XML_ELEMENT_NODE) &&
8173 (cur->children != NULL)) {
8174 /*
8175 * Process content of element-nodes only.
8176 */
8177 cur = cur->children;
8178 continue;
8179 }
8180next_sibling:
8181 if (cur == elem)
8182 break;
8183 if (cur->type == XML_ELEMENT_NODE) {
8184 if (nsMap != NULL) {
8185 /*
8186 * Pop mappings.
8187 */
8188 while ((topmi->depth >= 0) && (topmi->depth >= depth))
8189 topmi = topmi->prev;
8190 /*
8191 * Unshadow.
8192 */
8193 for (mi = nsMap; mi != topmi->next; mi = mi->next)
8194 if (mi->shadowDepth >= depth)
8195 mi->shadowDepth = -1;
8196 }
8197 depth--;
8198 }
8199 if (cur->next != NULL)
8200 cur = cur->next;
8201 else {
8202 cur = cur->parent;
8203 goto next_sibling;
8204 }
8205 } while (cur != NULL);
8206
8207 if (nsMap != NULL)
8208 xmlDOMWrapNSNormFreeNsMap(nsMap);
8209 return (0);
8210internal_error:
8211 if (nsMap != NULL)
8212 xmlDOMWrapNSNormFreeNsMap(nsMap);
8213 return (-1);
8214}
8215
8216/*
8217* xmlDOMWrapAdoptBranch:
8218* @ctxt: the optional context for custom processing
8219* @sourceDoc: the optional sourceDoc
8220* @node: the element-node to start with
8221* @destDoc: the destination doc for adoption
8222* @parent: the optional new parent of @node in @destDoc
8223* @options: option flags
8224*
8225* Ensures that ns-references point to @destDoc: either to
8226* elements->nsDef entries if @destParent is given, or to
8227* @destDoc->oldNs otherwise.
8228* If @destParent is given, it ensures that the tree is namespace
8229* wellformed by creating additional ns-decls where needed.
8230* Note that, since prefixes of already existent ns-decls can be
8231* shadowed by this process, it could break QNames in attribute
8232* values or element content.
8233*
8234* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8235*/
8236static int
8237xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
8238 xmlDocPtr sourceDoc,
8239 xmlNodePtr node,
8240 xmlDocPtr destDoc,
8241 xmlNodePtr destParent,
8242 int options ATTRIBUTE_UNUSED)
8243{
8244 int ret = 0;
8245 xmlNodePtr cur, curElem = NULL;
8246 xmlNsMapItemPtr nsMap = NULL, topmi = NULL, mi;
8247 xmlNsPtr ns;
8248 int depth = -1, adoptStr = 1;
8249 /* gather @parent's ns-decls. */
8250 int parnsdone = 0;
8251 /* @ancestorsOnly should be set per option. */
8252 int ancestorsOnly = 0;
8253
8254 /*
8255 * Optimize string adoption for equal or none dicts.
8256 */
8257 if ((sourceDoc != NULL) &&
8258 (sourceDoc->dict == destDoc->dict))
8259 adoptStr = 0;
8260 else
8261 adoptStr = 1;
8262
8263 cur = node;
8264 while (cur != NULL) {
8265 if (cur->doc != sourceDoc) {
8266 /*
8267 * We'll assume XIncluded nodes if the doc differs.
8268 * TODO: Do we need to reconciliate XIncluded nodes?
8269 * This here skips XIncluded nodes and tries to handle
8270 * broken sequences.
8271 */
8272 if (cur->next == NULL)
8273 goto leave_node;
8274 do {
8275 cur = cur->next;
8276 if ((cur->type == XML_XINCLUDE_END) ||
8277 (cur->doc == node->doc))
8278 break;
8279 } while (cur->next != NULL);
8280
8281 if (cur->doc != node->doc)
8282 goto leave_node;
8283 }
8284 cur->doc = destDoc;
8285 switch (cur->type) {
8286 case XML_XINCLUDE_START:
8287 case XML_XINCLUDE_END:
8288 /*
8289 * TODO
8290 */
8291 return (-1);
8292 case XML_ELEMENT_NODE:
8293 curElem = cur;
8294 depth++;
8295 /*
8296 * Namespace declarations.
8297 */
8298 if ((ctxt == NULL) && (cur->nsDef != NULL)) {
8299 if (! parnsdone) {
8300 if (destParent && (ctxt == NULL)) {
8301 /*
8302 * Gather @parent's in-scope ns-decls.
8303 */
8304 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8305 destParent) == -1)
8306 goto internal_error;
8307 if (nsMap != NULL)
8308 topmi = nsMap->prev;
8309 }
8310 parnsdone = 1;
8311 }
8312 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8313 /*
8314 * ns->prefix and ns->href seem not to be in the dict.
8315 * XML_TREE_ADOPT_STR(ns->prefix)
8316 * XML_TREE_ADOPT_STR(ns->href)
8317 */
8318 /*
8319 * Does it shadow any ns-decl?
8320 */
8321 if (nsMap) {
8322 for (mi = nsMap; mi != topmi->next;
8323 mi = mi->next) {
8324 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8325 (mi->shadowDepth == -1) &&
8326 ((ns->prefix == mi->newNs->prefix) ||
8327 xmlStrEqual(ns->prefix,
8328 mi->newNs->prefix))) {
8329
8330 mi->shadowDepth = depth;
8331 }
8332 }
8333 }
8334 /*
8335 * Push mapping.
8336 */
8337 if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi,
8338 ns, ns, depth) == NULL)
8339 goto internal_error;
8340 }
8341 }
8342 /* No break on purpose. */
8343 case XML_ATTRIBUTE_NODE:
8344
8345 if (cur->ns == NULL)
8346 goto ns_end;
8347 if (! parnsdone) {
8348 if (destParent && (ctxt == NULL)) {
8349 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8350 destParent) == -1)
8351 goto internal_error;
8352 if (nsMap != NULL)
8353 topmi = nsMap->prev;
8354 }
8355 parnsdone = 1;
8356 }
8357 /*
8358 * Adopt ns-references.
8359 */
8360 if (nsMap != NULL) {
8361 /*
8362 * Search for a mapping.
8363 */
8364 for (mi = nsMap; mi != topmi->next; mi = mi->next) {
8365 if ((mi->shadowDepth == -1) &&
8366 (cur->ns == mi->oldNs)) {
8367
8368 cur->ns = mi->newNs;
8369 goto ns_end;
8370 }
8371 }
8372 }
8373 /*
8374 * Start searching for an in-scope ns-decl.
8375 */
8376 if (ctxt != NULL) {
8377 /*
8378 * User-defined behaviour.
8379 */
8380#if 0
8381 ctxt->aquireNsDecl(ctxt, cur->ns, &ns);
8382#endif
8383 /*
8384 * Insert mapping if ns is available; it's the users fault
8385 * if not.
8386 */
8387 if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi,
8388 ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
8389 goto internal_error;
8390 cur->ns = ns;
8391 } else {
8392 /*
8393 * Aquire a normalized ns-decl and add it to the map.
8394 */
8395 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
8396 /* ns-decls on curElem or on destDoc->oldNs */
8397 destParent ? curElem : NULL,
8398 cur->ns, &ns,
8399 &nsMap, &topmi, depth,
8400 ancestorsOnly,
8401 /* ns-decls must be prefixed for attributes. */
8402 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8403 goto internal_error;
8404 cur->ns = ns;
8405 }
8406ns_end:
8407 /*
8408 * Further node properties.
8409 * TODO: Is this all?
8410 */
8411 XML_TREE_ADOPT_STR(cur->name)
8412 if (cur->type == XML_ELEMENT_NODE) {
8413 cur->psvi = NULL;
8414 cur->line = 0;
8415 cur->extra = 0;
8416 /*
8417 * Walk attributes.
8418 */
8419 if (cur->properties != NULL) {
8420 /*
8421 * Process first attribute node.
8422 */
8423 cur = (xmlNodePtr) cur->properties;
8424 continue;
8425 }
8426 } else {
8427 /*
8428 * Attributes.
8429 */
8430 if ((sourceDoc != NULL) &&
8431 (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID))
8432 xmlRemoveID(sourceDoc, (xmlAttrPtr) cur);
8433 ((xmlAttrPtr) cur)->atype = 0;
8434 ((xmlAttrPtr) cur)->psvi = NULL;
8435 }
8436 break;
8437 case XML_TEXT_NODE:
8438 case XML_CDATA_SECTION_NODE:
8439 /*
8440 * This puts the content in the dest dict, only if
8441 * it was previously in the source dict.
8442 */
8443 XML_TREE_ADOPT_STR_2(cur->content)
8444 goto leave_node;
8445 case XML_ENTITY_REF_NODE:
8446 /*
8447 * Remove reference to the entitity-node.
8448 */
8449 cur->content = NULL;
8450 cur->children = NULL;
8451 cur->last = NULL;
8452 if ((destDoc->intSubset) || (destDoc->extSubset)) {
8453 xmlEntityPtr ent;
8454 /*
8455 * Assign new entity-node if available.
8456 */
8457 ent = xmlGetDocEntity(destDoc, cur->name);
8458 if (ent != NULL) {
8459 cur->content = ent->content;
8460 cur->children = (xmlNodePtr) ent;
8461 cur->last = (xmlNodePtr) ent;
8462 }
8463 }
8464 goto leave_node;
8465 case XML_PI_NODE:
8466 XML_TREE_ADOPT_STR(cur->name)
8467 XML_TREE_ADOPT_STR_2(cur->content)
8468 break;
8469 case XML_COMMENT_NODE:
8470 break;
8471 default:
8472 goto internal_error;
8473 }
8474 /*
8475 * Walk the tree.
8476 */
8477 if (cur->children != NULL) {
8478 cur = cur->children;
8479 continue;
8480 }
8481
8482leave_node:
8483 if (cur == node)
8484 break;
8485 if ((cur->type == XML_ELEMENT_NODE) ||
8486 (cur->type == XML_XINCLUDE_START) ||
8487 (cur->type == XML_XINCLUDE_END)) {
8488 /*
8489 * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
8490 */
8491 if (nsMap != NULL) {
8492 /*
8493 * Pop mappings.
8494 */
8495 while (topmi->depth >= depth)
8496 topmi = topmi->prev;
8497 /*
8498 * Unshadow.
8499 */
8500 for (mi = nsMap; mi != topmi->next; mi = mi->next)
8501 if (mi->shadowDepth >= depth)
8502 mi->shadowDepth = -1;
8503 }
8504 depth--;
8505 }
8506 if (cur->next != NULL)
8507 cur = cur->next;
8508 else {
8509 cur = cur->parent;
8510 goto leave_node;
8511 }
8512 }
8513 /*
8514 * Cleanup.
8515 */
8516 if (nsMap != NULL)
8517 xmlDOMWrapNSNormFreeNsMap(nsMap);
8518 return (ret);
8519internal_error:
8520 if (nsMap != NULL)
8521 xmlDOMWrapNSNormFreeNsMap(nsMap);
8522 return (-1);
8523}
8524
8525/*
8526* xmlDOMWrapAdoptAttr:
8527* @ctxt: the optional context for custom processing
8528* @sourceDoc: the optional source document of attr
8529* @attr: the attribute-node to be adopted
8530* @destDoc: the destination doc for adoption
8531* @destParent: the optional new parent of @attr in @destDoc
8532* @options: option flags
8533*
8534* @attr is adopted by @destDoc.
8535* Ensures that ns-references point to @destDoc: either to
8536* elements->nsDef entries if @destParent is given, or to
8537* @destDoc->oldNs otherwise.
8538*
8539* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8540*/
8541static int
8542xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt,
8543 xmlDocPtr sourceDoc,
8544 xmlAttrPtr attr,
8545 xmlDocPtr destDoc,
8546 xmlNodePtr destParent,
8547 int options ATTRIBUTE_UNUSED)
8548{
8549 xmlNodePtr cur;
8550 int adoptStr = 1;
8551
8552 if ((attr == NULL) || (destDoc == NULL))
8553 return (-1);
8554
8555 attr->doc = destDoc;
8556 if (attr->ns != NULL) {
8557 xmlNsPtr ns = NULL;
8558
8559 if (ctxt != NULL) {
8560 /* TODO: User defined. */
8561 }
8562 /* XML Namespace. */
8563 if ((attr->ns->prefix[0] == 'x') && (attr->ns->prefix[1] == 'm') &&
8564 (attr->ns->prefix[2] == 'l') && (attr->ns->prefix[3] == 0)) {
8565 ns = xmlTreeEnsureXMLDecl(destDoc);
8566 } else if (destParent == NULL) {
8567 /*
8568 * Store in @destDoc->oldNs.
8569 */
8570 ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix);
8571 } else {
8572 /*
8573 * Declare on @destParent.
8574 */
8575 if (xmlSearchNsByHrefStrict(destDoc, destParent, attr->ns->href,
8576 &ns, 1) == -1)
8577 goto internal_error;
8578 if (ns == NULL) {
8579 ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent,
8580 attr->ns->href, attr->ns->prefix, 1);
8581 }
8582 }
8583 if (ns == NULL)
8584 goto internal_error;
8585 attr->ns = ns;
8586 }
8587
8588 XML_TREE_ADOPT_STR(attr->name);
8589 attr->atype = 0;
8590 attr->psvi = NULL;
8591 /*
8592 * Walk content.
8593 */
8594 if (attr->children == NULL)
8595 return (0);
8596 cur = attr->children;
8597 while (cur != NULL) {
8598 cur->doc = destDoc;
8599 switch (cur->type) {
8600 case XML_TEXT_NODE:
8601 case XML_CDATA_SECTION_NODE:
8602 XML_TREE_ADOPT_STR_2(cur->content)
8603 break;
8604 case XML_ENTITY_REF_NODE:
8605 /*
8606 * Remove reference to the entitity-node.
8607 */
8608 cur->content = NULL;
8609 cur->children = NULL;
8610 cur->last = NULL;
8611 if ((destDoc->intSubset) || (destDoc->extSubset)) {
8612 xmlEntityPtr ent;
8613 /*
8614 * Assign new entity-node if available.
8615 */
8616 ent = xmlGetDocEntity(destDoc, cur->name);
8617 if (ent != NULL) {
8618 cur->content = ent->content;
8619 cur->children = (xmlNodePtr) ent;
8620 cur->last = (xmlNodePtr) ent;
8621 }
8622 }
8623 break;
8624 default:
8625 break;
8626 }
8627 if (cur->children != NULL) {
8628 cur = cur->children;
8629 continue;
8630 }
8631next_sibling:
8632 if (cur == (xmlNodePtr) attr)
8633 break;
8634 if (cur->next != NULL)
8635 cur = cur->next;
8636 else {
8637 cur = cur->parent;
8638 goto next_sibling;
8639 }
8640 }
8641 return (0);
8642internal_error:
8643 return (-1);
8644}
8645
8646/*
8647* xmlDOMWrapAdoptNode:
8648* @ctxt: the optional context for custom processing
8649* @sourceDoc: the optional sourceDoc
8650* @node: the node to start with
8651* @destDoc: the destination doc
Kasimier T. Buchcik4d9c9482005-06-27 15:04:46 +00008652* @destParent: the optional new parent of @node in @destDoc
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008653* @options: option flags
8654*
8655* Ensures that ns-references point to @destDoc: either to
8656* elements->nsDef entries if @destParent is given, or to
8657* @destDoc->oldNs otherwise.
8658* If @destParent is given, it ensures that the tree is namespace
8659* wellformed by creating additional ns-decls where needed.
8660* Note that, since prefixes of already existent ns-decls can be
8661* shadowed by this process, it could break QNames in attribute
8662* values or element content.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00008663* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008664*
8665* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8666*/
8667int
8668xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt,
8669 xmlDocPtr sourceDoc,
8670 xmlNodePtr node,
8671 xmlDocPtr destDoc,
8672 xmlNodePtr destParent,
8673 int options)
8674{
8675 if ((node == NULL) || (destDoc == NULL) ||
8676 ((destParent != NULL) && (destParent->doc != destDoc)))
8677 return(-1);
8678 /*
8679 * Check node->doc sanity.
8680 */
8681 if ((node->doc != NULL) && (sourceDoc != NULL) &&
8682 (node->doc != sourceDoc)) {
8683 /*
8684 * Might be an XIncluded node.
8685 */
8686 return (-1);
8687 }
8688 if (sourceDoc == NULL)
8689 sourceDoc = node->doc;
8690 if (sourceDoc == destDoc)
8691 return (-1);
8692 switch (node->type) {
8693 case XML_ELEMENT_NODE:
8694 case XML_ATTRIBUTE_NODE:
8695 case XML_TEXT_NODE:
8696 case XML_CDATA_SECTION_NODE:
8697 case XML_ENTITY_REF_NODE:
8698 case XML_PI_NODE:
8699 case XML_COMMENT_NODE:
8700 break;
8701 case XML_DOCUMENT_FRAG_NODE:
8702 return (2);
8703 default:
8704 return (1);
8705 }
8706 /*
8707 * Unlink only if @node was not already added to @destParent.
8708 */
8709 if ((node->parent != NULL) && (destParent != node->parent))
8710 xmlUnlinkNode(node);
8711
8712 if (node->type == XML_ELEMENT_NODE) {
8713 return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node,
8714 destDoc, destParent, options));
8715 } else if (node->type == XML_ATTRIBUTE_NODE) {
8716 return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc,
8717 (xmlAttrPtr) node, destDoc, destParent, options));
8718 } else {
8719 xmlNodePtr cur = node;
8720 int adoptStr = 1;
8721
8722 cur->doc = destDoc;
8723 /*
8724 * Optimize string adoption.
8725 */
8726 if ((sourceDoc != NULL) &&
8727 (sourceDoc->dict == destDoc->dict))
8728 adoptStr = 0;
8729 switch (node->type) {
8730 case XML_TEXT_NODE:
8731 case XML_CDATA_SECTION_NODE:
8732 XML_TREE_ADOPT_STR_2(node->content)
8733 break;
8734 case XML_ENTITY_REF_NODE:
8735 /*
8736 * Remove reference to the entitity-node.
8737 */
8738 node->content = NULL;
8739 node->children = NULL;
8740 node->last = NULL;
8741 if ((destDoc->intSubset) || (destDoc->extSubset)) {
8742 xmlEntityPtr ent;
8743 /*
8744 * Assign new entity-node if available.
8745 */
8746 ent = xmlGetDocEntity(destDoc, node->name);
8747 if (ent != NULL) {
8748 node->content = ent->content;
8749 node->children = (xmlNodePtr) ent;
8750 node->last = (xmlNodePtr) ent;
8751 }
8752 }
8753 XML_TREE_ADOPT_STR(node->name)
8754 break;
Daniel Veillard7e21fd12005-07-03 21:44:07 +00008755 case XML_PI_NODE: {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008756 XML_TREE_ADOPT_STR(node->name)
8757 XML_TREE_ADOPT_STR_2(node->content)
8758 break;
Daniel Veillard7e21fd12005-07-03 21:44:07 +00008759 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008760 default:
8761 break;
8762 }
8763 }
8764 return (0);
8765}
8766
8767
Daniel Veillard5d4644e2005-04-01 13:11:58 +00008768#define bottom_tree
8769#include "elfgcchack.h"