blob: 2e7e856b45ac2c456095854e9a3bee55e5e64925 [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;
Rob Richards19dc9612005-10-28 16:15:16 +00002015 if (cur->next != NULL)
2016 cur->next->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002017 xmlFreeProp(cur);
2018 return(0);
2019 }
2020 while (tmp != NULL) {
2021 if (tmp->next == cur) {
2022 tmp->next = cur->next;
2023 if (tmp->next != NULL)
2024 tmp->next->prev = tmp;
2025 xmlFreeProp(cur);
2026 return(0);
2027 }
2028 tmp = tmp->next;
2029 }
2030#ifdef DEBUG_TREE
2031 xmlGenericError(xmlGenericErrorContext,
2032 "xmlRemoveProp : attribute not owned by its node\n");
2033#endif
2034 return(-1);
2035}
Daniel Veillard652327a2003-09-29 18:02:38 +00002036#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002037
2038/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002039 * xmlNewDocPI:
2040 * @doc: the target document
Owen Taylor3473f882001-02-23 17:55:21 +00002041 * @name: the processing instruction name
2042 * @content: the PI content
2043 *
2044 * Creation of a processing instruction element.
2045 * Returns a pointer to the new node object.
2046 */
2047xmlNodePtr
Daniel Veillard03a53c32004-10-26 16:06:51 +00002048xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
Owen Taylor3473f882001-02-23 17:55:21 +00002049 xmlNodePtr cur;
2050
2051 if (name == NULL) {
2052#ifdef DEBUG_TREE
2053 xmlGenericError(xmlGenericErrorContext,
2054 "xmlNewPI : name == NULL\n");
2055#endif
2056 return(NULL);
2057 }
2058
2059 /*
2060 * Allocate a new node and fill the fields.
2061 */
2062 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2063 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002064 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002065 return(NULL);
2066 }
2067 memset(cur, 0, sizeof(xmlNode));
2068 cur->type = XML_PI_NODE;
2069
Daniel Veillard03a53c32004-10-26 16:06:51 +00002070 if ((doc != NULL) && (doc->dict != NULL))
2071 cur->name = xmlDictLookup(doc->dict, name, -1);
2072 else
2073 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00002074 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002075 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002076 }
Daniel Veillarda03e3652004-11-02 18:45:30 +00002077 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002078
Daniel Veillarda880b122003-04-21 21:36:41 +00002079 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002080 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002081 return(cur);
2082}
2083
2084/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002085 * xmlNewPI:
2086 * @name: the processing instruction name
2087 * @content: the PI content
2088 *
2089 * Creation of a processing instruction element.
2090 * Use xmlDocNewPI preferably to get string interning
2091 *
2092 * Returns a pointer to the new node object.
2093 */
2094xmlNodePtr
2095xmlNewPI(const xmlChar *name, const xmlChar *content) {
2096 return(xmlNewDocPI(NULL, name, content));
2097}
2098
2099/**
Owen Taylor3473f882001-02-23 17:55:21 +00002100 * xmlNewNode:
2101 * @ns: namespace if any
2102 * @name: the node name
2103 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002104 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002105 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002106 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2107 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002108 */
2109xmlNodePtr
2110xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2111 xmlNodePtr cur;
2112
2113 if (name == NULL) {
2114#ifdef DEBUG_TREE
2115 xmlGenericError(xmlGenericErrorContext,
2116 "xmlNewNode : name == NULL\n");
2117#endif
2118 return(NULL);
2119 }
2120
2121 /*
2122 * Allocate a new node and fill the fields.
2123 */
2124 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2125 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002126 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002127 return(NULL);
2128 }
2129 memset(cur, 0, sizeof(xmlNode));
2130 cur->type = XML_ELEMENT_NODE;
2131
2132 cur->name = xmlStrdup(name);
2133 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002134
Daniel Veillarda880b122003-04-21 21:36:41 +00002135 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002136 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002137 return(cur);
2138}
2139
2140/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002141 * xmlNewNodeEatName:
2142 * @ns: namespace if any
2143 * @name: the node name
2144 *
2145 * Creation of a new node element. @ns is optional (NULL).
2146 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002147 * Returns a pointer to the new node object, with pointer @name as
2148 * new node's name. Use xmlNewNode() if a copy of @name string is
2149 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002150 */
2151xmlNodePtr
2152xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2153 xmlNodePtr cur;
2154
2155 if (name == NULL) {
2156#ifdef DEBUG_TREE
2157 xmlGenericError(xmlGenericErrorContext,
2158 "xmlNewNode : name == NULL\n");
2159#endif
2160 return(NULL);
2161 }
2162
2163 /*
2164 * Allocate a new node and fill the fields.
2165 */
2166 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2167 if (cur == NULL) {
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00002168 xmlFree(name);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002169 xmlTreeErrMemory("building node");
Daniel Veillard46de64e2002-05-29 08:21:33 +00002170 return(NULL);
2171 }
2172 memset(cur, 0, sizeof(xmlNode));
2173 cur->type = XML_ELEMENT_NODE;
2174
2175 cur->name = name;
2176 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002177
Daniel Veillarda880b122003-04-21 21:36:41 +00002178 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002179 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002180 return(cur);
2181}
2182
2183/**
Owen Taylor3473f882001-02-23 17:55:21 +00002184 * xmlNewDocNode:
2185 * @doc: the document
2186 * @ns: namespace if any
2187 * @name: the node name
2188 * @content: the XML text content if any
2189 *
2190 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002191 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002192 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2193 * references, but XML special chars need to be escaped first by using
2194 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2195 * need entities support.
2196 *
2197 * Returns a pointer to the new node object.
2198 */
2199xmlNodePtr
2200xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2201 const xmlChar *name, const xmlChar *content) {
2202 xmlNodePtr cur;
2203
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002204 if ((doc != NULL) && (doc->dict != NULL))
Daniel Veillard03a53c32004-10-26 16:06:51 +00002205 cur = xmlNewNodeEatName(ns, (xmlChar *)
2206 xmlDictLookup(doc->dict, name, -1));
2207 else
2208 cur = xmlNewNode(ns, name);
Owen Taylor3473f882001-02-23 17:55:21 +00002209 if (cur != NULL) {
2210 cur->doc = doc;
2211 if (content != NULL) {
2212 cur->children = xmlStringGetNodeList(doc, content);
2213 UPDATE_LAST_CHILD_AND_PARENT(cur)
2214 }
2215 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002216
Owen Taylor3473f882001-02-23 17:55:21 +00002217 return(cur);
2218}
2219
Daniel Veillard46de64e2002-05-29 08:21:33 +00002220/**
2221 * xmlNewDocNodeEatName:
2222 * @doc: the document
2223 * @ns: namespace if any
2224 * @name: the node name
2225 * @content: the XML text content if any
2226 *
2227 * Creation of a new node element within a document. @ns and @content
2228 * are optional (NULL).
2229 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2230 * references, but XML special chars need to be escaped first by using
2231 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2232 * need entities support.
2233 *
2234 * Returns a pointer to the new node object.
2235 */
2236xmlNodePtr
2237xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2238 xmlChar *name, const xmlChar *content) {
2239 xmlNodePtr cur;
2240
2241 cur = xmlNewNodeEatName(ns, name);
2242 if (cur != NULL) {
2243 cur->doc = doc;
2244 if (content != NULL) {
2245 cur->children = xmlStringGetNodeList(doc, content);
2246 UPDATE_LAST_CHILD_AND_PARENT(cur)
2247 }
2248 }
2249 return(cur);
2250}
2251
Daniel Veillard652327a2003-09-29 18:02:38 +00002252#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002253/**
2254 * xmlNewDocRawNode:
2255 * @doc: the document
2256 * @ns: namespace if any
2257 * @name: the node name
2258 * @content: the text content if any
2259 *
2260 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002261 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002262 *
2263 * Returns a pointer to the new node object.
2264 */
2265xmlNodePtr
2266xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2267 const xmlChar *name, const xmlChar *content) {
2268 xmlNodePtr cur;
2269
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002270 cur = xmlNewDocNode(doc, ns, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002271 if (cur != NULL) {
2272 cur->doc = doc;
2273 if (content != NULL) {
2274 cur->children = xmlNewDocText(doc, content);
2275 UPDATE_LAST_CHILD_AND_PARENT(cur)
2276 }
2277 }
2278 return(cur);
2279}
2280
2281/**
2282 * xmlNewDocFragment:
2283 * @doc: the document owning the fragment
2284 *
2285 * Creation of a new Fragment node.
2286 * Returns a pointer to the new node object.
2287 */
2288xmlNodePtr
2289xmlNewDocFragment(xmlDocPtr doc) {
2290 xmlNodePtr cur;
2291
2292 /*
2293 * Allocate a new DocumentFragment node and fill the fields.
2294 */
2295 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2296 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002297 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002298 return(NULL);
2299 }
2300 memset(cur, 0, sizeof(xmlNode));
2301 cur->type = XML_DOCUMENT_FRAG_NODE;
2302
2303 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002304
Daniel Veillarda880b122003-04-21 21:36:41 +00002305 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002306 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002307 return(cur);
2308}
Daniel Veillard652327a2003-09-29 18:02:38 +00002309#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002310
2311/**
2312 * xmlNewText:
2313 * @content: the text content
2314 *
2315 * Creation of a new text node.
2316 * Returns a pointer to the new node object.
2317 */
2318xmlNodePtr
2319xmlNewText(const xmlChar *content) {
2320 xmlNodePtr cur;
2321
2322 /*
2323 * Allocate a new node and fill the fields.
2324 */
2325 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2326 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002327 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002328 return(NULL);
2329 }
2330 memset(cur, 0, sizeof(xmlNode));
2331 cur->type = XML_TEXT_NODE;
2332
2333 cur->name = xmlStringText;
2334 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002335 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002336 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002337
Daniel Veillarda880b122003-04-21 21:36:41 +00002338 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002339 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002340 return(cur);
2341}
2342
Daniel Veillard652327a2003-09-29 18:02:38 +00002343#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002344/**
2345 * xmlNewTextChild:
2346 * @parent: the parent node
2347 * @ns: a namespace if any
2348 * @name: the name of the child
2349 * @content: the text content of the child if any.
2350 *
2351 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002352 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2353 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002354 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002355 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2356 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2357 * reserved XML chars that might appear in @content, such as the ampersand,
2358 * greater-than or less-than signs, are automatically replaced by their XML
2359 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002360 *
2361 * Returns a pointer to the new node object.
2362 */
2363xmlNodePtr
2364xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2365 const xmlChar *name, const xmlChar *content) {
2366 xmlNodePtr cur, prev;
2367
2368 if (parent == NULL) {
2369#ifdef DEBUG_TREE
2370 xmlGenericError(xmlGenericErrorContext,
2371 "xmlNewTextChild : parent == NULL\n");
2372#endif
2373 return(NULL);
2374 }
2375
2376 if (name == NULL) {
2377#ifdef DEBUG_TREE
2378 xmlGenericError(xmlGenericErrorContext,
2379 "xmlNewTextChild : name == NULL\n");
2380#endif
2381 return(NULL);
2382 }
2383
2384 /*
2385 * Allocate a new node
2386 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002387 if (parent->type == XML_ELEMENT_NODE) {
2388 if (ns == NULL)
2389 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2390 else
2391 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2392 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2393 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2394 if (ns == NULL)
2395 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2396 else
2397 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2398 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2399 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2400 } else {
2401 return(NULL);
2402 }
Owen Taylor3473f882001-02-23 17:55:21 +00002403 if (cur == NULL) return(NULL);
2404
2405 /*
2406 * add the new element at the end of the children list.
2407 */
2408 cur->type = XML_ELEMENT_NODE;
2409 cur->parent = parent;
2410 cur->doc = parent->doc;
2411 if (parent->children == NULL) {
2412 parent->children = cur;
2413 parent->last = cur;
2414 } else {
2415 prev = parent->last;
2416 prev->next = cur;
2417 cur->prev = prev;
2418 parent->last = cur;
2419 }
2420
2421 return(cur);
2422}
Daniel Veillard652327a2003-09-29 18:02:38 +00002423#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002424
2425/**
2426 * xmlNewCharRef:
2427 * @doc: the document
2428 * @name: the char ref string, starting with # or "&# ... ;"
2429 *
2430 * Creation of a new character reference node.
2431 * Returns a pointer to the new node object.
2432 */
2433xmlNodePtr
2434xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2435 xmlNodePtr cur;
2436
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002437 if (name == NULL)
2438 return(NULL);
2439
Owen Taylor3473f882001-02-23 17:55:21 +00002440 /*
2441 * Allocate a new node and fill the fields.
2442 */
2443 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2444 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002445 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002446 return(NULL);
2447 }
2448 memset(cur, 0, sizeof(xmlNode));
2449 cur->type = XML_ENTITY_REF_NODE;
2450
2451 cur->doc = doc;
2452 if (name[0] == '&') {
2453 int len;
2454 name++;
2455 len = xmlStrlen(name);
2456 if (name[len - 1] == ';')
2457 cur->name = xmlStrndup(name, len - 1);
2458 else
2459 cur->name = xmlStrndup(name, len);
2460 } else
2461 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002462
Daniel Veillarda880b122003-04-21 21:36:41 +00002463 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002464 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002465 return(cur);
2466}
2467
2468/**
2469 * xmlNewReference:
2470 * @doc: the document
2471 * @name: the reference name, or the reference string with & and ;
2472 *
2473 * Creation of a new reference node.
2474 * Returns a pointer to the new node object.
2475 */
2476xmlNodePtr
2477xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2478 xmlNodePtr cur;
2479 xmlEntityPtr ent;
2480
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002481 if (name == NULL)
2482 return(NULL);
2483
Owen Taylor3473f882001-02-23 17:55:21 +00002484 /*
2485 * Allocate a new node and fill the fields.
2486 */
2487 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2488 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002489 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002490 return(NULL);
2491 }
2492 memset(cur, 0, sizeof(xmlNode));
2493 cur->type = XML_ENTITY_REF_NODE;
2494
2495 cur->doc = doc;
2496 if (name[0] == '&') {
2497 int len;
2498 name++;
2499 len = xmlStrlen(name);
2500 if (name[len - 1] == ';')
2501 cur->name = xmlStrndup(name, len - 1);
2502 else
2503 cur->name = xmlStrndup(name, len);
2504 } else
2505 cur->name = xmlStrdup(name);
2506
2507 ent = xmlGetDocEntity(doc, cur->name);
2508 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002509 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002510 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002511 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002512 * updated. Not sure if this is 100% correct.
2513 * -George
2514 */
2515 cur->children = (xmlNodePtr) ent;
2516 cur->last = (xmlNodePtr) ent;
2517 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002518
Daniel Veillarda880b122003-04-21 21:36:41 +00002519 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002520 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002521 return(cur);
2522}
2523
2524/**
2525 * xmlNewDocText:
2526 * @doc: the document
2527 * @content: the text content
2528 *
2529 * Creation of a new text node within a document.
2530 * Returns a pointer to the new node object.
2531 */
2532xmlNodePtr
2533xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2534 xmlNodePtr cur;
2535
2536 cur = xmlNewText(content);
2537 if (cur != NULL) cur->doc = doc;
2538 return(cur);
2539}
2540
2541/**
2542 * xmlNewTextLen:
2543 * @content: the text content
2544 * @len: the text len.
2545 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002546 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002547 * Returns a pointer to the new node object.
2548 */
2549xmlNodePtr
2550xmlNewTextLen(const xmlChar *content, int len) {
2551 xmlNodePtr cur;
2552
2553 /*
2554 * Allocate a new node and fill the fields.
2555 */
2556 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2557 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002558 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002559 return(NULL);
2560 }
2561 memset(cur, 0, sizeof(xmlNode));
2562 cur->type = XML_TEXT_NODE;
2563
2564 cur->name = xmlStringText;
2565 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002566 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002567 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002568
Daniel Veillarda880b122003-04-21 21:36:41 +00002569 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002570 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002571 return(cur);
2572}
2573
2574/**
2575 * xmlNewDocTextLen:
2576 * @doc: the document
2577 * @content: the text content
2578 * @len: the text len.
2579 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002580 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002581 * text node pertain to a given document.
2582 * Returns a pointer to the new node object.
2583 */
2584xmlNodePtr
2585xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2586 xmlNodePtr cur;
2587
2588 cur = xmlNewTextLen(content, len);
2589 if (cur != NULL) cur->doc = doc;
2590 return(cur);
2591}
2592
2593/**
2594 * xmlNewComment:
2595 * @content: the comment content
2596 *
2597 * Creation of a new node containing a comment.
2598 * Returns a pointer to the new node object.
2599 */
2600xmlNodePtr
2601xmlNewComment(const xmlChar *content) {
2602 xmlNodePtr cur;
2603
2604 /*
2605 * Allocate a new node and fill the fields.
2606 */
2607 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2608 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002609 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002610 return(NULL);
2611 }
2612 memset(cur, 0, sizeof(xmlNode));
2613 cur->type = XML_COMMENT_NODE;
2614
2615 cur->name = xmlStringComment;
2616 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002617 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002618 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002619
Daniel Veillarda880b122003-04-21 21:36:41 +00002620 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002621 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002622 return(cur);
2623}
2624
2625/**
2626 * xmlNewCDataBlock:
2627 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002628 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002629 * @len: the length of the block
2630 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002631 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002632 * Returns a pointer to the new node object.
2633 */
2634xmlNodePtr
2635xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2636 xmlNodePtr cur;
2637
2638 /*
2639 * Allocate a new node and fill the fields.
2640 */
2641 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2642 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002643 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002644 return(NULL);
2645 }
2646 memset(cur, 0, sizeof(xmlNode));
2647 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002648 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002649
2650 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002651 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002652 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002653
Daniel Veillarda880b122003-04-21 21:36:41 +00002654 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002655 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002656 return(cur);
2657}
2658
2659/**
2660 * xmlNewDocComment:
2661 * @doc: the document
2662 * @content: the comment content
2663 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002664 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002665 * Returns a pointer to the new node object.
2666 */
2667xmlNodePtr
2668xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2669 xmlNodePtr cur;
2670
2671 cur = xmlNewComment(content);
2672 if (cur != NULL) cur->doc = doc;
2673 return(cur);
2674}
2675
2676/**
2677 * xmlSetTreeDoc:
2678 * @tree: the top element
2679 * @doc: the document
2680 *
2681 * update all nodes under the tree to point to the right document
2682 */
2683void
2684xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002685 xmlAttrPtr prop;
2686
Owen Taylor3473f882001-02-23 17:55:21 +00002687 if (tree == NULL)
2688 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002689 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002690 if(tree->type == XML_ELEMENT_NODE) {
2691 prop = tree->properties;
2692 while (prop != NULL) {
2693 prop->doc = doc;
2694 xmlSetListDoc(prop->children, doc);
2695 prop = prop->next;
2696 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002697 }
Owen Taylor3473f882001-02-23 17:55:21 +00002698 if (tree->children != NULL)
2699 xmlSetListDoc(tree->children, doc);
2700 tree->doc = doc;
2701 }
2702}
2703
2704/**
2705 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002706 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002707 * @doc: the document
2708 *
2709 * update all nodes in the list to point to the right document
2710 */
2711void
2712xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2713 xmlNodePtr cur;
2714
2715 if (list == NULL)
2716 return;
2717 cur = list;
2718 while (cur != NULL) {
2719 if (cur->doc != doc)
2720 xmlSetTreeDoc(cur, doc);
2721 cur = cur->next;
2722 }
2723}
2724
Daniel Veillard2156d432004-03-04 15:59:36 +00002725#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002726/**
2727 * xmlNewChild:
2728 * @parent: the parent node
2729 * @ns: a namespace if any
2730 * @name: the name of the child
2731 * @content: the XML content of the child if any.
2732 *
2733 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002734 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2735 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002736 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002737 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2738 * references. XML special chars must be escaped first by using
2739 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002740 *
2741 * Returns a pointer to the new node object.
2742 */
2743xmlNodePtr
2744xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2745 const xmlChar *name, const xmlChar *content) {
2746 xmlNodePtr cur, prev;
2747
2748 if (parent == NULL) {
2749#ifdef DEBUG_TREE
2750 xmlGenericError(xmlGenericErrorContext,
2751 "xmlNewChild : parent == NULL\n");
2752#endif
2753 return(NULL);
2754 }
2755
2756 if (name == NULL) {
2757#ifdef DEBUG_TREE
2758 xmlGenericError(xmlGenericErrorContext,
2759 "xmlNewChild : name == NULL\n");
2760#endif
2761 return(NULL);
2762 }
2763
2764 /*
2765 * Allocate a new node
2766 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002767 if (parent->type == XML_ELEMENT_NODE) {
2768 if (ns == NULL)
2769 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2770 else
2771 cur = xmlNewDocNode(parent->doc, ns, name, content);
2772 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2773 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2774 if (ns == NULL)
2775 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2776 else
2777 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002778 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2779 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002780 } else {
2781 return(NULL);
2782 }
Owen Taylor3473f882001-02-23 17:55:21 +00002783 if (cur == NULL) return(NULL);
2784
2785 /*
2786 * add the new element at the end of the children list.
2787 */
2788 cur->type = XML_ELEMENT_NODE;
2789 cur->parent = parent;
2790 cur->doc = parent->doc;
2791 if (parent->children == NULL) {
2792 parent->children = cur;
2793 parent->last = cur;
2794 } else {
2795 prev = parent->last;
2796 prev->next = cur;
2797 cur->prev = prev;
2798 parent->last = cur;
2799 }
2800
2801 return(cur);
2802}
Daniel Veillard652327a2003-09-29 18:02:38 +00002803#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002804
2805/**
2806 * xmlAddNextSibling:
2807 * @cur: the child node
2808 * @elem: the new node
2809 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002810 * Add a new node @elem as the next sibling of @cur
2811 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002812 * first unlinked from its existing context.
2813 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002814 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2815 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002816 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002817 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002818 */
2819xmlNodePtr
2820xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2821 if (cur == NULL) {
2822#ifdef DEBUG_TREE
2823 xmlGenericError(xmlGenericErrorContext,
2824 "xmlAddNextSibling : cur == NULL\n");
2825#endif
2826 return(NULL);
2827 }
2828 if (elem == NULL) {
2829#ifdef DEBUG_TREE
2830 xmlGenericError(xmlGenericErrorContext,
2831 "xmlAddNextSibling : elem == NULL\n");
2832#endif
2833 return(NULL);
2834 }
2835
Rob Richards19dc9612005-10-28 16:15:16 +00002836 if (cur == elem) {
2837#ifdef DEBUG_TREE
2838 xmlGenericError(xmlGenericErrorContext,
2839 "xmlAddNextSibling : cur == elem\n");
2840#endif
2841 return(NULL);
2842 }
2843
Owen Taylor3473f882001-02-23 17:55:21 +00002844 xmlUnlinkNode(elem);
2845
2846 if (elem->type == XML_TEXT_NODE) {
2847 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002848 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002849 xmlFreeNode(elem);
2850 return(cur);
2851 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002852 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2853 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002854 xmlChar *tmp;
2855
2856 tmp = xmlStrdup(elem->content);
2857 tmp = xmlStrcat(tmp, cur->next->content);
2858 xmlNodeSetContent(cur->next, tmp);
2859 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002860 xmlFreeNode(elem);
2861 return(cur->next);
2862 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002863 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2864 /* check if an attribute with the same name exists */
2865 xmlAttrPtr attr;
2866
Rob Richards19dc9612005-10-28 16:15:16 +00002867 if (cur->type != XML_ATTRIBUTE_NODE)
2868 return(NULL);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002869 if (elem->ns == NULL)
Rob Richardsc342ec62005-10-25 00:10:12 +00002870 attr = xmlHasNsProp(cur->parent, elem->name, NULL);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002871 else
2872 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
Rob Richardsc342ec62005-10-25 00:10:12 +00002873 /* elem has already been unlinked so can never be attr */
2874 if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002875 /* different instance, destroy it (attributes must be unique) */
Rob Richards19dc9612005-10-28 16:15:16 +00002876 xmlUnlinkNode((xmlNodePtr) attr);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002877 xmlFreeProp(attr);
2878 }
Owen Taylor3473f882001-02-23 17:55:21 +00002879 }
2880
2881 if (elem->doc != cur->doc) {
2882 xmlSetTreeDoc(elem, cur->doc);
2883 }
2884 elem->parent = cur->parent;
2885 elem->prev = cur;
2886 elem->next = cur->next;
2887 cur->next = elem;
2888 if (elem->next != NULL)
2889 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002890 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002891 elem->parent->last = elem;
2892 return(elem);
2893}
2894
William M. Brack21e4ef22005-01-02 09:53:13 +00002895#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
2896 defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002897/**
2898 * xmlAddPrevSibling:
2899 * @cur: the child node
2900 * @elem: the new node
2901 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002902 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002903 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002904 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002905 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002906 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2907 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002908 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002909 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002910 */
2911xmlNodePtr
2912xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2913 if (cur == NULL) {
2914#ifdef DEBUG_TREE
2915 xmlGenericError(xmlGenericErrorContext,
2916 "xmlAddPrevSibling : cur == NULL\n");
2917#endif
2918 return(NULL);
2919 }
2920 if (elem == NULL) {
2921#ifdef DEBUG_TREE
2922 xmlGenericError(xmlGenericErrorContext,
2923 "xmlAddPrevSibling : elem == NULL\n");
2924#endif
2925 return(NULL);
2926 }
2927
Rob Richards19dc9612005-10-28 16:15:16 +00002928 if (cur == elem) {
2929#ifdef DEBUG_TREE
2930 xmlGenericError(xmlGenericErrorContext,
2931 "xmlAddPrevSibling : cur == elem\n");
2932#endif
2933 return(NULL);
2934 }
2935
Owen Taylor3473f882001-02-23 17:55:21 +00002936 xmlUnlinkNode(elem);
2937
2938 if (elem->type == XML_TEXT_NODE) {
2939 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002940 xmlChar *tmp;
2941
2942 tmp = xmlStrdup(elem->content);
2943 tmp = xmlStrcat(tmp, cur->content);
2944 xmlNodeSetContent(cur, tmp);
2945 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002946 xmlFreeNode(elem);
2947 return(cur);
2948 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002949 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2950 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002951 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002952 xmlFreeNode(elem);
2953 return(cur->prev);
2954 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002955 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2956 /* check if an attribute with the same name exists */
2957 xmlAttrPtr attr;
2958
Rob Richards19dc9612005-10-28 16:15:16 +00002959 if (cur->type != XML_ATTRIBUTE_NODE)
2960 return(NULL);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002961 if (elem->ns == NULL)
Rob Richardsc342ec62005-10-25 00:10:12 +00002962 attr = xmlHasNsProp(cur->parent, elem->name, NULL);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002963 else
2964 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
Rob Richardsc342ec62005-10-25 00:10:12 +00002965 /* elem has already been unlinked so can never be attr */
2966 if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002967 /* different instance, destroy it (attributes must be unique) */
Rob Richards19dc9612005-10-28 16:15:16 +00002968 xmlUnlinkNode((xmlNodePtr) attr);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002969 xmlFreeProp(attr);
2970 }
Owen Taylor3473f882001-02-23 17:55:21 +00002971 }
2972
2973 if (elem->doc != cur->doc) {
2974 xmlSetTreeDoc(elem, cur->doc);
2975 }
2976 elem->parent = cur->parent;
2977 elem->next = cur;
2978 elem->prev = cur->prev;
2979 cur->prev = elem;
2980 if (elem->prev != NULL)
2981 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002982 if (elem->parent != NULL) {
2983 if (elem->type == XML_ATTRIBUTE_NODE) {
2984 if (elem->parent->properties == (xmlAttrPtr) cur) {
2985 elem->parent->properties = (xmlAttrPtr) elem;
2986 }
2987 } else {
2988 if (elem->parent->children == cur) {
2989 elem->parent->children = elem;
2990 }
2991 }
2992 }
Owen Taylor3473f882001-02-23 17:55:21 +00002993 return(elem);
2994}
Daniel Veillard652327a2003-09-29 18:02:38 +00002995#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002996
2997/**
2998 * xmlAddSibling:
2999 * @cur: the child node
3000 * @elem: the new node
3001 *
3002 * Add a new element @elem to the list of siblings of @cur
3003 * merging adjacent TEXT nodes (@elem may be freed)
3004 * If the new element was already inserted in a document it is
3005 * first unlinked from its existing context.
3006 *
3007 * Returns the new element or NULL in case of error.
3008 */
3009xmlNodePtr
3010xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
3011 xmlNodePtr parent;
3012
3013 if (cur == NULL) {
3014#ifdef DEBUG_TREE
3015 xmlGenericError(xmlGenericErrorContext,
3016 "xmlAddSibling : cur == NULL\n");
3017#endif
3018 return(NULL);
3019 }
3020
3021 if (elem == NULL) {
3022#ifdef DEBUG_TREE
3023 xmlGenericError(xmlGenericErrorContext,
3024 "xmlAddSibling : elem == NULL\n");
3025#endif
3026 return(NULL);
3027 }
3028
3029 /*
3030 * Constant time is we can rely on the ->parent->last to find
3031 * the last sibling.
3032 */
3033 if ((cur->parent != NULL) &&
3034 (cur->parent->children != NULL) &&
3035 (cur->parent->last != NULL) &&
3036 (cur->parent->last->next == NULL)) {
3037 cur = cur->parent->last;
3038 } else {
3039 while (cur->next != NULL) cur = cur->next;
3040 }
3041
3042 xmlUnlinkNode(elem);
3043
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003044 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3045 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003046 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003047 xmlFreeNode(elem);
3048 return(cur);
3049 }
3050
3051 if (elem->doc != cur->doc) {
3052 xmlSetTreeDoc(elem, cur->doc);
3053 }
3054 parent = cur->parent;
3055 elem->prev = cur;
3056 elem->next = NULL;
3057 elem->parent = parent;
3058 cur->next = elem;
3059 if (parent != NULL)
3060 parent->last = elem;
3061
3062 return(elem);
3063}
3064
3065/**
3066 * xmlAddChildList:
3067 * @parent: the parent node
3068 * @cur: the first node in the list
3069 *
3070 * Add a list of node at the end of the child list of the parent
3071 * merging adjacent TEXT nodes (@cur may be freed)
3072 *
3073 * Returns the last child or NULL in case of error.
3074 */
3075xmlNodePtr
3076xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3077 xmlNodePtr prev;
3078
3079 if (parent == NULL) {
3080#ifdef DEBUG_TREE
3081 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003082 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003083#endif
3084 return(NULL);
3085 }
3086
3087 if (cur == NULL) {
3088#ifdef DEBUG_TREE
3089 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003090 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003091#endif
3092 return(NULL);
3093 }
3094
3095 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3096 (cur->doc != parent->doc)) {
3097#ifdef DEBUG_TREE
3098 xmlGenericError(xmlGenericErrorContext,
3099 "Elements moved to a different document\n");
3100#endif
3101 }
3102
3103 /*
3104 * add the first element at the end of the children list.
3105 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003106
Owen Taylor3473f882001-02-23 17:55:21 +00003107 if (parent->children == NULL) {
3108 parent->children = cur;
3109 } else {
3110 /*
3111 * If cur and parent->last both are TEXT nodes, then merge them.
3112 */
3113 if ((cur->type == XML_TEXT_NODE) &&
3114 (parent->last->type == XML_TEXT_NODE) &&
3115 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003116 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003117 /*
3118 * if it's the only child, nothing more to be done.
3119 */
3120 if (cur->next == NULL) {
3121 xmlFreeNode(cur);
3122 return(parent->last);
3123 }
3124 prev = cur;
3125 cur = cur->next;
3126 xmlFreeNode(prev);
3127 }
3128 prev = parent->last;
3129 prev->next = cur;
3130 cur->prev = prev;
3131 }
3132 while (cur->next != NULL) {
3133 cur->parent = parent;
3134 if (cur->doc != parent->doc) {
3135 xmlSetTreeDoc(cur, parent->doc);
3136 }
3137 cur = cur->next;
3138 }
3139 cur->parent = parent;
3140 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3141 parent->last = cur;
3142
3143 return(cur);
3144}
3145
3146/**
3147 * xmlAddChild:
3148 * @parent: the parent node
3149 * @cur: the child node
3150 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003151 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003152 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003153 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3154 * If there is an attribute with equal name, it is first destroyed.
3155 *
Owen Taylor3473f882001-02-23 17:55:21 +00003156 * Returns the child or NULL in case of error.
3157 */
3158xmlNodePtr
3159xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3160 xmlNodePtr prev;
3161
3162 if (parent == NULL) {
3163#ifdef DEBUG_TREE
3164 xmlGenericError(xmlGenericErrorContext,
3165 "xmlAddChild : parent == NULL\n");
3166#endif
3167 return(NULL);
3168 }
3169
3170 if (cur == NULL) {
3171#ifdef DEBUG_TREE
3172 xmlGenericError(xmlGenericErrorContext,
3173 "xmlAddChild : child == NULL\n");
3174#endif
3175 return(NULL);
3176 }
3177
Rob Richards19dc9612005-10-28 16:15:16 +00003178 if (parent == cur) {
3179#ifdef DEBUG_TREE
3180 xmlGenericError(xmlGenericErrorContext,
3181 "xmlAddChild : parent == cur\n");
3182#endif
3183 return(NULL);
3184 }
Owen Taylor3473f882001-02-23 17:55:21 +00003185 /*
3186 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003187 * cur is then freed.
3188 */
3189 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003190 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003191 (parent->content != NULL) &&
Rob Richards19dc9612005-10-28 16:15:16 +00003192 (parent->name == cur->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003193 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003194 xmlFreeNode(cur);
3195 return(parent);
3196 }
3197 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003198 (parent->last->name == cur->name) &&
3199 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003200 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003201 xmlFreeNode(cur);
3202 return(parent->last);
3203 }
3204 }
3205
3206 /*
3207 * add the new element at the end of the children list.
3208 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003209 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003210 cur->parent = parent;
3211 if (cur->doc != parent->doc) {
3212 xmlSetTreeDoc(cur, parent->doc);
3213 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003214 /* this check prevents a loop on tree-traversions if a developer
3215 * tries to add a node to its parent multiple times
3216 */
3217 if (prev == parent)
3218 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003219
3220 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003221 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003222 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003223 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003224 (parent->content != NULL) &&
3225 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003226 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003227 xmlFreeNode(cur);
3228 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003229 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003230 if (cur->type == XML_ATTRIBUTE_NODE) {
Rob Richards19dc9612005-10-28 16:15:16 +00003231 if (parent->type != XML_ELEMENT_NODE)
3232 return(NULL);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003233 if (parent->properties == NULL) {
3234 parent->properties = (xmlAttrPtr) cur;
3235 } else {
3236 /* check if an attribute with the same name exists */
3237 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003238
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003239 if (cur->ns == NULL)
Rob Richardsc342ec62005-10-25 00:10:12 +00003240 lastattr = xmlHasNsProp(parent, cur->name, NULL);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003241 else
3242 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
Rob Richardsc342ec62005-10-25 00:10:12 +00003243 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur) && (lastattr->type != XML_ATTRIBUTE_DECL)) {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003244 /* different instance, destroy it (attributes must be unique) */
Rob Richards19dc9612005-10-28 16:15:16 +00003245 xmlUnlinkNode((xmlNodePtr) lastattr);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003246 xmlFreeProp(lastattr);
3247 }
Rob Richards19dc9612005-10-28 16:15:16 +00003248 if (lastattr == (xmlAttrPtr) cur)
3249 return(cur);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003250 /* find the end */
3251 lastattr = parent->properties;
3252 while (lastattr->next != NULL) {
3253 lastattr = lastattr->next;
3254 }
3255 lastattr->next = (xmlAttrPtr) cur;
3256 ((xmlAttrPtr) cur)->prev = lastattr;
3257 }
3258 } else {
3259 if (parent->children == NULL) {
3260 parent->children = cur;
3261 parent->last = cur;
3262 } else {
3263 prev = parent->last;
3264 prev->next = cur;
3265 cur->prev = prev;
3266 parent->last = cur;
3267 }
3268 }
Owen Taylor3473f882001-02-23 17:55:21 +00003269 return(cur);
3270}
3271
3272/**
3273 * xmlGetLastChild:
3274 * @parent: the parent node
3275 *
3276 * Search the last child of a node.
3277 * Returns the last child or NULL if none.
3278 */
3279xmlNodePtr
3280xmlGetLastChild(xmlNodePtr parent) {
3281 if (parent == NULL) {
3282#ifdef DEBUG_TREE
3283 xmlGenericError(xmlGenericErrorContext,
3284 "xmlGetLastChild : parent == NULL\n");
3285#endif
3286 return(NULL);
3287 }
3288 return(parent->last);
3289}
3290
3291/**
3292 * xmlFreeNodeList:
3293 * @cur: the first node in the list
3294 *
3295 * Free a node and all its siblings, this is a recursive behaviour, all
3296 * the children are freed too.
3297 */
3298void
3299xmlFreeNodeList(xmlNodePtr cur) {
3300 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003301 xmlDictPtr dict = NULL;
3302
3303 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003304 if (cur->type == XML_NAMESPACE_DECL) {
3305 xmlFreeNsList((xmlNsPtr) cur);
3306 return;
3307 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003308 if ((cur->type == XML_DOCUMENT_NODE) ||
3309#ifdef LIBXML_DOCB_ENABLED
3310 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003311#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003312 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003313 xmlFreeDoc((xmlDocPtr) cur);
3314 return;
3315 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003316 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003317 while (cur != NULL) {
3318 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003319 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003320
Daniel Veillarda880b122003-04-21 21:36:41 +00003321 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003322 xmlDeregisterNodeDefaultValue(cur);
3323
Daniel Veillard02141ea2001-04-30 11:46:40 +00003324 if ((cur->children != NULL) &&
3325 (cur->type != XML_ENTITY_REF_NODE))
3326 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003327 if (((cur->type == XML_ELEMENT_NODE) ||
3328 (cur->type == XML_XINCLUDE_START) ||
3329 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003330 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003331 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003332 if ((cur->type != XML_ELEMENT_NODE) &&
3333 (cur->type != XML_XINCLUDE_START) &&
3334 (cur->type != XML_XINCLUDE_END) &&
Daniel Veillard8874b942005-08-25 13:19:21 +00003335 (cur->type != XML_ENTITY_REF_NODE) &&
3336 (cur->content != (xmlChar *) &(cur->properties))) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003337 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003338 }
3339 if (((cur->type == XML_ELEMENT_NODE) ||
3340 (cur->type == XML_XINCLUDE_START) ||
3341 (cur->type == XML_XINCLUDE_END)) &&
3342 (cur->nsDef != NULL))
3343 xmlFreeNsList(cur->nsDef);
3344
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003345 /*
3346 * When a node is a text node or a comment, it uses a global static
3347 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003348 * Otherwise the node name might come from the document's
3349 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003350 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003351 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003352 (cur->type != XML_TEXT_NODE) &&
3353 (cur->type != XML_COMMENT_NODE))
3354 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003355 xmlFree(cur);
3356 }
Owen Taylor3473f882001-02-23 17:55:21 +00003357 cur = next;
3358 }
3359}
3360
3361/**
3362 * xmlFreeNode:
3363 * @cur: the node
3364 *
3365 * Free a node, this is a recursive behaviour, all the children are freed too.
3366 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3367 */
3368void
3369xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003370 xmlDictPtr dict = NULL;
3371
3372 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003373
Daniel Veillard02141ea2001-04-30 11:46:40 +00003374 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003375 if (cur->type == XML_DTD_NODE) {
3376 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003377 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003378 }
3379 if (cur->type == XML_NAMESPACE_DECL) {
3380 xmlFreeNs((xmlNsPtr) cur);
3381 return;
3382 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003383 if (cur->type == XML_ATTRIBUTE_NODE) {
3384 xmlFreeProp((xmlAttrPtr) cur);
3385 return;
3386 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003387
Daniel Veillarda880b122003-04-21 21:36:41 +00003388 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003389 xmlDeregisterNodeDefaultValue(cur);
3390
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003391 if (cur->doc != NULL) dict = cur->doc->dict;
3392
Owen Taylor3473f882001-02-23 17:55:21 +00003393 if ((cur->children != NULL) &&
3394 (cur->type != XML_ENTITY_REF_NODE))
3395 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003396 if (((cur->type == XML_ELEMENT_NODE) ||
3397 (cur->type == XML_XINCLUDE_START) ||
3398 (cur->type == XML_XINCLUDE_END)) &&
3399 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003400 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003401 if ((cur->type != XML_ELEMENT_NODE) &&
3402 (cur->content != NULL) &&
3403 (cur->type != XML_ENTITY_REF_NODE) &&
3404 (cur->type != XML_XINCLUDE_END) &&
Daniel Veillard8874b942005-08-25 13:19:21 +00003405 (cur->type != XML_XINCLUDE_START) &&
3406 (cur->content != (xmlChar *) &(cur->properties))) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003407 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003408 }
3409
Daniel Veillardacd370f2001-06-09 17:17:51 +00003410 /*
3411 * When a node is a text node or a comment, it uses a global static
3412 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003413 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003414 */
Owen Taylor3473f882001-02-23 17:55:21 +00003415 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003416 (cur->type != XML_TEXT_NODE) &&
3417 (cur->type != XML_COMMENT_NODE))
3418 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003419
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003420 if (((cur->type == XML_ELEMENT_NODE) ||
3421 (cur->type == XML_XINCLUDE_START) ||
3422 (cur->type == XML_XINCLUDE_END)) &&
3423 (cur->nsDef != NULL))
3424 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003425 xmlFree(cur);
3426}
3427
3428/**
3429 * xmlUnlinkNode:
3430 * @cur: the node
3431 *
3432 * Unlink a node from it's current context, the node is not freed
3433 */
3434void
3435xmlUnlinkNode(xmlNodePtr cur) {
3436 if (cur == NULL) {
3437#ifdef DEBUG_TREE
3438 xmlGenericError(xmlGenericErrorContext,
3439 "xmlUnlinkNode : node == NULL\n");
3440#endif
3441 return;
3442 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003443 if (cur->type == XML_DTD_NODE) {
3444 xmlDocPtr doc;
3445 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003446 if (doc != NULL) {
3447 if (doc->intSubset == (xmlDtdPtr) cur)
3448 doc->intSubset = NULL;
3449 if (doc->extSubset == (xmlDtdPtr) cur)
3450 doc->extSubset = NULL;
3451 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003452 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003453 if (cur->parent != NULL) {
3454 xmlNodePtr parent;
3455 parent = cur->parent;
3456 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardda6f4af2005-06-20 17:17:54 +00003457 /* If attribute is an ID from subset then remove it */
3458 if ((((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID) &&
3459 xmlIsID(parent->doc, parent, (xmlAttrPtr) cur)) {
3460 xmlRemoveID(cur->doc, (xmlAttrPtr) cur);
3461 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003462 if (parent->properties == (xmlAttrPtr) cur)
3463 parent->properties = ((xmlAttrPtr) cur)->next;
3464 } else {
3465 if (parent->children == cur)
3466 parent->children = cur->next;
3467 if (parent->last == cur)
3468 parent->last = cur->prev;
3469 }
3470 cur->parent = NULL;
3471 }
Owen Taylor3473f882001-02-23 17:55:21 +00003472 if (cur->next != NULL)
3473 cur->next->prev = cur->prev;
3474 if (cur->prev != NULL)
3475 cur->prev->next = cur->next;
3476 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003477}
3478
Daniel Veillard2156d432004-03-04 15:59:36 +00003479#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003480/**
3481 * xmlReplaceNode:
3482 * @old: the old node
3483 * @cur: the node
3484 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003485 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003486 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003487 * first unlinked from its existing context.
3488 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003489 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003490 */
3491xmlNodePtr
3492xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00003493 if (old == cur) return(NULL);
Daniel Veillarda03e3652004-11-02 18:45:30 +00003494 if ((old == NULL) || (old->parent == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003495#ifdef DEBUG_TREE
3496 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda03e3652004-11-02 18:45:30 +00003497 "xmlReplaceNode : old == NULL or without parent\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003498#endif
3499 return(NULL);
3500 }
3501 if (cur == NULL) {
3502 xmlUnlinkNode(old);
3503 return(old);
3504 }
3505 if (cur == old) {
3506 return(old);
3507 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003508 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3509#ifdef DEBUG_TREE
3510 xmlGenericError(xmlGenericErrorContext,
3511 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3512#endif
3513 return(old);
3514 }
3515 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3516#ifdef DEBUG_TREE
3517 xmlGenericError(xmlGenericErrorContext,
3518 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3519#endif
3520 return(old);
3521 }
Owen Taylor3473f882001-02-23 17:55:21 +00003522 xmlUnlinkNode(cur);
Daniel Veillard64d7d122005-05-11 18:03:42 +00003523 xmlSetTreeDoc(cur, old->doc);
Owen Taylor3473f882001-02-23 17:55:21 +00003524 cur->parent = old->parent;
3525 cur->next = old->next;
3526 if (cur->next != NULL)
3527 cur->next->prev = cur;
3528 cur->prev = old->prev;
3529 if (cur->prev != NULL)
3530 cur->prev->next = cur;
3531 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003532 if (cur->type == XML_ATTRIBUTE_NODE) {
3533 if (cur->parent->properties == (xmlAttrPtr)old)
3534 cur->parent->properties = ((xmlAttrPtr) cur);
Daniel Veillardda6f4af2005-06-20 17:17:54 +00003535
3536 /* If old attribute is ID and defined in DTD then remove ID */
3537 if ((((xmlAttrPtr) old)->atype == XML_ATTRIBUTE_ID) &&
3538 xmlIsID(old->doc, old->parent, (xmlAttrPtr) old)) {
3539 xmlRemoveID(old->doc, (xmlAttrPtr) old);
3540 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003541 } else {
3542 if (cur->parent->children == old)
3543 cur->parent->children = cur;
3544 if (cur->parent->last == old)
3545 cur->parent->last = cur;
3546 }
Owen Taylor3473f882001-02-23 17:55:21 +00003547 }
3548 old->next = old->prev = NULL;
3549 old->parent = NULL;
3550 return(old);
3551}
Daniel Veillard652327a2003-09-29 18:02:38 +00003552#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003553
3554/************************************************************************
3555 * *
3556 * Copy operations *
3557 * *
3558 ************************************************************************/
3559
3560/**
3561 * xmlCopyNamespace:
3562 * @cur: the namespace
3563 *
3564 * Do a copy of the namespace.
3565 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003566 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003567 */
3568xmlNsPtr
3569xmlCopyNamespace(xmlNsPtr cur) {
3570 xmlNsPtr ret;
3571
3572 if (cur == NULL) return(NULL);
3573 switch (cur->type) {
3574 case XML_LOCAL_NAMESPACE:
3575 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3576 break;
3577 default:
3578#ifdef DEBUG_TREE
3579 xmlGenericError(xmlGenericErrorContext,
3580 "xmlCopyNamespace: invalid type %d\n", cur->type);
3581#endif
3582 return(NULL);
3583 }
3584 return(ret);
3585}
3586
3587/**
3588 * xmlCopyNamespaceList:
3589 * @cur: the first namespace
3590 *
3591 * Do a copy of an namespace list.
3592 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003593 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003594 */
3595xmlNsPtr
3596xmlCopyNamespaceList(xmlNsPtr cur) {
3597 xmlNsPtr ret = NULL;
3598 xmlNsPtr p = NULL,q;
3599
3600 while (cur != NULL) {
3601 q = xmlCopyNamespace(cur);
3602 if (p == NULL) {
3603 ret = p = q;
3604 } else {
3605 p->next = q;
3606 p = q;
3607 }
3608 cur = cur->next;
3609 }
3610 return(ret);
3611}
3612
3613static xmlNodePtr
3614xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
Rob Richards19dc9612005-10-28 16:15:16 +00003615
3616static xmlAttrPtr
3617xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003618 xmlAttrPtr ret;
3619
3620 if (cur == NULL) return(NULL);
3621 if (target != NULL)
3622 ret = xmlNewDocProp(target->doc, cur->name, NULL);
Rob Richards19dc9612005-10-28 16:15:16 +00003623 else if (doc != NULL)
3624 ret = xmlNewDocProp(doc, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003625 else if (cur->parent != NULL)
3626 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3627 else if (cur->children != NULL)
3628 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3629 else
3630 ret = xmlNewDocProp(NULL, cur->name, NULL);
3631 if (ret == NULL) return(NULL);
3632 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003633
Owen Taylor3473f882001-02-23 17:55:21 +00003634 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003635 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003636
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003637 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3638 if (ns == NULL) {
3639 /*
3640 * Humm, we are copying an element whose namespace is defined
3641 * out of the new tree scope. Search it in the original tree
3642 * and add it at the top of the new tree
3643 */
3644 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3645 if (ns != NULL) {
3646 xmlNodePtr root = target;
3647 xmlNodePtr pred = NULL;
3648
3649 while (root->parent != NULL) {
3650 pred = root;
3651 root = root->parent;
3652 }
3653 if (root == (xmlNodePtr) target->doc) {
3654 /* correct possibly cycling above the document elt */
3655 root = pred;
3656 }
3657 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3658 }
3659 } else {
3660 /*
3661 * we have to find something appropriate here since
3662 * we cant be sure, that the namespce we found is identified
3663 * by the prefix
3664 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003665 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003666 /* this is the nice case */
3667 ret->ns = ns;
3668 } else {
3669 /*
3670 * we are in trouble: we need a new reconcilied namespace.
3671 * This is expensive
3672 */
3673 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3674 }
3675 }
3676
Owen Taylor3473f882001-02-23 17:55:21 +00003677 } else
3678 ret->ns = NULL;
3679
3680 if (cur->children != NULL) {
3681 xmlNodePtr tmp;
3682
3683 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3684 ret->last = NULL;
3685 tmp = ret->children;
3686 while (tmp != NULL) {
3687 /* tmp->parent = (xmlNodePtr)ret; */
3688 if (tmp->next == NULL)
3689 ret->last = tmp;
3690 tmp = tmp->next;
3691 }
3692 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003693 /*
3694 * Try to handle IDs
3695 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003696 if ((target!= NULL) && (cur!= NULL) &&
3697 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003698 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3699 if (xmlIsID(cur->doc, cur->parent, cur)) {
3700 xmlChar *id;
3701
3702 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3703 if (id != NULL) {
3704 xmlAddID(NULL, target->doc, id, ret);
3705 xmlFree(id);
3706 }
3707 }
3708 }
Owen Taylor3473f882001-02-23 17:55:21 +00003709 return(ret);
3710}
3711
3712/**
Rob Richards19dc9612005-10-28 16:15:16 +00003713 * xmlCopyProp:
3714 * @target: the element where the attribute will be grafted
3715 * @cur: the attribute
3716 *
3717 * Do a copy of the attribute.
3718 *
3719 * Returns: a new #xmlAttrPtr, or NULL in case of error.
3720 */
3721xmlAttrPtr
3722xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3723 return xmlCopyPropInternal(NULL, target, cur);
3724}
3725
3726/**
Owen Taylor3473f882001-02-23 17:55:21 +00003727 * xmlCopyPropList:
3728 * @target: the element where the attributes will be grafted
3729 * @cur: the first attribute
3730 *
3731 * Do a copy of an attribute list.
3732 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003733 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003734 */
3735xmlAttrPtr
3736xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3737 xmlAttrPtr ret = NULL;
3738 xmlAttrPtr p = NULL,q;
3739
3740 while (cur != NULL) {
3741 q = xmlCopyProp(target, cur);
William M. Brack13dfa872004-09-18 04:52:08 +00003742 if (q == NULL)
3743 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003744 if (p == NULL) {
3745 ret = p = q;
3746 } else {
3747 p->next = q;
3748 q->prev = p;
3749 p = q;
3750 }
3751 cur = cur->next;
3752 }
3753 return(ret);
3754}
3755
3756/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003757 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003758 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003759 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003760 * tricky reason: namespaces. Doing a direct copy of a node
3761 * say RPM:Copyright without changing the namespace pointer to
3762 * something else can produce stale links. One way to do it is
3763 * to keep a reference counter but this doesn't work as soon
3764 * as one move the element or the subtree out of the scope of
3765 * the existing namespace. The actual solution seems to add
3766 * a copy of the namespace at the top of the copied tree if
3767 * not available in the subtree.
3768 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00003769 * The argument "recursive" normally indicates a recursive copy
3770 * of the node with values 0 (no) and 1 (yes). For XInclude,
3771 * however, we allow a value of 2 to indicate copy properties and
3772 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00003773 */
3774
3775static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003776xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00003777 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003778 xmlNodePtr ret;
3779
3780 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003781 switch (node->type) {
3782 case XML_TEXT_NODE:
3783 case XML_CDATA_SECTION_NODE:
3784 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003785 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003786 case XML_ENTITY_REF_NODE:
3787 case XML_ENTITY_NODE:
3788 case XML_PI_NODE:
3789 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003790 case XML_XINCLUDE_START:
3791 case XML_XINCLUDE_END:
3792 break;
3793 case XML_ATTRIBUTE_NODE:
Rob Richards19dc9612005-10-28 16:15:16 +00003794 return((xmlNodePtr) xmlCopyPropInternal(doc, parent, (xmlAttrPtr) node));
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003795 case XML_NAMESPACE_DECL:
3796 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3797
Daniel Veillard39196eb2001-06-19 18:09:42 +00003798 case XML_DOCUMENT_NODE:
3799 case XML_HTML_DOCUMENT_NODE:
3800#ifdef LIBXML_DOCB_ENABLED
3801 case XML_DOCB_DOCUMENT_NODE:
3802#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003803#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00003804 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00003805#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003806 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003807 case XML_NOTATION_NODE:
3808 case XML_DTD_NODE:
3809 case XML_ELEMENT_DECL:
3810 case XML_ATTRIBUTE_DECL:
3811 case XML_ENTITY_DECL:
3812 return(NULL);
3813 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003814
Owen Taylor3473f882001-02-23 17:55:21 +00003815 /*
3816 * Allocate a new node and fill the fields.
3817 */
3818 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3819 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003820 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003821 return(NULL);
3822 }
3823 memset(ret, 0, sizeof(xmlNode));
3824 ret->type = node->type;
3825
3826 ret->doc = doc;
3827 ret->parent = parent;
3828 if (node->name == xmlStringText)
3829 ret->name = xmlStringText;
3830 else if (node->name == xmlStringTextNoenc)
3831 ret->name = xmlStringTextNoenc;
3832 else if (node->name == xmlStringComment)
3833 ret->name = xmlStringComment;
Daniel Veillard03a53c32004-10-26 16:06:51 +00003834 else if (node->name != NULL) {
3835 if ((doc != NULL) && (doc->dict != NULL))
3836 ret->name = xmlDictLookup(doc->dict, node->name, -1);
3837 else
3838 ret->name = xmlStrdup(node->name);
3839 }
Daniel Veillard7db37732001-07-12 01:20:08 +00003840 if ((node->type != XML_ELEMENT_NODE) &&
3841 (node->content != NULL) &&
3842 (node->type != XML_ENTITY_REF_NODE) &&
3843 (node->type != XML_XINCLUDE_END) &&
3844 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003845 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003846 }else{
3847 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003848 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003849 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003850 if (parent != NULL) {
3851 xmlNodePtr tmp;
3852
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003853 /*
3854 * this is a tricky part for the node register thing:
3855 * in case ret does get coalesced in xmlAddChild
3856 * the deregister-node callback is called; so we register ret now already
3857 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003858 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003859 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3860
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003861 tmp = xmlAddChild(parent, ret);
3862 /* node could have coalesced */
3863 if (tmp != ret)
3864 return(tmp);
3865 }
Owen Taylor3473f882001-02-23 17:55:21 +00003866
William M. Brack57e9e912004-03-09 16:19:02 +00003867 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003868 goto out;
Daniel Veillard8874b942005-08-25 13:19:21 +00003869 if ((node->type == XML_ELEMENT_NODE) && (node->nsDef != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00003870 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3871
3872 if (node->ns != NULL) {
3873 xmlNsPtr ns;
3874
3875 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3876 if (ns == NULL) {
3877 /*
3878 * Humm, we are copying an element whose namespace is defined
3879 * out of the new tree scope. Search it in the original tree
3880 * and add it at the top of the new tree
3881 */
3882 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3883 if (ns != NULL) {
3884 xmlNodePtr root = ret;
3885
3886 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003887 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003888 }
3889 } else {
3890 /*
3891 * reference the existing namespace definition in our own tree.
3892 */
3893 ret->ns = ns;
3894 }
3895 }
Daniel Veillard8874b942005-08-25 13:19:21 +00003896 if ((node->type == XML_ELEMENT_NODE) && (node->properties != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00003897 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003898 if (node->type == XML_ENTITY_REF_NODE) {
3899 if ((doc == NULL) || (node->doc != doc)) {
3900 /*
3901 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003902 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003903 * we cannot keep the reference. Try to find it in the
3904 * target document.
3905 */
3906 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3907 } else {
3908 ret->children = node->children;
3909 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003910 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00003911 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003912 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003913 UPDATE_LAST_CHILD_AND_PARENT(ret)
3914 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003915
3916out:
3917 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00003918 if ((parent == NULL) &&
3919 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003920 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003921 return(ret);
3922}
3923
3924static xmlNodePtr
3925xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3926 xmlNodePtr ret = NULL;
3927 xmlNodePtr p = NULL,q;
3928
3929 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003930#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003931 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003932 if (doc == NULL) {
3933 node = node->next;
3934 continue;
3935 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003936 if (doc->intSubset == NULL) {
3937 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3938 q->doc = doc;
3939 q->parent = parent;
3940 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003941 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003942 } else {
3943 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003944 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003945 }
3946 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003947#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003948 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003949 if (ret == NULL) {
3950 q->prev = NULL;
3951 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003952 } else if (p != q) {
3953 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003954 p->next = q;
3955 q->prev = p;
3956 p = q;
3957 }
3958 node = node->next;
3959 }
3960 return(ret);
3961}
3962
3963/**
3964 * xmlCopyNode:
3965 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00003966 * @extended: if 1 do a recursive copy (properties, namespaces and children
3967 * when applicable)
3968 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00003969 *
3970 * Do a copy of the node.
3971 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003972 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003973 */
3974xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003975xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003976 xmlNodePtr ret;
3977
William M. Brack57e9e912004-03-09 16:19:02 +00003978 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00003979 return(ret);
3980}
3981
3982/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003983 * xmlDocCopyNode:
3984 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003985 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00003986 * @extended: if 1 do a recursive copy (properties, namespaces and children
3987 * when applicable)
3988 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00003989 *
3990 * Do a copy of the node to a given document.
3991 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003992 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003993 */
3994xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003995xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003996 xmlNodePtr ret;
3997
William M. Brack57e9e912004-03-09 16:19:02 +00003998 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00003999 return(ret);
4000}
4001
4002/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00004003 * xmlDocCopyNodeList:
4004 * @doc: the target document
4005 * @node: the first node in the list.
4006 *
4007 * Do a recursive copy of the node list.
4008 *
4009 * Returns: a new #xmlNodePtr, or NULL in case of error.
4010 */
4011xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) {
4012 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
4013 return(ret);
4014}
4015
4016/**
Owen Taylor3473f882001-02-23 17:55:21 +00004017 * xmlCopyNodeList:
4018 * @node: the first node in the list.
4019 *
4020 * Do a recursive copy of the node list.
Daniel Veillard03a53c32004-10-26 16:06:51 +00004021 * Use xmlDocCopyNodeList() if possible to ensure string interning.
Owen Taylor3473f882001-02-23 17:55:21 +00004022 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004023 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004024 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00004025xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00004026 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
4027 return(ret);
4028}
4029
Daniel Veillard2156d432004-03-04 15:59:36 +00004030#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004031/**
Owen Taylor3473f882001-02-23 17:55:21 +00004032 * xmlCopyDtd:
4033 * @dtd: the dtd
4034 *
4035 * Do a copy of the dtd.
4036 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004037 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004038 */
4039xmlDtdPtr
4040xmlCopyDtd(xmlDtdPtr dtd) {
4041 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004042 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00004043
4044 if (dtd == NULL) return(NULL);
4045 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4046 if (ret == NULL) return(NULL);
4047 if (dtd->entities != NULL)
4048 ret->entities = (void *) xmlCopyEntitiesTable(
4049 (xmlEntitiesTablePtr) dtd->entities);
4050 if (dtd->notations != NULL)
4051 ret->notations = (void *) xmlCopyNotationTable(
4052 (xmlNotationTablePtr) dtd->notations);
4053 if (dtd->elements != NULL)
4054 ret->elements = (void *) xmlCopyElementTable(
4055 (xmlElementTablePtr) dtd->elements);
4056 if (dtd->attributes != NULL)
4057 ret->attributes = (void *) xmlCopyAttributeTable(
4058 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004059 if (dtd->pentities != NULL)
4060 ret->pentities = (void *) xmlCopyEntitiesTable(
4061 (xmlEntitiesTablePtr) dtd->pentities);
4062
4063 cur = dtd->children;
4064 while (cur != NULL) {
4065 q = NULL;
4066
4067 if (cur->type == XML_ENTITY_DECL) {
4068 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4069 switch (tmp->etype) {
4070 case XML_INTERNAL_GENERAL_ENTITY:
4071 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4072 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4073 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4074 break;
4075 case XML_INTERNAL_PARAMETER_ENTITY:
4076 case XML_EXTERNAL_PARAMETER_ENTITY:
4077 q = (xmlNodePtr)
4078 xmlGetParameterEntityFromDtd(ret, tmp->name);
4079 break;
4080 case XML_INTERNAL_PREDEFINED_ENTITY:
4081 break;
4082 }
4083 } else if (cur->type == XML_ELEMENT_DECL) {
4084 xmlElementPtr tmp = (xmlElementPtr) cur;
4085 q = (xmlNodePtr)
4086 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4087 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4088 xmlAttributePtr tmp = (xmlAttributePtr) cur;
4089 q = (xmlNodePtr)
4090 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4091 } else if (cur->type == XML_COMMENT_NODE) {
4092 q = xmlCopyNode(cur, 0);
4093 }
4094
4095 if (q == NULL) {
4096 cur = cur->next;
4097 continue;
4098 }
4099
4100 if (p == NULL)
4101 ret->children = q;
4102 else
4103 p->next = q;
4104
4105 q->prev = p;
4106 q->parent = (xmlNodePtr) ret;
4107 q->next = NULL;
4108 ret->last = q;
4109 p = q;
4110 cur = cur->next;
4111 }
4112
Owen Taylor3473f882001-02-23 17:55:21 +00004113 return(ret);
4114}
Daniel Veillard2156d432004-03-04 15:59:36 +00004115#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004116
Daniel Veillard2156d432004-03-04 15:59:36 +00004117#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004118/**
4119 * xmlCopyDoc:
4120 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004121 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004122 *
4123 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004124 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004125 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004126 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004127 */
4128xmlDocPtr
4129xmlCopyDoc(xmlDocPtr doc, int recursive) {
4130 xmlDocPtr ret;
4131
4132 if (doc == NULL) return(NULL);
4133 ret = xmlNewDoc(doc->version);
4134 if (ret == NULL) return(NULL);
4135 if (doc->name != NULL)
4136 ret->name = xmlMemStrdup(doc->name);
4137 if (doc->encoding != NULL)
4138 ret->encoding = xmlStrdup(doc->encoding);
Daniel Veillardf59507d2005-01-27 17:26:49 +00004139 if (doc->URL != NULL)
4140 ret->URL = xmlStrdup(doc->URL);
Owen Taylor3473f882001-02-23 17:55:21 +00004141 ret->charset = doc->charset;
4142 ret->compression = doc->compression;
4143 ret->standalone = doc->standalone;
4144 if (!recursive) return(ret);
4145
Daniel Veillardb33c2012001-04-25 12:59:04 +00004146 ret->last = NULL;
4147 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004148#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004149 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004150 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004151 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004152 ret->intSubset->parent = ret;
4153 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004154#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004155 if (doc->oldNs != NULL)
4156 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4157 if (doc->children != NULL) {
4158 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004159
4160 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4161 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004162 ret->last = NULL;
4163 tmp = ret->children;
4164 while (tmp != NULL) {
4165 if (tmp->next == NULL)
4166 ret->last = tmp;
4167 tmp = tmp->next;
4168 }
4169 }
4170 return(ret);
4171}
Daniel Veillard652327a2003-09-29 18:02:38 +00004172#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004173
4174/************************************************************************
4175 * *
4176 * Content access functions *
4177 * *
4178 ************************************************************************/
4179
4180/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004181 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004182 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004183 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004184 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004185 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004186 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004187 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004188 */
4189long
4190xmlGetLineNo(xmlNodePtr node)
4191{
4192 long result = -1;
4193
4194 if (!node)
4195 return result;
Daniel Veillard73da77e2005-08-24 14:05:37 +00004196 if ((node->type == XML_ELEMENT_NODE) ||
4197 (node->type == XML_TEXT_NODE) ||
4198 (node->type == XML_COMMENT_NODE) ||
4199 (node->type == XML_PI_NODE))
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004200 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004201 else if ((node->prev != NULL) &&
4202 ((node->prev->type == XML_ELEMENT_NODE) ||
Daniel Veillard73da77e2005-08-24 14:05:37 +00004203 (node->prev->type == XML_TEXT_NODE) ||
4204 (node->prev->type == XML_COMMENT_NODE) ||
4205 (node->prev->type == XML_PI_NODE)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004206 result = xmlGetLineNo(node->prev);
4207 else if ((node->parent != NULL) &&
Daniel Veillard73da77e2005-08-24 14:05:37 +00004208 (node->parent->type == XML_ELEMENT_NODE))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004209 result = xmlGetLineNo(node->parent);
4210
4211 return result;
4212}
4213
Daniel Veillard2156d432004-03-04 15:59:36 +00004214#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004215/**
4216 * xmlGetNodePath:
4217 * @node: a node
4218 *
4219 * Build a structure based Path for the given node
4220 *
4221 * Returns the new path or NULL in case of error. The caller must free
4222 * the returned string
4223 */
4224xmlChar *
4225xmlGetNodePath(xmlNodePtr node)
4226{
4227 xmlNodePtr cur, tmp, next;
4228 xmlChar *buffer = NULL, *temp;
4229 size_t buf_len;
4230 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004231 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004232 const char *name;
4233 char nametemp[100];
4234 int occur = 0;
4235
4236 if (node == NULL)
4237 return (NULL);
4238
4239 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004240 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004241 if (buffer == NULL) {
4242 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004243 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004244 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004245 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004246 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004247 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004248 xmlFree(buffer);
4249 return (NULL);
4250 }
4251
4252 buffer[0] = 0;
4253 cur = node;
4254 do {
4255 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004256 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004257 occur = 0;
4258 if ((cur->type == XML_DOCUMENT_NODE) ||
4259 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4260 if (buffer[0] == '/')
4261 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004262 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004263 next = NULL;
4264 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004265 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004266 name = (const char *) cur->name;
4267 if (cur->ns) {
William M. Brack84d83e32003-12-23 03:45:17 +00004268 if (cur->ns->prefix != NULL)
William M. Brack13dfa872004-09-18 04:52:08 +00004269 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4270 (char *)cur->ns->prefix, (char *)cur->name);
William M. Brack84d83e32003-12-23 03:45:17 +00004271 else
William M. Brack13dfa872004-09-18 04:52:08 +00004272 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4273 (char *)cur->name);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004274 nametemp[sizeof(nametemp) - 1] = 0;
4275 name = nametemp;
4276 }
4277 next = cur->parent;
4278
4279 /*
4280 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004281 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004282 */
4283 tmp = cur->prev;
4284 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004285 if ((tmp->type == XML_ELEMENT_NODE) &&
Daniel Veillard0996a162005-02-05 14:00:10 +00004286 (xmlStrEqual(cur->name, tmp->name)) &&
4287 ((tmp->ns == cur->ns) ||
4288 ((tmp->ns != NULL) && (cur->ns != NULL) &&
4289 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004290 occur++;
4291 tmp = tmp->prev;
4292 }
4293 if (occur == 0) {
4294 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004295 while (tmp != NULL && occur == 0) {
4296 if ((tmp->type == XML_ELEMENT_NODE) &&
Daniel Veillard0996a162005-02-05 14:00:10 +00004297 (xmlStrEqual(cur->name, tmp->name)) &&
4298 ((tmp->ns == cur->ns) ||
4299 ((tmp->ns != NULL) && (cur->ns != NULL) &&
4300 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004301 occur++;
4302 tmp = tmp->next;
4303 }
4304 if (occur != 0)
4305 occur = 1;
4306 } else
4307 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004308 } else if (cur->type == XML_COMMENT_NODE) {
4309 sep = "/";
4310 name = "comment()";
4311 next = cur->parent;
4312
4313 /*
4314 * Thumbler index computation
4315 */
4316 tmp = cur->prev;
4317 while (tmp != NULL) {
4318 if (tmp->type == XML_COMMENT_NODE)
4319 occur++;
4320 tmp = tmp->prev;
4321 }
4322 if (occur == 0) {
4323 tmp = cur->next;
4324 while (tmp != NULL && occur == 0) {
4325 if (tmp->type == XML_COMMENT_NODE)
4326 occur++;
4327 tmp = tmp->next;
4328 }
4329 if (occur != 0)
4330 occur = 1;
4331 } else
4332 occur++;
4333 } else if ((cur->type == XML_TEXT_NODE) ||
4334 (cur->type == XML_CDATA_SECTION_NODE)) {
4335 sep = "/";
4336 name = "text()";
4337 next = cur->parent;
4338
4339 /*
4340 * Thumbler index computation
4341 */
4342 tmp = cur->prev;
4343 while (tmp != NULL) {
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004344 if ((tmp->type == XML_TEXT_NODE) ||
4345 (tmp->type == XML_CDATA_SECTION_NODE))
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004346 occur++;
4347 tmp = tmp->prev;
4348 }
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004349 /*
4350 * Evaluate if this is the only text- or CDATA-section-node;
4351 * if yes, then we'll get "text()", otherwise "text()[1]".
4352 */
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004353 if (occur == 0) {
4354 tmp = cur->next;
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004355 while (tmp != NULL) {
4356 if ((tmp->type == XML_TEXT_NODE) ||
4357 (tmp->type == XML_CDATA_SECTION_NODE))
4358 {
4359 occur = 1;
4360 break;
4361 }
4362 tmp = tmp->next;
4363 }
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004364 } else
4365 occur++;
4366 } else if (cur->type == XML_PI_NODE) {
4367 sep = "/";
4368 snprintf(nametemp, sizeof(nametemp) - 1,
William M. Brack13dfa872004-09-18 04:52:08 +00004369 "processing-instruction('%s')", (char *)cur->name);
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004370 nametemp[sizeof(nametemp) - 1] = 0;
4371 name = nametemp;
4372
4373 next = cur->parent;
4374
4375 /*
4376 * Thumbler index computation
4377 */
4378 tmp = cur->prev;
4379 while (tmp != NULL) {
4380 if ((tmp->type == XML_PI_NODE) &&
4381 (xmlStrEqual(cur->name, tmp->name)))
4382 occur++;
4383 tmp = tmp->prev;
4384 }
4385 if (occur == 0) {
4386 tmp = cur->next;
4387 while (tmp != NULL && occur == 0) {
4388 if ((tmp->type == XML_PI_NODE) &&
4389 (xmlStrEqual(cur->name, tmp->name)))
4390 occur++;
4391 tmp = tmp->next;
4392 }
4393 if (occur != 0)
4394 occur = 1;
4395 } else
4396 occur++;
4397
Daniel Veillard8faa7832001-11-26 15:58:08 +00004398 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004399 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004400 name = (const char *) (((xmlAttrPtr) cur)->name);
Daniel Veillard365c8062005-07-19 11:31:55 +00004401 if (cur->ns) {
4402 if (cur->ns->prefix != NULL)
4403 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4404 (char *)cur->ns->prefix, (char *)cur->name);
4405 else
4406 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4407 (char *)cur->name);
4408 nametemp[sizeof(nametemp) - 1] = 0;
4409 name = nametemp;
4410 }
Daniel Veillard8faa7832001-11-26 15:58:08 +00004411 next = ((xmlAttrPtr) cur)->parent;
4412 } else {
4413 next = cur->parent;
4414 }
4415
4416 /*
4417 * Make sure there is enough room
4418 */
4419 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4420 buf_len =
4421 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4422 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4423 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004424 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004425 xmlFree(buf);
4426 xmlFree(buffer);
4427 return (NULL);
4428 }
4429 buffer = temp;
4430 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4431 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004432 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004433 xmlFree(buf);
4434 xmlFree(buffer);
4435 return (NULL);
4436 }
4437 buf = temp;
4438 }
4439 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004440 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004441 sep, name, (char *) buffer);
4442 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004443 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004444 sep, name, occur, (char *) buffer);
William M. Brack13dfa872004-09-18 04:52:08 +00004445 snprintf((char *) buffer, buf_len, "%s", (char *)buf);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004446 cur = next;
4447 } while (cur != NULL);
4448 xmlFree(buf);
4449 return (buffer);
4450}
Daniel Veillard652327a2003-09-29 18:02:38 +00004451#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004452
4453/**
Owen Taylor3473f882001-02-23 17:55:21 +00004454 * xmlDocGetRootElement:
4455 * @doc: the document
4456 *
4457 * Get the root element of the document (doc->children is a list
4458 * containing possibly comments, PIs, etc ...).
4459 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004460 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004461 */
4462xmlNodePtr
4463xmlDocGetRootElement(xmlDocPtr doc) {
4464 xmlNodePtr ret;
4465
4466 if (doc == NULL) return(NULL);
4467 ret = doc->children;
4468 while (ret != NULL) {
4469 if (ret->type == XML_ELEMENT_NODE)
4470 return(ret);
4471 ret = ret->next;
4472 }
4473 return(ret);
4474}
4475
Daniel Veillard2156d432004-03-04 15:59:36 +00004476#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004477/**
4478 * xmlDocSetRootElement:
4479 * @doc: the document
4480 * @root: the new document root element
4481 *
4482 * Set the root element of the document (doc->children is a list
4483 * containing possibly comments, PIs, etc ...).
4484 *
4485 * Returns the old root element if any was found
4486 */
4487xmlNodePtr
4488xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4489 xmlNodePtr old = NULL;
4490
4491 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004492 if (root == NULL)
4493 return(NULL);
4494 xmlUnlinkNode(root);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00004495 xmlSetTreeDoc(root, doc);
Daniel Veillardc575b992002-02-08 13:28:40 +00004496 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004497 old = doc->children;
4498 while (old != NULL) {
4499 if (old->type == XML_ELEMENT_NODE)
4500 break;
4501 old = old->next;
4502 }
4503 if (old == NULL) {
4504 if (doc->children == NULL) {
4505 doc->children = root;
4506 doc->last = root;
4507 } else {
4508 xmlAddSibling(doc->children, root);
4509 }
4510 } else {
4511 xmlReplaceNode(old, root);
4512 }
4513 return(old);
4514}
Daniel Veillard2156d432004-03-04 15:59:36 +00004515#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004516
Daniel Veillard2156d432004-03-04 15:59:36 +00004517#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004518/**
4519 * xmlNodeSetLang:
4520 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004521 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004522 *
4523 * Set the language of a node, i.e. the values of the xml:lang
4524 * attribute.
4525 */
4526void
4527xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004528 xmlNsPtr ns;
4529
Owen Taylor3473f882001-02-23 17:55:21 +00004530 if (cur == NULL) return;
4531 switch(cur->type) {
4532 case XML_TEXT_NODE:
4533 case XML_CDATA_SECTION_NODE:
4534 case XML_COMMENT_NODE:
4535 case XML_DOCUMENT_NODE:
4536 case XML_DOCUMENT_TYPE_NODE:
4537 case XML_DOCUMENT_FRAG_NODE:
4538 case XML_NOTATION_NODE:
4539 case XML_HTML_DOCUMENT_NODE:
4540 case XML_DTD_NODE:
4541 case XML_ELEMENT_DECL:
4542 case XML_ATTRIBUTE_DECL:
4543 case XML_ENTITY_DECL:
4544 case XML_PI_NODE:
4545 case XML_ENTITY_REF_NODE:
4546 case XML_ENTITY_NODE:
4547 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004548#ifdef LIBXML_DOCB_ENABLED
4549 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004550#endif
4551 case XML_XINCLUDE_START:
4552 case XML_XINCLUDE_END:
4553 return;
4554 case XML_ELEMENT_NODE:
4555 case XML_ATTRIBUTE_NODE:
4556 break;
4557 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004558 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4559 if (ns == NULL)
4560 return;
4561 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004562}
Daniel Veillard652327a2003-09-29 18:02:38 +00004563#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004564
4565/**
4566 * xmlNodeGetLang:
4567 * @cur: the node being checked
4568 *
4569 * Searches the language of a node, i.e. the values of the xml:lang
4570 * attribute or the one carried by the nearest ancestor.
4571 *
4572 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004573 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004574 */
4575xmlChar *
4576xmlNodeGetLang(xmlNodePtr cur) {
4577 xmlChar *lang;
4578
4579 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004580 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004581 if (lang != NULL)
4582 return(lang);
4583 cur = cur->parent;
4584 }
4585 return(NULL);
4586}
4587
4588
Daniel Veillard652327a2003-09-29 18:02:38 +00004589#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004590/**
4591 * xmlNodeSetSpacePreserve:
4592 * @cur: the node being changed
4593 * @val: the xml:space value ("0": default, 1: "preserve")
4594 *
4595 * Set (or reset) the space preserving behaviour of a node, i.e. the
4596 * value of the xml:space attribute.
4597 */
4598void
4599xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004600 xmlNsPtr ns;
4601
Owen Taylor3473f882001-02-23 17:55:21 +00004602 if (cur == NULL) return;
4603 switch(cur->type) {
4604 case XML_TEXT_NODE:
4605 case XML_CDATA_SECTION_NODE:
4606 case XML_COMMENT_NODE:
4607 case XML_DOCUMENT_NODE:
4608 case XML_DOCUMENT_TYPE_NODE:
4609 case XML_DOCUMENT_FRAG_NODE:
4610 case XML_NOTATION_NODE:
4611 case XML_HTML_DOCUMENT_NODE:
4612 case XML_DTD_NODE:
4613 case XML_ELEMENT_DECL:
4614 case XML_ATTRIBUTE_DECL:
4615 case XML_ENTITY_DECL:
4616 case XML_PI_NODE:
4617 case XML_ENTITY_REF_NODE:
4618 case XML_ENTITY_NODE:
4619 case XML_NAMESPACE_DECL:
4620 case XML_XINCLUDE_START:
4621 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004622#ifdef LIBXML_DOCB_ENABLED
4623 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004624#endif
4625 return;
4626 case XML_ELEMENT_NODE:
4627 case XML_ATTRIBUTE_NODE:
4628 break;
4629 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004630 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4631 if (ns == NULL)
4632 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004633 switch (val) {
4634 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004635 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004636 break;
4637 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004638 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004639 break;
4640 }
4641}
Daniel Veillard652327a2003-09-29 18:02:38 +00004642#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004643
4644/**
4645 * xmlNodeGetSpacePreserve:
4646 * @cur: the node being checked
4647 *
4648 * Searches the space preserving behaviour of a node, i.e. the values
4649 * of the xml:space attribute or the one carried by the nearest
4650 * ancestor.
4651 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004652 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004653 */
4654int
4655xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4656 xmlChar *space;
4657
4658 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004659 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004660 if (space != NULL) {
4661 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4662 xmlFree(space);
4663 return(1);
4664 }
4665 if (xmlStrEqual(space, BAD_CAST "default")) {
4666 xmlFree(space);
4667 return(0);
4668 }
4669 xmlFree(space);
4670 }
4671 cur = cur->parent;
4672 }
4673 return(-1);
4674}
4675
Daniel Veillard652327a2003-09-29 18:02:38 +00004676#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004677/**
4678 * xmlNodeSetName:
4679 * @cur: the node being changed
4680 * @name: the new tag name
4681 *
4682 * Set (or reset) the name of a node.
4683 */
4684void
4685xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00004686 xmlDocPtr doc;
4687 xmlDictPtr dict;
4688
Owen Taylor3473f882001-02-23 17:55:21 +00004689 if (cur == NULL) return;
4690 if (name == NULL) return;
4691 switch(cur->type) {
4692 case XML_TEXT_NODE:
4693 case XML_CDATA_SECTION_NODE:
4694 case XML_COMMENT_NODE:
4695 case XML_DOCUMENT_TYPE_NODE:
4696 case XML_DOCUMENT_FRAG_NODE:
4697 case XML_NOTATION_NODE:
4698 case XML_HTML_DOCUMENT_NODE:
4699 case XML_NAMESPACE_DECL:
4700 case XML_XINCLUDE_START:
4701 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004702#ifdef LIBXML_DOCB_ENABLED
4703 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004704#endif
4705 return;
4706 case XML_ELEMENT_NODE:
4707 case XML_ATTRIBUTE_NODE:
4708 case XML_PI_NODE:
4709 case XML_ENTITY_REF_NODE:
4710 case XML_ENTITY_NODE:
4711 case XML_DTD_NODE:
4712 case XML_DOCUMENT_NODE:
4713 case XML_ELEMENT_DECL:
4714 case XML_ATTRIBUTE_DECL:
4715 case XML_ENTITY_DECL:
4716 break;
4717 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00004718 doc = cur->doc;
4719 if (doc != NULL)
4720 dict = doc->dict;
4721 else
4722 dict = NULL;
4723 if (dict != NULL) {
4724 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
4725 xmlFree((xmlChar *) cur->name);
4726 cur->name = xmlDictLookup(dict, name, -1);
4727 } else {
4728 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4729 cur->name = xmlStrdup(name);
4730 }
Owen Taylor3473f882001-02-23 17:55:21 +00004731}
Daniel Veillard2156d432004-03-04 15:59:36 +00004732#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004733
Daniel Veillard2156d432004-03-04 15:59:36 +00004734#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004735/**
4736 * xmlNodeSetBase:
4737 * @cur: the node being changed
4738 * @uri: the new base URI
4739 *
4740 * Set (or reset) the base URI of a node, i.e. the value of the
4741 * xml:base attribute.
4742 */
4743void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004744xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004745 xmlNsPtr ns;
4746
Owen Taylor3473f882001-02-23 17:55:21 +00004747 if (cur == NULL) return;
4748 switch(cur->type) {
4749 case XML_TEXT_NODE:
4750 case XML_CDATA_SECTION_NODE:
4751 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004752 case XML_DOCUMENT_TYPE_NODE:
4753 case XML_DOCUMENT_FRAG_NODE:
4754 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004755 case XML_DTD_NODE:
4756 case XML_ELEMENT_DECL:
4757 case XML_ATTRIBUTE_DECL:
4758 case XML_ENTITY_DECL:
4759 case XML_PI_NODE:
4760 case XML_ENTITY_REF_NODE:
4761 case XML_ENTITY_NODE:
4762 case XML_NAMESPACE_DECL:
4763 case XML_XINCLUDE_START:
4764 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004765 return;
4766 case XML_ELEMENT_NODE:
4767 case XML_ATTRIBUTE_NODE:
4768 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004769 case XML_DOCUMENT_NODE:
4770#ifdef LIBXML_DOCB_ENABLED
4771 case XML_DOCB_DOCUMENT_NODE:
4772#endif
4773 case XML_HTML_DOCUMENT_NODE: {
4774 xmlDocPtr doc = (xmlDocPtr) cur;
4775
4776 if (doc->URL != NULL)
4777 xmlFree((xmlChar *) doc->URL);
4778 if (uri == NULL)
4779 doc->URL = NULL;
4780 else
4781 doc->URL = xmlStrdup(uri);
4782 return;
4783 }
Owen Taylor3473f882001-02-23 17:55:21 +00004784 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004785
4786 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4787 if (ns == NULL)
4788 return;
4789 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004790}
Daniel Veillard652327a2003-09-29 18:02:38 +00004791#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004792
4793/**
Owen Taylor3473f882001-02-23 17:55:21 +00004794 * xmlNodeGetBase:
4795 * @doc: the document the node pertains to
4796 * @cur: the node being checked
4797 *
4798 * Searches for the BASE URL. The code should work on both XML
4799 * and HTML document even if base mechanisms are completely different.
4800 * It returns the base as defined in RFC 2396 sections
4801 * 5.1.1. Base URI within Document Content
4802 * and
4803 * 5.1.2. Base URI from the Encapsulating Entity
4804 * However it does not return the document base (5.1.3), use
4805 * xmlDocumentGetBase() for this
4806 *
4807 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004808 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004809 */
4810xmlChar *
4811xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004812 xmlChar *oldbase = NULL;
4813 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004814
4815 if ((cur == NULL) && (doc == NULL))
4816 return(NULL);
4817 if (doc == NULL) doc = cur->doc;
4818 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4819 cur = doc->children;
4820 while ((cur != NULL) && (cur->name != NULL)) {
4821 if (cur->type != XML_ELEMENT_NODE) {
4822 cur = cur->next;
4823 continue;
4824 }
4825 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4826 cur = cur->children;
4827 continue;
4828 }
4829 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4830 cur = cur->children;
4831 continue;
4832 }
4833 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4834 return(xmlGetProp(cur, BAD_CAST "href"));
4835 }
4836 cur = cur->next;
4837 }
4838 return(NULL);
4839 }
4840 while (cur != NULL) {
4841 if (cur->type == XML_ENTITY_DECL) {
4842 xmlEntityPtr ent = (xmlEntityPtr) cur;
4843 return(xmlStrdup(ent->URI));
4844 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004845 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004846 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004847 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004848 if (oldbase != NULL) {
4849 newbase = xmlBuildURI(oldbase, base);
4850 if (newbase != NULL) {
4851 xmlFree(oldbase);
4852 xmlFree(base);
4853 oldbase = newbase;
4854 } else {
4855 xmlFree(oldbase);
4856 xmlFree(base);
4857 return(NULL);
4858 }
4859 } else {
4860 oldbase = base;
4861 }
4862 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4863 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4864 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4865 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004866 }
4867 }
Owen Taylor3473f882001-02-23 17:55:21 +00004868 cur = cur->parent;
4869 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004870 if ((doc != NULL) && (doc->URL != NULL)) {
4871 if (oldbase == NULL)
4872 return(xmlStrdup(doc->URL));
4873 newbase = xmlBuildURI(oldbase, doc->URL);
4874 xmlFree(oldbase);
4875 return(newbase);
4876 }
4877 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004878}
4879
4880/**
Daniel Veillard78697292003-10-19 20:44:43 +00004881 * xmlNodeBufGetContent:
4882 * @buffer: a buffer
4883 * @cur: the node being read
4884 *
4885 * Read the value of a node @cur, this can be either the text carried
4886 * directly by this node if it's a TEXT node or the aggregate string
4887 * of the values carried by this node child's (TEXT and ENTITY_REF).
4888 * Entity references are substituted.
4889 * Fills up the buffer @buffer with this value
4890 *
4891 * Returns 0 in case of success and -1 in case of error.
4892 */
4893int
4894xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4895{
4896 if ((cur == NULL) || (buffer == NULL)) return(-1);
4897 switch (cur->type) {
4898 case XML_CDATA_SECTION_NODE:
4899 case XML_TEXT_NODE:
4900 xmlBufferCat(buffer, cur->content);
4901 break;
4902 case XML_DOCUMENT_FRAG_NODE:
4903 case XML_ELEMENT_NODE:{
4904 xmlNodePtr tmp = cur;
4905
4906 while (tmp != NULL) {
4907 switch (tmp->type) {
4908 case XML_CDATA_SECTION_NODE:
4909 case XML_TEXT_NODE:
4910 if (tmp->content != NULL)
4911 xmlBufferCat(buffer, tmp->content);
4912 break;
4913 case XML_ENTITY_REF_NODE:
Rob Richards77b92ff2005-12-20 15:55:14 +00004914 xmlNodeBufGetContent(buffer, tmp);
4915 break;
Daniel Veillard78697292003-10-19 20:44:43 +00004916 default:
4917 break;
4918 }
4919 /*
4920 * Skip to next node
4921 */
4922 if (tmp->children != NULL) {
4923 if (tmp->children->type != XML_ENTITY_DECL) {
4924 tmp = tmp->children;
4925 continue;
4926 }
4927 }
4928 if (tmp == cur)
4929 break;
4930
4931 if (tmp->next != NULL) {
4932 tmp = tmp->next;
4933 continue;
4934 }
4935
4936 do {
4937 tmp = tmp->parent;
4938 if (tmp == NULL)
4939 break;
4940 if (tmp == cur) {
4941 tmp = NULL;
4942 break;
4943 }
4944 if (tmp->next != NULL) {
4945 tmp = tmp->next;
4946 break;
4947 }
4948 } while (tmp != NULL);
4949 }
4950 break;
4951 }
4952 case XML_ATTRIBUTE_NODE:{
4953 xmlAttrPtr attr = (xmlAttrPtr) cur;
4954 xmlNodePtr tmp = attr->children;
4955
4956 while (tmp != NULL) {
4957 if (tmp->type == XML_TEXT_NODE)
4958 xmlBufferCat(buffer, tmp->content);
4959 else
4960 xmlNodeBufGetContent(buffer, tmp);
4961 tmp = tmp->next;
4962 }
4963 break;
4964 }
4965 case XML_COMMENT_NODE:
4966 case XML_PI_NODE:
4967 xmlBufferCat(buffer, cur->content);
4968 break;
4969 case XML_ENTITY_REF_NODE:{
4970 xmlEntityPtr ent;
4971 xmlNodePtr tmp;
4972
4973 /* lookup entity declaration */
4974 ent = xmlGetDocEntity(cur->doc, cur->name);
4975 if (ent == NULL)
4976 return(-1);
4977
4978 /* an entity content can be any "well balanced chunk",
4979 * i.e. the result of the content [43] production:
4980 * http://www.w3.org/TR/REC-xml#NT-content
4981 * -> we iterate through child nodes and recursive call
4982 * xmlNodeGetContent() which handles all possible node types */
4983 tmp = ent->children;
4984 while (tmp) {
4985 xmlNodeBufGetContent(buffer, tmp);
4986 tmp = tmp->next;
4987 }
4988 break;
4989 }
4990 case XML_ENTITY_NODE:
4991 case XML_DOCUMENT_TYPE_NODE:
4992 case XML_NOTATION_NODE:
4993 case XML_DTD_NODE:
4994 case XML_XINCLUDE_START:
4995 case XML_XINCLUDE_END:
4996 break;
4997 case XML_DOCUMENT_NODE:
4998#ifdef LIBXML_DOCB_ENABLED
4999 case XML_DOCB_DOCUMENT_NODE:
5000#endif
5001 case XML_HTML_DOCUMENT_NODE:
5002 cur = cur->children;
5003 while (cur!= NULL) {
5004 if ((cur->type == XML_ELEMENT_NODE) ||
5005 (cur->type == XML_TEXT_NODE) ||
5006 (cur->type == XML_CDATA_SECTION_NODE)) {
5007 xmlNodeBufGetContent(buffer, cur);
5008 }
5009 cur = cur->next;
5010 }
5011 break;
5012 case XML_NAMESPACE_DECL:
5013 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
5014 break;
5015 case XML_ELEMENT_DECL:
5016 case XML_ATTRIBUTE_DECL:
5017 case XML_ENTITY_DECL:
5018 break;
5019 }
5020 return(0);
5021}
5022/**
Owen Taylor3473f882001-02-23 17:55:21 +00005023 * xmlNodeGetContent:
5024 * @cur: the node being read
5025 *
5026 * Read the value of a node, this can be either the text carried
5027 * directly by this node if it's a TEXT node or the aggregate string
5028 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00005029 * Entity references are substituted.
5030 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005031 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005032 */
5033xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00005034xmlNodeGetContent(xmlNodePtr cur)
5035{
5036 if (cur == NULL)
5037 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005038 switch (cur->type) {
5039 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005040 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00005041 xmlBufferPtr buffer;
5042 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00005043
Daniel Veillard814a76d2003-01-23 18:24:20 +00005044 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00005045 if (buffer == NULL)
5046 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00005047 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005048 ret = buffer->content;
5049 buffer->content = NULL;
5050 xmlBufferFree(buffer);
5051 return (ret);
5052 }
5053 case XML_ATTRIBUTE_NODE:{
5054 xmlAttrPtr attr = (xmlAttrPtr) cur;
5055
5056 if (attr->parent != NULL)
5057 return (xmlNodeListGetString
5058 (attr->parent->doc, attr->children, 1));
5059 else
5060 return (xmlNodeListGetString(NULL, attr->children, 1));
5061 break;
5062 }
Owen Taylor3473f882001-02-23 17:55:21 +00005063 case XML_COMMENT_NODE:
5064 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005065 if (cur->content != NULL)
5066 return (xmlStrdup(cur->content));
5067 return (NULL);
5068 case XML_ENTITY_REF_NODE:{
5069 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00005070 xmlBufferPtr buffer;
5071 xmlChar *ret;
5072
5073 /* lookup entity declaration */
5074 ent = xmlGetDocEntity(cur->doc, cur->name);
5075 if (ent == NULL)
5076 return (NULL);
5077
5078 buffer = xmlBufferCreate();
5079 if (buffer == NULL)
5080 return (NULL);
5081
Daniel Veillardc4696922003-10-19 21:47:14 +00005082 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005083
5084 ret = buffer->content;
5085 buffer->content = NULL;
5086 xmlBufferFree(buffer);
5087 return (ret);
5088 }
Owen Taylor3473f882001-02-23 17:55:21 +00005089 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005090 case XML_DOCUMENT_TYPE_NODE:
5091 case XML_NOTATION_NODE:
5092 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005093 case XML_XINCLUDE_START:
5094 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00005095 return (NULL);
5096 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005097#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005098 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005099#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005100 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00005101 xmlBufferPtr buffer;
5102 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005103
Daniel Veillardc4696922003-10-19 21:47:14 +00005104 buffer = xmlBufferCreate();
5105 if (buffer == NULL)
5106 return (NULL);
5107
5108 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5109
5110 ret = buffer->content;
5111 buffer->content = NULL;
5112 xmlBufferFree(buffer);
5113 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005114 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005115 case XML_NAMESPACE_DECL: {
5116 xmlChar *tmp;
5117
5118 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5119 return (tmp);
5120 }
Owen Taylor3473f882001-02-23 17:55:21 +00005121 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005122 /* TODO !!! */
5123 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005124 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005125 /* TODO !!! */
5126 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005127 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005128 /* TODO !!! */
5129 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005130 case XML_CDATA_SECTION_NODE:
5131 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005132 if (cur->content != NULL)
5133 return (xmlStrdup(cur->content));
5134 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005135 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005136 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005137}
Daniel Veillard652327a2003-09-29 18:02:38 +00005138
Owen Taylor3473f882001-02-23 17:55:21 +00005139/**
5140 * xmlNodeSetContent:
5141 * @cur: the node being modified
5142 * @content: the new value of the content
5143 *
5144 * Replace the content of a node.
5145 */
5146void
5147xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5148 if (cur == NULL) {
5149#ifdef DEBUG_TREE
5150 xmlGenericError(xmlGenericErrorContext,
5151 "xmlNodeSetContent : node == NULL\n");
5152#endif
5153 return;
5154 }
5155 switch (cur->type) {
5156 case XML_DOCUMENT_FRAG_NODE:
5157 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005158 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005159 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5160 cur->children = xmlStringGetNodeList(cur->doc, content);
5161 UPDATE_LAST_CHILD_AND_PARENT(cur)
5162 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005163 case XML_TEXT_NODE:
5164 case XML_CDATA_SECTION_NODE:
5165 case XML_ENTITY_REF_NODE:
5166 case XML_ENTITY_NODE:
5167 case XML_PI_NODE:
5168 case XML_COMMENT_NODE:
Daniel Veillard8874b942005-08-25 13:19:21 +00005169 if ((cur->content != NULL) &&
5170 (cur->content != (xmlChar *) &(cur->properties))) {
William M. Brack7762bb12004-01-04 14:49:01 +00005171 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
Daniel Veillardc587bce2005-05-10 15:28:08 +00005172 (xmlDictOwns(cur->doc->dict, cur->content))))
William M. Brack7762bb12004-01-04 14:49:01 +00005173 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005174 }
5175 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5176 cur->last = cur->children = NULL;
5177 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005178 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005179 } else
5180 cur->content = NULL;
Daniel Veillard8874b942005-08-25 13:19:21 +00005181 cur->properties = NULL;
5182 cur->nsDef = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00005183 break;
5184 case XML_DOCUMENT_NODE:
5185 case XML_HTML_DOCUMENT_NODE:
5186 case XML_DOCUMENT_TYPE_NODE:
5187 case XML_XINCLUDE_START:
5188 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005189#ifdef LIBXML_DOCB_ENABLED
5190 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005191#endif
5192 break;
5193 case XML_NOTATION_NODE:
5194 break;
5195 case XML_DTD_NODE:
5196 break;
5197 case XML_NAMESPACE_DECL:
5198 break;
5199 case XML_ELEMENT_DECL:
5200 /* TODO !!! */
5201 break;
5202 case XML_ATTRIBUTE_DECL:
5203 /* TODO !!! */
5204 break;
5205 case XML_ENTITY_DECL:
5206 /* TODO !!! */
5207 break;
5208 }
5209}
5210
Daniel Veillard652327a2003-09-29 18:02:38 +00005211#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005212/**
5213 * xmlNodeSetContentLen:
5214 * @cur: the node being modified
5215 * @content: the new value of the content
5216 * @len: the size of @content
5217 *
5218 * Replace the content of a node.
5219 */
5220void
5221xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5222 if (cur == NULL) {
5223#ifdef DEBUG_TREE
5224 xmlGenericError(xmlGenericErrorContext,
5225 "xmlNodeSetContentLen : node == NULL\n");
5226#endif
5227 return;
5228 }
5229 switch (cur->type) {
5230 case XML_DOCUMENT_FRAG_NODE:
5231 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005232 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005233 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5234 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5235 UPDATE_LAST_CHILD_AND_PARENT(cur)
5236 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005237 case XML_TEXT_NODE:
5238 case XML_CDATA_SECTION_NODE:
5239 case XML_ENTITY_REF_NODE:
5240 case XML_ENTITY_NODE:
5241 case XML_PI_NODE:
5242 case XML_COMMENT_NODE:
5243 case XML_NOTATION_NODE:
Daniel Veillard8874b942005-08-25 13:19:21 +00005244 if ((cur->content != NULL) &&
5245 (cur->content != (xmlChar *) &(cur->properties))) {
5246 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5247 (xmlDictOwns(cur->doc->dict, cur->content))))
5248 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005249 }
5250 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5251 cur->children = cur->last = NULL;
5252 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005253 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005254 } else
5255 cur->content = NULL;
Daniel Veillard8874b942005-08-25 13:19:21 +00005256 cur->properties = NULL;
5257 cur->nsDef = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00005258 break;
5259 case XML_DOCUMENT_NODE:
5260 case XML_DTD_NODE:
5261 case XML_HTML_DOCUMENT_NODE:
5262 case XML_DOCUMENT_TYPE_NODE:
5263 case XML_NAMESPACE_DECL:
5264 case XML_XINCLUDE_START:
5265 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005266#ifdef LIBXML_DOCB_ENABLED
5267 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005268#endif
5269 break;
5270 case XML_ELEMENT_DECL:
5271 /* TODO !!! */
5272 break;
5273 case XML_ATTRIBUTE_DECL:
5274 /* TODO !!! */
5275 break;
5276 case XML_ENTITY_DECL:
5277 /* TODO !!! */
5278 break;
5279 }
5280}
Daniel Veillard652327a2003-09-29 18:02:38 +00005281#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005282
5283/**
5284 * xmlNodeAddContentLen:
5285 * @cur: the node being modified
5286 * @content: extra content
5287 * @len: the size of @content
5288 *
5289 * Append the extra substring to the node content.
5290 */
5291void
5292xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5293 if (cur == NULL) {
5294#ifdef DEBUG_TREE
5295 xmlGenericError(xmlGenericErrorContext,
5296 "xmlNodeAddContentLen : node == NULL\n");
5297#endif
5298 return;
5299 }
5300 if (len <= 0) return;
5301 switch (cur->type) {
5302 case XML_DOCUMENT_FRAG_NODE:
5303 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005304 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005305
Daniel Veillard7db37732001-07-12 01:20:08 +00005306 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005307 newNode = xmlNewTextLen(content, len);
5308 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005309 tmp = xmlAddChild(cur, newNode);
5310 if (tmp != newNode)
5311 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005312 if ((last != NULL) && (last->next == newNode)) {
5313 xmlTextMerge(last, newNode);
5314 }
5315 }
5316 break;
5317 }
5318 case XML_ATTRIBUTE_NODE:
5319 break;
5320 case XML_TEXT_NODE:
5321 case XML_CDATA_SECTION_NODE:
5322 case XML_ENTITY_REF_NODE:
5323 case XML_ENTITY_NODE:
5324 case XML_PI_NODE:
5325 case XML_COMMENT_NODE:
5326 case XML_NOTATION_NODE:
5327 if (content != NULL) {
Daniel Veillard8874b942005-08-25 13:19:21 +00005328 if ((cur->content == (xmlChar *) &(cur->properties)) ||
5329 ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5330 xmlDictOwns(cur->doc->dict, cur->content))) {
5331 cur->content = xmlStrncatNew(cur->content, content, len);
5332 cur->properties = NULL;
5333 cur->nsDef = NULL;
William M. Brack7762bb12004-01-04 14:49:01 +00005334 break;
5335 }
Owen Taylor3473f882001-02-23 17:55:21 +00005336 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005337 }
5338 case XML_DOCUMENT_NODE:
5339 case XML_DTD_NODE:
5340 case XML_HTML_DOCUMENT_NODE:
5341 case XML_DOCUMENT_TYPE_NODE:
5342 case XML_NAMESPACE_DECL:
5343 case XML_XINCLUDE_START:
5344 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005345#ifdef LIBXML_DOCB_ENABLED
5346 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005347#endif
5348 break;
5349 case XML_ELEMENT_DECL:
5350 case XML_ATTRIBUTE_DECL:
5351 case XML_ENTITY_DECL:
5352 break;
5353 }
5354}
5355
5356/**
5357 * xmlNodeAddContent:
5358 * @cur: the node being modified
5359 * @content: extra content
5360 *
5361 * Append the extra substring to the node content.
5362 */
5363void
5364xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5365 int len;
5366
5367 if (cur == NULL) {
5368#ifdef DEBUG_TREE
5369 xmlGenericError(xmlGenericErrorContext,
5370 "xmlNodeAddContent : node == NULL\n");
5371#endif
5372 return;
5373 }
5374 if (content == NULL) return;
5375 len = xmlStrlen(content);
5376 xmlNodeAddContentLen(cur, content, len);
5377}
5378
5379/**
5380 * xmlTextMerge:
5381 * @first: the first text node
5382 * @second: the second text node being merged
5383 *
5384 * Merge two text nodes into one
5385 * Returns the first text node augmented
5386 */
5387xmlNodePtr
5388xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5389 if (first == NULL) return(second);
5390 if (second == NULL) return(first);
5391 if (first->type != XML_TEXT_NODE) return(first);
5392 if (second->type != XML_TEXT_NODE) return(first);
5393 if (second->name != first->name)
5394 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005395 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005396 xmlUnlinkNode(second);
5397 xmlFreeNode(second);
5398 return(first);
5399}
5400
Daniel Veillard2156d432004-03-04 15:59:36 +00005401#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005402/**
5403 * xmlGetNsList:
5404 * @doc: the document
5405 * @node: the current node
5406 *
5407 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005408 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005409 * that need to be freed by the caller or NULL if no
5410 * namespace if defined
5411 */
5412xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005413xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5414{
Owen Taylor3473f882001-02-23 17:55:21 +00005415 xmlNsPtr cur;
5416 xmlNsPtr *ret = NULL;
5417 int nbns = 0;
5418 int maxns = 10;
5419 int i;
5420
5421 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005422 if (node->type == XML_ELEMENT_NODE) {
5423 cur = node->nsDef;
5424 while (cur != NULL) {
5425 if (ret == NULL) {
5426 ret =
5427 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5428 sizeof(xmlNsPtr));
5429 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005430 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005431 return (NULL);
5432 }
5433 ret[nbns] = NULL;
5434 }
5435 for (i = 0; i < nbns; i++) {
5436 if ((cur->prefix == ret[i]->prefix) ||
5437 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5438 break;
5439 }
5440 if (i >= nbns) {
5441 if (nbns >= maxns) {
5442 maxns *= 2;
5443 ret = (xmlNsPtr *) xmlRealloc(ret,
5444 (maxns +
5445 1) *
5446 sizeof(xmlNsPtr));
5447 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005448 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005449 return (NULL);
5450 }
5451 }
5452 ret[nbns++] = cur;
5453 ret[nbns] = NULL;
5454 }
Owen Taylor3473f882001-02-23 17:55:21 +00005455
Daniel Veillard77044732001-06-29 21:31:07 +00005456 cur = cur->next;
5457 }
5458 }
5459 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005460 }
Daniel Veillard77044732001-06-29 21:31:07 +00005461 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005462}
Daniel Veillard652327a2003-09-29 18:02:38 +00005463#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005464
5465/**
5466 * xmlSearchNs:
5467 * @doc: the document
5468 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005469 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005470 *
5471 * Search a Ns registered under a given name space for a document.
5472 * recurse on the parents until it finds the defined namespace
5473 * or return NULL otherwise.
5474 * @nameSpace can be NULL, this is a search for the default namespace.
5475 * We don't allow to cross entities boundaries. If you don't declare
5476 * the namespace within those you will be in troubles !!! A warning
5477 * is generated to cover this case.
5478 *
5479 * Returns the namespace pointer or NULL.
5480 */
5481xmlNsPtr
5482xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005483
Owen Taylor3473f882001-02-23 17:55:21 +00005484 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005485 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005486
5487 if (node == NULL) return(NULL);
5488 if ((nameSpace != NULL) &&
5489 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005490 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5491 /*
5492 * The XML-1.0 namespace is normally held on the root
5493 * element. In this case exceptionally create it on the
5494 * node element.
5495 */
5496 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5497 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005498 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005499 return(NULL);
5500 }
5501 memset(cur, 0, sizeof(xmlNs));
5502 cur->type = XML_LOCAL_NAMESPACE;
5503 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5504 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5505 cur->next = node->nsDef;
5506 node->nsDef = cur;
5507 return(cur);
5508 }
Owen Taylor3473f882001-02-23 17:55:21 +00005509 if (doc->oldNs == NULL) {
5510 /*
5511 * Allocate a new Namespace and fill the fields.
5512 */
5513 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5514 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005515 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005516 return(NULL);
5517 }
5518 memset(doc->oldNs, 0, sizeof(xmlNs));
5519 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5520
5521 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5522 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5523 }
5524 return(doc->oldNs);
5525 }
5526 while (node != NULL) {
5527 if ((node->type == XML_ENTITY_REF_NODE) ||
5528 (node->type == XML_ENTITY_NODE) ||
5529 (node->type == XML_ENTITY_DECL))
5530 return(NULL);
5531 if (node->type == XML_ELEMENT_NODE) {
5532 cur = node->nsDef;
5533 while (cur != NULL) {
5534 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5535 (cur->href != NULL))
5536 return(cur);
5537 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5538 (cur->href != NULL) &&
5539 (xmlStrEqual(cur->prefix, nameSpace)))
5540 return(cur);
5541 cur = cur->next;
5542 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005543 if (orig != node) {
5544 cur = node->ns;
5545 if (cur != NULL) {
5546 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5547 (cur->href != NULL))
5548 return(cur);
5549 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5550 (cur->href != NULL) &&
5551 (xmlStrEqual(cur->prefix, nameSpace)))
5552 return(cur);
5553 }
5554 }
Owen Taylor3473f882001-02-23 17:55:21 +00005555 }
5556 node = node->parent;
5557 }
5558 return(NULL);
5559}
5560
5561/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005562 * xmlNsInScope:
5563 * @doc: the document
5564 * @node: the current node
5565 * @ancestor: the ancestor carrying the namespace
5566 * @prefix: the namespace prefix
5567 *
5568 * Verify that the given namespace held on @ancestor is still in scope
5569 * on node.
5570 *
5571 * Returns 1 if true, 0 if false and -1 in case of error.
5572 */
5573static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005574xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5575 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005576{
5577 xmlNsPtr tst;
5578
5579 while ((node != NULL) && (node != ancestor)) {
5580 if ((node->type == XML_ENTITY_REF_NODE) ||
5581 (node->type == XML_ENTITY_NODE) ||
5582 (node->type == XML_ENTITY_DECL))
5583 return (-1);
5584 if (node->type == XML_ELEMENT_NODE) {
5585 tst = node->nsDef;
5586 while (tst != NULL) {
5587 if ((tst->prefix == NULL)
5588 && (prefix == NULL))
5589 return (0);
5590 if ((tst->prefix != NULL)
5591 && (prefix != NULL)
5592 && (xmlStrEqual(tst->prefix, prefix)))
5593 return (0);
5594 tst = tst->next;
5595 }
5596 }
5597 node = node->parent;
5598 }
5599 if (node != ancestor)
5600 return (-1);
5601 return (1);
5602}
5603
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005604/**
Owen Taylor3473f882001-02-23 17:55:21 +00005605 * xmlSearchNsByHref:
5606 * @doc: the document
5607 * @node: the current node
5608 * @href: the namespace value
5609 *
5610 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5611 * the defined namespace or return NULL otherwise.
5612 * Returns the namespace pointer or NULL.
5613 */
5614xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005615xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5616{
Owen Taylor3473f882001-02-23 17:55:21 +00005617 xmlNsPtr cur;
5618 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005619 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005620
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005621 if ((node == NULL) || (href == NULL))
5622 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005623 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005624 /*
5625 * Only the document can hold the XML spec namespace.
5626 */
5627 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5628 /*
5629 * The XML-1.0 namespace is normally held on the root
5630 * element. In this case exceptionally create it on the
5631 * node element.
5632 */
5633 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5634 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005635 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005636 return (NULL);
5637 }
5638 memset(cur, 0, sizeof(xmlNs));
5639 cur->type = XML_LOCAL_NAMESPACE;
5640 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5641 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5642 cur->next = node->nsDef;
5643 node->nsDef = cur;
5644 return (cur);
5645 }
5646 if (doc->oldNs == NULL) {
5647 /*
5648 * Allocate a new Namespace and fill the fields.
5649 */
5650 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5651 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005652 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005653 return (NULL);
5654 }
5655 memset(doc->oldNs, 0, sizeof(xmlNs));
5656 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005657
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005658 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5659 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5660 }
5661 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005662 }
Daniel Veillard62040be2004-05-17 03:17:26 +00005663 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00005664 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005665 if ((node->type == XML_ENTITY_REF_NODE) ||
5666 (node->type == XML_ENTITY_NODE) ||
5667 (node->type == XML_ENTITY_DECL))
5668 return (NULL);
5669 if (node->type == XML_ELEMENT_NODE) {
5670 cur = node->nsDef;
5671 while (cur != NULL) {
5672 if ((cur->href != NULL) && (href != NULL) &&
5673 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005674 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00005675 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005676 return (cur);
5677 }
5678 cur = cur->next;
5679 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005680 if (orig != node) {
5681 cur = node->ns;
5682 if (cur != NULL) {
5683 if ((cur->href != NULL) && (href != NULL) &&
5684 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005685 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00005686 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00005687 return (cur);
5688 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005689 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005690 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005691 }
5692 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005693 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005694 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005695}
5696
5697/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005698 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005699 * @doc: the document
5700 * @tree: a node expected to hold the new namespace
5701 * @ns: the original namespace
5702 *
5703 * This function tries to locate a namespace definition in a tree
5704 * ancestors, or create a new namespace definition node similar to
5705 * @ns trying to reuse the same prefix. However if the given prefix is
5706 * null (default namespace) or reused within the subtree defined by
5707 * @tree or on one of its ancestors then a new prefix is generated.
5708 * Returns the (new) namespace definition or NULL in case of error
5709 */
5710xmlNsPtr
5711xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5712 xmlNsPtr def;
5713 xmlChar prefix[50];
5714 int counter = 1;
5715
5716 if (tree == NULL) {
5717#ifdef DEBUG_TREE
5718 xmlGenericError(xmlGenericErrorContext,
5719 "xmlNewReconciliedNs : tree == NULL\n");
5720#endif
5721 return(NULL);
5722 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00005723 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005724#ifdef DEBUG_TREE
5725 xmlGenericError(xmlGenericErrorContext,
5726 "xmlNewReconciliedNs : ns == NULL\n");
5727#endif
5728 return(NULL);
5729 }
5730 /*
5731 * Search an existing namespace definition inherited.
5732 */
5733 def = xmlSearchNsByHref(doc, tree, ns->href);
5734 if (def != NULL)
5735 return(def);
5736
5737 /*
5738 * Find a close prefix which is not already in use.
5739 * Let's strip namespace prefixes longer than 20 chars !
5740 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005741 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005742 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005743 else
William M. Brack13dfa872004-09-18 04:52:08 +00005744 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005745
Owen Taylor3473f882001-02-23 17:55:21 +00005746 def = xmlSearchNs(doc, tree, prefix);
5747 while (def != NULL) {
5748 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005749 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005750 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005751 else
William M. Brack13dfa872004-09-18 04:52:08 +00005752 snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
5753 (char *)ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005754 def = xmlSearchNs(doc, tree, prefix);
5755 }
5756
5757 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005758 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005759 */
5760 def = xmlNewNs(tree, ns->href, prefix);
5761 return(def);
5762}
5763
Daniel Veillard652327a2003-09-29 18:02:38 +00005764#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005765/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005766 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005767 * @doc: the document
5768 * @tree: a node defining the subtree to reconciliate
5769 *
5770 * This function checks that all the namespaces declared within the given
5771 * tree are properly declared. This is needed for example after Copy or Cut
5772 * and then paste operations. The subtree may still hold pointers to
5773 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005774 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005775 * the new environment. If not possible the new namespaces are redeclared
5776 * on @tree at the top of the given subtree.
5777 * Returns the number of namespace declarations created or -1 in case of error.
5778 */
5779int
5780xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5781 xmlNsPtr *oldNs = NULL;
5782 xmlNsPtr *newNs = NULL;
5783 int sizeCache = 0;
5784 int nbCache = 0;
5785
5786 xmlNsPtr n;
5787 xmlNodePtr node = tree;
5788 xmlAttrPtr attr;
5789 int ret = 0, i;
5790
Daniel Veillardce244ad2004-11-05 10:03:46 +00005791 if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1);
5792 if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1);
5793 if (node->doc != doc) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005794 while (node != NULL) {
5795 /*
5796 * Reconciliate the node namespace
5797 */
5798 if (node->ns != NULL) {
5799 /*
5800 * initialize the cache if needed
5801 */
5802 if (sizeCache == 0) {
5803 sizeCache = 10;
5804 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5805 sizeof(xmlNsPtr));
5806 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005807 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005808 return(-1);
5809 }
5810 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5811 sizeof(xmlNsPtr));
5812 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005813 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005814 xmlFree(oldNs);
5815 return(-1);
5816 }
5817 }
5818 for (i = 0;i < nbCache;i++) {
5819 if (oldNs[i] == node->ns) {
5820 node->ns = newNs[i];
5821 break;
5822 }
5823 }
5824 if (i == nbCache) {
5825 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005826 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005827 */
5828 n = xmlNewReconciliedNs(doc, tree, node->ns);
5829 if (n != NULL) { /* :-( what if else ??? */
5830 /*
5831 * check if we need to grow the cache buffers.
5832 */
5833 if (sizeCache <= nbCache) {
5834 sizeCache *= 2;
5835 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5836 sizeof(xmlNsPtr));
5837 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005838 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005839 xmlFree(newNs);
5840 return(-1);
5841 }
5842 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5843 sizeof(xmlNsPtr));
5844 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005845 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005846 xmlFree(oldNs);
5847 return(-1);
5848 }
5849 }
5850 newNs[nbCache] = n;
5851 oldNs[nbCache++] = node->ns;
5852 node->ns = n;
5853 }
5854 }
5855 }
5856 /*
5857 * now check for namespace hold by attributes on the node.
5858 */
5859 attr = node->properties;
5860 while (attr != NULL) {
5861 if (attr->ns != NULL) {
5862 /*
5863 * initialize the cache if needed
5864 */
5865 if (sizeCache == 0) {
5866 sizeCache = 10;
5867 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5868 sizeof(xmlNsPtr));
5869 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005870 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005871 return(-1);
5872 }
5873 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5874 sizeof(xmlNsPtr));
5875 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005876 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005877 xmlFree(oldNs);
5878 return(-1);
5879 }
5880 }
5881 for (i = 0;i < nbCache;i++) {
5882 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005883 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005884 break;
5885 }
5886 }
5887 if (i == nbCache) {
5888 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005889 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005890 */
5891 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5892 if (n != NULL) { /* :-( what if else ??? */
5893 /*
5894 * check if we need to grow the cache buffers.
5895 */
5896 if (sizeCache <= nbCache) {
5897 sizeCache *= 2;
5898 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5899 sizeof(xmlNsPtr));
5900 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005901 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005902 xmlFree(newNs);
5903 return(-1);
5904 }
5905 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5906 sizeof(xmlNsPtr));
5907 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005908 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005909 xmlFree(oldNs);
5910 return(-1);
5911 }
5912 }
5913 newNs[nbCache] = n;
5914 oldNs[nbCache++] = attr->ns;
5915 attr->ns = n;
5916 }
5917 }
5918 }
5919 attr = attr->next;
5920 }
5921
5922 /*
5923 * Browse the full subtree, deep first
5924 */
Daniel Veillardac996a12004-07-30 12:02:58 +00005925 if (node->children != NULL && node->type != XML_ENTITY_REF_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00005926 /* deep first */
5927 node = node->children;
5928 } else if ((node != tree) && (node->next != NULL)) {
5929 /* then siblings */
5930 node = node->next;
5931 } else if (node != tree) {
5932 /* go up to parents->next if needed */
5933 while (node != tree) {
5934 if (node->parent != NULL)
5935 node = node->parent;
5936 if ((node != tree) && (node->next != NULL)) {
5937 node = node->next;
5938 break;
5939 }
5940 if (node->parent == NULL) {
5941 node = NULL;
5942 break;
5943 }
5944 }
5945 /* exit condition */
5946 if (node == tree)
5947 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005948 } else
5949 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005950 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005951 if (oldNs != NULL)
5952 xmlFree(oldNs);
5953 if (newNs != NULL)
5954 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005955 return(ret);
5956}
Daniel Veillard652327a2003-09-29 18:02:38 +00005957#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005958
5959/**
5960 * xmlHasProp:
5961 * @node: the node
5962 * @name: the attribute name
5963 *
5964 * Search an attribute associated to a node
5965 * This function also looks in DTD attribute declaration for #FIXED or
5966 * default declaration values unless DTD use has been turned off.
5967 *
5968 * Returns the attribute or the attribute declaration or NULL if
5969 * neither was found.
5970 */
5971xmlAttrPtr
5972xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5973 xmlAttrPtr prop;
5974 xmlDocPtr doc;
5975
Daniel Veillard8874b942005-08-25 13:19:21 +00005976 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
5977 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005978 /*
5979 * Check on the properties attached to the node
5980 */
5981 prop = node->properties;
5982 while (prop != NULL) {
5983 if (xmlStrEqual(prop->name, name)) {
5984 return(prop);
5985 }
5986 prop = prop->next;
5987 }
5988 if (!xmlCheckDTD) return(NULL);
5989
5990 /*
5991 * Check if there is a default declaration in the internal
5992 * or external subsets
5993 */
5994 doc = node->doc;
5995 if (doc != NULL) {
5996 xmlAttributePtr attrDecl;
5997 if (doc->intSubset != NULL) {
5998 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5999 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6000 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006001 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6002 /* return attribute declaration only if a default value is given
6003 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006004 return((xmlAttrPtr) attrDecl);
6005 }
6006 }
6007 return(NULL);
6008}
6009
6010/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00006011 * xmlHasNsProp:
6012 * @node: the node
6013 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006014 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00006015 *
6016 * Search for an attribute associated to a node
6017 * This attribute has to be anchored in the namespace specified.
6018 * This does the entity substitution.
6019 * This function looks in DTD attribute declaration for #FIXED or
6020 * default declaration values unless DTD use has been turned off.
William M. Brack2c228442004-10-03 04:10:00 +00006021 * Note that a namespace of NULL indicates to use the default namespace.
Daniel Veillarde95e2392001-06-06 10:46:28 +00006022 *
6023 * Returns the attribute or the attribute declaration or NULL
6024 * if neither was found.
6025 */
6026xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00006027xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00006028 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00006029#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00006030 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00006031#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00006032
Daniel Veillard8874b942005-08-25 13:19:21 +00006033 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
Daniel Veillarde95e2392001-06-06 10:46:28 +00006034 return(NULL);
6035
6036 prop = node->properties;
Daniel Veillarde95e2392001-06-06 10:46:28 +00006037 while (prop != NULL) {
6038 /*
6039 * One need to have
6040 * - same attribute names
6041 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00006042 */
William M. Brack2c228442004-10-03 04:10:00 +00006043 if (xmlStrEqual(prop->name, name)) {
6044 if (((prop->ns != NULL) &&
6045 (xmlStrEqual(prop->ns->href, nameSpace))) ||
6046 ((prop->ns == NULL) && (nameSpace == NULL))) {
6047 return(prop);
6048 }
Daniel Veillarde95e2392001-06-06 10:46:28 +00006049 }
6050 prop = prop->next;
6051 }
6052 if (!xmlCheckDTD) return(NULL);
6053
Daniel Veillard652327a2003-09-29 18:02:38 +00006054#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00006055 /*
6056 * Check if there is a default declaration in the internal
6057 * or external subsets
6058 */
6059 doc = node->doc;
6060 if (doc != NULL) {
6061 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006062 xmlAttributePtr attrDecl = NULL;
6063 xmlNsPtr *nsList, *cur;
6064 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00006065
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006066 nsList = xmlGetNsList(node->doc, node);
6067 if (nsList == NULL)
6068 return(NULL);
6069 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
6070 ename = xmlStrdup(node->ns->prefix);
6071 ename = xmlStrcat(ename, BAD_CAST ":");
6072 ename = xmlStrcat(ename, node->name);
6073 } else {
6074 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006075 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006076 if (ename == NULL) {
6077 xmlFree(nsList);
6078 return(NULL);
6079 }
6080
William M. Brack2c228442004-10-03 04:10:00 +00006081 if (nameSpace == NULL) {
6082 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
6083 name, NULL);
6084 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
6085 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6086 name, NULL);
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006087 }
William M. Brack2c228442004-10-03 04:10:00 +00006088 } else {
6089 cur = nsList;
6090 while (*cur != NULL) {
6091 if (xmlStrEqual((*cur)->href, nameSpace)) {
6092 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
6093 name, (*cur)->prefix);
6094 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6095 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6096 name, (*cur)->prefix);
6097 }
6098 cur++;
6099 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006100 }
6101 xmlFree(nsList);
6102 xmlFree(ename);
6103 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006104 }
6105 }
Daniel Veillard652327a2003-09-29 18:02:38 +00006106#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00006107 return(NULL);
6108}
6109
6110/**
Owen Taylor3473f882001-02-23 17:55:21 +00006111 * xmlGetProp:
6112 * @node: the node
6113 * @name: the attribute name
6114 *
6115 * Search and get the value of an attribute associated to a node
6116 * This does the entity substitution.
6117 * This function looks in DTD attribute declaration for #FIXED or
6118 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00006119 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00006120 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6121 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00006122 *
6123 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006124 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006125 */
6126xmlChar *
6127xmlGetProp(xmlNodePtr node, const xmlChar *name) {
6128 xmlAttrPtr prop;
6129 xmlDocPtr doc;
6130
Daniel Veillard8874b942005-08-25 13:19:21 +00006131 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6132 return(NULL);
6133
Owen Taylor3473f882001-02-23 17:55:21 +00006134 /*
6135 * Check on the properties attached to the node
6136 */
6137 prop = node->properties;
6138 while (prop != NULL) {
6139 if (xmlStrEqual(prop->name, name)) {
6140 xmlChar *ret;
6141
6142 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6143 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6144 return(ret);
6145 }
6146 prop = prop->next;
6147 }
6148 if (!xmlCheckDTD) return(NULL);
6149
6150 /*
6151 * Check if there is a default declaration in the internal
6152 * or external subsets
6153 */
6154 doc = node->doc;
6155 if (doc != NULL) {
6156 xmlAttributePtr attrDecl;
6157 if (doc->intSubset != NULL) {
6158 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6159 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6160 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006161 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6162 /* return attribute declaration only if a default value is given
6163 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006164 return(xmlStrdup(attrDecl->defaultValue));
6165 }
6166 }
6167 return(NULL);
6168}
6169
6170/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006171 * xmlGetNoNsProp:
6172 * @node: the node
6173 * @name: the attribute name
6174 *
6175 * Search and get the value of an attribute associated to a node
6176 * This does the entity substitution.
6177 * This function looks in DTD attribute declaration for #FIXED or
6178 * default declaration values unless DTD use has been turned off.
6179 * This function is similar to xmlGetProp except it will accept only
6180 * an attribute in no namespace.
6181 *
6182 * Returns the attribute value or NULL if not found.
6183 * It's up to the caller to free the memory with xmlFree().
6184 */
6185xmlChar *
6186xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6187 xmlAttrPtr prop;
6188 xmlDocPtr doc;
6189
Daniel Veillard8874b942005-08-25 13:19:21 +00006190 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6191 return(NULL);
Daniel Veillard71531f32003-02-05 13:19:53 +00006192 /*
6193 * Check on the properties attached to the node
6194 */
6195 prop = node->properties;
6196 while (prop != NULL) {
6197 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6198 xmlChar *ret;
6199
6200 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6201 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6202 return(ret);
6203 }
6204 prop = prop->next;
6205 }
6206 if (!xmlCheckDTD) return(NULL);
6207
6208 /*
6209 * Check if there is a default declaration in the internal
6210 * or external subsets
6211 */
6212 doc = node->doc;
6213 if (doc != NULL) {
6214 xmlAttributePtr attrDecl;
6215 if (doc->intSubset != NULL) {
6216 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6217 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6218 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006219 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6220 /* return attribute declaration only if a default value is given
6221 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006222 return(xmlStrdup(attrDecl->defaultValue));
6223 }
6224 }
6225 return(NULL);
6226}
6227
6228/**
Owen Taylor3473f882001-02-23 17:55:21 +00006229 * xmlGetNsProp:
6230 * @node: the node
6231 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006232 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006233 *
6234 * Search and get the value of an attribute associated to a node
6235 * This attribute has to be anchored in the namespace specified.
6236 * This does the entity substitution.
6237 * This function looks in DTD attribute declaration for #FIXED or
6238 * default declaration values unless DTD use has been turned off.
6239 *
6240 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006241 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006242 */
6243xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006244xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006245 xmlAttrPtr prop;
6246 xmlDocPtr doc;
6247 xmlNsPtr ns;
6248
Daniel Veillard8874b942005-08-25 13:19:21 +00006249 if ((node == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006250 return(NULL);
6251
6252 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006253 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006254 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006255 while (prop != NULL) {
6256 /*
6257 * One need to have
6258 * - same attribute names
6259 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006260 */
6261 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006262 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006263 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006264 xmlChar *ret;
6265
6266 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6267 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6268 return(ret);
6269 }
6270 prop = prop->next;
6271 }
6272 if (!xmlCheckDTD) return(NULL);
6273
6274 /*
6275 * Check if there is a default declaration in the internal
6276 * or external subsets
6277 */
6278 doc = node->doc;
6279 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006280 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006281 xmlAttributePtr attrDecl;
6282
Owen Taylor3473f882001-02-23 17:55:21 +00006283 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6284 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6285 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6286
6287 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6288 /*
6289 * The DTD declaration only allows a prefix search
6290 */
6291 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006292 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006293 return(xmlStrdup(attrDecl->defaultValue));
6294 }
6295 }
6296 }
6297 return(NULL);
6298}
6299
Daniel Veillard2156d432004-03-04 15:59:36 +00006300#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6301/**
6302 * xmlUnsetProp:
6303 * @node: the node
6304 * @name: the attribute name
6305 *
6306 * Remove an attribute carried by a node.
6307 * Returns 0 if successful, -1 if not found
6308 */
6309int
6310xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Kasimier T. Buchcik65c2f1d2005-10-17 12:39:58 +00006311 xmlAttrPtr prop;
Daniel Veillard2156d432004-03-04 15:59:36 +00006312
Daniel Veillard8874b942005-08-25 13:19:21 +00006313 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
Daniel Veillard2156d432004-03-04 15:59:36 +00006314 return(-1);
6315 prop = node->properties;
6316 while (prop != NULL) {
6317 if ((xmlStrEqual(prop->name, name)) &&
6318 (prop->ns == NULL)) {
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00006319 xmlUnlinkNode((xmlNodePtr) prop);
Daniel Veillard2156d432004-03-04 15:59:36 +00006320 xmlFreeProp(prop);
6321 return(0);
6322 }
Daniel Veillard2156d432004-03-04 15:59:36 +00006323 prop = prop->next;
6324 }
6325 return(-1);
6326}
6327
6328/**
6329 * xmlUnsetNsProp:
6330 * @node: the node
6331 * @ns: the namespace definition
6332 * @name: the attribute name
6333 *
6334 * Remove an attribute carried by a node.
6335 * Returns 0 if successful, -1 if not found
6336 */
6337int
6338xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
Kasimier T. Buchcik65c2f1d2005-10-17 12:39:58 +00006339 xmlAttrPtr prop;
Daniel Veillard2156d432004-03-04 15:59:36 +00006340
Daniel Veillard8874b942005-08-25 13:19:21 +00006341 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
Daniel Veillard2156d432004-03-04 15:59:36 +00006342 return(-1);
Daniel Veillard27f20102004-11-05 11:50:11 +00006343 prop = node->properties;
Daniel Veillard2156d432004-03-04 15:59:36 +00006344 if (ns == NULL)
6345 return(xmlUnsetProp(node, name));
6346 if (ns->href == NULL)
6347 return(-1);
6348 while (prop != NULL) {
6349 if ((xmlStrEqual(prop->name, name)) &&
6350 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00006351 xmlUnlinkNode((xmlNodePtr) prop);
Daniel Veillard2156d432004-03-04 15:59:36 +00006352 xmlFreeProp(prop);
6353 return(0);
6354 }
Daniel Veillard2156d432004-03-04 15:59:36 +00006355 prop = prop->next;
6356 }
6357 return(-1);
6358}
6359#endif
6360
6361#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006362/**
6363 * xmlSetProp:
6364 * @node: the node
6365 * @name: the attribute name
6366 * @value: the attribute value
6367 *
6368 * Set (or reset) an attribute carried by a node.
6369 * Returns the attribute pointer.
6370 */
6371xmlAttrPtr
6372xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006373 xmlAttrPtr prop;
6374 xmlDocPtr doc;
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006375 int len;
6376 const xmlChar *nqname;
Owen Taylor3473f882001-02-23 17:55:21 +00006377
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006378 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006379 return(NULL);
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006380
6381 /*
6382 * handle QNames
6383 */
6384 nqname = xmlSplitQName3(name, &len);
6385 if (nqname != NULL) {
6386 xmlNsPtr ns;
6387 xmlChar *prefix = xmlStrndup(name, len);
6388 ns = xmlSearchNs(node->doc, node, prefix);
6389 if (prefix != NULL)
6390 xmlFree(prefix);
6391 if (ns != NULL)
6392 return(xmlSetNsProp(node, ns, nqname, value));
6393 }
6394
Owen Taylor3473f882001-02-23 17:55:21 +00006395 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006396 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006397 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006398 if ((xmlStrEqual(prop->name, name)) &&
6399 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006400 xmlNodePtr oldprop = prop->children;
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006401 int id = xmlIsID(node->doc, node, prop);
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006402
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006403 if (id == 1)
6404 xmlRemoveID(node->doc, prop);
Owen Taylor3473f882001-02-23 17:55:21 +00006405 prop->children = NULL;
6406 prop->last = NULL;
6407 if (value != NULL) {
6408 xmlChar *buffer;
6409 xmlNodePtr tmp;
6410
6411 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6412 prop->children = xmlStringGetNodeList(node->doc, buffer);
6413 prop->last = NULL;
6414 prop->doc = doc;
6415 tmp = prop->children;
6416 while (tmp != NULL) {
6417 tmp->parent = (xmlNodePtr) prop;
6418 tmp->doc = doc;
6419 if (tmp->next == NULL)
6420 prop->last = tmp;
6421 tmp = tmp->next;
6422 }
6423 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006424 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006425 if (oldprop != NULL)
6426 xmlFreeNodeList(oldprop);
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006427 if (id)
6428 xmlAddID(NULL, node->doc, value, prop);
Owen Taylor3473f882001-02-23 17:55:21 +00006429 return(prop);
6430 }
6431 prop = prop->next;
6432 }
6433 prop = xmlNewProp(node, name, value);
6434 return(prop);
6435}
6436
6437/**
6438 * xmlSetNsProp:
6439 * @node: the node
6440 * @ns: the namespace definition
6441 * @name: the attribute name
6442 * @value: the attribute value
6443 *
6444 * Set (or reset) an attribute carried by a node.
6445 * The ns structure must be in scope, this is not checked.
6446 *
6447 * Returns the attribute pointer.
6448 */
6449xmlAttrPtr
6450xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6451 const xmlChar *value) {
6452 xmlAttrPtr prop;
6453
Daniel Veillardb6b36d32005-02-09 16:48:53 +00006454 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006455 return(NULL);
6456
6457 if (ns == NULL)
6458 return(xmlSetProp(node, name, value));
6459 if (ns->href == NULL)
6460 return(NULL);
6461 prop = node->properties;
6462
6463 while (prop != NULL) {
6464 /*
6465 * One need to have
6466 * - same attribute names
6467 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006468 */
6469 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006470 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006471 int id = xmlIsID(node->doc, node, prop);
6472
6473 if (id == 1)
6474 xmlRemoveID(node->doc, prop);
Owen Taylor3473f882001-02-23 17:55:21 +00006475 if (prop->children != NULL)
6476 xmlFreeNodeList(prop->children);
6477 prop->children = NULL;
6478 prop->last = NULL;
6479 prop->ns = ns;
6480 if (value != NULL) {
6481 xmlChar *buffer;
6482 xmlNodePtr tmp;
6483
6484 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6485 prop->children = xmlStringGetNodeList(node->doc, buffer);
6486 prop->last = NULL;
6487 tmp = prop->children;
6488 while (tmp != NULL) {
6489 tmp->parent = (xmlNodePtr) prop;
6490 if (tmp->next == NULL)
6491 prop->last = tmp;
6492 tmp = tmp->next;
6493 }
6494 xmlFree(buffer);
6495 }
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006496 if (id)
6497 xmlAddID(NULL, node->doc, value, prop);
Owen Taylor3473f882001-02-23 17:55:21 +00006498 return(prop);
6499 }
6500 prop = prop->next;
6501 }
6502 prop = xmlNewNsProp(node, ns, name, value);
6503 return(prop);
6504}
6505
Daniel Veillard652327a2003-09-29 18:02:38 +00006506#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006507
6508/**
Owen Taylor3473f882001-02-23 17:55:21 +00006509 * xmlNodeIsText:
6510 * @node: the node
6511 *
6512 * Is this node a Text node ?
6513 * Returns 1 yes, 0 no
6514 */
6515int
6516xmlNodeIsText(xmlNodePtr node) {
6517 if (node == NULL) return(0);
6518
6519 if (node->type == XML_TEXT_NODE) return(1);
6520 return(0);
6521}
6522
6523/**
6524 * xmlIsBlankNode:
6525 * @node: the node
6526 *
6527 * Checks whether this node is an empty or whitespace only
6528 * (and possibly ignorable) text-node.
6529 *
6530 * Returns 1 yes, 0 no
6531 */
6532int
6533xmlIsBlankNode(xmlNodePtr node) {
6534 const xmlChar *cur;
6535 if (node == NULL) return(0);
6536
Daniel Veillard7db37732001-07-12 01:20:08 +00006537 if ((node->type != XML_TEXT_NODE) &&
6538 (node->type != XML_CDATA_SECTION_NODE))
6539 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006540 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006541 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006542 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006543 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006544 cur++;
6545 }
6546
6547 return(1);
6548}
6549
6550/**
6551 * xmlTextConcat:
6552 * @node: the node
6553 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006554 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006555 *
6556 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006557 *
6558 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006559 */
6560
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006561int
Owen Taylor3473f882001-02-23 17:55:21 +00006562xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006563 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006564
6565 if ((node->type != XML_TEXT_NODE) &&
6566 (node->type != XML_CDATA_SECTION_NODE)) {
6567#ifdef DEBUG_TREE
6568 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006569 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006570#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006571 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006572 }
William M. Brack7762bb12004-01-04 14:49:01 +00006573 /* need to check if content is currently in the dictionary */
Daniel Veillard8874b942005-08-25 13:19:21 +00006574 if ((node->content == (xmlChar *) &(node->properties)) ||
6575 ((node->doc != NULL) && (node->doc->dict != NULL) &&
6576 xmlDictOwns(node->doc->dict, node->content))) {
William M. Brack7762bb12004-01-04 14:49:01 +00006577 node->content = xmlStrncatNew(node->content, content, len);
6578 } else {
6579 node->content = xmlStrncat(node->content, content, len);
6580 }
Daniel Veillard8874b942005-08-25 13:19:21 +00006581 node->properties = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006582 if (node->content == NULL)
6583 return(-1);
6584 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006585}
6586
6587/************************************************************************
6588 * *
6589 * Output : to a FILE or in memory *
6590 * *
6591 ************************************************************************/
6592
Owen Taylor3473f882001-02-23 17:55:21 +00006593/**
6594 * xmlBufferCreate:
6595 *
6596 * routine to create an XML buffer.
6597 * returns the new structure.
6598 */
6599xmlBufferPtr
6600xmlBufferCreate(void) {
6601 xmlBufferPtr ret;
6602
6603 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6604 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006605 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006606 return(NULL);
6607 }
6608 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006609 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006610 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006611 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006612 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006613 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006614 xmlFree(ret);
6615 return(NULL);
6616 }
6617 ret->content[0] = 0;
6618 return(ret);
6619}
6620
6621/**
6622 * xmlBufferCreateSize:
6623 * @size: initial size of buffer
6624 *
6625 * routine to create an XML buffer.
6626 * returns the new structure.
6627 */
6628xmlBufferPtr
6629xmlBufferCreateSize(size_t size) {
6630 xmlBufferPtr ret;
6631
6632 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6633 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006634 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006635 return(NULL);
6636 }
6637 ret->use = 0;
6638 ret->alloc = xmlBufferAllocScheme;
6639 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6640 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006641 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006642 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006643 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006644 xmlFree(ret);
6645 return(NULL);
6646 }
6647 ret->content[0] = 0;
6648 } else
6649 ret->content = NULL;
6650 return(ret);
6651}
6652
6653/**
Daniel Veillard53350552003-09-18 13:35:51 +00006654 * xmlBufferCreateStatic:
6655 * @mem: the memory area
6656 * @size: the size in byte
6657 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006658 * routine to create an XML buffer from an immutable memory area.
6659 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006660 * present until the end of the buffer lifetime.
6661 *
6662 * returns the new structure.
6663 */
6664xmlBufferPtr
6665xmlBufferCreateStatic(void *mem, size_t size) {
6666 xmlBufferPtr ret;
6667
6668 if ((mem == NULL) || (size == 0))
6669 return(NULL);
6670
6671 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6672 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006673 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006674 return(NULL);
6675 }
6676 ret->use = size;
6677 ret->size = size;
6678 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6679 ret->content = (xmlChar *) mem;
6680 return(ret);
6681}
6682
6683/**
Owen Taylor3473f882001-02-23 17:55:21 +00006684 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006685 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006686 * @scheme: allocation scheme to use
6687 *
6688 * Sets the allocation scheme for this buffer
6689 */
6690void
6691xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6692 xmlBufferAllocationScheme scheme) {
6693 if (buf == NULL) {
6694#ifdef DEBUG_BUFFER
6695 xmlGenericError(xmlGenericErrorContext,
6696 "xmlBufferSetAllocationScheme: buf == NULL\n");
6697#endif
6698 return;
6699 }
Daniel Veillard53350552003-09-18 13:35:51 +00006700 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006701
6702 buf->alloc = scheme;
6703}
6704
6705/**
6706 * xmlBufferFree:
6707 * @buf: the buffer to free
6708 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006709 * Frees an XML buffer. It frees both the content and the structure which
6710 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006711 */
6712void
6713xmlBufferFree(xmlBufferPtr buf) {
6714 if (buf == NULL) {
6715#ifdef DEBUG_BUFFER
6716 xmlGenericError(xmlGenericErrorContext,
6717 "xmlBufferFree: buf == NULL\n");
6718#endif
6719 return;
6720 }
Daniel Veillard53350552003-09-18 13:35:51 +00006721
6722 if ((buf->content != NULL) &&
6723 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006724 xmlFree(buf->content);
6725 }
Owen Taylor3473f882001-02-23 17:55:21 +00006726 xmlFree(buf);
6727}
6728
6729/**
6730 * xmlBufferEmpty:
6731 * @buf: the buffer
6732 *
6733 * empty a buffer.
6734 */
6735void
6736xmlBufferEmpty(xmlBufferPtr buf) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006737 if (buf == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006738 if (buf->content == NULL) return;
6739 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006740 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006741 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006742 } else {
6743 memset(buf->content, 0, buf->size);
6744 }
Owen Taylor3473f882001-02-23 17:55:21 +00006745}
6746
6747/**
6748 * xmlBufferShrink:
6749 * @buf: the buffer to dump
6750 * @len: the number of xmlChar to remove
6751 *
6752 * Remove the beginning of an XML buffer.
6753 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006754 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006755 */
6756int
6757xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
Daniel Veillard3d97e662004-11-04 10:49:00 +00006758 if (buf == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006759 if (len == 0) return(0);
6760 if (len > buf->use) return(-1);
6761
6762 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006763 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6764 buf->content += len;
6765 } else {
6766 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6767 buf->content[buf->use] = 0;
6768 }
Owen Taylor3473f882001-02-23 17:55:21 +00006769 return(len);
6770}
6771
6772/**
6773 * xmlBufferGrow:
6774 * @buf: the buffer
6775 * @len: the minimum free size to allocate
6776 *
6777 * Grow the available space of an XML buffer.
6778 *
6779 * Returns the new available space or -1 in case of error
6780 */
6781int
6782xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6783 int size;
6784 xmlChar *newbuf;
6785
Daniel Veillard3d97e662004-11-04 10:49:00 +00006786 if (buf == NULL) return(-1);
6787
Daniel Veillard53350552003-09-18 13:35:51 +00006788 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006789 if (len + buf->use < buf->size) return(0);
6790
William M. Brack30fe43f2004-07-26 18:00:58 +00006791/*
6792 * Windows has a BIG problem on realloc timing, so we try to double
6793 * the buffer size (if that's enough) (bug 146697)
6794 */
6795#ifdef WIN32
6796 if (buf->size > len)
6797 size = buf->size * 2;
6798 else
6799 size = buf->use + len + 100;
6800#else
Owen Taylor3473f882001-02-23 17:55:21 +00006801 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00006802#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006803
6804 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006805 if (newbuf == NULL) {
6806 xmlTreeErrMemory("growing buffer");
6807 return(-1);
6808 }
Owen Taylor3473f882001-02-23 17:55:21 +00006809 buf->content = newbuf;
6810 buf->size = size;
6811 return(buf->size - buf->use);
6812}
6813
6814/**
6815 * xmlBufferDump:
6816 * @file: the file output
6817 * @buf: the buffer to dump
6818 *
6819 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006820 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006821 */
6822int
6823xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6824 int ret;
6825
6826 if (buf == NULL) {
6827#ifdef DEBUG_BUFFER
6828 xmlGenericError(xmlGenericErrorContext,
6829 "xmlBufferDump: buf == NULL\n");
6830#endif
6831 return(0);
6832 }
6833 if (buf->content == NULL) {
6834#ifdef DEBUG_BUFFER
6835 xmlGenericError(xmlGenericErrorContext,
6836 "xmlBufferDump: buf->content == NULL\n");
6837#endif
6838 return(0);
6839 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006840 if (file == NULL)
6841 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006842 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6843 return(ret);
6844}
6845
6846/**
6847 * xmlBufferContent:
6848 * @buf: the buffer
6849 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006850 * Function to extract the content of a buffer
6851 *
Owen Taylor3473f882001-02-23 17:55:21 +00006852 * Returns the internal content
6853 */
6854
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006855const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006856xmlBufferContent(const xmlBufferPtr buf)
6857{
6858 if(!buf)
6859 return NULL;
6860
6861 return buf->content;
6862}
6863
6864/**
6865 * xmlBufferLength:
6866 * @buf: the buffer
6867 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006868 * Function to get the length of a buffer
6869 *
Owen Taylor3473f882001-02-23 17:55:21 +00006870 * Returns the length of data in the internal content
6871 */
6872
6873int
6874xmlBufferLength(const xmlBufferPtr buf)
6875{
6876 if(!buf)
6877 return 0;
6878
6879 return buf->use;
6880}
6881
6882/**
6883 * xmlBufferResize:
6884 * @buf: the buffer to resize
6885 * @size: the desired size
6886 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006887 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006888 *
6889 * Returns 0 in case of problems, 1 otherwise
6890 */
6891int
6892xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6893{
6894 unsigned int newSize;
6895 xmlChar* rebuf = NULL;
6896
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006897 if (buf == NULL)
6898 return(0);
6899
Daniel Veillard53350552003-09-18 13:35:51 +00006900 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6901
Owen Taylor3473f882001-02-23 17:55:21 +00006902 /* Don't resize if we don't have to */
6903 if (size < buf->size)
6904 return 1;
6905
6906 /* figure out new size */
6907 switch (buf->alloc){
6908 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillardbf629492004-04-20 22:20:59 +00006909 /*take care of empty case*/
6910 newSize = (buf->size ? buf->size*2 : size + 10);
Owen Taylor3473f882001-02-23 17:55:21 +00006911 while (size > newSize) newSize *= 2;
6912 break;
6913 case XML_BUFFER_ALLOC_EXACT:
6914 newSize = size+10;
6915 break;
6916 default:
6917 newSize = size+10;
6918 break;
6919 }
6920
6921 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006922 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006923 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006924 rebuf = (xmlChar *) xmlRealloc(buf->content,
6925 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006926 } else {
6927 /*
6928 * if we are reallocating a buffer far from being full, it's
6929 * better to make a new allocation and copy only the used range
6930 * and free the old one.
6931 */
6932 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6933 if (rebuf != NULL) {
6934 memcpy(rebuf, buf->content, buf->use);
6935 xmlFree(buf->content);
William M. Brack42331a92004-07-29 07:07:16 +00006936 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006937 }
6938 }
Owen Taylor3473f882001-02-23 17:55:21 +00006939 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006940 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006941 return 0;
6942 }
6943 buf->content = rebuf;
6944 buf->size = newSize;
6945
6946 return 1;
6947}
6948
6949/**
6950 * xmlBufferAdd:
6951 * @buf: the buffer to dump
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 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006955 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006956 * 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 +00006962xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6963 unsigned int needSize;
6964
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006965 if ((str == NULL) || (buf == NULL)) {
William M. Bracka3215c72004-07-31 16:24:01 +00006966 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006967 }
William M. Bracka3215c72004-07-31 16:24:01 +00006968 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006969 if (len < -1) {
6970#ifdef DEBUG_BUFFER
6971 xmlGenericError(xmlGenericErrorContext,
6972 "xmlBufferAdd: len < 0\n");
6973#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006974 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006975 }
William M. Bracka3215c72004-07-31 16:24:01 +00006976 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006977
6978 if (len < 0)
6979 len = xmlStrlen(str);
6980
William M. Bracka3215c72004-07-31 16:24:01 +00006981 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006982
6983 needSize = buf->use + len + 2;
6984 if (needSize > buf->size){
6985 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006986 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006987 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006988 }
6989 }
6990
6991 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6992 buf->use += len;
6993 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006994 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006995}
6996
6997/**
6998 * xmlBufferAddHead:
6999 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00007000 * @str: the #xmlChar string
7001 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00007002 *
7003 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00007004 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00007005 *
7006 * Returns 0 successful, a positive error code number otherwise
7007 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007008 */
William M. Bracka3215c72004-07-31 16:24:01 +00007009int
Owen Taylor3473f882001-02-23 17:55:21 +00007010xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
7011 unsigned int needSize;
7012
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007013 if (buf == NULL)
7014 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007015 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007016 if (str == NULL) {
7017#ifdef DEBUG_BUFFER
7018 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007019 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007020#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007021 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007022 }
7023 if (len < -1) {
7024#ifdef DEBUG_BUFFER
7025 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007026 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007027#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007028 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007029 }
William M. Bracka3215c72004-07-31 16:24:01 +00007030 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007031
7032 if (len < 0)
7033 len = xmlStrlen(str);
7034
William M. Bracka3215c72004-07-31 16:24:01 +00007035 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007036
7037 needSize = buf->use + len + 2;
7038 if (needSize > buf->size){
7039 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007040 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007041 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007042 }
7043 }
7044
7045 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
7046 memmove(&buf->content[0], str, len * sizeof(xmlChar));
7047 buf->use += len;
7048 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007049 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007050}
7051
7052/**
7053 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00007054 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00007055 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00007056 *
7057 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007058 *
7059 * Returns 0 successful, a positive error code number otherwise
7060 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007061 */
William M. Bracka3215c72004-07-31 16:24:01 +00007062int
Owen Taylor3473f882001-02-23 17:55:21 +00007063xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007064 if (buf == NULL)
7065 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007066 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
7067 if (str == NULL) return -1;
7068 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00007069}
7070
7071/**
7072 * xmlBufferCCat:
7073 * @buf: the buffer to dump
7074 * @str: the C char string
7075 *
7076 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007077 *
7078 * Returns 0 successful, a positive error code number otherwise
7079 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007080 */
William M. Bracka3215c72004-07-31 16:24:01 +00007081int
Owen Taylor3473f882001-02-23 17:55:21 +00007082xmlBufferCCat(xmlBufferPtr buf, const char *str) {
7083 const char *cur;
7084
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007085 if (buf == NULL)
7086 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007087 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007088 if (str == NULL) {
7089#ifdef DEBUG_BUFFER
7090 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007091 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007092#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007093 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007094 }
7095 for (cur = str;*cur != 0;cur++) {
7096 if (buf->use + 10 >= buf->size) {
7097 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007098 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007099 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007100 }
7101 }
7102 buf->content[buf->use++] = *cur;
7103 }
7104 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007105 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007106}
7107
7108/**
7109 * xmlBufferWriteCHAR:
7110 * @buf: the XML buffer
7111 * @string: the string to add
7112 *
7113 * routine which manages and grows an output buffer. This one adds
7114 * xmlChars at the end of the buffer.
7115 */
7116void
Daniel Veillard53350552003-09-18 13:35:51 +00007117xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007118 if (buf == NULL)
7119 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007120 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007121 xmlBufferCat(buf, string);
7122}
7123
7124/**
7125 * xmlBufferWriteChar:
7126 * @buf: the XML buffer output
7127 * @string: the string to add
7128 *
7129 * routine which manage and grows an output buffer. This one add
7130 * C chars at the end of the array.
7131 */
7132void
7133xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007134 if (buf == NULL)
7135 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007136 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007137 xmlBufferCCat(buf, string);
7138}
7139
7140
7141/**
7142 * xmlBufferWriteQuotedString:
7143 * @buf: the XML buffer output
7144 * @string: the string to add
7145 *
7146 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00007147 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00007148 * quote or double-quotes internally
7149 */
7150void
7151xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00007152 const xmlChar *cur, *base;
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007153 if (buf == NULL)
7154 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007155 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00007156 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00007157 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00007158#ifdef DEBUG_BUFFER
7159 xmlGenericError(xmlGenericErrorContext,
7160 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7161#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00007162 xmlBufferCCat(buf, "\"");
7163 base = cur = string;
7164 while(*cur != 0){
7165 if(*cur == '"'){
7166 if (base != cur)
7167 xmlBufferAdd(buf, base, cur - base);
7168 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7169 cur++;
7170 base = cur;
7171 }
7172 else {
7173 cur++;
7174 }
7175 }
7176 if (base != cur)
7177 xmlBufferAdd(buf, base, cur - base);
7178 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007179 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007180 else{
7181 xmlBufferCCat(buf, "\'");
7182 xmlBufferCat(buf, string);
7183 xmlBufferCCat(buf, "\'");
7184 }
Owen Taylor3473f882001-02-23 17:55:21 +00007185 } else {
7186 xmlBufferCCat(buf, "\"");
7187 xmlBufferCat(buf, string);
7188 xmlBufferCCat(buf, "\"");
7189 }
7190}
7191
7192
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007193/**
7194 * xmlGetDocCompressMode:
7195 * @doc: the document
7196 *
7197 * get the compression ratio for a document, ZLIB based
7198 * Returns 0 (uncompressed) to 9 (max compression)
7199 */
7200int
7201xmlGetDocCompressMode (xmlDocPtr doc) {
7202 if (doc == NULL) return(-1);
7203 return(doc->compression);
7204}
7205
7206/**
7207 * xmlSetDocCompressMode:
7208 * @doc: the document
7209 * @mode: the compression ratio
7210 *
7211 * set the compression ratio for a document, ZLIB based
7212 * Correct values: 0 (uncompressed) to 9 (max compression)
7213 */
7214void
7215xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7216 if (doc == NULL) return;
7217 if (mode < 0) doc->compression = 0;
7218 else if (mode > 9) doc->compression = 9;
7219 else doc->compression = mode;
7220}
7221
7222/**
7223 * xmlGetCompressMode:
7224 *
7225 * get the default compression mode used, ZLIB based.
7226 * Returns 0 (uncompressed) to 9 (max compression)
7227 */
7228int
7229xmlGetCompressMode(void)
7230{
7231 return (xmlCompressMode);
7232}
7233
7234/**
7235 * xmlSetCompressMode:
7236 * @mode: the compression ratio
7237 *
7238 * set the default compression mode used, ZLIB based
7239 * Correct values: 0 (uncompressed) to 9 (max compression)
7240 */
7241void
7242xmlSetCompressMode(int mode) {
7243 if (mode < 0) xmlCompressMode = 0;
7244 else if (mode > 9) xmlCompressMode = 9;
7245 else xmlCompressMode = mode;
7246}
7247
Kasimier T. Buchcik4d9c9482005-06-27 15:04:46 +00007248/*
7249* xmlDOMWrapNewCtxt:
7250*
7251* Allocates and initializes a new DOM-wrapper context.
7252*
7253* Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal errror.
7254*/
7255xmlDOMWrapCtxtPtr
7256xmlDOMWrapNewCtxt(void)
7257{
7258 xmlDOMWrapCtxtPtr ret;
7259
7260 ret = xmlMalloc(sizeof(xmlDOMWrapCtxt));
7261 if (ret == NULL) {
7262 xmlTreeErrMemory("allocating DOM-wrapper context");
7263 return (NULL);
7264 }
7265 memset(ret, 0, sizeof(xmlDOMWrapCtxt));
7266 return (ret);
7267}
7268
7269/*
7270* xmlDOMWrapFreeCtxt:
7271* @ctxt: the DOM-wrapper context
7272*
7273* Frees the DOM-wrapper context.
7274*/
7275void
7276xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt)
7277{
7278 if (ctxt == NULL)
7279 return;
7280 xmlFree(ctxt);
7281}
7282
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007283#define XML_TREE_NSMAP_PARENT -1
7284#define XML_TREE_NSMAP_XML -2
7285#define XML_TREE_NSMAP_DOC -3
7286#define XML_TREE_NSMAP_CUSTOM -4
7287
7288typedef struct xmlNsMapItem *xmlNsMapItemPtr;
7289struct xmlNsMapItem {
7290 xmlNsMapItemPtr next;
7291 xmlNsMapItemPtr prev;
7292 xmlNsPtr oldNs; /* old ns decl reference */
7293 xmlNsPtr newNs; /* new ns decl reference */
7294 int shadowDepth; /* Shadowed at this depth */
7295 /*
7296 * depth:
7297 * >= 0 == @node's ns-decls
7298 * -1 == @parent's ns-decls
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00007299 * -2 == the doc->oldNs XML ns-decl
7300 * -3 == the doc->oldNs storage ns-decls
7301 * -4 == ns-decls provided via custom ns-handling
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007302 */
7303 int depth;
7304};
7305
7306/*
7307* xmlTreeAddNsMapItem:
7308* @map: the ns-map
7309* @cur: the current map entry to append a new entry to
7310* @oldNs: the old ns-struct
7311* @newNs: the new ns-struct
7312* @depth: depth and ns-kind information
7313*
7314* Frees the ns-map
7315*/
7316static xmlNsMapItemPtr
7317xmlDOMWrapNSNormAddNsMapItem(xmlNsMapItemPtr *map,
7318 xmlNsMapItemPtr *cur,
7319 xmlNsPtr oldNs,
7320 xmlNsPtr newNs,
7321 int depth)
7322{
7323 xmlNsMapItemPtr ret;
7324
7325 if ((cur != NULL) && (*cur != NULL) && ((*cur)->next != NULL)) {
7326 /*
7327 * Reuse.
7328 */
7329 ret = (*cur)->next;
7330 *cur = ret;
7331 } else {
7332 ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem));
7333 if (ret == NULL) {
7334 xmlTreeErrMemory("allocating namespace map item");
7335 return (NULL);
7336 }
7337 memset(ret, 0, sizeof(struct xmlNsMapItem));
7338 if (*map == NULL) {
7339 /*
7340 * First ever.
7341 */
7342 *map = ret;
7343 ret->prev = ret;
7344 if (cur != NULL)
7345 *cur = ret;
7346 } else {
7347 if (cur) {
7348 /*
7349 * Append.
7350 */
7351 (*cur)->next = ret;
7352 ret->prev = *cur;
7353 *cur = ret;
7354 } else {
7355 /*
7356 * Set on first position.
7357 */
7358 ret->next = (*map);
7359 ret->prev = (*map)->prev;
7360 (*map)->prev = ret;
7361 *map = ret;
7362 }
7363 }
7364 }
7365 ret->oldNs = oldNs;
7366 ret->newNs = newNs;
7367 ret->shadowDepth = -1;
7368 ret->depth = depth;
7369 return (ret);
7370}
7371
7372/*
7373* xmlTreeFreeNsMap:
7374* @map: the ns-map
7375*
7376* Frees the ns-map
7377*/
7378static void
7379xmlDOMWrapNSNormFreeNsMap(xmlNsMapItemPtr map)
7380{
7381 xmlNsMapItemPtr mi = map, miprev;
7382
7383 while (mi != NULL) {
7384 miprev = mi;
7385 mi = mi->next;
7386 xmlFree(miprev);
7387 }
7388}
7389
7390/*
7391* xmlTreeEnsureXMLDecl:
7392* @doc: the doc
7393*
7394* Ensures that there is an XML namespace declaration on the doc.
7395*
7396* Returns the XML ns-struct or NULL on API and internal errors.
7397*/
7398static xmlNsPtr
7399xmlTreeEnsureXMLDecl(xmlDocPtr doc)
7400{
7401 if (doc == NULL)
7402 return (NULL);
7403 if (doc->oldNs != NULL)
7404 return (doc->oldNs);
7405 {
7406 xmlNsPtr ns;
7407 ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
7408 if (ns == NULL) {
7409 xmlTreeErrMemory(
7410 "allocating the XML namespace");
7411 return (NULL);
7412 }
7413 memset(ns, 0, sizeof(xmlNs));
7414 ns->type = XML_LOCAL_NAMESPACE;
7415 ns->href = xmlStrdup(XML_XML_NAMESPACE);
7416 ns->prefix = xmlStrdup((const xmlChar *)"xml");
7417 doc->oldNs = ns;
7418 return (ns);
7419 }
7420}
7421
7422/*
7423* xmlDOMWrapStoreNs:
7424* @doc: the doc
7425* @nsName: the namespace name
7426* @prefix: the prefix
7427*
7428* Creates or reuses an xmlNs struct on doc->oldNs with
7429* the given prefix and namespace name.
7430*
7431* Returns the aquired ns struct or NULL in case of an API
7432* or internal error.
7433*/
7434static xmlNsPtr
7435xmlDOMWrapStoreNs(xmlDocPtr doc,
7436 const xmlChar *nsName,
7437 const xmlChar *prefix)
7438{
7439 xmlNsPtr ns;
7440
7441 if (doc == NULL)
7442 return (NULL);
7443 ns = xmlTreeEnsureXMLDecl(doc);
7444 if (ns == NULL)
7445 return (NULL);
7446 if (ns->next != NULL) {
7447 /* Reuse. */
7448 ns = ns->next;
7449 while (ns != NULL) {
7450 if (((ns->prefix == prefix) ||
7451 xmlStrEqual(ns->prefix, prefix)) &&
7452 xmlStrEqual(ns->href, nsName)) {
7453 return (ns);
7454 }
7455 if (ns->next == NULL)
7456 break;
7457 ns = ns->next;
7458 }
7459 }
7460 /* Create. */
7461 ns->next = xmlNewNs(NULL, nsName, prefix);
7462 return (ns->next);
7463}
7464
7465/*
7466* xmlTreeLookupNsListByPrefix:
7467* @nsList: a list of ns-structs
7468* @prefix: the searched prefix
7469*
7470* Searches for a ns-decl with the given prefix in @nsList.
7471*
7472* Returns the ns-decl if found, NULL if not found and on
7473* API errors.
7474*/
7475static xmlNsPtr
7476xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix)
7477{
7478 if (nsList == NULL)
7479 return (NULL);
7480 {
7481 xmlNsPtr ns;
7482 ns = nsList;
7483 do {
7484 if ((prefix == ns->prefix) ||
7485 xmlStrEqual(prefix, ns->prefix)) {
7486 return (ns);
7487 }
7488 ns = ns->next;
7489 } while (ns != NULL);
7490 }
7491 return (NULL);
7492}
7493
7494/*
7495*
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00007496* xmlDOMWrapNSNormGatherInScopeNs:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007497* @map: the namespace map
7498* @node: the node to start with
7499*
7500* Puts in-scope namespaces into the ns-map.
7501*
7502* Returns 0 on success, -1 on API or internal errors.
7503*/
7504static int
7505xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapItemPtr *map,
7506 xmlNodePtr node)
7507{
7508 xmlNodePtr cur;
7509 xmlNsPtr ns;
7510 xmlNsMapItemPtr mi;
7511 int shadowed;
7512
7513 if ((map == NULL) || (*map != NULL))
7514 return (-1);
7515 /*
7516 * Get in-scope ns-decls of @parent.
7517 */
7518 cur = node;
7519 while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) {
7520 if (cur->type == XML_ELEMENT_NODE) {
7521 if (cur->nsDef != NULL) {
7522 ns = cur->nsDef;
7523 do {
7524 shadowed = 0;
7525 if (*map != NULL) {
7526 /*
7527 * Skip shadowed prefixes.
7528 */
7529 for (mi = *map; mi != NULL; mi = mi->next) {
7530 if ((ns->prefix == mi->newNs->prefix) ||
7531 xmlStrEqual(ns->prefix, mi->newNs->prefix)) {
7532 shadowed = 1;
7533 break;
7534 }
7535 }
7536 }
7537 /*
7538 * Insert mapping.
7539 */
7540 mi = xmlDOMWrapNSNormAddNsMapItem(map, NULL, NULL,
7541 ns, XML_TREE_NSMAP_PARENT);
7542 if (mi == NULL)
7543 return (-1);
7544 if (shadowed)
7545 mi->shadowDepth = 0;
7546 ns = ns->next;
7547 } while (ns != NULL);
7548 }
7549 }
7550 cur = cur->parent;
7551 }
7552 return (0);
7553}
7554
7555/*
7556* XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict;
7557* otherwise copy it, when it was in the source-dict.
7558*/
7559#define XML_TREE_ADOPT_STR(str) \
7560 if (adoptStr && (str != NULL)) { \
7561 if (destDoc->dict) { \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00007562 const xmlChar *old = str; \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007563 str = xmlDictLookup(destDoc->dict, str, -1); \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00007564 if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \
7565 (!xmlDictOwns(sourceDoc->dict, old))) \
Daniel Veillard39e5c892005-07-03 22:48:50 +00007566 xmlFree((char *)old); \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007567 } else if ((sourceDoc) && (sourceDoc->dict) && \
7568 xmlDictOwns(sourceDoc->dict, str)) { \
7569 str = BAD_CAST xmlStrdup(str); \
7570 } \
7571 }
7572
7573/*
7574* XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then
7575* put it in dest-dict or copy it.
7576*/
7577#define XML_TREE_ADOPT_STR_2(str) \
7578 if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \
7579 (sourceDoc->dict != NULL) && \
7580 xmlDictOwns(sourceDoc->dict, cur->content)) { \
7581 if (destDoc->dict) \
7582 cur->content = (xmlChar *) \
7583 xmlDictLookup(destDoc->dict, cur->content, -1); \
7584 else \
7585 cur->content = xmlStrdup(BAD_CAST cur->content); \
7586 }
7587
7588/*
7589* xmlDOMWrapNSNormAddNsMapItem2:
7590*
7591* For internal use. Adds a ns-decl mapping.
7592*
7593* Returns 0 on success, -1 on internal errors.
7594*/
7595static int
7596xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number,
7597 xmlNsPtr oldNs, xmlNsPtr newNs)
7598{
7599 if (*list == NULL) {
7600 *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr));
7601 if (*list == NULL) {
7602 xmlTreeErrMemory("alloc ns map item");
7603 return(-1);
7604 }
7605 *size = 3;
7606 *number = 0;
7607 } else if ((*number) >= (*size)) {
7608 *size *= 2;
7609 *list = (xmlNsPtr *) xmlRealloc(*list,
7610 (*size) * 2 * sizeof(xmlNsPtr));
7611 if (*list == NULL) {
7612 xmlTreeErrMemory("realloc ns map item");
7613 return(-1);
7614 }
7615 }
7616 (*list)[2 * (*number)] = oldNs;
7617 (*list)[2 * (*number) +1] = newNs;
7618 (*number)++;
7619 return (0);
7620}
7621
7622/*
7623* xmlDOMWrapRemoveNode:
Daniel Veillard304e78c2005-07-03 16:19:41 +00007624* @ctxt: a DOM wrapper context
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007625* @doc: the doc
7626* @node: the node to be removed.
Daniel Veillard304e78c2005-07-03 16:19:41 +00007627* @options: set of options, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007628*
7629* Unlinks the given node from its owner.
7630* This will substitute ns-references to node->nsDef for
7631* ns-references to doc->oldNs, thus ensuring the removed
7632* branch to be autark wrt ns-references.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00007633* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007634*
7635* Returns 0 on success, 1 if the node is not supported,
7636* -1 on API and internal errors.
7637*/
7638int
7639xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc,
7640 xmlNodePtr node, int options ATTRIBUTE_UNUSED)
7641{
7642 xmlNsPtr *list = NULL;
7643 int sizeList, nbList, i, j;
7644 xmlNsPtr ns;
7645
7646 if ((node == NULL) || (doc == NULL) || (node->doc != doc))
7647 return (-1);
7648
7649 /* TODO: 0 or -1 ? */
7650 if (node->parent == NULL)
7651 return (0);
7652
7653 switch (node->type) {
7654 case XML_TEXT_NODE:
7655 case XML_CDATA_SECTION_NODE:
7656 case XML_ENTITY_REF_NODE:
7657 case XML_PI_NODE:
7658 case XML_COMMENT_NODE:
7659 xmlUnlinkNode(node);
7660 return (0);
7661 case XML_ELEMENT_NODE:
7662 case XML_ATTRIBUTE_NODE:
7663 break;
7664 default:
7665 return (1);
7666 }
7667 xmlUnlinkNode(node);
7668 /*
7669 * Save out-of-scope ns-references in doc->oldNs.
7670 */
7671 do {
7672 switch (node->type) {
7673 case XML_ELEMENT_NODE:
7674 if ((ctxt == NULL) && (node->nsDef != NULL)) {
7675 ns = node->nsDef;
7676 do {
7677 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
7678 &nbList, ns, ns) == -1)
7679 goto internal_error;
7680 ns = ns->next;
7681 } while (ns != NULL);
7682 }
7683 /* No break on purpose. */
7684 case XML_ATTRIBUTE_NODE:
7685 if (node->ns != NULL) {
7686 /*
7687 * Find a mapping.
7688 */
7689 if (list != NULL) {
7690 for (i = 0, j = 0; i < nbList; i++, j += 2) {
7691 if (node->ns == list[j]) {
7692 node->ns = list[++j];
7693 goto next_node;
7694 }
7695 }
7696 }
7697 ns = NULL;
7698 if (ctxt != NULL) {
7699 /*
7700 * User defined.
7701 */
7702 } else {
7703 /*
7704 * Add to doc's oldNs.
7705 */
7706 ns = xmlDOMWrapStoreNs(doc, node->ns->href,
7707 node->ns->prefix);
7708 if (ns == NULL)
7709 goto internal_error;
7710 }
7711 if (ns != NULL) {
7712 /*
7713 * Add mapping.
7714 */
7715 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
7716 &nbList, node->ns, ns) == -1)
7717 goto internal_error;
7718 }
7719 node->ns = ns;
7720 }
7721 if ((node->type == XML_ELEMENT_NODE) &&
7722 (node->properties != NULL)) {
7723 node = (xmlNodePtr) node->properties;
7724 continue;
7725 }
7726 break;
7727 default:
7728 goto next_sibling;
7729 }
7730next_node:
7731 if ((node->type == XML_ELEMENT_NODE) &&
7732 (node->children != NULL)) {
7733 node = node->children;
7734 continue;
7735 }
7736next_sibling:
7737 if (node == NULL)
7738 break;
7739 if (node->next != NULL)
7740 node = node->next;
7741 else {
7742 node = node->parent;
7743 goto next_sibling;
7744 }
7745 } while (node != NULL);
7746
7747 if (list != NULL)
7748 xmlFree(list);
7749 return (0);
7750
7751internal_error:
7752 if (list != NULL)
7753 xmlFree(list);
7754 return (-1);
7755}
7756
7757/*
7758* xmlSearchNsByHrefStrict:
7759* @doc: the document
7760* @node: the start node
7761* @nsName: the searched namespace name
7762* @retNs: the resulting ns-decl
7763* @prefixed: if the found ns-decl must have a prefix (for attributes)
7764*
7765* Dynamically searches for a ns-declaration which matches
7766* the given @nsName in the ancestor-or-self axis of @node.
7767*
7768* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7769* and internal errors.
7770*/
7771static int
7772xmlSearchNsByHrefStrict(xmlDocPtr doc, xmlNodePtr node, const xmlChar* nsName,
7773 xmlNsPtr *retNs, int prefixed)
7774{
7775 xmlNodePtr cur, prev = NULL, out = NULL;
7776 xmlNsPtr ns, prevns;
7777
7778 if ((doc == NULL) || (nsName == NULL) || (retNs == NULL))
7779 return (-1);
7780
7781 *retNs = NULL;
7782 if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
7783 *retNs = xmlTreeEnsureXMLDecl(doc);
7784 if (*retNs == NULL)
7785 return (-1);
7786 return (1);
7787 }
7788 cur = node;
7789 do {
7790 if (cur->type == XML_ELEMENT_NODE) {
7791 if (cur->nsDef != NULL) {
7792 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
7793 if (prefixed && (ns->prefix == NULL))
7794 continue;
7795 if (prev != NULL) {
7796 /*
7797 * Check the last level of ns-decls for a
7798 * shadowing prefix.
7799 */
7800 prevns = prev->nsDef;
7801 do {
7802 if ((prevns->prefix == ns->prefix) ||
7803 ((prevns->prefix != NULL) &&
7804 (ns->prefix != NULL) &&
7805 xmlStrEqual(prevns->prefix, ns->prefix))) {
7806 /*
7807 * Shadowed.
7808 */
7809 break;
7810 }
7811 prevns = prevns->next;
7812 } while (prevns != NULL);
7813 if (prevns != NULL)
7814 continue;
7815 }
7816 /*
7817 * Ns-name comparison.
7818 */
7819 if ((nsName == ns->href) ||
7820 xmlStrEqual(nsName, ns->href)) {
7821 /*
7822 * At this point the prefix can only be shadowed,
7823 * if we are the the (at least) 3rd level of
7824 * ns-decls.
7825 */
7826 if (out) {
7827 int ret;
7828
7829 ret = xmlNsInScope(doc, node, prev, ns->prefix);
7830 if (ret < 0)
7831 return (-1);
7832 /*
7833 * TODO: Should we try to find a matching ns-name
7834 * only once? This here keeps on searching.
7835 * I think we should try further since, there might
7836 * be an other matching ns-decl with an unshadowed
7837 * prefix.
7838 */
7839 if (! ret)
7840 continue;
7841 }
7842 *retNs = ns;
7843 return (1);
7844 }
7845 }
7846 out = prev;
7847 prev = cur;
7848 }
7849 } else if ((node->type == XML_ENTITY_REF_NODE) ||
7850 (node->type == XML_ENTITY_NODE) ||
7851 (node->type == XML_ENTITY_DECL))
7852 return (0);
7853 cur = cur->parent;
7854 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
7855 return (0);
7856}
7857
7858/*
7859* xmlDOMWrapNSNormDeclareNsForced:
7860* @doc: the doc
7861* @elem: the element-node to declare on
7862* @nsName: the namespace-name of the ns-decl
7863* @prefix: the preferred prefix of the ns-decl
7864* @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls
7865*
7866* Declares a new namespace on @elem. It tries to use the
7867* given @prefix; if a ns-decl with the given prefix is already existent
7868* on @elem, it will generate an other prefix.
7869*
7870* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7871* and internal errors.
7872*/
7873static xmlNsPtr
7874xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc,
7875 xmlNodePtr elem,
7876 const xmlChar *nsName,
7877 const xmlChar *prefix,
7878 int checkShadow)
7879{
7880
7881 xmlNsPtr ret;
7882 char buf[50];
7883 const xmlChar *pref;
7884 int counter = 0;
7885 /*
7886 * Create a ns-decl on @anchor.
7887 */
7888 pref = prefix;
7889 while (1) {
7890 /*
7891 * Lookup whether the prefix is unused in elem's ns-decls.
7892 */
7893 if ((elem->nsDef != NULL) &&
7894 (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL))
7895 goto ns_next_prefix;
7896 if (checkShadow && elem->parent &&
7897 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
7898 /*
7899 * Does it shadow ancestor ns-decls?
7900 */
7901 if (xmlSearchNs(doc, elem->parent, pref) != NULL)
7902 goto ns_next_prefix;
7903 }
7904 ret = xmlNewNs(NULL, nsName, pref);
7905 if (ret == NULL)
7906 return (NULL);
7907 if (elem->nsDef == NULL)
7908 elem->nsDef = ret;
7909 else {
7910 xmlNsPtr ns2 = elem->nsDef;
7911 while (ns2->next != NULL)
7912 ns2 = ns2->next;
7913 ns2->next = ret;
7914 }
7915 return (ret);
7916ns_next_prefix:
7917 counter++;
7918 if (counter > 1000)
7919 return (NULL);
7920 if (prefix == NULL) {
7921 snprintf((char *) buf, sizeof(buf),
7922 "default%d", counter);
7923 } else
7924 snprintf((char *) buf, sizeof(buf),
7925 "%.30s%d", (char *)prefix, counter);
7926 pref = BAD_CAST buf;
7927 }
7928}
7929
7930/*
7931* xmlDOMWrapNSNormAquireNormalizedNs:
7932* @doc: the doc
7933* @elem: the element-node to declare namespaces on
7934* @ns: the ns-struct to use for the search
7935* @retNs: the found/created ns-struct
7936* @nsMap: the ns-map
7937* @topmi: the last ns-map entry
7938* @depth: the current tree depth
7939* @ancestorsOnly: search in ancestor ns-decls only
7940* @prefixed: if the searched ns-decl must have a prefix (for attributes)
7941*
7942* Searches for a matching ns-name in the ns-decls of @nsMap, if not
7943* found it will either declare it on @elem, or store it in doc->oldNs.
7944* If a new ns-decl needs to be declared on @elem, it tries to use the
7945* @ns->prefix for it, if this prefix is already in use on @elem, it will
7946* change the prefix or the new ns-decl.
7947*
7948* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
7949*/
7950static int
7951xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc,
7952 xmlNodePtr elem,
7953 xmlNsPtr ns,
7954 xmlNsPtr *retNs,
7955 xmlNsMapItemPtr *nsMap,
7956 xmlNsMapItemPtr *topmi,
7957 int depth,
7958 int ancestorsOnly,
7959 int prefixed)
7960{
7961 xmlNsMapItemPtr mi;
7962
7963 if ((doc == NULL) || (ns == NULL) || (retNs == NULL) ||
7964 (nsMap == NULL) || (topmi == NULL))
7965 return (-1);
7966
7967 *retNs = NULL;
7968 /*
7969 * Handle XML namespace.
7970 */
7971 if ((ns->prefix) &&
7972 (ns->prefix[0] == 'x') &&
7973 (ns->prefix[1] == 'm') &&
7974 (ns->prefix[2] == 'l') &&
7975 (ns->prefix[3] == 0)) {
7976 /*
7977 * Insert XML namespace mapping.
7978 */
7979 *retNs = xmlTreeEnsureXMLDecl(doc);
7980 if (*retNs == NULL)
7981 return (-1);
7982 return (0);
7983 }
7984 /*
7985 * If the search should be done in ancestors only and no
7986 * @elem (the first ancestor) was specified, then skip the search.
7987 */
7988 if ((! (ancestorsOnly && (elem == NULL))) &&
7989 (*nsMap != NULL)) {
7990
7991 /*
7992 * Try to find an equal ns-name in in-scope ns-decls.
7993 */
7994 for (mi = *nsMap; mi != (*topmi)->next; mi = mi->next) {
7995
7996 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
7997 /*
7998 * This should be turned on to gain speed, if one knows
7999 * that the branch itself was already ns-wellformed and no
8000 * stale references existed. I.e. it searches in the ancestor
8001 * axis only.
8002 */
8003 ((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) &&
8004 /* Skip shadowed prefixes. */
8005 (mi->shadowDepth == -1) &&
8006 /* Skip xmlns="" or xmlns:foo="". */
8007 ((mi->newNs->href != NULL) &&
8008 (mi->newNs->href[0] != 0)) &&
8009 /* Ensure a prefix if wanted. */
8010 ((! prefixed) || (mi->newNs->prefix != NULL)) &&
8011 /* Equal ns name */
8012 ((mi->newNs->href == ns->href) ||
8013 xmlStrEqual(mi->newNs->href, ns->href))) {
8014 /* Set the mapping. */
8015 mi->oldNs = ns;
8016 *retNs = mi->newNs;
8017 return (0);
8018 }
8019 }
8020 }
8021 /*
8022 * No luck, the namespace is out of scope or shadowed.
8023 */
8024 if (elem == NULL) {
8025 xmlNsPtr tmpns;
8026
8027 /*
8028 * Store ns-decls in "oldNs" of the document-node.
8029 */
8030 tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix);
8031 if (tmpns == NULL)
8032 return (-1);
8033 /*
8034 * Insert mapping.
8035 */
8036 if (xmlDOMWrapNSNormAddNsMapItem(nsMap, NULL, ns,
8037 tmpns, XML_TREE_NSMAP_DOC) == NULL) {
8038 xmlFreeNs(tmpns);
8039 return (-1);
8040 }
8041 *retNs = tmpns;
8042 } else {
8043 xmlNsPtr tmpns;
8044
8045 tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href,
8046 ns->prefix, 0);
8047 if (tmpns == NULL)
8048 return (-1);
8049
8050 if (*nsMap != NULL) {
8051 /*
8052 * Does it shadow ancestor ns-decls?
8053 */
8054 for (mi = *nsMap; mi != (*topmi)->next; mi = mi->next) {
8055 if ((mi->depth < depth) &&
8056 (mi->shadowDepth == -1) &&
8057 ((ns->prefix == mi->newNs->prefix) ||
8058 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8059 /*
8060 * Shadows.
8061 */
8062 mi->shadowDepth = depth;
8063 break;
8064 }
8065 }
8066 }
8067 if (xmlDOMWrapNSNormAddNsMapItem(nsMap, topmi, ns,
8068 tmpns, depth) == NULL) {
8069 xmlFreeNs(tmpns);
8070 return (-1);
8071 }
8072 *retNs = tmpns;
8073 }
8074 return (0);
8075}
8076
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008077typedef enum {
8078 XML_DOM_RECONNS_REMOVEREDUND = 1<<0
8079} xmlDOMReconcileNSOptions;
8080
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008081/*
8082* xmlDOMWrapReconcileNamespaces:
Daniel Veillard304e78c2005-07-03 16:19:41 +00008083* @ctxt: DOM wrapper context, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008084* @elem: the element-node
8085* @options: option flags
8086*
8087* Ensures that ns-references point to ns-decls hold on element-nodes.
8088* Ensures that the tree is namespace wellformed by creating additional
8089* ns-decls where needed. Note that, since prefixes of already existent
8090* ns-decls can be shadowed by this process, it could break QNames in
8091* attribute values or element content.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00008092* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008093*
8094* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008095*/
8096
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008097int
8098xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,
8099 xmlNodePtr elem,
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008100 int options)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008101{
8102 int depth = -1, adoptns = 0, parnsdone = 0;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008103 xmlNsPtr ns, prevns;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008104 xmlDocPtr doc;
8105 xmlNodePtr cur, curElem = NULL;
8106 xmlNsMapItemPtr nsMap = NULL, topmi = NULL, mi;
8107 /* @ancestorsOnly should be set by an option flag. */
8108 int ancestorsOnly = 0;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008109 int optRemoveDedundantNS =
8110 ((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0;
8111 xmlNsPtr *listRedund = NULL;
8112 int sizeRedund = 0, nbRedund = 0, ret, i, j;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008113
8114 if ((elem == NULL) || (elem->doc == NULL) ||
8115 (elem->type != XML_ELEMENT_NODE))
8116 return (-1);
8117
8118 doc = elem->doc;
8119 cur = elem;
8120 do {
8121 switch (cur->type) {
8122 case XML_ELEMENT_NODE:
8123 adoptns = 1;
8124 curElem = cur;
8125 depth++;
8126 /*
8127 * Namespace declarations.
8128 */
8129 if (cur->nsDef != NULL) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008130 prevns = NULL;
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008131 ns = cur->nsDef;
8132 while (ns != NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008133 if (! parnsdone) {
8134 if ((elem->parent) &&
8135 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8136 /*
8137 * Gather ancestor in-scope ns-decls.
8138 */
8139 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8140 elem->parent) == -1)
8141 goto internal_error;
8142 if (nsMap != NULL)
8143 topmi = nsMap->prev;
8144 }
8145 parnsdone = 1;
8146 }
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008147
8148 /*
8149 * Lookup the ns ancestor-axis for equal ns-decls in scope.
8150 */
8151 if (optRemoveDedundantNS && nsMap) {
8152 for (mi = nsMap; mi != topmi->next; mi = mi->next) {
8153 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8154 (mi->shadowDepth == -1) &&
8155 ((ns->prefix == mi->newNs->prefix) ||
8156 xmlStrEqual(ns->prefix, mi->newNs->prefix)) &&
8157 ((ns->href == mi->newNs->href) ||
8158 xmlStrEqual(ns->href, mi->newNs->href)))
8159 {
8160 /*
8161 * A redundant ns-decl was found.
8162 * Add it to the list of redundant ns-decls.
8163 */
8164 if (xmlDOMWrapNSNormAddNsMapItem2(&listRedund,
8165 &sizeRedund, &nbRedund, ns, mi->newNs) == -1)
8166 goto internal_error;
8167 /*
8168 * Remove the ns-decl from the element-node.
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008169 */
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008170 if (prevns)
8171 prevns->next = ns->next;
8172 else
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008173 cur->nsDef = ns->next;
8174 goto next_ns_decl;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008175 }
8176 }
8177 }
8178
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008179 /*
8180 * Skip ns-references handling if the referenced
8181 * ns-decl is declared on the same element.
8182 */
8183 if ((cur->ns != NULL) && adoptns && (cur->ns == ns))
8184 adoptns = 0;
8185 /*
8186 * Does it shadow any ns-decl?
8187 */
8188 if (nsMap) {
8189 for (mi = nsMap; mi != topmi->next; mi = mi->next) {
8190 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8191 (mi->shadowDepth == -1) &&
8192 ((ns->prefix == mi->newNs->prefix) ||
8193 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8194
8195 mi->shadowDepth = depth;
8196 }
8197 }
8198 }
8199 /*
8200 * Push mapping.
8201 */
8202 if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi, ns, ns,
8203 depth) == NULL)
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008204 goto internal_error;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008205
8206 prevns = ns;
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008207next_ns_decl:
8208 ns = ns->next;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008209 }
8210 }
8211 if (! adoptns)
8212 goto ns_end;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008213 /* No break on purpose. */
8214 case XML_ATTRIBUTE_NODE:
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008215 /* No ns, no fun. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008216 if (cur->ns == NULL)
8217 goto ns_end;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008218
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008219 if (! parnsdone) {
8220 if ((elem->parent) &&
8221 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8222 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8223 elem->parent) == -1)
8224 goto internal_error;
8225 if (nsMap != NULL)
8226 topmi = nsMap->prev;
8227 }
8228 parnsdone = 1;
8229 }
8230 /*
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008231 * Adjust the reference if this was a redundant ns-decl.
8232 */
8233 if (listRedund) {
8234 for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8235 if (cur->ns == listRedund[j]) {
8236 cur->ns = listRedund[++j];
8237 break;
8238 }
8239 }
8240 }
8241 /*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008242 * Adopt ns-references.
8243 */
8244 if (nsMap != NULL) {
8245 /*
8246 * Search for a mapping.
8247 */
8248 for (mi = nsMap; mi != topmi->next; mi = mi->next) {
8249 if ((mi->shadowDepth == -1) &&
8250 (cur->ns == mi->oldNs)) {
8251
8252 cur->ns = mi->newNs;
8253 goto ns_end;
8254 }
8255 }
8256 }
8257 /*
8258 * Aquire a normalized ns-decl and add it to the map.
8259 */
8260 if (xmlDOMWrapNSNormAquireNormalizedNs(doc, curElem,
8261 cur->ns, &ns,
8262 &nsMap, &topmi, depth,
8263 ancestorsOnly,
8264 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8265 goto internal_error;
8266 cur->ns = ns;
8267
8268ns_end:
8269 if ((cur->type == XML_ELEMENT_NODE) &&
8270 (cur->properties != NULL)) {
8271 /*
8272 * Process attributes.
8273 */
8274 cur = (xmlNodePtr) cur->properties;
8275 continue;
8276 }
8277 break;
8278 default:
8279 goto next_sibling;
8280 }
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008281into_content:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008282 if ((cur->type == XML_ELEMENT_NODE) &&
8283 (cur->children != NULL)) {
8284 /*
8285 * Process content of element-nodes only.
8286 */
8287 cur = cur->children;
8288 continue;
8289 }
8290next_sibling:
8291 if (cur == elem)
8292 break;
8293 if (cur->type == XML_ELEMENT_NODE) {
8294 if (nsMap != NULL) {
8295 /*
8296 * Pop mappings.
8297 */
8298 while ((topmi->depth >= 0) && (topmi->depth >= depth))
8299 topmi = topmi->prev;
8300 /*
8301 * Unshadow.
8302 */
8303 for (mi = nsMap; mi != topmi->next; mi = mi->next)
8304 if (mi->shadowDepth >= depth)
8305 mi->shadowDepth = -1;
8306 }
8307 depth--;
8308 }
8309 if (cur->next != NULL)
8310 cur = cur->next;
8311 else {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008312 if (cur->type == XML_ATTRIBUTE_NODE) {
8313 cur = cur->parent;
8314 goto into_content;
8315 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008316 cur = cur->parent;
8317 goto next_sibling;
8318 }
8319 } while (cur != NULL);
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008320
8321 ret = 0;
8322 goto exit;
8323internal_error:
8324 ret = -1;
8325exit:
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008326 if (listRedund) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008327 for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8328 xmlFreeNs(listRedund[j]);
8329 }
8330 xmlFree(listRedund);
8331 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008332 if (nsMap != NULL)
8333 xmlDOMWrapNSNormFreeNsMap(nsMap);
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008334 return (ret);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008335}
8336
8337/*
8338* xmlDOMWrapAdoptBranch:
8339* @ctxt: the optional context for custom processing
8340* @sourceDoc: the optional sourceDoc
8341* @node: the element-node to start with
8342* @destDoc: the destination doc for adoption
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008343* @destParent: the optional new parent of @node in @destDoc
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008344* @options: option flags
8345*
8346* Ensures that ns-references point to @destDoc: either to
8347* elements->nsDef entries if @destParent is given, or to
8348* @destDoc->oldNs otherwise.
8349* If @destParent is given, it ensures that the tree is namespace
8350* wellformed by creating additional ns-decls where needed.
8351* Note that, since prefixes of already existent ns-decls can be
8352* shadowed by this process, it could break QNames in attribute
8353* values or element content.
8354*
8355* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8356*/
8357static int
8358xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
8359 xmlDocPtr sourceDoc,
8360 xmlNodePtr node,
8361 xmlDocPtr destDoc,
8362 xmlNodePtr destParent,
8363 int options ATTRIBUTE_UNUSED)
8364{
8365 int ret = 0;
8366 xmlNodePtr cur, curElem = NULL;
8367 xmlNsMapItemPtr nsMap = NULL, topmi = NULL, mi;
8368 xmlNsPtr ns;
8369 int depth = -1, adoptStr = 1;
8370 /* gather @parent's ns-decls. */
8371 int parnsdone = 0;
8372 /* @ancestorsOnly should be set per option. */
8373 int ancestorsOnly = 0;
8374
8375 /*
8376 * Optimize string adoption for equal or none dicts.
8377 */
8378 if ((sourceDoc != NULL) &&
8379 (sourceDoc->dict == destDoc->dict))
8380 adoptStr = 0;
8381 else
8382 adoptStr = 1;
8383
8384 cur = node;
8385 while (cur != NULL) {
8386 if (cur->doc != sourceDoc) {
8387 /*
8388 * We'll assume XIncluded nodes if the doc differs.
8389 * TODO: Do we need to reconciliate XIncluded nodes?
8390 * This here skips XIncluded nodes and tries to handle
8391 * broken sequences.
8392 */
8393 if (cur->next == NULL)
8394 goto leave_node;
8395 do {
8396 cur = cur->next;
8397 if ((cur->type == XML_XINCLUDE_END) ||
8398 (cur->doc == node->doc))
8399 break;
8400 } while (cur->next != NULL);
8401
8402 if (cur->doc != node->doc)
8403 goto leave_node;
8404 }
8405 cur->doc = destDoc;
8406 switch (cur->type) {
8407 case XML_XINCLUDE_START:
8408 case XML_XINCLUDE_END:
8409 /*
8410 * TODO
8411 */
8412 return (-1);
8413 case XML_ELEMENT_NODE:
8414 curElem = cur;
8415 depth++;
8416 /*
8417 * Namespace declarations.
8418 */
8419 if ((ctxt == NULL) && (cur->nsDef != NULL)) {
8420 if (! parnsdone) {
8421 if (destParent && (ctxt == NULL)) {
8422 /*
8423 * Gather @parent's in-scope ns-decls.
8424 */
8425 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8426 destParent) == -1)
8427 goto internal_error;
8428 if (nsMap != NULL)
8429 topmi = nsMap->prev;
8430 }
8431 parnsdone = 1;
8432 }
8433 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8434 /*
8435 * ns->prefix and ns->href seem not to be in the dict.
8436 * XML_TREE_ADOPT_STR(ns->prefix)
8437 * XML_TREE_ADOPT_STR(ns->href)
8438 */
8439 /*
8440 * Does it shadow any ns-decl?
8441 */
8442 if (nsMap) {
8443 for (mi = nsMap; mi != topmi->next;
8444 mi = mi->next) {
8445 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8446 (mi->shadowDepth == -1) &&
8447 ((ns->prefix == mi->newNs->prefix) ||
8448 xmlStrEqual(ns->prefix,
8449 mi->newNs->prefix))) {
8450
8451 mi->shadowDepth = depth;
8452 }
8453 }
8454 }
8455 /*
8456 * Push mapping.
8457 */
8458 if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi,
8459 ns, ns, depth) == NULL)
8460 goto internal_error;
8461 }
8462 }
8463 /* No break on purpose. */
8464 case XML_ATTRIBUTE_NODE:
8465
8466 if (cur->ns == NULL)
8467 goto ns_end;
8468 if (! parnsdone) {
8469 if (destParent && (ctxt == NULL)) {
8470 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8471 destParent) == -1)
8472 goto internal_error;
8473 if (nsMap != NULL)
8474 topmi = nsMap->prev;
8475 }
8476 parnsdone = 1;
8477 }
8478 /*
8479 * Adopt ns-references.
8480 */
8481 if (nsMap != NULL) {
8482 /*
8483 * Search for a mapping.
8484 */
8485 for (mi = nsMap; mi != topmi->next; mi = mi->next) {
8486 if ((mi->shadowDepth == -1) &&
8487 (cur->ns == mi->oldNs)) {
8488
8489 cur->ns = mi->newNs;
8490 goto ns_end;
8491 }
8492 }
8493 }
8494 /*
8495 * Start searching for an in-scope ns-decl.
8496 */
8497 if (ctxt != NULL) {
8498 /*
8499 * User-defined behaviour.
8500 */
8501#if 0
8502 ctxt->aquireNsDecl(ctxt, cur->ns, &ns);
8503#endif
8504 /*
8505 * Insert mapping if ns is available; it's the users fault
8506 * if not.
8507 */
8508 if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi,
8509 ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
8510 goto internal_error;
8511 cur->ns = ns;
8512 } else {
8513 /*
8514 * Aquire a normalized ns-decl and add it to the map.
8515 */
8516 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
8517 /* ns-decls on curElem or on destDoc->oldNs */
8518 destParent ? curElem : NULL,
8519 cur->ns, &ns,
8520 &nsMap, &topmi, depth,
8521 ancestorsOnly,
8522 /* ns-decls must be prefixed for attributes. */
8523 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8524 goto internal_error;
8525 cur->ns = ns;
8526 }
8527ns_end:
8528 /*
8529 * Further node properties.
8530 * TODO: Is this all?
8531 */
8532 XML_TREE_ADOPT_STR(cur->name)
8533 if (cur->type == XML_ELEMENT_NODE) {
8534 cur->psvi = NULL;
8535 cur->line = 0;
8536 cur->extra = 0;
8537 /*
8538 * Walk attributes.
8539 */
8540 if (cur->properties != NULL) {
8541 /*
8542 * Process first attribute node.
8543 */
8544 cur = (xmlNodePtr) cur->properties;
8545 continue;
8546 }
8547 } else {
8548 /*
8549 * Attributes.
8550 */
8551 if ((sourceDoc != NULL) &&
8552 (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID))
8553 xmlRemoveID(sourceDoc, (xmlAttrPtr) cur);
8554 ((xmlAttrPtr) cur)->atype = 0;
8555 ((xmlAttrPtr) cur)->psvi = NULL;
8556 }
8557 break;
8558 case XML_TEXT_NODE:
8559 case XML_CDATA_SECTION_NODE:
8560 /*
8561 * This puts the content in the dest dict, only if
8562 * it was previously in the source dict.
8563 */
8564 XML_TREE_ADOPT_STR_2(cur->content)
8565 goto leave_node;
8566 case XML_ENTITY_REF_NODE:
8567 /*
8568 * Remove reference to the entitity-node.
8569 */
8570 cur->content = NULL;
8571 cur->children = NULL;
8572 cur->last = NULL;
8573 if ((destDoc->intSubset) || (destDoc->extSubset)) {
8574 xmlEntityPtr ent;
8575 /*
8576 * Assign new entity-node if available.
8577 */
8578 ent = xmlGetDocEntity(destDoc, cur->name);
8579 if (ent != NULL) {
8580 cur->content = ent->content;
8581 cur->children = (xmlNodePtr) ent;
8582 cur->last = (xmlNodePtr) ent;
8583 }
8584 }
8585 goto leave_node;
8586 case XML_PI_NODE:
8587 XML_TREE_ADOPT_STR(cur->name)
8588 XML_TREE_ADOPT_STR_2(cur->content)
8589 break;
8590 case XML_COMMENT_NODE:
8591 break;
8592 default:
8593 goto internal_error;
8594 }
8595 /*
8596 * Walk the tree.
8597 */
8598 if (cur->children != NULL) {
8599 cur = cur->children;
8600 continue;
8601 }
8602
8603leave_node:
8604 if (cur == node)
8605 break;
8606 if ((cur->type == XML_ELEMENT_NODE) ||
8607 (cur->type == XML_XINCLUDE_START) ||
8608 (cur->type == XML_XINCLUDE_END)) {
8609 /*
8610 * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
8611 */
8612 if (nsMap != NULL) {
8613 /*
8614 * Pop mappings.
8615 */
8616 while (topmi->depth >= depth)
8617 topmi = topmi->prev;
8618 /*
8619 * Unshadow.
8620 */
8621 for (mi = nsMap; mi != topmi->next; mi = mi->next)
8622 if (mi->shadowDepth >= depth)
8623 mi->shadowDepth = -1;
8624 }
8625 depth--;
8626 }
8627 if (cur->next != NULL)
8628 cur = cur->next;
8629 else {
8630 cur = cur->parent;
8631 goto leave_node;
8632 }
8633 }
8634 /*
8635 * Cleanup.
8636 */
8637 if (nsMap != NULL)
8638 xmlDOMWrapNSNormFreeNsMap(nsMap);
8639 return (ret);
8640internal_error:
8641 if (nsMap != NULL)
8642 xmlDOMWrapNSNormFreeNsMap(nsMap);
8643 return (-1);
8644}
8645
8646/*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008647* xmlDOMWrapCloneNode:
8648* @ctxt: the optional context for custom processing
8649* @sourceDoc: the optional sourceDoc
8650* @node: the node to start with
8651* @resNode: the clone of the given @node
8652* @destDoc: the destination doc
8653* @destParent: the optional new parent of @node in @destDoc
8654* @options: option flags
8655*
8656* References of out-of scope ns-decls are remapped to point to @destDoc:
8657* 1) If @destParent is given, then nsDef entries on element-nodes are used
8658* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used
8659* This is the case when you have an unliked node and just want to move it
8660* to the context of
8661*
8662* If @destParent is given, it ensures that the tree is namespace
8663* wellformed by creating additional ns-decls where needed.
8664* Note that, since prefixes of already existent ns-decls can be
8665* shadowed by this process, it could break QNames in attribute
8666* values or element content.
8667* TODO:
8668* 1) Support dicts
8669* Optimize string adoption for equal or none dicts.
8670* 2) XInclude
8671* WARNING: This function is in a experimental state and should only be currently
8672* only be used to test it.
8673*
8674* Returns 0 if the operation succeeded,
8675* 1 if a node of unsupported (or not yet supported) type was given,
8676* -1 on API/internal errors.
8677*/
8678
8679int
8680xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt,
8681 xmlDocPtr sourceDoc,
8682 xmlNodePtr node,
8683 xmlNodePtr *resNode,
8684 xmlDocPtr destDoc,
8685 xmlNodePtr destParent,
8686 int deep,
8687 int options ATTRIBUTE_UNUSED)
8688{
8689 int ret = 0;
8690 xmlNodePtr cur, curElem = NULL;
8691 xmlNsMapItemPtr nsMap = NULL, topmi = NULL, mi;
8692 xmlNsPtr ns;
8693 int depth = -1;
8694 /* int adoptStr = 1; */
8695 /* gather @parent's ns-decls. */
8696 int parnsdone = 0;
8697 /* @ancestorsOnly should be set per option. */
8698 int ancestorsOnly = 0;
8699 xmlNodePtr resultClone = NULL, clone = NULL, parentClone = NULL, prevClone = NULL;
8700 xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL;
8701
8702 if ((node == NULL) || (resNode == NULL) ||
8703 (sourceDoc == NULL) || (destDoc == NULL))
8704 return(-1);
8705 /*
8706 * TODO: Initially we support only element-nodes.
8707 */
8708 if (node->type != XML_ELEMENT_NODE)
8709 return(1);
8710 /*
8711 * Check node->doc sanity.
8712 */
8713 if ((node->doc != NULL) && (sourceDoc != NULL) &&
8714 (node->doc != sourceDoc)) {
8715 /*
8716 * Might be an XIncluded node.
8717 */
8718 return (-1);
8719 }
8720 if (sourceDoc == NULL)
8721 sourceDoc = node->doc;
8722 if (sourceDoc == destDoc)
8723 return (-1);
8724
8725 *resNode = NULL;
8726
8727 deep = 1;
8728 cur = node;
8729 while (cur != NULL) {
8730 if (cur->doc != sourceDoc) {
8731 /*
8732 * We'll assume XIncluded nodes if the doc differs.
8733 * TODO: Do we need to reconciliate XIncluded nodes?
8734 * TODO: This here returns -1 in this case.
8735 */
8736 goto internal_error;
8737 }
8738 /*
8739 * Create a new node.
8740 */
8741 switch (cur->type) {
8742 case XML_XINCLUDE_START:
8743 case XML_XINCLUDE_END:
8744 /* TODO: What to do with XInclude? */
8745 goto internal_error;
8746 break;
8747 case XML_TEXT_NODE:
8748 case XML_CDATA_SECTION_NODE:
8749 case XML_ELEMENT_NODE:
8750 case XML_DOCUMENT_FRAG_NODE:
8751 case XML_ENTITY_REF_NODE:
8752 case XML_ENTITY_NODE:
8753 case XML_PI_NODE:
8754 case XML_COMMENT_NODE:
8755 /*
8756 * Nodes of xmlNode structure.
8757 */
8758 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
8759 if (clone == NULL) {
8760 xmlTreeErrMemory("xmlDOMWrapCloneBranch(): allocating a node");
8761 goto internal_error;
8762 }
8763 memset(clone, 0, sizeof(xmlNode));
8764 /*
8765 * Set hierachical links.
8766 */
8767 if (resultClone != NULL) {
8768 clone->parent = parentClone;
8769 if (prevClone) {
8770 prevClone->next = clone;
8771 clone->prev = prevClone;
8772 } else
8773 parentClone->children = clone;
8774 } else
8775 resultClone = clone;
8776
8777 break;
8778 case XML_ATTRIBUTE_NODE:
8779 /*
8780 * Attributes (xmlAttr).
8781 */
8782 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlAttr));
8783 if (clone == NULL) {
8784 xmlTreeErrMemory("xmlDOMWrapCloneBranch(): allocating an attr-node");
8785 goto internal_error;
8786 }
8787 memset(clone, 0, sizeof(xmlAttr));
8788 /*
8789 * Set hierachical links.
8790 */
8791 if (resultClone != NULL) {
8792 clone->parent = parentClone;
8793 if (prevClone) {
8794 prevClone->next = clone;
8795 clone->prev = prevClone;
8796 } else
8797 parentClone->properties = (xmlAttrPtr) clone;
8798 } else
8799 resultClone = clone;
8800 break;
8801 default:
8802 /* TODO */
8803 goto internal_error;
8804 }
8805
8806 clone->type = cur->type;
8807 clone->doc = destDoc;
8808
8809 if (cur->name == xmlStringText)
8810 clone->name = xmlStringText;
8811 else if (cur->name == xmlStringTextNoenc)
8812 /*
8813 * TODO: xmlStringTextNoenc is never assigned to a node
8814 * in tree.c.
8815 */
8816 clone->name = xmlStringTextNoenc;
8817 else if (cur->name == xmlStringComment)
8818 clone->name = xmlStringComment;
8819 else if (cur->name != NULL) {
8820 if ((destDoc != NULL) && (destDoc->dict != NULL))
8821 clone->name = xmlDictLookup(destDoc->dict, cur->name, -1);
8822 else
8823 clone->name = xmlStrdup(cur->name);
8824 }
8825
8826 switch (cur->type) {
8827 case XML_XINCLUDE_START:
8828 case XML_XINCLUDE_END:
8829 /*
8830 * TODO
8831 */
8832 return (-1);
8833 case XML_ELEMENT_NODE:
8834 curElem = cur;
8835 depth++;
8836 /*
8837 * Namespace declarations.
8838 */
8839 if ((ctxt == NULL) && (cur->nsDef != NULL)) {
8840 if (! parnsdone) {
8841 if (destParent && (ctxt == NULL)) {
8842 /*
8843 * Gather @parent's in-scope ns-decls.
8844 */
8845 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8846 destParent) == -1)
8847 goto internal_error;
8848 if (nsMap != NULL)
8849 topmi = nsMap->prev;
8850 }
8851 parnsdone = 1;
8852 }
8853 /*
8854 * Clone namespace declarations.
8855 */
8856 cloneNsDefSlot = &(clone->nsDef);
8857 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8858 /*
8859 * Create a new xmlNs.
8860 */
8861 cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
8862 if (cloneNs == NULL) {
8863 xmlTreeErrMemory("xmlDOMWrapCloneBranch(): "
8864 "allocating namespace");
8865 return(-1);
8866 }
8867 memset(cloneNs, 0, sizeof(xmlNs));
8868 cloneNs->type = XML_LOCAL_NAMESPACE;
8869
8870 if (ns->href != NULL)
8871 cloneNs->href = xmlStrdup(ns->href);
8872 if (ns->prefix != NULL)
8873 cloneNs->prefix = xmlStrdup(ns->prefix);
8874
8875 *cloneNsDefSlot = cloneNs;
8876 cloneNsDefSlot = &(cloneNs->next);
8877
8878 /*
8879 * Does it shadow any ns-decl?
8880 */
8881 if (nsMap) {
8882 for (mi = nsMap; mi != topmi->next;
8883 mi = mi->next) {
8884 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8885 (mi->shadowDepth == -1) &&
8886 ((ns->prefix == mi->newNs->prefix) ||
8887 xmlStrEqual(ns->prefix,
8888 mi->newNs->prefix))) {
8889 /* Mark as shadowed at the current depth. */
8890 mi->shadowDepth = depth;
8891 }
8892 }
8893 }
8894 /*
8895 * Push mapping.
8896 */
8897 if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi,
8898 ns, cloneNs, depth) == NULL)
8899 goto internal_error;
8900 }
8901 }
8902 /* cur->ns will be processed further down. */
8903 break;
8904 case XML_ATTRIBUTE_NODE:
8905 /* IDs will be processed further down. */
8906 /* cur->ns will be processed further down. */
8907 break;
8908 case XML_TEXT_NODE:
8909 case XML_CDATA_SECTION_NODE:
8910 if (cur->content)
8911 clone->content = xmlStrdup(cur->content);
8912 goto leave_node;
8913 case XML_ENTITY_REF_NODE:
8914 if (sourceDoc != destDoc) {
8915 if ((destDoc->intSubset) || (destDoc->extSubset)) {
8916 xmlEntityPtr ent;
8917 /*
8918 * Assign new entity-node if available.
8919 */
8920 ent = xmlGetDocEntity(destDoc, cur->name);
8921 if (ent != NULL) {
8922 clone->content = ent->content;
8923 clone->children = (xmlNodePtr) ent;
8924 clone->last = (xmlNodePtr) ent;
8925 }
8926 }
8927 } else {
8928 /*
8929 * Use the current node's entity declaration and value.
8930 */
8931 clone->content = cur->content;
8932 clone->children = cur->children;
8933 clone->last = cur->last;
8934 }
8935 goto leave_node;
8936 case XML_PI_NODE:
8937 if (cur->content)
8938 clone->content = xmlStrdup(cur->content);
8939 goto leave_node;
8940 case XML_COMMENT_NODE:
8941 if (cur->content)
8942 clone->content = xmlStrdup(cur->content);
8943 goto leave_node;
8944 default:
8945 goto internal_error;
8946 }
8947
8948 if (cur->ns == NULL)
8949 goto end_ns_reference;
8950
8951/* handle_ns_reference: */
8952 /*
8953 ** The following will take care of references to ns-decls ********
8954 ** and is intended only for element- and attribute-nodes.
8955 **
8956 */
8957 if (! parnsdone) {
8958 if (destParent && (ctxt == NULL)) {
8959 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8960 destParent) == -1)
8961 goto internal_error;
8962 if (nsMap != NULL)
8963 topmi = nsMap->prev;
8964 }
8965 parnsdone = 1;
8966 }
8967 /*
8968 * Adopt ns-references.
8969 */
8970 if (nsMap != NULL) {
8971 /*
8972 * Search for a mapping.
8973 */
8974 for (mi = nsMap; mi != topmi->next; mi = mi->next) {
8975 if ((mi->shadowDepth == -1) &&
8976 (cur->ns == mi->oldNs)) {
8977 /*
8978 * This is the nice case: a mapping was found.
8979 */
8980 clone->ns = mi->newNs;
8981 goto end_ns_reference;
8982 }
8983 }
8984 }
8985 /*
8986 * Start searching for an in-scope ns-decl.
8987 */
8988 if (ctxt != NULL) {
8989 /*
8990 * User-defined behaviour.
8991 */
8992#if 0
8993 ctxt->aquireNsDecl(ctxt, cur->ns, &ns);
8994#endif
8995 /*
8996 * Add user's mapping.
8997 */
8998 if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi,
8999 cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
9000 goto internal_error;
9001 clone->ns = ns;
9002 } else {
9003 /*
9004 * Aquire a normalized ns-decl and add it to the map.
9005 */
9006 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
9007 /* ns-decls on curElem or on destDoc->oldNs */
9008 destParent ? curElem : NULL,
9009 cur->ns, &ns,
9010 &nsMap, &topmi, depth,
9011 ancestorsOnly,
9012 /* ns-decls must be prefixed for attributes. */
9013 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
9014 goto internal_error;
9015 clone->ns = ns;
9016 }
9017
9018end_ns_reference:
9019
9020 /*
9021 * Some post-processing.
9022 *
9023 * Handle ID attributes.
9024 */
9025 if ((clone->type == XML_ATTRIBUTE_NODE) &&
9026 (clone->parent != NULL)) {
9027 if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) {
9028
9029 xmlChar *idVal;
9030
9031 idVal = xmlNodeListGetString(cur->doc, cur->children, 1);
9032 if (idVal != NULL) {
9033 if (xmlAddID(NULL, destDoc, idVal, (xmlAttrPtr) cur) == NULL) {
9034 /* TODO: error message. */
9035 xmlFree(idVal);
9036 goto internal_error;
9037 }
9038 xmlFree(idVal);
9039 }
9040 }
9041 }
9042 /*
9043 **
9044 ** The following will traversing the tree ************************
9045 **
9046 *
9047 * Walk the element's attributes before descending into child-nodes.
9048 */
9049 if ((cur->type == XML_ELEMENT_NODE) && (cur->properties != NULL)) {
9050 prevClone = NULL;
9051 parentClone = clone;
9052 cur = (xmlNodePtr) cur->properties;
9053 continue;
9054 }
9055into_content:
9056 /*
9057 * Descend into child-nodes.
9058 */
9059 if (cur->children != NULL) {
9060 prevClone = NULL;
9061 parentClone = clone;
9062 cur = cur->children;
9063 continue;
9064 }
9065
9066leave_node:
9067 /*
9068 * At this point we are done with the node, its content
9069 * and an element-nodes's attribute-nodes.
9070 */
9071 if (cur == node)
9072 break;
9073 if ((cur->type == XML_ELEMENT_NODE) ||
9074 (cur->type == XML_XINCLUDE_START) ||
9075 (cur->type == XML_XINCLUDE_END)) {
9076 /*
9077 * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
9078 */
9079 if (nsMap != NULL) {
9080 /*
9081 * Pop mappings.
9082 */
9083 while (topmi->depth >= depth)
9084 topmi = topmi->prev;
9085 /*
9086 * Unshadow.
9087 * TODO: How to optimize this?
9088 */
9089 for (mi = nsMap; mi != topmi->next; mi = mi->next)
9090 if (mi->shadowDepth >= depth)
9091 mi->shadowDepth = -1;
9092 }
9093 depth--;
9094 }
9095 if (cur->next != NULL) {
9096 prevClone = clone;
9097 cur = cur->next;
9098 } else if (cur->type != XML_ATTRIBUTE_NODE) {
9099 /*
9100 * Set clone->last.
9101 */
9102 clone->parent->last = clone;
9103 clone = clone->parent;
9104 parentClone = clone->parent;
9105 /*
9106 * Process parent --> next;
9107 */
9108 cur = cur->parent;
9109 goto leave_node;
9110 } else {
9111 /* This is for attributes only. */
9112 clone = clone->parent;
9113 parentClone = clone->parent;
9114 /*
9115 * Process parent-element --> children.
9116 */
9117 cur = cur->parent;
9118 goto into_content;
9119 }
9120 }
9121 goto exit;
9122
9123internal_error:
9124 ret = -1;
9125
9126exit:
9127 /*
9128 * Cleanup.
9129 */
9130 if (nsMap != NULL)
9131 xmlDOMWrapNSNormFreeNsMap(nsMap);
9132 /*
9133 * TODO: Should we try a cleanup of the cloned node in case of a
9134 * fatal error?
9135 */
9136 *resNode = resultClone;
9137 return (ret);
9138}
9139
9140/*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009141* xmlDOMWrapAdoptAttr:
9142* @ctxt: the optional context for custom processing
9143* @sourceDoc: the optional source document of attr
9144* @attr: the attribute-node to be adopted
9145* @destDoc: the destination doc for adoption
9146* @destParent: the optional new parent of @attr in @destDoc
9147* @options: option flags
9148*
9149* @attr is adopted by @destDoc.
9150* Ensures that ns-references point to @destDoc: either to
9151* elements->nsDef entries if @destParent is given, or to
9152* @destDoc->oldNs otherwise.
9153*
9154* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
9155*/
9156static int
9157xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt,
9158 xmlDocPtr sourceDoc,
9159 xmlAttrPtr attr,
9160 xmlDocPtr destDoc,
9161 xmlNodePtr destParent,
9162 int options ATTRIBUTE_UNUSED)
9163{
9164 xmlNodePtr cur;
9165 int adoptStr = 1;
9166
9167 if ((attr == NULL) || (destDoc == NULL))
9168 return (-1);
9169
9170 attr->doc = destDoc;
9171 if (attr->ns != NULL) {
9172 xmlNsPtr ns = NULL;
9173
9174 if (ctxt != NULL) {
9175 /* TODO: User defined. */
9176 }
9177 /* XML Namespace. */
9178 if ((attr->ns->prefix[0] == 'x') && (attr->ns->prefix[1] == 'm') &&
9179 (attr->ns->prefix[2] == 'l') && (attr->ns->prefix[3] == 0)) {
9180 ns = xmlTreeEnsureXMLDecl(destDoc);
9181 } else if (destParent == NULL) {
9182 /*
9183 * Store in @destDoc->oldNs.
9184 */
9185 ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix);
9186 } else {
9187 /*
9188 * Declare on @destParent.
9189 */
9190 if (xmlSearchNsByHrefStrict(destDoc, destParent, attr->ns->href,
9191 &ns, 1) == -1)
9192 goto internal_error;
9193 if (ns == NULL) {
9194 ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent,
9195 attr->ns->href, attr->ns->prefix, 1);
9196 }
9197 }
9198 if (ns == NULL)
9199 goto internal_error;
9200 attr->ns = ns;
9201 }
9202
9203 XML_TREE_ADOPT_STR(attr->name);
9204 attr->atype = 0;
9205 attr->psvi = NULL;
9206 /*
9207 * Walk content.
9208 */
9209 if (attr->children == NULL)
9210 return (0);
9211 cur = attr->children;
9212 while (cur != NULL) {
9213 cur->doc = destDoc;
9214 switch (cur->type) {
9215 case XML_TEXT_NODE:
9216 case XML_CDATA_SECTION_NODE:
9217 XML_TREE_ADOPT_STR_2(cur->content)
9218 break;
9219 case XML_ENTITY_REF_NODE:
9220 /*
9221 * Remove reference to the entitity-node.
9222 */
9223 cur->content = NULL;
9224 cur->children = NULL;
9225 cur->last = NULL;
9226 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9227 xmlEntityPtr ent;
9228 /*
9229 * Assign new entity-node if available.
9230 */
9231 ent = xmlGetDocEntity(destDoc, cur->name);
9232 if (ent != NULL) {
9233 cur->content = ent->content;
9234 cur->children = (xmlNodePtr) ent;
9235 cur->last = (xmlNodePtr) ent;
9236 }
9237 }
9238 break;
9239 default:
9240 break;
9241 }
9242 if (cur->children != NULL) {
9243 cur = cur->children;
9244 continue;
9245 }
9246next_sibling:
9247 if (cur == (xmlNodePtr) attr)
9248 break;
9249 if (cur->next != NULL)
9250 cur = cur->next;
9251 else {
9252 cur = cur->parent;
9253 goto next_sibling;
9254 }
9255 }
9256 return (0);
9257internal_error:
9258 return (-1);
9259}
9260
9261/*
9262* xmlDOMWrapAdoptNode:
9263* @ctxt: the optional context for custom processing
9264* @sourceDoc: the optional sourceDoc
9265* @node: the node to start with
9266* @destDoc: the destination doc
Kasimier T. Buchcik4d9c9482005-06-27 15:04:46 +00009267* @destParent: the optional new parent of @node in @destDoc
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009268* @options: option flags
9269*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009270* References of out-of scope ns-decls are remapped to point to @destDoc:
9271* 1) If @destParent is given, then nsDef entries on element-nodes are used
9272* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used
9273* This is the case when you have an unliked node and just want to move it
9274* to the context of
9275*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009276* If @destParent is given, it ensures that the tree is namespace
9277* wellformed by creating additional ns-decls where needed.
9278* Note that, since prefixes of already existent ns-decls can be
9279* shadowed by this process, it could break QNames in attribute
9280* values or element content.
Kasimier T. Buchcik017264f2005-06-27 13:45:24 +00009281* WARNING: This function is in a experimental state.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009282*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009283* Returns 0 if the operation succeeded,
9284* 1 if a node of unsupported type was given,
9285* 2 if a node of not yet supported type was given and
9286* -1 on API/internal errors.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009287*/
9288int
9289xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt,
9290 xmlDocPtr sourceDoc,
9291 xmlNodePtr node,
9292 xmlDocPtr destDoc,
9293 xmlNodePtr destParent,
9294 int options)
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009295{
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009296 if ((node == NULL) || (destDoc == NULL) ||
9297 ((destParent != NULL) && (destParent->doc != destDoc)))
9298 return(-1);
9299 /*
9300 * Check node->doc sanity.
9301 */
9302 if ((node->doc != NULL) && (sourceDoc != NULL) &&
9303 (node->doc != sourceDoc)) {
9304 /*
9305 * Might be an XIncluded node.
9306 */
9307 return (-1);
9308 }
9309 if (sourceDoc == NULL)
9310 sourceDoc = node->doc;
9311 if (sourceDoc == destDoc)
9312 return (-1);
9313 switch (node->type) {
9314 case XML_ELEMENT_NODE:
9315 case XML_ATTRIBUTE_NODE:
9316 case XML_TEXT_NODE:
9317 case XML_CDATA_SECTION_NODE:
9318 case XML_ENTITY_REF_NODE:
9319 case XML_PI_NODE:
9320 case XML_COMMENT_NODE:
9321 break;
9322 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009323 /* TODO: Support document-fragment-nodes. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009324 return (2);
9325 default:
9326 return (1);
9327 }
9328 /*
9329 * Unlink only if @node was not already added to @destParent.
9330 */
9331 if ((node->parent != NULL) && (destParent != node->parent))
9332 xmlUnlinkNode(node);
9333
9334 if (node->type == XML_ELEMENT_NODE) {
9335 return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node,
9336 destDoc, destParent, options));
9337 } else if (node->type == XML_ATTRIBUTE_NODE) {
9338 return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc,
9339 (xmlAttrPtr) node, destDoc, destParent, options));
9340 } else {
9341 xmlNodePtr cur = node;
9342 int adoptStr = 1;
9343
9344 cur->doc = destDoc;
9345 /*
9346 * Optimize string adoption.
9347 */
9348 if ((sourceDoc != NULL) &&
9349 (sourceDoc->dict == destDoc->dict))
9350 adoptStr = 0;
9351 switch (node->type) {
9352 case XML_TEXT_NODE:
9353 case XML_CDATA_SECTION_NODE:
9354 XML_TREE_ADOPT_STR_2(node->content)
9355 break;
9356 case XML_ENTITY_REF_NODE:
9357 /*
9358 * Remove reference to the entitity-node.
9359 */
9360 node->content = NULL;
9361 node->children = NULL;
9362 node->last = NULL;
9363 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9364 xmlEntityPtr ent;
9365 /*
9366 * Assign new entity-node if available.
9367 */
9368 ent = xmlGetDocEntity(destDoc, node->name);
9369 if (ent != NULL) {
9370 node->content = ent->content;
9371 node->children = (xmlNodePtr) ent;
9372 node->last = (xmlNodePtr) ent;
9373 }
9374 }
9375 XML_TREE_ADOPT_STR(node->name)
9376 break;
Daniel Veillard7e21fd12005-07-03 21:44:07 +00009377 case XML_PI_NODE: {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009378 XML_TREE_ADOPT_STR(node->name)
9379 XML_TREE_ADOPT_STR_2(node->content)
9380 break;
Daniel Veillard7e21fd12005-07-03 21:44:07 +00009381 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009382 default:
9383 break;
9384 }
9385 }
9386 return (0);
9387}
9388
9389
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009390
Daniel Veillard5d4644e2005-04-01 13:11:58 +00009391#define bottom_tree
9392#include "elfgcchack.h"