blob: aba96a159db0f474255404f81fdf1d0380966bec [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)
Rob Richardsc342ec62005-10-25 00:10:12 +00002858 attr = xmlHasNsProp(cur->parent, elem->name, NULL);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002859 else
2860 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
Rob Richardsc342ec62005-10-25 00:10:12 +00002861 /* elem has already been unlinked so can never be attr */
2862 if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002863 /* different instance, destroy it (attributes must be unique) */
2864 xmlFreeProp(attr);
2865 }
Owen Taylor3473f882001-02-23 17:55:21 +00002866 }
2867
2868 if (elem->doc != cur->doc) {
2869 xmlSetTreeDoc(elem, cur->doc);
2870 }
2871 elem->parent = cur->parent;
2872 elem->prev = cur;
2873 elem->next = cur->next;
2874 cur->next = elem;
2875 if (elem->next != NULL)
2876 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002877 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002878 elem->parent->last = elem;
2879 return(elem);
2880}
2881
William M. Brack21e4ef22005-01-02 09:53:13 +00002882#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
2883 defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002884/**
2885 * xmlAddPrevSibling:
2886 * @cur: the child node
2887 * @elem: the new node
2888 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002889 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002890 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002891 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002892 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002893 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2894 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002895 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002896 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002897 */
2898xmlNodePtr
2899xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2900 if (cur == NULL) {
2901#ifdef DEBUG_TREE
2902 xmlGenericError(xmlGenericErrorContext,
2903 "xmlAddPrevSibling : cur == NULL\n");
2904#endif
2905 return(NULL);
2906 }
2907 if (elem == NULL) {
2908#ifdef DEBUG_TREE
2909 xmlGenericError(xmlGenericErrorContext,
2910 "xmlAddPrevSibling : elem == NULL\n");
2911#endif
2912 return(NULL);
2913 }
2914
2915 xmlUnlinkNode(elem);
2916
2917 if (elem->type == XML_TEXT_NODE) {
2918 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002919 xmlChar *tmp;
2920
2921 tmp = xmlStrdup(elem->content);
2922 tmp = xmlStrcat(tmp, cur->content);
2923 xmlNodeSetContent(cur, tmp);
2924 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002925 xmlFreeNode(elem);
2926 return(cur);
2927 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002928 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2929 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002930 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002931 xmlFreeNode(elem);
2932 return(cur->prev);
2933 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002934 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2935 /* check if an attribute with the same name exists */
2936 xmlAttrPtr attr;
2937
2938 if (elem->ns == NULL)
Rob Richardsc342ec62005-10-25 00:10:12 +00002939 attr = xmlHasNsProp(cur->parent, elem->name, NULL);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002940 else
2941 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
Rob Richardsc342ec62005-10-25 00:10:12 +00002942 /* elem has already been unlinked so can never be attr */
2943 if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002944 /* different instance, destroy it (attributes must be unique) */
2945 xmlFreeProp(attr);
2946 }
Owen Taylor3473f882001-02-23 17:55:21 +00002947 }
2948
2949 if (elem->doc != cur->doc) {
2950 xmlSetTreeDoc(elem, cur->doc);
2951 }
2952 elem->parent = cur->parent;
2953 elem->next = cur;
2954 elem->prev = cur->prev;
2955 cur->prev = elem;
2956 if (elem->prev != NULL)
2957 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002958 if (elem->parent != NULL) {
2959 if (elem->type == XML_ATTRIBUTE_NODE) {
2960 if (elem->parent->properties == (xmlAttrPtr) cur) {
2961 elem->parent->properties = (xmlAttrPtr) elem;
2962 }
2963 } else {
2964 if (elem->parent->children == cur) {
2965 elem->parent->children = elem;
2966 }
2967 }
2968 }
Owen Taylor3473f882001-02-23 17:55:21 +00002969 return(elem);
2970}
Daniel Veillard652327a2003-09-29 18:02:38 +00002971#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002972
2973/**
2974 * xmlAddSibling:
2975 * @cur: the child node
2976 * @elem: the new node
2977 *
2978 * Add a new element @elem to the list of siblings of @cur
2979 * merging adjacent TEXT nodes (@elem may be freed)
2980 * If the new element was already inserted in a document it is
2981 * first unlinked from its existing context.
2982 *
2983 * Returns the new element or NULL in case of error.
2984 */
2985xmlNodePtr
2986xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2987 xmlNodePtr parent;
2988
2989 if (cur == NULL) {
2990#ifdef DEBUG_TREE
2991 xmlGenericError(xmlGenericErrorContext,
2992 "xmlAddSibling : cur == NULL\n");
2993#endif
2994 return(NULL);
2995 }
2996
2997 if (elem == NULL) {
2998#ifdef DEBUG_TREE
2999 xmlGenericError(xmlGenericErrorContext,
3000 "xmlAddSibling : elem == NULL\n");
3001#endif
3002 return(NULL);
3003 }
3004
3005 /*
3006 * Constant time is we can rely on the ->parent->last to find
3007 * the last sibling.
3008 */
3009 if ((cur->parent != NULL) &&
3010 (cur->parent->children != NULL) &&
3011 (cur->parent->last != NULL) &&
3012 (cur->parent->last->next == NULL)) {
3013 cur = cur->parent->last;
3014 } else {
3015 while (cur->next != NULL) cur = cur->next;
3016 }
3017
3018 xmlUnlinkNode(elem);
3019
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003020 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3021 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003022 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003023 xmlFreeNode(elem);
3024 return(cur);
3025 }
3026
3027 if (elem->doc != cur->doc) {
3028 xmlSetTreeDoc(elem, cur->doc);
3029 }
3030 parent = cur->parent;
3031 elem->prev = cur;
3032 elem->next = NULL;
3033 elem->parent = parent;
3034 cur->next = elem;
3035 if (parent != NULL)
3036 parent->last = elem;
3037
3038 return(elem);
3039}
3040
3041/**
3042 * xmlAddChildList:
3043 * @parent: the parent node
3044 * @cur: the first node in the list
3045 *
3046 * Add a list of node at the end of the child list of the parent
3047 * merging adjacent TEXT nodes (@cur may be freed)
3048 *
3049 * Returns the last child or NULL in case of error.
3050 */
3051xmlNodePtr
3052xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3053 xmlNodePtr prev;
3054
3055 if (parent == NULL) {
3056#ifdef DEBUG_TREE
3057 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003058 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003059#endif
3060 return(NULL);
3061 }
3062
3063 if (cur == NULL) {
3064#ifdef DEBUG_TREE
3065 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003066 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003067#endif
3068 return(NULL);
3069 }
3070
3071 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3072 (cur->doc != parent->doc)) {
3073#ifdef DEBUG_TREE
3074 xmlGenericError(xmlGenericErrorContext,
3075 "Elements moved to a different document\n");
3076#endif
3077 }
3078
3079 /*
3080 * add the first element at the end of the children list.
3081 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003082
Owen Taylor3473f882001-02-23 17:55:21 +00003083 if (parent->children == NULL) {
3084 parent->children = cur;
3085 } else {
3086 /*
3087 * If cur and parent->last both are TEXT nodes, then merge them.
3088 */
3089 if ((cur->type == XML_TEXT_NODE) &&
3090 (parent->last->type == XML_TEXT_NODE) &&
3091 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003092 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003093 /*
3094 * if it's the only child, nothing more to be done.
3095 */
3096 if (cur->next == NULL) {
3097 xmlFreeNode(cur);
3098 return(parent->last);
3099 }
3100 prev = cur;
3101 cur = cur->next;
3102 xmlFreeNode(prev);
3103 }
3104 prev = parent->last;
3105 prev->next = cur;
3106 cur->prev = prev;
3107 }
3108 while (cur->next != NULL) {
3109 cur->parent = parent;
3110 if (cur->doc != parent->doc) {
3111 xmlSetTreeDoc(cur, parent->doc);
3112 }
3113 cur = cur->next;
3114 }
3115 cur->parent = parent;
3116 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3117 parent->last = cur;
3118
3119 return(cur);
3120}
3121
3122/**
3123 * xmlAddChild:
3124 * @parent: the parent node
3125 * @cur: the child node
3126 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003127 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003128 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003129 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3130 * If there is an attribute with equal name, it is first destroyed.
3131 *
Owen Taylor3473f882001-02-23 17:55:21 +00003132 * Returns the child or NULL in case of error.
3133 */
3134xmlNodePtr
3135xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3136 xmlNodePtr prev;
3137
3138 if (parent == NULL) {
3139#ifdef DEBUG_TREE
3140 xmlGenericError(xmlGenericErrorContext,
3141 "xmlAddChild : parent == NULL\n");
3142#endif
3143 return(NULL);
3144 }
3145
3146 if (cur == NULL) {
3147#ifdef DEBUG_TREE
3148 xmlGenericError(xmlGenericErrorContext,
3149 "xmlAddChild : child == NULL\n");
3150#endif
3151 return(NULL);
3152 }
3153
Owen Taylor3473f882001-02-23 17:55:21 +00003154 /*
3155 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003156 * cur is then freed.
3157 */
3158 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003159 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003160 (parent->content != NULL) &&
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003161 (parent->name == cur->name) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003162 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003163 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003164 xmlFreeNode(cur);
3165 return(parent);
3166 }
3167 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003168 (parent->last->name == cur->name) &&
3169 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003170 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003171 xmlFreeNode(cur);
3172 return(parent->last);
3173 }
3174 }
3175
3176 /*
3177 * add the new element at the end of the children list.
3178 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003179 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003180 cur->parent = parent;
3181 if (cur->doc != parent->doc) {
3182 xmlSetTreeDoc(cur, parent->doc);
3183 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003184 /* this check prevents a loop on tree-traversions if a developer
3185 * tries to add a node to its parent multiple times
3186 */
3187 if (prev == parent)
3188 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003189
3190 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003191 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003192 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003193 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003194 (parent->content != NULL) &&
3195 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003196 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003197 xmlFreeNode(cur);
3198 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003199 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003200 if (cur->type == XML_ATTRIBUTE_NODE) {
3201 if (parent->properties == NULL) {
3202 parent->properties = (xmlAttrPtr) cur;
3203 } else {
3204 /* check if an attribute with the same name exists */
3205 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003206
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003207 if (cur->ns == NULL)
Rob Richardsc342ec62005-10-25 00:10:12 +00003208 lastattr = xmlHasNsProp(parent, cur->name, NULL);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003209 else
3210 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
Rob Richardsc342ec62005-10-25 00:10:12 +00003211 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur) && (lastattr->type != XML_ATTRIBUTE_DECL)) {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003212 /* different instance, destroy it (attributes must be unique) */
3213 xmlFreeProp(lastattr);
3214 }
3215 /* find the end */
3216 lastattr = parent->properties;
3217 while (lastattr->next != NULL) {
3218 lastattr = lastattr->next;
3219 }
3220 lastattr->next = (xmlAttrPtr) cur;
3221 ((xmlAttrPtr) cur)->prev = lastattr;
3222 }
3223 } else {
3224 if (parent->children == NULL) {
3225 parent->children = cur;
3226 parent->last = cur;
3227 } else {
3228 prev = parent->last;
3229 prev->next = cur;
3230 cur->prev = prev;
3231 parent->last = cur;
3232 }
3233 }
Owen Taylor3473f882001-02-23 17:55:21 +00003234 return(cur);
3235}
3236
3237/**
3238 * xmlGetLastChild:
3239 * @parent: the parent node
3240 *
3241 * Search the last child of a node.
3242 * Returns the last child or NULL if none.
3243 */
3244xmlNodePtr
3245xmlGetLastChild(xmlNodePtr parent) {
3246 if (parent == NULL) {
3247#ifdef DEBUG_TREE
3248 xmlGenericError(xmlGenericErrorContext,
3249 "xmlGetLastChild : parent == NULL\n");
3250#endif
3251 return(NULL);
3252 }
3253 return(parent->last);
3254}
3255
3256/**
3257 * xmlFreeNodeList:
3258 * @cur: the first node in the list
3259 *
3260 * Free a node and all its siblings, this is a recursive behaviour, all
3261 * the children are freed too.
3262 */
3263void
3264xmlFreeNodeList(xmlNodePtr cur) {
3265 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003266 xmlDictPtr dict = NULL;
3267
3268 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003269 if (cur->type == XML_NAMESPACE_DECL) {
3270 xmlFreeNsList((xmlNsPtr) cur);
3271 return;
3272 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003273 if ((cur->type == XML_DOCUMENT_NODE) ||
3274#ifdef LIBXML_DOCB_ENABLED
3275 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003276#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003277 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003278 xmlFreeDoc((xmlDocPtr) cur);
3279 return;
3280 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003281 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003282 while (cur != NULL) {
3283 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003284 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003285
Daniel Veillarda880b122003-04-21 21:36:41 +00003286 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003287 xmlDeregisterNodeDefaultValue(cur);
3288
Daniel Veillard02141ea2001-04-30 11:46:40 +00003289 if ((cur->children != NULL) &&
3290 (cur->type != XML_ENTITY_REF_NODE))
3291 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003292 if (((cur->type == XML_ELEMENT_NODE) ||
3293 (cur->type == XML_XINCLUDE_START) ||
3294 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003295 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003296 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003297 if ((cur->type != XML_ELEMENT_NODE) &&
3298 (cur->type != XML_XINCLUDE_START) &&
3299 (cur->type != XML_XINCLUDE_END) &&
Daniel Veillard8874b942005-08-25 13:19:21 +00003300 (cur->type != XML_ENTITY_REF_NODE) &&
3301 (cur->content != (xmlChar *) &(cur->properties))) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003302 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003303 }
3304 if (((cur->type == XML_ELEMENT_NODE) ||
3305 (cur->type == XML_XINCLUDE_START) ||
3306 (cur->type == XML_XINCLUDE_END)) &&
3307 (cur->nsDef != NULL))
3308 xmlFreeNsList(cur->nsDef);
3309
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003310 /*
3311 * When a node is a text node or a comment, it uses a global static
3312 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003313 * Otherwise the node name might come from the document's
3314 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003315 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003316 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003317 (cur->type != XML_TEXT_NODE) &&
3318 (cur->type != XML_COMMENT_NODE))
3319 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003320 xmlFree(cur);
3321 }
Owen Taylor3473f882001-02-23 17:55:21 +00003322 cur = next;
3323 }
3324}
3325
3326/**
3327 * xmlFreeNode:
3328 * @cur: the node
3329 *
3330 * Free a node, this is a recursive behaviour, all the children are freed too.
3331 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3332 */
3333void
3334xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003335 xmlDictPtr dict = NULL;
3336
3337 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003338
Daniel Veillard02141ea2001-04-30 11:46:40 +00003339 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003340 if (cur->type == XML_DTD_NODE) {
3341 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003342 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003343 }
3344 if (cur->type == XML_NAMESPACE_DECL) {
3345 xmlFreeNs((xmlNsPtr) cur);
3346 return;
3347 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003348 if (cur->type == XML_ATTRIBUTE_NODE) {
3349 xmlFreeProp((xmlAttrPtr) cur);
3350 return;
3351 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003352
Daniel Veillarda880b122003-04-21 21:36:41 +00003353 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003354 xmlDeregisterNodeDefaultValue(cur);
3355
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003356 if (cur->doc != NULL) dict = cur->doc->dict;
3357
Owen Taylor3473f882001-02-23 17:55:21 +00003358 if ((cur->children != NULL) &&
3359 (cur->type != XML_ENTITY_REF_NODE))
3360 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003361 if (((cur->type == XML_ELEMENT_NODE) ||
3362 (cur->type == XML_XINCLUDE_START) ||
3363 (cur->type == XML_XINCLUDE_END)) &&
3364 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003365 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003366 if ((cur->type != XML_ELEMENT_NODE) &&
3367 (cur->content != NULL) &&
3368 (cur->type != XML_ENTITY_REF_NODE) &&
3369 (cur->type != XML_XINCLUDE_END) &&
Daniel Veillard8874b942005-08-25 13:19:21 +00003370 (cur->type != XML_XINCLUDE_START) &&
3371 (cur->content != (xmlChar *) &(cur->properties))) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003372 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003373 }
3374
Daniel Veillardacd370f2001-06-09 17:17:51 +00003375 /*
3376 * When a node is a text node or a comment, it uses a global static
3377 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003378 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003379 */
Owen Taylor3473f882001-02-23 17:55:21 +00003380 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003381 (cur->type != XML_TEXT_NODE) &&
3382 (cur->type != XML_COMMENT_NODE))
3383 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003384
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003385 if (((cur->type == XML_ELEMENT_NODE) ||
3386 (cur->type == XML_XINCLUDE_START) ||
3387 (cur->type == XML_XINCLUDE_END)) &&
3388 (cur->nsDef != NULL))
3389 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003390 xmlFree(cur);
3391}
3392
3393/**
3394 * xmlUnlinkNode:
3395 * @cur: the node
3396 *
3397 * Unlink a node from it's current context, the node is not freed
3398 */
3399void
3400xmlUnlinkNode(xmlNodePtr cur) {
3401 if (cur == NULL) {
3402#ifdef DEBUG_TREE
3403 xmlGenericError(xmlGenericErrorContext,
3404 "xmlUnlinkNode : node == NULL\n");
3405#endif
3406 return;
3407 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003408 if (cur->type == XML_DTD_NODE) {
3409 xmlDocPtr doc;
3410 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003411 if (doc != NULL) {
3412 if (doc->intSubset == (xmlDtdPtr) cur)
3413 doc->intSubset = NULL;
3414 if (doc->extSubset == (xmlDtdPtr) cur)
3415 doc->extSubset = NULL;
3416 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003417 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003418 if (cur->parent != NULL) {
3419 xmlNodePtr parent;
3420 parent = cur->parent;
3421 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardda6f4af2005-06-20 17:17:54 +00003422 /* If attribute is an ID from subset then remove it */
3423 if ((((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID) &&
3424 xmlIsID(parent->doc, parent, (xmlAttrPtr) cur)) {
3425 xmlRemoveID(cur->doc, (xmlAttrPtr) cur);
3426 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003427 if (parent->properties == (xmlAttrPtr) cur)
3428 parent->properties = ((xmlAttrPtr) cur)->next;
3429 } else {
3430 if (parent->children == cur)
3431 parent->children = cur->next;
3432 if (parent->last == cur)
3433 parent->last = cur->prev;
3434 }
3435 cur->parent = NULL;
3436 }
Owen Taylor3473f882001-02-23 17:55:21 +00003437 if (cur->next != NULL)
3438 cur->next->prev = cur->prev;
3439 if (cur->prev != NULL)
3440 cur->prev->next = cur->next;
3441 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003442}
3443
Daniel Veillard2156d432004-03-04 15:59:36 +00003444#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003445/**
3446 * xmlReplaceNode:
3447 * @old: the old node
3448 * @cur: the node
3449 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003450 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003451 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003452 * first unlinked from its existing context.
3453 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003454 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003455 */
3456xmlNodePtr
3457xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00003458 if (old == cur) return(NULL);
Daniel Veillarda03e3652004-11-02 18:45:30 +00003459 if ((old == NULL) || (old->parent == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003460#ifdef DEBUG_TREE
3461 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda03e3652004-11-02 18:45:30 +00003462 "xmlReplaceNode : old == NULL or without parent\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003463#endif
3464 return(NULL);
3465 }
3466 if (cur == NULL) {
3467 xmlUnlinkNode(old);
3468 return(old);
3469 }
3470 if (cur == old) {
3471 return(old);
3472 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003473 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3474#ifdef DEBUG_TREE
3475 xmlGenericError(xmlGenericErrorContext,
3476 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3477#endif
3478 return(old);
3479 }
3480 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3481#ifdef DEBUG_TREE
3482 xmlGenericError(xmlGenericErrorContext,
3483 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3484#endif
3485 return(old);
3486 }
Owen Taylor3473f882001-02-23 17:55:21 +00003487 xmlUnlinkNode(cur);
Daniel Veillard64d7d122005-05-11 18:03:42 +00003488 xmlSetTreeDoc(cur, old->doc);
Owen Taylor3473f882001-02-23 17:55:21 +00003489 cur->parent = old->parent;
3490 cur->next = old->next;
3491 if (cur->next != NULL)
3492 cur->next->prev = cur;
3493 cur->prev = old->prev;
3494 if (cur->prev != NULL)
3495 cur->prev->next = cur;
3496 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003497 if (cur->type == XML_ATTRIBUTE_NODE) {
3498 if (cur->parent->properties == (xmlAttrPtr)old)
3499 cur->parent->properties = ((xmlAttrPtr) cur);
Daniel Veillardda6f4af2005-06-20 17:17:54 +00003500
3501 /* If old attribute is ID and defined in DTD then remove ID */
3502 if ((((xmlAttrPtr) old)->atype == XML_ATTRIBUTE_ID) &&
3503 xmlIsID(old->doc, old->parent, (xmlAttrPtr) old)) {
3504 xmlRemoveID(old->doc, (xmlAttrPtr) old);
3505 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003506 } else {
3507 if (cur->parent->children == old)
3508 cur->parent->children = cur;
3509 if (cur->parent->last == old)
3510 cur->parent->last = cur;
3511 }
Owen Taylor3473f882001-02-23 17:55:21 +00003512 }
3513 old->next = old->prev = NULL;
3514 old->parent = NULL;
3515 return(old);
3516}
Daniel Veillard652327a2003-09-29 18:02:38 +00003517#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003518
3519/************************************************************************
3520 * *
3521 * Copy operations *
3522 * *
3523 ************************************************************************/
3524
3525/**
3526 * xmlCopyNamespace:
3527 * @cur: the namespace
3528 *
3529 * Do a copy of the namespace.
3530 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003531 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003532 */
3533xmlNsPtr
3534xmlCopyNamespace(xmlNsPtr cur) {
3535 xmlNsPtr ret;
3536
3537 if (cur == NULL) return(NULL);
3538 switch (cur->type) {
3539 case XML_LOCAL_NAMESPACE:
3540 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3541 break;
3542 default:
3543#ifdef DEBUG_TREE
3544 xmlGenericError(xmlGenericErrorContext,
3545 "xmlCopyNamespace: invalid type %d\n", cur->type);
3546#endif
3547 return(NULL);
3548 }
3549 return(ret);
3550}
3551
3552/**
3553 * xmlCopyNamespaceList:
3554 * @cur: the first namespace
3555 *
3556 * Do a copy of an namespace list.
3557 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003558 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003559 */
3560xmlNsPtr
3561xmlCopyNamespaceList(xmlNsPtr cur) {
3562 xmlNsPtr ret = NULL;
3563 xmlNsPtr p = NULL,q;
3564
3565 while (cur != NULL) {
3566 q = xmlCopyNamespace(cur);
3567 if (p == NULL) {
3568 ret = p = q;
3569 } else {
3570 p->next = q;
3571 p = q;
3572 }
3573 cur = cur->next;
3574 }
3575 return(ret);
3576}
3577
3578static xmlNodePtr
3579xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3580/**
3581 * xmlCopyProp:
3582 * @target: the element where the attribute will be grafted
3583 * @cur: the attribute
3584 *
3585 * Do a copy of the attribute.
3586 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003587 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003588 */
3589xmlAttrPtr
3590xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3591 xmlAttrPtr ret;
3592
3593 if (cur == NULL) return(NULL);
3594 if (target != NULL)
3595 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3596 else if (cur->parent != NULL)
3597 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3598 else if (cur->children != NULL)
3599 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3600 else
3601 ret = xmlNewDocProp(NULL, cur->name, NULL);
3602 if (ret == NULL) return(NULL);
3603 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003604
Owen Taylor3473f882001-02-23 17:55:21 +00003605 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003606 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003607
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003608 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3609 if (ns == NULL) {
3610 /*
3611 * Humm, we are copying an element whose namespace is defined
3612 * out of the new tree scope. Search it in the original tree
3613 * and add it at the top of the new tree
3614 */
3615 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3616 if (ns != NULL) {
3617 xmlNodePtr root = target;
3618 xmlNodePtr pred = NULL;
3619
3620 while (root->parent != NULL) {
3621 pred = root;
3622 root = root->parent;
3623 }
3624 if (root == (xmlNodePtr) target->doc) {
3625 /* correct possibly cycling above the document elt */
3626 root = pred;
3627 }
3628 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3629 }
3630 } else {
3631 /*
3632 * we have to find something appropriate here since
3633 * we cant be sure, that the namespce we found is identified
3634 * by the prefix
3635 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003636 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003637 /* this is the nice case */
3638 ret->ns = ns;
3639 } else {
3640 /*
3641 * we are in trouble: we need a new reconcilied namespace.
3642 * This is expensive
3643 */
3644 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3645 }
3646 }
3647
Owen Taylor3473f882001-02-23 17:55:21 +00003648 } else
3649 ret->ns = NULL;
3650
3651 if (cur->children != NULL) {
3652 xmlNodePtr tmp;
3653
3654 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3655 ret->last = NULL;
3656 tmp = ret->children;
3657 while (tmp != NULL) {
3658 /* tmp->parent = (xmlNodePtr)ret; */
3659 if (tmp->next == NULL)
3660 ret->last = tmp;
3661 tmp = tmp->next;
3662 }
3663 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003664 /*
3665 * Try to handle IDs
3666 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003667 if ((target!= NULL) && (cur!= NULL) &&
3668 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003669 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3670 if (xmlIsID(cur->doc, cur->parent, cur)) {
3671 xmlChar *id;
3672
3673 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3674 if (id != NULL) {
3675 xmlAddID(NULL, target->doc, id, ret);
3676 xmlFree(id);
3677 }
3678 }
3679 }
Owen Taylor3473f882001-02-23 17:55:21 +00003680 return(ret);
3681}
3682
3683/**
3684 * xmlCopyPropList:
3685 * @target: the element where the attributes will be grafted
3686 * @cur: the first attribute
3687 *
3688 * Do a copy of an attribute list.
3689 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003690 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003691 */
3692xmlAttrPtr
3693xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3694 xmlAttrPtr ret = NULL;
3695 xmlAttrPtr p = NULL,q;
3696
3697 while (cur != NULL) {
3698 q = xmlCopyProp(target, cur);
William M. Brack13dfa872004-09-18 04:52:08 +00003699 if (q == NULL)
3700 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003701 if (p == NULL) {
3702 ret = p = q;
3703 } else {
3704 p->next = q;
3705 q->prev = p;
3706 p = q;
3707 }
3708 cur = cur->next;
3709 }
3710 return(ret);
3711}
3712
3713/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003714 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003715 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003716 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003717 * tricky reason: namespaces. Doing a direct copy of a node
3718 * say RPM:Copyright without changing the namespace pointer to
3719 * something else can produce stale links. One way to do it is
3720 * to keep a reference counter but this doesn't work as soon
3721 * as one move the element or the subtree out of the scope of
3722 * the existing namespace. The actual solution seems to add
3723 * a copy of the namespace at the top of the copied tree if
3724 * not available in the subtree.
3725 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00003726 * The argument "recursive" normally indicates a recursive copy
3727 * of the node with values 0 (no) and 1 (yes). For XInclude,
3728 * however, we allow a value of 2 to indicate copy properties and
3729 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00003730 */
3731
3732static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003733xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00003734 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003735 xmlNodePtr ret;
3736
3737 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003738 switch (node->type) {
3739 case XML_TEXT_NODE:
3740 case XML_CDATA_SECTION_NODE:
3741 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003742 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003743 case XML_ENTITY_REF_NODE:
3744 case XML_ENTITY_NODE:
3745 case XML_PI_NODE:
3746 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003747 case XML_XINCLUDE_START:
3748 case XML_XINCLUDE_END:
3749 break;
3750 case XML_ATTRIBUTE_NODE:
3751 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3752 case XML_NAMESPACE_DECL:
3753 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3754
Daniel Veillard39196eb2001-06-19 18:09:42 +00003755 case XML_DOCUMENT_NODE:
3756 case XML_HTML_DOCUMENT_NODE:
3757#ifdef LIBXML_DOCB_ENABLED
3758 case XML_DOCB_DOCUMENT_NODE:
3759#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003760#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00003761 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00003762#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003763 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003764 case XML_NOTATION_NODE:
3765 case XML_DTD_NODE:
3766 case XML_ELEMENT_DECL:
3767 case XML_ATTRIBUTE_DECL:
3768 case XML_ENTITY_DECL:
3769 return(NULL);
3770 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003771
Owen Taylor3473f882001-02-23 17:55:21 +00003772 /*
3773 * Allocate a new node and fill the fields.
3774 */
3775 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3776 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003777 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003778 return(NULL);
3779 }
3780 memset(ret, 0, sizeof(xmlNode));
3781 ret->type = node->type;
3782
3783 ret->doc = doc;
3784 ret->parent = parent;
3785 if (node->name == xmlStringText)
3786 ret->name = xmlStringText;
3787 else if (node->name == xmlStringTextNoenc)
3788 ret->name = xmlStringTextNoenc;
3789 else if (node->name == xmlStringComment)
3790 ret->name = xmlStringComment;
Daniel Veillard03a53c32004-10-26 16:06:51 +00003791 else if (node->name != NULL) {
3792 if ((doc != NULL) && (doc->dict != NULL))
3793 ret->name = xmlDictLookup(doc->dict, node->name, -1);
3794 else
3795 ret->name = xmlStrdup(node->name);
3796 }
Daniel Veillard7db37732001-07-12 01:20:08 +00003797 if ((node->type != XML_ELEMENT_NODE) &&
3798 (node->content != NULL) &&
3799 (node->type != XML_ENTITY_REF_NODE) &&
3800 (node->type != XML_XINCLUDE_END) &&
3801 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003802 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003803 }else{
3804 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003805 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003806 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003807 if (parent != NULL) {
3808 xmlNodePtr tmp;
3809
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003810 /*
3811 * this is a tricky part for the node register thing:
3812 * in case ret does get coalesced in xmlAddChild
3813 * the deregister-node callback is called; so we register ret now already
3814 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003815 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003816 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3817
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003818 tmp = xmlAddChild(parent, ret);
3819 /* node could have coalesced */
3820 if (tmp != ret)
3821 return(tmp);
3822 }
Owen Taylor3473f882001-02-23 17:55:21 +00003823
William M. Brack57e9e912004-03-09 16:19:02 +00003824 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003825 goto out;
Daniel Veillard8874b942005-08-25 13:19:21 +00003826 if ((node->type == XML_ELEMENT_NODE) && (node->nsDef != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00003827 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3828
3829 if (node->ns != NULL) {
3830 xmlNsPtr ns;
3831
3832 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3833 if (ns == NULL) {
3834 /*
3835 * Humm, we are copying an element whose namespace is defined
3836 * out of the new tree scope. Search it in the original tree
3837 * and add it at the top of the new tree
3838 */
3839 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3840 if (ns != NULL) {
3841 xmlNodePtr root = ret;
3842
3843 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003844 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003845 }
3846 } else {
3847 /*
3848 * reference the existing namespace definition in our own tree.
3849 */
3850 ret->ns = ns;
3851 }
3852 }
Daniel Veillard8874b942005-08-25 13:19:21 +00003853 if ((node->type == XML_ELEMENT_NODE) && (node->properties != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00003854 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003855 if (node->type == XML_ENTITY_REF_NODE) {
3856 if ((doc == NULL) || (node->doc != doc)) {
3857 /*
3858 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003859 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003860 * we cannot keep the reference. Try to find it in the
3861 * target document.
3862 */
3863 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3864 } else {
3865 ret->children = node->children;
3866 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003867 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00003868 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003869 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003870 UPDATE_LAST_CHILD_AND_PARENT(ret)
3871 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003872
3873out:
3874 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00003875 if ((parent == NULL) &&
3876 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003877 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003878 return(ret);
3879}
3880
3881static xmlNodePtr
3882xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3883 xmlNodePtr ret = NULL;
3884 xmlNodePtr p = NULL,q;
3885
3886 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003887#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003888 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003889 if (doc == NULL) {
3890 node = node->next;
3891 continue;
3892 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003893 if (doc->intSubset == NULL) {
3894 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3895 q->doc = doc;
3896 q->parent = parent;
3897 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003898 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003899 } else {
3900 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003901 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003902 }
3903 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003904#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003905 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003906 if (ret == NULL) {
3907 q->prev = NULL;
3908 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003909 } else if (p != q) {
3910 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003911 p->next = q;
3912 q->prev = p;
3913 p = q;
3914 }
3915 node = node->next;
3916 }
3917 return(ret);
3918}
3919
3920/**
3921 * xmlCopyNode:
3922 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00003923 * @extended: if 1 do a recursive copy (properties, namespaces and children
3924 * when applicable)
3925 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00003926 *
3927 * Do a copy of the node.
3928 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003929 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003930 */
3931xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003932xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003933 xmlNodePtr ret;
3934
William M. Brack57e9e912004-03-09 16:19:02 +00003935 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00003936 return(ret);
3937}
3938
3939/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003940 * xmlDocCopyNode:
3941 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003942 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00003943 * @extended: if 1 do a recursive copy (properties, namespaces and children
3944 * when applicable)
3945 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00003946 *
3947 * Do a copy of the node to a given document.
3948 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003949 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003950 */
3951xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003952xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003953 xmlNodePtr ret;
3954
William M. Brack57e9e912004-03-09 16:19:02 +00003955 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00003956 return(ret);
3957}
3958
3959/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00003960 * xmlDocCopyNodeList:
3961 * @doc: the target document
3962 * @node: the first node in the list.
3963 *
3964 * Do a recursive copy of the node list.
3965 *
3966 * Returns: a new #xmlNodePtr, or NULL in case of error.
3967 */
3968xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) {
3969 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
3970 return(ret);
3971}
3972
3973/**
Owen Taylor3473f882001-02-23 17:55:21 +00003974 * xmlCopyNodeList:
3975 * @node: the first node in the list.
3976 *
3977 * Do a recursive copy of the node list.
Daniel Veillard03a53c32004-10-26 16:06:51 +00003978 * Use xmlDocCopyNodeList() if possible to ensure string interning.
Owen Taylor3473f882001-02-23 17:55:21 +00003979 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003980 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003981 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003982xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003983 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3984 return(ret);
3985}
3986
Daniel Veillard2156d432004-03-04 15:59:36 +00003987#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003988/**
Owen Taylor3473f882001-02-23 17:55:21 +00003989 * xmlCopyDtd:
3990 * @dtd: the dtd
3991 *
3992 * Do a copy of the dtd.
3993 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003994 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003995 */
3996xmlDtdPtr
3997xmlCopyDtd(xmlDtdPtr dtd) {
3998 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003999 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00004000
4001 if (dtd == NULL) return(NULL);
4002 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4003 if (ret == NULL) return(NULL);
4004 if (dtd->entities != NULL)
4005 ret->entities = (void *) xmlCopyEntitiesTable(
4006 (xmlEntitiesTablePtr) dtd->entities);
4007 if (dtd->notations != NULL)
4008 ret->notations = (void *) xmlCopyNotationTable(
4009 (xmlNotationTablePtr) dtd->notations);
4010 if (dtd->elements != NULL)
4011 ret->elements = (void *) xmlCopyElementTable(
4012 (xmlElementTablePtr) dtd->elements);
4013 if (dtd->attributes != NULL)
4014 ret->attributes = (void *) xmlCopyAttributeTable(
4015 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004016 if (dtd->pentities != NULL)
4017 ret->pentities = (void *) xmlCopyEntitiesTable(
4018 (xmlEntitiesTablePtr) dtd->pentities);
4019
4020 cur = dtd->children;
4021 while (cur != NULL) {
4022 q = NULL;
4023
4024 if (cur->type == XML_ENTITY_DECL) {
4025 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4026 switch (tmp->etype) {
4027 case XML_INTERNAL_GENERAL_ENTITY:
4028 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4029 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4030 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4031 break;
4032 case XML_INTERNAL_PARAMETER_ENTITY:
4033 case XML_EXTERNAL_PARAMETER_ENTITY:
4034 q = (xmlNodePtr)
4035 xmlGetParameterEntityFromDtd(ret, tmp->name);
4036 break;
4037 case XML_INTERNAL_PREDEFINED_ENTITY:
4038 break;
4039 }
4040 } else if (cur->type == XML_ELEMENT_DECL) {
4041 xmlElementPtr tmp = (xmlElementPtr) cur;
4042 q = (xmlNodePtr)
4043 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4044 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4045 xmlAttributePtr tmp = (xmlAttributePtr) cur;
4046 q = (xmlNodePtr)
4047 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4048 } else if (cur->type == XML_COMMENT_NODE) {
4049 q = xmlCopyNode(cur, 0);
4050 }
4051
4052 if (q == NULL) {
4053 cur = cur->next;
4054 continue;
4055 }
4056
4057 if (p == NULL)
4058 ret->children = q;
4059 else
4060 p->next = q;
4061
4062 q->prev = p;
4063 q->parent = (xmlNodePtr) ret;
4064 q->next = NULL;
4065 ret->last = q;
4066 p = q;
4067 cur = cur->next;
4068 }
4069
Owen Taylor3473f882001-02-23 17:55:21 +00004070 return(ret);
4071}
Daniel Veillard2156d432004-03-04 15:59:36 +00004072#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004073
Daniel Veillard2156d432004-03-04 15:59:36 +00004074#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004075/**
4076 * xmlCopyDoc:
4077 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004078 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004079 *
4080 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004081 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004082 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004083 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004084 */
4085xmlDocPtr
4086xmlCopyDoc(xmlDocPtr doc, int recursive) {
4087 xmlDocPtr ret;
4088
4089 if (doc == NULL) return(NULL);
4090 ret = xmlNewDoc(doc->version);
4091 if (ret == NULL) return(NULL);
4092 if (doc->name != NULL)
4093 ret->name = xmlMemStrdup(doc->name);
4094 if (doc->encoding != NULL)
4095 ret->encoding = xmlStrdup(doc->encoding);
Daniel Veillardf59507d2005-01-27 17:26:49 +00004096 if (doc->URL != NULL)
4097 ret->URL = xmlStrdup(doc->URL);
Owen Taylor3473f882001-02-23 17:55:21 +00004098 ret->charset = doc->charset;
4099 ret->compression = doc->compression;
4100 ret->standalone = doc->standalone;
4101 if (!recursive) return(ret);
4102
Daniel Veillardb33c2012001-04-25 12:59:04 +00004103 ret->last = NULL;
4104 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004105#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004106 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004107 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004108 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004109 ret->intSubset->parent = ret;
4110 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004111#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004112 if (doc->oldNs != NULL)
4113 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4114 if (doc->children != NULL) {
4115 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004116
4117 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4118 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004119 ret->last = NULL;
4120 tmp = ret->children;
4121 while (tmp != NULL) {
4122 if (tmp->next == NULL)
4123 ret->last = tmp;
4124 tmp = tmp->next;
4125 }
4126 }
4127 return(ret);
4128}
Daniel Veillard652327a2003-09-29 18:02:38 +00004129#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004130
4131/************************************************************************
4132 * *
4133 * Content access functions *
4134 * *
4135 ************************************************************************/
4136
4137/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004138 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004139 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004140 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004141 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004142 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004143 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004144 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004145 */
4146long
4147xmlGetLineNo(xmlNodePtr node)
4148{
4149 long result = -1;
4150
4151 if (!node)
4152 return result;
Daniel Veillard73da77e2005-08-24 14:05:37 +00004153 if ((node->type == XML_ELEMENT_NODE) ||
4154 (node->type == XML_TEXT_NODE) ||
4155 (node->type == XML_COMMENT_NODE) ||
4156 (node->type == XML_PI_NODE))
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004157 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004158 else if ((node->prev != NULL) &&
4159 ((node->prev->type == XML_ELEMENT_NODE) ||
Daniel Veillard73da77e2005-08-24 14:05:37 +00004160 (node->prev->type == XML_TEXT_NODE) ||
4161 (node->prev->type == XML_COMMENT_NODE) ||
4162 (node->prev->type == XML_PI_NODE)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004163 result = xmlGetLineNo(node->prev);
4164 else if ((node->parent != NULL) &&
Daniel Veillard73da77e2005-08-24 14:05:37 +00004165 (node->parent->type == XML_ELEMENT_NODE))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004166 result = xmlGetLineNo(node->parent);
4167
4168 return result;
4169}
4170
Daniel Veillard2156d432004-03-04 15:59:36 +00004171#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004172/**
4173 * xmlGetNodePath:
4174 * @node: a node
4175 *
4176 * Build a structure based Path for the given node
4177 *
4178 * Returns the new path or NULL in case of error. The caller must free
4179 * the returned string
4180 */
4181xmlChar *
4182xmlGetNodePath(xmlNodePtr node)
4183{
4184 xmlNodePtr cur, tmp, next;
4185 xmlChar *buffer = NULL, *temp;
4186 size_t buf_len;
4187 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004188 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004189 const char *name;
4190 char nametemp[100];
4191 int occur = 0;
4192
4193 if (node == NULL)
4194 return (NULL);
4195
4196 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004197 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004198 if (buffer == NULL) {
4199 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004200 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004201 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004202 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004203 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004204 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004205 xmlFree(buffer);
4206 return (NULL);
4207 }
4208
4209 buffer[0] = 0;
4210 cur = node;
4211 do {
4212 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004213 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004214 occur = 0;
4215 if ((cur->type == XML_DOCUMENT_NODE) ||
4216 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4217 if (buffer[0] == '/')
4218 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004219 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004220 next = NULL;
4221 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004222 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004223 name = (const char *) cur->name;
4224 if (cur->ns) {
William M. Brack84d83e32003-12-23 03:45:17 +00004225 if (cur->ns->prefix != NULL)
William M. Brack13dfa872004-09-18 04:52:08 +00004226 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4227 (char *)cur->ns->prefix, (char *)cur->name);
William M. Brack84d83e32003-12-23 03:45:17 +00004228 else
William M. Brack13dfa872004-09-18 04:52:08 +00004229 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4230 (char *)cur->name);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004231 nametemp[sizeof(nametemp) - 1] = 0;
4232 name = nametemp;
4233 }
4234 next = cur->parent;
4235
4236 /*
4237 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004238 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004239 */
4240 tmp = cur->prev;
4241 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004242 if ((tmp->type == XML_ELEMENT_NODE) &&
Daniel Veillard0996a162005-02-05 14:00:10 +00004243 (xmlStrEqual(cur->name, tmp->name)) &&
4244 ((tmp->ns == cur->ns) ||
4245 ((tmp->ns != NULL) && (cur->ns != NULL) &&
4246 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004247 occur++;
4248 tmp = tmp->prev;
4249 }
4250 if (occur == 0) {
4251 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004252 while (tmp != NULL && occur == 0) {
4253 if ((tmp->type == XML_ELEMENT_NODE) &&
Daniel Veillard0996a162005-02-05 14:00:10 +00004254 (xmlStrEqual(cur->name, tmp->name)) &&
4255 ((tmp->ns == cur->ns) ||
4256 ((tmp->ns != NULL) && (cur->ns != NULL) &&
4257 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004258 occur++;
4259 tmp = tmp->next;
4260 }
4261 if (occur != 0)
4262 occur = 1;
4263 } else
4264 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004265 } else if (cur->type == XML_COMMENT_NODE) {
4266 sep = "/";
4267 name = "comment()";
4268 next = cur->parent;
4269
4270 /*
4271 * Thumbler index computation
4272 */
4273 tmp = cur->prev;
4274 while (tmp != NULL) {
4275 if (tmp->type == XML_COMMENT_NODE)
4276 occur++;
4277 tmp = tmp->prev;
4278 }
4279 if (occur == 0) {
4280 tmp = cur->next;
4281 while (tmp != NULL && occur == 0) {
4282 if (tmp->type == XML_COMMENT_NODE)
4283 occur++;
4284 tmp = tmp->next;
4285 }
4286 if (occur != 0)
4287 occur = 1;
4288 } else
4289 occur++;
4290 } else if ((cur->type == XML_TEXT_NODE) ||
4291 (cur->type == XML_CDATA_SECTION_NODE)) {
4292 sep = "/";
4293 name = "text()";
4294 next = cur->parent;
4295
4296 /*
4297 * Thumbler index computation
4298 */
4299 tmp = cur->prev;
4300 while (tmp != NULL) {
4301 if ((cur->type == XML_TEXT_NODE) ||
4302 (cur->type == XML_CDATA_SECTION_NODE))
4303 occur++;
4304 tmp = tmp->prev;
4305 }
4306 if (occur == 0) {
4307 tmp = cur->next;
4308 while (tmp != NULL && occur == 0) {
Daniel Veillard1f8658a2004-08-14 21:46:31 +00004309 if ((tmp->type == XML_TEXT_NODE) ||
4310 (tmp->type == XML_CDATA_SECTION_NODE))
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004311 occur++;
4312 tmp = tmp->next;
4313 }
4314 if (occur != 0)
4315 occur = 1;
4316 } else
4317 occur++;
4318 } else if (cur->type == XML_PI_NODE) {
4319 sep = "/";
4320 snprintf(nametemp, sizeof(nametemp) - 1,
William M. Brack13dfa872004-09-18 04:52:08 +00004321 "processing-instruction('%s')", (char *)cur->name);
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004322 nametemp[sizeof(nametemp) - 1] = 0;
4323 name = nametemp;
4324
4325 next = cur->parent;
4326
4327 /*
4328 * Thumbler index computation
4329 */
4330 tmp = cur->prev;
4331 while (tmp != NULL) {
4332 if ((tmp->type == XML_PI_NODE) &&
4333 (xmlStrEqual(cur->name, tmp->name)))
4334 occur++;
4335 tmp = tmp->prev;
4336 }
4337 if (occur == 0) {
4338 tmp = cur->next;
4339 while (tmp != NULL && occur == 0) {
4340 if ((tmp->type == XML_PI_NODE) &&
4341 (xmlStrEqual(cur->name, tmp->name)))
4342 occur++;
4343 tmp = tmp->next;
4344 }
4345 if (occur != 0)
4346 occur = 1;
4347 } else
4348 occur++;
4349
Daniel Veillard8faa7832001-11-26 15:58:08 +00004350 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004351 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004352 name = (const char *) (((xmlAttrPtr) cur)->name);
Daniel Veillard365c8062005-07-19 11:31:55 +00004353 if (cur->ns) {
4354 if (cur->ns->prefix != NULL)
4355 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4356 (char *)cur->ns->prefix, (char *)cur->name);
4357 else
4358 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4359 (char *)cur->name);
4360 nametemp[sizeof(nametemp) - 1] = 0;
4361 name = nametemp;
4362 }
Daniel Veillard8faa7832001-11-26 15:58:08 +00004363 next = ((xmlAttrPtr) cur)->parent;
4364 } else {
4365 next = cur->parent;
4366 }
4367
4368 /*
4369 * Make sure there is enough room
4370 */
4371 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4372 buf_len =
4373 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4374 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4375 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004376 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004377 xmlFree(buf);
4378 xmlFree(buffer);
4379 return (NULL);
4380 }
4381 buffer = temp;
4382 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4383 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004384 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004385 xmlFree(buf);
4386 xmlFree(buffer);
4387 return (NULL);
4388 }
4389 buf = temp;
4390 }
4391 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004392 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004393 sep, name, (char *) buffer);
4394 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004395 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004396 sep, name, occur, (char *) buffer);
William M. Brack13dfa872004-09-18 04:52:08 +00004397 snprintf((char *) buffer, buf_len, "%s", (char *)buf);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004398 cur = next;
4399 } while (cur != NULL);
4400 xmlFree(buf);
4401 return (buffer);
4402}
Daniel Veillard652327a2003-09-29 18:02:38 +00004403#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004404
4405/**
Owen Taylor3473f882001-02-23 17:55:21 +00004406 * xmlDocGetRootElement:
4407 * @doc: the document
4408 *
4409 * Get the root element of the document (doc->children is a list
4410 * containing possibly comments, PIs, etc ...).
4411 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004412 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004413 */
4414xmlNodePtr
4415xmlDocGetRootElement(xmlDocPtr doc) {
4416 xmlNodePtr ret;
4417
4418 if (doc == NULL) return(NULL);
4419 ret = doc->children;
4420 while (ret != NULL) {
4421 if (ret->type == XML_ELEMENT_NODE)
4422 return(ret);
4423 ret = ret->next;
4424 }
4425 return(ret);
4426}
4427
Daniel Veillard2156d432004-03-04 15:59:36 +00004428#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004429/**
4430 * xmlDocSetRootElement:
4431 * @doc: the document
4432 * @root: the new document root element
4433 *
4434 * Set the root element of the document (doc->children is a list
4435 * containing possibly comments, PIs, etc ...).
4436 *
4437 * Returns the old root element if any was found
4438 */
4439xmlNodePtr
4440xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4441 xmlNodePtr old = NULL;
4442
4443 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004444 if (root == NULL)
4445 return(NULL);
4446 xmlUnlinkNode(root);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00004447 xmlSetTreeDoc(root, doc);
Daniel Veillardc575b992002-02-08 13:28:40 +00004448 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004449 old = doc->children;
4450 while (old != NULL) {
4451 if (old->type == XML_ELEMENT_NODE)
4452 break;
4453 old = old->next;
4454 }
4455 if (old == NULL) {
4456 if (doc->children == NULL) {
4457 doc->children = root;
4458 doc->last = root;
4459 } else {
4460 xmlAddSibling(doc->children, root);
4461 }
4462 } else {
4463 xmlReplaceNode(old, root);
4464 }
4465 return(old);
4466}
Daniel Veillard2156d432004-03-04 15:59:36 +00004467#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004468
Daniel Veillard2156d432004-03-04 15:59:36 +00004469#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004470/**
4471 * xmlNodeSetLang:
4472 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004473 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004474 *
4475 * Set the language of a node, i.e. the values of the xml:lang
4476 * attribute.
4477 */
4478void
4479xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004480 xmlNsPtr ns;
4481
Owen Taylor3473f882001-02-23 17:55:21 +00004482 if (cur == NULL) return;
4483 switch(cur->type) {
4484 case XML_TEXT_NODE:
4485 case XML_CDATA_SECTION_NODE:
4486 case XML_COMMENT_NODE:
4487 case XML_DOCUMENT_NODE:
4488 case XML_DOCUMENT_TYPE_NODE:
4489 case XML_DOCUMENT_FRAG_NODE:
4490 case XML_NOTATION_NODE:
4491 case XML_HTML_DOCUMENT_NODE:
4492 case XML_DTD_NODE:
4493 case XML_ELEMENT_DECL:
4494 case XML_ATTRIBUTE_DECL:
4495 case XML_ENTITY_DECL:
4496 case XML_PI_NODE:
4497 case XML_ENTITY_REF_NODE:
4498 case XML_ENTITY_NODE:
4499 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004500#ifdef LIBXML_DOCB_ENABLED
4501 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004502#endif
4503 case XML_XINCLUDE_START:
4504 case XML_XINCLUDE_END:
4505 return;
4506 case XML_ELEMENT_NODE:
4507 case XML_ATTRIBUTE_NODE:
4508 break;
4509 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004510 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4511 if (ns == NULL)
4512 return;
4513 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004514}
Daniel Veillard652327a2003-09-29 18:02:38 +00004515#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004516
4517/**
4518 * xmlNodeGetLang:
4519 * @cur: the node being checked
4520 *
4521 * Searches the language of a node, i.e. the values of the xml:lang
4522 * attribute or the one carried by the nearest ancestor.
4523 *
4524 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004525 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004526 */
4527xmlChar *
4528xmlNodeGetLang(xmlNodePtr cur) {
4529 xmlChar *lang;
4530
4531 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004532 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004533 if (lang != NULL)
4534 return(lang);
4535 cur = cur->parent;
4536 }
4537 return(NULL);
4538}
4539
4540
Daniel Veillard652327a2003-09-29 18:02:38 +00004541#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004542/**
4543 * xmlNodeSetSpacePreserve:
4544 * @cur: the node being changed
4545 * @val: the xml:space value ("0": default, 1: "preserve")
4546 *
4547 * Set (or reset) the space preserving behaviour of a node, i.e. the
4548 * value of the xml:space attribute.
4549 */
4550void
4551xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004552 xmlNsPtr ns;
4553
Owen Taylor3473f882001-02-23 17:55:21 +00004554 if (cur == NULL) return;
4555 switch(cur->type) {
4556 case XML_TEXT_NODE:
4557 case XML_CDATA_SECTION_NODE:
4558 case XML_COMMENT_NODE:
4559 case XML_DOCUMENT_NODE:
4560 case XML_DOCUMENT_TYPE_NODE:
4561 case XML_DOCUMENT_FRAG_NODE:
4562 case XML_NOTATION_NODE:
4563 case XML_HTML_DOCUMENT_NODE:
4564 case XML_DTD_NODE:
4565 case XML_ELEMENT_DECL:
4566 case XML_ATTRIBUTE_DECL:
4567 case XML_ENTITY_DECL:
4568 case XML_PI_NODE:
4569 case XML_ENTITY_REF_NODE:
4570 case XML_ENTITY_NODE:
4571 case XML_NAMESPACE_DECL:
4572 case XML_XINCLUDE_START:
4573 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004574#ifdef LIBXML_DOCB_ENABLED
4575 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004576#endif
4577 return;
4578 case XML_ELEMENT_NODE:
4579 case XML_ATTRIBUTE_NODE:
4580 break;
4581 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004582 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4583 if (ns == NULL)
4584 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004585 switch (val) {
4586 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004587 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004588 break;
4589 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004590 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004591 break;
4592 }
4593}
Daniel Veillard652327a2003-09-29 18:02:38 +00004594#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004595
4596/**
4597 * xmlNodeGetSpacePreserve:
4598 * @cur: the node being checked
4599 *
4600 * Searches the space preserving behaviour of a node, i.e. the values
4601 * of the xml:space attribute or the one carried by the nearest
4602 * ancestor.
4603 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004604 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004605 */
4606int
4607xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4608 xmlChar *space;
4609
4610 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004611 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004612 if (space != NULL) {
4613 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4614 xmlFree(space);
4615 return(1);
4616 }
4617 if (xmlStrEqual(space, BAD_CAST "default")) {
4618 xmlFree(space);
4619 return(0);
4620 }
4621 xmlFree(space);
4622 }
4623 cur = cur->parent;
4624 }
4625 return(-1);
4626}
4627
Daniel Veillard652327a2003-09-29 18:02:38 +00004628#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004629/**
4630 * xmlNodeSetName:
4631 * @cur: the node being changed
4632 * @name: the new tag name
4633 *
4634 * Set (or reset) the name of a node.
4635 */
4636void
4637xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00004638 xmlDocPtr doc;
4639 xmlDictPtr dict;
4640
Owen Taylor3473f882001-02-23 17:55:21 +00004641 if (cur == NULL) return;
4642 if (name == NULL) return;
4643 switch(cur->type) {
4644 case XML_TEXT_NODE:
4645 case XML_CDATA_SECTION_NODE:
4646 case XML_COMMENT_NODE:
4647 case XML_DOCUMENT_TYPE_NODE:
4648 case XML_DOCUMENT_FRAG_NODE:
4649 case XML_NOTATION_NODE:
4650 case XML_HTML_DOCUMENT_NODE:
4651 case XML_NAMESPACE_DECL:
4652 case XML_XINCLUDE_START:
4653 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004654#ifdef LIBXML_DOCB_ENABLED
4655 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004656#endif
4657 return;
4658 case XML_ELEMENT_NODE:
4659 case XML_ATTRIBUTE_NODE:
4660 case XML_PI_NODE:
4661 case XML_ENTITY_REF_NODE:
4662 case XML_ENTITY_NODE:
4663 case XML_DTD_NODE:
4664 case XML_DOCUMENT_NODE:
4665 case XML_ELEMENT_DECL:
4666 case XML_ATTRIBUTE_DECL:
4667 case XML_ENTITY_DECL:
4668 break;
4669 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00004670 doc = cur->doc;
4671 if (doc != NULL)
4672 dict = doc->dict;
4673 else
4674 dict = NULL;
4675 if (dict != NULL) {
4676 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
4677 xmlFree((xmlChar *) cur->name);
4678 cur->name = xmlDictLookup(dict, name, -1);
4679 } else {
4680 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4681 cur->name = xmlStrdup(name);
4682 }
Owen Taylor3473f882001-02-23 17:55:21 +00004683}
Daniel Veillard2156d432004-03-04 15:59:36 +00004684#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004685
Daniel Veillard2156d432004-03-04 15:59:36 +00004686#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004687/**
4688 * xmlNodeSetBase:
4689 * @cur: the node being changed
4690 * @uri: the new base URI
4691 *
4692 * Set (or reset) the base URI of a node, i.e. the value of the
4693 * xml:base attribute.
4694 */
4695void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004696xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004697 xmlNsPtr ns;
4698
Owen Taylor3473f882001-02-23 17:55:21 +00004699 if (cur == NULL) return;
4700 switch(cur->type) {
4701 case XML_TEXT_NODE:
4702 case XML_CDATA_SECTION_NODE:
4703 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004704 case XML_DOCUMENT_TYPE_NODE:
4705 case XML_DOCUMENT_FRAG_NODE:
4706 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004707 case XML_DTD_NODE:
4708 case XML_ELEMENT_DECL:
4709 case XML_ATTRIBUTE_DECL:
4710 case XML_ENTITY_DECL:
4711 case XML_PI_NODE:
4712 case XML_ENTITY_REF_NODE:
4713 case XML_ENTITY_NODE:
4714 case XML_NAMESPACE_DECL:
4715 case XML_XINCLUDE_START:
4716 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004717 return;
4718 case XML_ELEMENT_NODE:
4719 case XML_ATTRIBUTE_NODE:
4720 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004721 case XML_DOCUMENT_NODE:
4722#ifdef LIBXML_DOCB_ENABLED
4723 case XML_DOCB_DOCUMENT_NODE:
4724#endif
4725 case XML_HTML_DOCUMENT_NODE: {
4726 xmlDocPtr doc = (xmlDocPtr) cur;
4727
4728 if (doc->URL != NULL)
4729 xmlFree((xmlChar *) doc->URL);
4730 if (uri == NULL)
4731 doc->URL = NULL;
4732 else
4733 doc->URL = xmlStrdup(uri);
4734 return;
4735 }
Owen Taylor3473f882001-02-23 17:55:21 +00004736 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004737
4738 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4739 if (ns == NULL)
4740 return;
4741 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004742}
Daniel Veillard652327a2003-09-29 18:02:38 +00004743#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004744
4745/**
Owen Taylor3473f882001-02-23 17:55:21 +00004746 * xmlNodeGetBase:
4747 * @doc: the document the node pertains to
4748 * @cur: the node being checked
4749 *
4750 * Searches for the BASE URL. The code should work on both XML
4751 * and HTML document even if base mechanisms are completely different.
4752 * It returns the base as defined in RFC 2396 sections
4753 * 5.1.1. Base URI within Document Content
4754 * and
4755 * 5.1.2. Base URI from the Encapsulating Entity
4756 * However it does not return the document base (5.1.3), use
4757 * xmlDocumentGetBase() for this
4758 *
4759 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004760 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004761 */
4762xmlChar *
4763xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004764 xmlChar *oldbase = NULL;
4765 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004766
4767 if ((cur == NULL) && (doc == NULL))
4768 return(NULL);
4769 if (doc == NULL) doc = cur->doc;
4770 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4771 cur = doc->children;
4772 while ((cur != NULL) && (cur->name != NULL)) {
4773 if (cur->type != XML_ELEMENT_NODE) {
4774 cur = cur->next;
4775 continue;
4776 }
4777 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4778 cur = cur->children;
4779 continue;
4780 }
4781 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4782 cur = cur->children;
4783 continue;
4784 }
4785 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4786 return(xmlGetProp(cur, BAD_CAST "href"));
4787 }
4788 cur = cur->next;
4789 }
4790 return(NULL);
4791 }
4792 while (cur != NULL) {
4793 if (cur->type == XML_ENTITY_DECL) {
4794 xmlEntityPtr ent = (xmlEntityPtr) cur;
4795 return(xmlStrdup(ent->URI));
4796 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004797 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004798 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004799 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004800 if (oldbase != NULL) {
4801 newbase = xmlBuildURI(oldbase, base);
4802 if (newbase != NULL) {
4803 xmlFree(oldbase);
4804 xmlFree(base);
4805 oldbase = newbase;
4806 } else {
4807 xmlFree(oldbase);
4808 xmlFree(base);
4809 return(NULL);
4810 }
4811 } else {
4812 oldbase = base;
4813 }
4814 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4815 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4816 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4817 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004818 }
4819 }
Owen Taylor3473f882001-02-23 17:55:21 +00004820 cur = cur->parent;
4821 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004822 if ((doc != NULL) && (doc->URL != NULL)) {
4823 if (oldbase == NULL)
4824 return(xmlStrdup(doc->URL));
4825 newbase = xmlBuildURI(oldbase, doc->URL);
4826 xmlFree(oldbase);
4827 return(newbase);
4828 }
4829 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004830}
4831
4832/**
Daniel Veillard78697292003-10-19 20:44:43 +00004833 * xmlNodeBufGetContent:
4834 * @buffer: a buffer
4835 * @cur: the node being read
4836 *
4837 * Read the value of a node @cur, this can be either the text carried
4838 * directly by this node if it's a TEXT node or the aggregate string
4839 * of the values carried by this node child's (TEXT and ENTITY_REF).
4840 * Entity references are substituted.
4841 * Fills up the buffer @buffer with this value
4842 *
4843 * Returns 0 in case of success and -1 in case of error.
4844 */
4845int
4846xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4847{
4848 if ((cur == NULL) || (buffer == NULL)) return(-1);
4849 switch (cur->type) {
4850 case XML_CDATA_SECTION_NODE:
4851 case XML_TEXT_NODE:
4852 xmlBufferCat(buffer, cur->content);
4853 break;
4854 case XML_DOCUMENT_FRAG_NODE:
4855 case XML_ELEMENT_NODE:{
4856 xmlNodePtr tmp = cur;
4857
4858 while (tmp != NULL) {
4859 switch (tmp->type) {
4860 case XML_CDATA_SECTION_NODE:
4861 case XML_TEXT_NODE:
4862 if (tmp->content != NULL)
4863 xmlBufferCat(buffer, tmp->content);
4864 break;
4865 case XML_ENTITY_REF_NODE:
4866 xmlNodeBufGetContent(buffer, tmp->children);
4867 break;
4868 default:
4869 break;
4870 }
4871 /*
4872 * Skip to next node
4873 */
4874 if (tmp->children != NULL) {
4875 if (tmp->children->type != XML_ENTITY_DECL) {
4876 tmp = tmp->children;
4877 continue;
4878 }
4879 }
4880 if (tmp == cur)
4881 break;
4882
4883 if (tmp->next != NULL) {
4884 tmp = tmp->next;
4885 continue;
4886 }
4887
4888 do {
4889 tmp = tmp->parent;
4890 if (tmp == NULL)
4891 break;
4892 if (tmp == cur) {
4893 tmp = NULL;
4894 break;
4895 }
4896 if (tmp->next != NULL) {
4897 tmp = tmp->next;
4898 break;
4899 }
4900 } while (tmp != NULL);
4901 }
4902 break;
4903 }
4904 case XML_ATTRIBUTE_NODE:{
4905 xmlAttrPtr attr = (xmlAttrPtr) cur;
4906 xmlNodePtr tmp = attr->children;
4907
4908 while (tmp != NULL) {
4909 if (tmp->type == XML_TEXT_NODE)
4910 xmlBufferCat(buffer, tmp->content);
4911 else
4912 xmlNodeBufGetContent(buffer, tmp);
4913 tmp = tmp->next;
4914 }
4915 break;
4916 }
4917 case XML_COMMENT_NODE:
4918 case XML_PI_NODE:
4919 xmlBufferCat(buffer, cur->content);
4920 break;
4921 case XML_ENTITY_REF_NODE:{
4922 xmlEntityPtr ent;
4923 xmlNodePtr tmp;
4924
4925 /* lookup entity declaration */
4926 ent = xmlGetDocEntity(cur->doc, cur->name);
4927 if (ent == NULL)
4928 return(-1);
4929
4930 /* an entity content can be any "well balanced chunk",
4931 * i.e. the result of the content [43] production:
4932 * http://www.w3.org/TR/REC-xml#NT-content
4933 * -> we iterate through child nodes and recursive call
4934 * xmlNodeGetContent() which handles all possible node types */
4935 tmp = ent->children;
4936 while (tmp) {
4937 xmlNodeBufGetContent(buffer, tmp);
4938 tmp = tmp->next;
4939 }
4940 break;
4941 }
4942 case XML_ENTITY_NODE:
4943 case XML_DOCUMENT_TYPE_NODE:
4944 case XML_NOTATION_NODE:
4945 case XML_DTD_NODE:
4946 case XML_XINCLUDE_START:
4947 case XML_XINCLUDE_END:
4948 break;
4949 case XML_DOCUMENT_NODE:
4950#ifdef LIBXML_DOCB_ENABLED
4951 case XML_DOCB_DOCUMENT_NODE:
4952#endif
4953 case XML_HTML_DOCUMENT_NODE:
4954 cur = cur->children;
4955 while (cur!= NULL) {
4956 if ((cur->type == XML_ELEMENT_NODE) ||
4957 (cur->type == XML_TEXT_NODE) ||
4958 (cur->type == XML_CDATA_SECTION_NODE)) {
4959 xmlNodeBufGetContent(buffer, cur);
4960 }
4961 cur = cur->next;
4962 }
4963 break;
4964 case XML_NAMESPACE_DECL:
4965 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
4966 break;
4967 case XML_ELEMENT_DECL:
4968 case XML_ATTRIBUTE_DECL:
4969 case XML_ENTITY_DECL:
4970 break;
4971 }
4972 return(0);
4973}
4974/**
Owen Taylor3473f882001-02-23 17:55:21 +00004975 * xmlNodeGetContent:
4976 * @cur: the node being read
4977 *
4978 * Read the value of a node, this can be either the text carried
4979 * directly by this node if it's a TEXT node or the aggregate string
4980 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004981 * Entity references are substituted.
4982 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004983 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004984 */
4985xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004986xmlNodeGetContent(xmlNodePtr cur)
4987{
4988 if (cur == NULL)
4989 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004990 switch (cur->type) {
4991 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004992 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00004993 xmlBufferPtr buffer;
4994 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004995
Daniel Veillard814a76d2003-01-23 18:24:20 +00004996 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004997 if (buffer == NULL)
4998 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00004999 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005000 ret = buffer->content;
5001 buffer->content = NULL;
5002 xmlBufferFree(buffer);
5003 return (ret);
5004 }
5005 case XML_ATTRIBUTE_NODE:{
5006 xmlAttrPtr attr = (xmlAttrPtr) cur;
5007
5008 if (attr->parent != NULL)
5009 return (xmlNodeListGetString
5010 (attr->parent->doc, attr->children, 1));
5011 else
5012 return (xmlNodeListGetString(NULL, attr->children, 1));
5013 break;
5014 }
Owen Taylor3473f882001-02-23 17:55:21 +00005015 case XML_COMMENT_NODE:
5016 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005017 if (cur->content != NULL)
5018 return (xmlStrdup(cur->content));
5019 return (NULL);
5020 case XML_ENTITY_REF_NODE:{
5021 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00005022 xmlBufferPtr buffer;
5023 xmlChar *ret;
5024
5025 /* lookup entity declaration */
5026 ent = xmlGetDocEntity(cur->doc, cur->name);
5027 if (ent == NULL)
5028 return (NULL);
5029
5030 buffer = xmlBufferCreate();
5031 if (buffer == NULL)
5032 return (NULL);
5033
Daniel Veillardc4696922003-10-19 21:47:14 +00005034 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005035
5036 ret = buffer->content;
5037 buffer->content = NULL;
5038 xmlBufferFree(buffer);
5039 return (ret);
5040 }
Owen Taylor3473f882001-02-23 17:55:21 +00005041 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005042 case XML_DOCUMENT_TYPE_NODE:
5043 case XML_NOTATION_NODE:
5044 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005045 case XML_XINCLUDE_START:
5046 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00005047 return (NULL);
5048 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005049#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005050 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005051#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005052 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00005053 xmlBufferPtr buffer;
5054 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005055
Daniel Veillardc4696922003-10-19 21:47:14 +00005056 buffer = xmlBufferCreate();
5057 if (buffer == NULL)
5058 return (NULL);
5059
5060 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5061
5062 ret = buffer->content;
5063 buffer->content = NULL;
5064 xmlBufferFree(buffer);
5065 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005066 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005067 case XML_NAMESPACE_DECL: {
5068 xmlChar *tmp;
5069
5070 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5071 return (tmp);
5072 }
Owen Taylor3473f882001-02-23 17:55:21 +00005073 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005074 /* TODO !!! */
5075 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005076 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005077 /* TODO !!! */
5078 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005079 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005080 /* TODO !!! */
5081 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005082 case XML_CDATA_SECTION_NODE:
5083 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005084 if (cur->content != NULL)
5085 return (xmlStrdup(cur->content));
5086 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005087 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005088 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005089}
Daniel Veillard652327a2003-09-29 18:02:38 +00005090
Owen Taylor3473f882001-02-23 17:55:21 +00005091/**
5092 * xmlNodeSetContent:
5093 * @cur: the node being modified
5094 * @content: the new value of the content
5095 *
5096 * Replace the content of a node.
5097 */
5098void
5099xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5100 if (cur == NULL) {
5101#ifdef DEBUG_TREE
5102 xmlGenericError(xmlGenericErrorContext,
5103 "xmlNodeSetContent : node == NULL\n");
5104#endif
5105 return;
5106 }
5107 switch (cur->type) {
5108 case XML_DOCUMENT_FRAG_NODE:
5109 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005110 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005111 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5112 cur->children = xmlStringGetNodeList(cur->doc, content);
5113 UPDATE_LAST_CHILD_AND_PARENT(cur)
5114 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005115 case XML_TEXT_NODE:
5116 case XML_CDATA_SECTION_NODE:
5117 case XML_ENTITY_REF_NODE:
5118 case XML_ENTITY_NODE:
5119 case XML_PI_NODE:
5120 case XML_COMMENT_NODE:
Daniel Veillard8874b942005-08-25 13:19:21 +00005121 if ((cur->content != NULL) &&
5122 (cur->content != (xmlChar *) &(cur->properties))) {
William M. Brack7762bb12004-01-04 14:49:01 +00005123 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
Daniel Veillardc587bce2005-05-10 15:28:08 +00005124 (xmlDictOwns(cur->doc->dict, cur->content))))
William M. Brack7762bb12004-01-04 14:49:01 +00005125 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005126 }
5127 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5128 cur->last = cur->children = NULL;
5129 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005130 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005131 } else
5132 cur->content = NULL;
Daniel Veillard8874b942005-08-25 13:19:21 +00005133 cur->properties = NULL;
5134 cur->nsDef = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00005135 break;
5136 case XML_DOCUMENT_NODE:
5137 case XML_HTML_DOCUMENT_NODE:
5138 case XML_DOCUMENT_TYPE_NODE:
5139 case XML_XINCLUDE_START:
5140 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005141#ifdef LIBXML_DOCB_ENABLED
5142 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005143#endif
5144 break;
5145 case XML_NOTATION_NODE:
5146 break;
5147 case XML_DTD_NODE:
5148 break;
5149 case XML_NAMESPACE_DECL:
5150 break;
5151 case XML_ELEMENT_DECL:
5152 /* TODO !!! */
5153 break;
5154 case XML_ATTRIBUTE_DECL:
5155 /* TODO !!! */
5156 break;
5157 case XML_ENTITY_DECL:
5158 /* TODO !!! */
5159 break;
5160 }
5161}
5162
Daniel Veillard652327a2003-09-29 18:02:38 +00005163#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005164/**
5165 * xmlNodeSetContentLen:
5166 * @cur: the node being modified
5167 * @content: the new value of the content
5168 * @len: the size of @content
5169 *
5170 * Replace the content of a node.
5171 */
5172void
5173xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5174 if (cur == NULL) {
5175#ifdef DEBUG_TREE
5176 xmlGenericError(xmlGenericErrorContext,
5177 "xmlNodeSetContentLen : node == NULL\n");
5178#endif
5179 return;
5180 }
5181 switch (cur->type) {
5182 case XML_DOCUMENT_FRAG_NODE:
5183 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005184 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005185 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5186 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5187 UPDATE_LAST_CHILD_AND_PARENT(cur)
5188 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005189 case XML_TEXT_NODE:
5190 case XML_CDATA_SECTION_NODE:
5191 case XML_ENTITY_REF_NODE:
5192 case XML_ENTITY_NODE:
5193 case XML_PI_NODE:
5194 case XML_COMMENT_NODE:
5195 case XML_NOTATION_NODE:
Daniel Veillard8874b942005-08-25 13:19:21 +00005196 if ((cur->content != NULL) &&
5197 (cur->content != (xmlChar *) &(cur->properties))) {
5198 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5199 (xmlDictOwns(cur->doc->dict, cur->content))))
5200 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005201 }
5202 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5203 cur->children = cur->last = NULL;
5204 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005205 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005206 } else
5207 cur->content = NULL;
Daniel Veillard8874b942005-08-25 13:19:21 +00005208 cur->properties = NULL;
5209 cur->nsDef = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00005210 break;
5211 case XML_DOCUMENT_NODE:
5212 case XML_DTD_NODE:
5213 case XML_HTML_DOCUMENT_NODE:
5214 case XML_DOCUMENT_TYPE_NODE:
5215 case XML_NAMESPACE_DECL:
5216 case XML_XINCLUDE_START:
5217 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005218#ifdef LIBXML_DOCB_ENABLED
5219 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005220#endif
5221 break;
5222 case XML_ELEMENT_DECL:
5223 /* TODO !!! */
5224 break;
5225 case XML_ATTRIBUTE_DECL:
5226 /* TODO !!! */
5227 break;
5228 case XML_ENTITY_DECL:
5229 /* TODO !!! */
5230 break;
5231 }
5232}
Daniel Veillard652327a2003-09-29 18:02:38 +00005233#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005234
5235/**
5236 * xmlNodeAddContentLen:
5237 * @cur: the node being modified
5238 * @content: extra content
5239 * @len: the size of @content
5240 *
5241 * Append the extra substring to the node content.
5242 */
5243void
5244xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5245 if (cur == NULL) {
5246#ifdef DEBUG_TREE
5247 xmlGenericError(xmlGenericErrorContext,
5248 "xmlNodeAddContentLen : node == NULL\n");
5249#endif
5250 return;
5251 }
5252 if (len <= 0) return;
5253 switch (cur->type) {
5254 case XML_DOCUMENT_FRAG_NODE:
5255 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005256 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005257
Daniel Veillard7db37732001-07-12 01:20:08 +00005258 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005259 newNode = xmlNewTextLen(content, len);
5260 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005261 tmp = xmlAddChild(cur, newNode);
5262 if (tmp != newNode)
5263 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005264 if ((last != NULL) && (last->next == newNode)) {
5265 xmlTextMerge(last, newNode);
5266 }
5267 }
5268 break;
5269 }
5270 case XML_ATTRIBUTE_NODE:
5271 break;
5272 case XML_TEXT_NODE:
5273 case XML_CDATA_SECTION_NODE:
5274 case XML_ENTITY_REF_NODE:
5275 case XML_ENTITY_NODE:
5276 case XML_PI_NODE:
5277 case XML_COMMENT_NODE:
5278 case XML_NOTATION_NODE:
5279 if (content != NULL) {
Daniel Veillard8874b942005-08-25 13:19:21 +00005280 if ((cur->content == (xmlChar *) &(cur->properties)) ||
5281 ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5282 xmlDictOwns(cur->doc->dict, cur->content))) {
5283 cur->content = xmlStrncatNew(cur->content, content, len);
5284 cur->properties = NULL;
5285 cur->nsDef = NULL;
William M. Brack7762bb12004-01-04 14:49:01 +00005286 break;
5287 }
Owen Taylor3473f882001-02-23 17:55:21 +00005288 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005289 }
5290 case XML_DOCUMENT_NODE:
5291 case XML_DTD_NODE:
5292 case XML_HTML_DOCUMENT_NODE:
5293 case XML_DOCUMENT_TYPE_NODE:
5294 case XML_NAMESPACE_DECL:
5295 case XML_XINCLUDE_START:
5296 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005297#ifdef LIBXML_DOCB_ENABLED
5298 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005299#endif
5300 break;
5301 case XML_ELEMENT_DECL:
5302 case XML_ATTRIBUTE_DECL:
5303 case XML_ENTITY_DECL:
5304 break;
5305 }
5306}
5307
5308/**
5309 * xmlNodeAddContent:
5310 * @cur: the node being modified
5311 * @content: extra content
5312 *
5313 * Append the extra substring to the node content.
5314 */
5315void
5316xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5317 int len;
5318
5319 if (cur == NULL) {
5320#ifdef DEBUG_TREE
5321 xmlGenericError(xmlGenericErrorContext,
5322 "xmlNodeAddContent : node == NULL\n");
5323#endif
5324 return;
5325 }
5326 if (content == NULL) return;
5327 len = xmlStrlen(content);
5328 xmlNodeAddContentLen(cur, content, len);
5329}
5330
5331/**
5332 * xmlTextMerge:
5333 * @first: the first text node
5334 * @second: the second text node being merged
5335 *
5336 * Merge two text nodes into one
5337 * Returns the first text node augmented
5338 */
5339xmlNodePtr
5340xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5341 if (first == NULL) return(second);
5342 if (second == NULL) return(first);
5343 if (first->type != XML_TEXT_NODE) return(first);
5344 if (second->type != XML_TEXT_NODE) return(first);
5345 if (second->name != first->name)
5346 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005347 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005348 xmlUnlinkNode(second);
5349 xmlFreeNode(second);
5350 return(first);
5351}
5352
Daniel Veillard2156d432004-03-04 15:59:36 +00005353#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005354/**
5355 * xmlGetNsList:
5356 * @doc: the document
5357 * @node: the current node
5358 *
5359 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005360 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005361 * that need to be freed by the caller or NULL if no
5362 * namespace if defined
5363 */
5364xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005365xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5366{
Owen Taylor3473f882001-02-23 17:55:21 +00005367 xmlNsPtr cur;
5368 xmlNsPtr *ret = NULL;
5369 int nbns = 0;
5370 int maxns = 10;
5371 int i;
5372
5373 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005374 if (node->type == XML_ELEMENT_NODE) {
5375 cur = node->nsDef;
5376 while (cur != NULL) {
5377 if (ret == NULL) {
5378 ret =
5379 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5380 sizeof(xmlNsPtr));
5381 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005382 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005383 return (NULL);
5384 }
5385 ret[nbns] = NULL;
5386 }
5387 for (i = 0; i < nbns; i++) {
5388 if ((cur->prefix == ret[i]->prefix) ||
5389 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5390 break;
5391 }
5392 if (i >= nbns) {
5393 if (nbns >= maxns) {
5394 maxns *= 2;
5395 ret = (xmlNsPtr *) xmlRealloc(ret,
5396 (maxns +
5397 1) *
5398 sizeof(xmlNsPtr));
5399 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005400 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005401 return (NULL);
5402 }
5403 }
5404 ret[nbns++] = cur;
5405 ret[nbns] = NULL;
5406 }
Owen Taylor3473f882001-02-23 17:55:21 +00005407
Daniel Veillard77044732001-06-29 21:31:07 +00005408 cur = cur->next;
5409 }
5410 }
5411 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005412 }
Daniel Veillard77044732001-06-29 21:31:07 +00005413 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005414}
Daniel Veillard652327a2003-09-29 18:02:38 +00005415#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005416
5417/**
5418 * xmlSearchNs:
5419 * @doc: the document
5420 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005421 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005422 *
5423 * Search a Ns registered under a given name space for a document.
5424 * recurse on the parents until it finds the defined namespace
5425 * or return NULL otherwise.
5426 * @nameSpace can be NULL, this is a search for the default namespace.
5427 * We don't allow to cross entities boundaries. If you don't declare
5428 * the namespace within those you will be in troubles !!! A warning
5429 * is generated to cover this case.
5430 *
5431 * Returns the namespace pointer or NULL.
5432 */
5433xmlNsPtr
5434xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005435
Owen Taylor3473f882001-02-23 17:55:21 +00005436 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005437 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005438
5439 if (node == NULL) return(NULL);
5440 if ((nameSpace != NULL) &&
5441 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005442 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5443 /*
5444 * The XML-1.0 namespace is normally held on the root
5445 * element. In this case exceptionally create it on the
5446 * node element.
5447 */
5448 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5449 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005450 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005451 return(NULL);
5452 }
5453 memset(cur, 0, sizeof(xmlNs));
5454 cur->type = XML_LOCAL_NAMESPACE;
5455 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5456 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5457 cur->next = node->nsDef;
5458 node->nsDef = cur;
5459 return(cur);
5460 }
Owen Taylor3473f882001-02-23 17:55:21 +00005461 if (doc->oldNs == NULL) {
5462 /*
5463 * Allocate a new Namespace and fill the fields.
5464 */
5465 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5466 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005467 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005468 return(NULL);
5469 }
5470 memset(doc->oldNs, 0, sizeof(xmlNs));
5471 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5472
5473 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5474 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5475 }
5476 return(doc->oldNs);
5477 }
5478 while (node != NULL) {
5479 if ((node->type == XML_ENTITY_REF_NODE) ||
5480 (node->type == XML_ENTITY_NODE) ||
5481 (node->type == XML_ENTITY_DECL))
5482 return(NULL);
5483 if (node->type == XML_ELEMENT_NODE) {
5484 cur = node->nsDef;
5485 while (cur != NULL) {
5486 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5487 (cur->href != NULL))
5488 return(cur);
5489 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5490 (cur->href != NULL) &&
5491 (xmlStrEqual(cur->prefix, nameSpace)))
5492 return(cur);
5493 cur = cur->next;
5494 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005495 if (orig != node) {
5496 cur = node->ns;
5497 if (cur != NULL) {
5498 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5499 (cur->href != NULL))
5500 return(cur);
5501 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5502 (cur->href != NULL) &&
5503 (xmlStrEqual(cur->prefix, nameSpace)))
5504 return(cur);
5505 }
5506 }
Owen Taylor3473f882001-02-23 17:55:21 +00005507 }
5508 node = node->parent;
5509 }
5510 return(NULL);
5511}
5512
5513/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005514 * xmlNsInScope:
5515 * @doc: the document
5516 * @node: the current node
5517 * @ancestor: the ancestor carrying the namespace
5518 * @prefix: the namespace prefix
5519 *
5520 * Verify that the given namespace held on @ancestor is still in scope
5521 * on node.
5522 *
5523 * Returns 1 if true, 0 if false and -1 in case of error.
5524 */
5525static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005526xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5527 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005528{
5529 xmlNsPtr tst;
5530
5531 while ((node != NULL) && (node != ancestor)) {
5532 if ((node->type == XML_ENTITY_REF_NODE) ||
5533 (node->type == XML_ENTITY_NODE) ||
5534 (node->type == XML_ENTITY_DECL))
5535 return (-1);
5536 if (node->type == XML_ELEMENT_NODE) {
5537 tst = node->nsDef;
5538 while (tst != NULL) {
5539 if ((tst->prefix == NULL)
5540 && (prefix == NULL))
5541 return (0);
5542 if ((tst->prefix != NULL)
5543 && (prefix != NULL)
5544 && (xmlStrEqual(tst->prefix, prefix)))
5545 return (0);
5546 tst = tst->next;
5547 }
5548 }
5549 node = node->parent;
5550 }
5551 if (node != ancestor)
5552 return (-1);
5553 return (1);
5554}
5555
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005556/**
Owen Taylor3473f882001-02-23 17:55:21 +00005557 * xmlSearchNsByHref:
5558 * @doc: the document
5559 * @node: the current node
5560 * @href: the namespace value
5561 *
5562 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5563 * the defined namespace or return NULL otherwise.
5564 * Returns the namespace pointer or NULL.
5565 */
5566xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005567xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5568{
Owen Taylor3473f882001-02-23 17:55:21 +00005569 xmlNsPtr cur;
5570 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005571 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005572
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005573 if ((node == NULL) || (href == NULL))
5574 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005575 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005576 /*
5577 * Only the document can hold the XML spec namespace.
5578 */
5579 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5580 /*
5581 * The XML-1.0 namespace is normally held on the root
5582 * element. In this case exceptionally create it on the
5583 * node element.
5584 */
5585 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5586 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005587 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005588 return (NULL);
5589 }
5590 memset(cur, 0, sizeof(xmlNs));
5591 cur->type = XML_LOCAL_NAMESPACE;
5592 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5593 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5594 cur->next = node->nsDef;
5595 node->nsDef = cur;
5596 return (cur);
5597 }
5598 if (doc->oldNs == NULL) {
5599 /*
5600 * Allocate a new Namespace and fill the fields.
5601 */
5602 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5603 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005604 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005605 return (NULL);
5606 }
5607 memset(doc->oldNs, 0, sizeof(xmlNs));
5608 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005609
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005610 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5611 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5612 }
5613 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005614 }
Daniel Veillard62040be2004-05-17 03:17:26 +00005615 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00005616 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005617 if ((node->type == XML_ENTITY_REF_NODE) ||
5618 (node->type == XML_ENTITY_NODE) ||
5619 (node->type == XML_ENTITY_DECL))
5620 return (NULL);
5621 if (node->type == XML_ELEMENT_NODE) {
5622 cur = node->nsDef;
5623 while (cur != NULL) {
5624 if ((cur->href != NULL) && (href != NULL) &&
5625 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005626 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00005627 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005628 return (cur);
5629 }
5630 cur = cur->next;
5631 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005632 if (orig != node) {
5633 cur = node->ns;
5634 if (cur != NULL) {
5635 if ((cur->href != NULL) && (href != NULL) &&
5636 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005637 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00005638 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00005639 return (cur);
5640 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005641 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005642 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005643 }
5644 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005645 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005646 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005647}
5648
5649/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005650 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005651 * @doc: the document
5652 * @tree: a node expected to hold the new namespace
5653 * @ns: the original namespace
5654 *
5655 * This function tries to locate a namespace definition in a tree
5656 * ancestors, or create a new namespace definition node similar to
5657 * @ns trying to reuse the same prefix. However if the given prefix is
5658 * null (default namespace) or reused within the subtree defined by
5659 * @tree or on one of its ancestors then a new prefix is generated.
5660 * Returns the (new) namespace definition or NULL in case of error
5661 */
5662xmlNsPtr
5663xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5664 xmlNsPtr def;
5665 xmlChar prefix[50];
5666 int counter = 1;
5667
5668 if (tree == NULL) {
5669#ifdef DEBUG_TREE
5670 xmlGenericError(xmlGenericErrorContext,
5671 "xmlNewReconciliedNs : tree == NULL\n");
5672#endif
5673 return(NULL);
5674 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00005675 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005676#ifdef DEBUG_TREE
5677 xmlGenericError(xmlGenericErrorContext,
5678 "xmlNewReconciliedNs : ns == NULL\n");
5679#endif
5680 return(NULL);
5681 }
5682 /*
5683 * Search an existing namespace definition inherited.
5684 */
5685 def = xmlSearchNsByHref(doc, tree, ns->href);
5686 if (def != NULL)
5687 return(def);
5688
5689 /*
5690 * Find a close prefix which is not already in use.
5691 * Let's strip namespace prefixes longer than 20 chars !
5692 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005693 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005694 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005695 else
William M. Brack13dfa872004-09-18 04:52:08 +00005696 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005697
Owen Taylor3473f882001-02-23 17:55:21 +00005698 def = xmlSearchNs(doc, tree, prefix);
5699 while (def != NULL) {
5700 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005701 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005702 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005703 else
William M. Brack13dfa872004-09-18 04:52:08 +00005704 snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
5705 (char *)ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005706 def = xmlSearchNs(doc, tree, prefix);
5707 }
5708
5709 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005710 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005711 */
5712 def = xmlNewNs(tree, ns->href, prefix);
5713 return(def);
5714}
5715
Daniel Veillard652327a2003-09-29 18:02:38 +00005716#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005717/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005718 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005719 * @doc: the document
5720 * @tree: a node defining the subtree to reconciliate
5721 *
5722 * This function checks that all the namespaces declared within the given
5723 * tree are properly declared. This is needed for example after Copy or Cut
5724 * and then paste operations. The subtree may still hold pointers to
5725 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005726 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005727 * the new environment. If not possible the new namespaces are redeclared
5728 * on @tree at the top of the given subtree.
5729 * Returns the number of namespace declarations created or -1 in case of error.
5730 */
5731int
5732xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5733 xmlNsPtr *oldNs = NULL;
5734 xmlNsPtr *newNs = NULL;
5735 int sizeCache = 0;
5736 int nbCache = 0;
5737
5738 xmlNsPtr n;
5739 xmlNodePtr node = tree;
5740 xmlAttrPtr attr;
5741 int ret = 0, i;
5742
Daniel Veillardce244ad2004-11-05 10:03:46 +00005743 if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1);
5744 if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1);
5745 if (node->doc != doc) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005746 while (node != NULL) {
5747 /*
5748 * Reconciliate the node namespace
5749 */
5750 if (node->ns != NULL) {
5751 /*
5752 * initialize the cache if needed
5753 */
5754 if (sizeCache == 0) {
5755 sizeCache = 10;
5756 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5757 sizeof(xmlNsPtr));
5758 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005759 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005760 return(-1);
5761 }
5762 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5763 sizeof(xmlNsPtr));
5764 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005765 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005766 xmlFree(oldNs);
5767 return(-1);
5768 }
5769 }
5770 for (i = 0;i < nbCache;i++) {
5771 if (oldNs[i] == node->ns) {
5772 node->ns = newNs[i];
5773 break;
5774 }
5775 }
5776 if (i == nbCache) {
5777 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005778 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005779 */
5780 n = xmlNewReconciliedNs(doc, tree, node->ns);
5781 if (n != NULL) { /* :-( what if else ??? */
5782 /*
5783 * check if we need to grow the cache buffers.
5784 */
5785 if (sizeCache <= nbCache) {
5786 sizeCache *= 2;
5787 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5788 sizeof(xmlNsPtr));
5789 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005790 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005791 xmlFree(newNs);
5792 return(-1);
5793 }
5794 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5795 sizeof(xmlNsPtr));
5796 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005797 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005798 xmlFree(oldNs);
5799 return(-1);
5800 }
5801 }
5802 newNs[nbCache] = n;
5803 oldNs[nbCache++] = node->ns;
5804 node->ns = n;
5805 }
5806 }
5807 }
5808 /*
5809 * now check for namespace hold by attributes on the node.
5810 */
5811 attr = node->properties;
5812 while (attr != NULL) {
5813 if (attr->ns != NULL) {
5814 /*
5815 * initialize the cache if needed
5816 */
5817 if (sizeCache == 0) {
5818 sizeCache = 10;
5819 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5820 sizeof(xmlNsPtr));
5821 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005822 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005823 return(-1);
5824 }
5825 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5826 sizeof(xmlNsPtr));
5827 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005828 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005829 xmlFree(oldNs);
5830 return(-1);
5831 }
5832 }
5833 for (i = 0;i < nbCache;i++) {
5834 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005835 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005836 break;
5837 }
5838 }
5839 if (i == nbCache) {
5840 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005841 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005842 */
5843 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5844 if (n != NULL) { /* :-( what if else ??? */
5845 /*
5846 * check if we need to grow the cache buffers.
5847 */
5848 if (sizeCache <= nbCache) {
5849 sizeCache *= 2;
5850 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5851 sizeof(xmlNsPtr));
5852 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005853 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005854 xmlFree(newNs);
5855 return(-1);
5856 }
5857 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5858 sizeof(xmlNsPtr));
5859 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005860 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005861 xmlFree(oldNs);
5862 return(-1);
5863 }
5864 }
5865 newNs[nbCache] = n;
5866 oldNs[nbCache++] = attr->ns;
5867 attr->ns = n;
5868 }
5869 }
5870 }
5871 attr = attr->next;
5872 }
5873
5874 /*
5875 * Browse the full subtree, deep first
5876 */
Daniel Veillardac996a12004-07-30 12:02:58 +00005877 if (node->children != NULL && node->type != XML_ENTITY_REF_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00005878 /* deep first */
5879 node = node->children;
5880 } else if ((node != tree) && (node->next != NULL)) {
5881 /* then siblings */
5882 node = node->next;
5883 } else if (node != tree) {
5884 /* go up to parents->next if needed */
5885 while (node != tree) {
5886 if (node->parent != NULL)
5887 node = node->parent;
5888 if ((node != tree) && (node->next != NULL)) {
5889 node = node->next;
5890 break;
5891 }
5892 if (node->parent == NULL) {
5893 node = NULL;
5894 break;
5895 }
5896 }
5897 /* exit condition */
5898 if (node == tree)
5899 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005900 } else
5901 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005902 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005903 if (oldNs != NULL)
5904 xmlFree(oldNs);
5905 if (newNs != NULL)
5906 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005907 return(ret);
5908}
Daniel Veillard652327a2003-09-29 18:02:38 +00005909#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005910
5911/**
5912 * xmlHasProp:
5913 * @node: the node
5914 * @name: the attribute name
5915 *
5916 * Search an attribute associated to a node
5917 * This function also looks in DTD attribute declaration for #FIXED or
5918 * default declaration values unless DTD use has been turned off.
5919 *
5920 * Returns the attribute or the attribute declaration or NULL if
5921 * neither was found.
5922 */
5923xmlAttrPtr
5924xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5925 xmlAttrPtr prop;
5926 xmlDocPtr doc;
5927
Daniel Veillard8874b942005-08-25 13:19:21 +00005928 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
5929 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005930 /*
5931 * Check on the properties attached to the node
5932 */
5933 prop = node->properties;
5934 while (prop != NULL) {
5935 if (xmlStrEqual(prop->name, name)) {
5936 return(prop);
5937 }
5938 prop = prop->next;
5939 }
5940 if (!xmlCheckDTD) return(NULL);
5941
5942 /*
5943 * Check if there is a default declaration in the internal
5944 * or external subsets
5945 */
5946 doc = node->doc;
5947 if (doc != NULL) {
5948 xmlAttributePtr attrDecl;
5949 if (doc->intSubset != NULL) {
5950 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5951 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5952 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005953 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5954 /* return attribute declaration only if a default value is given
5955 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005956 return((xmlAttrPtr) attrDecl);
5957 }
5958 }
5959 return(NULL);
5960}
5961
5962/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005963 * xmlHasNsProp:
5964 * @node: the node
5965 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005966 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005967 *
5968 * Search for an attribute associated to a node
5969 * This attribute has to be anchored in the namespace specified.
5970 * This does the entity substitution.
5971 * This function looks in DTD attribute declaration for #FIXED or
5972 * default declaration values unless DTD use has been turned off.
William M. Brack2c228442004-10-03 04:10:00 +00005973 * Note that a namespace of NULL indicates to use the default namespace.
Daniel Veillarde95e2392001-06-06 10:46:28 +00005974 *
5975 * Returns the attribute or the attribute declaration or NULL
5976 * if neither was found.
5977 */
5978xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005979xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005980 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00005981#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005982 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00005983#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005984
Daniel Veillard8874b942005-08-25 13:19:21 +00005985 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
Daniel Veillarde95e2392001-06-06 10:46:28 +00005986 return(NULL);
5987
5988 prop = node->properties;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005989 while (prop != NULL) {
5990 /*
5991 * One need to have
5992 * - same attribute names
5993 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005994 */
William M. Brack2c228442004-10-03 04:10:00 +00005995 if (xmlStrEqual(prop->name, name)) {
5996 if (((prop->ns != NULL) &&
5997 (xmlStrEqual(prop->ns->href, nameSpace))) ||
5998 ((prop->ns == NULL) && (nameSpace == NULL))) {
5999 return(prop);
6000 }
Daniel Veillarde95e2392001-06-06 10:46:28 +00006001 }
6002 prop = prop->next;
6003 }
6004 if (!xmlCheckDTD) return(NULL);
6005
Daniel Veillard652327a2003-09-29 18:02:38 +00006006#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00006007 /*
6008 * Check if there is a default declaration in the internal
6009 * or external subsets
6010 */
6011 doc = node->doc;
6012 if (doc != NULL) {
6013 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006014 xmlAttributePtr attrDecl = NULL;
6015 xmlNsPtr *nsList, *cur;
6016 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00006017
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006018 nsList = xmlGetNsList(node->doc, node);
6019 if (nsList == NULL)
6020 return(NULL);
6021 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
6022 ename = xmlStrdup(node->ns->prefix);
6023 ename = xmlStrcat(ename, BAD_CAST ":");
6024 ename = xmlStrcat(ename, node->name);
6025 } else {
6026 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006027 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006028 if (ename == NULL) {
6029 xmlFree(nsList);
6030 return(NULL);
6031 }
6032
William M. Brack2c228442004-10-03 04:10:00 +00006033 if (nameSpace == NULL) {
6034 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
6035 name, NULL);
6036 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
6037 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6038 name, NULL);
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006039 }
William M. Brack2c228442004-10-03 04:10:00 +00006040 } else {
6041 cur = nsList;
6042 while (*cur != NULL) {
6043 if (xmlStrEqual((*cur)->href, nameSpace)) {
6044 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
6045 name, (*cur)->prefix);
6046 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6047 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6048 name, (*cur)->prefix);
6049 }
6050 cur++;
6051 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006052 }
6053 xmlFree(nsList);
6054 xmlFree(ename);
6055 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006056 }
6057 }
Daniel Veillard652327a2003-09-29 18:02:38 +00006058#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00006059 return(NULL);
6060}
6061
6062/**
Owen Taylor3473f882001-02-23 17:55:21 +00006063 * xmlGetProp:
6064 * @node: the node
6065 * @name: the attribute name
6066 *
6067 * Search and get the value of an attribute associated to a node
6068 * This does the entity substitution.
6069 * This function looks in DTD attribute declaration for #FIXED or
6070 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00006071 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00006072 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6073 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00006074 *
6075 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006076 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006077 */
6078xmlChar *
6079xmlGetProp(xmlNodePtr node, const xmlChar *name) {
6080 xmlAttrPtr prop;
6081 xmlDocPtr doc;
6082
Daniel Veillard8874b942005-08-25 13:19:21 +00006083 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6084 return(NULL);
6085
Owen Taylor3473f882001-02-23 17:55:21 +00006086 /*
6087 * Check on the properties attached to the node
6088 */
6089 prop = node->properties;
6090 while (prop != NULL) {
6091 if (xmlStrEqual(prop->name, name)) {
6092 xmlChar *ret;
6093
6094 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6095 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6096 return(ret);
6097 }
6098 prop = prop->next;
6099 }
6100 if (!xmlCheckDTD) return(NULL);
6101
6102 /*
6103 * Check if there is a default declaration in the internal
6104 * or external subsets
6105 */
6106 doc = node->doc;
6107 if (doc != NULL) {
6108 xmlAttributePtr attrDecl;
6109 if (doc->intSubset != NULL) {
6110 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6111 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6112 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006113 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6114 /* return attribute declaration only if a default value is given
6115 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006116 return(xmlStrdup(attrDecl->defaultValue));
6117 }
6118 }
6119 return(NULL);
6120}
6121
6122/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006123 * xmlGetNoNsProp:
6124 * @node: the node
6125 * @name: the attribute name
6126 *
6127 * Search and get the value of an attribute associated to a node
6128 * This does the entity substitution.
6129 * This function looks in DTD attribute declaration for #FIXED or
6130 * default declaration values unless DTD use has been turned off.
6131 * This function is similar to xmlGetProp except it will accept only
6132 * an attribute in no namespace.
6133 *
6134 * Returns the attribute value or NULL if not found.
6135 * It's up to the caller to free the memory with xmlFree().
6136 */
6137xmlChar *
6138xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6139 xmlAttrPtr prop;
6140 xmlDocPtr doc;
6141
Daniel Veillard8874b942005-08-25 13:19:21 +00006142 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6143 return(NULL);
Daniel Veillard71531f32003-02-05 13:19:53 +00006144 /*
6145 * Check on the properties attached to the node
6146 */
6147 prop = node->properties;
6148 while (prop != NULL) {
6149 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6150 xmlChar *ret;
6151
6152 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6153 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6154 return(ret);
6155 }
6156 prop = prop->next;
6157 }
6158 if (!xmlCheckDTD) return(NULL);
6159
6160 /*
6161 * Check if there is a default declaration in the internal
6162 * or external subsets
6163 */
6164 doc = node->doc;
6165 if (doc != NULL) {
6166 xmlAttributePtr attrDecl;
6167 if (doc->intSubset != NULL) {
6168 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6169 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6170 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006171 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6172 /* return attribute declaration only if a default value is given
6173 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006174 return(xmlStrdup(attrDecl->defaultValue));
6175 }
6176 }
6177 return(NULL);
6178}
6179
6180/**
Owen Taylor3473f882001-02-23 17:55:21 +00006181 * xmlGetNsProp:
6182 * @node: the node
6183 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006184 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006185 *
6186 * Search and get the value of an attribute associated to a node
6187 * This attribute has to be anchored in the namespace specified.
6188 * This does the entity substitution.
6189 * This function looks in DTD attribute declaration for #FIXED or
6190 * default declaration values unless DTD use has been turned off.
6191 *
6192 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006193 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006194 */
6195xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006196xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006197 xmlAttrPtr prop;
6198 xmlDocPtr doc;
6199 xmlNsPtr ns;
6200
Daniel Veillard8874b942005-08-25 13:19:21 +00006201 if ((node == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006202 return(NULL);
6203
6204 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006205 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006206 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006207 while (prop != NULL) {
6208 /*
6209 * One need to have
6210 * - same attribute names
6211 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006212 */
6213 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006214 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006215 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006216 xmlChar *ret;
6217
6218 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6219 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6220 return(ret);
6221 }
6222 prop = prop->next;
6223 }
6224 if (!xmlCheckDTD) return(NULL);
6225
6226 /*
6227 * Check if there is a default declaration in the internal
6228 * or external subsets
6229 */
6230 doc = node->doc;
6231 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006232 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006233 xmlAttributePtr attrDecl;
6234
Owen Taylor3473f882001-02-23 17:55:21 +00006235 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6236 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6237 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6238
6239 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6240 /*
6241 * The DTD declaration only allows a prefix search
6242 */
6243 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006244 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006245 return(xmlStrdup(attrDecl->defaultValue));
6246 }
6247 }
6248 }
6249 return(NULL);
6250}
6251
Daniel Veillard2156d432004-03-04 15:59:36 +00006252#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6253/**
6254 * xmlUnsetProp:
6255 * @node: the node
6256 * @name: the attribute name
6257 *
6258 * Remove an attribute carried by a node.
6259 * Returns 0 if successful, -1 if not found
6260 */
6261int
6262xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Kasimier T. Buchcik65c2f1d2005-10-17 12:39:58 +00006263 xmlAttrPtr prop;
Daniel Veillard2156d432004-03-04 15:59:36 +00006264
Daniel Veillard8874b942005-08-25 13:19:21 +00006265 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
Daniel Veillard2156d432004-03-04 15:59:36 +00006266 return(-1);
6267 prop = node->properties;
6268 while (prop != NULL) {
6269 if ((xmlStrEqual(prop->name, name)) &&
6270 (prop->ns == NULL)) {
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00006271 xmlUnlinkNode((xmlNodePtr) prop);
Daniel Veillard2156d432004-03-04 15:59:36 +00006272 xmlFreeProp(prop);
6273 return(0);
6274 }
Daniel Veillard2156d432004-03-04 15:59:36 +00006275 prop = prop->next;
6276 }
6277 return(-1);
6278}
6279
6280/**
6281 * xmlUnsetNsProp:
6282 * @node: the node
6283 * @ns: the namespace definition
6284 * @name: the attribute name
6285 *
6286 * Remove an attribute carried by a node.
6287 * Returns 0 if successful, -1 if not found
6288 */
6289int
6290xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
Kasimier T. Buchcik65c2f1d2005-10-17 12:39:58 +00006291 xmlAttrPtr prop;
Daniel Veillard2156d432004-03-04 15:59:36 +00006292
Daniel Veillard8874b942005-08-25 13:19:21 +00006293 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
Daniel Veillard2156d432004-03-04 15:59:36 +00006294 return(-1);
Daniel Veillard27f20102004-11-05 11:50:11 +00006295 prop = node->properties;
Daniel Veillard2156d432004-03-04 15:59:36 +00006296 if (ns == NULL)
6297 return(xmlUnsetProp(node, name));
6298 if (ns->href == NULL)
6299 return(-1);
6300 while (prop != NULL) {
6301 if ((xmlStrEqual(prop->name, name)) &&
6302 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00006303 xmlUnlinkNode((xmlNodePtr) prop);
Daniel Veillard2156d432004-03-04 15:59:36 +00006304 xmlFreeProp(prop);
6305 return(0);
6306 }
Daniel Veillard2156d432004-03-04 15:59:36 +00006307 prop = prop->next;
6308 }
6309 return(-1);
6310}
6311#endif
6312
6313#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006314/**
6315 * xmlSetProp:
6316 * @node: the node
6317 * @name: the attribute name
6318 * @value: the attribute value
6319 *
6320 * Set (or reset) an attribute carried by a node.
6321 * Returns the attribute pointer.
6322 */
6323xmlAttrPtr
6324xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006325 xmlAttrPtr prop;
6326 xmlDocPtr doc;
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006327 int len;
6328 const xmlChar *nqname;
Owen Taylor3473f882001-02-23 17:55:21 +00006329
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006330 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006331 return(NULL);
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006332
6333 /*
6334 * handle QNames
6335 */
6336 nqname = xmlSplitQName3(name, &len);
6337 if (nqname != NULL) {
6338 xmlNsPtr ns;
6339 xmlChar *prefix = xmlStrndup(name, len);
6340 ns = xmlSearchNs(node->doc, node, prefix);
6341 if (prefix != NULL)
6342 xmlFree(prefix);
6343 if (ns != NULL)
6344 return(xmlSetNsProp(node, ns, nqname, value));
6345 }
6346
Owen Taylor3473f882001-02-23 17:55:21 +00006347 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006348 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006349 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006350 if ((xmlStrEqual(prop->name, name)) &&
6351 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006352 xmlNodePtr oldprop = prop->children;
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006353 int id = xmlIsID(node->doc, node, prop);
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006354
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006355 if (id == 1)
6356 xmlRemoveID(node->doc, prop);
Owen Taylor3473f882001-02-23 17:55:21 +00006357 prop->children = NULL;
6358 prop->last = NULL;
6359 if (value != NULL) {
6360 xmlChar *buffer;
6361 xmlNodePtr tmp;
6362
6363 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6364 prop->children = xmlStringGetNodeList(node->doc, buffer);
6365 prop->last = NULL;
6366 prop->doc = doc;
6367 tmp = prop->children;
6368 while (tmp != NULL) {
6369 tmp->parent = (xmlNodePtr) prop;
6370 tmp->doc = doc;
6371 if (tmp->next == NULL)
6372 prop->last = tmp;
6373 tmp = tmp->next;
6374 }
6375 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006376 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006377 if (oldprop != NULL)
6378 xmlFreeNodeList(oldprop);
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006379 if (id)
6380 xmlAddID(NULL, node->doc, value, prop);
Owen Taylor3473f882001-02-23 17:55:21 +00006381 return(prop);
6382 }
6383 prop = prop->next;
6384 }
6385 prop = xmlNewProp(node, name, value);
6386 return(prop);
6387}
6388
6389/**
6390 * xmlSetNsProp:
6391 * @node: the node
6392 * @ns: the namespace definition
6393 * @name: the attribute name
6394 * @value: the attribute value
6395 *
6396 * Set (or reset) an attribute carried by a node.
6397 * The ns structure must be in scope, this is not checked.
6398 *
6399 * Returns the attribute pointer.
6400 */
6401xmlAttrPtr
6402xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6403 const xmlChar *value) {
6404 xmlAttrPtr prop;
6405
Daniel Veillardb6b36d32005-02-09 16:48:53 +00006406 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006407 return(NULL);
6408
6409 if (ns == NULL)
6410 return(xmlSetProp(node, name, value));
6411 if (ns->href == NULL)
6412 return(NULL);
6413 prop = node->properties;
6414
6415 while (prop != NULL) {
6416 /*
6417 * One need to have
6418 * - same attribute names
6419 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006420 */
6421 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006422 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006423 int id = xmlIsID(node->doc, node, prop);
6424
6425 if (id == 1)
6426 xmlRemoveID(node->doc, prop);
Owen Taylor3473f882001-02-23 17:55:21 +00006427 if (prop->children != NULL)
6428 xmlFreeNodeList(prop->children);
6429 prop->children = NULL;
6430 prop->last = NULL;
6431 prop->ns = ns;
6432 if (value != NULL) {
6433 xmlChar *buffer;
6434 xmlNodePtr tmp;
6435
6436 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6437 prop->children = xmlStringGetNodeList(node->doc, buffer);
6438 prop->last = NULL;
6439 tmp = prop->children;
6440 while (tmp != NULL) {
6441 tmp->parent = (xmlNodePtr) prop;
6442 if (tmp->next == NULL)
6443 prop->last = tmp;
6444 tmp = tmp->next;
6445 }
6446 xmlFree(buffer);
6447 }
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006448 if (id)
6449 xmlAddID(NULL, node->doc, value, prop);
Owen Taylor3473f882001-02-23 17:55:21 +00006450 return(prop);
6451 }
6452 prop = prop->next;
6453 }
6454 prop = xmlNewNsProp(node, ns, name, value);
6455 return(prop);
6456}
6457
Daniel Veillard652327a2003-09-29 18:02:38 +00006458#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006459
6460/**
Owen Taylor3473f882001-02-23 17:55:21 +00006461 * xmlNodeIsText:
6462 * @node: the node
6463 *
6464 * Is this node a Text node ?
6465 * Returns 1 yes, 0 no
6466 */
6467int
6468xmlNodeIsText(xmlNodePtr node) {
6469 if (node == NULL) return(0);
6470
6471 if (node->type == XML_TEXT_NODE) return(1);
6472 return(0);
6473}
6474
6475/**
6476 * xmlIsBlankNode:
6477 * @node: the node
6478 *
6479 * Checks whether this node is an empty or whitespace only
6480 * (and possibly ignorable) text-node.
6481 *
6482 * Returns 1 yes, 0 no
6483 */
6484int
6485xmlIsBlankNode(xmlNodePtr node) {
6486 const xmlChar *cur;
6487 if (node == NULL) return(0);
6488
Daniel Veillard7db37732001-07-12 01:20:08 +00006489 if ((node->type != XML_TEXT_NODE) &&
6490 (node->type != XML_CDATA_SECTION_NODE))
6491 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006492 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006493 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006494 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006495 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006496 cur++;
6497 }
6498
6499 return(1);
6500}
6501
6502/**
6503 * xmlTextConcat:
6504 * @node: the node
6505 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006506 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006507 *
6508 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006509 *
6510 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006511 */
6512
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006513int
Owen Taylor3473f882001-02-23 17:55:21 +00006514xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006515 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006516
6517 if ((node->type != XML_TEXT_NODE) &&
6518 (node->type != XML_CDATA_SECTION_NODE)) {
6519#ifdef DEBUG_TREE
6520 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006521 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006522#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006523 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006524 }
William M. Brack7762bb12004-01-04 14:49:01 +00006525 /* need to check if content is currently in the dictionary */
Daniel Veillard8874b942005-08-25 13:19:21 +00006526 if ((node->content == (xmlChar *) &(node->properties)) ||
6527 ((node->doc != NULL) && (node->doc->dict != NULL) &&
6528 xmlDictOwns(node->doc->dict, node->content))) {
William M. Brack7762bb12004-01-04 14:49:01 +00006529 node->content = xmlStrncatNew(node->content, content, len);
6530 } else {
6531 node->content = xmlStrncat(node->content, content, len);
6532 }
Daniel Veillard8874b942005-08-25 13:19:21 +00006533 node->properties = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006534 if (node->content == NULL)
6535 return(-1);
6536 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006537}
6538
6539/************************************************************************
6540 * *
6541 * Output : to a FILE or in memory *
6542 * *
6543 ************************************************************************/
6544
Owen Taylor3473f882001-02-23 17:55:21 +00006545/**
6546 * xmlBufferCreate:
6547 *
6548 * routine to create an XML buffer.
6549 * returns the new structure.
6550 */
6551xmlBufferPtr
6552xmlBufferCreate(void) {
6553 xmlBufferPtr ret;
6554
6555 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6556 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006557 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006558 return(NULL);
6559 }
6560 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006561 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006562 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006563 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006564 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006565 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006566 xmlFree(ret);
6567 return(NULL);
6568 }
6569 ret->content[0] = 0;
6570 return(ret);
6571}
6572
6573/**
6574 * xmlBufferCreateSize:
6575 * @size: initial size of buffer
6576 *
6577 * routine to create an XML buffer.
6578 * returns the new structure.
6579 */
6580xmlBufferPtr
6581xmlBufferCreateSize(size_t size) {
6582 xmlBufferPtr ret;
6583
6584 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6585 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006586 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006587 return(NULL);
6588 }
6589 ret->use = 0;
6590 ret->alloc = xmlBufferAllocScheme;
6591 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6592 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006593 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006594 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006595 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006596 xmlFree(ret);
6597 return(NULL);
6598 }
6599 ret->content[0] = 0;
6600 } else
6601 ret->content = NULL;
6602 return(ret);
6603}
6604
6605/**
Daniel Veillard53350552003-09-18 13:35:51 +00006606 * xmlBufferCreateStatic:
6607 * @mem: the memory area
6608 * @size: the size in byte
6609 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006610 * routine to create an XML buffer from an immutable memory area.
6611 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006612 * present until the end of the buffer lifetime.
6613 *
6614 * returns the new structure.
6615 */
6616xmlBufferPtr
6617xmlBufferCreateStatic(void *mem, size_t size) {
6618 xmlBufferPtr ret;
6619
6620 if ((mem == NULL) || (size == 0))
6621 return(NULL);
6622
6623 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6624 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006625 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006626 return(NULL);
6627 }
6628 ret->use = size;
6629 ret->size = size;
6630 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6631 ret->content = (xmlChar *) mem;
6632 return(ret);
6633}
6634
6635/**
Owen Taylor3473f882001-02-23 17:55:21 +00006636 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006637 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006638 * @scheme: allocation scheme to use
6639 *
6640 * Sets the allocation scheme for this buffer
6641 */
6642void
6643xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6644 xmlBufferAllocationScheme scheme) {
6645 if (buf == NULL) {
6646#ifdef DEBUG_BUFFER
6647 xmlGenericError(xmlGenericErrorContext,
6648 "xmlBufferSetAllocationScheme: buf == NULL\n");
6649#endif
6650 return;
6651 }
Daniel Veillard53350552003-09-18 13:35:51 +00006652 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006653
6654 buf->alloc = scheme;
6655}
6656
6657/**
6658 * xmlBufferFree:
6659 * @buf: the buffer to free
6660 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006661 * Frees an XML buffer. It frees both the content and the structure which
6662 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006663 */
6664void
6665xmlBufferFree(xmlBufferPtr buf) {
6666 if (buf == NULL) {
6667#ifdef DEBUG_BUFFER
6668 xmlGenericError(xmlGenericErrorContext,
6669 "xmlBufferFree: buf == NULL\n");
6670#endif
6671 return;
6672 }
Daniel Veillard53350552003-09-18 13:35:51 +00006673
6674 if ((buf->content != NULL) &&
6675 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006676 xmlFree(buf->content);
6677 }
Owen Taylor3473f882001-02-23 17:55:21 +00006678 xmlFree(buf);
6679}
6680
6681/**
6682 * xmlBufferEmpty:
6683 * @buf: the buffer
6684 *
6685 * empty a buffer.
6686 */
6687void
6688xmlBufferEmpty(xmlBufferPtr buf) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006689 if (buf == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006690 if (buf->content == NULL) return;
6691 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006692 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006693 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006694 } else {
6695 memset(buf->content, 0, buf->size);
6696 }
Owen Taylor3473f882001-02-23 17:55:21 +00006697}
6698
6699/**
6700 * xmlBufferShrink:
6701 * @buf: the buffer to dump
6702 * @len: the number of xmlChar to remove
6703 *
6704 * Remove the beginning of an XML buffer.
6705 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006706 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006707 */
6708int
6709xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
Daniel Veillard3d97e662004-11-04 10:49:00 +00006710 if (buf == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006711 if (len == 0) return(0);
6712 if (len > buf->use) return(-1);
6713
6714 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006715 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6716 buf->content += len;
6717 } else {
6718 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6719 buf->content[buf->use] = 0;
6720 }
Owen Taylor3473f882001-02-23 17:55:21 +00006721 return(len);
6722}
6723
6724/**
6725 * xmlBufferGrow:
6726 * @buf: the buffer
6727 * @len: the minimum free size to allocate
6728 *
6729 * Grow the available space of an XML buffer.
6730 *
6731 * Returns the new available space or -1 in case of error
6732 */
6733int
6734xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6735 int size;
6736 xmlChar *newbuf;
6737
Daniel Veillard3d97e662004-11-04 10:49:00 +00006738 if (buf == NULL) return(-1);
6739
Daniel Veillard53350552003-09-18 13:35:51 +00006740 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006741 if (len + buf->use < buf->size) return(0);
6742
William M. Brack30fe43f2004-07-26 18:00:58 +00006743/*
6744 * Windows has a BIG problem on realloc timing, so we try to double
6745 * the buffer size (if that's enough) (bug 146697)
6746 */
6747#ifdef WIN32
6748 if (buf->size > len)
6749 size = buf->size * 2;
6750 else
6751 size = buf->use + len + 100;
6752#else
Owen Taylor3473f882001-02-23 17:55:21 +00006753 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00006754#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006755
6756 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006757 if (newbuf == NULL) {
6758 xmlTreeErrMemory("growing buffer");
6759 return(-1);
6760 }
Owen Taylor3473f882001-02-23 17:55:21 +00006761 buf->content = newbuf;
6762 buf->size = size;
6763 return(buf->size - buf->use);
6764}
6765
6766/**
6767 * xmlBufferDump:
6768 * @file: the file output
6769 * @buf: the buffer to dump
6770 *
6771 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006772 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006773 */
6774int
6775xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6776 int ret;
6777
6778 if (buf == NULL) {
6779#ifdef DEBUG_BUFFER
6780 xmlGenericError(xmlGenericErrorContext,
6781 "xmlBufferDump: buf == NULL\n");
6782#endif
6783 return(0);
6784 }
6785 if (buf->content == NULL) {
6786#ifdef DEBUG_BUFFER
6787 xmlGenericError(xmlGenericErrorContext,
6788 "xmlBufferDump: buf->content == NULL\n");
6789#endif
6790 return(0);
6791 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006792 if (file == NULL)
6793 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006794 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6795 return(ret);
6796}
6797
6798/**
6799 * xmlBufferContent:
6800 * @buf: the buffer
6801 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006802 * Function to extract the content of a buffer
6803 *
Owen Taylor3473f882001-02-23 17:55:21 +00006804 * Returns the internal content
6805 */
6806
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006807const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006808xmlBufferContent(const xmlBufferPtr buf)
6809{
6810 if(!buf)
6811 return NULL;
6812
6813 return buf->content;
6814}
6815
6816/**
6817 * xmlBufferLength:
6818 * @buf: the buffer
6819 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006820 * Function to get the length of a buffer
6821 *
Owen Taylor3473f882001-02-23 17:55:21 +00006822 * Returns the length of data in the internal content
6823 */
6824
6825int
6826xmlBufferLength(const xmlBufferPtr buf)
6827{
6828 if(!buf)
6829 return 0;
6830
6831 return buf->use;
6832}
6833
6834/**
6835 * xmlBufferResize:
6836 * @buf: the buffer to resize
6837 * @size: the desired size
6838 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006839 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006840 *
6841 * Returns 0 in case of problems, 1 otherwise
6842 */
6843int
6844xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6845{
6846 unsigned int newSize;
6847 xmlChar* rebuf = NULL;
6848
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006849 if (buf == NULL)
6850 return(0);
6851
Daniel Veillard53350552003-09-18 13:35:51 +00006852 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6853
Owen Taylor3473f882001-02-23 17:55:21 +00006854 /* Don't resize if we don't have to */
6855 if (size < buf->size)
6856 return 1;
6857
6858 /* figure out new size */
6859 switch (buf->alloc){
6860 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillardbf629492004-04-20 22:20:59 +00006861 /*take care of empty case*/
6862 newSize = (buf->size ? buf->size*2 : size + 10);
Owen Taylor3473f882001-02-23 17:55:21 +00006863 while (size > newSize) newSize *= 2;
6864 break;
6865 case XML_BUFFER_ALLOC_EXACT:
6866 newSize = size+10;
6867 break;
6868 default:
6869 newSize = size+10;
6870 break;
6871 }
6872
6873 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006874 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006875 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006876 rebuf = (xmlChar *) xmlRealloc(buf->content,
6877 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006878 } else {
6879 /*
6880 * if we are reallocating a buffer far from being full, it's
6881 * better to make a new allocation and copy only the used range
6882 * and free the old one.
6883 */
6884 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6885 if (rebuf != NULL) {
6886 memcpy(rebuf, buf->content, buf->use);
6887 xmlFree(buf->content);
William M. Brack42331a92004-07-29 07:07:16 +00006888 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006889 }
6890 }
Owen Taylor3473f882001-02-23 17:55:21 +00006891 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006892 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006893 return 0;
6894 }
6895 buf->content = rebuf;
6896 buf->size = newSize;
6897
6898 return 1;
6899}
6900
6901/**
6902 * xmlBufferAdd:
6903 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006904 * @str: the #xmlChar string
6905 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006906 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006907 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006908 * str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006909 *
6910 * Returns 0 successful, a positive error code number otherwise
6911 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006912 */
William M. Bracka3215c72004-07-31 16:24:01 +00006913int
Owen Taylor3473f882001-02-23 17:55:21 +00006914xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6915 unsigned int needSize;
6916
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006917 if ((str == NULL) || (buf == NULL)) {
William M. Bracka3215c72004-07-31 16:24:01 +00006918 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006919 }
William M. Bracka3215c72004-07-31 16:24:01 +00006920 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006921 if (len < -1) {
6922#ifdef DEBUG_BUFFER
6923 xmlGenericError(xmlGenericErrorContext,
6924 "xmlBufferAdd: len < 0\n");
6925#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006926 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006927 }
William M. Bracka3215c72004-07-31 16:24:01 +00006928 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006929
6930 if (len < 0)
6931 len = xmlStrlen(str);
6932
William M. Bracka3215c72004-07-31 16:24:01 +00006933 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006934
6935 needSize = buf->use + len + 2;
6936 if (needSize > buf->size){
6937 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006938 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006939 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006940 }
6941 }
6942
6943 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6944 buf->use += len;
6945 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006946 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006947}
6948
6949/**
6950 * xmlBufferAddHead:
6951 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006952 * @str: the #xmlChar string
6953 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006954 *
6955 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006956 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006957 *
6958 * Returns 0 successful, a positive error code number otherwise
6959 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006960 */
William M. Bracka3215c72004-07-31 16:24:01 +00006961int
Owen Taylor3473f882001-02-23 17:55:21 +00006962xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6963 unsigned int needSize;
6964
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006965 if (buf == NULL)
6966 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00006967 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006968 if (str == NULL) {
6969#ifdef DEBUG_BUFFER
6970 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006971 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006972#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006973 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006974 }
6975 if (len < -1) {
6976#ifdef DEBUG_BUFFER
6977 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006978 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006979#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006980 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006981 }
William M. Bracka3215c72004-07-31 16:24:01 +00006982 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006983
6984 if (len < 0)
6985 len = xmlStrlen(str);
6986
William M. Bracka3215c72004-07-31 16:24:01 +00006987 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006988
6989 needSize = buf->use + len + 2;
6990 if (needSize > buf->size){
6991 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006992 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006993 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006994 }
6995 }
6996
6997 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6998 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6999 buf->use += len;
7000 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007001 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007002}
7003
7004/**
7005 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00007006 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00007007 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00007008 *
7009 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007010 *
7011 * Returns 0 successful, a positive error code number otherwise
7012 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007013 */
William M. Bracka3215c72004-07-31 16:24:01 +00007014int
Owen Taylor3473f882001-02-23 17:55:21 +00007015xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007016 if (buf == NULL)
7017 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007018 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
7019 if (str == NULL) return -1;
7020 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00007021}
7022
7023/**
7024 * xmlBufferCCat:
7025 * @buf: the buffer to dump
7026 * @str: the C char string
7027 *
7028 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007029 *
7030 * Returns 0 successful, a positive error code number otherwise
7031 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007032 */
William M. Bracka3215c72004-07-31 16:24:01 +00007033int
Owen Taylor3473f882001-02-23 17:55:21 +00007034xmlBufferCCat(xmlBufferPtr buf, const char *str) {
7035 const char *cur;
7036
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007037 if (buf == NULL)
7038 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007039 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007040 if (str == NULL) {
7041#ifdef DEBUG_BUFFER
7042 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007043 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007044#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007045 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007046 }
7047 for (cur = str;*cur != 0;cur++) {
7048 if (buf->use + 10 >= buf->size) {
7049 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007050 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007051 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007052 }
7053 }
7054 buf->content[buf->use++] = *cur;
7055 }
7056 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007057 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007058}
7059
7060/**
7061 * xmlBufferWriteCHAR:
7062 * @buf: the XML buffer
7063 * @string: the string to add
7064 *
7065 * routine which manages and grows an output buffer. This one adds
7066 * xmlChars at the end of the buffer.
7067 */
7068void
Daniel Veillard53350552003-09-18 13:35:51 +00007069xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007070 if (buf == NULL)
7071 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007072 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007073 xmlBufferCat(buf, string);
7074}
7075
7076/**
7077 * xmlBufferWriteChar:
7078 * @buf: the XML buffer output
7079 * @string: the string to add
7080 *
7081 * routine which manage and grows an output buffer. This one add
7082 * C chars at the end of the array.
7083 */
7084void
7085xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007086 if (buf == NULL)
7087 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007088 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007089 xmlBufferCCat(buf, string);
7090}
7091
7092
7093/**
7094 * xmlBufferWriteQuotedString:
7095 * @buf: the XML buffer output
7096 * @string: the string to add
7097 *
7098 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00007099 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00007100 * quote or double-quotes internally
7101 */
7102void
7103xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00007104 const xmlChar *cur, *base;
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007105 if (buf == NULL)
7106 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007107 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00007108 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00007109 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00007110#ifdef DEBUG_BUFFER
7111 xmlGenericError(xmlGenericErrorContext,
7112 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7113#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00007114 xmlBufferCCat(buf, "\"");
7115 base = cur = string;
7116 while(*cur != 0){
7117 if(*cur == '"'){
7118 if (base != cur)
7119 xmlBufferAdd(buf, base, cur - base);
7120 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7121 cur++;
7122 base = cur;
7123 }
7124 else {
7125 cur++;
7126 }
7127 }
7128 if (base != cur)
7129 xmlBufferAdd(buf, base, cur - base);
7130 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007131 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007132 else{
7133 xmlBufferCCat(buf, "\'");
7134 xmlBufferCat(buf, string);
7135 xmlBufferCCat(buf, "\'");
7136 }
Owen Taylor3473f882001-02-23 17:55:21 +00007137 } else {
7138 xmlBufferCCat(buf, "\"");
7139 xmlBufferCat(buf, string);
7140 xmlBufferCCat(buf, "\"");
7141 }
7142}
7143
7144
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007145/**
7146 * xmlGetDocCompressMode:
7147 * @doc: the document
7148 *
7149 * get the compression ratio for a document, ZLIB based
7150 * Returns 0 (uncompressed) to 9 (max compression)
7151 */
7152int
7153xmlGetDocCompressMode (xmlDocPtr doc) {
7154 if (doc == NULL) return(-1);
7155 return(doc->compression);
7156}
7157
7158/**
7159 * xmlSetDocCompressMode:
7160 * @doc: the document
7161 * @mode: the compression ratio
7162 *
7163 * set the compression ratio for a document, ZLIB based
7164 * Correct values: 0 (uncompressed) to 9 (max compression)
7165 */
7166void
7167xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7168 if (doc == NULL) return;
7169 if (mode < 0) doc->compression = 0;
7170 else if (mode > 9) doc->compression = 9;
7171 else doc->compression = mode;
7172}
7173
7174/**
7175 * xmlGetCompressMode:
7176 *
7177 * get the default compression mode used, ZLIB based.
7178 * Returns 0 (uncompressed) to 9 (max compression)
7179 */
7180int
7181xmlGetCompressMode(void)
7182{
7183 return (xmlCompressMode);
7184}
7185
7186/**
7187 * xmlSetCompressMode:
7188 * @mode: the compression ratio
7189 *
7190 * set the default compression mode used, ZLIB based
7191 * Correct values: 0 (uncompressed) to 9 (max compression)
7192 */
7193void
7194xmlSetCompressMode(int mode) {
7195 if (mode < 0) xmlCompressMode = 0;
7196 else if (mode > 9) xmlCompressMode = 9;
7197 else xmlCompressMode = mode;
7198}
7199
Kasimier T. Buchcik4d9c9482005-06-27 15:04:46 +00007200/*
7201* xmlDOMWrapNewCtxt:
7202*
7203* Allocates and initializes a new DOM-wrapper context.
7204*
7205* Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal errror.
7206*/
7207xmlDOMWrapCtxtPtr
7208xmlDOMWrapNewCtxt(void)
7209{
7210 xmlDOMWrapCtxtPtr ret;
7211
7212 ret = xmlMalloc(sizeof(xmlDOMWrapCtxt));
7213 if (ret == NULL) {
7214 xmlTreeErrMemory("allocating DOM-wrapper context");
7215 return (NULL);
7216 }
7217 memset(ret, 0, sizeof(xmlDOMWrapCtxt));
7218 return (ret);
7219}
7220
7221/*
7222* xmlDOMWrapFreeCtxt:
7223* @ctxt: the DOM-wrapper context
7224*
7225* Frees the DOM-wrapper context.
7226*/
7227void
7228xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt)
7229{
7230 if (ctxt == NULL)
7231 return;
7232 xmlFree(ctxt);
7233}
7234
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007235#define XML_TREE_NSMAP_PARENT -1
7236#define XML_TREE_NSMAP_XML -2
7237#define XML_TREE_NSMAP_DOC -3
7238#define XML_TREE_NSMAP_CUSTOM -4
7239
7240typedef struct xmlNsMapItem *xmlNsMapItemPtr;
7241struct xmlNsMapItem {
7242 xmlNsMapItemPtr next;
7243 xmlNsMapItemPtr prev;
7244 xmlNsPtr oldNs; /* old ns decl reference */
7245 xmlNsPtr newNs; /* new ns decl reference */
7246 int shadowDepth; /* Shadowed at this depth */
7247 /*
7248 * depth:
7249 * >= 0 == @node's ns-decls
7250 * -1 == @parent's ns-decls
7251 * -2 == @parent's out-of-scope ns-decls
7252 * -3 == the doc->oldNs XML ns-decl
7253 * -4 == the doc->oldNs storage ns-decls
7254 */
7255 int depth;
7256};
7257
7258/*
7259* xmlTreeAddNsMapItem:
7260* @map: the ns-map
7261* @cur: the current map entry to append a new entry to
7262* @oldNs: the old ns-struct
7263* @newNs: the new ns-struct
7264* @depth: depth and ns-kind information
7265*
7266* Frees the ns-map
7267*/
7268static xmlNsMapItemPtr
7269xmlDOMWrapNSNormAddNsMapItem(xmlNsMapItemPtr *map,
7270 xmlNsMapItemPtr *cur,
7271 xmlNsPtr oldNs,
7272 xmlNsPtr newNs,
7273 int depth)
7274{
7275 xmlNsMapItemPtr ret;
7276
7277 if ((cur != NULL) && (*cur != NULL) && ((*cur)->next != NULL)) {
7278 /*
7279 * Reuse.
7280 */
7281 ret = (*cur)->next;
7282 *cur = ret;
7283 } else {
7284 ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem));
7285 if (ret == NULL) {
7286 xmlTreeErrMemory("allocating namespace map item");
7287 return (NULL);
7288 }
7289 memset(ret, 0, sizeof(struct xmlNsMapItem));
7290 if (*map == NULL) {
7291 /*
7292 * First ever.
7293 */
7294 *map = ret;
7295 ret->prev = ret;
7296 if (cur != NULL)
7297 *cur = ret;
7298 } else {
7299 if (cur) {
7300 /*
7301 * Append.
7302 */
7303 (*cur)->next = ret;
7304 ret->prev = *cur;
7305 *cur = ret;
7306 } else {
7307 /*
7308 * Set on first position.
7309 */
7310 ret->next = (*map);
7311 ret->prev = (*map)->prev;
7312 (*map)->prev = ret;
7313 *map = ret;
7314 }
7315 }
7316 }
7317 ret->oldNs = oldNs;
7318 ret->newNs = newNs;
7319 ret->shadowDepth = -1;
7320 ret->depth = depth;
7321 return (ret);
7322}
7323
7324/*
7325* xmlTreeFreeNsMap:
7326* @map: the ns-map
7327*
7328* Frees the ns-map
7329*/
7330static void
7331xmlDOMWrapNSNormFreeNsMap(xmlNsMapItemPtr map)
7332{
7333 xmlNsMapItemPtr mi = map, miprev;
7334
7335 while (mi != NULL) {
7336 miprev = mi;
7337 mi = mi->next;
7338 xmlFree(miprev);
7339 }
7340}
7341
7342/*
7343* xmlTreeEnsureXMLDecl:
7344* @doc: the doc
7345*
7346* Ensures that there is an XML namespace declaration on the doc.
7347*
7348* Returns the XML ns-struct or NULL on API and internal errors.
7349*/
7350static xmlNsPtr
7351xmlTreeEnsureXMLDecl(xmlDocPtr doc)
7352{
7353 if (doc == NULL)
7354 return (NULL);
7355 if (doc->oldNs != NULL)
7356 return (doc->oldNs);
7357 {
7358 xmlNsPtr ns;
7359 ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
7360 if (ns == NULL) {
7361 xmlTreeErrMemory(
7362 "allocating the XML namespace");
7363 return (NULL);
7364 }
7365 memset(ns, 0, sizeof(xmlNs));
7366 ns->type = XML_LOCAL_NAMESPACE;
7367 ns->href = xmlStrdup(XML_XML_NAMESPACE);
7368 ns->prefix = xmlStrdup((const xmlChar *)"xml");
7369 doc->oldNs = ns;
7370 return (ns);
7371 }
7372}
7373
7374/*
7375* xmlDOMWrapStoreNs:
7376* @doc: the doc
7377* @nsName: the namespace name
7378* @prefix: the prefix
7379*
7380* Creates or reuses an xmlNs struct on doc->oldNs with
7381* the given prefix and namespace name.
7382*
7383* Returns the aquired ns struct or NULL in case of an API
7384* or internal error.
7385*/
7386static xmlNsPtr
7387xmlDOMWrapStoreNs(xmlDocPtr doc,
7388 const xmlChar *nsName,
7389 const xmlChar *prefix)
7390{
7391 xmlNsPtr ns;
7392
7393 if (doc == NULL)
7394 return (NULL);
7395 ns = xmlTreeEnsureXMLDecl(doc);
7396 if (ns == NULL)
7397 return (NULL);
7398 if (ns->next != NULL) {
7399 /* Reuse. */
7400 ns = ns->next;
7401 while (ns != NULL) {
7402 if (((ns->prefix == prefix) ||
7403 xmlStrEqual(ns->prefix, prefix)) &&
7404 xmlStrEqual(ns->href, nsName)) {
7405 return (ns);
7406 }
7407 if (ns->next == NULL)
7408 break;
7409 ns = ns->next;
7410 }
7411 }
7412 /* Create. */
7413 ns->next = xmlNewNs(NULL, nsName, prefix);
7414 return (ns->next);
7415}
7416
7417/*
7418* xmlTreeLookupNsListByPrefix:
7419* @nsList: a list of ns-structs
7420* @prefix: the searched prefix
7421*
7422* Searches for a ns-decl with the given prefix in @nsList.
7423*
7424* Returns the ns-decl if found, NULL if not found and on
7425* API errors.
7426*/
7427static xmlNsPtr
7428xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix)
7429{
7430 if (nsList == NULL)
7431 return (NULL);
7432 {
7433 xmlNsPtr ns;
7434 ns = nsList;
7435 do {
7436 if ((prefix == ns->prefix) ||
7437 xmlStrEqual(prefix, ns->prefix)) {
7438 return (ns);
7439 }
7440 ns = ns->next;
7441 } while (ns != NULL);
7442 }
7443 return (NULL);
7444}
7445
7446/*
7447*
7448* xmlTreeGetInScopeNamespaces:
7449* @map: the namespace map
7450* @node: the node to start with
7451*
7452* Puts in-scope namespaces into the ns-map.
7453*
7454* Returns 0 on success, -1 on API or internal errors.
7455*/
7456static int
7457xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapItemPtr *map,
7458 xmlNodePtr node)
7459{
7460 xmlNodePtr cur;
7461 xmlNsPtr ns;
7462 xmlNsMapItemPtr mi;
7463 int shadowed;
7464
7465 if ((map == NULL) || (*map != NULL))
7466 return (-1);
7467 /*
7468 * Get in-scope ns-decls of @parent.
7469 */
7470 cur = node;
7471 while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) {
7472 if (cur->type == XML_ELEMENT_NODE) {
7473 if (cur->nsDef != NULL) {
7474 ns = cur->nsDef;
7475 do {
7476 shadowed = 0;
7477 if (*map != NULL) {
7478 /*
7479 * Skip shadowed prefixes.
7480 */
7481 for (mi = *map; mi != NULL; mi = mi->next) {
7482 if ((ns->prefix == mi->newNs->prefix) ||
7483 xmlStrEqual(ns->prefix, mi->newNs->prefix)) {
7484 shadowed = 1;
7485 break;
7486 }
7487 }
7488 }
7489 /*
7490 * Insert mapping.
7491 */
7492 mi = xmlDOMWrapNSNormAddNsMapItem(map, NULL, NULL,
7493 ns, XML_TREE_NSMAP_PARENT);
7494 if (mi == NULL)
7495 return (-1);
7496 if (shadowed)
7497 mi->shadowDepth = 0;
7498 ns = ns->next;
7499 } while (ns != NULL);
7500 }
7501 }
7502 cur = cur->parent;
7503 }
7504 return (0);
7505}
7506
7507/*
7508* XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict;
7509* otherwise copy it, when it was in the source-dict.
7510*/
7511#define XML_TREE_ADOPT_STR(str) \
7512 if (adoptStr && (str != NULL)) { \
7513 if (destDoc->dict) { \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00007514 const xmlChar *old = str; \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007515 str = xmlDictLookup(destDoc->dict, str, -1); \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00007516 if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \
7517 (!xmlDictOwns(sourceDoc->dict, old))) \
Daniel Veillard39e5c892005-07-03 22:48:50 +00007518 xmlFree((char *)old); \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007519 } else if ((sourceDoc) && (sourceDoc->dict) && \
7520 xmlDictOwns(sourceDoc->dict, str)) { \
7521 str = BAD_CAST xmlStrdup(str); \
7522 } \
7523 }
7524
7525/*
7526* XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then
7527* put it in dest-dict or copy it.
7528*/
7529#define XML_TREE_ADOPT_STR_2(str) \
7530 if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \
7531 (sourceDoc->dict != NULL) && \
7532 xmlDictOwns(sourceDoc->dict, cur->content)) { \
7533 if (destDoc->dict) \
7534 cur->content = (xmlChar *) \
7535 xmlDictLookup(destDoc->dict, cur->content, -1); \
7536 else \
7537 cur->content = xmlStrdup(BAD_CAST cur->content); \
7538 }
7539
7540/*
7541* xmlDOMWrapNSNormAddNsMapItem2:
7542*
7543* For internal use. Adds a ns-decl mapping.
7544*
7545* Returns 0 on success, -1 on internal errors.
7546*/
7547static int
7548xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number,
7549 xmlNsPtr oldNs, xmlNsPtr newNs)
7550{
7551 if (*list == NULL) {
7552 *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr));
7553 if (*list == NULL) {
7554 xmlTreeErrMemory("alloc ns map item");
7555 return(-1);
7556 }
7557 *size = 3;
7558 *number = 0;
7559 } else if ((*number) >= (*size)) {
7560 *size *= 2;
7561 *list = (xmlNsPtr *) xmlRealloc(*list,
7562 (*size) * 2 * sizeof(xmlNsPtr));
7563 if (*list == NULL) {
7564 xmlTreeErrMemory("realloc ns map item");
7565 return(-1);
7566 }
7567 }
7568 (*list)[2 * (*number)] = oldNs;
7569 (*list)[2 * (*number) +1] = newNs;
7570 (*number)++;
7571 return (0);
7572}
7573
7574/*
7575* xmlDOMWrapRemoveNode:
Daniel Veillard304e78c2005-07-03 16:19:41 +00007576* @ctxt: a DOM wrapper context
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007577* @doc: the doc
7578* @node: the node to be removed.
Daniel Veillard304e78c2005-07-03 16:19:41 +00007579* @options: set of options, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007580*
7581* Unlinks the given node from its owner.
7582* This will substitute ns-references to node->nsDef for
7583* ns-references to doc->oldNs, thus ensuring the removed
7584* branch to be autark wrt ns-references.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00007585* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007586*
7587* Returns 0 on success, 1 if the node is not supported,
7588* -1 on API and internal errors.
7589*/
7590int
7591xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc,
7592 xmlNodePtr node, int options ATTRIBUTE_UNUSED)
7593{
7594 xmlNsPtr *list = NULL;
7595 int sizeList, nbList, i, j;
7596 xmlNsPtr ns;
7597
7598 if ((node == NULL) || (doc == NULL) || (node->doc != doc))
7599 return (-1);
7600
7601 /* TODO: 0 or -1 ? */
7602 if (node->parent == NULL)
7603 return (0);
7604
7605 switch (node->type) {
7606 case XML_TEXT_NODE:
7607 case XML_CDATA_SECTION_NODE:
7608 case XML_ENTITY_REF_NODE:
7609 case XML_PI_NODE:
7610 case XML_COMMENT_NODE:
7611 xmlUnlinkNode(node);
7612 return (0);
7613 case XML_ELEMENT_NODE:
7614 case XML_ATTRIBUTE_NODE:
7615 break;
7616 default:
7617 return (1);
7618 }
7619 xmlUnlinkNode(node);
7620 /*
7621 * Save out-of-scope ns-references in doc->oldNs.
7622 */
7623 do {
7624 switch (node->type) {
7625 case XML_ELEMENT_NODE:
7626 if ((ctxt == NULL) && (node->nsDef != NULL)) {
7627 ns = node->nsDef;
7628 do {
7629 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
7630 &nbList, ns, ns) == -1)
7631 goto internal_error;
7632 ns = ns->next;
7633 } while (ns != NULL);
7634 }
7635 /* No break on purpose. */
7636 case XML_ATTRIBUTE_NODE:
7637 if (node->ns != NULL) {
7638 /*
7639 * Find a mapping.
7640 */
7641 if (list != NULL) {
7642 for (i = 0, j = 0; i < nbList; i++, j += 2) {
7643 if (node->ns == list[j]) {
7644 node->ns = list[++j];
7645 goto next_node;
7646 }
7647 }
7648 }
7649 ns = NULL;
7650 if (ctxt != NULL) {
7651 /*
7652 * User defined.
7653 */
7654 } else {
7655 /*
7656 * Add to doc's oldNs.
7657 */
7658 ns = xmlDOMWrapStoreNs(doc, node->ns->href,
7659 node->ns->prefix);
7660 if (ns == NULL)
7661 goto internal_error;
7662 }
7663 if (ns != NULL) {
7664 /*
7665 * Add mapping.
7666 */
7667 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
7668 &nbList, node->ns, ns) == -1)
7669 goto internal_error;
7670 }
7671 node->ns = ns;
7672 }
7673 if ((node->type == XML_ELEMENT_NODE) &&
7674 (node->properties != NULL)) {
7675 node = (xmlNodePtr) node->properties;
7676 continue;
7677 }
7678 break;
7679 default:
7680 goto next_sibling;
7681 }
7682next_node:
7683 if ((node->type == XML_ELEMENT_NODE) &&
7684 (node->children != NULL)) {
7685 node = node->children;
7686 continue;
7687 }
7688next_sibling:
7689 if (node == NULL)
7690 break;
7691 if (node->next != NULL)
7692 node = node->next;
7693 else {
7694 node = node->parent;
7695 goto next_sibling;
7696 }
7697 } while (node != NULL);
7698
7699 if (list != NULL)
7700 xmlFree(list);
7701 return (0);
7702
7703internal_error:
7704 if (list != NULL)
7705 xmlFree(list);
7706 return (-1);
7707}
7708
7709/*
7710* xmlSearchNsByHrefStrict:
7711* @doc: the document
7712* @node: the start node
7713* @nsName: the searched namespace name
7714* @retNs: the resulting ns-decl
7715* @prefixed: if the found ns-decl must have a prefix (for attributes)
7716*
7717* Dynamically searches for a ns-declaration which matches
7718* the given @nsName in the ancestor-or-self axis of @node.
7719*
7720* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7721* and internal errors.
7722*/
7723static int
7724xmlSearchNsByHrefStrict(xmlDocPtr doc, xmlNodePtr node, const xmlChar* nsName,
7725 xmlNsPtr *retNs, int prefixed)
7726{
7727 xmlNodePtr cur, prev = NULL, out = NULL;
7728 xmlNsPtr ns, prevns;
7729
7730 if ((doc == NULL) || (nsName == NULL) || (retNs == NULL))
7731 return (-1);
7732
7733 *retNs = NULL;
7734 if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
7735 *retNs = xmlTreeEnsureXMLDecl(doc);
7736 if (*retNs == NULL)
7737 return (-1);
7738 return (1);
7739 }
7740 cur = node;
7741 do {
7742 if (cur->type == XML_ELEMENT_NODE) {
7743 if (cur->nsDef != NULL) {
7744 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
7745 if (prefixed && (ns->prefix == NULL))
7746 continue;
7747 if (prev != NULL) {
7748 /*
7749 * Check the last level of ns-decls for a
7750 * shadowing prefix.
7751 */
7752 prevns = prev->nsDef;
7753 do {
7754 if ((prevns->prefix == ns->prefix) ||
7755 ((prevns->prefix != NULL) &&
7756 (ns->prefix != NULL) &&
7757 xmlStrEqual(prevns->prefix, ns->prefix))) {
7758 /*
7759 * Shadowed.
7760 */
7761 break;
7762 }
7763 prevns = prevns->next;
7764 } while (prevns != NULL);
7765 if (prevns != NULL)
7766 continue;
7767 }
7768 /*
7769 * Ns-name comparison.
7770 */
7771 if ((nsName == ns->href) ||
7772 xmlStrEqual(nsName, ns->href)) {
7773 /*
7774 * At this point the prefix can only be shadowed,
7775 * if we are the the (at least) 3rd level of
7776 * ns-decls.
7777 */
7778 if (out) {
7779 int ret;
7780
7781 ret = xmlNsInScope(doc, node, prev, ns->prefix);
7782 if (ret < 0)
7783 return (-1);
7784 /*
7785 * TODO: Should we try to find a matching ns-name
7786 * only once? This here keeps on searching.
7787 * I think we should try further since, there might
7788 * be an other matching ns-decl with an unshadowed
7789 * prefix.
7790 */
7791 if (! ret)
7792 continue;
7793 }
7794 *retNs = ns;
7795 return (1);
7796 }
7797 }
7798 out = prev;
7799 prev = cur;
7800 }
7801 } else if ((node->type == XML_ENTITY_REF_NODE) ||
7802 (node->type == XML_ENTITY_NODE) ||
7803 (node->type == XML_ENTITY_DECL))
7804 return (0);
7805 cur = cur->parent;
7806 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
7807 return (0);
7808}
7809
7810/*
7811* xmlDOMWrapNSNormDeclareNsForced:
7812* @doc: the doc
7813* @elem: the element-node to declare on
7814* @nsName: the namespace-name of the ns-decl
7815* @prefix: the preferred prefix of the ns-decl
7816* @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls
7817*
7818* Declares a new namespace on @elem. It tries to use the
7819* given @prefix; if a ns-decl with the given prefix is already existent
7820* on @elem, it will generate an other prefix.
7821*
7822* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7823* and internal errors.
7824*/
7825static xmlNsPtr
7826xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc,
7827 xmlNodePtr elem,
7828 const xmlChar *nsName,
7829 const xmlChar *prefix,
7830 int checkShadow)
7831{
7832
7833 xmlNsPtr ret;
7834 char buf[50];
7835 const xmlChar *pref;
7836 int counter = 0;
7837 /*
7838 * Create a ns-decl on @anchor.
7839 */
7840 pref = prefix;
7841 while (1) {
7842 /*
7843 * Lookup whether the prefix is unused in elem's ns-decls.
7844 */
7845 if ((elem->nsDef != NULL) &&
7846 (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL))
7847 goto ns_next_prefix;
7848 if (checkShadow && elem->parent &&
7849 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
7850 /*
7851 * Does it shadow ancestor ns-decls?
7852 */
7853 if (xmlSearchNs(doc, elem->parent, pref) != NULL)
7854 goto ns_next_prefix;
7855 }
7856 ret = xmlNewNs(NULL, nsName, pref);
7857 if (ret == NULL)
7858 return (NULL);
7859 if (elem->nsDef == NULL)
7860 elem->nsDef = ret;
7861 else {
7862 xmlNsPtr ns2 = elem->nsDef;
7863 while (ns2->next != NULL)
7864 ns2 = ns2->next;
7865 ns2->next = ret;
7866 }
7867 return (ret);
7868ns_next_prefix:
7869 counter++;
7870 if (counter > 1000)
7871 return (NULL);
7872 if (prefix == NULL) {
7873 snprintf((char *) buf, sizeof(buf),
7874 "default%d", counter);
7875 } else
7876 snprintf((char *) buf, sizeof(buf),
7877 "%.30s%d", (char *)prefix, counter);
7878 pref = BAD_CAST buf;
7879 }
7880}
7881
7882/*
7883* xmlDOMWrapNSNormAquireNormalizedNs:
7884* @doc: the doc
7885* @elem: the element-node to declare namespaces on
7886* @ns: the ns-struct to use for the search
7887* @retNs: the found/created ns-struct
7888* @nsMap: the ns-map
7889* @topmi: the last ns-map entry
7890* @depth: the current tree depth
7891* @ancestorsOnly: search in ancestor ns-decls only
7892* @prefixed: if the searched ns-decl must have a prefix (for attributes)
7893*
7894* Searches for a matching ns-name in the ns-decls of @nsMap, if not
7895* found it will either declare it on @elem, or store it in doc->oldNs.
7896* If a new ns-decl needs to be declared on @elem, it tries to use the
7897* @ns->prefix for it, if this prefix is already in use on @elem, it will
7898* change the prefix or the new ns-decl.
7899*
7900* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
7901*/
7902static int
7903xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc,
7904 xmlNodePtr elem,
7905 xmlNsPtr ns,
7906 xmlNsPtr *retNs,
7907 xmlNsMapItemPtr *nsMap,
7908 xmlNsMapItemPtr *topmi,
7909 int depth,
7910 int ancestorsOnly,
7911 int prefixed)
7912{
7913 xmlNsMapItemPtr mi;
7914
7915 if ((doc == NULL) || (ns == NULL) || (retNs == NULL) ||
7916 (nsMap == NULL) || (topmi == NULL))
7917 return (-1);
7918
7919 *retNs = NULL;
7920 /*
7921 * Handle XML namespace.
7922 */
7923 if ((ns->prefix) &&
7924 (ns->prefix[0] == 'x') &&
7925 (ns->prefix[1] == 'm') &&
7926 (ns->prefix[2] == 'l') &&
7927 (ns->prefix[3] == 0)) {
7928 /*
7929 * Insert XML namespace mapping.
7930 */
7931 *retNs = xmlTreeEnsureXMLDecl(doc);
7932 if (*retNs == NULL)
7933 return (-1);
7934 return (0);
7935 }
7936 /*
7937 * If the search should be done in ancestors only and no
7938 * @elem (the first ancestor) was specified, then skip the search.
7939 */
7940 if ((! (ancestorsOnly && (elem == NULL))) &&
7941 (*nsMap != NULL)) {
7942
7943 /*
7944 * Try to find an equal ns-name in in-scope ns-decls.
7945 */
7946 for (mi = *nsMap; mi != (*topmi)->next; mi = mi->next) {
7947
7948 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
7949 /*
7950 * This should be turned on to gain speed, if one knows
7951 * that the branch itself was already ns-wellformed and no
7952 * stale references existed. I.e. it searches in the ancestor
7953 * axis only.
7954 */
7955 ((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) &&
7956 /* Skip shadowed prefixes. */
7957 (mi->shadowDepth == -1) &&
7958 /* Skip xmlns="" or xmlns:foo="". */
7959 ((mi->newNs->href != NULL) &&
7960 (mi->newNs->href[0] != 0)) &&
7961 /* Ensure a prefix if wanted. */
7962 ((! prefixed) || (mi->newNs->prefix != NULL)) &&
7963 /* Equal ns name */
7964 ((mi->newNs->href == ns->href) ||
7965 xmlStrEqual(mi->newNs->href, ns->href))) {
7966 /* Set the mapping. */
7967 mi->oldNs = ns;
7968 *retNs = mi->newNs;
7969 return (0);
7970 }
7971 }
7972 }
7973 /*
7974 * No luck, the namespace is out of scope or shadowed.
7975 */
7976 if (elem == NULL) {
7977 xmlNsPtr tmpns;
7978
7979 /*
7980 * Store ns-decls in "oldNs" of the document-node.
7981 */
7982 tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix);
7983 if (tmpns == NULL)
7984 return (-1);
7985 /*
7986 * Insert mapping.
7987 */
7988 if (xmlDOMWrapNSNormAddNsMapItem(nsMap, NULL, ns,
7989 tmpns, XML_TREE_NSMAP_DOC) == NULL) {
7990 xmlFreeNs(tmpns);
7991 return (-1);
7992 }
7993 *retNs = tmpns;
7994 } else {
7995 xmlNsPtr tmpns;
7996
7997 tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href,
7998 ns->prefix, 0);
7999 if (tmpns == NULL)
8000 return (-1);
8001
8002 if (*nsMap != NULL) {
8003 /*
8004 * Does it shadow ancestor ns-decls?
8005 */
8006 for (mi = *nsMap; mi != (*topmi)->next; mi = mi->next) {
8007 if ((mi->depth < depth) &&
8008 (mi->shadowDepth == -1) &&
8009 ((ns->prefix == mi->newNs->prefix) ||
8010 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8011 /*
8012 * Shadows.
8013 */
8014 mi->shadowDepth = depth;
8015 break;
8016 }
8017 }
8018 }
8019 if (xmlDOMWrapNSNormAddNsMapItem(nsMap, topmi, ns,
8020 tmpns, depth) == NULL) {
8021 xmlFreeNs(tmpns);
8022 return (-1);
8023 }
8024 *retNs = tmpns;
8025 }
8026 return (0);
8027}
8028
8029/*
8030* xmlDOMWrapReconcileNamespaces:
Daniel Veillard304e78c2005-07-03 16:19:41 +00008031* @ctxt: DOM wrapper context, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008032* @elem: the element-node
8033* @options: option flags
8034*
8035* Ensures that ns-references point to ns-decls hold on element-nodes.
8036* Ensures that the tree is namespace wellformed by creating additional
8037* ns-decls where needed. Note that, since prefixes of already existent
8038* ns-decls can be shadowed by this process, it could break QNames in
8039* attribute values or element content.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00008040* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008041*
8042* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8043*/
8044int
8045xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,
8046 xmlNodePtr elem,
8047 int options ATTRIBUTE_UNUSED)
8048{
8049 int depth = -1, adoptns = 0, parnsdone = 0;
8050 xmlNsPtr ns;
8051 xmlDocPtr doc;
8052 xmlNodePtr cur, curElem = NULL;
8053 xmlNsMapItemPtr nsMap = NULL, topmi = NULL, mi;
8054 /* @ancestorsOnly should be set by an option flag. */
8055 int ancestorsOnly = 0;
8056
8057 if ((elem == NULL) || (elem->doc == NULL) ||
8058 (elem->type != XML_ELEMENT_NODE))
8059 return (-1);
8060
8061 doc = elem->doc;
8062 cur = elem;
8063 do {
8064 switch (cur->type) {
8065 case XML_ELEMENT_NODE:
8066 adoptns = 1;
8067 curElem = cur;
8068 depth++;
8069 /*
8070 * Namespace declarations.
8071 */
8072 if (cur->nsDef != NULL) {
8073 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8074 if (! parnsdone) {
8075 if ((elem->parent) &&
8076 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8077 /*
8078 * Gather ancestor in-scope ns-decls.
8079 */
8080 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8081 elem->parent) == -1)
8082 goto internal_error;
8083 if (nsMap != NULL)
8084 topmi = nsMap->prev;
8085 }
8086 parnsdone = 1;
8087 }
8088 /*
8089 * Skip ns-references handling if the referenced
8090 * ns-decl is declared on the same element.
8091 */
8092 if ((cur->ns != NULL) && adoptns && (cur->ns == ns))
8093 adoptns = 0;
8094 /*
8095 * Does it shadow any ns-decl?
8096 */
8097 if (nsMap) {
8098 for (mi = nsMap; mi != topmi->next; mi = mi->next) {
8099 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8100 (mi->shadowDepth == -1) &&
8101 ((ns->prefix == mi->newNs->prefix) ||
8102 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8103
8104 mi->shadowDepth = depth;
8105 }
8106 }
8107 }
8108 /*
8109 * Push mapping.
8110 */
8111 if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi, ns, ns,
8112 depth) == NULL)
8113 goto internal_error;
8114 }
8115 }
8116 if (! adoptns)
8117 goto ns_end;
8118
8119 /* No break on purpose. */
8120 case XML_ATTRIBUTE_NODE:
8121 if (cur->ns == NULL)
8122 goto ns_end;
8123 if (! parnsdone) {
8124 if ((elem->parent) &&
8125 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8126 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8127 elem->parent) == -1)
8128 goto internal_error;
8129 if (nsMap != NULL)
8130 topmi = nsMap->prev;
8131 }
8132 parnsdone = 1;
8133 }
8134 /*
8135 * Adopt ns-references.
8136 */
8137 if (nsMap != NULL) {
8138 /*
8139 * Search for a mapping.
8140 */
8141 for (mi = nsMap; mi != topmi->next; mi = mi->next) {
8142 if ((mi->shadowDepth == -1) &&
8143 (cur->ns == mi->oldNs)) {
8144
8145 cur->ns = mi->newNs;
8146 goto ns_end;
8147 }
8148 }
8149 }
8150 /*
8151 * Aquire a normalized ns-decl and add it to the map.
8152 */
8153 if (xmlDOMWrapNSNormAquireNormalizedNs(doc, curElem,
8154 cur->ns, &ns,
8155 &nsMap, &topmi, depth,
8156 ancestorsOnly,
8157 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8158 goto internal_error;
8159 cur->ns = ns;
8160
8161ns_end:
8162 if ((cur->type == XML_ELEMENT_NODE) &&
8163 (cur->properties != NULL)) {
8164 /*
8165 * Process attributes.
8166 */
8167 cur = (xmlNodePtr) cur->properties;
8168 continue;
8169 }
8170 break;
8171 default:
8172 goto next_sibling;
8173 }
8174 if ((cur->type == XML_ELEMENT_NODE) &&
8175 (cur->children != NULL)) {
8176 /*
8177 * Process content of element-nodes only.
8178 */
8179 cur = cur->children;
8180 continue;
8181 }
8182next_sibling:
8183 if (cur == elem)
8184 break;
8185 if (cur->type == XML_ELEMENT_NODE) {
8186 if (nsMap != NULL) {
8187 /*
8188 * Pop mappings.
8189 */
8190 while ((topmi->depth >= 0) && (topmi->depth >= depth))
8191 topmi = topmi->prev;
8192 /*
8193 * Unshadow.
8194 */
8195 for (mi = nsMap; mi != topmi->next; mi = mi->next)
8196 if (mi->shadowDepth >= depth)
8197 mi->shadowDepth = -1;
8198 }
8199 depth--;
8200 }
8201 if (cur->next != NULL)
8202 cur = cur->next;
8203 else {
8204 cur = cur->parent;
8205 goto next_sibling;
8206 }
8207 } while (cur != NULL);
8208
8209 if (nsMap != NULL)
8210 xmlDOMWrapNSNormFreeNsMap(nsMap);
8211 return (0);
8212internal_error:
8213 if (nsMap != NULL)
8214 xmlDOMWrapNSNormFreeNsMap(nsMap);
8215 return (-1);
8216}
8217
8218/*
8219* xmlDOMWrapAdoptBranch:
8220* @ctxt: the optional context for custom processing
8221* @sourceDoc: the optional sourceDoc
8222* @node: the element-node to start with
8223* @destDoc: the destination doc for adoption
8224* @parent: the optional new parent of @node in @destDoc
8225* @options: option flags
8226*
8227* Ensures that ns-references point to @destDoc: either to
8228* elements->nsDef entries if @destParent is given, or to
8229* @destDoc->oldNs otherwise.
8230* If @destParent is given, it ensures that the tree is namespace
8231* wellformed by creating additional ns-decls where needed.
8232* Note that, since prefixes of already existent ns-decls can be
8233* shadowed by this process, it could break QNames in attribute
8234* values or element content.
8235*
8236* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8237*/
8238static int
8239xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
8240 xmlDocPtr sourceDoc,
8241 xmlNodePtr node,
8242 xmlDocPtr destDoc,
8243 xmlNodePtr destParent,
8244 int options ATTRIBUTE_UNUSED)
8245{
8246 int ret = 0;
8247 xmlNodePtr cur, curElem = NULL;
8248 xmlNsMapItemPtr nsMap = NULL, topmi = NULL, mi;
8249 xmlNsPtr ns;
8250 int depth = -1, adoptStr = 1;
8251 /* gather @parent's ns-decls. */
8252 int parnsdone = 0;
8253 /* @ancestorsOnly should be set per option. */
8254 int ancestorsOnly = 0;
8255
8256 /*
8257 * Optimize string adoption for equal or none dicts.
8258 */
8259 if ((sourceDoc != NULL) &&
8260 (sourceDoc->dict == destDoc->dict))
8261 adoptStr = 0;
8262 else
8263 adoptStr = 1;
8264
8265 cur = node;
8266 while (cur != NULL) {
8267 if (cur->doc != sourceDoc) {
8268 /*
8269 * We'll assume XIncluded nodes if the doc differs.
8270 * TODO: Do we need to reconciliate XIncluded nodes?
8271 * This here skips XIncluded nodes and tries to handle
8272 * broken sequences.
8273 */
8274 if (cur->next == NULL)
8275 goto leave_node;
8276 do {
8277 cur = cur->next;
8278 if ((cur->type == XML_XINCLUDE_END) ||
8279 (cur->doc == node->doc))
8280 break;
8281 } while (cur->next != NULL);
8282
8283 if (cur->doc != node->doc)
8284 goto leave_node;
8285 }
8286 cur->doc = destDoc;
8287 switch (cur->type) {
8288 case XML_XINCLUDE_START:
8289 case XML_XINCLUDE_END:
8290 /*
8291 * TODO
8292 */
8293 return (-1);
8294 case XML_ELEMENT_NODE:
8295 curElem = cur;
8296 depth++;
8297 /*
8298 * Namespace declarations.
8299 */
8300 if ((ctxt == NULL) && (cur->nsDef != NULL)) {
8301 if (! parnsdone) {
8302 if (destParent && (ctxt == NULL)) {
8303 /*
8304 * Gather @parent's in-scope ns-decls.
8305 */
8306 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8307 destParent) == -1)
8308 goto internal_error;
8309 if (nsMap != NULL)
8310 topmi = nsMap->prev;
8311 }
8312 parnsdone = 1;
8313 }
8314 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8315 /*
8316 * ns->prefix and ns->href seem not to be in the dict.
8317 * XML_TREE_ADOPT_STR(ns->prefix)
8318 * XML_TREE_ADOPT_STR(ns->href)
8319 */
8320 /*
8321 * Does it shadow any ns-decl?
8322 */
8323 if (nsMap) {
8324 for (mi = nsMap; mi != topmi->next;
8325 mi = mi->next) {
8326 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8327 (mi->shadowDepth == -1) &&
8328 ((ns->prefix == mi->newNs->prefix) ||
8329 xmlStrEqual(ns->prefix,
8330 mi->newNs->prefix))) {
8331
8332 mi->shadowDepth = depth;
8333 }
8334 }
8335 }
8336 /*
8337 * Push mapping.
8338 */
8339 if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi,
8340 ns, ns, depth) == NULL)
8341 goto internal_error;
8342 }
8343 }
8344 /* No break on purpose. */
8345 case XML_ATTRIBUTE_NODE:
8346
8347 if (cur->ns == NULL)
8348 goto ns_end;
8349 if (! parnsdone) {
8350 if (destParent && (ctxt == NULL)) {
8351 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8352 destParent) == -1)
8353 goto internal_error;
8354 if (nsMap != NULL)
8355 topmi = nsMap->prev;
8356 }
8357 parnsdone = 1;
8358 }
8359 /*
8360 * Adopt ns-references.
8361 */
8362 if (nsMap != NULL) {
8363 /*
8364 * Search for a mapping.
8365 */
8366 for (mi = nsMap; mi != topmi->next; mi = mi->next) {
8367 if ((mi->shadowDepth == -1) &&
8368 (cur->ns == mi->oldNs)) {
8369
8370 cur->ns = mi->newNs;
8371 goto ns_end;
8372 }
8373 }
8374 }
8375 /*
8376 * Start searching for an in-scope ns-decl.
8377 */
8378 if (ctxt != NULL) {
8379 /*
8380 * User-defined behaviour.
8381 */
8382#if 0
8383 ctxt->aquireNsDecl(ctxt, cur->ns, &ns);
8384#endif
8385 /*
8386 * Insert mapping if ns is available; it's the users fault
8387 * if not.
8388 */
8389 if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi,
8390 ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
8391 goto internal_error;
8392 cur->ns = ns;
8393 } else {
8394 /*
8395 * Aquire a normalized ns-decl and add it to the map.
8396 */
8397 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
8398 /* ns-decls on curElem or on destDoc->oldNs */
8399 destParent ? curElem : NULL,
8400 cur->ns, &ns,
8401 &nsMap, &topmi, depth,
8402 ancestorsOnly,
8403 /* ns-decls must be prefixed for attributes. */
8404 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8405 goto internal_error;
8406 cur->ns = ns;
8407 }
8408ns_end:
8409 /*
8410 * Further node properties.
8411 * TODO: Is this all?
8412 */
8413 XML_TREE_ADOPT_STR(cur->name)
8414 if (cur->type == XML_ELEMENT_NODE) {
8415 cur->psvi = NULL;
8416 cur->line = 0;
8417 cur->extra = 0;
8418 /*
8419 * Walk attributes.
8420 */
8421 if (cur->properties != NULL) {
8422 /*
8423 * Process first attribute node.
8424 */
8425 cur = (xmlNodePtr) cur->properties;
8426 continue;
8427 }
8428 } else {
8429 /*
8430 * Attributes.
8431 */
8432 if ((sourceDoc != NULL) &&
8433 (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID))
8434 xmlRemoveID(sourceDoc, (xmlAttrPtr) cur);
8435 ((xmlAttrPtr) cur)->atype = 0;
8436 ((xmlAttrPtr) cur)->psvi = NULL;
8437 }
8438 break;
8439 case XML_TEXT_NODE:
8440 case XML_CDATA_SECTION_NODE:
8441 /*
8442 * This puts the content in the dest dict, only if
8443 * it was previously in the source dict.
8444 */
8445 XML_TREE_ADOPT_STR_2(cur->content)
8446 goto leave_node;
8447 case XML_ENTITY_REF_NODE:
8448 /*
8449 * Remove reference to the entitity-node.
8450 */
8451 cur->content = NULL;
8452 cur->children = NULL;
8453 cur->last = NULL;
8454 if ((destDoc->intSubset) || (destDoc->extSubset)) {
8455 xmlEntityPtr ent;
8456 /*
8457 * Assign new entity-node if available.
8458 */
8459 ent = xmlGetDocEntity(destDoc, cur->name);
8460 if (ent != NULL) {
8461 cur->content = ent->content;
8462 cur->children = (xmlNodePtr) ent;
8463 cur->last = (xmlNodePtr) ent;
8464 }
8465 }
8466 goto leave_node;
8467 case XML_PI_NODE:
8468 XML_TREE_ADOPT_STR(cur->name)
8469 XML_TREE_ADOPT_STR_2(cur->content)
8470 break;
8471 case XML_COMMENT_NODE:
8472 break;
8473 default:
8474 goto internal_error;
8475 }
8476 /*
8477 * Walk the tree.
8478 */
8479 if (cur->children != NULL) {
8480 cur = cur->children;
8481 continue;
8482 }
8483
8484leave_node:
8485 if (cur == node)
8486 break;
8487 if ((cur->type == XML_ELEMENT_NODE) ||
8488 (cur->type == XML_XINCLUDE_START) ||
8489 (cur->type == XML_XINCLUDE_END)) {
8490 /*
8491 * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
8492 */
8493 if (nsMap != NULL) {
8494 /*
8495 * Pop mappings.
8496 */
8497 while (topmi->depth >= depth)
8498 topmi = topmi->prev;
8499 /*
8500 * Unshadow.
8501 */
8502 for (mi = nsMap; mi != topmi->next; mi = mi->next)
8503 if (mi->shadowDepth >= depth)
8504 mi->shadowDepth = -1;
8505 }
8506 depth--;
8507 }
8508 if (cur->next != NULL)
8509 cur = cur->next;
8510 else {
8511 cur = cur->parent;
8512 goto leave_node;
8513 }
8514 }
8515 /*
8516 * Cleanup.
8517 */
8518 if (nsMap != NULL)
8519 xmlDOMWrapNSNormFreeNsMap(nsMap);
8520 return (ret);
8521internal_error:
8522 if (nsMap != NULL)
8523 xmlDOMWrapNSNormFreeNsMap(nsMap);
8524 return (-1);
8525}
8526
8527/*
8528* xmlDOMWrapAdoptAttr:
8529* @ctxt: the optional context for custom processing
8530* @sourceDoc: the optional source document of attr
8531* @attr: the attribute-node to be adopted
8532* @destDoc: the destination doc for adoption
8533* @destParent: the optional new parent of @attr in @destDoc
8534* @options: option flags
8535*
8536* @attr is adopted by @destDoc.
8537* Ensures that ns-references point to @destDoc: either to
8538* elements->nsDef entries if @destParent is given, or to
8539* @destDoc->oldNs otherwise.
8540*
8541* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8542*/
8543static int
8544xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt,
8545 xmlDocPtr sourceDoc,
8546 xmlAttrPtr attr,
8547 xmlDocPtr destDoc,
8548 xmlNodePtr destParent,
8549 int options ATTRIBUTE_UNUSED)
8550{
8551 xmlNodePtr cur;
8552 int adoptStr = 1;
8553
8554 if ((attr == NULL) || (destDoc == NULL))
8555 return (-1);
8556
8557 attr->doc = destDoc;
8558 if (attr->ns != NULL) {
8559 xmlNsPtr ns = NULL;
8560
8561 if (ctxt != NULL) {
8562 /* TODO: User defined. */
8563 }
8564 /* XML Namespace. */
8565 if ((attr->ns->prefix[0] == 'x') && (attr->ns->prefix[1] == 'm') &&
8566 (attr->ns->prefix[2] == 'l') && (attr->ns->prefix[3] == 0)) {
8567 ns = xmlTreeEnsureXMLDecl(destDoc);
8568 } else if (destParent == NULL) {
8569 /*
8570 * Store in @destDoc->oldNs.
8571 */
8572 ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix);
8573 } else {
8574 /*
8575 * Declare on @destParent.
8576 */
8577 if (xmlSearchNsByHrefStrict(destDoc, destParent, attr->ns->href,
8578 &ns, 1) == -1)
8579 goto internal_error;
8580 if (ns == NULL) {
8581 ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent,
8582 attr->ns->href, attr->ns->prefix, 1);
8583 }
8584 }
8585 if (ns == NULL)
8586 goto internal_error;
8587 attr->ns = ns;
8588 }
8589
8590 XML_TREE_ADOPT_STR(attr->name);
8591 attr->atype = 0;
8592 attr->psvi = NULL;
8593 /*
8594 * Walk content.
8595 */
8596 if (attr->children == NULL)
8597 return (0);
8598 cur = attr->children;
8599 while (cur != NULL) {
8600 cur->doc = destDoc;
8601 switch (cur->type) {
8602 case XML_TEXT_NODE:
8603 case XML_CDATA_SECTION_NODE:
8604 XML_TREE_ADOPT_STR_2(cur->content)
8605 break;
8606 case XML_ENTITY_REF_NODE:
8607 /*
8608 * Remove reference to the entitity-node.
8609 */
8610 cur->content = NULL;
8611 cur->children = NULL;
8612 cur->last = NULL;
8613 if ((destDoc->intSubset) || (destDoc->extSubset)) {
8614 xmlEntityPtr ent;
8615 /*
8616 * Assign new entity-node if available.
8617 */
8618 ent = xmlGetDocEntity(destDoc, cur->name);
8619 if (ent != NULL) {
8620 cur->content = ent->content;
8621 cur->children = (xmlNodePtr) ent;
8622 cur->last = (xmlNodePtr) ent;
8623 }
8624 }
8625 break;
8626 default:
8627 break;
8628 }
8629 if (cur->children != NULL) {
8630 cur = cur->children;
8631 continue;
8632 }
8633next_sibling:
8634 if (cur == (xmlNodePtr) attr)
8635 break;
8636 if (cur->next != NULL)
8637 cur = cur->next;
8638 else {
8639 cur = cur->parent;
8640 goto next_sibling;
8641 }
8642 }
8643 return (0);
8644internal_error:
8645 return (-1);
8646}
8647
8648/*
8649* xmlDOMWrapAdoptNode:
8650* @ctxt: the optional context for custom processing
8651* @sourceDoc: the optional sourceDoc
8652* @node: the node to start with
8653* @destDoc: the destination doc
Kasimier T. Buchcik4d9c9482005-06-27 15:04:46 +00008654* @destParent: the optional new parent of @node in @destDoc
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008655* @options: option flags
8656*
8657* Ensures that ns-references point to @destDoc: either to
8658* elements->nsDef entries if @destParent is given, or to
8659* @destDoc->oldNs otherwise.
8660* If @destParent is given, it ensures that the tree is namespace
8661* wellformed by creating additional ns-decls where needed.
8662* Note that, since prefixes of already existent ns-decls can be
8663* shadowed by this process, it could break QNames in attribute
8664* values or element content.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00008665* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008666*
8667* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8668*/
8669int
8670xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt,
8671 xmlDocPtr sourceDoc,
8672 xmlNodePtr node,
8673 xmlDocPtr destDoc,
8674 xmlNodePtr destParent,
8675 int options)
8676{
8677 if ((node == NULL) || (destDoc == NULL) ||
8678 ((destParent != NULL) && (destParent->doc != destDoc)))
8679 return(-1);
8680 /*
8681 * Check node->doc sanity.
8682 */
8683 if ((node->doc != NULL) && (sourceDoc != NULL) &&
8684 (node->doc != sourceDoc)) {
8685 /*
8686 * Might be an XIncluded node.
8687 */
8688 return (-1);
8689 }
8690 if (sourceDoc == NULL)
8691 sourceDoc = node->doc;
8692 if (sourceDoc == destDoc)
8693 return (-1);
8694 switch (node->type) {
8695 case XML_ELEMENT_NODE:
8696 case XML_ATTRIBUTE_NODE:
8697 case XML_TEXT_NODE:
8698 case XML_CDATA_SECTION_NODE:
8699 case XML_ENTITY_REF_NODE:
8700 case XML_PI_NODE:
8701 case XML_COMMENT_NODE:
8702 break;
8703 case XML_DOCUMENT_FRAG_NODE:
8704 return (2);
8705 default:
8706 return (1);
8707 }
8708 /*
8709 * Unlink only if @node was not already added to @destParent.
8710 */
8711 if ((node->parent != NULL) && (destParent != node->parent))
8712 xmlUnlinkNode(node);
8713
8714 if (node->type == XML_ELEMENT_NODE) {
8715 return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node,
8716 destDoc, destParent, options));
8717 } else if (node->type == XML_ATTRIBUTE_NODE) {
8718 return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc,
8719 (xmlAttrPtr) node, destDoc, destParent, options));
8720 } else {
8721 xmlNodePtr cur = node;
8722 int adoptStr = 1;
8723
8724 cur->doc = destDoc;
8725 /*
8726 * Optimize string adoption.
8727 */
8728 if ((sourceDoc != NULL) &&
8729 (sourceDoc->dict == destDoc->dict))
8730 adoptStr = 0;
8731 switch (node->type) {
8732 case XML_TEXT_NODE:
8733 case XML_CDATA_SECTION_NODE:
8734 XML_TREE_ADOPT_STR_2(node->content)
8735 break;
8736 case XML_ENTITY_REF_NODE:
8737 /*
8738 * Remove reference to the entitity-node.
8739 */
8740 node->content = NULL;
8741 node->children = NULL;
8742 node->last = NULL;
8743 if ((destDoc->intSubset) || (destDoc->extSubset)) {
8744 xmlEntityPtr ent;
8745 /*
8746 * Assign new entity-node if available.
8747 */
8748 ent = xmlGetDocEntity(destDoc, node->name);
8749 if (ent != NULL) {
8750 node->content = ent->content;
8751 node->children = (xmlNodePtr) ent;
8752 node->last = (xmlNodePtr) ent;
8753 }
8754 }
8755 XML_TREE_ADOPT_STR(node->name)
8756 break;
Daniel Veillard7e21fd12005-07-03 21:44:07 +00008757 case XML_PI_NODE: {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008758 XML_TREE_ADOPT_STR(node->name)
8759 XML_TREE_ADOPT_STR_2(node->content)
8760 break;
Daniel Veillard7e21fd12005-07-03 21:44:07 +00008761 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008762 default:
8763 break;
8764 }
8765 }
8766 return (0);
8767}
8768
8769
Daniel Veillard5d4644e2005-04-01 13:11:58 +00008770#define bottom_tree
8771#include "elfgcchack.h"