blob: a2fdcbf5c7f827e81b1dcc48d8c04511290b3dbb [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 ! */
Daniel Veillard1dc9feb2008-11-17 15:59:21 +000017#include <limits.h>
Owen Taylor3473f882001-02-23 17:55:21 +000018#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
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +000046/************************************************************************
47 * *
Daniel Veillardaa6de472008-08-25 14:53:31 +000048 * Forward declarations *
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +000049 * *
50 ************************************************************************/
51
Daniel Veillard8ed10722009-08-20 19:17:36 +020052static xmlNsPtr
53xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
Daniel Veillard56a4cb82001-03-24 17:00:36 +000054
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +000055static xmlChar* xmlGetPropNodeValueInternal(xmlAttrPtr prop);
56
Daniel Veillard56a4cb82001-03-24 17:00:36 +000057/************************************************************************
58 * *
Daniel Veillardaa6de472008-08-25 14:53:31 +000059 * Tree memory error handler *
Daniel Veillard18ec16e2003-10-07 23:16:40 +000060 * *
61 ************************************************************************/
62/**
63 * xmlTreeErrMemory:
64 * @extra: extra informations
65 *
66 * Handle an out of memory condition
67 */
68static void
69xmlTreeErrMemory(const char *extra)
70{
71 __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
72}
73
74/**
75 * xmlTreeErr:
76 * @code: the error number
77 * @extra: extra informations
78 *
79 * Handle an out of memory condition
80 */
81static void
82xmlTreeErr(int code, xmlNodePtr node, const char *extra)
83{
84 const char *msg = NULL;
85
86 switch(code) {
87 case XML_TREE_INVALID_HEX:
Daniel Veillardac996a12004-07-30 12:02:58 +000088 msg = "invalid hexadecimal character value\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000089 break;
90 case XML_TREE_INVALID_DEC:
Daniel Veillardac996a12004-07-30 12:02:58 +000091 msg = "invalid decimal character value\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000092 break;
93 case XML_TREE_UNTERMINATED_ENTITY:
Daniel Veillardac996a12004-07-30 12:02:58 +000094 msg = "unterminated entity reference %15s\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000095 break;
Daniel Veillard6f8611f2008-02-15 08:33:21 +000096 case XML_TREE_NOT_UTF8:
97 msg = "string is not in UTF-8\n";
98 break;
Daniel Veillard18ec16e2003-10-07 23:16:40 +000099 default:
Daniel Veillardac996a12004-07-30 12:02:58 +0000100 msg = "unexpected error number\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000101 }
102 __xmlSimpleError(XML_FROM_TREE, code, node, msg, extra);
103}
104
105/************************************************************************
106 * *
Daniel Veillardaa6de472008-08-25 14:53:31 +0000107 * A few static variables and macros *
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000108 * *
109 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +0000110/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +0000111const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +0000112/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +0000113const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +0000114 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +0000115/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +0000116const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
117
Owen Taylor3473f882001-02-23 17:55:21 +0000118static int xmlCompressMode = 0;
119static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000120
Owen Taylor3473f882001-02-23 17:55:21 +0000121#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
122 xmlNodePtr ulccur = (n)->children; \
123 if (ulccur == NULL) { \
124 (n)->last = NULL; \
125 } else { \
126 while (ulccur->next != NULL) { \
Daniel Veillardaa6de472008-08-25 14:53:31 +0000127 ulccur->parent = (n); \
Owen Taylor3473f882001-02-23 17:55:21 +0000128 ulccur = ulccur->next; \
129 } \
130 ulccur->parent = (n); \
131 (n)->last = ulccur; \
132}}
133
Kasimier T. Buchcik44353412006-03-06 13:26:16 +0000134#define IS_STR_XML(str) ((str != NULL) && (str[0] == 'x') && \
135 (str[1] == 'm') && (str[2] == 'l') && (str[3] == 0))
136
Owen Taylor3473f882001-02-23 17:55:21 +0000137/* #define DEBUG_BUFFER */
138/* #define DEBUG_TREE */
139
140/************************************************************************
141 * *
Daniel Veillardaa6de472008-08-25 14:53:31 +0000142 * Functions to move to entities.c once the *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000143 * API freeze is smoothen and they can be made public. *
144 * *
145 ************************************************************************/
146#include <libxml/hash.h>
Daniel Veillardaa6de472008-08-25 14:53:31 +0000147
Daniel Veillard652327a2003-09-29 18:02:38 +0000148#ifdef LIBXML_TREE_ENABLED
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000149/**
150 * xmlGetEntityFromDtd:
151 * @dtd: A pointer to the DTD to search
152 * @name: The entity name
153 *
154 * Do an entity lookup in the DTD entity hash table and
155 * return the corresponding entity, if found.
Daniel Veillardaa6de472008-08-25 14:53:31 +0000156 *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000157 * Returns A pointer to the entity structure or NULL if not found.
158 */
159static xmlEntityPtr
160xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
161 xmlEntitiesTablePtr table;
Daniel Veillardaa6de472008-08-25 14:53:31 +0000162
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000163 if((dtd != NULL) && (dtd->entities != NULL)) {
164 table = (xmlEntitiesTablePtr) dtd->entities;
165 return((xmlEntityPtr) xmlHashLookup(table, name));
Daniel Veillardaa6de472008-08-25 14:53:31 +0000166 /* return(xmlGetEntityFromTable(table, name)); */
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000167 }
168 return(NULL);
169}
170/**
171 * xmlGetParameterEntityFromDtd:
172 * @dtd: A pointer to the DTD to search
173 * @name: The entity name
Daniel Veillardaa6de472008-08-25 14:53:31 +0000174 *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000175 * Do an entity lookup in the DTD pararmeter entity hash table and
176 * return the corresponding entity, if found.
177 *
178 * Returns A pointer to the entity structure or NULL if not found.
179 */
180static xmlEntityPtr
181xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
182 xmlEntitiesTablePtr table;
Daniel Veillardaa6de472008-08-25 14:53:31 +0000183
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000184 if ((dtd != NULL) && (dtd->pentities != NULL)) {
185 table = (xmlEntitiesTablePtr) dtd->pentities;
186 return((xmlEntityPtr) xmlHashLookup(table, name));
187 /* return(xmlGetEntityFromTable(table, name)); */
188 }
189 return(NULL);
190}
Daniel Veillard652327a2003-09-29 18:02:38 +0000191#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000192
193/************************************************************************
194 * *
Daniel Veillardc00cda82003-04-07 10:22:39 +0000195 * QName handling helper *
196 * *
197 ************************************************************************/
198
199/**
200 * xmlBuildQName:
201 * @ncname: the Name
202 * @prefix: the prefix
203 * @memory: preallocated memory
204 * @len: preallocated memory length
205 *
206 * Builds the QName @prefix:@ncname in @memory if there is enough space
207 * and prefix is not NULL nor empty, otherwise allocate a new string.
208 * If prefix is NULL or empty it returns ncname.
209 *
210 * Returns the new string which must be freed by the caller if different from
211 * @memory and @ncname or NULL in case of error
212 */
213xmlChar *
214xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
215 xmlChar *memory, int len) {
216 int lenn, lenp;
217 xmlChar *ret;
218
Daniel Veillard3b7840c2003-09-11 23:42:01 +0000219 if (ncname == NULL) return(NULL);
220 if (prefix == NULL) return((xmlChar *) ncname);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000221
222 lenn = strlen((char *) ncname);
223 lenp = strlen((char *) prefix);
224
225 if ((memory == NULL) || (len < lenn + lenp + 2)) {
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000226 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000227 if (ret == NULL) {
228 xmlTreeErrMemory("building QName");
229 return(NULL);
230 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000231 } else {
232 ret = memory;
233 }
234 memcpy(&ret[0], prefix, lenp);
235 ret[lenp] = ':';
236 memcpy(&ret[lenp + 1], ncname, lenn);
237 ret[lenn + lenp + 1] = 0;
238 return(ret);
239}
240
241/**
242 * xmlSplitQName2:
243 * @name: the full QName
Daniel Veillardaa6de472008-08-25 14:53:31 +0000244 * @prefix: a xmlChar **
Daniel Veillardc00cda82003-04-07 10:22:39 +0000245 *
246 * parse an XML qualified name string
247 *
248 * [NS 5] QName ::= (Prefix ':')? LocalPart
249 *
250 * [NS 6] Prefix ::= NCName
251 *
252 * [NS 7] LocalPart ::= NCName
253 *
254 * Returns NULL if not a QName, otherwise the local part, and prefix
255 * is updated to get the Prefix if any.
256 */
257
258xmlChar *
259xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
260 int len = 0;
261 xmlChar *ret = NULL;
262
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000263 if (prefix == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000264 *prefix = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000265 if (name == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000266
267#ifndef XML_XML_NAMESPACE
268 /* xml: prefix is not really a namespace */
269 if ((name[0] == 'x') && (name[1] == 'm') &&
270 (name[2] == 'l') && (name[3] == ':'))
271 return(NULL);
272#endif
273
274 /* nasty but valid */
275 if (name[0] == ':')
276 return(NULL);
277
278 /*
279 * we are not trying to validate but just to cut, and yes it will
280 * work even if this is as set of UTF-8 encoded chars
281 */
Daniel Veillardaa6de472008-08-25 14:53:31 +0000282 while ((name[len] != 0) && (name[len] != ':'))
Daniel Veillardc00cda82003-04-07 10:22:39 +0000283 len++;
Daniel Veillardaa6de472008-08-25 14:53:31 +0000284
Daniel Veillardc00cda82003-04-07 10:22:39 +0000285 if (name[len] == 0)
286 return(NULL);
287
288 *prefix = xmlStrndup(name, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000289 if (*prefix == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000290 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000291 return(NULL);
292 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000293 ret = xmlStrdup(&name[len + 1]);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000294 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000295 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000296 if (*prefix != NULL) {
297 xmlFree(*prefix);
298 *prefix = NULL;
299 }
300 return(NULL);
301 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000302
303 return(ret);
304}
305
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000306/**
307 * xmlSplitQName3:
308 * @name: the full QName
309 * @len: an int *
310 *
311 * parse an XML qualified name string,i
312 *
313 * returns NULL if it is not a Qualified Name, otherwise, update len
314 * with the lenght in byte of the prefix and return a pointer
Daniel Veillard54f9a4f2005-09-03 13:28:24 +0000315 * to the start of the name without the prefix
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000316 */
317
318const xmlChar *
319xmlSplitQName3(const xmlChar *name, int *len) {
320 int l = 0;
321
322 if (name == NULL) return(NULL);
323 if (len == NULL) return(NULL);
324
325 /* nasty but valid */
326 if (name[0] == ':')
327 return(NULL);
328
329 /*
330 * we are not trying to validate but just to cut, and yes it will
331 * work even if this is as set of UTF-8 encoded chars
332 */
Daniel Veillardaa6de472008-08-25 14:53:31 +0000333 while ((name[l] != 0) && (name[l] != ':'))
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000334 l++;
Daniel Veillardaa6de472008-08-25 14:53:31 +0000335
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000336 if (name[l] == 0)
337 return(NULL);
338
339 *len = l;
340
341 return(&name[l+1]);
342}
343
Daniel Veillardc00cda82003-04-07 10:22:39 +0000344/************************************************************************
345 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000346 * Check Name, NCName and QName strings *
347 * *
348 ************************************************************************/
Daniel Veillardaa6de472008-08-25 14:53:31 +0000349
Daniel Veillardd2298792003-02-14 16:54:11 +0000350#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
351
Daniel Veillardf1a27c62006-10-13 22:33:03 +0000352#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED) || defined (LIBXML_HTML_ENABLED) || defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_HTML_ENABLED) || defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_DOCB_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000353/**
354 * xmlValidateNCName:
355 * @value: the value to check
356 * @space: allow spaces in front and end of the string
357 *
358 * Check that a value conforms to the lexical space of NCName
359 *
360 * Returns 0 if this validates, a positive error code number otherwise
361 * and -1 in case of internal or API error.
362 */
363int
364xmlValidateNCName(const xmlChar *value, int space) {
365 const xmlChar *cur = value;
366 int c,l;
367
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000368 if (value == NULL)
369 return(-1);
370
Daniel Veillardd2298792003-02-14 16:54:11 +0000371 /*
372 * First quick algorithm for ASCII range
373 */
374 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000375 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000376 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
377 (*cur == '_'))
378 cur++;
379 else
380 goto try_complex;
381 while (((*cur >= 'a') && (*cur <= 'z')) ||
382 ((*cur >= 'A') && (*cur <= 'Z')) ||
383 ((*cur >= '0') && (*cur <= '9')) ||
384 (*cur == '_') || (*cur == '-') || (*cur == '.'))
385 cur++;
386 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000387 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000388 if (*cur == 0)
389 return(0);
390
391try_complex:
392 /*
393 * Second check for chars outside the ASCII range
394 */
395 cur = value;
396 c = CUR_SCHAR(cur, l);
397 if (space) {
398 while (IS_BLANK(c)) {
399 cur += l;
400 c = CUR_SCHAR(cur, l);
401 }
402 }
William M. Brack871611b2003-10-18 04:53:14 +0000403 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000404 return(1);
405 cur += l;
406 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000407 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
408 (c == '-') || (c == '_') || IS_COMBINING(c) ||
409 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000410 cur += l;
411 c = CUR_SCHAR(cur, l);
412 }
413 if (space) {
414 while (IS_BLANK(c)) {
415 cur += l;
416 c = CUR_SCHAR(cur, l);
417 }
418 }
419 if (c != 0)
420 return(1);
421
422 return(0);
423}
Daniel Veillard2156d432004-03-04 15:59:36 +0000424#endif
Daniel Veillardd2298792003-02-14 16:54:11 +0000425
Daniel Veillard2156d432004-03-04 15:59:36 +0000426#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000427/**
428 * xmlValidateQName:
429 * @value: the value to check
430 * @space: allow spaces in front and end of the string
431 *
432 * Check that a value conforms to the lexical space of QName
433 *
434 * Returns 0 if this validates, a positive error code number otherwise
435 * and -1 in case of internal or API error.
436 */
437int
438xmlValidateQName(const xmlChar *value, int space) {
439 const xmlChar *cur = value;
440 int c,l;
441
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000442 if (value == NULL)
443 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +0000444 /*
445 * First quick algorithm for ASCII range
446 */
447 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000448 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000449 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
450 (*cur == '_'))
451 cur++;
452 else
453 goto try_complex;
454 while (((*cur >= 'a') && (*cur <= 'z')) ||
455 ((*cur >= 'A') && (*cur <= 'Z')) ||
456 ((*cur >= '0') && (*cur <= '9')) ||
457 (*cur == '_') || (*cur == '-') || (*cur == '.'))
458 cur++;
459 if (*cur == ':') {
460 cur++;
461 if (((*cur >= 'a') && (*cur <= 'z')) ||
462 ((*cur >= 'A') && (*cur <= 'Z')) ||
463 (*cur == '_'))
464 cur++;
465 else
466 goto try_complex;
467 while (((*cur >= 'a') && (*cur <= 'z')) ||
468 ((*cur >= 'A') && (*cur <= 'Z')) ||
469 ((*cur >= '0') && (*cur <= '9')) ||
470 (*cur == '_') || (*cur == '-') || (*cur == '.'))
471 cur++;
472 }
473 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000474 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000475 if (*cur == 0)
476 return(0);
477
478try_complex:
479 /*
480 * Second check for chars outside the ASCII range
481 */
482 cur = value;
483 c = CUR_SCHAR(cur, l);
484 if (space) {
485 while (IS_BLANK(c)) {
486 cur += l;
487 c = CUR_SCHAR(cur, l);
488 }
489 }
William M. Brack871611b2003-10-18 04:53:14 +0000490 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000491 return(1);
492 cur += l;
493 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000494 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
495 (c == '-') || (c == '_') || IS_COMBINING(c) ||
496 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000497 cur += l;
498 c = CUR_SCHAR(cur, l);
499 }
500 if (c == ':') {
501 cur += l;
502 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000503 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000504 return(1);
505 cur += l;
506 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000507 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
508 (c == '-') || (c == '_') || IS_COMBINING(c) ||
509 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000510 cur += l;
511 c = CUR_SCHAR(cur, l);
512 }
513 }
514 if (space) {
515 while (IS_BLANK(c)) {
516 cur += l;
517 c = CUR_SCHAR(cur, l);
518 }
519 }
520 if (c != 0)
521 return(1);
522 return(0);
523}
524
525/**
526 * xmlValidateName:
527 * @value: the value to check
528 * @space: allow spaces in front and end of the string
529 *
530 * Check that a value conforms to the lexical space of Name
531 *
532 * Returns 0 if this validates, a positive error code number otherwise
533 * and -1 in case of internal or API error.
534 */
535int
536xmlValidateName(const xmlChar *value, int space) {
537 const xmlChar *cur = value;
538 int c,l;
539
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000540 if (value == NULL)
541 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +0000542 /*
543 * First quick algorithm for ASCII range
544 */
545 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000546 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000547 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
548 (*cur == '_') || (*cur == ':'))
549 cur++;
550 else
551 goto try_complex;
552 while (((*cur >= 'a') && (*cur <= 'z')) ||
553 ((*cur >= 'A') && (*cur <= 'Z')) ||
554 ((*cur >= '0') && (*cur <= '9')) ||
555 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
556 cur++;
557 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000558 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000559 if (*cur == 0)
560 return(0);
561
562try_complex:
563 /*
564 * Second check for chars outside the ASCII range
565 */
566 cur = value;
567 c = CUR_SCHAR(cur, l);
568 if (space) {
569 while (IS_BLANK(c)) {
570 cur += l;
571 c = CUR_SCHAR(cur, l);
572 }
573 }
William M. Brack871611b2003-10-18 04:53:14 +0000574 if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000575 return(1);
576 cur += l;
577 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000578 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
579 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000580 cur += l;
581 c = CUR_SCHAR(cur, l);
582 }
583 if (space) {
584 while (IS_BLANK(c)) {
585 cur += l;
586 c = CUR_SCHAR(cur, l);
587 }
588 }
589 if (c != 0)
590 return(1);
591 return(0);
592}
593
Daniel Veillardd4310742003-02-18 21:12:46 +0000594/**
595 * xmlValidateNMToken:
596 * @value: the value to check
597 * @space: allow spaces in front and end of the string
598 *
599 * Check that a value conforms to the lexical space of NMToken
600 *
601 * Returns 0 if this validates, a positive error code number otherwise
602 * and -1 in case of internal or API error.
603 */
604int
605xmlValidateNMToken(const xmlChar *value, int space) {
606 const xmlChar *cur = value;
607 int c,l;
608
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000609 if (value == NULL)
610 return(-1);
Daniel Veillardd4310742003-02-18 21:12:46 +0000611 /*
612 * First quick algorithm for ASCII range
613 */
614 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000615 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000616 if (((*cur >= 'a') && (*cur <= 'z')) ||
617 ((*cur >= 'A') && (*cur <= 'Z')) ||
618 ((*cur >= '0') && (*cur <= '9')) ||
619 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
620 cur++;
621 else
622 goto try_complex;
623 while (((*cur >= 'a') && (*cur <= 'z')) ||
624 ((*cur >= 'A') && (*cur <= 'Z')) ||
625 ((*cur >= '0') && (*cur <= '9')) ||
626 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
627 cur++;
628 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000629 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000630 if (*cur == 0)
631 return(0);
632
633try_complex:
634 /*
635 * Second check for chars outside the ASCII range
636 */
637 cur = value;
638 c = CUR_SCHAR(cur, l);
639 if (space) {
640 while (IS_BLANK(c)) {
641 cur += l;
642 c = CUR_SCHAR(cur, l);
643 }
644 }
William M. Brack871611b2003-10-18 04:53:14 +0000645 if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
646 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
Daniel Veillardd4310742003-02-18 21:12:46 +0000647 return(1);
648 cur += l;
649 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000650 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
651 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd4310742003-02-18 21:12:46 +0000652 cur += l;
653 c = CUR_SCHAR(cur, l);
654 }
655 if (space) {
656 while (IS_BLANK(c)) {
657 cur += l;
658 c = CUR_SCHAR(cur, l);
659 }
660 }
661 if (c != 0)
662 return(1);
663 return(0);
664}
Daniel Veillard652327a2003-09-29 18:02:38 +0000665#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardd4310742003-02-18 21:12:46 +0000666
Daniel Veillardd2298792003-02-14 16:54:11 +0000667/************************************************************************
668 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000669 * Allocation and deallocation of basic structures *
670 * *
671 ************************************************************************/
Daniel Veillardaa6de472008-08-25 14:53:31 +0000672
Owen Taylor3473f882001-02-23 17:55:21 +0000673/**
674 * xmlSetBufferAllocationScheme:
675 * @scheme: allocation method to use
Daniel Veillardaa6de472008-08-25 14:53:31 +0000676 *
Owen Taylor3473f882001-02-23 17:55:21 +0000677 * Set the buffer allocation method. Types are
678 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
Daniel Veillardaa6de472008-08-25 14:53:31 +0000679 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
Owen Taylor3473f882001-02-23 17:55:21 +0000680 * improves performance
681 */
682void
683xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
Daniel Veillardda3fee42008-09-01 13:08:57 +0000684 if ((scheme == XML_BUFFER_ALLOC_EXACT) ||
685 (scheme == XML_BUFFER_ALLOC_DOUBLEIT))
686 xmlBufferAllocScheme = scheme;
Owen Taylor3473f882001-02-23 17:55:21 +0000687}
688
689/**
690 * xmlGetBufferAllocationScheme:
691 *
692 * Types are
693 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
Daniel Veillardaa6de472008-08-25 14:53:31 +0000694 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
Owen Taylor3473f882001-02-23 17:55:21 +0000695 * improves performance
Daniel Veillardaa6de472008-08-25 14:53:31 +0000696 *
Owen Taylor3473f882001-02-23 17:55:21 +0000697 * Returns the current allocation scheme
698 */
699xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000700xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000701 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000702}
703
704/**
705 * xmlNewNs:
706 * @node: the element carrying the namespace
707 * @href: the URI associated
708 * @prefix: the prefix for the namespace
709 *
710 * Creation of a new Namespace. This function will refuse to create
711 * a namespace with a similar prefix than an existing one present on this
712 * node.
713 * We use href==NULL in the case of an element creation where the namespace
714 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000715 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000716 */
717xmlNsPtr
718xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
719 xmlNsPtr cur;
720
721 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
722 return(NULL);
723
Daniel Veillardaa54d372010-09-09 18:17:47 +0200724 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))) {
725 /* xml namespace is predefined, no need to add it */
726 if (xmlStrEqual(href, XML_XML_NAMESPACE))
727 return(NULL);
728
729 /*
730 * Problem, this is an attempt to bind xml prefix to a wrong
731 * namespace, which breaks
732 * Namespace constraint: Reserved Prefixes and Namespace Names
733 * from XML namespace. But documents authors may not care in
734 * their context so let's proceed.
735 */
736 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000737
Owen Taylor3473f882001-02-23 17:55:21 +0000738 /*
739 * Allocate a new Namespace and fill the fields.
740 */
741 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
742 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000743 xmlTreeErrMemory("building namespace");
Owen Taylor3473f882001-02-23 17:55:21 +0000744 return(NULL);
745 }
746 memset(cur, 0, sizeof(xmlNs));
747 cur->type = XML_LOCAL_NAMESPACE;
748
749 if (href != NULL)
Daniel Veillardaa6de472008-08-25 14:53:31 +0000750 cur->href = xmlStrdup(href);
Owen Taylor3473f882001-02-23 17:55:21 +0000751 if (prefix != NULL)
Daniel Veillardaa6de472008-08-25 14:53:31 +0000752 cur->prefix = xmlStrdup(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000753
754 /*
755 * Add it at the end to preserve parsing order ...
756 * and checks for existing use of the prefix
757 */
758 if (node != NULL) {
759 if (node->nsDef == NULL) {
760 node->nsDef = cur;
761 } else {
762 xmlNsPtr prev = node->nsDef;
763
764 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
765 (xmlStrEqual(prev->prefix, cur->prefix))) {
766 xmlFreeNs(cur);
767 return(NULL);
Daniel Veillardaa6de472008-08-25 14:53:31 +0000768 }
Owen Taylor3473f882001-02-23 17:55:21 +0000769 while (prev->next != NULL) {
770 prev = prev->next;
771 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
772 (xmlStrEqual(prev->prefix, cur->prefix))) {
773 xmlFreeNs(cur);
774 return(NULL);
Daniel Veillardaa6de472008-08-25 14:53:31 +0000775 }
Owen Taylor3473f882001-02-23 17:55:21 +0000776 }
777 prev->next = cur;
778 }
779 }
780 return(cur);
781}
782
783/**
784 * xmlSetNs:
785 * @node: a node in the document
786 * @ns: a namespace pointer
787 *
788 * Associate a namespace to a node, a posteriori.
789 */
790void
791xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
792 if (node == NULL) {
793#ifdef DEBUG_TREE
794 xmlGenericError(xmlGenericErrorContext,
795 "xmlSetNs: node == NULL\n");
796#endif
797 return;
798 }
799 node->ns = ns;
800}
801
802/**
803 * xmlFreeNs:
804 * @cur: the namespace pointer
805 *
806 * Free up the structures associated to a namespace
807 */
808void
809xmlFreeNs(xmlNsPtr cur) {
810 if (cur == NULL) {
811#ifdef DEBUG_TREE
812 xmlGenericError(xmlGenericErrorContext,
813 "xmlFreeNs : ns == NULL\n");
814#endif
815 return;
816 }
817 if (cur->href != NULL) xmlFree((char *) cur->href);
818 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000819 xmlFree(cur);
820}
821
822/**
823 * xmlFreeNsList:
824 * @cur: the first namespace pointer
825 *
826 * Free up all the structures associated to the chained namespaces.
827 */
828void
829xmlFreeNsList(xmlNsPtr cur) {
830 xmlNsPtr next;
831 if (cur == NULL) {
832#ifdef DEBUG_TREE
833 xmlGenericError(xmlGenericErrorContext,
834 "xmlFreeNsList : ns == NULL\n");
835#endif
836 return;
837 }
838 while (cur != NULL) {
839 next = cur->next;
840 xmlFreeNs(cur);
841 cur = next;
842 }
843}
844
845/**
846 * xmlNewDtd:
847 * @doc: the document pointer
848 * @name: the DTD name
849 * @ExternalID: the external ID
850 * @SystemID: the system ID
851 *
852 * Creation of a new DTD for the external subset. To create an
853 * internal subset, use xmlCreateIntSubset().
854 *
855 * Returns a pointer to the new DTD structure
856 */
857xmlDtdPtr
858xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
859 const xmlChar *ExternalID, const xmlChar *SystemID) {
860 xmlDtdPtr cur;
861
862 if ((doc != NULL) && (doc->extSubset != NULL)) {
863#ifdef DEBUG_TREE
864 xmlGenericError(xmlGenericErrorContext,
865 "xmlNewDtd(%s): document %s already have a DTD %s\n",
866 /* !!! */ (char *) name, doc->name,
867 /* !!! */ (char *)doc->extSubset->name);
868#endif
869 return(NULL);
870 }
871
872 /*
873 * Allocate a new DTD and fill the fields.
874 */
875 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
876 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000877 xmlTreeErrMemory("building DTD");
Owen Taylor3473f882001-02-23 17:55:21 +0000878 return(NULL);
879 }
880 memset(cur, 0 , sizeof(xmlDtd));
881 cur->type = XML_DTD_NODE;
882
883 if (name != NULL)
Daniel Veillardaa6de472008-08-25 14:53:31 +0000884 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +0000885 if (ExternalID != NULL)
Daniel Veillardaa6de472008-08-25 14:53:31 +0000886 cur->ExternalID = xmlStrdup(ExternalID);
Owen Taylor3473f882001-02-23 17:55:21 +0000887 if (SystemID != NULL)
Daniel Veillardaa6de472008-08-25 14:53:31 +0000888 cur->SystemID = xmlStrdup(SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +0000889 if (doc != NULL)
890 doc->extSubset = cur;
891 cur->doc = doc;
892
Daniel Veillarda880b122003-04-21 21:36:41 +0000893 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000894 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000895 return(cur);
896}
897
898/**
899 * xmlGetIntSubset:
900 * @doc: the document pointer
901 *
902 * Get the internal subset of a document
903 * Returns a pointer to the DTD structure or NULL if not found
904 */
905
906xmlDtdPtr
907xmlGetIntSubset(xmlDocPtr doc) {
908 xmlNodePtr cur;
909
910 if (doc == NULL)
911 return(NULL);
912 cur = doc->children;
913 while (cur != NULL) {
914 if (cur->type == XML_DTD_NODE)
915 return((xmlDtdPtr) cur);
916 cur = cur->next;
917 }
918 return((xmlDtdPtr) doc->intSubset);
919}
920
921/**
922 * xmlCreateIntSubset:
923 * @doc: the document pointer
924 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000925 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000926 * @SystemID: the system ID
927 *
928 * Create the internal subset of a document
929 * Returns a pointer to the new DTD structure
930 */
931xmlDtdPtr
932xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
933 const xmlChar *ExternalID, const xmlChar *SystemID) {
934 xmlDtdPtr cur;
935
936 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
937#ifdef DEBUG_TREE
938 xmlGenericError(xmlGenericErrorContext,
939
940 "xmlCreateIntSubset(): document %s already have an internal subset\n",
941 doc->name);
942#endif
943 return(NULL);
944 }
945
946 /*
947 * Allocate a new DTD and fill the fields.
948 */
949 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
950 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000951 xmlTreeErrMemory("building internal subset");
Owen Taylor3473f882001-02-23 17:55:21 +0000952 return(NULL);
953 }
954 memset(cur, 0, sizeof(xmlDtd));
955 cur->type = XML_DTD_NODE;
956
William M. Bracka3215c72004-07-31 16:24:01 +0000957 if (name != NULL) {
958 cur->name = xmlStrdup(name);
959 if (cur->name == NULL) {
960 xmlTreeErrMemory("building internal subset");
961 xmlFree(cur);
962 return(NULL);
963 }
964 }
965 if (ExternalID != NULL) {
Daniel Veillardaa6de472008-08-25 14:53:31 +0000966 cur->ExternalID = xmlStrdup(ExternalID);
William M. Bracka3215c72004-07-31 16:24:01 +0000967 if (cur->ExternalID == NULL) {
968 xmlTreeErrMemory("building internal subset");
969 if (cur->name != NULL)
970 xmlFree((char *)cur->name);
971 xmlFree(cur);
972 return(NULL);
973 }
974 }
975 if (SystemID != NULL) {
Daniel Veillardaa6de472008-08-25 14:53:31 +0000976 cur->SystemID = xmlStrdup(SystemID);
William M. Bracka3215c72004-07-31 16:24:01 +0000977 if (cur->SystemID == NULL) {
978 xmlTreeErrMemory("building internal subset");
979 if (cur->name != NULL)
980 xmlFree((char *)cur->name);
981 if (cur->ExternalID != NULL)
982 xmlFree((char *)cur->ExternalID);
983 xmlFree(cur);
984 return(NULL);
985 }
986 }
Owen Taylor3473f882001-02-23 17:55:21 +0000987 if (doc != NULL) {
988 doc->intSubset = cur;
989 cur->parent = doc;
990 cur->doc = doc;
991 if (doc->children == NULL) {
992 doc->children = (xmlNodePtr) cur;
993 doc->last = (xmlNodePtr) cur;
994 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000995 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000996 xmlNodePtr prev;
997
Owen Taylor3473f882001-02-23 17:55:21 +0000998 prev = doc->children;
999 prev->prev = (xmlNodePtr) cur;
1000 cur->next = prev;
1001 doc->children = (xmlNodePtr) cur;
1002 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +00001003 xmlNodePtr next;
1004
1005 next = doc->children;
1006 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
1007 next = next->next;
1008 if (next == NULL) {
1009 cur->prev = doc->last;
1010 cur->prev->next = (xmlNodePtr) cur;
1011 cur->next = NULL;
1012 doc->last = (xmlNodePtr) cur;
1013 } else {
1014 cur->next = next;
1015 cur->prev = next->prev;
1016 if (cur->prev == NULL)
1017 doc->children = (xmlNodePtr) cur;
1018 else
1019 cur->prev->next = (xmlNodePtr) cur;
1020 next->prev = (xmlNodePtr) cur;
1021 }
Owen Taylor3473f882001-02-23 17:55:21 +00001022 }
1023 }
1024 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001025
Daniel Veillarda880b122003-04-21 21:36:41 +00001026 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001027 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001028 return(cur);
1029}
1030
1031/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001032 * DICT_FREE:
1033 * @str: a string
1034 *
1035 * Free a string if it is not owned by the "dict" dictionnary in the
1036 * current scope
1037 */
1038#define DICT_FREE(str) \
Daniel Veillardaa6de472008-08-25 14:53:31 +00001039 if ((str) && ((!dict) || \
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001040 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
1041 xmlFree((char *)(str));
1042
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00001043
1044/**
1045 * DICT_COPY:
1046 * @str: a string
1047 *
1048 * Copy a string using a "dict" dictionnary in the current scope,
1049 * if availabe.
1050 */
1051#define DICT_COPY(str, cpy) \
1052 if (str) { \
1053 if (dict) { \
1054 if (xmlDictOwns(dict, (const xmlChar *)(str))) \
1055 cpy = (xmlChar *) (str); \
1056 else \
1057 cpy = (xmlChar *) xmlDictLookup((dict), (const xmlChar *)(str), -1); \
1058 } else \
1059 cpy = xmlStrdup((const xmlChar *)(str)); }
1060
1061/**
1062 * DICT_CONST_COPY:
1063 * @str: a string
1064 *
1065 * Copy a string using a "dict" dictionnary in the current scope,
1066 * if availabe.
1067 */
1068#define DICT_CONST_COPY(str, cpy) \
1069 if (str) { \
1070 if (dict) { \
1071 if (xmlDictOwns(dict, (const xmlChar *)(str))) \
1072 cpy = (const xmlChar *) (str); \
1073 else \
1074 cpy = xmlDictLookup((dict), (const xmlChar *)(str), -1); \
1075 } else \
1076 cpy = (const xmlChar *) xmlStrdup((const xmlChar *)(str)); }
1077
1078
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001079/**
Owen Taylor3473f882001-02-23 17:55:21 +00001080 * xmlFreeDtd:
1081 * @cur: the DTD structure to free up
1082 *
1083 * Free a DTD structure.
1084 */
1085void
1086xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001087 xmlDictPtr dict = NULL;
1088
Owen Taylor3473f882001-02-23 17:55:21 +00001089 if (cur == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001090 return;
1091 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001092 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001093
Daniel Veillarda880b122003-04-21 21:36:41 +00001094 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001095 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1096
Owen Taylor3473f882001-02-23 17:55:21 +00001097 if (cur->children != NULL) {
1098 xmlNodePtr next, c = cur->children;
1099
1100 /*
William M. Brack18a04f22004-08-03 16:42:37 +00001101 * Cleanup all nodes which are not part of the specific lists
1102 * of notations, elements, attributes and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00001103 */
1104 while (c != NULL) {
1105 next = c->next;
William M. Brack18a04f22004-08-03 16:42:37 +00001106 if ((c->type != XML_NOTATION_NODE) &&
1107 (c->type != XML_ELEMENT_DECL) &&
1108 (c->type != XML_ATTRIBUTE_DECL) &&
1109 (c->type != XML_ENTITY_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001110 xmlUnlinkNode(c);
1111 xmlFreeNode(c);
1112 }
1113 c = next;
1114 }
1115 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001116 DICT_FREE(cur->name)
1117 DICT_FREE(cur->SystemID)
1118 DICT_FREE(cur->ExternalID)
Owen Taylor3473f882001-02-23 17:55:21 +00001119 /* TODO !!! */
1120 if (cur->notations != NULL)
1121 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
Daniel Veillardaa6de472008-08-25 14:53:31 +00001122
Owen Taylor3473f882001-02-23 17:55:21 +00001123 if (cur->elements != NULL)
1124 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1125 if (cur->attributes != NULL)
1126 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1127 if (cur->entities != NULL)
1128 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1129 if (cur->pentities != NULL)
1130 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1131
Owen Taylor3473f882001-02-23 17:55:21 +00001132 xmlFree(cur);
1133}
1134
1135/**
1136 * xmlNewDoc:
1137 * @version: xmlChar string giving the version of XML "1.0"
1138 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001139 * Creates a new XML document
1140 *
Owen Taylor3473f882001-02-23 17:55:21 +00001141 * Returns a new document
1142 */
1143xmlDocPtr
1144xmlNewDoc(const xmlChar *version) {
1145 xmlDocPtr cur;
1146
1147 if (version == NULL)
1148 version = (const xmlChar *) "1.0";
1149
1150 /*
1151 * Allocate a new document and fill the fields.
1152 */
1153 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1154 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001155 xmlTreeErrMemory("building doc");
Owen Taylor3473f882001-02-23 17:55:21 +00001156 return(NULL);
1157 }
1158 memset(cur, 0, sizeof(xmlDoc));
1159 cur->type = XML_DOCUMENT_NODE;
1160
Daniel Veillardaa6de472008-08-25 14:53:31 +00001161 cur->version = xmlStrdup(version);
William M. Bracka3215c72004-07-31 16:24:01 +00001162 if (cur->version == NULL) {
1163 xmlTreeErrMemory("building doc");
1164 xmlFree(cur);
Daniel Veillardae0765b2008-07-31 19:54:59 +00001165 return(NULL);
William M. Bracka3215c72004-07-31 16:24:01 +00001166 }
Owen Taylor3473f882001-02-23 17:55:21 +00001167 cur->standalone = -1;
1168 cur->compression = -1; /* not initialized */
1169 cur->doc = cur;
Daniel Veillardae0765b2008-07-31 19:54:59 +00001170 cur->parseFlags = 0;
1171 cur->properties = XML_DOC_USERBUILT;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001172 /*
1173 * The in memory encoding is always UTF8
1174 * This field will never change and would
1175 * be obsolete if not for binary compatibility.
1176 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001177 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001178
Daniel Veillarda880b122003-04-21 21:36:41 +00001179 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001180 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001181 return(cur);
1182}
1183
1184/**
1185 * xmlFreeDoc:
1186 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001187 *
1188 * Free up all the structures used by a document, tree included.
1189 */
1190void
1191xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001192 xmlDtdPtr extSubset, intSubset;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001193 xmlDictPtr dict = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001194
Owen Taylor3473f882001-02-23 17:55:21 +00001195 if (cur == NULL) {
1196#ifdef DEBUG_TREE
1197 xmlGenericError(xmlGenericErrorContext,
1198 "xmlFreeDoc : document == NULL\n");
1199#endif
1200 return;
1201 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001202#ifdef LIBXML_DEBUG_RUNTIME
Daniel Veillardbca3ad22005-08-23 22:14:02 +00001203#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001204 xmlDebugCheckDocument(stderr, cur);
1205#endif
Daniel Veillardbca3ad22005-08-23 22:14:02 +00001206#endif
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001207
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001208 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001209
Daniel Veillarda880b122003-04-21 21:36:41 +00001210 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001211 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1212
Daniel Veillard76d66f42001-05-16 21:05:17 +00001213 /*
1214 * Do this before freeing the children list to avoid ID lookups
1215 */
1216 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1217 cur->ids = NULL;
1218 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1219 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001220 extSubset = cur->extSubset;
1221 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001222 if (intSubset == extSubset)
1223 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001224 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001225 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001226 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001227 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001228 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001229 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001230 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001231 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001232 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001233 }
1234
1235 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001236 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001237
1238 DICT_FREE(cur->version)
1239 DICT_FREE(cur->name)
1240 DICT_FREE(cur->encoding)
1241 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001242 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001243 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001244}
1245
1246/**
1247 * xmlStringLenGetNodeList:
1248 * @doc: the document
1249 * @value: the value of the text
1250 * @len: the length of the string value
1251 *
1252 * Parse the value string and build the node list associated. Should
1253 * produce a flat tree with only TEXTs and ENTITY_REFs.
1254 * Returns a pointer to the first child
1255 */
1256xmlNodePtr
1257xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1258 xmlNodePtr ret = NULL, last = NULL;
1259 xmlNodePtr node;
1260 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001261 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001262 const xmlChar *q;
1263 xmlEntityPtr ent;
1264
1265 if (value == NULL) return(NULL);
1266
1267 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001268 while ((cur < end) && (*cur != 0)) {
1269 if (cur[0] == '&') {
1270 int charval = 0;
1271 xmlChar tmp;
1272
Owen Taylor3473f882001-02-23 17:55:21 +00001273 /*
1274 * Save the current text.
1275 */
1276 if (cur != q) {
1277 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1278 xmlNodeAddContentLen(last, q, cur - q);
1279 } else {
1280 node = xmlNewDocTextLen(doc, q, cur - q);
1281 if (node == NULL) return(ret);
1282 if (last == NULL)
1283 last = ret = node;
1284 else {
1285 last->next = node;
1286 node->prev = last;
1287 last = node;
1288 }
1289 }
1290 }
Owen Taylor3473f882001-02-23 17:55:21 +00001291 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001292 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1293 cur += 3;
1294 if (cur < end)
1295 tmp = *cur;
1296 else
1297 tmp = 0;
1298 while (tmp != ';') { /* Non input consuming loop */
Daniel Veillardaa6de472008-08-25 14:53:31 +00001299 if ((tmp >= '0') && (tmp <= '9'))
Daniel Veillard07cb8222003-09-10 10:51:05 +00001300 charval = charval * 16 + (tmp - '0');
1301 else if ((tmp >= 'a') && (tmp <= 'f'))
1302 charval = charval * 16 + (tmp - 'a') + 10;
1303 else if ((tmp >= 'A') && (tmp <= 'F'))
1304 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001305 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001306 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1307 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001308 charval = 0;
1309 break;
1310 }
1311 cur++;
1312 if (cur < end)
1313 tmp = *cur;
1314 else
1315 tmp = 0;
1316 }
1317 if (tmp == ';')
1318 cur++;
1319 q = cur;
1320 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1321 cur += 2;
1322 if (cur < end)
1323 tmp = *cur;
1324 else
1325 tmp = 0;
1326 while (tmp != ';') { /* Non input consuming loops */
Daniel Veillardaa6de472008-08-25 14:53:31 +00001327 if ((tmp >= '0') && (tmp <= '9'))
Daniel Veillard07cb8222003-09-10 10:51:05 +00001328 charval = charval * 10 + (tmp - '0');
1329 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001330 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1331 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001332 charval = 0;
1333 break;
1334 }
1335 cur++;
1336 if (cur < end)
1337 tmp = *cur;
1338 else
1339 tmp = 0;
1340 }
1341 if (tmp == ';')
1342 cur++;
1343 q = cur;
1344 } else {
1345 /*
1346 * Read the entity string
1347 */
1348 cur++;
1349 q = cur;
1350 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1351 if ((cur >= end) || (*cur == 0)) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001352 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1353 (const char *) q);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001354 return(ret);
1355 }
1356 if (cur != q) {
1357 /*
1358 * Predefined entities don't generate nodes
1359 */
1360 val = xmlStrndup(q, cur - q);
1361 ent = xmlGetDocEntity(doc, val);
1362 if ((ent != NULL) &&
1363 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1364 if (last == NULL) {
1365 node = xmlNewDocText(doc, ent->content);
1366 last = ret = node;
1367 } else if (last->type != XML_TEXT_NODE) {
1368 node = xmlNewDocText(doc, ent->content);
1369 last = xmlAddNextSibling(last, node);
1370 } else
1371 xmlNodeAddContent(last, ent->content);
Daniel Veillardaa6de472008-08-25 14:53:31 +00001372
Daniel Veillard07cb8222003-09-10 10:51:05 +00001373 } else {
1374 /*
1375 * Create a new REFERENCE_REF node
1376 */
1377 node = xmlNewReference(doc, val);
1378 if (node == NULL) {
1379 if (val != NULL) xmlFree(val);
1380 return(ret);
1381 }
1382 else if ((ent != NULL) && (ent->children == NULL)) {
1383 xmlNodePtr temp;
1384
1385 ent->children = xmlStringGetNodeList(doc,
1386 (const xmlChar*)node->content);
1387 ent->owner = 1;
1388 temp = ent->children;
1389 while (temp) {
1390 temp->parent = (xmlNodePtr)ent;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001391 ent->last = temp;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001392 temp = temp->next;
1393 }
1394 }
1395 if (last == NULL) {
1396 last = ret = node;
1397 } else {
1398 last = xmlAddNextSibling(last, node);
1399 }
1400 }
1401 xmlFree(val);
1402 }
1403 cur++;
1404 q = cur;
1405 }
1406 if (charval != 0) {
1407 xmlChar buf[10];
1408 int l;
1409
1410 l = xmlCopyCharMultiByte(buf, charval);
1411 buf[l] = 0;
1412 node = xmlNewDocText(doc, buf);
1413 if (node != NULL) {
1414 if (last == NULL) {
1415 last = ret = node;
1416 } else {
1417 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001418 }
1419 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001420 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001421 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001422 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001423 cur++;
1424 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001425 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001426 /*
1427 * Handle the last piece of text.
1428 */
1429 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1430 xmlNodeAddContentLen(last, q, cur - q);
1431 } else {
1432 node = xmlNewDocTextLen(doc, q, cur - q);
1433 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001434 if (last == NULL) {
Daniel Veillard594e5df2009-09-07 14:58:47 +02001435 ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001436 } else {
Daniel Veillard594e5df2009-09-07 14:58:47 +02001437 xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001438 }
1439 }
1440 }
1441 return(ret);
1442}
1443
1444/**
1445 * xmlStringGetNodeList:
1446 * @doc: the document
1447 * @value: the value of the attribute
1448 *
1449 * Parse the value string and build the node list associated. Should
1450 * produce a flat tree with only TEXTs and ENTITY_REFs.
1451 * Returns a pointer to the first child
1452 */
1453xmlNodePtr
1454xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1455 xmlNodePtr ret = NULL, last = NULL;
1456 xmlNodePtr node;
1457 xmlChar *val;
1458 const xmlChar *cur = value;
1459 const xmlChar *q;
1460 xmlEntityPtr ent;
1461
1462 if (value == NULL) return(NULL);
1463
1464 q = cur;
1465 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001466 if (cur[0] == '&') {
1467 int charval = 0;
1468 xmlChar tmp;
1469
Owen Taylor3473f882001-02-23 17:55:21 +00001470 /*
1471 * Save the current text.
1472 */
1473 if (cur != q) {
1474 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1475 xmlNodeAddContentLen(last, q, cur - q);
1476 } else {
1477 node = xmlNewDocTextLen(doc, q, cur - q);
1478 if (node == NULL) return(ret);
1479 if (last == NULL)
1480 last = ret = node;
1481 else {
1482 last->next = node;
1483 node->prev = last;
1484 last = node;
1485 }
1486 }
1487 }
Owen Taylor3473f882001-02-23 17:55:21 +00001488 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001489 if ((cur[1] == '#') && (cur[2] == 'x')) {
1490 cur += 3;
1491 tmp = *cur;
1492 while (tmp != ';') { /* Non input consuming loop */
Daniel Veillardaa6de472008-08-25 14:53:31 +00001493 if ((tmp >= '0') && (tmp <= '9'))
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001494 charval = charval * 16 + (tmp - '0');
1495 else if ((tmp >= 'a') && (tmp <= 'f'))
1496 charval = charval * 16 + (tmp - 'a') + 10;
1497 else if ((tmp >= 'A') && (tmp <= 'F'))
1498 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001499 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001500 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1501 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001502 charval = 0;
1503 break;
1504 }
1505 cur++;
1506 tmp = *cur;
1507 }
1508 if (tmp == ';')
1509 cur++;
1510 q = cur;
1511 } else if (cur[1] == '#') {
1512 cur += 2;
1513 tmp = *cur;
1514 while (tmp != ';') { /* Non input consuming loops */
Daniel Veillardaa6de472008-08-25 14:53:31 +00001515 if ((tmp >= '0') && (tmp <= '9'))
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001516 charval = charval * 10 + (tmp - '0');
1517 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001518 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1519 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001520 charval = 0;
1521 break;
1522 }
1523 cur++;
1524 tmp = *cur;
1525 }
1526 if (tmp == ';')
1527 cur++;
1528 q = cur;
1529 } else {
1530 /*
1531 * Read the entity string
1532 */
1533 cur++;
1534 q = cur;
1535 while ((*cur != 0) && (*cur != ';')) cur++;
1536 if (*cur == 0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001537 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1538 (xmlNodePtr) doc, (const char *) q);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001539 return(ret);
1540 }
1541 if (cur != q) {
1542 /*
1543 * Predefined entities don't generate nodes
1544 */
1545 val = xmlStrndup(q, cur - q);
1546 ent = xmlGetDocEntity(doc, val);
1547 if ((ent != NULL) &&
1548 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1549 if (last == NULL) {
1550 node = xmlNewDocText(doc, ent->content);
1551 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001552 } else if (last->type != XML_TEXT_NODE) {
1553 node = xmlNewDocText(doc, ent->content);
1554 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001555 } else
1556 xmlNodeAddContent(last, ent->content);
Daniel Veillardaa6de472008-08-25 14:53:31 +00001557
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001558 } else {
1559 /*
1560 * Create a new REFERENCE_REF node
1561 */
1562 node = xmlNewReference(doc, val);
1563 if (node == NULL) {
1564 if (val != NULL) xmlFree(val);
1565 return(ret);
1566 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001567 else if ((ent != NULL) && (ent->children == NULL)) {
1568 xmlNodePtr temp;
1569
1570 ent->children = xmlStringGetNodeList(doc,
1571 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001572 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001573 temp = ent->children;
1574 while (temp) {
1575 temp->parent = (xmlNodePtr)ent;
1576 temp = temp->next;
1577 }
1578 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001579 if (last == NULL) {
1580 last = ret = node;
1581 } else {
1582 last = xmlAddNextSibling(last, node);
1583 }
1584 }
1585 xmlFree(val);
1586 }
1587 cur++;
1588 q = cur;
1589 }
1590 if (charval != 0) {
1591 xmlChar buf[10];
1592 int len;
1593
1594 len = xmlCopyCharMultiByte(buf, charval);
1595 buf[len] = 0;
1596 node = xmlNewDocText(doc, buf);
1597 if (node != NULL) {
1598 if (last == NULL) {
1599 last = ret = node;
1600 } else {
1601 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001602 }
1603 }
Owen Taylor3473f882001-02-23 17:55:21 +00001604 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001605 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001606 cur++;
1607 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001608 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001609 /*
1610 * Handle the last piece of text.
1611 */
1612 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1613 xmlNodeAddContentLen(last, q, cur - q);
1614 } else {
1615 node = xmlNewDocTextLen(doc, q, cur - q);
1616 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001617 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001618 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001619 } else {
1620 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001621 }
1622 }
1623 }
1624 return(ret);
1625}
1626
1627/**
1628 * xmlNodeListGetString:
1629 * @doc: the document
1630 * @list: a Node list
1631 * @inLine: should we replace entity contents or show their external form
1632 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001633 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001634 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001635 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001636 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001637 */
1638xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001639xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1640{
Owen Taylor3473f882001-02-23 17:55:21 +00001641 xmlNodePtr node = list;
1642 xmlChar *ret = NULL;
1643 xmlEntityPtr ent;
1644
Daniel Veillard7646b182002-04-20 06:41:40 +00001645 if (list == NULL)
1646 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001647
1648 while (node != NULL) {
1649 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001650 (node->type == XML_CDATA_SECTION_NODE)) {
1651 if (inLine) {
1652 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001653 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001654 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001655
Daniel Veillard7646b182002-04-20 06:41:40 +00001656 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1657 if (buffer != NULL) {
1658 ret = xmlStrcat(ret, buffer);
1659 xmlFree(buffer);
1660 }
1661 }
1662 } else if (node->type == XML_ENTITY_REF_NODE) {
1663 if (inLine) {
1664 ent = xmlGetDocEntity(doc, node->name);
1665 if (ent != NULL) {
1666 xmlChar *buffer;
1667
1668 /* an entity content can be any "well balanced chunk",
1669 * i.e. the result of the content [43] production:
1670 * http://www.w3.org/TR/REC-xml#NT-content.
1671 * So it can contain text, CDATA section or nested
1672 * entity reference nodes (among others).
1673 * -> we recursive call xmlNodeListGetString()
1674 * which handles these types */
1675 buffer = xmlNodeListGetString(doc, ent->children, 1);
1676 if (buffer != NULL) {
1677 ret = xmlStrcat(ret, buffer);
1678 xmlFree(buffer);
1679 }
1680 } else {
1681 ret = xmlStrcat(ret, node->content);
1682 }
1683 } else {
1684 xmlChar buf[2];
1685
1686 buf[0] = '&';
1687 buf[1] = 0;
1688 ret = xmlStrncat(ret, buf, 1);
1689 ret = xmlStrcat(ret, node->name);
1690 buf[0] = ';';
1691 buf[1] = 0;
1692 ret = xmlStrncat(ret, buf, 1);
1693 }
1694 }
1695#if 0
1696 else {
1697 xmlGenericError(xmlGenericErrorContext,
1698 "xmlGetNodeListString : invalid node type %d\n",
1699 node->type);
1700 }
1701#endif
1702 node = node->next;
1703 }
1704 return (ret);
1705}
Daniel Veillard652327a2003-09-29 18:02:38 +00001706
1707#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001708/**
1709 * xmlNodeListGetRawString:
1710 * @doc: the document
1711 * @list: a Node list
1712 * @inLine: should we replace entity contents or show their external form
1713 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001714 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001715 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1716 * this function doesn't do any character encoding handling.
1717 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001718 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001719 */
1720xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001721xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1722{
Owen Taylor3473f882001-02-23 17:55:21 +00001723 xmlNodePtr node = list;
1724 xmlChar *ret = NULL;
1725 xmlEntityPtr ent;
1726
Daniel Veillard7646b182002-04-20 06:41:40 +00001727 if (list == NULL)
1728 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001729
1730 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001731 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001732 (node->type == XML_CDATA_SECTION_NODE)) {
1733 if (inLine) {
1734 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001735 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001736 xmlChar *buffer;
1737
1738 buffer = xmlEncodeSpecialChars(doc, node->content);
1739 if (buffer != NULL) {
1740 ret = xmlStrcat(ret, buffer);
1741 xmlFree(buffer);
1742 }
1743 }
1744 } else if (node->type == XML_ENTITY_REF_NODE) {
1745 if (inLine) {
1746 ent = xmlGetDocEntity(doc, node->name);
1747 if (ent != NULL) {
1748 xmlChar *buffer;
1749
1750 /* an entity content can be any "well balanced chunk",
1751 * i.e. the result of the content [43] production:
1752 * http://www.w3.org/TR/REC-xml#NT-content.
1753 * So it can contain text, CDATA section or nested
1754 * entity reference nodes (among others).
1755 * -> we recursive call xmlNodeListGetRawString()
1756 * which handles these types */
1757 buffer =
1758 xmlNodeListGetRawString(doc, ent->children, 1);
1759 if (buffer != NULL) {
1760 ret = xmlStrcat(ret, buffer);
1761 xmlFree(buffer);
1762 }
1763 } else {
1764 ret = xmlStrcat(ret, node->content);
1765 }
1766 } else {
1767 xmlChar buf[2];
1768
1769 buf[0] = '&';
1770 buf[1] = 0;
1771 ret = xmlStrncat(ret, buf, 1);
1772 ret = xmlStrcat(ret, node->name);
1773 buf[0] = ';';
1774 buf[1] = 0;
1775 ret = xmlStrncat(ret, buf, 1);
1776 }
1777 }
Owen Taylor3473f882001-02-23 17:55:21 +00001778#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001779 else {
1780 xmlGenericError(xmlGenericErrorContext,
1781 "xmlGetNodeListString : invalid node type %d\n",
1782 node->type);
1783 }
Owen Taylor3473f882001-02-23 17:55:21 +00001784#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001785 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001786 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001787 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001788}
Daniel Veillard652327a2003-09-29 18:02:38 +00001789#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001790
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001791static xmlAttrPtr
1792xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns,
1793 const xmlChar * name, const xmlChar * value,
1794 int eatname)
1795{
Owen Taylor3473f882001-02-23 17:55:21 +00001796 xmlAttrPtr cur;
1797 xmlDocPtr doc = NULL;
1798
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001799 if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) {
Daniel Veillard8f6c2b12008-04-03 11:17:21 +00001800 if ((eatname == 1) &&
1801 ((node->doc == NULL) ||
Daniel Veillarded939f82008-04-08 08:20:08 +00001802 (!(xmlDictOwns(node->doc->dict, name)))))
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001803 xmlFree((xmlChar *) name);
1804 return (NULL);
1805 }
Owen Taylor3473f882001-02-23 17:55:21 +00001806
1807 /*
1808 * Allocate a new property and fill the fields.
1809 */
1810 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1811 if (cur == NULL) {
Daniel Veillard8f6c2b12008-04-03 11:17:21 +00001812 if ((eatname == 1) &&
Daniel Veillard76d36452009-09-07 11:19:33 +02001813 ((node == NULL) || (node->doc == NULL) ||
Daniel Veillarded939f82008-04-08 08:20:08 +00001814 (!(xmlDictOwns(node->doc->dict, name)))))
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001815 xmlFree((xmlChar *) name);
1816 xmlTreeErrMemory("building attribute");
1817 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001818 }
1819 memset(cur, 0, sizeof(xmlAttr));
1820 cur->type = XML_ATTRIBUTE_NODE;
1821
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001822 cur->parent = node;
Owen Taylor3473f882001-02-23 17:55:21 +00001823 if (node != NULL) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001824 doc = node->doc;
1825 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001826 }
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001827 cur->ns = ns;
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001828
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001829 if (eatname == 0) {
1830 if ((doc != NULL) && (doc->dict != NULL))
1831 cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
1832 else
1833 cur->name = xmlStrdup(name);
1834 } else
1835 cur->name = name;
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001836
Owen Taylor3473f882001-02-23 17:55:21 +00001837 if (value != NULL) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001838 xmlNodePtr tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00001839
Daniel Veillard6f8611f2008-02-15 08:33:21 +00001840 if(!xmlCheckUTF8(value)) {
1841 xmlTreeErr(XML_TREE_NOT_UTF8, (xmlNodePtr) doc,
1842 NULL);
1843 if (doc != NULL)
1844 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
1845 }
1846 cur->children = xmlNewDocText(doc, value);
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001847 cur->last = NULL;
1848 tmp = cur->children;
1849 while (tmp != NULL) {
1850 tmp->parent = (xmlNodePtr) cur;
1851 if (tmp->next == NULL)
1852 cur->last = tmp;
1853 tmp = tmp->next;
1854 }
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001855 }
Owen Taylor3473f882001-02-23 17:55:21 +00001856
1857 /*
1858 * Add it at the end to preserve parsing order ...
1859 */
1860 if (node != NULL) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001861 if (node->properties == NULL) {
1862 node->properties = cur;
1863 } else {
1864 xmlAttrPtr prev = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00001865
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001866 while (prev->next != NULL)
1867 prev = prev->next;
1868 prev->next = cur;
1869 cur->prev = prev;
1870 }
Owen Taylor3473f882001-02-23 17:55:21 +00001871 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001872
Daniel Veillard76d36452009-09-07 11:19:33 +02001873 if ((value != NULL) && (node != NULL) &&
1874 (xmlIsID(node->doc, node, cur) == 1))
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001875 xmlAddID(NULL, node->doc, value, cur);
1876
Daniel Veillarda880b122003-04-21 21:36:41 +00001877 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001878 xmlRegisterNodeDefaultValue((xmlNodePtr) cur);
1879 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001880}
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001881
1882#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
1883 defined(LIBXML_SCHEMAS_ENABLED)
1884/**
1885 * xmlNewProp:
1886 * @node: the holding node
1887 * @name: the name of the attribute
1888 * @value: the value of the attribute
1889 *
1890 * Create a new property carried by a node.
1891 * Returns a pointer to the attribute
1892 */
1893xmlAttrPtr
1894xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1895
1896 if (name == NULL) {
1897#ifdef DEBUG_TREE
1898 xmlGenericError(xmlGenericErrorContext,
1899 "xmlNewProp : name == NULL\n");
1900#endif
1901 return(NULL);
1902 }
1903
1904 return xmlNewPropInternal(node, NULL, name, value, 0);
1905}
Daniel Veillard652327a2003-09-29 18:02:38 +00001906#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001907
1908/**
1909 * xmlNewNsProp:
1910 * @node: the holding node
1911 * @ns: the namespace
1912 * @name: the name of the attribute
1913 * @value: the value of the attribute
1914 *
1915 * Create a new property tagged with a namespace and carried by a node.
1916 * Returns a pointer to the attribute
1917 */
1918xmlAttrPtr
1919xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1920 const xmlChar *value) {
Owen Taylor3473f882001-02-23 17:55:21 +00001921
1922 if (name == NULL) {
1923#ifdef DEBUG_TREE
1924 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001925 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001926#endif
1927 return(NULL);
1928 }
1929
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001930 return xmlNewPropInternal(node, ns, name, value, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001931}
1932
1933/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001934 * xmlNewNsPropEatName:
1935 * @node: the holding node
1936 * @ns: the namespace
1937 * @name: the name of the attribute
1938 * @value: the value of the attribute
1939 *
1940 * Create a new property tagged with a namespace and carried by a node.
1941 * Returns a pointer to the attribute
1942 */
1943xmlAttrPtr
1944xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1945 const xmlChar *value) {
Daniel Veillard46de64e2002-05-29 08:21:33 +00001946
1947 if (name == NULL) {
1948#ifdef DEBUG_TREE
1949 xmlGenericError(xmlGenericErrorContext,
1950 "xmlNewNsPropEatName : name == NULL\n");
1951#endif
1952 return(NULL);
1953 }
1954
Daniel Veillard8f6c2b12008-04-03 11:17:21 +00001955 return xmlNewPropInternal(node, ns, name, value, 1);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001956}
1957
1958/**
Owen Taylor3473f882001-02-23 17:55:21 +00001959 * xmlNewDocProp:
1960 * @doc: the document
1961 * @name: the name of the attribute
1962 * @value: the value of the attribute
1963 *
1964 * Create a new property carried by a document.
1965 * Returns a pointer to the attribute
1966 */
1967xmlAttrPtr
1968xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1969 xmlAttrPtr cur;
1970
1971 if (name == NULL) {
1972#ifdef DEBUG_TREE
1973 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001974 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001975#endif
1976 return(NULL);
1977 }
1978
1979 /*
1980 * Allocate a new property and fill the fields.
1981 */
1982 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1983 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001984 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001985 return(NULL);
1986 }
1987 memset(cur, 0, sizeof(xmlAttr));
1988 cur->type = XML_ATTRIBUTE_NODE;
1989
Daniel Veillard03a53c32004-10-26 16:06:51 +00001990 if ((doc != NULL) && (doc->dict != NULL))
1991 cur->name = xmlDictLookup(doc->dict, name, -1);
1992 else
1993 cur->name = xmlStrdup(name);
Daniel Veillardaa6de472008-08-25 14:53:31 +00001994 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001995 if (value != NULL) {
1996 xmlNodePtr tmp;
1997
1998 cur->children = xmlStringGetNodeList(doc, value);
1999 cur->last = NULL;
2000
2001 tmp = cur->children;
2002 while (tmp != NULL) {
2003 tmp->parent = (xmlNodePtr) cur;
2004 if (tmp->next == NULL)
2005 cur->last = tmp;
2006 tmp = tmp->next;
2007 }
2008 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002009
Daniel Veillarda880b122003-04-21 21:36:41 +00002010 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002011 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002012 return(cur);
2013}
2014
2015/**
2016 * xmlFreePropList:
2017 * @cur: the first property in the list
2018 *
2019 * Free a property and all its siblings, all the children are freed too.
2020 */
2021void
2022xmlFreePropList(xmlAttrPtr cur) {
2023 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002024 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002025 while (cur != NULL) {
2026 next = cur->next;
2027 xmlFreeProp(cur);
2028 cur = next;
2029 }
2030}
2031
2032/**
2033 * xmlFreeProp:
2034 * @cur: an attribute
2035 *
2036 * Free one attribute, all the content is freed too
2037 */
2038void
2039xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002040 xmlDictPtr dict = NULL;
2041 if (cur == NULL) return;
2042
2043 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002044
Daniel Veillarda880b122003-04-21 21:36:41 +00002045 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002046 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
2047
Owen Taylor3473f882001-02-23 17:55:21 +00002048 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillardda6f4af2005-06-20 17:17:54 +00002049 if ((cur->doc != NULL) && (cur->atype == XML_ATTRIBUTE_ID)) {
2050 xmlRemoveID(cur->doc, cur);
Daniel Veillard76d66f42001-05-16 21:05:17 +00002051 }
Owen Taylor3473f882001-02-23 17:55:21 +00002052 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002053 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002054 xmlFree(cur);
2055}
2056
2057/**
2058 * xmlRemoveProp:
2059 * @cur: an attribute
2060 *
2061 * Unlink and free one attribute, all the content is freed too
2062 * Note this doesn't work for namespace definition attributes
2063 *
2064 * Returns 0 if success and -1 in case of error.
2065 */
2066int
2067xmlRemoveProp(xmlAttrPtr cur) {
2068 xmlAttrPtr tmp;
2069 if (cur == NULL) {
2070#ifdef DEBUG_TREE
2071 xmlGenericError(xmlGenericErrorContext,
2072 "xmlRemoveProp : cur == NULL\n");
2073#endif
2074 return(-1);
2075 }
2076 if (cur->parent == NULL) {
2077#ifdef DEBUG_TREE
2078 xmlGenericError(xmlGenericErrorContext,
2079 "xmlRemoveProp : cur->parent == NULL\n");
2080#endif
2081 return(-1);
2082 }
2083 tmp = cur->parent->properties;
2084 if (tmp == cur) {
2085 cur->parent->properties = cur->next;
Rob Richards19dc9612005-10-28 16:15:16 +00002086 if (cur->next != NULL)
2087 cur->next->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002088 xmlFreeProp(cur);
2089 return(0);
2090 }
2091 while (tmp != NULL) {
2092 if (tmp->next == cur) {
2093 tmp->next = cur->next;
2094 if (tmp->next != NULL)
2095 tmp->next->prev = tmp;
2096 xmlFreeProp(cur);
2097 return(0);
2098 }
2099 tmp = tmp->next;
2100 }
2101#ifdef DEBUG_TREE
2102 xmlGenericError(xmlGenericErrorContext,
2103 "xmlRemoveProp : attribute not owned by its node\n");
2104#endif
2105 return(-1);
2106}
2107
2108/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002109 * xmlNewDocPI:
2110 * @doc: the target document
Owen Taylor3473f882001-02-23 17:55:21 +00002111 * @name: the processing instruction name
2112 * @content: the PI content
2113 *
2114 * Creation of a processing instruction element.
2115 * Returns a pointer to the new node object.
2116 */
2117xmlNodePtr
Daniel Veillard03a53c32004-10-26 16:06:51 +00002118xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
Owen Taylor3473f882001-02-23 17:55:21 +00002119 xmlNodePtr cur;
2120
2121 if (name == NULL) {
2122#ifdef DEBUG_TREE
2123 xmlGenericError(xmlGenericErrorContext,
2124 "xmlNewPI : name == NULL\n");
2125#endif
2126 return(NULL);
2127 }
2128
2129 /*
2130 * Allocate a new node and fill the fields.
2131 */
2132 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2133 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002134 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002135 return(NULL);
2136 }
2137 memset(cur, 0, sizeof(xmlNode));
2138 cur->type = XML_PI_NODE;
2139
Daniel Veillard03a53c32004-10-26 16:06:51 +00002140 if ((doc != NULL) && (doc->dict != NULL))
2141 cur->name = xmlDictLookup(doc->dict, name, -1);
2142 else
2143 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00002144 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002145 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002146 }
Daniel Veillarda03e3652004-11-02 18:45:30 +00002147 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002148
Daniel Veillarda880b122003-04-21 21:36:41 +00002149 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002150 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002151 return(cur);
2152}
2153
2154/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002155 * xmlNewPI:
2156 * @name: the processing instruction name
2157 * @content: the PI content
2158 *
2159 * Creation of a processing instruction element.
2160 * Use xmlDocNewPI preferably to get string interning
2161 *
2162 * Returns a pointer to the new node object.
2163 */
2164xmlNodePtr
2165xmlNewPI(const xmlChar *name, const xmlChar *content) {
2166 return(xmlNewDocPI(NULL, name, content));
2167}
2168
2169/**
Owen Taylor3473f882001-02-23 17:55:21 +00002170 * xmlNewNode:
2171 * @ns: namespace if any
2172 * @name: the node name
2173 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002174 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002175 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002176 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2177 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002178 */
2179xmlNodePtr
2180xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2181 xmlNodePtr cur;
2182
2183 if (name == NULL) {
2184#ifdef DEBUG_TREE
2185 xmlGenericError(xmlGenericErrorContext,
2186 "xmlNewNode : name == NULL\n");
2187#endif
2188 return(NULL);
2189 }
2190
2191 /*
2192 * Allocate a new node and fill the fields.
2193 */
2194 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2195 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002196 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002197 return(NULL);
2198 }
2199 memset(cur, 0, sizeof(xmlNode));
2200 cur->type = XML_ELEMENT_NODE;
Daniel Veillardaa6de472008-08-25 14:53:31 +00002201
Owen Taylor3473f882001-02-23 17:55:21 +00002202 cur->name = xmlStrdup(name);
2203 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002204
Daniel Veillarda880b122003-04-21 21:36:41 +00002205 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002206 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002207 return(cur);
2208}
2209
2210/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002211 * xmlNewNodeEatName:
2212 * @ns: namespace if any
2213 * @name: the node name
2214 *
2215 * Creation of a new node element. @ns is optional (NULL).
2216 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002217 * Returns a pointer to the new node object, with pointer @name as
2218 * new node's name. Use xmlNewNode() if a copy of @name string is
2219 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002220 */
2221xmlNodePtr
2222xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2223 xmlNodePtr cur;
2224
2225 if (name == NULL) {
2226#ifdef DEBUG_TREE
2227 xmlGenericError(xmlGenericErrorContext,
2228 "xmlNewNode : name == NULL\n");
2229#endif
2230 return(NULL);
2231 }
2232
2233 /*
2234 * Allocate a new node and fill the fields.
2235 */
2236 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2237 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002238 xmlTreeErrMemory("building node");
Daniel Veillard8f6c2b12008-04-03 11:17:21 +00002239 /* we can't check here that name comes from the doc dictionnary */
Daniel Veillard46de64e2002-05-29 08:21:33 +00002240 return(NULL);
2241 }
2242 memset(cur, 0, sizeof(xmlNode));
2243 cur->type = XML_ELEMENT_NODE;
Daniel Veillardaa6de472008-08-25 14:53:31 +00002244
Daniel Veillard46de64e2002-05-29 08:21:33 +00002245 cur->name = name;
2246 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002247
Daniel Veillarda880b122003-04-21 21:36:41 +00002248 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002249 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002250 return(cur);
2251}
2252
2253/**
Owen Taylor3473f882001-02-23 17:55:21 +00002254 * xmlNewDocNode:
2255 * @doc: the document
2256 * @ns: namespace if any
2257 * @name: the node name
2258 * @content: the XML 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 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2263 * references, but XML special chars need to be escaped first by using
2264 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2265 * need entities support.
2266 *
2267 * Returns a pointer to the new node object.
2268 */
2269xmlNodePtr
2270xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2271 const xmlChar *name, const xmlChar *content) {
2272 xmlNodePtr cur;
2273
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002274 if ((doc != NULL) && (doc->dict != NULL))
Daniel Veillard03a53c32004-10-26 16:06:51 +00002275 cur = xmlNewNodeEatName(ns, (xmlChar *)
2276 xmlDictLookup(doc->dict, name, -1));
2277 else
2278 cur = xmlNewNode(ns, name);
Owen Taylor3473f882001-02-23 17:55:21 +00002279 if (cur != NULL) {
2280 cur->doc = doc;
2281 if (content != NULL) {
2282 cur->children = xmlStringGetNodeList(doc, content);
2283 UPDATE_LAST_CHILD_AND_PARENT(cur)
2284 }
2285 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002286
Owen Taylor3473f882001-02-23 17:55:21 +00002287 return(cur);
2288}
2289
Daniel Veillard46de64e2002-05-29 08:21:33 +00002290/**
2291 * xmlNewDocNodeEatName:
2292 * @doc: the document
2293 * @ns: namespace if any
2294 * @name: the node name
2295 * @content: the XML text content if any
2296 *
2297 * Creation of a new node element within a document. @ns and @content
2298 * are optional (NULL).
2299 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2300 * references, but XML special chars need to be escaped first by using
2301 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2302 * need entities support.
2303 *
2304 * Returns a pointer to the new node object.
2305 */
2306xmlNodePtr
2307xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2308 xmlChar *name, const xmlChar *content) {
2309 xmlNodePtr cur;
2310
2311 cur = xmlNewNodeEatName(ns, name);
2312 if (cur != NULL) {
2313 cur->doc = doc;
2314 if (content != NULL) {
2315 cur->children = xmlStringGetNodeList(doc, content);
2316 UPDATE_LAST_CHILD_AND_PARENT(cur)
2317 }
Daniel Veillard8f6c2b12008-04-03 11:17:21 +00002318 } else {
2319 /* if name don't come from the doc dictionnary free it here */
2320 if ((name != NULL) && (doc != NULL) &&
2321 (!(xmlDictOwns(doc->dict, name))))
2322 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002323 }
2324 return(cur);
2325}
2326
Daniel Veillard652327a2003-09-29 18:02:38 +00002327#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002328/**
2329 * xmlNewDocRawNode:
2330 * @doc: the document
2331 * @ns: namespace if any
2332 * @name: the node name
2333 * @content: the text content if any
2334 *
2335 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002336 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002337 *
2338 * Returns a pointer to the new node object.
2339 */
2340xmlNodePtr
2341xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2342 const xmlChar *name, const xmlChar *content) {
2343 xmlNodePtr cur;
2344
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002345 cur = xmlNewDocNode(doc, ns, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002346 if (cur != NULL) {
2347 cur->doc = doc;
2348 if (content != NULL) {
2349 cur->children = xmlNewDocText(doc, content);
2350 UPDATE_LAST_CHILD_AND_PARENT(cur)
2351 }
2352 }
2353 return(cur);
2354}
2355
2356/**
2357 * xmlNewDocFragment:
2358 * @doc: the document owning the fragment
2359 *
2360 * Creation of a new Fragment node.
2361 * Returns a pointer to the new node object.
2362 */
2363xmlNodePtr
2364xmlNewDocFragment(xmlDocPtr doc) {
2365 xmlNodePtr cur;
2366
2367 /*
2368 * Allocate a new DocumentFragment node and fill the fields.
2369 */
2370 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2371 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002372 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002373 return(NULL);
2374 }
2375 memset(cur, 0, sizeof(xmlNode));
2376 cur->type = XML_DOCUMENT_FRAG_NODE;
2377
2378 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002379
Daniel Veillarda880b122003-04-21 21:36:41 +00002380 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002381 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002382 return(cur);
2383}
Daniel Veillard652327a2003-09-29 18:02:38 +00002384#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002385
2386/**
2387 * xmlNewText:
2388 * @content: the text content
2389 *
2390 * Creation of a new text node.
2391 * Returns a pointer to the new node object.
2392 */
2393xmlNodePtr
2394xmlNewText(const xmlChar *content) {
2395 xmlNodePtr cur;
2396
2397 /*
2398 * Allocate a new node and fill the fields.
2399 */
2400 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2401 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002402 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002403 return(NULL);
2404 }
2405 memset(cur, 0, sizeof(xmlNode));
2406 cur->type = XML_TEXT_NODE;
2407
2408 cur->name = xmlStringText;
2409 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002410 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002411 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002412
Daniel Veillarda880b122003-04-21 21:36:41 +00002413 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002414 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002415 return(cur);
2416}
2417
Daniel Veillard652327a2003-09-29 18:02:38 +00002418#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002419/**
2420 * xmlNewTextChild:
2421 * @parent: the parent node
2422 * @ns: a namespace if any
2423 * @name: the name of the child
2424 * @content: the text content of the child if any.
2425 *
2426 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002427 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2428 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002429 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002430 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2431 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
Daniel Veillardaa6de472008-08-25 14:53:31 +00002432 * reserved XML chars that might appear in @content, such as the ampersand,
2433 * greater-than or less-than signs, are automatically replaced by their XML
2434 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002435 *
2436 * Returns a pointer to the new node object.
2437 */
2438xmlNodePtr
2439xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2440 const xmlChar *name, const xmlChar *content) {
2441 xmlNodePtr cur, prev;
2442
2443 if (parent == NULL) {
2444#ifdef DEBUG_TREE
2445 xmlGenericError(xmlGenericErrorContext,
2446 "xmlNewTextChild : parent == NULL\n");
2447#endif
2448 return(NULL);
2449 }
2450
2451 if (name == NULL) {
2452#ifdef DEBUG_TREE
2453 xmlGenericError(xmlGenericErrorContext,
2454 "xmlNewTextChild : name == NULL\n");
2455#endif
2456 return(NULL);
2457 }
2458
2459 /*
2460 * Allocate a new node
2461 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002462 if (parent->type == XML_ELEMENT_NODE) {
2463 if (ns == NULL)
2464 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2465 else
2466 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2467 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2468 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2469 if (ns == NULL)
2470 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2471 else
2472 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2473 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2474 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2475 } else {
2476 return(NULL);
2477 }
Owen Taylor3473f882001-02-23 17:55:21 +00002478 if (cur == NULL) return(NULL);
2479
2480 /*
2481 * add the new element at the end of the children list.
2482 */
2483 cur->type = XML_ELEMENT_NODE;
2484 cur->parent = parent;
2485 cur->doc = parent->doc;
2486 if (parent->children == NULL) {
2487 parent->children = cur;
2488 parent->last = cur;
2489 } else {
2490 prev = parent->last;
2491 prev->next = cur;
2492 cur->prev = prev;
2493 parent->last = cur;
2494 }
2495
2496 return(cur);
2497}
Daniel Veillard652327a2003-09-29 18:02:38 +00002498#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002499
2500/**
2501 * xmlNewCharRef:
2502 * @doc: the document
2503 * @name: the char ref string, starting with # or "&# ... ;"
2504 *
2505 * Creation of a new character reference node.
2506 * Returns a pointer to the new node object.
2507 */
2508xmlNodePtr
2509xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2510 xmlNodePtr cur;
2511
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002512 if (name == NULL)
2513 return(NULL);
2514
Owen Taylor3473f882001-02-23 17:55:21 +00002515 /*
2516 * Allocate a new node and fill the fields.
2517 */
2518 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2519 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002520 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002521 return(NULL);
2522 }
2523 memset(cur, 0, sizeof(xmlNode));
2524 cur->type = XML_ENTITY_REF_NODE;
2525
2526 cur->doc = doc;
2527 if (name[0] == '&') {
2528 int len;
2529 name++;
2530 len = xmlStrlen(name);
2531 if (name[len - 1] == ';')
2532 cur->name = xmlStrndup(name, len - 1);
2533 else
2534 cur->name = xmlStrndup(name, len);
2535 } else
2536 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002537
Daniel Veillarda880b122003-04-21 21:36:41 +00002538 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002539 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002540 return(cur);
2541}
2542
2543/**
2544 * xmlNewReference:
2545 * @doc: the document
2546 * @name: the reference name, or the reference string with & and ;
2547 *
2548 * Creation of a new reference node.
2549 * Returns a pointer to the new node object.
2550 */
2551xmlNodePtr
2552xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2553 xmlNodePtr cur;
2554 xmlEntityPtr ent;
2555
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002556 if (name == NULL)
2557 return(NULL);
2558
Owen Taylor3473f882001-02-23 17:55:21 +00002559 /*
2560 * Allocate a new node and fill the fields.
2561 */
2562 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2563 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002564 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002565 return(NULL);
2566 }
2567 memset(cur, 0, sizeof(xmlNode));
2568 cur->type = XML_ENTITY_REF_NODE;
2569
2570 cur->doc = doc;
2571 if (name[0] == '&') {
2572 int len;
2573 name++;
2574 len = xmlStrlen(name);
2575 if (name[len - 1] == ';')
2576 cur->name = xmlStrndup(name, len - 1);
2577 else
2578 cur->name = xmlStrndup(name, len);
2579 } else
2580 cur->name = xmlStrdup(name);
2581
2582 ent = xmlGetDocEntity(doc, cur->name);
2583 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002584 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002585 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002586 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002587 * updated. Not sure if this is 100% correct.
2588 * -George
2589 */
2590 cur->children = (xmlNodePtr) ent;
2591 cur->last = (xmlNodePtr) ent;
2592 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002593
Daniel Veillarda880b122003-04-21 21:36:41 +00002594 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002595 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002596 return(cur);
2597}
2598
2599/**
2600 * xmlNewDocText:
2601 * @doc: the document
2602 * @content: the text content
2603 *
2604 * Creation of a new text node within a document.
2605 * Returns a pointer to the new node object.
2606 */
2607xmlNodePtr
2608xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2609 xmlNodePtr cur;
2610
2611 cur = xmlNewText(content);
2612 if (cur != NULL) cur->doc = doc;
2613 return(cur);
2614}
2615
2616/**
2617 * xmlNewTextLen:
2618 * @content: the text content
2619 * @len: the text len.
2620 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002621 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002622 * Returns a pointer to the new node object.
2623 */
2624xmlNodePtr
2625xmlNewTextLen(const xmlChar *content, int len) {
2626 xmlNodePtr cur;
2627
2628 /*
2629 * Allocate a new node and fill the fields.
2630 */
2631 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2632 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002633 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002634 return(NULL);
2635 }
2636 memset(cur, 0, sizeof(xmlNode));
2637 cur->type = XML_TEXT_NODE;
2638
2639 cur->name = xmlStringText;
2640 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002641 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002642 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002643
Daniel Veillarda880b122003-04-21 21:36:41 +00002644 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002645 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002646 return(cur);
2647}
2648
2649/**
2650 * xmlNewDocTextLen:
2651 * @doc: the document
2652 * @content: the text content
2653 * @len: the text len.
2654 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002655 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002656 * text node pertain to a given document.
2657 * Returns a pointer to the new node object.
2658 */
2659xmlNodePtr
2660xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2661 xmlNodePtr cur;
2662
2663 cur = xmlNewTextLen(content, len);
2664 if (cur != NULL) cur->doc = doc;
2665 return(cur);
2666}
2667
2668/**
2669 * xmlNewComment:
2670 * @content: the comment content
2671 *
2672 * Creation of a new node containing a comment.
2673 * Returns a pointer to the new node object.
2674 */
2675xmlNodePtr
2676xmlNewComment(const xmlChar *content) {
2677 xmlNodePtr cur;
2678
2679 /*
2680 * Allocate a new node and fill the fields.
2681 */
2682 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2683 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002684 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002685 return(NULL);
2686 }
2687 memset(cur, 0, sizeof(xmlNode));
2688 cur->type = XML_COMMENT_NODE;
2689
2690 cur->name = xmlStringComment;
2691 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002692 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002693 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002694
Daniel Veillarda880b122003-04-21 21:36:41 +00002695 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002696 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002697 return(cur);
2698}
2699
2700/**
2701 * xmlNewCDataBlock:
2702 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002703 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002704 * @len: the length of the block
2705 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002706 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002707 * Returns a pointer to the new node object.
2708 */
2709xmlNodePtr
2710xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2711 xmlNodePtr cur;
2712
2713 /*
2714 * Allocate a new node and fill the fields.
2715 */
2716 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2717 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002718 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002719 return(NULL);
2720 }
2721 memset(cur, 0, sizeof(xmlNode));
2722 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002723 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002724
2725 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002726 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002727 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002728
Daniel Veillarda880b122003-04-21 21:36:41 +00002729 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002730 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002731 return(cur);
2732}
2733
2734/**
2735 * xmlNewDocComment:
2736 * @doc: the document
2737 * @content: the comment content
2738 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002739 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002740 * Returns a pointer to the new node object.
2741 */
2742xmlNodePtr
2743xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2744 xmlNodePtr cur;
2745
2746 cur = xmlNewComment(content);
2747 if (cur != NULL) cur->doc = doc;
2748 return(cur);
2749}
2750
2751/**
2752 * xmlSetTreeDoc:
2753 * @tree: the top element
2754 * @doc: the document
2755 *
2756 * update all nodes under the tree to point to the right document
2757 */
2758void
2759xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002760 xmlAttrPtr prop;
2761
Owen Taylor3473f882001-02-23 17:55:21 +00002762 if (tree == NULL)
2763 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002764 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002765 if(tree->type == XML_ELEMENT_NODE) {
2766 prop = tree->properties;
2767 while (prop != NULL) {
2768 prop->doc = doc;
2769 xmlSetListDoc(prop->children, doc);
2770 prop = prop->next;
2771 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002772 }
Owen Taylor3473f882001-02-23 17:55:21 +00002773 if (tree->children != NULL)
2774 xmlSetListDoc(tree->children, doc);
2775 tree->doc = doc;
2776 }
2777}
2778
2779/**
2780 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002781 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002782 * @doc: the document
2783 *
2784 * update all nodes in the list to point to the right document
2785 */
2786void
2787xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2788 xmlNodePtr cur;
2789
2790 if (list == NULL)
2791 return;
2792 cur = list;
2793 while (cur != NULL) {
2794 if (cur->doc != doc)
2795 xmlSetTreeDoc(cur, doc);
2796 cur = cur->next;
2797 }
2798}
2799
Daniel Veillard2156d432004-03-04 15:59:36 +00002800#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002801/**
2802 * xmlNewChild:
2803 * @parent: the parent node
2804 * @ns: a namespace if any
2805 * @name: the name of the child
2806 * @content: the XML content of the child if any.
2807 *
2808 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002809 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2810 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002811 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002812 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2813 * references. XML special chars must be escaped first by using
2814 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002815 *
2816 * Returns a pointer to the new node object.
2817 */
2818xmlNodePtr
2819xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2820 const xmlChar *name, const xmlChar *content) {
2821 xmlNodePtr cur, prev;
2822
2823 if (parent == NULL) {
2824#ifdef DEBUG_TREE
2825 xmlGenericError(xmlGenericErrorContext,
2826 "xmlNewChild : parent == NULL\n");
2827#endif
2828 return(NULL);
2829 }
2830
2831 if (name == NULL) {
2832#ifdef DEBUG_TREE
2833 xmlGenericError(xmlGenericErrorContext,
2834 "xmlNewChild : name == NULL\n");
2835#endif
2836 return(NULL);
2837 }
2838
2839 /*
2840 * Allocate a new node
2841 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002842 if (parent->type == XML_ELEMENT_NODE) {
2843 if (ns == NULL)
2844 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2845 else
2846 cur = xmlNewDocNode(parent->doc, ns, name, content);
2847 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2848 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2849 if (ns == NULL)
2850 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2851 else
2852 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002853 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2854 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002855 } else {
2856 return(NULL);
2857 }
Owen Taylor3473f882001-02-23 17:55:21 +00002858 if (cur == NULL) return(NULL);
2859
2860 /*
2861 * add the new element at the end of the children list.
2862 */
2863 cur->type = XML_ELEMENT_NODE;
2864 cur->parent = parent;
2865 cur->doc = parent->doc;
2866 if (parent->children == NULL) {
2867 parent->children = cur;
2868 parent->last = cur;
2869 } else {
2870 prev = parent->last;
2871 prev->next = cur;
2872 cur->prev = prev;
2873 parent->last = cur;
2874 }
2875
2876 return(cur);
2877}
Daniel Veillard652327a2003-09-29 18:02:38 +00002878#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002879
2880/**
Rob Richards65815122006-02-25 17:13:33 +00002881 * xmlAddPropSibling:
Daniel Veillardaa6de472008-08-25 14:53:31 +00002882 * @prev: the attribute to which @prop is added after
Rob Richards65815122006-02-25 17:13:33 +00002883 * @cur: the base attribute passed to calling function
2884 * @prop: the new attribute
2885 *
2886 * Add a new attribute after @prev using @cur as base attribute.
2887 * When inserting before @cur, @prev is passed as @cur->prev.
2888 * When inserting after @cur, @prev is passed as @cur.
Daniel Veillardaa6de472008-08-25 14:53:31 +00002889 * If an existing attribute is found it is detroyed prior to adding @prop.
Rob Richards65815122006-02-25 17:13:33 +00002890 *
2891 * Returns the attribute being inserted or NULL in case of error.
2892 */
2893static xmlNodePtr
2894xmlAddPropSibling(xmlNodePtr prev, xmlNodePtr cur, xmlNodePtr prop) {
2895 xmlAttrPtr attr;
2896
2897 if (cur->type != XML_ATTRIBUTE_NODE)
2898 return(NULL);
2899
2900 /* check if an attribute with the same name exists */
2901 if (prop->ns == NULL)
2902 attr = xmlHasNsProp(cur->parent, prop->name, NULL);
2903 else
2904 attr = xmlHasNsProp(cur->parent, prop->name, prop->ns->href);
2905
2906 if (prop->doc != cur->doc) {
2907 xmlSetTreeDoc(prop, cur->doc);
2908 }
2909 prop->parent = cur->parent;
2910 prop->prev = prev;
2911 if (prev != NULL) {
2912 prop->next = prev->next;
2913 prev->next = prop;
2914 if (prop->next)
2915 prop->next->prev = prop;
2916 } else {
2917 prop->next = cur;
2918 cur->prev = prop;
2919 }
2920 if (prop->prev == NULL && prop->parent != NULL)
2921 prop->parent->properties = (xmlAttrPtr) prop;
2922 if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) {
2923 /* different instance, destroy it (attributes must be unique) */
2924 xmlRemoveProp((xmlAttrPtr) attr);
2925 }
2926 return prop;
2927}
2928
2929/**
Owen Taylor3473f882001-02-23 17:55:21 +00002930 * xmlAddNextSibling:
2931 * @cur: the child node
2932 * @elem: the new node
2933 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002934 * Add a new node @elem as the next sibling of @cur
2935 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002936 * first unlinked from its existing context.
2937 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002938 * If the new node is ATTRIBUTE, it is added into properties instead of children.
Daniel Veillardaa6de472008-08-25 14:53:31 +00002939 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002940 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002941 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002942 */
2943xmlNodePtr
2944xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2945 if (cur == NULL) {
2946#ifdef DEBUG_TREE
2947 xmlGenericError(xmlGenericErrorContext,
2948 "xmlAddNextSibling : cur == NULL\n");
2949#endif
2950 return(NULL);
2951 }
2952 if (elem == NULL) {
2953#ifdef DEBUG_TREE
2954 xmlGenericError(xmlGenericErrorContext,
2955 "xmlAddNextSibling : elem == NULL\n");
2956#endif
2957 return(NULL);
2958 }
2959
Rob Richards19dc9612005-10-28 16:15:16 +00002960 if (cur == elem) {
2961#ifdef DEBUG_TREE
2962 xmlGenericError(xmlGenericErrorContext,
2963 "xmlAddNextSibling : cur == elem\n");
2964#endif
2965 return(NULL);
2966 }
2967
Owen Taylor3473f882001-02-23 17:55:21 +00002968 xmlUnlinkNode(elem);
2969
2970 if (elem->type == XML_TEXT_NODE) {
2971 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002972 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002973 xmlFreeNode(elem);
2974 return(cur);
2975 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002976 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2977 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002978 xmlChar *tmp;
2979
2980 tmp = xmlStrdup(elem->content);
2981 tmp = xmlStrcat(tmp, cur->next->content);
2982 xmlNodeSetContent(cur->next, tmp);
2983 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002984 xmlFreeNode(elem);
2985 return(cur->next);
2986 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002987 } else if (elem->type == XML_ATTRIBUTE_NODE) {
Rob Richards65815122006-02-25 17:13:33 +00002988 return xmlAddPropSibling(cur, cur, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00002989 }
2990
2991 if (elem->doc != cur->doc) {
2992 xmlSetTreeDoc(elem, cur->doc);
2993 }
2994 elem->parent = cur->parent;
2995 elem->prev = cur;
2996 elem->next = cur->next;
2997 cur->next = elem;
2998 if (elem->next != NULL)
2999 elem->next->prev = elem;
Rob Richards65815122006-02-25 17:13:33 +00003000 if ((elem->parent != NULL) && (elem->parent->last == cur))
Owen Taylor3473f882001-02-23 17:55:21 +00003001 elem->parent->last = elem;
3002 return(elem);
3003}
3004
William M. Brack21e4ef22005-01-02 09:53:13 +00003005#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
3006 defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003007/**
3008 * xmlAddPrevSibling:
3009 * @cur: the child node
3010 * @elem: the new node
3011 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003012 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00003013 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003014 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003015 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003016 * If the new node is ATTRIBUTE, it is added into properties instead of children.
Daniel Veillardaa6de472008-08-25 14:53:31 +00003017 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00003018 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003019 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003020 */
3021xmlNodePtr
3022xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
3023 if (cur == NULL) {
3024#ifdef DEBUG_TREE
3025 xmlGenericError(xmlGenericErrorContext,
3026 "xmlAddPrevSibling : cur == NULL\n");
3027#endif
3028 return(NULL);
3029 }
3030 if (elem == NULL) {
3031#ifdef DEBUG_TREE
3032 xmlGenericError(xmlGenericErrorContext,
3033 "xmlAddPrevSibling : elem == NULL\n");
3034#endif
3035 return(NULL);
3036 }
3037
Rob Richards19dc9612005-10-28 16:15:16 +00003038 if (cur == elem) {
3039#ifdef DEBUG_TREE
3040 xmlGenericError(xmlGenericErrorContext,
3041 "xmlAddPrevSibling : cur == elem\n");
3042#endif
3043 return(NULL);
3044 }
3045
Owen Taylor3473f882001-02-23 17:55:21 +00003046 xmlUnlinkNode(elem);
3047
3048 if (elem->type == XML_TEXT_NODE) {
3049 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00003050 xmlChar *tmp;
3051
3052 tmp = xmlStrdup(elem->content);
3053 tmp = xmlStrcat(tmp, cur->content);
3054 xmlNodeSetContent(cur, tmp);
3055 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00003056 xmlFreeNode(elem);
3057 return(cur);
3058 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00003059 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
3060 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003061 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003062 xmlFreeNode(elem);
3063 return(cur->prev);
3064 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003065 } else if (elem->type == XML_ATTRIBUTE_NODE) {
Rob Richards65815122006-02-25 17:13:33 +00003066 return xmlAddPropSibling(cur->prev, cur, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00003067 }
3068
3069 if (elem->doc != cur->doc) {
3070 xmlSetTreeDoc(elem, cur->doc);
3071 }
3072 elem->parent = cur->parent;
3073 elem->next = cur;
3074 elem->prev = cur->prev;
3075 cur->prev = elem;
3076 if (elem->prev != NULL)
3077 elem->prev->next = elem;
Rob Richards65815122006-02-25 17:13:33 +00003078 if ((elem->parent != NULL) && (elem->parent->children == cur)) {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003079 elem->parent->children = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003080 }
Owen Taylor3473f882001-02-23 17:55:21 +00003081 return(elem);
3082}
Daniel Veillard652327a2003-09-29 18:02:38 +00003083#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003084
3085/**
3086 * xmlAddSibling:
3087 * @cur: the child node
3088 * @elem: the new node
3089 *
3090 * Add a new element @elem to the list of siblings of @cur
3091 * merging adjacent TEXT nodes (@elem may be freed)
3092 * If the new element was already inserted in a document it is
3093 * first unlinked from its existing context.
3094 *
3095 * Returns the new element or NULL in case of error.
3096 */
3097xmlNodePtr
3098xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
3099 xmlNodePtr parent;
3100
3101 if (cur == NULL) {
3102#ifdef DEBUG_TREE
3103 xmlGenericError(xmlGenericErrorContext,
3104 "xmlAddSibling : cur == NULL\n");
3105#endif
3106 return(NULL);
3107 }
3108
3109 if (elem == NULL) {
3110#ifdef DEBUG_TREE
3111 xmlGenericError(xmlGenericErrorContext,
3112 "xmlAddSibling : elem == NULL\n");
3113#endif
3114 return(NULL);
3115 }
3116
Daniel Veillard43bc89c2009-03-23 19:32:04 +00003117 if (cur == elem) {
3118#ifdef DEBUG_TREE
3119 xmlGenericError(xmlGenericErrorContext,
3120 "xmlAddSibling : cur == elem\n");
3121#endif
3122 return(NULL);
3123 }
3124
Owen Taylor3473f882001-02-23 17:55:21 +00003125 /*
3126 * Constant time is we can rely on the ->parent->last to find
3127 * the last sibling.
3128 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00003129 if ((cur->type != XML_ATTRIBUTE_NODE) && (cur->parent != NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00003130 (cur->parent->children != NULL) &&
3131 (cur->parent->last != NULL) &&
3132 (cur->parent->last->next == NULL)) {
3133 cur = cur->parent->last;
3134 } else {
3135 while (cur->next != NULL) cur = cur->next;
3136 }
3137
3138 xmlUnlinkNode(elem);
3139
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003140 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3141 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003142 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003143 xmlFreeNode(elem);
3144 return(cur);
Rob Richards65815122006-02-25 17:13:33 +00003145 } else if (elem->type == XML_ATTRIBUTE_NODE) {
3146 return xmlAddPropSibling(cur, cur, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00003147 }
3148
3149 if (elem->doc != cur->doc) {
3150 xmlSetTreeDoc(elem, cur->doc);
3151 }
3152 parent = cur->parent;
3153 elem->prev = cur;
3154 elem->next = NULL;
3155 elem->parent = parent;
3156 cur->next = elem;
3157 if (parent != NULL)
3158 parent->last = elem;
3159
3160 return(elem);
3161}
3162
3163/**
3164 * xmlAddChildList:
3165 * @parent: the parent node
3166 * @cur: the first node in the list
3167 *
3168 * Add a list of node at the end of the child list of the parent
3169 * merging adjacent TEXT nodes (@cur may be freed)
3170 *
3171 * Returns the last child or NULL in case of error.
3172 */
3173xmlNodePtr
3174xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3175 xmlNodePtr prev;
3176
3177 if (parent == NULL) {
3178#ifdef DEBUG_TREE
3179 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003180 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003181#endif
3182 return(NULL);
3183 }
3184
3185 if (cur == NULL) {
3186#ifdef DEBUG_TREE
3187 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003188 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003189#endif
3190 return(NULL);
3191 }
3192
3193 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3194 (cur->doc != parent->doc)) {
3195#ifdef DEBUG_TREE
3196 xmlGenericError(xmlGenericErrorContext,
3197 "Elements moved to a different document\n");
3198#endif
3199 }
3200
3201 /*
3202 * add the first element at the end of the children list.
3203 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003204
Owen Taylor3473f882001-02-23 17:55:21 +00003205 if (parent->children == NULL) {
3206 parent->children = cur;
3207 } else {
3208 /*
3209 * If cur and parent->last both are TEXT nodes, then merge them.
3210 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00003211 if ((cur->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00003212 (parent->last->type == XML_TEXT_NODE) &&
3213 (cur->name == parent->last->name)) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00003214 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003215 /*
3216 * if it's the only child, nothing more to be done.
3217 */
3218 if (cur->next == NULL) {
3219 xmlFreeNode(cur);
3220 return(parent->last);
3221 }
3222 prev = cur;
3223 cur = cur->next;
3224 xmlFreeNode(prev);
3225 }
3226 prev = parent->last;
3227 prev->next = cur;
3228 cur->prev = prev;
3229 }
3230 while (cur->next != NULL) {
3231 cur->parent = parent;
3232 if (cur->doc != parent->doc) {
3233 xmlSetTreeDoc(cur, parent->doc);
3234 }
3235 cur = cur->next;
3236 }
3237 cur->parent = parent;
Rob Richards810a78b2008-12-31 22:13:57 +00003238 /* the parent may not be linked to a doc ! */
3239 if (cur->doc != parent->doc) {
3240 xmlSetTreeDoc(cur, parent->doc);
3241 }
Owen Taylor3473f882001-02-23 17:55:21 +00003242 parent->last = cur;
3243
3244 return(cur);
3245}
3246
3247/**
3248 * xmlAddChild:
3249 * @parent: the parent node
3250 * @cur: the child node
3251 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003252 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003253 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003254 * If the new node is ATTRIBUTE, it is added into properties instead of children.
Daniel Veillardaa6de472008-08-25 14:53:31 +00003255 * If there is an attribute with equal name, it is first destroyed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003256 *
Owen Taylor3473f882001-02-23 17:55:21 +00003257 * Returns the child or NULL in case of error.
3258 */
3259xmlNodePtr
3260xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3261 xmlNodePtr prev;
3262
3263 if (parent == NULL) {
3264#ifdef DEBUG_TREE
3265 xmlGenericError(xmlGenericErrorContext,
3266 "xmlAddChild : parent == NULL\n");
3267#endif
3268 return(NULL);
3269 }
3270
3271 if (cur == NULL) {
3272#ifdef DEBUG_TREE
3273 xmlGenericError(xmlGenericErrorContext,
3274 "xmlAddChild : child == NULL\n");
3275#endif
3276 return(NULL);
3277 }
3278
Rob Richards19dc9612005-10-28 16:15:16 +00003279 if (parent == cur) {
3280#ifdef DEBUG_TREE
3281 xmlGenericError(xmlGenericErrorContext,
3282 "xmlAddChild : parent == cur\n");
3283#endif
3284 return(NULL);
3285 }
Owen Taylor3473f882001-02-23 17:55:21 +00003286 /*
3287 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003288 * cur is then freed.
3289 */
3290 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003291 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003292 (parent->content != NULL) &&
Rob Richards19dc9612005-10-28 16:15:16 +00003293 (parent->name == cur->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003294 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003295 xmlFreeNode(cur);
3296 return(parent);
3297 }
3298 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003299 (parent->last->name == cur->name) &&
3300 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003301 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003302 xmlFreeNode(cur);
3303 return(parent->last);
3304 }
3305 }
3306
3307 /*
3308 * add the new element at the end of the children list.
3309 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003310 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003311 cur->parent = parent;
3312 if (cur->doc != parent->doc) {
3313 xmlSetTreeDoc(cur, parent->doc);
3314 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003315 /* this check prevents a loop on tree-traversions if a developer
3316 * tries to add a node to its parent multiple times
3317 */
3318 if (prev == parent)
3319 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003320
3321 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003322 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003323 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003324 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003325 (parent->content != NULL) &&
3326 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003327 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003328 xmlFreeNode(cur);
3329 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003330 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003331 if (cur->type == XML_ATTRIBUTE_NODE) {
Rob Richards19dc9612005-10-28 16:15:16 +00003332 if (parent->type != XML_ELEMENT_NODE)
3333 return(NULL);
Rob Richards810a78b2008-12-31 22:13:57 +00003334 if (parent->properties != NULL) {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003335 /* check if an attribute with the same name exists */
3336 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003337
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003338 if (cur->ns == NULL)
Rob Richardsc342ec62005-10-25 00:10:12 +00003339 lastattr = xmlHasNsProp(parent, cur->name, NULL);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003340 else
3341 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
Rob Richardsc342ec62005-10-25 00:10:12 +00003342 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur) && (lastattr->type != XML_ATTRIBUTE_DECL)) {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003343 /* different instance, destroy it (attributes must be unique) */
Rob Richards19dc9612005-10-28 16:15:16 +00003344 xmlUnlinkNode((xmlNodePtr) lastattr);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003345 xmlFreeProp(lastattr);
3346 }
Rob Richards19dc9612005-10-28 16:15:16 +00003347 if (lastattr == (xmlAttrPtr) cur)
3348 return(cur);
Rob Richards810a78b2008-12-31 22:13:57 +00003349
3350 }
3351 if (parent->properties == NULL) {
3352 parent->properties = (xmlAttrPtr) cur;
3353 } else {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003354 /* find the end */
Rob Richards810a78b2008-12-31 22:13:57 +00003355 xmlAttrPtr lastattr = parent->properties;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003356 while (lastattr->next != NULL) {
3357 lastattr = lastattr->next;
3358 }
3359 lastattr->next = (xmlAttrPtr) cur;
3360 ((xmlAttrPtr) cur)->prev = lastattr;
3361 }
3362 } else {
3363 if (parent->children == NULL) {
3364 parent->children = cur;
3365 parent->last = cur;
3366 } else {
3367 prev = parent->last;
3368 prev->next = cur;
3369 cur->prev = prev;
3370 parent->last = cur;
3371 }
3372 }
Owen Taylor3473f882001-02-23 17:55:21 +00003373 return(cur);
3374}
3375
3376/**
3377 * xmlGetLastChild:
3378 * @parent: the parent node
3379 *
3380 * Search the last child of a node.
3381 * Returns the last child or NULL if none.
3382 */
3383xmlNodePtr
3384xmlGetLastChild(xmlNodePtr parent) {
3385 if (parent == NULL) {
3386#ifdef DEBUG_TREE
3387 xmlGenericError(xmlGenericErrorContext,
3388 "xmlGetLastChild : parent == NULL\n");
3389#endif
3390 return(NULL);
3391 }
3392 return(parent->last);
3393}
3394
Daniel Veillardbe2bd6a2008-11-27 15:26:28 +00003395#ifdef LIBXML_TREE_ENABLED
3396/*
3397 * 5 interfaces from DOM ElementTraversal
3398 */
3399
3400/**
3401 * xmlChildElementCount:
3402 * @parent: the parent node
3403 *
3404 * Finds the current number of child nodes of that element which are
3405 * element nodes.
3406 * Note the handling of entities references is different than in
3407 * the W3C DOM element traversal spec since we don't have back reference
3408 * from entities content to entities references.
3409 *
3410 * Returns the count of element child or 0 if not available
3411 */
3412unsigned long
3413xmlChildElementCount(xmlNodePtr parent) {
3414 unsigned long ret = 0;
3415 xmlNodePtr cur = NULL;
3416
3417 if (parent == NULL)
3418 return(0);
3419 switch (parent->type) {
3420 case XML_ELEMENT_NODE:
3421 case XML_ENTITY_NODE:
3422 case XML_DOCUMENT_NODE:
3423 case XML_HTML_DOCUMENT_NODE:
3424 cur = parent->children;
3425 break;
3426 default:
3427 return(0);
3428 }
3429 while (cur != NULL) {
3430 if (cur->type == XML_ELEMENT_NODE)
3431 ret++;
3432 cur = cur->next;
3433 }
3434 return(ret);
3435}
3436
3437/**
3438 * xmlFirstElementChild:
3439 * @parent: the parent node
3440 *
3441 * Finds the first child node of that element which is a Element node
3442 * Note the handling of entities references is different than in
3443 * the W3C DOM element traversal spec since we don't have back reference
3444 * from entities content to entities references.
3445 *
3446 * Returns the first element child or NULL if not available
3447 */
3448xmlNodePtr
3449xmlFirstElementChild(xmlNodePtr parent) {
3450 xmlNodePtr cur = NULL;
3451
3452 if (parent == NULL)
3453 return(NULL);
3454 switch (parent->type) {
3455 case XML_ELEMENT_NODE:
3456 case XML_ENTITY_NODE:
3457 case XML_DOCUMENT_NODE:
3458 case XML_HTML_DOCUMENT_NODE:
3459 cur = parent->children;
3460 break;
3461 default:
3462 return(NULL);
3463 }
3464 while (cur != NULL) {
3465 if (cur->type == XML_ELEMENT_NODE)
3466 return(cur);
3467 cur = cur->next;
3468 }
3469 return(NULL);
3470}
3471
3472/**
3473 * xmlLastElementChild:
3474 * @parent: the parent node
3475 *
3476 * Finds the last child node of that element which is a Element node
3477 * Note the handling of entities references is different than in
3478 * the W3C DOM element traversal spec since we don't have back reference
3479 * from entities content to entities references.
3480 *
3481 * Returns the last element child or NULL if not available
3482 */
3483xmlNodePtr
3484xmlLastElementChild(xmlNodePtr parent) {
3485 xmlNodePtr cur = NULL;
3486
3487 if (parent == NULL)
3488 return(NULL);
3489 switch (parent->type) {
3490 case XML_ELEMENT_NODE:
3491 case XML_ENTITY_NODE:
3492 case XML_DOCUMENT_NODE:
3493 case XML_HTML_DOCUMENT_NODE:
3494 cur = parent->last;
3495 break;
3496 default:
3497 return(NULL);
3498 }
3499 while (cur != NULL) {
3500 if (cur->type == XML_ELEMENT_NODE)
3501 return(cur);
3502 cur = cur->prev;
3503 }
3504 return(NULL);
3505}
3506
3507/**
3508 * xmlPreviousElementSibling:
3509 * @node: the current node
3510 *
3511 * Finds the first closest previous sibling of the node which is an
3512 * element node.
3513 * Note the handling of entities references is different than in
3514 * the W3C DOM element traversal spec since we don't have back reference
3515 * from entities content to entities references.
3516 *
3517 * Returns the previous element sibling or NULL if not available
3518 */
3519xmlNodePtr
3520xmlPreviousElementSibling(xmlNodePtr node) {
3521 if (node == NULL)
3522 return(NULL);
3523 switch (node->type) {
3524 case XML_ELEMENT_NODE:
3525 case XML_TEXT_NODE:
3526 case XML_CDATA_SECTION_NODE:
3527 case XML_ENTITY_REF_NODE:
3528 case XML_ENTITY_NODE:
3529 case XML_PI_NODE:
3530 case XML_COMMENT_NODE:
3531 case XML_XINCLUDE_START:
3532 case XML_XINCLUDE_END:
3533 node = node->prev;
3534 break;
3535 default:
3536 return(NULL);
3537 }
3538 while (node != NULL) {
3539 if (node->type == XML_ELEMENT_NODE)
3540 return(node);
François Delyon2f700902010-02-03 17:32:37 +01003541 node = node->prev;
Daniel Veillardbe2bd6a2008-11-27 15:26:28 +00003542 }
3543 return(NULL);
3544}
3545
3546/**
3547 * xmlNextElementSibling:
3548 * @node: the current node
3549 *
3550 * Finds the first closest next sibling of the node which is an
3551 * element node.
3552 * Note the handling of entities references is different than in
3553 * the W3C DOM element traversal spec since we don't have back reference
3554 * from entities content to entities references.
3555 *
3556 * Returns the next element sibling or NULL if not available
3557 */
3558xmlNodePtr
3559xmlNextElementSibling(xmlNodePtr node) {
3560 if (node == NULL)
3561 return(NULL);
3562 switch (node->type) {
3563 case XML_ELEMENT_NODE:
3564 case XML_TEXT_NODE:
3565 case XML_CDATA_SECTION_NODE:
3566 case XML_ENTITY_REF_NODE:
3567 case XML_ENTITY_NODE:
3568 case XML_PI_NODE:
3569 case XML_COMMENT_NODE:
3570 case XML_DTD_NODE:
3571 case XML_XINCLUDE_START:
3572 case XML_XINCLUDE_END:
3573 node = node->next;
3574 break;
3575 default:
3576 return(NULL);
3577 }
3578 while (node != NULL) {
3579 if (node->type == XML_ELEMENT_NODE)
3580 return(node);
3581 node = node->next;
3582 }
3583 return(NULL);
3584}
3585
3586#endif /* LIBXML_TREE_ENABLED */
3587
Owen Taylor3473f882001-02-23 17:55:21 +00003588/**
3589 * xmlFreeNodeList:
3590 * @cur: the first node in the list
3591 *
3592 * Free a node and all its siblings, this is a recursive behaviour, all
3593 * the children are freed too.
3594 */
3595void
3596xmlFreeNodeList(xmlNodePtr cur) {
3597 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003598 xmlDictPtr dict = NULL;
3599
3600 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003601 if (cur->type == XML_NAMESPACE_DECL) {
3602 xmlFreeNsList((xmlNsPtr) cur);
3603 return;
3604 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003605 if ((cur->type == XML_DOCUMENT_NODE) ||
3606#ifdef LIBXML_DOCB_ENABLED
3607 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003608#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003609 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003610 xmlFreeDoc((xmlDocPtr) cur);
3611 return;
3612 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003613 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003614 while (cur != NULL) {
3615 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003616 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003617
Daniel Veillarda880b122003-04-21 21:36:41 +00003618 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003619 xmlDeregisterNodeDefaultValue(cur);
3620
Daniel Veillard02141ea2001-04-30 11:46:40 +00003621 if ((cur->children != NULL) &&
3622 (cur->type != XML_ENTITY_REF_NODE))
3623 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003624 if (((cur->type == XML_ELEMENT_NODE) ||
3625 (cur->type == XML_XINCLUDE_START) ||
3626 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003627 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003628 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003629 if ((cur->type != XML_ELEMENT_NODE) &&
3630 (cur->type != XML_XINCLUDE_START) &&
3631 (cur->type != XML_XINCLUDE_END) &&
Daniel Veillard8874b942005-08-25 13:19:21 +00003632 (cur->type != XML_ENTITY_REF_NODE) &&
3633 (cur->content != (xmlChar *) &(cur->properties))) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003634 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003635 }
3636 if (((cur->type == XML_ELEMENT_NODE) ||
3637 (cur->type == XML_XINCLUDE_START) ||
3638 (cur->type == XML_XINCLUDE_END)) &&
3639 (cur->nsDef != NULL))
3640 xmlFreeNsList(cur->nsDef);
3641
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003642 /*
3643 * When a node is a text node or a comment, it uses a global static
3644 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003645 * Otherwise the node name might come from the document's
3646 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003647 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003648 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003649 (cur->type != XML_TEXT_NODE) &&
3650 (cur->type != XML_COMMENT_NODE))
3651 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003652 xmlFree(cur);
3653 }
Owen Taylor3473f882001-02-23 17:55:21 +00003654 cur = next;
3655 }
3656}
3657
3658/**
3659 * xmlFreeNode:
3660 * @cur: the node
3661 *
3662 * Free a node, this is a recursive behaviour, all the children are freed too.
3663 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3664 */
3665void
3666xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003667 xmlDictPtr dict = NULL;
3668
3669 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003670
Daniel Veillard02141ea2001-04-30 11:46:40 +00003671 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003672 if (cur->type == XML_DTD_NODE) {
3673 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003674 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003675 }
3676 if (cur->type == XML_NAMESPACE_DECL) {
3677 xmlFreeNs((xmlNsPtr) cur);
3678 return;
3679 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003680 if (cur->type == XML_ATTRIBUTE_NODE) {
3681 xmlFreeProp((xmlAttrPtr) cur);
3682 return;
3683 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003684
Daniel Veillarda880b122003-04-21 21:36:41 +00003685 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003686 xmlDeregisterNodeDefaultValue(cur);
3687
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003688 if (cur->doc != NULL) dict = cur->doc->dict;
3689
Daniel Veillard2cba4152008-08-27 11:45:41 +00003690 if (cur->type == XML_ENTITY_DECL) {
3691 xmlEntityPtr ent = (xmlEntityPtr) cur;
3692 DICT_FREE(ent->SystemID);
3693 DICT_FREE(ent->ExternalID);
3694 }
Owen Taylor3473f882001-02-23 17:55:21 +00003695 if ((cur->children != NULL) &&
3696 (cur->type != XML_ENTITY_REF_NODE))
3697 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003698 if (((cur->type == XML_ELEMENT_NODE) ||
3699 (cur->type == XML_XINCLUDE_START) ||
3700 (cur->type == XML_XINCLUDE_END)) &&
3701 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003702 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003703 if ((cur->type != XML_ELEMENT_NODE) &&
3704 (cur->content != NULL) &&
3705 (cur->type != XML_ENTITY_REF_NODE) &&
3706 (cur->type != XML_XINCLUDE_END) &&
Daniel Veillard8874b942005-08-25 13:19:21 +00003707 (cur->type != XML_XINCLUDE_START) &&
3708 (cur->content != (xmlChar *) &(cur->properties))) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003709 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003710 }
3711
Daniel Veillardacd370f2001-06-09 17:17:51 +00003712 /*
3713 * When a node is a text node or a comment, it uses a global static
3714 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003715 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003716 */
Owen Taylor3473f882001-02-23 17:55:21 +00003717 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003718 (cur->type != XML_TEXT_NODE) &&
3719 (cur->type != XML_COMMENT_NODE))
3720 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003721
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003722 if (((cur->type == XML_ELEMENT_NODE) ||
3723 (cur->type == XML_XINCLUDE_START) ||
3724 (cur->type == XML_XINCLUDE_END)) &&
3725 (cur->nsDef != NULL))
3726 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003727 xmlFree(cur);
3728}
3729
3730/**
3731 * xmlUnlinkNode:
3732 * @cur: the node
3733 *
3734 * Unlink a node from it's current context, the node is not freed
Daniel Veillarda6b14bf2012-01-26 17:44:35 +08003735 * If one need to free the node, use xmlNodeFree() routine after the
3736 * unlink.
Owen Taylor3473f882001-02-23 17:55:21 +00003737 */
3738void
3739xmlUnlinkNode(xmlNodePtr cur) {
3740 if (cur == NULL) {
3741#ifdef DEBUG_TREE
3742 xmlGenericError(xmlGenericErrorContext,
3743 "xmlUnlinkNode : node == NULL\n");
3744#endif
3745 return;
3746 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003747 if (cur->type == XML_DTD_NODE) {
3748 xmlDocPtr doc;
3749 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003750 if (doc != NULL) {
3751 if (doc->intSubset == (xmlDtdPtr) cur)
3752 doc->intSubset = NULL;
3753 if (doc->extSubset == (xmlDtdPtr) cur)
3754 doc->extSubset = NULL;
3755 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003756 }
Daniel Veillard2cba4152008-08-27 11:45:41 +00003757 if (cur->type == XML_ENTITY_DECL) {
3758 xmlDocPtr doc;
3759 doc = cur->doc;
3760 if (doc != NULL) {
3761 if (doc->intSubset != NULL) {
3762 if (xmlHashLookup(doc->intSubset->entities, cur->name) == cur)
3763 xmlHashRemoveEntry(doc->intSubset->entities, cur->name,
3764 NULL);
3765 if (xmlHashLookup(doc->intSubset->pentities, cur->name) == cur)
3766 xmlHashRemoveEntry(doc->intSubset->pentities, cur->name,
3767 NULL);
3768 }
3769 if (doc->extSubset != NULL) {
3770 if (xmlHashLookup(doc->extSubset->entities, cur->name) == cur)
3771 xmlHashRemoveEntry(doc->extSubset->entities, cur->name,
3772 NULL);
3773 if (xmlHashLookup(doc->extSubset->pentities, cur->name) == cur)
3774 xmlHashRemoveEntry(doc->extSubset->pentities, cur->name,
3775 NULL);
3776 }
3777 }
3778 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003779 if (cur->parent != NULL) {
3780 xmlNodePtr parent;
3781 parent = cur->parent;
3782 if (cur->type == XML_ATTRIBUTE_NODE) {
3783 if (parent->properties == (xmlAttrPtr) cur)
3784 parent->properties = ((xmlAttrPtr) cur)->next;
3785 } else {
3786 if (parent->children == cur)
3787 parent->children = cur->next;
3788 if (parent->last == cur)
3789 parent->last = cur->prev;
3790 }
3791 cur->parent = NULL;
3792 }
Owen Taylor3473f882001-02-23 17:55:21 +00003793 if (cur->next != NULL)
3794 cur->next->prev = cur->prev;
3795 if (cur->prev != NULL)
3796 cur->prev->next = cur->next;
3797 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003798}
3799
Daniel Veillard2156d432004-03-04 15:59:36 +00003800#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003801/**
3802 * xmlReplaceNode:
3803 * @old: the old node
3804 * @cur: the node
3805 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003806 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003807 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003808 * first unlinked from its existing context.
3809 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003810 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003811 */
3812xmlNodePtr
3813xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00003814 if (old == cur) return(NULL);
Daniel Veillarda03e3652004-11-02 18:45:30 +00003815 if ((old == NULL) || (old->parent == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003816#ifdef DEBUG_TREE
3817 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda03e3652004-11-02 18:45:30 +00003818 "xmlReplaceNode : old == NULL or without parent\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003819#endif
3820 return(NULL);
3821 }
3822 if (cur == NULL) {
3823 xmlUnlinkNode(old);
3824 return(old);
3825 }
3826 if (cur == old) {
3827 return(old);
3828 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003829 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3830#ifdef DEBUG_TREE
3831 xmlGenericError(xmlGenericErrorContext,
3832 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3833#endif
3834 return(old);
3835 }
3836 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3837#ifdef DEBUG_TREE
3838 xmlGenericError(xmlGenericErrorContext,
3839 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3840#endif
3841 return(old);
3842 }
Owen Taylor3473f882001-02-23 17:55:21 +00003843 xmlUnlinkNode(cur);
Daniel Veillard64d7d122005-05-11 18:03:42 +00003844 xmlSetTreeDoc(cur, old->doc);
Owen Taylor3473f882001-02-23 17:55:21 +00003845 cur->parent = old->parent;
3846 cur->next = old->next;
3847 if (cur->next != NULL)
3848 cur->next->prev = cur;
3849 cur->prev = old->prev;
3850 if (cur->prev != NULL)
3851 cur->prev->next = cur;
3852 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003853 if (cur->type == XML_ATTRIBUTE_NODE) {
3854 if (cur->parent->properties == (xmlAttrPtr)old)
3855 cur->parent->properties = ((xmlAttrPtr) cur);
3856 } else {
3857 if (cur->parent->children == old)
3858 cur->parent->children = cur;
3859 if (cur->parent->last == old)
3860 cur->parent->last = cur;
3861 }
Owen Taylor3473f882001-02-23 17:55:21 +00003862 }
3863 old->next = old->prev = NULL;
3864 old->parent = NULL;
3865 return(old);
3866}
Daniel Veillard652327a2003-09-29 18:02:38 +00003867#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003868
3869/************************************************************************
3870 * *
3871 * Copy operations *
3872 * *
3873 ************************************************************************/
Daniel Veillardaa6de472008-08-25 14:53:31 +00003874
Owen Taylor3473f882001-02-23 17:55:21 +00003875/**
3876 * xmlCopyNamespace:
3877 * @cur: the namespace
3878 *
3879 * Do a copy of the namespace.
3880 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003881 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003882 */
3883xmlNsPtr
3884xmlCopyNamespace(xmlNsPtr cur) {
3885 xmlNsPtr ret;
3886
3887 if (cur == NULL) return(NULL);
3888 switch (cur->type) {
3889 case XML_LOCAL_NAMESPACE:
3890 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3891 break;
3892 default:
3893#ifdef DEBUG_TREE
3894 xmlGenericError(xmlGenericErrorContext,
3895 "xmlCopyNamespace: invalid type %d\n", cur->type);
3896#endif
3897 return(NULL);
3898 }
3899 return(ret);
3900}
3901
3902/**
3903 * xmlCopyNamespaceList:
3904 * @cur: the first namespace
3905 *
3906 * Do a copy of an namespace list.
3907 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003908 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003909 */
3910xmlNsPtr
3911xmlCopyNamespaceList(xmlNsPtr cur) {
3912 xmlNsPtr ret = NULL;
3913 xmlNsPtr p = NULL,q;
3914
3915 while (cur != NULL) {
3916 q = xmlCopyNamespace(cur);
3917 if (p == NULL) {
3918 ret = p = q;
3919 } else {
3920 p->next = q;
3921 p = q;
3922 }
3923 cur = cur->next;
3924 }
3925 return(ret);
3926}
3927
3928static xmlNodePtr
3929xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
Rob Richards19dc9612005-10-28 16:15:16 +00003930
3931static xmlAttrPtr
3932xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003933 xmlAttrPtr ret;
3934
3935 if (cur == NULL) return(NULL);
3936 if (target != NULL)
3937 ret = xmlNewDocProp(target->doc, cur->name, NULL);
Rob Richards19dc9612005-10-28 16:15:16 +00003938 else if (doc != NULL)
3939 ret = xmlNewDocProp(doc, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003940 else if (cur->parent != NULL)
3941 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3942 else if (cur->children != NULL)
3943 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3944 else
3945 ret = xmlNewDocProp(NULL, cur->name, NULL);
3946 if (ret == NULL) return(NULL);
3947 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003948
Owen Taylor3473f882001-02-23 17:55:21 +00003949 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003950 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003951
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003952 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3953 if (ns == NULL) {
3954 /*
3955 * Humm, we are copying an element whose namespace is defined
3956 * out of the new tree scope. Search it in the original tree
3957 * and add it at the top of the new tree
3958 */
3959 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3960 if (ns != NULL) {
3961 xmlNodePtr root = target;
3962 xmlNodePtr pred = NULL;
3963
3964 while (root->parent != NULL) {
3965 pred = root;
3966 root = root->parent;
3967 }
3968 if (root == (xmlNodePtr) target->doc) {
3969 /* correct possibly cycling above the document elt */
3970 root = pred;
3971 }
3972 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3973 }
3974 } else {
3975 /*
3976 * we have to find something appropriate here since
3977 * we cant be sure, that the namespce we found is identified
3978 * by the prefix
3979 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003980 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003981 /* this is the nice case */
3982 ret->ns = ns;
3983 } else {
3984 /*
3985 * we are in trouble: we need a new reconcilied namespace.
3986 * This is expensive
3987 */
3988 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3989 }
3990 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003991
Owen Taylor3473f882001-02-23 17:55:21 +00003992 } else
3993 ret->ns = NULL;
3994
3995 if (cur->children != NULL) {
3996 xmlNodePtr tmp;
3997
3998 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3999 ret->last = NULL;
4000 tmp = ret->children;
4001 while (tmp != NULL) {
4002 /* tmp->parent = (xmlNodePtr)ret; */
4003 if (tmp->next == NULL)
4004 ret->last = tmp;
4005 tmp = tmp->next;
4006 }
4007 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00004008 /*
4009 * Try to handle IDs
4010 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00004011 if ((target!= NULL) && (cur!= NULL) &&
4012 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00004013 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
4014 if (xmlIsID(cur->doc, cur->parent, cur)) {
4015 xmlChar *id;
4016
4017 id = xmlNodeListGetString(cur->doc, cur->children, 1);
4018 if (id != NULL) {
4019 xmlAddID(NULL, target->doc, id, ret);
4020 xmlFree(id);
4021 }
4022 }
4023 }
Owen Taylor3473f882001-02-23 17:55:21 +00004024 return(ret);
4025}
4026
4027/**
Rob Richards19dc9612005-10-28 16:15:16 +00004028 * xmlCopyProp:
4029 * @target: the element where the attribute will be grafted
4030 * @cur: the attribute
4031 *
4032 * Do a copy of the attribute.
4033 *
4034 * Returns: a new #xmlAttrPtr, or NULL in case of error.
4035 */
4036xmlAttrPtr
4037xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
4038 return xmlCopyPropInternal(NULL, target, cur);
4039}
4040
4041/**
Owen Taylor3473f882001-02-23 17:55:21 +00004042 * xmlCopyPropList:
4043 * @target: the element where the attributes will be grafted
4044 * @cur: the first attribute
4045 *
4046 * Do a copy of an attribute list.
4047 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004048 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004049 */
4050xmlAttrPtr
4051xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
4052 xmlAttrPtr ret = NULL;
4053 xmlAttrPtr p = NULL,q;
4054
4055 while (cur != NULL) {
4056 q = xmlCopyProp(target, cur);
William M. Brack13dfa872004-09-18 04:52:08 +00004057 if (q == NULL)
4058 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004059 if (p == NULL) {
4060 ret = p = q;
4061 } else {
4062 p->next = q;
4063 q->prev = p;
4064 p = q;
4065 }
4066 cur = cur->next;
4067 }
4068 return(ret);
4069}
4070
4071/*
Daniel Veillardd1640922001-12-17 15:30:10 +00004072 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00004073 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004074 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00004075 * tricky reason: namespaces. Doing a direct copy of a node
4076 * say RPM:Copyright without changing the namespace pointer to
4077 * something else can produce stale links. One way to do it is
4078 * to keep a reference counter but this doesn't work as soon
4079 * as one move the element or the subtree out of the scope of
4080 * the existing namespace. The actual solution seems to add
4081 * a copy of the namespace at the top of the copied tree if
4082 * not available in the subtree.
4083 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00004084 * The argument "recursive" normally indicates a recursive copy
4085 * of the node with values 0 (no) and 1 (yes). For XInclude,
4086 * however, we allow a value of 2 to indicate copy properties and
4087 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00004088 */
4089
4090static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00004091xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00004092 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00004093 xmlNodePtr ret;
4094
4095 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00004096 switch (node->type) {
4097 case XML_TEXT_NODE:
4098 case XML_CDATA_SECTION_NODE:
4099 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00004100 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00004101 case XML_ENTITY_REF_NODE:
4102 case XML_ENTITY_NODE:
4103 case XML_PI_NODE:
4104 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00004105 case XML_XINCLUDE_START:
4106 case XML_XINCLUDE_END:
4107 break;
4108 case XML_ATTRIBUTE_NODE:
Rob Richards19dc9612005-10-28 16:15:16 +00004109 return((xmlNodePtr) xmlCopyPropInternal(doc, parent, (xmlAttrPtr) node));
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00004110 case XML_NAMESPACE_DECL:
4111 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
Daniel Veillardaa6de472008-08-25 14:53:31 +00004112
Daniel Veillard39196eb2001-06-19 18:09:42 +00004113 case XML_DOCUMENT_NODE:
4114 case XML_HTML_DOCUMENT_NODE:
4115#ifdef LIBXML_DOCB_ENABLED
4116 case XML_DOCB_DOCUMENT_NODE:
4117#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00004118#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00004119 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00004120#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00004121 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00004122 case XML_NOTATION_NODE:
4123 case XML_DTD_NODE:
4124 case XML_ELEMENT_DECL:
4125 case XML_ATTRIBUTE_DECL:
4126 case XML_ENTITY_DECL:
4127 return(NULL);
4128 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00004129
Owen Taylor3473f882001-02-23 17:55:21 +00004130 /*
4131 * Allocate a new node and fill the fields.
4132 */
4133 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
4134 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004135 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00004136 return(NULL);
4137 }
4138 memset(ret, 0, sizeof(xmlNode));
4139 ret->type = node->type;
4140
4141 ret->doc = doc;
Daniel Veillardaa6de472008-08-25 14:53:31 +00004142 ret->parent = parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004143 if (node->name == xmlStringText)
4144 ret->name = xmlStringText;
4145 else if (node->name == xmlStringTextNoenc)
4146 ret->name = xmlStringTextNoenc;
4147 else if (node->name == xmlStringComment)
4148 ret->name = xmlStringComment;
Daniel Veillard03a53c32004-10-26 16:06:51 +00004149 else if (node->name != NULL) {
4150 if ((doc != NULL) && (doc->dict != NULL))
4151 ret->name = xmlDictLookup(doc->dict, node->name, -1);
4152 else
4153 ret->name = xmlStrdup(node->name);
4154 }
Daniel Veillard7db37732001-07-12 01:20:08 +00004155 if ((node->type != XML_ELEMENT_NODE) &&
4156 (node->content != NULL) &&
4157 (node->type != XML_ENTITY_REF_NODE) &&
4158 (node->type != XML_XINCLUDE_END) &&
4159 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004160 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00004161 }else{
4162 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004163 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00004164 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004165 if (parent != NULL) {
4166 xmlNodePtr tmp;
4167
Daniel Veillard8a1b1852003-01-05 22:37:17 +00004168 /*
4169 * this is a tricky part for the node register thing:
4170 * in case ret does get coalesced in xmlAddChild
4171 * the deregister-node callback is called; so we register ret now already
4172 */
Daniel Veillarda880b122003-04-21 21:36:41 +00004173 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00004174 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
4175
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004176 tmp = xmlAddChild(parent, ret);
4177 /* node could have coalesced */
4178 if (tmp != ret)
4179 return(tmp);
4180 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00004181
William M. Brack57e9e912004-03-09 16:19:02 +00004182 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00004183 goto out;
Petr Pajas2afca4a2009-07-30 17:47:32 +02004184 if (((node->type == XML_ELEMENT_NODE) ||
4185 (node->type == XML_XINCLUDE_START)) && (node->nsDef != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00004186 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
4187
4188 if (node->ns != NULL) {
4189 xmlNsPtr ns;
4190
4191 ns = xmlSearchNs(doc, ret, node->ns->prefix);
4192 if (ns == NULL) {
4193 /*
4194 * Humm, we are copying an element whose namespace is defined
4195 * out of the new tree scope. Search it in the original tree
4196 * and add it at the top of the new tree
4197 */
4198 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
4199 if (ns != NULL) {
4200 xmlNodePtr root = ret;
4201
4202 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00004203 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Rob Richardsddb01cb2010-01-29 13:32:12 -05004204 } else {
4205 ret->ns = xmlNewReconciliedNs(doc, ret, node->ns);
Owen Taylor3473f882001-02-23 17:55:21 +00004206 }
4207 } else {
4208 /*
4209 * reference the existing namespace definition in our own tree.
4210 */
4211 ret->ns = ns;
4212 }
4213 }
Petr Pajas2afca4a2009-07-30 17:47:32 +02004214 if (((node->type == XML_ELEMENT_NODE) ||
4215 (node->type == XML_XINCLUDE_START)) && (node->properties != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00004216 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004217 if (node->type == XML_ENTITY_REF_NODE) {
4218 if ((doc == NULL) || (node->doc != doc)) {
4219 /*
4220 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00004221 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00004222 * we cannot keep the reference. Try to find it in the
4223 * target document.
4224 */
4225 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
4226 } else {
4227 ret->children = node->children;
4228 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00004229 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00004230 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004231 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00004232 UPDATE_LAST_CHILD_AND_PARENT(ret)
4233 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00004234
4235out:
4236 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00004237 if ((parent == NULL) &&
4238 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00004239 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004240 return(ret);
4241}
4242
4243static xmlNodePtr
4244xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
4245 xmlNodePtr ret = NULL;
4246 xmlNodePtr p = NULL,q;
4247
4248 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00004249#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00004250 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00004251 if (doc == NULL) {
4252 node = node->next;
4253 continue;
4254 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00004255 if (doc->intSubset == NULL) {
4256 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
4257 q->doc = doc;
4258 q->parent = parent;
4259 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004260 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004261 } else {
4262 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004263 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004264 }
4265 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00004266#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00004267 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00004268 if (ret == NULL) {
4269 q->prev = NULL;
4270 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004271 } else if (p != q) {
4272 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00004273 p->next = q;
4274 q->prev = p;
4275 p = q;
4276 }
4277 node = node->next;
4278 }
4279 return(ret);
4280}
4281
4282/**
4283 * xmlCopyNode:
4284 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00004285 * @extended: if 1 do a recursive copy (properties, namespaces and children
4286 * when applicable)
4287 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00004288 *
4289 * Do a copy of the node.
4290 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004291 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004292 */
4293xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00004294xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00004295 xmlNodePtr ret;
4296
William M. Brack57e9e912004-03-09 16:19:02 +00004297 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00004298 return(ret);
4299}
4300
4301/**
Daniel Veillard82daa812001-04-12 08:55:36 +00004302 * xmlDocCopyNode:
4303 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00004304 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004305 * @extended: if 1 do a recursive copy (properties, namespaces and children
4306 * when applicable)
4307 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00004308 *
4309 * Do a copy of the node to a given document.
4310 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004311 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00004312 */
4313xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00004314xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00004315 xmlNodePtr ret;
4316
William M. Brack57e9e912004-03-09 16:19:02 +00004317 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00004318 return(ret);
4319}
4320
4321/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00004322 * xmlDocCopyNodeList:
4323 * @doc: the target document
4324 * @node: the first node in the list.
4325 *
4326 * Do a recursive copy of the node list.
4327 *
4328 * Returns: a new #xmlNodePtr, or NULL in case of error.
4329 */
4330xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) {
4331 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
4332 return(ret);
4333}
4334
4335/**
Owen Taylor3473f882001-02-23 17:55:21 +00004336 * xmlCopyNodeList:
4337 * @node: the first node in the list.
4338 *
4339 * Do a recursive copy of the node list.
Daniel Veillard03a53c32004-10-26 16:06:51 +00004340 * Use xmlDocCopyNodeList() if possible to ensure string interning.
Owen Taylor3473f882001-02-23 17:55:21 +00004341 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004342 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004343 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00004344xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00004345 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
4346 return(ret);
4347}
4348
Daniel Veillard2156d432004-03-04 15:59:36 +00004349#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004350/**
Owen Taylor3473f882001-02-23 17:55:21 +00004351 * xmlCopyDtd:
4352 * @dtd: the dtd
4353 *
4354 * Do a copy of the dtd.
4355 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004356 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004357 */
4358xmlDtdPtr
4359xmlCopyDtd(xmlDtdPtr dtd) {
4360 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004361 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00004362
4363 if (dtd == NULL) return(NULL);
4364 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4365 if (ret == NULL) return(NULL);
4366 if (dtd->entities != NULL)
4367 ret->entities = (void *) xmlCopyEntitiesTable(
4368 (xmlEntitiesTablePtr) dtd->entities);
4369 if (dtd->notations != NULL)
4370 ret->notations = (void *) xmlCopyNotationTable(
4371 (xmlNotationTablePtr) dtd->notations);
4372 if (dtd->elements != NULL)
4373 ret->elements = (void *) xmlCopyElementTable(
4374 (xmlElementTablePtr) dtd->elements);
4375 if (dtd->attributes != NULL)
4376 ret->attributes = (void *) xmlCopyAttributeTable(
4377 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004378 if (dtd->pentities != NULL)
4379 ret->pentities = (void *) xmlCopyEntitiesTable(
4380 (xmlEntitiesTablePtr) dtd->pentities);
Daniel Veillardaa6de472008-08-25 14:53:31 +00004381
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004382 cur = dtd->children;
4383 while (cur != NULL) {
4384 q = NULL;
4385
4386 if (cur->type == XML_ENTITY_DECL) {
4387 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4388 switch (tmp->etype) {
4389 case XML_INTERNAL_GENERAL_ENTITY:
4390 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4391 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4392 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4393 break;
4394 case XML_INTERNAL_PARAMETER_ENTITY:
4395 case XML_EXTERNAL_PARAMETER_ENTITY:
Daniel Veillardaa6de472008-08-25 14:53:31 +00004396 q = (xmlNodePtr)
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004397 xmlGetParameterEntityFromDtd(ret, tmp->name);
4398 break;
4399 case XML_INTERNAL_PREDEFINED_ENTITY:
4400 break;
4401 }
4402 } else if (cur->type == XML_ELEMENT_DECL) {
4403 xmlElementPtr tmp = (xmlElementPtr) cur;
4404 q = (xmlNodePtr)
4405 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4406 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4407 xmlAttributePtr tmp = (xmlAttributePtr) cur;
Daniel Veillardaa6de472008-08-25 14:53:31 +00004408 q = (xmlNodePtr)
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004409 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4410 } else if (cur->type == XML_COMMENT_NODE) {
4411 q = xmlCopyNode(cur, 0);
4412 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00004413
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004414 if (q == NULL) {
4415 cur = cur->next;
4416 continue;
4417 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00004418
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004419 if (p == NULL)
4420 ret->children = q;
4421 else
Daniel Veillardaa6de472008-08-25 14:53:31 +00004422 p->next = q;
4423
4424 q->prev = p;
4425 q->parent = (xmlNodePtr) ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004426 q->next = NULL;
4427 ret->last = q;
Daniel Veillardaa6de472008-08-25 14:53:31 +00004428 p = q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004429 cur = cur->next;
4430 }
4431
Owen Taylor3473f882001-02-23 17:55:21 +00004432 return(ret);
4433}
Daniel Veillard2156d432004-03-04 15:59:36 +00004434#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004435
Daniel Veillard2156d432004-03-04 15:59:36 +00004436#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004437/**
4438 * xmlCopyDoc:
4439 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004440 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004441 *
4442 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004443 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004444 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004445 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004446 */
4447xmlDocPtr
4448xmlCopyDoc(xmlDocPtr doc, int recursive) {
4449 xmlDocPtr ret;
4450
4451 if (doc == NULL) return(NULL);
4452 ret = xmlNewDoc(doc->version);
4453 if (ret == NULL) return(NULL);
4454 if (doc->name != NULL)
4455 ret->name = xmlMemStrdup(doc->name);
4456 if (doc->encoding != NULL)
4457 ret->encoding = xmlStrdup(doc->encoding);
Daniel Veillardf59507d2005-01-27 17:26:49 +00004458 if (doc->URL != NULL)
4459 ret->URL = xmlStrdup(doc->URL);
Owen Taylor3473f882001-02-23 17:55:21 +00004460 ret->charset = doc->charset;
4461 ret->compression = doc->compression;
4462 ret->standalone = doc->standalone;
4463 if (!recursive) return(ret);
4464
Daniel Veillardb33c2012001-04-25 12:59:04 +00004465 ret->last = NULL;
4466 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004467#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004468 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004469 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004470 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004471 ret->intSubset->parent = ret;
4472 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004473#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004474 if (doc->oldNs != NULL)
4475 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4476 if (doc->children != NULL) {
4477 xmlNodePtr tmp;
Daniel Veillardaa6de472008-08-25 14:53:31 +00004478
Daniel Veillardb33c2012001-04-25 12:59:04 +00004479 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4480 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004481 ret->last = NULL;
4482 tmp = ret->children;
4483 while (tmp != NULL) {
4484 if (tmp->next == NULL)
4485 ret->last = tmp;
4486 tmp = tmp->next;
4487 }
4488 }
4489 return(ret);
4490}
Daniel Veillard652327a2003-09-29 18:02:38 +00004491#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004492
4493/************************************************************************
4494 * *
4495 * Content access functions *
4496 * *
4497 ************************************************************************/
Daniel Veillardaa6de472008-08-25 14:53:31 +00004498
Owen Taylor3473f882001-02-23 17:55:21 +00004499/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004500 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004501 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004502 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004503 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004504 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004505 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004506 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004507 */
4508long
4509xmlGetLineNo(xmlNodePtr node)
4510{
4511 long result = -1;
4512
4513 if (!node)
4514 return result;
Daniel Veillard73da77e2005-08-24 14:05:37 +00004515 if ((node->type == XML_ELEMENT_NODE) ||
4516 (node->type == XML_TEXT_NODE) ||
4517 (node->type == XML_COMMENT_NODE) ||
4518 (node->type == XML_PI_NODE))
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004519 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004520 else if ((node->prev != NULL) &&
4521 ((node->prev->type == XML_ELEMENT_NODE) ||
Daniel Veillard73da77e2005-08-24 14:05:37 +00004522 (node->prev->type == XML_TEXT_NODE) ||
4523 (node->prev->type == XML_COMMENT_NODE) ||
4524 (node->prev->type == XML_PI_NODE)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004525 result = xmlGetLineNo(node->prev);
4526 else if ((node->parent != NULL) &&
Daniel Veillard73da77e2005-08-24 14:05:37 +00004527 (node->parent->type == XML_ELEMENT_NODE))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004528 result = xmlGetLineNo(node->parent);
4529
4530 return result;
4531}
4532
Daniel Veillard2156d432004-03-04 15:59:36 +00004533#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004534/**
4535 * xmlGetNodePath:
4536 * @node: a node
4537 *
4538 * Build a structure based Path for the given node
4539 *
4540 * Returns the new path or NULL in case of error. The caller must free
4541 * the returned string
4542 */
4543xmlChar *
4544xmlGetNodePath(xmlNodePtr node)
4545{
4546 xmlNodePtr cur, tmp, next;
4547 xmlChar *buffer = NULL, *temp;
4548 size_t buf_len;
4549 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004550 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004551 const char *name;
4552 char nametemp[100];
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004553 int occur = 0, generic;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004554
4555 if (node == NULL)
4556 return (NULL);
4557
4558 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004559 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004560 if (buffer == NULL) {
4561 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004562 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004563 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004564 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004565 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004566 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004567 xmlFree(buffer);
4568 return (NULL);
4569 }
4570
4571 buffer[0] = 0;
4572 cur = node;
4573 do {
4574 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004575 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004576 occur = 0;
4577 if ((cur->type == XML_DOCUMENT_NODE) ||
4578 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4579 if (buffer[0] == '/')
4580 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004581 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004582 next = NULL;
4583 } else if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004584 generic = 0;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004585 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004586 name = (const char *) cur->name;
4587 if (cur->ns) {
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004588 if (cur->ns->prefix != NULL) {
William M. Brack13dfa872004-09-18 04:52:08 +00004589 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
Daniel Veillardaa6de472008-08-25 14:53:31 +00004590 (char *)cur->ns->prefix, (char *)cur->name);
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004591 nametemp[sizeof(nametemp) - 1] = 0;
4592 name = nametemp;
4593 } else {
4594 /*
4595 * We cannot express named elements in the default
4596 * namespace, so use "*".
4597 */
4598 generic = 1;
4599 name = "*";
Daniel Veillardaa6de472008-08-25 14:53:31 +00004600 }
Daniel Veillard8faa7832001-11-26 15:58:08 +00004601 }
4602 next = cur->parent;
4603
4604 /*
4605 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004606 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004607 */
4608 tmp = cur->prev;
4609 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004610 if ((tmp->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004611 (generic ||
Kasimier T. Buchcik43ceb1e2006-06-12 11:08:18 +00004612 (xmlStrEqual(cur->name, tmp->name) &&
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004613 ((tmp->ns == cur->ns) ||
4614 ((tmp->ns != NULL) && (cur->ns != NULL) &&
Kasimier T. Buchcik43ceb1e2006-06-12 11:08:18 +00004615 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004616 occur++;
4617 tmp = tmp->prev;
4618 }
4619 if (occur == 0) {
4620 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004621 while (tmp != NULL && occur == 0) {
4622 if ((tmp->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004623 (generic ||
Kasimier T. Buchcik43ceb1e2006-06-12 11:08:18 +00004624 (xmlStrEqual(cur->name, tmp->name) &&
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004625 ((tmp->ns == cur->ns) ||
4626 ((tmp->ns != NULL) && (cur->ns != NULL) &&
Kasimier T. Buchcik43ceb1e2006-06-12 11:08:18 +00004627 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004628 occur++;
4629 tmp = tmp->next;
4630 }
4631 if (occur != 0)
4632 occur = 1;
4633 } else
4634 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004635 } else if (cur->type == XML_COMMENT_NODE) {
4636 sep = "/";
4637 name = "comment()";
4638 next = cur->parent;
4639
4640 /*
4641 * Thumbler index computation
4642 */
4643 tmp = cur->prev;
4644 while (tmp != NULL) {
4645 if (tmp->type == XML_COMMENT_NODE)
4646 occur++;
4647 tmp = tmp->prev;
4648 }
4649 if (occur == 0) {
4650 tmp = cur->next;
4651 while (tmp != NULL && occur == 0) {
4652 if (tmp->type == XML_COMMENT_NODE)
4653 occur++;
4654 tmp = tmp->next;
4655 }
4656 if (occur != 0)
4657 occur = 1;
4658 } else
4659 occur++;
4660 } else if ((cur->type == XML_TEXT_NODE) ||
4661 (cur->type == XML_CDATA_SECTION_NODE)) {
4662 sep = "/";
4663 name = "text()";
4664 next = cur->parent;
4665
4666 /*
4667 * Thumbler index computation
4668 */
4669 tmp = cur->prev;
4670 while (tmp != NULL) {
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004671 if ((tmp->type == XML_TEXT_NODE) ||
4672 (tmp->type == XML_CDATA_SECTION_NODE))
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004673 occur++;
4674 tmp = tmp->prev;
4675 }
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004676 /*
4677 * Evaluate if this is the only text- or CDATA-section-node;
4678 * if yes, then we'll get "text()", otherwise "text()[1]".
4679 */
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004680 if (occur == 0) {
4681 tmp = cur->next;
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004682 while (tmp != NULL) {
4683 if ((tmp->type == XML_TEXT_NODE) ||
4684 (tmp->type == XML_CDATA_SECTION_NODE))
4685 {
4686 occur = 1;
4687 break;
Daniel Veillardaa6de472008-08-25 14:53:31 +00004688 }
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004689 tmp = tmp->next;
4690 }
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004691 } else
4692 occur++;
4693 } else if (cur->type == XML_PI_NODE) {
4694 sep = "/";
4695 snprintf(nametemp, sizeof(nametemp) - 1,
William M. Brack13dfa872004-09-18 04:52:08 +00004696 "processing-instruction('%s')", (char *)cur->name);
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004697 nametemp[sizeof(nametemp) - 1] = 0;
4698 name = nametemp;
4699
4700 next = cur->parent;
4701
4702 /*
4703 * Thumbler index computation
4704 */
4705 tmp = cur->prev;
4706 while (tmp != NULL) {
4707 if ((tmp->type == XML_PI_NODE) &&
4708 (xmlStrEqual(cur->name, tmp->name)))
4709 occur++;
4710 tmp = tmp->prev;
4711 }
4712 if (occur == 0) {
4713 tmp = cur->next;
4714 while (tmp != NULL && occur == 0) {
4715 if ((tmp->type == XML_PI_NODE) &&
4716 (xmlStrEqual(cur->name, tmp->name)))
4717 occur++;
4718 tmp = tmp->next;
4719 }
4720 if (occur != 0)
4721 occur = 1;
4722 } else
4723 occur++;
4724
Daniel Veillard8faa7832001-11-26 15:58:08 +00004725 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004726 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004727 name = (const char *) (((xmlAttrPtr) cur)->name);
Daniel Veillard365c8062005-07-19 11:31:55 +00004728 if (cur->ns) {
4729 if (cur->ns->prefix != NULL)
4730 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
Daniel Veillardaa6de472008-08-25 14:53:31 +00004731 (char *)cur->ns->prefix, (char *)cur->name);
Daniel Veillard365c8062005-07-19 11:31:55 +00004732 else
4733 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
Daniel Veillardaa6de472008-08-25 14:53:31 +00004734 (char *)cur->name);
Daniel Veillard365c8062005-07-19 11:31:55 +00004735 nametemp[sizeof(nametemp) - 1] = 0;
4736 name = nametemp;
4737 }
Daniel Veillard8faa7832001-11-26 15:58:08 +00004738 next = ((xmlAttrPtr) cur)->parent;
4739 } else {
4740 next = cur->parent;
4741 }
4742
4743 /*
4744 * Make sure there is enough room
4745 */
4746 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4747 buf_len =
4748 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4749 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4750 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004751 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004752 xmlFree(buf);
4753 xmlFree(buffer);
4754 return (NULL);
4755 }
4756 buffer = temp;
4757 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4758 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004759 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004760 xmlFree(buf);
4761 xmlFree(buffer);
4762 return (NULL);
4763 }
4764 buf = temp;
4765 }
4766 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004767 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004768 sep, name, (char *) buffer);
4769 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004770 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004771 sep, name, occur, (char *) buffer);
William M. Brack13dfa872004-09-18 04:52:08 +00004772 snprintf((char *) buffer, buf_len, "%s", (char *)buf);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004773 cur = next;
4774 } while (cur != NULL);
4775 xmlFree(buf);
4776 return (buffer);
4777}
Daniel Veillard652327a2003-09-29 18:02:38 +00004778#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004779
4780/**
Owen Taylor3473f882001-02-23 17:55:21 +00004781 * xmlDocGetRootElement:
4782 * @doc: the document
4783 *
4784 * Get the root element of the document (doc->children is a list
4785 * containing possibly comments, PIs, etc ...).
4786 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004787 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004788 */
4789xmlNodePtr
4790xmlDocGetRootElement(xmlDocPtr doc) {
4791 xmlNodePtr ret;
4792
4793 if (doc == NULL) return(NULL);
4794 ret = doc->children;
4795 while (ret != NULL) {
4796 if (ret->type == XML_ELEMENT_NODE)
4797 return(ret);
4798 ret = ret->next;
4799 }
4800 return(ret);
4801}
Daniel Veillardaa6de472008-08-25 14:53:31 +00004802
Daniel Veillard2156d432004-03-04 15:59:36 +00004803#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004804/**
4805 * xmlDocSetRootElement:
4806 * @doc: the document
Daniel Veillard26a45c82006-10-20 12:55:34 +00004807 * @root: the new document root element, if root is NULL no action is taken,
4808 * to remove a node from a document use xmlUnlinkNode(root) instead.
Owen Taylor3473f882001-02-23 17:55:21 +00004809 *
4810 * Set the root element of the document (doc->children is a list
4811 * containing possibly comments, PIs, etc ...).
4812 *
Daniel Veillard26a45c82006-10-20 12:55:34 +00004813 * Returns the old root element if any was found, NULL if root was NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004814 */
4815xmlNodePtr
4816xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4817 xmlNodePtr old = NULL;
4818
4819 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004820 if (root == NULL)
4821 return(NULL);
4822 xmlUnlinkNode(root);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00004823 xmlSetTreeDoc(root, doc);
Daniel Veillardc575b992002-02-08 13:28:40 +00004824 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004825 old = doc->children;
4826 while (old != NULL) {
4827 if (old->type == XML_ELEMENT_NODE)
4828 break;
4829 old = old->next;
4830 }
4831 if (old == NULL) {
4832 if (doc->children == NULL) {
4833 doc->children = root;
4834 doc->last = root;
4835 } else {
4836 xmlAddSibling(doc->children, root);
4837 }
4838 } else {
4839 xmlReplaceNode(old, root);
4840 }
4841 return(old);
4842}
Daniel Veillard2156d432004-03-04 15:59:36 +00004843#endif
Daniel Veillardaa6de472008-08-25 14:53:31 +00004844
Daniel Veillard2156d432004-03-04 15:59:36 +00004845#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004846/**
4847 * xmlNodeSetLang:
4848 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004849 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004850 *
4851 * Set the language of a node, i.e. the values of the xml:lang
4852 * attribute.
4853 */
4854void
4855xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004856 xmlNsPtr ns;
4857
Owen Taylor3473f882001-02-23 17:55:21 +00004858 if (cur == NULL) return;
4859 switch(cur->type) {
4860 case XML_TEXT_NODE:
4861 case XML_CDATA_SECTION_NODE:
4862 case XML_COMMENT_NODE:
4863 case XML_DOCUMENT_NODE:
4864 case XML_DOCUMENT_TYPE_NODE:
4865 case XML_DOCUMENT_FRAG_NODE:
4866 case XML_NOTATION_NODE:
4867 case XML_HTML_DOCUMENT_NODE:
4868 case XML_DTD_NODE:
4869 case XML_ELEMENT_DECL:
4870 case XML_ATTRIBUTE_DECL:
4871 case XML_ENTITY_DECL:
4872 case XML_PI_NODE:
4873 case XML_ENTITY_REF_NODE:
4874 case XML_ENTITY_NODE:
4875 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004876#ifdef LIBXML_DOCB_ENABLED
4877 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004878#endif
4879 case XML_XINCLUDE_START:
4880 case XML_XINCLUDE_END:
4881 return;
4882 case XML_ELEMENT_NODE:
4883 case XML_ATTRIBUTE_NODE:
4884 break;
4885 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004886 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4887 if (ns == NULL)
4888 return;
4889 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004890}
Daniel Veillard652327a2003-09-29 18:02:38 +00004891#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardaa6de472008-08-25 14:53:31 +00004892
Owen Taylor3473f882001-02-23 17:55:21 +00004893/**
4894 * xmlNodeGetLang:
4895 * @cur: the node being checked
4896 *
4897 * Searches the language of a node, i.e. the values of the xml:lang
4898 * attribute or the one carried by the nearest ancestor.
4899 *
4900 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004901 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004902 */
4903xmlChar *
4904xmlNodeGetLang(xmlNodePtr cur) {
4905 xmlChar *lang;
4906
4907 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004908 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004909 if (lang != NULL)
4910 return(lang);
4911 cur = cur->parent;
4912 }
4913 return(NULL);
4914}
Daniel Veillardaa6de472008-08-25 14:53:31 +00004915
Owen Taylor3473f882001-02-23 17:55:21 +00004916
Daniel Veillard652327a2003-09-29 18:02:38 +00004917#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004918/**
4919 * xmlNodeSetSpacePreserve:
4920 * @cur: the node being changed
4921 * @val: the xml:space value ("0": default, 1: "preserve")
4922 *
4923 * Set (or reset) the space preserving behaviour of a node, i.e. the
4924 * value of the xml:space attribute.
4925 */
4926void
4927xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004928 xmlNsPtr ns;
4929
Owen Taylor3473f882001-02-23 17:55:21 +00004930 if (cur == NULL) return;
4931 switch(cur->type) {
4932 case XML_TEXT_NODE:
4933 case XML_CDATA_SECTION_NODE:
4934 case XML_COMMENT_NODE:
4935 case XML_DOCUMENT_NODE:
4936 case XML_DOCUMENT_TYPE_NODE:
4937 case XML_DOCUMENT_FRAG_NODE:
4938 case XML_NOTATION_NODE:
4939 case XML_HTML_DOCUMENT_NODE:
4940 case XML_DTD_NODE:
4941 case XML_ELEMENT_DECL:
4942 case XML_ATTRIBUTE_DECL:
4943 case XML_ENTITY_DECL:
4944 case XML_PI_NODE:
4945 case XML_ENTITY_REF_NODE:
4946 case XML_ENTITY_NODE:
4947 case XML_NAMESPACE_DECL:
4948 case XML_XINCLUDE_START:
4949 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004950#ifdef LIBXML_DOCB_ENABLED
4951 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004952#endif
4953 return;
4954 case XML_ELEMENT_NODE:
4955 case XML_ATTRIBUTE_NODE:
4956 break;
4957 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004958 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4959 if (ns == NULL)
4960 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004961 switch (val) {
4962 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004963 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004964 break;
4965 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004966 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004967 break;
4968 }
4969}
Daniel Veillard652327a2003-09-29 18:02:38 +00004970#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004971
4972/**
4973 * xmlNodeGetSpacePreserve:
4974 * @cur: the node being checked
4975 *
4976 * Searches the space preserving behaviour of a node, i.e. the values
4977 * of the xml:space attribute or the one carried by the nearest
4978 * ancestor.
4979 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004980 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004981 */
4982int
4983xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4984 xmlChar *space;
4985
4986 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004987 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004988 if (space != NULL) {
4989 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4990 xmlFree(space);
4991 return(1);
4992 }
4993 if (xmlStrEqual(space, BAD_CAST "default")) {
4994 xmlFree(space);
4995 return(0);
4996 }
4997 xmlFree(space);
4998 }
4999 cur = cur->parent;
5000 }
5001 return(-1);
5002}
Daniel Veillardaa6de472008-08-25 14:53:31 +00005003
Daniel Veillard652327a2003-09-29 18:02:38 +00005004#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005005/**
5006 * xmlNodeSetName:
5007 * @cur: the node being changed
5008 * @name: the new tag name
5009 *
5010 * Set (or reset) the name of a node.
5011 */
5012void
5013xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00005014 xmlDocPtr doc;
5015 xmlDictPtr dict;
5016
Owen Taylor3473f882001-02-23 17:55:21 +00005017 if (cur == NULL) return;
5018 if (name == NULL) return;
5019 switch(cur->type) {
5020 case XML_TEXT_NODE:
5021 case XML_CDATA_SECTION_NODE:
5022 case XML_COMMENT_NODE:
5023 case XML_DOCUMENT_TYPE_NODE:
5024 case XML_DOCUMENT_FRAG_NODE:
5025 case XML_NOTATION_NODE:
5026 case XML_HTML_DOCUMENT_NODE:
5027 case XML_NAMESPACE_DECL:
5028 case XML_XINCLUDE_START:
5029 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005030#ifdef LIBXML_DOCB_ENABLED
5031 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005032#endif
5033 return;
5034 case XML_ELEMENT_NODE:
5035 case XML_ATTRIBUTE_NODE:
5036 case XML_PI_NODE:
5037 case XML_ENTITY_REF_NODE:
5038 case XML_ENTITY_NODE:
5039 case XML_DTD_NODE:
5040 case XML_DOCUMENT_NODE:
5041 case XML_ELEMENT_DECL:
5042 case XML_ATTRIBUTE_DECL:
5043 case XML_ENTITY_DECL:
5044 break;
5045 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00005046 doc = cur->doc;
5047 if (doc != NULL)
5048 dict = doc->dict;
5049 else
5050 dict = NULL;
5051 if (dict != NULL) {
5052 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
5053 xmlFree((xmlChar *) cur->name);
5054 cur->name = xmlDictLookup(dict, name, -1);
5055 } else {
5056 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
5057 cur->name = xmlStrdup(name);
5058 }
Owen Taylor3473f882001-02-23 17:55:21 +00005059}
Daniel Veillard2156d432004-03-04 15:59:36 +00005060#endif
Daniel Veillardaa6de472008-08-25 14:53:31 +00005061
Daniel Veillard2156d432004-03-04 15:59:36 +00005062#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005063/**
5064 * xmlNodeSetBase:
5065 * @cur: the node being changed
5066 * @uri: the new base URI
5067 *
5068 * Set (or reset) the base URI of a node, i.e. the value of the
5069 * xml:base attribute.
5070 */
5071void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00005072xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00005073 xmlNsPtr ns;
Martin Trappelf3703102010-01-22 12:08:00 +01005074 xmlChar* fixed;
Daniel Veillardcfa0d812002-01-17 08:46:58 +00005075
Owen Taylor3473f882001-02-23 17:55:21 +00005076 if (cur == NULL) return;
5077 switch(cur->type) {
5078 case XML_TEXT_NODE:
5079 case XML_CDATA_SECTION_NODE:
5080 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005081 case XML_DOCUMENT_TYPE_NODE:
5082 case XML_DOCUMENT_FRAG_NODE:
5083 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005084 case XML_DTD_NODE:
5085 case XML_ELEMENT_DECL:
5086 case XML_ATTRIBUTE_DECL:
5087 case XML_ENTITY_DECL:
5088 case XML_PI_NODE:
5089 case XML_ENTITY_REF_NODE:
5090 case XML_ENTITY_NODE:
5091 case XML_NAMESPACE_DECL:
5092 case XML_XINCLUDE_START:
5093 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00005094 return;
5095 case XML_ELEMENT_NODE:
5096 case XML_ATTRIBUTE_NODE:
5097 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00005098 case XML_DOCUMENT_NODE:
5099#ifdef LIBXML_DOCB_ENABLED
5100 case XML_DOCB_DOCUMENT_NODE:
5101#endif
5102 case XML_HTML_DOCUMENT_NODE: {
5103 xmlDocPtr doc = (xmlDocPtr) cur;
5104
5105 if (doc->URL != NULL)
5106 xmlFree((xmlChar *) doc->URL);
5107 if (uri == NULL)
5108 doc->URL = NULL;
5109 else
Daniel Veillardb8efdda2006-10-10 12:37:14 +00005110 doc->URL = xmlPathToURI(uri);
Daniel Veillard4cbe4702002-05-05 06:57:27 +00005111 return;
5112 }
Owen Taylor3473f882001-02-23 17:55:21 +00005113 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00005114
Daniel Veillardcfa0d812002-01-17 08:46:58 +00005115 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
5116 if (ns == NULL)
5117 return;
Daniel Veillardb8efdda2006-10-10 12:37:14 +00005118 fixed = xmlPathToURI(uri);
5119 if (fixed != NULL) {
5120 xmlSetNsProp(cur, ns, BAD_CAST "base", fixed);
Martin Trappelf3703102010-01-22 12:08:00 +01005121 xmlFree(fixed);
Daniel Veillardb8efdda2006-10-10 12:37:14 +00005122 } else {
5123 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
5124 }
Owen Taylor3473f882001-02-23 17:55:21 +00005125}
Daniel Veillard652327a2003-09-29 18:02:38 +00005126#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005127
5128/**
Owen Taylor3473f882001-02-23 17:55:21 +00005129 * xmlNodeGetBase:
5130 * @doc: the document the node pertains to
5131 * @cur: the node being checked
5132 *
5133 * Searches for the BASE URL. The code should work on both XML
5134 * and HTML document even if base mechanisms are completely different.
5135 * It returns the base as defined in RFC 2396 sections
5136 * 5.1.1. Base URI within Document Content
5137 * and
5138 * 5.1.2. Base URI from the Encapsulating Entity
5139 * However it does not return the document base (5.1.3), use
Daniel Veillarde4d18492010-03-09 11:12:30 +01005140 * doc->URL in this case
Owen Taylor3473f882001-02-23 17:55:21 +00005141 *
5142 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005143 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005144 */
5145xmlChar *
5146xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00005147 xmlChar *oldbase = NULL;
5148 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00005149
Daniel Veillardaa6de472008-08-25 14:53:31 +00005150 if ((cur == NULL) && (doc == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00005151 return(NULL);
Daniel Veillardaa6de472008-08-25 14:53:31 +00005152 if (doc == NULL) doc = cur->doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005153 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
5154 cur = doc->children;
5155 while ((cur != NULL) && (cur->name != NULL)) {
5156 if (cur->type != XML_ELEMENT_NODE) {
5157 cur = cur->next;
5158 continue;
5159 }
5160 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
5161 cur = cur->children;
5162 continue;
5163 }
5164 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
5165 cur = cur->children;
5166 continue;
5167 }
5168 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
5169 return(xmlGetProp(cur, BAD_CAST "href"));
5170 }
5171 cur = cur->next;
5172 }
5173 return(NULL);
5174 }
5175 while (cur != NULL) {
5176 if (cur->type == XML_ENTITY_DECL) {
5177 xmlEntityPtr ent = (xmlEntityPtr) cur;
5178 return(xmlStrdup(ent->URI));
5179 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00005180 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00005181 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00005182 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00005183 if (oldbase != NULL) {
5184 newbase = xmlBuildURI(oldbase, base);
5185 if (newbase != NULL) {
5186 xmlFree(oldbase);
5187 xmlFree(base);
5188 oldbase = newbase;
5189 } else {
5190 xmlFree(oldbase);
5191 xmlFree(base);
5192 return(NULL);
5193 }
5194 } else {
5195 oldbase = base;
5196 }
5197 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
5198 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
5199 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
5200 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00005201 }
5202 }
Owen Taylor3473f882001-02-23 17:55:21 +00005203 cur = cur->parent;
5204 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00005205 if ((doc != NULL) && (doc->URL != NULL)) {
5206 if (oldbase == NULL)
5207 return(xmlStrdup(doc->URL));
5208 newbase = xmlBuildURI(oldbase, doc->URL);
5209 xmlFree(oldbase);
5210 return(newbase);
5211 }
5212 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00005213}
Daniel Veillardaa6de472008-08-25 14:53:31 +00005214
Owen Taylor3473f882001-02-23 17:55:21 +00005215/**
Daniel Veillard78697292003-10-19 20:44:43 +00005216 * xmlNodeBufGetContent:
5217 * @buffer: a buffer
5218 * @cur: the node being read
5219 *
5220 * Read the value of a node @cur, this can be either the text carried
5221 * directly by this node if it's a TEXT node or the aggregate string
5222 * of the values carried by this node child's (TEXT and ENTITY_REF).
5223 * Entity references are substituted.
5224 * Fills up the buffer @buffer with this value
Daniel Veillardaa6de472008-08-25 14:53:31 +00005225 *
Daniel Veillard78697292003-10-19 20:44:43 +00005226 * Returns 0 in case of success and -1 in case of error.
5227 */
5228int
5229xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
5230{
5231 if ((cur == NULL) || (buffer == NULL)) return(-1);
5232 switch (cur->type) {
5233 case XML_CDATA_SECTION_NODE:
5234 case XML_TEXT_NODE:
5235 xmlBufferCat(buffer, cur->content);
5236 break;
5237 case XML_DOCUMENT_FRAG_NODE:
5238 case XML_ELEMENT_NODE:{
5239 xmlNodePtr tmp = cur;
5240
5241 while (tmp != NULL) {
5242 switch (tmp->type) {
5243 case XML_CDATA_SECTION_NODE:
5244 case XML_TEXT_NODE:
5245 if (tmp->content != NULL)
5246 xmlBufferCat(buffer, tmp->content);
5247 break;
5248 case XML_ENTITY_REF_NODE:
Rob Richards77b92ff2005-12-20 15:55:14 +00005249 xmlNodeBufGetContent(buffer, tmp);
5250 break;
Daniel Veillard78697292003-10-19 20:44:43 +00005251 default:
5252 break;
5253 }
5254 /*
5255 * Skip to next node
5256 */
5257 if (tmp->children != NULL) {
5258 if (tmp->children->type != XML_ENTITY_DECL) {
5259 tmp = tmp->children;
5260 continue;
5261 }
5262 }
5263 if (tmp == cur)
5264 break;
5265
5266 if (tmp->next != NULL) {
5267 tmp = tmp->next;
5268 continue;
5269 }
5270
5271 do {
5272 tmp = tmp->parent;
5273 if (tmp == NULL)
5274 break;
5275 if (tmp == cur) {
5276 tmp = NULL;
5277 break;
5278 }
5279 if (tmp->next != NULL) {
5280 tmp = tmp->next;
5281 break;
5282 }
5283 } while (tmp != NULL);
5284 }
5285 break;
5286 }
5287 case XML_ATTRIBUTE_NODE:{
5288 xmlAttrPtr attr = (xmlAttrPtr) cur;
5289 xmlNodePtr tmp = attr->children;
5290
5291 while (tmp != NULL) {
5292 if (tmp->type == XML_TEXT_NODE)
5293 xmlBufferCat(buffer, tmp->content);
5294 else
5295 xmlNodeBufGetContent(buffer, tmp);
5296 tmp = tmp->next;
5297 }
5298 break;
5299 }
5300 case XML_COMMENT_NODE:
5301 case XML_PI_NODE:
5302 xmlBufferCat(buffer, cur->content);
5303 break;
5304 case XML_ENTITY_REF_NODE:{
5305 xmlEntityPtr ent;
5306 xmlNodePtr tmp;
5307
5308 /* lookup entity declaration */
5309 ent = xmlGetDocEntity(cur->doc, cur->name);
5310 if (ent == NULL)
5311 return(-1);
5312
5313 /* an entity content can be any "well balanced chunk",
5314 * i.e. the result of the content [43] production:
5315 * http://www.w3.org/TR/REC-xml#NT-content
5316 * -> we iterate through child nodes and recursive call
5317 * xmlNodeGetContent() which handles all possible node types */
5318 tmp = ent->children;
5319 while (tmp) {
5320 xmlNodeBufGetContent(buffer, tmp);
5321 tmp = tmp->next;
5322 }
5323 break;
5324 }
5325 case XML_ENTITY_NODE:
5326 case XML_DOCUMENT_TYPE_NODE:
5327 case XML_NOTATION_NODE:
5328 case XML_DTD_NODE:
5329 case XML_XINCLUDE_START:
5330 case XML_XINCLUDE_END:
5331 break;
5332 case XML_DOCUMENT_NODE:
5333#ifdef LIBXML_DOCB_ENABLED
5334 case XML_DOCB_DOCUMENT_NODE:
5335#endif
5336 case XML_HTML_DOCUMENT_NODE:
5337 cur = cur->children;
5338 while (cur!= NULL) {
5339 if ((cur->type == XML_ELEMENT_NODE) ||
5340 (cur->type == XML_TEXT_NODE) ||
5341 (cur->type == XML_CDATA_SECTION_NODE)) {
5342 xmlNodeBufGetContent(buffer, cur);
5343 }
5344 cur = cur->next;
5345 }
5346 break;
5347 case XML_NAMESPACE_DECL:
5348 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
5349 break;
5350 case XML_ELEMENT_DECL:
5351 case XML_ATTRIBUTE_DECL:
5352 case XML_ENTITY_DECL:
5353 break;
5354 }
5355 return(0);
5356}
5357/**
Owen Taylor3473f882001-02-23 17:55:21 +00005358 * xmlNodeGetContent:
5359 * @cur: the node being read
5360 *
5361 * Read the value of a node, this can be either the text carried
5362 * directly by this node if it's a TEXT node or the aggregate string
5363 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00005364 * Entity references are substituted.
5365 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005366 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005367 */
5368xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00005369xmlNodeGetContent(xmlNodePtr cur)
5370{
5371 if (cur == NULL)
5372 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005373 switch (cur->type) {
5374 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005375 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00005376 xmlBufferPtr buffer;
5377 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00005378
Daniel Veillard814a76d2003-01-23 18:24:20 +00005379 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00005380 if (buffer == NULL)
5381 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00005382 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005383 ret = buffer->content;
5384 buffer->content = NULL;
5385 xmlBufferFree(buffer);
5386 return (ret);
5387 }
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00005388 case XML_ATTRIBUTE_NODE:
5389 return(xmlGetPropNodeValueInternal((xmlAttrPtr) cur));
Owen Taylor3473f882001-02-23 17:55:21 +00005390 case XML_COMMENT_NODE:
5391 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005392 if (cur->content != NULL)
5393 return (xmlStrdup(cur->content));
5394 return (NULL);
5395 case XML_ENTITY_REF_NODE:{
5396 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00005397 xmlBufferPtr buffer;
5398 xmlChar *ret;
5399
5400 /* lookup entity declaration */
5401 ent = xmlGetDocEntity(cur->doc, cur->name);
5402 if (ent == NULL)
5403 return (NULL);
5404
5405 buffer = xmlBufferCreate();
5406 if (buffer == NULL)
5407 return (NULL);
5408
Daniel Veillardc4696922003-10-19 21:47:14 +00005409 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005410
5411 ret = buffer->content;
5412 buffer->content = NULL;
5413 xmlBufferFree(buffer);
5414 return (ret);
5415 }
Owen Taylor3473f882001-02-23 17:55:21 +00005416 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005417 case XML_DOCUMENT_TYPE_NODE:
5418 case XML_NOTATION_NODE:
5419 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005420 case XML_XINCLUDE_START:
5421 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00005422 return (NULL);
5423 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005424#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005425 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005426#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005427 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00005428 xmlBufferPtr buffer;
5429 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005430
Daniel Veillardc4696922003-10-19 21:47:14 +00005431 buffer = xmlBufferCreate();
5432 if (buffer == NULL)
5433 return (NULL);
5434
5435 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5436
5437 ret = buffer->content;
5438 buffer->content = NULL;
5439 xmlBufferFree(buffer);
5440 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005441 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005442 case XML_NAMESPACE_DECL: {
5443 xmlChar *tmp;
5444
5445 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5446 return (tmp);
5447 }
Owen Taylor3473f882001-02-23 17:55:21 +00005448 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005449 /* TODO !!! */
5450 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005451 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005452 /* TODO !!! */
5453 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005454 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005455 /* TODO !!! */
5456 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005457 case XML_CDATA_SECTION_NODE:
5458 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005459 if (cur->content != NULL)
5460 return (xmlStrdup(cur->content));
5461 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005462 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005463 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005464}
Daniel Veillard652327a2003-09-29 18:02:38 +00005465
Owen Taylor3473f882001-02-23 17:55:21 +00005466/**
5467 * xmlNodeSetContent:
5468 * @cur: the node being modified
5469 * @content: the new value of the content
5470 *
5471 * Replace the content of a node.
Daniel Veillard0e05f4c2006-11-01 15:33:04 +00005472 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
5473 * references, but XML special chars need to be escaped first by using
5474 * xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars().
Owen Taylor3473f882001-02-23 17:55:21 +00005475 */
5476void
5477xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5478 if (cur == NULL) {
5479#ifdef DEBUG_TREE
5480 xmlGenericError(xmlGenericErrorContext,
5481 "xmlNodeSetContent : node == NULL\n");
5482#endif
5483 return;
5484 }
5485 switch (cur->type) {
5486 case XML_DOCUMENT_FRAG_NODE:
5487 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005488 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005489 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5490 cur->children = xmlStringGetNodeList(cur->doc, content);
5491 UPDATE_LAST_CHILD_AND_PARENT(cur)
5492 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005493 case XML_TEXT_NODE:
5494 case XML_CDATA_SECTION_NODE:
5495 case XML_ENTITY_REF_NODE:
5496 case XML_ENTITY_NODE:
5497 case XML_PI_NODE:
5498 case XML_COMMENT_NODE:
Daniel Veillard8874b942005-08-25 13:19:21 +00005499 if ((cur->content != NULL) &&
5500 (cur->content != (xmlChar *) &(cur->properties))) {
William M. Brack7762bb12004-01-04 14:49:01 +00005501 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
Daniel Veillardc587bce2005-05-10 15:28:08 +00005502 (xmlDictOwns(cur->doc->dict, cur->content))))
William M. Brack7762bb12004-01-04 14:49:01 +00005503 xmlFree(cur->content);
Daniel Veillardaa6de472008-08-25 14:53:31 +00005504 }
Owen Taylor3473f882001-02-23 17:55:21 +00005505 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5506 cur->last = cur->children = NULL;
5507 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005508 cur->content = xmlStrdup(content);
Daniel Veillardaa6de472008-08-25 14:53:31 +00005509 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005510 cur->content = NULL;
Daniel Veillard8874b942005-08-25 13:19:21 +00005511 cur->properties = NULL;
5512 cur->nsDef = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00005513 break;
5514 case XML_DOCUMENT_NODE:
5515 case XML_HTML_DOCUMENT_NODE:
5516 case XML_DOCUMENT_TYPE_NODE:
5517 case XML_XINCLUDE_START:
5518 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005519#ifdef LIBXML_DOCB_ENABLED
5520 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005521#endif
5522 break;
5523 case XML_NOTATION_NODE:
5524 break;
5525 case XML_DTD_NODE:
5526 break;
5527 case XML_NAMESPACE_DECL:
5528 break;
5529 case XML_ELEMENT_DECL:
5530 /* TODO !!! */
5531 break;
5532 case XML_ATTRIBUTE_DECL:
5533 /* TODO !!! */
5534 break;
5535 case XML_ENTITY_DECL:
5536 /* TODO !!! */
5537 break;
5538 }
5539}
5540
Daniel Veillard652327a2003-09-29 18:02:38 +00005541#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005542/**
5543 * xmlNodeSetContentLen:
5544 * @cur: the node being modified
5545 * @content: the new value of the content
5546 * @len: the size of @content
5547 *
5548 * Replace the content of a node.
Daniel Veillard0e05f4c2006-11-01 15:33:04 +00005549 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
5550 * references, but XML special chars need to be escaped first by using
5551 * xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars().
Owen Taylor3473f882001-02-23 17:55:21 +00005552 */
5553void
5554xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5555 if (cur == NULL) {
5556#ifdef DEBUG_TREE
5557 xmlGenericError(xmlGenericErrorContext,
5558 "xmlNodeSetContentLen : node == NULL\n");
5559#endif
5560 return;
5561 }
5562 switch (cur->type) {
5563 case XML_DOCUMENT_FRAG_NODE:
5564 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005565 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005566 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5567 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5568 UPDATE_LAST_CHILD_AND_PARENT(cur)
5569 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005570 case XML_TEXT_NODE:
5571 case XML_CDATA_SECTION_NODE:
5572 case XML_ENTITY_REF_NODE:
5573 case XML_ENTITY_NODE:
5574 case XML_PI_NODE:
5575 case XML_COMMENT_NODE:
5576 case XML_NOTATION_NODE:
Daniel Veillard8874b942005-08-25 13:19:21 +00005577 if ((cur->content != NULL) &&
5578 (cur->content != (xmlChar *) &(cur->properties))) {
5579 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5580 (xmlDictOwns(cur->doc->dict, cur->content))))
5581 xmlFree(cur->content);
Daniel Veillardaa6de472008-08-25 14:53:31 +00005582 }
Owen Taylor3473f882001-02-23 17:55:21 +00005583 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5584 cur->children = cur->last = NULL;
5585 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005586 cur->content = xmlStrndup(content, len);
Daniel Veillardaa6de472008-08-25 14:53:31 +00005587 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005588 cur->content = NULL;
Daniel Veillard8874b942005-08-25 13:19:21 +00005589 cur->properties = NULL;
5590 cur->nsDef = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00005591 break;
5592 case XML_DOCUMENT_NODE:
5593 case XML_DTD_NODE:
5594 case XML_HTML_DOCUMENT_NODE:
5595 case XML_DOCUMENT_TYPE_NODE:
5596 case XML_NAMESPACE_DECL:
5597 case XML_XINCLUDE_START:
5598 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005599#ifdef LIBXML_DOCB_ENABLED
5600 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005601#endif
5602 break;
5603 case XML_ELEMENT_DECL:
5604 /* TODO !!! */
5605 break;
5606 case XML_ATTRIBUTE_DECL:
5607 /* TODO !!! */
5608 break;
5609 case XML_ENTITY_DECL:
5610 /* TODO !!! */
5611 break;
5612 }
5613}
Daniel Veillard652327a2003-09-29 18:02:38 +00005614#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005615
5616/**
5617 * xmlNodeAddContentLen:
5618 * @cur: the node being modified
5619 * @content: extra content
5620 * @len: the size of @content
Daniel Veillardaa6de472008-08-25 14:53:31 +00005621 *
Owen Taylor3473f882001-02-23 17:55:21 +00005622 * Append the extra substring to the node content.
Daniel Veillard0e05f4c2006-11-01 15:33:04 +00005623 * NOTE: In contrast to xmlNodeSetContentLen(), @content is supposed to be
5624 * raw text, so unescaped XML special chars are allowed, entity
5625 * references are not supported.
Owen Taylor3473f882001-02-23 17:55:21 +00005626 */
5627void
5628xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5629 if (cur == NULL) {
5630#ifdef DEBUG_TREE
5631 xmlGenericError(xmlGenericErrorContext,
5632 "xmlNodeAddContentLen : node == NULL\n");
5633#endif
5634 return;
5635 }
5636 if (len <= 0) return;
5637 switch (cur->type) {
5638 case XML_DOCUMENT_FRAG_NODE:
5639 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005640 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005641
Daniel Veillard7db37732001-07-12 01:20:08 +00005642 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005643 newNode = xmlNewTextLen(content, len);
5644 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005645 tmp = xmlAddChild(cur, newNode);
5646 if (tmp != newNode)
5647 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005648 if ((last != NULL) && (last->next == newNode)) {
5649 xmlTextMerge(last, newNode);
5650 }
5651 }
5652 break;
5653 }
5654 case XML_ATTRIBUTE_NODE:
5655 break;
5656 case XML_TEXT_NODE:
5657 case XML_CDATA_SECTION_NODE:
5658 case XML_ENTITY_REF_NODE:
5659 case XML_ENTITY_NODE:
5660 case XML_PI_NODE:
5661 case XML_COMMENT_NODE:
5662 case XML_NOTATION_NODE:
5663 if (content != NULL) {
Daniel Veillard8874b942005-08-25 13:19:21 +00005664 if ((cur->content == (xmlChar *) &(cur->properties)) ||
5665 ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5666 xmlDictOwns(cur->doc->dict, cur->content))) {
5667 cur->content = xmlStrncatNew(cur->content, content, len);
5668 cur->properties = NULL;
5669 cur->nsDef = NULL;
William M. Brack7762bb12004-01-04 14:49:01 +00005670 break;
5671 }
Owen Taylor3473f882001-02-23 17:55:21 +00005672 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005673 }
5674 case XML_DOCUMENT_NODE:
5675 case XML_DTD_NODE:
5676 case XML_HTML_DOCUMENT_NODE:
5677 case XML_DOCUMENT_TYPE_NODE:
5678 case XML_NAMESPACE_DECL:
5679 case XML_XINCLUDE_START:
5680 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005681#ifdef LIBXML_DOCB_ENABLED
5682 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005683#endif
5684 break;
5685 case XML_ELEMENT_DECL:
5686 case XML_ATTRIBUTE_DECL:
5687 case XML_ENTITY_DECL:
5688 break;
5689 }
5690}
5691
5692/**
5693 * xmlNodeAddContent:
5694 * @cur: the node being modified
5695 * @content: extra content
Daniel Veillardaa6de472008-08-25 14:53:31 +00005696 *
Owen Taylor3473f882001-02-23 17:55:21 +00005697 * Append the extra substring to the node content.
Daniel Veillard0e05f4c2006-11-01 15:33:04 +00005698 * NOTE: In contrast to xmlNodeSetContent(), @content is supposed to be
5699 * raw text, so unescaped XML special chars are allowed, entity
5700 * references are not supported.
Owen Taylor3473f882001-02-23 17:55:21 +00005701 */
5702void
5703xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5704 int len;
5705
5706 if (cur == NULL) {
5707#ifdef DEBUG_TREE
5708 xmlGenericError(xmlGenericErrorContext,
5709 "xmlNodeAddContent : node == NULL\n");
5710#endif
5711 return;
5712 }
5713 if (content == NULL) return;
5714 len = xmlStrlen(content);
5715 xmlNodeAddContentLen(cur, content, len);
5716}
5717
5718/**
5719 * xmlTextMerge:
5720 * @first: the first text node
5721 * @second: the second text node being merged
Daniel Veillardaa6de472008-08-25 14:53:31 +00005722 *
Owen Taylor3473f882001-02-23 17:55:21 +00005723 * Merge two text nodes into one
5724 * Returns the first text node augmented
5725 */
5726xmlNodePtr
5727xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5728 if (first == NULL) return(second);
5729 if (second == NULL) return(first);
5730 if (first->type != XML_TEXT_NODE) return(first);
5731 if (second->type != XML_TEXT_NODE) return(first);
5732 if (second->name != first->name)
5733 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005734 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005735 xmlUnlinkNode(second);
5736 xmlFreeNode(second);
5737 return(first);
5738}
5739
Daniel Veillardf1a27c62006-10-13 22:33:03 +00005740#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005741/**
5742 * xmlGetNsList:
5743 * @doc: the document
5744 * @node: the current node
5745 *
5746 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005747 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005748 * that need to be freed by the caller or NULL if no
5749 * namespace if defined
5750 */
5751xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005752xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5753{
Owen Taylor3473f882001-02-23 17:55:21 +00005754 xmlNsPtr cur;
5755 xmlNsPtr *ret = NULL;
5756 int nbns = 0;
5757 int maxns = 10;
5758 int i;
5759
5760 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005761 if (node->type == XML_ELEMENT_NODE) {
5762 cur = node->nsDef;
5763 while (cur != NULL) {
5764 if (ret == NULL) {
5765 ret =
5766 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5767 sizeof(xmlNsPtr));
5768 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005769 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005770 return (NULL);
5771 }
5772 ret[nbns] = NULL;
5773 }
5774 for (i = 0; i < nbns; i++) {
5775 if ((cur->prefix == ret[i]->prefix) ||
5776 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5777 break;
5778 }
5779 if (i >= nbns) {
5780 if (nbns >= maxns) {
5781 maxns *= 2;
5782 ret = (xmlNsPtr *) xmlRealloc(ret,
5783 (maxns +
5784 1) *
5785 sizeof(xmlNsPtr));
5786 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005787 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005788 return (NULL);
5789 }
5790 }
5791 ret[nbns++] = cur;
5792 ret[nbns] = NULL;
5793 }
Owen Taylor3473f882001-02-23 17:55:21 +00005794
Daniel Veillard77044732001-06-29 21:31:07 +00005795 cur = cur->next;
5796 }
5797 }
5798 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005799 }
Daniel Veillard77044732001-06-29 21:31:07 +00005800 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005801}
Daniel Veillard652327a2003-09-29 18:02:38 +00005802#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005803
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00005804/*
5805* xmlTreeEnsureXMLDecl:
5806* @doc: the doc
Daniel Veillardaa6de472008-08-25 14:53:31 +00005807*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00005808* Ensures that there is an XML namespace declaration on the doc.
Daniel Veillardaa6de472008-08-25 14:53:31 +00005809*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00005810* Returns the XML ns-struct or NULL on API and internal errors.
5811*/
5812static xmlNsPtr
5813xmlTreeEnsureXMLDecl(xmlDocPtr doc)
5814{
5815 if (doc == NULL)
5816 return (NULL);
5817 if (doc->oldNs != NULL)
5818 return (doc->oldNs);
5819 {
5820 xmlNsPtr ns;
5821 ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5822 if (ns == NULL) {
5823 xmlTreeErrMemory(
5824 "allocating the XML namespace");
5825 return (NULL);
5826 }
5827 memset(ns, 0, sizeof(xmlNs));
5828 ns->type = XML_LOCAL_NAMESPACE;
Daniel Veillardaa6de472008-08-25 14:53:31 +00005829 ns->href = xmlStrdup(XML_XML_NAMESPACE);
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00005830 ns->prefix = xmlStrdup((const xmlChar *)"xml");
5831 doc->oldNs = ns;
5832 return (ns);
5833 }
5834}
5835
Owen Taylor3473f882001-02-23 17:55:21 +00005836/**
5837 * xmlSearchNs:
5838 * @doc: the document
5839 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005840 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005841 *
5842 * Search a Ns registered under a given name space for a document.
5843 * recurse on the parents until it finds the defined namespace
5844 * or return NULL otherwise.
5845 * @nameSpace can be NULL, this is a search for the default namespace.
5846 * We don't allow to cross entities boundaries. If you don't declare
5847 * the namespace within those you will be in troubles !!! A warning
5848 * is generated to cover this case.
5849 *
5850 * Returns the namespace pointer or NULL.
5851 */
5852xmlNsPtr
5853xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00005854
Owen Taylor3473f882001-02-23 17:55:21 +00005855 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005856 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005857
5858 if (node == NULL) return(NULL);
5859 if ((nameSpace != NULL) &&
5860 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005861 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5862 /*
5863 * The XML-1.0 namespace is normally held on the root
5864 * element. In this case exceptionally create it on the
5865 * node element.
5866 */
5867 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5868 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005869 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005870 return(NULL);
5871 }
5872 memset(cur, 0, sizeof(xmlNs));
5873 cur->type = XML_LOCAL_NAMESPACE;
Daniel Veillardaa6de472008-08-25 14:53:31 +00005874 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5875 cur->prefix = xmlStrdup((const xmlChar *)"xml");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005876 cur->next = node->nsDef;
5877 node->nsDef = cur;
5878 return(cur);
5879 }
Daniel Veillard11ce4002006-03-10 00:36:23 +00005880 if (doc == NULL) {
5881 doc = node->doc;
5882 if (doc == NULL)
5883 return(NULL);
5884 }
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00005885 /*
5886 * Return the XML namespace declaration held by the doc.
5887 */
5888 if (doc->oldNs == NULL)
5889 return(xmlTreeEnsureXMLDecl(doc));
5890 else
5891 return(doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005892 }
5893 while (node != NULL) {
5894 if ((node->type == XML_ENTITY_REF_NODE) ||
5895 (node->type == XML_ENTITY_NODE) ||
5896 (node->type == XML_ENTITY_DECL))
5897 return(NULL);
5898 if (node->type == XML_ELEMENT_NODE) {
5899 cur = node->nsDef;
5900 while (cur != NULL) {
5901 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5902 (cur->href != NULL))
5903 return(cur);
5904 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5905 (cur->href != NULL) &&
5906 (xmlStrEqual(cur->prefix, nameSpace)))
5907 return(cur);
5908 cur = cur->next;
5909 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00005910 if (orig != node) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005911 cur = node->ns;
5912 if (cur != NULL) {
5913 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5914 (cur->href != NULL))
5915 return(cur);
5916 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5917 (cur->href != NULL) &&
5918 (xmlStrEqual(cur->prefix, nameSpace)))
5919 return(cur);
5920 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00005921 }
Owen Taylor3473f882001-02-23 17:55:21 +00005922 }
5923 node = node->parent;
5924 }
5925 return(NULL);
5926}
5927
5928/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005929 * xmlNsInScope:
5930 * @doc: the document
5931 * @node: the current node
5932 * @ancestor: the ancestor carrying the namespace
5933 * @prefix: the namespace prefix
5934 *
5935 * Verify that the given namespace held on @ancestor is still in scope
5936 * on node.
Daniel Veillardaa6de472008-08-25 14:53:31 +00005937 *
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005938 * Returns 1 if true, 0 if false and -1 in case of error.
5939 */
5940static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005941xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5942 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005943{
5944 xmlNsPtr tst;
5945
5946 while ((node != NULL) && (node != ancestor)) {
5947 if ((node->type == XML_ENTITY_REF_NODE) ||
5948 (node->type == XML_ENTITY_NODE) ||
5949 (node->type == XML_ENTITY_DECL))
5950 return (-1);
5951 if (node->type == XML_ELEMENT_NODE) {
5952 tst = node->nsDef;
5953 while (tst != NULL) {
5954 if ((tst->prefix == NULL)
5955 && (prefix == NULL))
5956 return (0);
5957 if ((tst->prefix != NULL)
5958 && (prefix != NULL)
5959 && (xmlStrEqual(tst->prefix, prefix)))
5960 return (0);
5961 tst = tst->next;
5962 }
5963 }
5964 node = node->parent;
5965 }
5966 if (node != ancestor)
5967 return (-1);
5968 return (1);
5969}
Daniel Veillardaa6de472008-08-25 14:53:31 +00005970
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005971/**
Owen Taylor3473f882001-02-23 17:55:21 +00005972 * xmlSearchNsByHref:
5973 * @doc: the document
5974 * @node: the current node
5975 * @href: the namespace value
5976 *
5977 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5978 * the defined namespace or return NULL otherwise.
5979 * Returns the namespace pointer or NULL.
5980 */
5981xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005982xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5983{
Owen Taylor3473f882001-02-23 17:55:21 +00005984 xmlNsPtr cur;
5985 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005986 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005987
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005988 if ((node == NULL) || (href == NULL))
5989 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005990 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005991 /*
5992 * Only the document can hold the XML spec namespace.
5993 */
5994 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5995 /*
5996 * The XML-1.0 namespace is normally held on the root
5997 * element. In this case exceptionally create it on the
5998 * node element.
5999 */
6000 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
6001 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006002 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006003 return (NULL);
6004 }
6005 memset(cur, 0, sizeof(xmlNs));
6006 cur->type = XML_LOCAL_NAMESPACE;
6007 cur->href = xmlStrdup(XML_XML_NAMESPACE);
6008 cur->prefix = xmlStrdup((const xmlChar *) "xml");
6009 cur->next = node->nsDef;
6010 node->nsDef = cur;
6011 return (cur);
6012 }
Daniel Veillard11ce4002006-03-10 00:36:23 +00006013 if (doc == NULL) {
6014 doc = node->doc;
6015 if (doc == NULL)
6016 return(NULL);
6017 }
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00006018 /*
6019 * Return the XML namespace declaration held by the doc.
6020 */
6021 if (doc->oldNs == NULL)
6022 return(xmlTreeEnsureXMLDecl(doc));
6023 else
Daniel Veillardaa6de472008-08-25 14:53:31 +00006024 return(doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00006025 }
Daniel Veillard62040be2004-05-17 03:17:26 +00006026 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00006027 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006028 if ((node->type == XML_ENTITY_REF_NODE) ||
6029 (node->type == XML_ENTITY_NODE) ||
6030 (node->type == XML_ENTITY_DECL))
6031 return (NULL);
6032 if (node->type == XML_ELEMENT_NODE) {
6033 cur = node->nsDef;
6034 while (cur != NULL) {
6035 if ((cur->href != NULL) && (href != NULL) &&
6036 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00006037 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00006038 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006039 return (cur);
6040 }
6041 cur = cur->next;
6042 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00006043 if (orig != node) {
6044 cur = node->ns;
6045 if (cur != NULL) {
6046 if ((cur->href != NULL) && (href != NULL) &&
6047 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00006048 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00006049 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00006050 return (cur);
6051 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006052 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00006053 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006054 }
6055 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00006056 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006057 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006058}
6059
6060/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006061 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00006062 * @doc: the document
6063 * @tree: a node expected to hold the new namespace
6064 * @ns: the original namespace
6065 *
6066 * This function tries to locate a namespace definition in a tree
6067 * ancestors, or create a new namespace definition node similar to
6068 * @ns trying to reuse the same prefix. However if the given prefix is
6069 * null (default namespace) or reused within the subtree defined by
6070 * @tree or on one of its ancestors then a new prefix is generated.
6071 * Returns the (new) namespace definition or NULL in case of error
6072 */
Daniel Veillard8ed10722009-08-20 19:17:36 +02006073static xmlNsPtr
Owen Taylor3473f882001-02-23 17:55:21 +00006074xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
6075 xmlNsPtr def;
6076 xmlChar prefix[50];
6077 int counter = 1;
6078
6079 if (tree == NULL) {
6080#ifdef DEBUG_TREE
6081 xmlGenericError(xmlGenericErrorContext,
6082 "xmlNewReconciliedNs : tree == NULL\n");
6083#endif
6084 return(NULL);
6085 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00006086 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006087#ifdef DEBUG_TREE
6088 xmlGenericError(xmlGenericErrorContext,
6089 "xmlNewReconciliedNs : ns == NULL\n");
6090#endif
6091 return(NULL);
6092 }
6093 /*
6094 * Search an existing namespace definition inherited.
6095 */
6096 def = xmlSearchNsByHref(doc, tree, ns->href);
6097 if (def != NULL)
6098 return(def);
6099
6100 /*
6101 * Find a close prefix which is not already in use.
6102 * Let's strip namespace prefixes longer than 20 chars !
6103 */
Daniel Veillardf742d342002-03-07 00:05:35 +00006104 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00006105 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00006106 else
William M. Brack13dfa872004-09-18 04:52:08 +00006107 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00006108
Owen Taylor3473f882001-02-23 17:55:21 +00006109 def = xmlSearchNs(doc, tree, prefix);
6110 while (def != NULL) {
6111 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00006112 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00006113 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00006114 else
William M. Brack13dfa872004-09-18 04:52:08 +00006115 snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
Daniel Veillardaa6de472008-08-25 14:53:31 +00006116 (char *)ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00006117 def = xmlSearchNs(doc, tree, prefix);
6118 }
6119
6120 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00006121 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00006122 */
6123 def = xmlNewNs(tree, ns->href, prefix);
6124 return(def);
6125}
6126
Daniel Veillard652327a2003-09-29 18:02:38 +00006127#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00006128/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006129 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00006130 * @doc: the document
6131 * @tree: a node defining the subtree to reconciliate
6132 *
6133 * This function checks that all the namespaces declared within the given
6134 * tree are properly declared. This is needed for example after Copy or Cut
6135 * and then paste operations. The subtree may still hold pointers to
6136 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00006137 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00006138 * the new environment. If not possible the new namespaces are redeclared
6139 * on @tree at the top of the given subtree.
6140 * Returns the number of namespace declarations created or -1 in case of error.
6141 */
6142int
6143xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
6144 xmlNsPtr *oldNs = NULL;
6145 xmlNsPtr *newNs = NULL;
6146 int sizeCache = 0;
6147 int nbCache = 0;
6148
6149 xmlNsPtr n;
6150 xmlNodePtr node = tree;
6151 xmlAttrPtr attr;
6152 int ret = 0, i;
6153
Daniel Veillardce244ad2004-11-05 10:03:46 +00006154 if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1);
6155 if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1);
6156 if (node->doc != doc) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006157 while (node != NULL) {
6158 /*
6159 * Reconciliate the node namespace
6160 */
6161 if (node->ns != NULL) {
6162 /*
6163 * initialize the cache if needed
6164 */
6165 if (sizeCache == 0) {
6166 sizeCache = 10;
6167 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
6168 sizeof(xmlNsPtr));
6169 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006170 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00006171 return(-1);
6172 }
6173 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
6174 sizeof(xmlNsPtr));
6175 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006176 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00006177 xmlFree(oldNs);
6178 return(-1);
6179 }
6180 }
6181 for (i = 0;i < nbCache;i++) {
6182 if (oldNs[i] == node->ns) {
6183 node->ns = newNs[i];
6184 break;
6185 }
6186 }
6187 if (i == nbCache) {
6188 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00006189 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00006190 */
6191 n = xmlNewReconciliedNs(doc, tree, node->ns);
6192 if (n != NULL) { /* :-( what if else ??? */
6193 /*
6194 * check if we need to grow the cache buffers.
6195 */
6196 if (sizeCache <= nbCache) {
6197 sizeCache *= 2;
6198 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
6199 sizeof(xmlNsPtr));
6200 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006201 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00006202 xmlFree(newNs);
6203 return(-1);
6204 }
6205 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
6206 sizeof(xmlNsPtr));
6207 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006208 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00006209 xmlFree(oldNs);
6210 return(-1);
6211 }
6212 }
6213 newNs[nbCache] = n;
6214 oldNs[nbCache++] = node->ns;
6215 node->ns = n;
6216 }
6217 }
6218 }
6219 /*
6220 * now check for namespace hold by attributes on the node.
6221 */
Daniel Veillardb5f11972006-10-14 08:46:40 +00006222 if (node->type == XML_ELEMENT_NODE) {
6223 attr = node->properties;
6224 while (attr != NULL) {
6225 if (attr->ns != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006226 /*
Daniel Veillardb5f11972006-10-14 08:46:40 +00006227 * initialize the cache if needed
Owen Taylor3473f882001-02-23 17:55:21 +00006228 */
Daniel Veillardb5f11972006-10-14 08:46:40 +00006229 if (sizeCache == 0) {
6230 sizeCache = 10;
6231 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
6232 sizeof(xmlNsPtr));
6233 if (oldNs == NULL) {
6234 xmlTreeErrMemory("fixing namespaces");
6235 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006236 }
Daniel Veillardb5f11972006-10-14 08:46:40 +00006237 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
6238 sizeof(xmlNsPtr));
6239 if (newNs == NULL) {
6240 xmlTreeErrMemory("fixing namespaces");
6241 xmlFree(oldNs);
6242 return(-1);
6243 }
6244 }
6245 for (i = 0;i < nbCache;i++) {
6246 if (oldNs[i] == attr->ns) {
6247 attr->ns = newNs[i];
6248 break;
6249 }
6250 }
6251 if (i == nbCache) {
6252 /*
6253 * OK we need to recreate a new namespace definition
6254 */
6255 n = xmlNewReconciliedNs(doc, tree, attr->ns);
6256 if (n != NULL) { /* :-( what if else ??? */
6257 /*
6258 * check if we need to grow the cache buffers.
6259 */
6260 if (sizeCache <= nbCache) {
6261 sizeCache *= 2;
6262 oldNs = (xmlNsPtr *) xmlRealloc(oldNs,
6263 sizeCache * sizeof(xmlNsPtr));
6264 if (oldNs == NULL) {
6265 xmlTreeErrMemory("fixing namespaces");
6266 xmlFree(newNs);
6267 return(-1);
6268 }
6269 newNs = (xmlNsPtr *) xmlRealloc(newNs,
6270 sizeCache * sizeof(xmlNsPtr));
6271 if (newNs == NULL) {
6272 xmlTreeErrMemory("fixing namespaces");
6273 xmlFree(oldNs);
6274 return(-1);
6275 }
6276 }
6277 newNs[nbCache] = n;
6278 oldNs[nbCache++] = attr->ns;
6279 attr->ns = n;
6280 }
Owen Taylor3473f882001-02-23 17:55:21 +00006281 }
6282 }
Daniel Veillardb5f11972006-10-14 08:46:40 +00006283 attr = attr->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006284 }
Owen Taylor3473f882001-02-23 17:55:21 +00006285 }
6286
6287 /*
6288 * Browse the full subtree, deep first
6289 */
Daniel Veillardb5f11972006-10-14 08:46:40 +00006290 if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006291 /* deep first */
6292 node = node->children;
6293 } else if ((node != tree) && (node->next != NULL)) {
6294 /* then siblings */
6295 node = node->next;
6296 } else if (node != tree) {
6297 /* go up to parents->next if needed */
6298 while (node != tree) {
6299 if (node->parent != NULL)
6300 node = node->parent;
6301 if ((node != tree) && (node->next != NULL)) {
6302 node = node->next;
6303 break;
6304 }
6305 if (node->parent == NULL) {
6306 node = NULL;
6307 break;
6308 }
6309 }
6310 /* exit condition */
Daniel Veillardaa6de472008-08-25 14:53:31 +00006311 if (node == tree)
Owen Taylor3473f882001-02-23 17:55:21 +00006312 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00006313 } else
6314 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006315 }
Daniel Veillardf742d342002-03-07 00:05:35 +00006316 if (oldNs != NULL)
6317 xmlFree(oldNs);
6318 if (newNs != NULL)
6319 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00006320 return(ret);
6321}
Daniel Veillard652327a2003-09-29 18:02:38 +00006322#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00006323
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006324static xmlAttrPtr
6325xmlGetPropNodeInternal(xmlNodePtr node, const xmlChar *name,
6326 const xmlChar *nsName, int useDTD)
6327{
6328 xmlAttrPtr prop;
6329
6330 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6331 return(NULL);
6332
6333 if (node->properties != NULL) {
6334 prop = node->properties;
6335 if (nsName == NULL) {
6336 /*
6337 * We want the attr to be in no namespace.
6338 */
6339 do {
6340 if ((prop->ns == NULL) && xmlStrEqual(prop->name, name)) {
6341 return(prop);
6342 }
6343 prop = prop->next;
6344 } while (prop != NULL);
6345 } else {
6346 /*
6347 * We want the attr to be in the specified namespace.
6348 */
6349 do {
6350 if ((prop->ns != NULL) && xmlStrEqual(prop->name, name) &&
6351 ((prop->ns->href == nsName) ||
6352 xmlStrEqual(prop->ns->href, nsName)))
6353 {
6354 return(prop);
6355 }
6356 prop = prop->next;
6357 } while (prop != NULL);
6358 }
6359 }
6360
6361#ifdef LIBXML_TREE_ENABLED
6362 if (! useDTD)
6363 return(NULL);
6364 /*
6365 * Check if there is a default/fixed attribute declaration in
6366 * the internal or external subset.
Daniel Veillardaa6de472008-08-25 14:53:31 +00006367 */
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006368 if ((node->doc != NULL) && (node->doc->intSubset != NULL)) {
6369 xmlDocPtr doc = node->doc;
6370 xmlAttributePtr attrDecl = NULL;
6371 xmlChar *elemQName, *tmpstr = NULL;
6372
6373 /*
Daniel Veillardaa6de472008-08-25 14:53:31 +00006374 * We need the QName of the element for the DTD-lookup.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006375 */
6376 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
6377 tmpstr = xmlStrdup(node->ns->prefix);
6378 tmpstr = xmlStrcat(tmpstr, BAD_CAST ":");
6379 tmpstr = xmlStrcat(tmpstr, node->name);
6380 if (tmpstr == NULL)
6381 return(NULL);
6382 elemQName = tmpstr;
6383 } else
6384 elemQName = (xmlChar *) node->name;
6385 if (nsName == NULL) {
6386 /*
6387 * The common and nice case: Attr in no namespace.
6388 */
6389 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset,
6390 elemQName, name, NULL);
6391 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
6392 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset,
6393 elemQName, name, NULL);
6394 }
6395 } else {
6396 xmlNsPtr *nsList, *cur;
6397
6398 /*
6399 * The ugly case: Search using the prefixes of in-scope
6400 * ns-decls corresponding to @nsName.
6401 */
6402 nsList = xmlGetNsList(node->doc, node);
6403 if (nsList == NULL) {
6404 if (tmpstr != NULL)
6405 xmlFree(tmpstr);
6406 return(NULL);
6407 }
6408 cur = nsList;
6409 while (*cur != NULL) {
6410 if (xmlStrEqual((*cur)->href, nsName)) {
6411 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elemQName,
6412 name, (*cur)->prefix);
6413 if (attrDecl)
6414 break;
6415 if (doc->extSubset != NULL) {
6416 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elemQName,
6417 name, (*cur)->prefix);
6418 if (attrDecl)
6419 break;
6420 }
6421 }
6422 cur++;
6423 }
6424 xmlFree(nsList);
Daniel Veillardaa6de472008-08-25 14:53:31 +00006425 }
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006426 if (tmpstr != NULL)
6427 xmlFree(tmpstr);
6428 /*
6429 * Only default/fixed attrs are relevant.
6430 */
6431 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6432 return((xmlAttrPtr) attrDecl);
6433 }
6434#endif /* LIBXML_TREE_ENABLED */
6435 return(NULL);
6436}
6437
6438static xmlChar*
6439xmlGetPropNodeValueInternal(xmlAttrPtr prop)
6440{
6441 if (prop == NULL)
6442 return(NULL);
6443 if (prop->type == XML_ATTRIBUTE_NODE) {
6444 /*
6445 * Note that we return at least the empty string.
6446 * TODO: Do we really always want that?
6447 */
6448 if (prop->children != NULL) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00006449 if ((prop->children->next == NULL) &&
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006450 ((prop->children->type == XML_TEXT_NODE) ||
6451 (prop->children->type == XML_CDATA_SECTION_NODE)))
6452 {
6453 /*
6454 * Optimization for the common case: only 1 text node.
6455 */
6456 return(xmlStrdup(prop->children->content));
6457 } else {
6458 xmlChar *ret;
6459
6460 ret = xmlNodeListGetString(prop->doc, prop->children, 1);
6461 if (ret != NULL)
6462 return(ret);
6463 }
6464 }
6465 return(xmlStrdup((xmlChar *)""));
6466 } else if (prop->type == XML_ATTRIBUTE_DECL) {
6467 return(xmlStrdup(((xmlAttributePtr)prop)->defaultValue));
6468 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00006469 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006470}
6471
Owen Taylor3473f882001-02-23 17:55:21 +00006472/**
6473 * xmlHasProp:
6474 * @node: the node
6475 * @name: the attribute name
6476 *
6477 * Search an attribute associated to a node
6478 * This function also looks in DTD attribute declaration for #FIXED or
6479 * default declaration values unless DTD use has been turned off.
6480 *
Daniel Veillardaa6de472008-08-25 14:53:31 +00006481 * Returns the attribute or the attribute declaration or NULL if
Owen Taylor3473f882001-02-23 17:55:21 +00006482 * neither was found.
6483 */
6484xmlAttrPtr
6485xmlHasProp(xmlNodePtr node, const xmlChar *name) {
6486 xmlAttrPtr prop;
6487 xmlDocPtr doc;
6488
Daniel Veillard8874b942005-08-25 13:19:21 +00006489 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6490 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006491 /*
6492 * Check on the properties attached to the node
6493 */
6494 prop = node->properties;
6495 while (prop != NULL) {
6496 if (xmlStrEqual(prop->name, name)) {
6497 return(prop);
6498 }
6499 prop = prop->next;
6500 }
6501 if (!xmlCheckDTD) return(NULL);
6502
6503 /*
6504 * Check if there is a default declaration in the internal
6505 * or external subsets
6506 */
6507 doc = node->doc;
6508 if (doc != NULL) {
6509 xmlAttributePtr attrDecl;
6510 if (doc->intSubset != NULL) {
6511 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6512 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6513 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006514 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6515 /* return attribute declaration only if a default value is given
6516 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006517 return((xmlAttrPtr) attrDecl);
6518 }
6519 }
6520 return(NULL);
6521}
6522
6523/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00006524 * xmlHasNsProp:
6525 * @node: the node
6526 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006527 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00006528 *
6529 * Search for an attribute associated to a node
6530 * This attribute has to be anchored in the namespace specified.
6531 * This does the entity substitution.
6532 * This function looks in DTD attribute declaration for #FIXED or
6533 * default declaration values unless DTD use has been turned off.
William M. Brack2c228442004-10-03 04:10:00 +00006534 * Note that a namespace of NULL indicates to use the default namespace.
Daniel Veillarde95e2392001-06-06 10:46:28 +00006535 *
6536 * Returns the attribute or the attribute declaration or NULL
6537 * if neither was found.
6538 */
6539xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00006540xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00006541
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006542 return(xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD));
Daniel Veillarde95e2392001-06-06 10:46:28 +00006543}
6544
6545/**
Owen Taylor3473f882001-02-23 17:55:21 +00006546 * xmlGetProp:
6547 * @node: the node
6548 * @name: the attribute name
6549 *
6550 * Search and get the value of an attribute associated to a node
6551 * This does the entity substitution.
6552 * This function looks in DTD attribute declaration for #FIXED or
6553 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00006554 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00006555 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6556 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00006557 *
6558 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006559 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006560 */
6561xmlChar *
6562xmlGetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00006563 xmlAttrPtr prop;
Owen Taylor3473f882001-02-23 17:55:21 +00006564
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006565 prop = xmlHasProp(node, name);
6566 if (prop == NULL)
6567 return(NULL);
Daniel Veillardaa6de472008-08-25 14:53:31 +00006568 return(xmlGetPropNodeValueInternal(prop));
Owen Taylor3473f882001-02-23 17:55:21 +00006569}
6570
6571/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006572 * xmlGetNoNsProp:
6573 * @node: the node
6574 * @name: the attribute name
6575 *
6576 * Search and get the value of an attribute associated to a node
6577 * This does the entity substitution.
6578 * This function looks in DTD attribute declaration for #FIXED or
6579 * default declaration values unless DTD use has been turned off.
6580 * This function is similar to xmlGetProp except it will accept only
6581 * an attribute in no namespace.
6582 *
6583 * Returns the attribute value or NULL if not found.
6584 * It's up to the caller to free the memory with xmlFree().
6585 */
6586xmlChar *
6587xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6588 xmlAttrPtr prop;
Daniel Veillardaa6de472008-08-25 14:53:31 +00006589
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006590 prop = xmlGetPropNodeInternal(node, name, NULL, xmlCheckDTD);
6591 if (prop == NULL)
Daniel Veillard8874b942005-08-25 13:19:21 +00006592 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006593 return(xmlGetPropNodeValueInternal(prop));
Daniel Veillard71531f32003-02-05 13:19:53 +00006594}
6595
6596/**
Owen Taylor3473f882001-02-23 17:55:21 +00006597 * xmlGetNsProp:
6598 * @node: the node
6599 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006600 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006601 *
6602 * Search and get the value of an attribute associated to a node
6603 * This attribute has to be anchored in the namespace specified.
6604 * This does the entity substitution.
6605 * This function looks in DTD attribute declaration for #FIXED or
6606 * default declaration values unless DTD use has been turned off.
6607 *
6608 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006609 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006610 */
6611xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006612xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006613 xmlAttrPtr prop;
Owen Taylor3473f882001-02-23 17:55:21 +00006614
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006615 prop = xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD);
6616 if (prop == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006617 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006618 return(xmlGetPropNodeValueInternal(prop));
Owen Taylor3473f882001-02-23 17:55:21 +00006619}
6620
Daniel Veillard2156d432004-03-04 15:59:36 +00006621#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6622/**
6623 * xmlUnsetProp:
6624 * @node: the node
6625 * @name: the attribute name
6626 *
6627 * Remove an attribute carried by a node.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006628 * This handles only attributes in no namespace.
Daniel Veillard2156d432004-03-04 15:59:36 +00006629 * Returns 0 if successful, -1 if not found
6630 */
6631int
6632xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Kasimier T. Buchcik65c2f1d2005-10-17 12:39:58 +00006633 xmlAttrPtr prop;
Daniel Veillard2156d432004-03-04 15:59:36 +00006634
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006635 prop = xmlGetPropNodeInternal(node, name, NULL, 0);
6636 if (prop == NULL)
Daniel Veillard2156d432004-03-04 15:59:36 +00006637 return(-1);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006638 xmlUnlinkNode((xmlNodePtr) prop);
6639 xmlFreeProp(prop);
6640 return(0);
Daniel Veillard2156d432004-03-04 15:59:36 +00006641}
6642
6643/**
6644 * xmlUnsetNsProp:
6645 * @node: the node
6646 * @ns: the namespace definition
6647 * @name: the attribute name
6648 *
6649 * Remove an attribute carried by a node.
6650 * Returns 0 if successful, -1 if not found
6651 */
6652int
6653xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
Kasimier T. Buchcik65c2f1d2005-10-17 12:39:58 +00006654 xmlAttrPtr prop;
Daniel Veillardaa6de472008-08-25 14:53:31 +00006655
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006656 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
6657 if (prop == NULL)
Daniel Veillard2156d432004-03-04 15:59:36 +00006658 return(-1);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006659 xmlUnlinkNode((xmlNodePtr) prop);
6660 xmlFreeProp(prop);
6661 return(0);
Daniel Veillard2156d432004-03-04 15:59:36 +00006662}
6663#endif
6664
6665#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006666/**
6667 * xmlSetProp:
6668 * @node: the node
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006669 * @name: the attribute name (a QName)
Owen Taylor3473f882001-02-23 17:55:21 +00006670 * @value: the attribute value
6671 *
6672 * Set (or reset) an attribute carried by a node.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006673 * If @name has a prefix, then the corresponding
6674 * namespace-binding will be used, if in scope; it is an
6675 * error it there's no such ns-binding for the prefix in
6676 * scope.
Owen Taylor3473f882001-02-23 17:55:21 +00006677 * Returns the attribute pointer.
Daniel Veillardaa6de472008-08-25 14:53:31 +00006678 *
Owen Taylor3473f882001-02-23 17:55:21 +00006679 */
6680xmlAttrPtr
6681xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006682 int len;
6683 const xmlChar *nqname;
Owen Taylor3473f882001-02-23 17:55:21 +00006684
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006685 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006686 return(NULL);
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006687
6688 /*
6689 * handle QNames
6690 */
6691 nqname = xmlSplitQName3(name, &len);
6692 if (nqname != NULL) {
6693 xmlNsPtr ns;
6694 xmlChar *prefix = xmlStrndup(name, len);
6695 ns = xmlSearchNs(node->doc, node, prefix);
6696 if (prefix != NULL)
6697 xmlFree(prefix);
6698 if (ns != NULL)
6699 return(xmlSetNsProp(node, ns, nqname, value));
6700 }
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006701 return(xmlSetNsProp(node, NULL, name, value));
Owen Taylor3473f882001-02-23 17:55:21 +00006702}
6703
6704/**
6705 * xmlSetNsProp:
6706 * @node: the node
6707 * @ns: the namespace definition
6708 * @name: the attribute name
6709 * @value: the attribute value
6710 *
6711 * Set (or reset) an attribute carried by a node.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006712 * The ns structure must be in scope, this is not checked
Owen Taylor3473f882001-02-23 17:55:21 +00006713 *
6714 * Returns the attribute pointer.
6715 */
6716xmlAttrPtr
6717xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006718 const xmlChar *value)
6719{
Owen Taylor3473f882001-02-23 17:55:21 +00006720 xmlAttrPtr prop;
Daniel Veillardaa6de472008-08-25 14:53:31 +00006721
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006722 if (ns && (ns->href == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006723 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006724 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
6725 if (prop != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006726 /*
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006727 * Modify the attribute's value.
6728 */
6729 if (prop->atype == XML_ATTRIBUTE_ID) {
6730 xmlRemoveID(node->doc, prop);
6731 prop->atype = XML_ATTRIBUTE_ID;
6732 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00006733 if (prop->children != NULL)
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006734 xmlFreeNodeList(prop->children);
6735 prop->children = NULL;
6736 prop->last = NULL;
6737 prop->ns = ns;
6738 if (value != NULL) {
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006739 xmlNodePtr tmp;
Daniel Veillardaa6de472008-08-25 14:53:31 +00006740
Daniel Veillard6f8611f2008-02-15 08:33:21 +00006741 if(!xmlCheckUTF8(value)) {
6742 xmlTreeErr(XML_TREE_NOT_UTF8, (xmlNodePtr) node->doc,
6743 NULL);
6744 if (node->doc != NULL)
6745 node->doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
6746 }
6747 prop->children = xmlNewDocText(node->doc, value);
Owen Taylor3473f882001-02-23 17:55:21 +00006748 prop->last = NULL;
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006749 tmp = prop->children;
6750 while (tmp != NULL) {
6751 tmp->parent = (xmlNodePtr) prop;
6752 if (tmp->next == NULL)
6753 prop->last = tmp;
6754 tmp = tmp->next;
6755 }
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006756 }
6757 if (prop->atype == XML_ATTRIBUTE_ID)
6758 xmlAddID(NULL, node->doc, value, prop);
6759 return(prop);
Owen Taylor3473f882001-02-23 17:55:21 +00006760 }
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006761 /*
6762 * No equal attr found; create a new one.
6763 */
6764 return(xmlNewPropInternal(node, ns, name, value, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006765}
6766
Daniel Veillard652327a2003-09-29 18:02:38 +00006767#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006768
6769/**
Owen Taylor3473f882001-02-23 17:55:21 +00006770 * xmlNodeIsText:
6771 * @node: the node
Daniel Veillardaa6de472008-08-25 14:53:31 +00006772 *
Owen Taylor3473f882001-02-23 17:55:21 +00006773 * Is this node a Text node ?
6774 * Returns 1 yes, 0 no
6775 */
6776int
6777xmlNodeIsText(xmlNodePtr node) {
6778 if (node == NULL) return(0);
6779
6780 if (node->type == XML_TEXT_NODE) return(1);
6781 return(0);
6782}
6783
6784/**
6785 * xmlIsBlankNode:
6786 * @node: the node
Daniel Veillardaa6de472008-08-25 14:53:31 +00006787 *
Owen Taylor3473f882001-02-23 17:55:21 +00006788 * Checks whether this node is an empty or whitespace only
6789 * (and possibly ignorable) text-node.
6790 *
6791 * Returns 1 yes, 0 no
6792 */
6793int
6794xmlIsBlankNode(xmlNodePtr node) {
6795 const xmlChar *cur;
6796 if (node == NULL) return(0);
6797
Daniel Veillard7db37732001-07-12 01:20:08 +00006798 if ((node->type != XML_TEXT_NODE) &&
6799 (node->type != XML_CDATA_SECTION_NODE))
6800 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006801 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006802 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006803 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006804 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006805 cur++;
6806 }
6807
6808 return(1);
6809}
6810
6811/**
6812 * xmlTextConcat:
6813 * @node: the node
6814 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006815 * @len: @content length
Daniel Veillardaa6de472008-08-25 14:53:31 +00006816 *
Owen Taylor3473f882001-02-23 17:55:21 +00006817 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006818 *
6819 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006820 */
6821
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006822int
Owen Taylor3473f882001-02-23 17:55:21 +00006823xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006824 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006825
6826 if ((node->type != XML_TEXT_NODE) &&
Rob Richardsa02f1992006-09-16 14:04:26 +00006827 (node->type != XML_CDATA_SECTION_NODE) &&
6828 (node->type != XML_COMMENT_NODE) &&
6829 (node->type != XML_PI_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006830#ifdef DEBUG_TREE
6831 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006832 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006833#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006834 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006835 }
William M. Brack7762bb12004-01-04 14:49:01 +00006836 /* need to check if content is currently in the dictionary */
Daniel Veillard8874b942005-08-25 13:19:21 +00006837 if ((node->content == (xmlChar *) &(node->properties)) ||
6838 ((node->doc != NULL) && (node->doc->dict != NULL) &&
6839 xmlDictOwns(node->doc->dict, node->content))) {
William M. Brack7762bb12004-01-04 14:49:01 +00006840 node->content = xmlStrncatNew(node->content, content, len);
6841 } else {
6842 node->content = xmlStrncat(node->content, content, len);
6843 }
Daniel Veillard8874b942005-08-25 13:19:21 +00006844 node->properties = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006845 if (node->content == NULL)
6846 return(-1);
6847 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006848}
6849
6850/************************************************************************
6851 * *
6852 * Output : to a FILE or in memory *
6853 * *
6854 ************************************************************************/
6855
Owen Taylor3473f882001-02-23 17:55:21 +00006856/**
6857 * xmlBufferCreate:
6858 *
6859 * routine to create an XML buffer.
6860 * returns the new structure.
6861 */
6862xmlBufferPtr
6863xmlBufferCreate(void) {
6864 xmlBufferPtr ret;
6865
6866 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6867 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006868 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006869 return(NULL);
6870 }
6871 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006872 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006873 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006874 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006875 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006876 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006877 xmlFree(ret);
6878 return(NULL);
6879 }
6880 ret->content[0] = 0;
Daniel Veillarde83e93e2008-08-30 12:52:26 +00006881 ret->contentIO = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00006882 return(ret);
6883}
6884
6885/**
6886 * xmlBufferCreateSize:
6887 * @size: initial size of buffer
6888 *
6889 * routine to create an XML buffer.
6890 * returns the new structure.
6891 */
6892xmlBufferPtr
6893xmlBufferCreateSize(size_t size) {
6894 xmlBufferPtr ret;
6895
6896 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6897 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006898 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006899 return(NULL);
6900 }
6901 ret->use = 0;
6902 ret->alloc = xmlBufferAllocScheme;
6903 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6904 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006905 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006906 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006907 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006908 xmlFree(ret);
6909 return(NULL);
6910 }
6911 ret->content[0] = 0;
6912 } else
6913 ret->content = NULL;
Daniel Veillarde83e93e2008-08-30 12:52:26 +00006914 ret->contentIO = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00006915 return(ret);
6916}
6917
6918/**
Daniel Veillard53350552003-09-18 13:35:51 +00006919 * xmlBufferCreateStatic:
6920 * @mem: the memory area
6921 * @size: the size in byte
6922 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006923 * routine to create an XML buffer from an immutable memory area.
6924 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006925 * present until the end of the buffer lifetime.
6926 *
6927 * returns the new structure.
6928 */
6929xmlBufferPtr
6930xmlBufferCreateStatic(void *mem, size_t size) {
6931 xmlBufferPtr ret;
6932
6933 if ((mem == NULL) || (size == 0))
6934 return(NULL);
6935
6936 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6937 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006938 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006939 return(NULL);
6940 }
6941 ret->use = size;
6942 ret->size = size;
6943 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6944 ret->content = (xmlChar *) mem;
6945 return(ret);
6946}
6947
6948/**
Owen Taylor3473f882001-02-23 17:55:21 +00006949 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006950 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006951 * @scheme: allocation scheme to use
6952 *
6953 * Sets the allocation scheme for this buffer
6954 */
6955void
Daniel Veillardaa6de472008-08-25 14:53:31 +00006956xmlBufferSetAllocationScheme(xmlBufferPtr buf,
Owen Taylor3473f882001-02-23 17:55:21 +00006957 xmlBufferAllocationScheme scheme) {
6958 if (buf == NULL) {
6959#ifdef DEBUG_BUFFER
6960 xmlGenericError(xmlGenericErrorContext,
6961 "xmlBufferSetAllocationScheme: buf == NULL\n");
6962#endif
6963 return;
6964 }
Daniel Veillardda3fee42008-09-01 13:08:57 +00006965 if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) ||
6966 (buf->alloc == XML_BUFFER_ALLOC_IO)) return;
6967 if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
6968 (scheme == XML_BUFFER_ALLOC_EXACT) ||
6969 (scheme == XML_BUFFER_ALLOC_IMMUTABLE))
6970 buf->alloc = scheme;
Owen Taylor3473f882001-02-23 17:55:21 +00006971}
6972
6973/**
6974 * xmlBufferFree:
6975 * @buf: the buffer to free
6976 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006977 * Frees an XML buffer. It frees both the content and the structure which
6978 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006979 */
6980void
6981xmlBufferFree(xmlBufferPtr buf) {
6982 if (buf == NULL) {
6983#ifdef DEBUG_BUFFER
6984 xmlGenericError(xmlGenericErrorContext,
6985 "xmlBufferFree: buf == NULL\n");
6986#endif
6987 return;
6988 }
Daniel Veillard53350552003-09-18 13:35:51 +00006989
Daniel Veillarde83e93e2008-08-30 12:52:26 +00006990 if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
6991 (buf->contentIO != NULL)) {
6992 xmlFree(buf->contentIO);
6993 } else if ((buf->content != NULL) &&
Daniel Veillard53350552003-09-18 13:35:51 +00006994 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006995 xmlFree(buf->content);
6996 }
Owen Taylor3473f882001-02-23 17:55:21 +00006997 xmlFree(buf);
6998}
6999
7000/**
7001 * xmlBufferEmpty:
7002 * @buf: the buffer
7003 *
7004 * empty a buffer.
7005 */
7006void
7007xmlBufferEmpty(xmlBufferPtr buf) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007008 if (buf == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007009 if (buf->content == NULL) return;
7010 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00007011 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00007012 buf->content = BAD_CAST "";
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007013 } else if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
7014 (buf->contentIO != NULL)) {
7015 size_t start_buf = buf->content - buf->contentIO;
7016
7017 buf->size += start_buf;
7018 buf->content = buf->contentIO;
7019 buf->content[0] = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00007020 } else {
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007021 buf->content[0] = 0;
7022 }
Owen Taylor3473f882001-02-23 17:55:21 +00007023}
7024
7025/**
7026 * xmlBufferShrink:
7027 * @buf: the buffer to dump
7028 * @len: the number of xmlChar to remove
7029 *
7030 * Remove the beginning of an XML buffer.
7031 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007032 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007033 */
7034int
7035xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
Daniel Veillard3d97e662004-11-04 10:49:00 +00007036 if (buf == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007037 if (len == 0) return(0);
7038 if (len > buf->use) return(-1);
7039
7040 buf->use -= len;
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007041 if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) ||
7042 ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL))) {
7043 /*
7044 * we just move the content pointer, but also make sure
7045 * the perceived buffer size has shrinked accordingly
7046 */
Daniel Veillard53350552003-09-18 13:35:51 +00007047 buf->content += len;
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007048 buf->size -= len;
7049
7050 /*
7051 * sometimes though it maybe be better to really shrink
7052 * on IO buffers
7053 */
7054 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7055 size_t start_buf = buf->content - buf->contentIO;
7056 if (start_buf >= buf->size) {
7057 memmove(buf->contentIO, &buf->content[0], buf->use);
7058 buf->content = buf->contentIO;
7059 buf->content[buf->use] = 0;
7060 buf->size += start_buf;
7061 }
7062 }
Daniel Veillard53350552003-09-18 13:35:51 +00007063 } else {
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007064 memmove(buf->content, &buf->content[len], buf->use);
Daniel Veillard53350552003-09-18 13:35:51 +00007065 buf->content[buf->use] = 0;
7066 }
Owen Taylor3473f882001-02-23 17:55:21 +00007067 return(len);
7068}
7069
7070/**
7071 * xmlBufferGrow:
7072 * @buf: the buffer
7073 * @len: the minimum free size to allocate
7074 *
7075 * Grow the available space of an XML buffer.
7076 *
7077 * Returns the new available space or -1 in case of error
7078 */
7079int
7080xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
7081 int size;
7082 xmlChar *newbuf;
7083
Daniel Veillard3d97e662004-11-04 10:49:00 +00007084 if (buf == NULL) return(-1);
7085
Daniel Veillard53350552003-09-18 13:35:51 +00007086 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007087 if (len + buf->use < buf->size) return(0);
7088
Daniel Veillardee20cd72009-08-22 15:18:31 +02007089 /*
7090 * Windows has a BIG problem on realloc timing, so we try to double
7091 * the buffer size (if that's enough) (bug 146697)
7092 * Apparently BSD too, and it's probably best for linux too
7093 * On an embedded system this may be something to change
7094 */
7095#if 1
William M. Brack30fe43f2004-07-26 18:00:58 +00007096 if (buf->size > len)
7097 size = buf->size * 2;
7098 else
7099 size = buf->use + len + 100;
7100#else
Owen Taylor3473f882001-02-23 17:55:21 +00007101 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00007102#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007103
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007104 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7105 size_t start_buf = buf->content - buf->contentIO;
7106
7107 newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size);
7108 if (newbuf == NULL) {
7109 xmlTreeErrMemory("growing buffer");
7110 return(-1);
7111 }
7112 buf->contentIO = newbuf;
7113 buf->content = newbuf + start_buf;
7114 } else {
7115 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
7116 if (newbuf == NULL) {
7117 xmlTreeErrMemory("growing buffer");
7118 return(-1);
7119 }
7120 buf->content = newbuf;
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007121 }
Owen Taylor3473f882001-02-23 17:55:21 +00007122 buf->size = size;
7123 return(buf->size - buf->use);
7124}
7125
7126/**
7127 * xmlBufferDump:
7128 * @file: the file output
7129 * @buf: the buffer to dump
7130 *
7131 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00007132 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00007133 */
7134int
7135xmlBufferDump(FILE *file, xmlBufferPtr buf) {
7136 int ret;
7137
7138 if (buf == NULL) {
7139#ifdef DEBUG_BUFFER
7140 xmlGenericError(xmlGenericErrorContext,
7141 "xmlBufferDump: buf == NULL\n");
7142#endif
7143 return(0);
7144 }
7145 if (buf->content == NULL) {
7146#ifdef DEBUG_BUFFER
7147 xmlGenericError(xmlGenericErrorContext,
7148 "xmlBufferDump: buf->content == NULL\n");
7149#endif
7150 return(0);
7151 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00007152 if (file == NULL)
7153 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00007154 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
7155 return(ret);
7156}
7157
7158/**
7159 * xmlBufferContent:
7160 * @buf: the buffer
7161 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007162 * Function to extract the content of a buffer
7163 *
Owen Taylor3473f882001-02-23 17:55:21 +00007164 * Returns the internal content
7165 */
7166
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007167const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007168xmlBufferContent(const xmlBufferPtr buf)
7169{
7170 if(!buf)
7171 return NULL;
7172
7173 return buf->content;
7174}
7175
7176/**
7177 * xmlBufferLength:
Daniel Veillardaa6de472008-08-25 14:53:31 +00007178 * @buf: the buffer
Owen Taylor3473f882001-02-23 17:55:21 +00007179 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007180 * Function to get the length of a buffer
7181 *
Owen Taylor3473f882001-02-23 17:55:21 +00007182 * Returns the length of data in the internal content
7183 */
7184
7185int
7186xmlBufferLength(const xmlBufferPtr buf)
7187{
7188 if(!buf)
7189 return 0;
7190
7191 return buf->use;
7192}
7193
7194/**
7195 * xmlBufferResize:
7196 * @buf: the buffer to resize
7197 * @size: the desired size
7198 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007199 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00007200 *
7201 * Returns 0 in case of problems, 1 otherwise
7202 */
7203int
7204xmlBufferResize(xmlBufferPtr buf, unsigned int size)
7205{
7206 unsigned int newSize;
7207 xmlChar* rebuf = NULL;
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007208 size_t start_buf;
Owen Taylor3473f882001-02-23 17:55:21 +00007209
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007210 if (buf == NULL)
7211 return(0);
7212
Daniel Veillard53350552003-09-18 13:35:51 +00007213 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
7214
Owen Taylor3473f882001-02-23 17:55:21 +00007215 /* Don't resize if we don't have to */
7216 if (size < buf->size)
7217 return 1;
7218
7219 /* figure out new size */
7220 switch (buf->alloc){
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007221 case XML_BUFFER_ALLOC_IO:
7222 case XML_BUFFER_ALLOC_DOUBLEIT:
7223 /*take care of empty case*/
7224 newSize = (buf->size ? buf->size*2 : size + 10);
Daniel Veillard1dc9feb2008-11-17 15:59:21 +00007225 while (size > newSize) {
7226 if (newSize > UINT_MAX / 2) {
7227 xmlTreeErrMemory("growing buffer");
7228 return 0;
7229 }
7230 newSize *= 2;
7231 }
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007232 break;
7233 case XML_BUFFER_ALLOC_EXACT:
7234 newSize = size+10;
7235 break;
7236 default:
7237 newSize = size+10;
7238 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007239 }
7240
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007241 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7242 start_buf = buf->content - buf->contentIO;
7243
7244 if (start_buf > newSize) {
7245 /* move data back to start */
7246 memmove(buf->contentIO, buf->content, buf->use);
7247 buf->content = buf->contentIO;
7248 buf->content[buf->use] = 0;
7249 buf->size += start_buf;
7250 } else {
7251 rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize);
7252 if (rebuf == NULL) {
7253 xmlTreeErrMemory("growing buffer");
7254 return 0;
7255 }
7256 buf->contentIO = rebuf;
7257 buf->content = rebuf + start_buf;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00007258 }
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007259 } else {
7260 if (buf->content == NULL) {
7261 rebuf = (xmlChar *) xmlMallocAtomic(newSize);
7262 } else if (buf->size - buf->use < 100) {
7263 rebuf = (xmlChar *) xmlRealloc(buf->content, newSize);
7264 } else {
7265 /*
7266 * if we are reallocating a buffer far from being full, it's
7267 * better to make a new allocation and copy only the used range
7268 * and free the old one.
7269 */
7270 rebuf = (xmlChar *) xmlMallocAtomic(newSize);
7271 if (rebuf != NULL) {
7272 memcpy(rebuf, buf->content, buf->use);
7273 xmlFree(buf->content);
7274 rebuf[buf->use] = 0;
7275 }
7276 }
7277 if (rebuf == NULL) {
7278 xmlTreeErrMemory("growing buffer");
7279 return 0;
7280 }
7281 buf->content = rebuf;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00007282 }
Owen Taylor3473f882001-02-23 17:55:21 +00007283 buf->size = newSize;
7284
7285 return 1;
7286}
7287
7288/**
7289 * xmlBufferAdd:
7290 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00007291 * @str: the #xmlChar string
7292 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00007293 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007294 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00007295 * str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00007296 *
7297 * Returns 0 successful, a positive error code number otherwise
7298 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007299 */
William M. Bracka3215c72004-07-31 16:24:01 +00007300int
Owen Taylor3473f882001-02-23 17:55:21 +00007301xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
7302 unsigned int needSize;
7303
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007304 if ((str == NULL) || (buf == NULL)) {
William M. Bracka3215c72004-07-31 16:24:01 +00007305 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007306 }
William M. Bracka3215c72004-07-31 16:24:01 +00007307 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007308 if (len < -1) {
7309#ifdef DEBUG_BUFFER
7310 xmlGenericError(xmlGenericErrorContext,
7311 "xmlBufferAdd: len < 0\n");
7312#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007313 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007314 }
William M. Bracka3215c72004-07-31 16:24:01 +00007315 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007316
7317 if (len < 0)
7318 len = xmlStrlen(str);
7319
Daniel Veillardc9923322007-04-24 18:12:06 +00007320 if (len < 0) return -1;
7321 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007322
7323 needSize = buf->use + len + 2;
7324 if (needSize > buf->size){
7325 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007326 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007327 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007328 }
7329 }
7330
7331 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
7332 buf->use += len;
7333 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007334 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007335}
7336
7337/**
7338 * xmlBufferAddHead:
7339 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00007340 * @str: the #xmlChar string
7341 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00007342 *
7343 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00007344 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00007345 *
7346 * Returns 0 successful, a positive error code number otherwise
7347 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007348 */
William M. Bracka3215c72004-07-31 16:24:01 +00007349int
Owen Taylor3473f882001-02-23 17:55:21 +00007350xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
7351 unsigned int needSize;
7352
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007353 if (buf == NULL)
7354 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007355 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007356 if (str == NULL) {
7357#ifdef DEBUG_BUFFER
7358 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007359 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007360#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007361 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007362 }
7363 if (len < -1) {
7364#ifdef DEBUG_BUFFER
7365 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007366 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007367#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007368 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007369 }
William M. Bracka3215c72004-07-31 16:24:01 +00007370 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007371
7372 if (len < 0)
7373 len = xmlStrlen(str);
7374
William M. Bracka3215c72004-07-31 16:24:01 +00007375 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007376
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007377 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7378 size_t start_buf = buf->content - buf->contentIO;
7379
7380 if (start_buf > (unsigned int) len) {
7381 /*
7382 * We can add it in the space previously shrinked
7383 */
7384 buf->content -= len;
7385 memmove(&buf->content[0], str, len);
7386 buf->use += len;
7387 buf->size += len;
7388 return(0);
7389 }
7390 }
Owen Taylor3473f882001-02-23 17:55:21 +00007391 needSize = buf->use + len + 2;
7392 if (needSize > buf->size){
7393 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007394 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007395 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007396 }
7397 }
7398
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007399 memmove(&buf->content[len], &buf->content[0], buf->use);
7400 memmove(&buf->content[0], str, len);
Owen Taylor3473f882001-02-23 17:55:21 +00007401 buf->use += len;
7402 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007403 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007404}
7405
7406/**
7407 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00007408 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00007409 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00007410 *
7411 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007412 *
7413 * Returns 0 successful, a positive error code number otherwise
7414 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007415 */
William M. Bracka3215c72004-07-31 16:24:01 +00007416int
Owen Taylor3473f882001-02-23 17:55:21 +00007417xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007418 if (buf == NULL)
7419 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007420 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
7421 if (str == NULL) return -1;
7422 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00007423}
7424
7425/**
7426 * xmlBufferCCat:
7427 * @buf: the buffer to dump
7428 * @str: the C char string
7429 *
7430 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007431 *
7432 * Returns 0 successful, a positive error code number otherwise
7433 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007434 */
William M. Bracka3215c72004-07-31 16:24:01 +00007435int
Owen Taylor3473f882001-02-23 17:55:21 +00007436xmlBufferCCat(xmlBufferPtr buf, const char *str) {
7437 const char *cur;
7438
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007439 if (buf == NULL)
7440 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007441 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007442 if (str == NULL) {
7443#ifdef DEBUG_BUFFER
7444 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007445 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007446#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007447 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007448 }
7449 for (cur = str;*cur != 0;cur++) {
7450 if (buf->use + 10 >= buf->size) {
7451 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007452 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007453 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007454 }
7455 }
7456 buf->content[buf->use++] = *cur;
7457 }
7458 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007459 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007460}
7461
7462/**
7463 * xmlBufferWriteCHAR:
7464 * @buf: the XML buffer
7465 * @string: the string to add
7466 *
7467 * routine which manages and grows an output buffer. This one adds
7468 * xmlChars at the end of the buffer.
7469 */
7470void
Daniel Veillard53350552003-09-18 13:35:51 +00007471xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007472 if (buf == NULL)
7473 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007474 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007475 xmlBufferCat(buf, string);
7476}
7477
7478/**
7479 * xmlBufferWriteChar:
7480 * @buf: the XML buffer output
7481 * @string: the string to add
7482 *
7483 * routine which manage and grows an output buffer. This one add
7484 * C chars at the end of the array.
7485 */
7486void
7487xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007488 if (buf == NULL)
7489 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007490 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007491 xmlBufferCCat(buf, string);
7492}
7493
7494
7495/**
7496 * xmlBufferWriteQuotedString:
7497 * @buf: the XML buffer output
7498 * @string: the string to add
7499 *
7500 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00007501 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00007502 * quote or double-quotes internally
7503 */
7504void
7505xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00007506 const xmlChar *cur, *base;
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007507 if (buf == NULL)
7508 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007509 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00007510 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00007511 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00007512#ifdef DEBUG_BUFFER
7513 xmlGenericError(xmlGenericErrorContext,
7514 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7515#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00007516 xmlBufferCCat(buf, "\"");
7517 base = cur = string;
7518 while(*cur != 0){
7519 if(*cur == '"'){
7520 if (base != cur)
7521 xmlBufferAdd(buf, base, cur - base);
7522 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7523 cur++;
7524 base = cur;
7525 }
7526 else {
7527 cur++;
7528 }
7529 }
7530 if (base != cur)
7531 xmlBufferAdd(buf, base, cur - base);
7532 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007533 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007534 else{
7535 xmlBufferCCat(buf, "\'");
7536 xmlBufferCat(buf, string);
7537 xmlBufferCCat(buf, "\'");
7538 }
Owen Taylor3473f882001-02-23 17:55:21 +00007539 } else {
7540 xmlBufferCCat(buf, "\"");
7541 xmlBufferCat(buf, string);
7542 xmlBufferCCat(buf, "\"");
7543 }
7544}
7545
7546
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007547/**
7548 * xmlGetDocCompressMode:
7549 * @doc: the document
7550 *
7551 * get the compression ratio for a document, ZLIB based
7552 * Returns 0 (uncompressed) to 9 (max compression)
7553 */
7554int
7555xmlGetDocCompressMode (xmlDocPtr doc) {
7556 if (doc == NULL) return(-1);
7557 return(doc->compression);
7558}
7559
7560/**
7561 * xmlSetDocCompressMode:
7562 * @doc: the document
7563 * @mode: the compression ratio
7564 *
7565 * set the compression ratio for a document, ZLIB based
7566 * Correct values: 0 (uncompressed) to 9 (max compression)
7567 */
7568void
7569xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7570 if (doc == NULL) return;
7571 if (mode < 0) doc->compression = 0;
7572 else if (mode > 9) doc->compression = 9;
7573 else doc->compression = mode;
7574}
7575
7576/**
7577 * xmlGetCompressMode:
7578 *
7579 * get the default compression mode used, ZLIB based.
7580 * Returns 0 (uncompressed) to 9 (max compression)
7581 */
7582int
7583xmlGetCompressMode(void)
7584{
7585 return (xmlCompressMode);
7586}
7587
7588/**
7589 * xmlSetCompressMode:
7590 * @mode: the compression ratio
7591 *
7592 * set the default compression mode used, ZLIB based
7593 * Correct values: 0 (uncompressed) to 9 (max compression)
7594 */
7595void
7596xmlSetCompressMode(int mode) {
7597 if (mode < 0) xmlCompressMode = 0;
7598 else if (mode > 9) xmlCompressMode = 9;
7599 else xmlCompressMode = mode;
7600}
7601
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007602#define XML_TREE_NSMAP_PARENT -1
7603#define XML_TREE_NSMAP_XML -2
7604#define XML_TREE_NSMAP_DOC -3
7605#define XML_TREE_NSMAP_CUSTOM -4
7606
7607typedef struct xmlNsMapItem *xmlNsMapItemPtr;
7608struct xmlNsMapItem {
7609 xmlNsMapItemPtr next;
7610 xmlNsMapItemPtr prev;
7611 xmlNsPtr oldNs; /* old ns decl reference */
7612 xmlNsPtr newNs; /* new ns decl reference */
7613 int shadowDepth; /* Shadowed at this depth */
7614 /*
7615 * depth:
7616 * >= 0 == @node's ns-decls
7617 * -1 == @parent's ns-decls
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00007618 * -2 == the doc->oldNs XML ns-decl
7619 * -3 == the doc->oldNs storage ns-decls
7620 * -4 == ns-decls provided via custom ns-handling
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007621 */
7622 int depth;
7623};
7624
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007625typedef struct xmlNsMap *xmlNsMapPtr;
7626struct xmlNsMap {
7627 xmlNsMapItemPtr first;
7628 xmlNsMapItemPtr last;
7629 xmlNsMapItemPtr pool;
7630};
7631
7632#define XML_NSMAP_NOTEMPTY(m) (((m) != NULL) && ((m)->first != NULL))
7633#define XML_NSMAP_FOREACH(m, i) for (i = (m)->first; i != NULL; i = (i)->next)
7634#define XML_NSMAP_POP(m, i) \
7635 i = (m)->last; \
7636 (m)->last = (i)->prev; \
7637 if ((m)->last == NULL) \
7638 (m)->first = NULL; \
7639 else \
7640 (m)->last->next = NULL; \
7641 (i)->next = (m)->pool; \
7642 (m)->pool = i;
7643
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007644/*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007645* xmlDOMWrapNsMapFree:
7646* @map: the ns-map
Daniel Veillardaa6de472008-08-25 14:53:31 +00007647*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007648* Frees the ns-map
7649*/
7650static void
7651xmlDOMWrapNsMapFree(xmlNsMapPtr nsmap)
7652{
7653 xmlNsMapItemPtr cur, tmp;
7654
7655 if (nsmap == NULL)
7656 return;
7657 cur = nsmap->pool;
7658 while (cur != NULL) {
7659 tmp = cur;
7660 cur = cur->next;
7661 xmlFree(tmp);
7662 }
7663 cur = nsmap->first;
7664 while (cur != NULL) {
7665 tmp = cur;
7666 cur = cur->next;
7667 xmlFree(tmp);
7668 }
7669 xmlFree(nsmap);
7670}
7671
7672/*
7673* xmlDOMWrapNsMapAddItem:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007674* @map: the ns-map
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007675* @oldNs: the old ns-struct
7676* @newNs: the new ns-struct
7677* @depth: depth and ns-kind information
Daniel Veillardaa6de472008-08-25 14:53:31 +00007678*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007679* Adds an ns-mapping item.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007680*/
7681static xmlNsMapItemPtr
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00007682xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007683 xmlNsPtr oldNs, xmlNsPtr newNs, int depth)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007684{
7685 xmlNsMapItemPtr ret;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007686 xmlNsMapPtr map;
7687
7688 if (nsmap == NULL)
7689 return(NULL);
7690 if ((position != -1) && (position != 0))
7691 return(NULL);
7692 map = *nsmap;
7693
7694 if (map == NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007695 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007696 * Create the ns-map.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007697 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007698 map = (xmlNsMapPtr) xmlMalloc(sizeof(struct xmlNsMap));
7699 if (map == NULL) {
7700 xmlTreeErrMemory("allocating namespace map");
7701 return (NULL);
7702 }
7703 memset(map, 0, sizeof(struct xmlNsMap));
7704 *nsmap = map;
7705 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00007706
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007707 if (map->pool != NULL) {
7708 /*
7709 * Reuse an item from the pool.
7710 */
7711 ret = map->pool;
7712 map->pool = ret->next;
7713 memset(ret, 0, sizeof(struct xmlNsMapItem));
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007714 } else {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007715 /*
7716 * Create a new item.
7717 */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007718 ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem));
7719 if (ret == NULL) {
7720 xmlTreeErrMemory("allocating namespace map item");
7721 return (NULL);
7722 }
7723 memset(ret, 0, sizeof(struct xmlNsMapItem));
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007724 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00007725
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007726 if (map->first == NULL) {
7727 /*
7728 * First ever.
Daniel Veillardaa6de472008-08-25 14:53:31 +00007729 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007730 map->first = ret;
7731 map->last = ret;
7732 } else if (position == -1) {
7733 /*
7734 * Append.
7735 */
7736 ret->prev = map->last;
7737 map->last->next = ret;
Daniel Veillardaa6de472008-08-25 14:53:31 +00007738 map->last = ret;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007739 } else if (position == 0) {
7740 /*
7741 * Set on first position.
7742 */
7743 map->first->prev = ret;
Daniel Veillardaa6de472008-08-25 14:53:31 +00007744 ret->next = map->first;
7745 map->first = ret;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007746 } else
7747 return(NULL);
7748
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007749 ret->oldNs = oldNs;
7750 ret->newNs = newNs;
7751 ret->shadowDepth = -1;
7752 ret->depth = depth;
7753 return (ret);
7754}
7755
7756/*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007757* xmlDOMWrapStoreNs:
7758* @doc: the doc
7759* @nsName: the namespace name
7760* @prefix: the prefix
Daniel Veillardaa6de472008-08-25 14:53:31 +00007761*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007762* Creates or reuses an xmlNs struct on doc->oldNs with
7763* the given prefix and namespace name.
Daniel Veillardaa6de472008-08-25 14:53:31 +00007764*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007765* Returns the aquired ns struct or NULL in case of an API
7766* or internal error.
7767*/
7768static xmlNsPtr
7769xmlDOMWrapStoreNs(xmlDocPtr doc,
7770 const xmlChar *nsName,
7771 const xmlChar *prefix)
7772{
7773 xmlNsPtr ns;
7774
7775 if (doc == NULL)
7776 return (NULL);
7777 ns = xmlTreeEnsureXMLDecl(doc);
7778 if (ns == NULL)
7779 return (NULL);
7780 if (ns->next != NULL) {
7781 /* Reuse. */
7782 ns = ns->next;
7783 while (ns != NULL) {
7784 if (((ns->prefix == prefix) ||
7785 xmlStrEqual(ns->prefix, prefix)) &&
7786 xmlStrEqual(ns->href, nsName)) {
7787 return (ns);
7788 }
7789 if (ns->next == NULL)
7790 break;
7791 ns = ns->next;
7792 }
7793 }
7794 /* Create. */
Daniel Veillard76d36452009-09-07 11:19:33 +02007795 if (ns != NULL) {
7796 ns->next = xmlNewNs(NULL, nsName, prefix);
7797 return (ns->next);
7798 }
7799 return(NULL);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007800}
7801
7802/*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00007803* xmlDOMWrapNewCtxt:
7804*
7805* Allocates and initializes a new DOM-wrapper context.
7806*
Daniel Veillardaa6de472008-08-25 14:53:31 +00007807* Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal errror.
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00007808*/
7809xmlDOMWrapCtxtPtr
7810xmlDOMWrapNewCtxt(void)
7811{
7812 xmlDOMWrapCtxtPtr ret;
7813
7814 ret = xmlMalloc(sizeof(xmlDOMWrapCtxt));
7815 if (ret == NULL) {
7816 xmlTreeErrMemory("allocating DOM-wrapper context");
7817 return (NULL);
7818 }
7819 memset(ret, 0, sizeof(xmlDOMWrapCtxt));
7820 return (ret);
7821}
7822
7823/*
7824* xmlDOMWrapFreeCtxt:
7825* @ctxt: the DOM-wrapper context
7826*
7827* Frees the DOM-wrapper context.
7828*/
7829void
7830xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt)
7831{
7832 if (ctxt == NULL)
7833 return;
7834 if (ctxt->namespaceMap != NULL)
7835 xmlDOMWrapNsMapFree((xmlNsMapPtr) ctxt->namespaceMap);
7836 /*
7837 * TODO: Store the namespace map in the context.
7838 */
7839 xmlFree(ctxt);
7840}
7841
7842/*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007843* xmlTreeLookupNsListByPrefix:
7844* @nsList: a list of ns-structs
7845* @prefix: the searched prefix
Daniel Veillardaa6de472008-08-25 14:53:31 +00007846*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007847* Searches for a ns-decl with the given prefix in @nsList.
Daniel Veillardaa6de472008-08-25 14:53:31 +00007848*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007849* Returns the ns-decl if found, NULL if not found and on
7850* API errors.
7851*/
7852static xmlNsPtr
7853xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix)
7854{
7855 if (nsList == NULL)
7856 return (NULL);
7857 {
7858 xmlNsPtr ns;
7859 ns = nsList;
7860 do {
7861 if ((prefix == ns->prefix) ||
7862 xmlStrEqual(prefix, ns->prefix)) {
7863 return (ns);
7864 }
7865 ns = ns->next;
7866 } while (ns != NULL);
7867 }
7868 return (NULL);
7869}
7870
7871/*
7872*
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00007873* xmlDOMWrapNSNormGatherInScopeNs:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007874* @map: the namespace map
7875* @node: the node to start with
Daniel Veillardaa6de472008-08-25 14:53:31 +00007876*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007877* Puts in-scope namespaces into the ns-map.
Daniel Veillardaa6de472008-08-25 14:53:31 +00007878*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007879* Returns 0 on success, -1 on API or internal errors.
7880*/
7881static int
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007882xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapPtr *map,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007883 xmlNodePtr node)
7884{
7885 xmlNodePtr cur;
7886 xmlNsPtr ns;
7887 xmlNsMapItemPtr mi;
7888 int shadowed;
7889
7890 if ((map == NULL) || (*map != NULL))
7891 return (-1);
7892 /*
7893 * Get in-scope ns-decls of @parent.
7894 */
7895 cur = node;
7896 while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) {
7897 if (cur->type == XML_ELEMENT_NODE) {
7898 if (cur->nsDef != NULL) {
7899 ns = cur->nsDef;
7900 do {
7901 shadowed = 0;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007902 if (XML_NSMAP_NOTEMPTY(*map)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007903 /*
7904 * Skip shadowed prefixes.
7905 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007906 XML_NSMAP_FOREACH(*map, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007907 if ((ns->prefix == mi->newNs->prefix) ||
7908 xmlStrEqual(ns->prefix, mi->newNs->prefix)) {
7909 shadowed = 1;
7910 break;
7911 }
7912 }
7913 }
7914 /*
7915 * Insert mapping.
7916 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007917 mi = xmlDOMWrapNsMapAddItem(map, 0, NULL,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007918 ns, XML_TREE_NSMAP_PARENT);
7919 if (mi == NULL)
7920 return (-1);
7921 if (shadowed)
7922 mi->shadowDepth = 0;
7923 ns = ns->next;
7924 } while (ns != NULL);
7925 }
7926 }
7927 cur = cur->parent;
7928 }
7929 return (0);
7930}
7931
7932/*
7933* XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict;
7934* otherwise copy it, when it was in the source-dict.
7935*/
7936#define XML_TREE_ADOPT_STR(str) \
7937 if (adoptStr && (str != NULL)) { \
7938 if (destDoc->dict) { \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00007939 const xmlChar *old = str; \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007940 str = xmlDictLookup(destDoc->dict, str, -1); \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00007941 if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \
7942 (!xmlDictOwns(sourceDoc->dict, old))) \
Daniel Veillard39e5c892005-07-03 22:48:50 +00007943 xmlFree((char *)old); \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007944 } else if ((sourceDoc) && (sourceDoc->dict) && \
7945 xmlDictOwns(sourceDoc->dict, str)) { \
7946 str = BAD_CAST xmlStrdup(str); \
7947 } \
7948 }
7949
7950/*
7951* XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then
7952* put it in dest-dict or copy it.
7953*/
7954#define XML_TREE_ADOPT_STR_2(str) \
7955 if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \
7956 (sourceDoc->dict != NULL) && \
7957 xmlDictOwns(sourceDoc->dict, cur->content)) { \
7958 if (destDoc->dict) \
7959 cur->content = (xmlChar *) \
7960 xmlDictLookup(destDoc->dict, cur->content, -1); \
7961 else \
7962 cur->content = xmlStrdup(BAD_CAST cur->content); \
7963 }
7964
7965/*
7966* xmlDOMWrapNSNormAddNsMapItem2:
7967*
7968* For internal use. Adds a ns-decl mapping.
7969*
Daniel Veillardaa6de472008-08-25 14:53:31 +00007970* Returns 0 on success, -1 on internal errors.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007971*/
7972static int
7973xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number,
7974 xmlNsPtr oldNs, xmlNsPtr newNs)
7975{
7976 if (*list == NULL) {
7977 *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr));
7978 if (*list == NULL) {
7979 xmlTreeErrMemory("alloc ns map item");
7980 return(-1);
7981 }
7982 *size = 3;
7983 *number = 0;
7984 } else if ((*number) >= (*size)) {
7985 *size *= 2;
7986 *list = (xmlNsPtr *) xmlRealloc(*list,
7987 (*size) * 2 * sizeof(xmlNsPtr));
7988 if (*list == NULL) {
7989 xmlTreeErrMemory("realloc ns map item");
7990 return(-1);
7991 }
7992 }
7993 (*list)[2 * (*number)] = oldNs;
7994 (*list)[2 * (*number) +1] = newNs;
7995 (*number)++;
7996 return (0);
7997}
7998
7999/*
8000* xmlDOMWrapRemoveNode:
Daniel Veillard304e78c2005-07-03 16:19:41 +00008001* @ctxt: a DOM wrapper context
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008002* @doc: the doc
8003* @node: the node to be removed.
Daniel Veillard304e78c2005-07-03 16:19:41 +00008004* @options: set of options, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008005*
8006* Unlinks the given node from its owner.
8007* This will substitute ns-references to node->nsDef for
8008* ns-references to doc->oldNs, thus ensuring the removed
8009* branch to be autark wrt ns-references.
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008010*
8011* NOTE: This function was not intensively tested.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008012*
8013* Returns 0 on success, 1 if the node is not supported,
Daniel Veillardaa6de472008-08-25 14:53:31 +00008014* -1 on API and internal errors.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008015*/
8016int
8017xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc,
8018 xmlNodePtr node, int options ATTRIBUTE_UNUSED)
8019{
8020 xmlNsPtr *list = NULL;
8021 int sizeList, nbList, i, j;
8022 xmlNsPtr ns;
8023
8024 if ((node == NULL) || (doc == NULL) || (node->doc != doc))
8025 return (-1);
8026
8027 /* TODO: 0 or -1 ? */
8028 if (node->parent == NULL)
8029 return (0);
8030
Daniel Veillardaa6de472008-08-25 14:53:31 +00008031 switch (node->type) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008032 case XML_TEXT_NODE:
8033 case XML_CDATA_SECTION_NODE:
8034 case XML_ENTITY_REF_NODE:
8035 case XML_PI_NODE:
8036 case XML_COMMENT_NODE:
8037 xmlUnlinkNode(node);
8038 return (0);
Daniel Veillardaa6de472008-08-25 14:53:31 +00008039 case XML_ELEMENT_NODE:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008040 case XML_ATTRIBUTE_NODE:
8041 break;
8042 default:
8043 return (1);
8044 }
8045 xmlUnlinkNode(node);
8046 /*
8047 * Save out-of-scope ns-references in doc->oldNs.
8048 */
8049 do {
8050 switch (node->type) {
8051 case XML_ELEMENT_NODE:
8052 if ((ctxt == NULL) && (node->nsDef != NULL)) {
8053 ns = node->nsDef;
8054 do {
8055 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
8056 &nbList, ns, ns) == -1)
8057 goto internal_error;
8058 ns = ns->next;
8059 } while (ns != NULL);
8060 }
8061 /* No break on purpose. */
8062 case XML_ATTRIBUTE_NODE:
Daniel Veillardaa6de472008-08-25 14:53:31 +00008063 if (node->ns != NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008064 /*
8065 * Find a mapping.
8066 */
8067 if (list != NULL) {
8068 for (i = 0, j = 0; i < nbList; i++, j += 2) {
8069 if (node->ns == list[j]) {
8070 node->ns = list[++j];
8071 goto next_node;
8072 }
8073 }
8074 }
8075 ns = NULL;
8076 if (ctxt != NULL) {
8077 /*
8078 * User defined.
8079 */
8080 } else {
8081 /*
8082 * Add to doc's oldNs.
8083 */
8084 ns = xmlDOMWrapStoreNs(doc, node->ns->href,
8085 node->ns->prefix);
8086 if (ns == NULL)
8087 goto internal_error;
8088 }
8089 if (ns != NULL) {
8090 /*
8091 * Add mapping.
8092 */
8093 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
8094 &nbList, node->ns, ns) == -1)
8095 goto internal_error;
8096 }
8097 node->ns = ns;
8098 }
8099 if ((node->type == XML_ELEMENT_NODE) &&
8100 (node->properties != NULL)) {
8101 node = (xmlNodePtr) node->properties;
8102 continue;
8103 }
8104 break;
8105 default:
8106 goto next_sibling;
Daniel Veillardaa6de472008-08-25 14:53:31 +00008107 }
8108next_node:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008109 if ((node->type == XML_ELEMENT_NODE) &&
8110 (node->children != NULL)) {
8111 node = node->children;
8112 continue;
8113 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00008114next_sibling:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008115 if (node == NULL)
8116 break;
8117 if (node->next != NULL)
8118 node = node->next;
8119 else {
8120 node = node->parent;
8121 goto next_sibling;
8122 }
8123 } while (node != NULL);
8124
8125 if (list != NULL)
8126 xmlFree(list);
8127 return (0);
8128
8129internal_error:
8130 if (list != NULL)
8131 xmlFree(list);
8132 return (-1);
8133}
8134
8135/*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008136* xmlSearchNsByNamespaceStrict:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008137* @doc: the document
8138* @node: the start node
8139* @nsName: the searched namespace name
8140* @retNs: the resulting ns-decl
8141* @prefixed: if the found ns-decl must have a prefix (for attributes)
8142*
8143* Dynamically searches for a ns-declaration which matches
8144* the given @nsName in the ancestor-or-self axis of @node.
8145*
8146* Returns 1 if a ns-decl was found, 0 if not and -1 on API
8147* and internal errors.
8148*/
8149static int
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008150xmlSearchNsByNamespaceStrict(xmlDocPtr doc, xmlNodePtr node,
8151 const xmlChar* nsName,
8152 xmlNsPtr *retNs, int prefixed)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008153{
8154 xmlNodePtr cur, prev = NULL, out = NULL;
8155 xmlNsPtr ns, prevns;
8156
8157 if ((doc == NULL) || (nsName == NULL) || (retNs == NULL))
8158 return (-1);
8159
8160 *retNs = NULL;
8161 if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
8162 *retNs = xmlTreeEnsureXMLDecl(doc);
8163 if (*retNs == NULL)
8164 return (-1);
8165 return (1);
8166 }
8167 cur = node;
8168 do {
8169 if (cur->type == XML_ELEMENT_NODE) {
8170 if (cur->nsDef != NULL) {
8171 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8172 if (prefixed && (ns->prefix == NULL))
8173 continue;
8174 if (prev != NULL) {
8175 /*
8176 * Check the last level of ns-decls for a
8177 * shadowing prefix.
8178 */
8179 prevns = prev->nsDef;
8180 do {
8181 if ((prevns->prefix == ns->prefix) ||
8182 ((prevns->prefix != NULL) &&
8183 (ns->prefix != NULL) &&
8184 xmlStrEqual(prevns->prefix, ns->prefix))) {
8185 /*
8186 * Shadowed.
8187 */
8188 break;
8189 }
8190 prevns = prevns->next;
8191 } while (prevns != NULL);
8192 if (prevns != NULL)
8193 continue;
8194 }
8195 /*
8196 * Ns-name comparison.
8197 */
8198 if ((nsName == ns->href) ||
8199 xmlStrEqual(nsName, ns->href)) {
8200 /*
8201 * At this point the prefix can only be shadowed,
8202 * if we are the the (at least) 3rd level of
8203 * ns-decls.
8204 */
8205 if (out) {
8206 int ret;
Daniel Veillardaa6de472008-08-25 14:53:31 +00008207
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008208 ret = xmlNsInScope(doc, node, prev, ns->prefix);
8209 if (ret < 0)
8210 return (-1);
8211 /*
8212 * TODO: Should we try to find a matching ns-name
8213 * only once? This here keeps on searching.
8214 * I think we should try further since, there might
8215 * be an other matching ns-decl with an unshadowed
8216 * prefix.
8217 */
8218 if (! ret)
8219 continue;
8220 }
8221 *retNs = ns;
8222 return (1);
8223 }
8224 }
8225 out = prev;
8226 prev = cur;
8227 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008228 } else if ((cur->type == XML_ENTITY_NODE) ||
8229 (cur->type == XML_ENTITY_DECL))
8230 return (0);
8231 cur = cur->parent;
8232 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
8233 return (0);
8234}
8235
8236/*
8237* xmlSearchNsByPrefixStrict:
8238* @doc: the document
8239* @node: the start node
8240* @prefix: the searched namespace prefix
8241* @retNs: the resulting ns-decl
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008242*
8243* Dynamically searches for a ns-declaration which matches
8244* the given @nsName in the ancestor-or-self axis of @node.
8245*
8246* Returns 1 if a ns-decl was found, 0 if not and -1 on API
8247* and internal errors.
8248*/
8249static int
8250xmlSearchNsByPrefixStrict(xmlDocPtr doc, xmlNodePtr node,
8251 const xmlChar* prefix,
8252 xmlNsPtr *retNs)
8253{
8254 xmlNodePtr cur;
8255 xmlNsPtr ns;
8256
8257 if ((doc == NULL) || (node == NULL))
8258 return (-1);
8259
8260 if (retNs)
8261 *retNs = NULL;
8262 if (IS_STR_XML(prefix)) {
8263 if (retNs) {
8264 *retNs = xmlTreeEnsureXMLDecl(doc);
8265 if (*retNs == NULL)
8266 return (-1);
8267 }
8268 return (1);
8269 }
8270 cur = node;
8271 do {
8272 if (cur->type == XML_ELEMENT_NODE) {
8273 if (cur->nsDef != NULL) {
8274 ns = cur->nsDef;
Daniel Veillardaa6de472008-08-25 14:53:31 +00008275 do {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008276 if ((prefix == ns->prefix) ||
8277 xmlStrEqual(prefix, ns->prefix))
8278 {
8279 /*
8280 * Disabled namespaces, e.g. xmlns:abc="".
8281 */
8282 if (ns->href == NULL)
8283 return(0);
8284 if (retNs)
8285 *retNs = ns;
8286 return (1);
8287 }
8288 ns = ns->next;
Daniel Veillardaa6de472008-08-25 14:53:31 +00008289 } while (ns != NULL);
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008290 }
8291 } else if ((cur->type == XML_ENTITY_NODE) ||
8292 (cur->type == XML_ENTITY_DECL))
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008293 return (0);
8294 cur = cur->parent;
8295 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
8296 return (0);
8297}
8298
8299/*
8300* xmlDOMWrapNSNormDeclareNsForced:
8301* @doc: the doc
8302* @elem: the element-node to declare on
8303* @nsName: the namespace-name of the ns-decl
8304* @prefix: the preferred prefix of the ns-decl
8305* @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls
8306*
8307* Declares a new namespace on @elem. It tries to use the
8308* given @prefix; if a ns-decl with the given prefix is already existent
8309* on @elem, it will generate an other prefix.
8310*
8311* Returns 1 if a ns-decl was found, 0 if not and -1 on API
8312* and internal errors.
8313*/
8314static xmlNsPtr
8315xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc,
8316 xmlNodePtr elem,
8317 const xmlChar *nsName,
8318 const xmlChar *prefix,
8319 int checkShadow)
8320{
8321
8322 xmlNsPtr ret;
8323 char buf[50];
8324 const xmlChar *pref;
8325 int counter = 0;
8326 /*
8327 * Create a ns-decl on @anchor.
8328 */
8329 pref = prefix;
8330 while (1) {
8331 /*
8332 * Lookup whether the prefix is unused in elem's ns-decls.
8333 */
8334 if ((elem->nsDef != NULL) &&
8335 (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL))
8336 goto ns_next_prefix;
8337 if (checkShadow && elem->parent &&
8338 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8339 /*
8340 * Does it shadow ancestor ns-decls?
8341 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008342 if (xmlSearchNsByPrefixStrict(doc, elem->parent, pref, NULL) == 1)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008343 goto ns_next_prefix;
8344 }
8345 ret = xmlNewNs(NULL, nsName, pref);
8346 if (ret == NULL)
8347 return (NULL);
8348 if (elem->nsDef == NULL)
8349 elem->nsDef = ret;
8350 else {
8351 xmlNsPtr ns2 = elem->nsDef;
8352 while (ns2->next != NULL)
8353 ns2 = ns2->next;
8354 ns2->next = ret;
8355 }
8356 return (ret);
8357ns_next_prefix:
8358 counter++;
8359 if (counter > 1000)
8360 return (NULL);
8361 if (prefix == NULL) {
8362 snprintf((char *) buf, sizeof(buf),
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008363 "ns_%d", counter);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008364 } else
8365 snprintf((char *) buf, sizeof(buf),
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008366 "%.30s_%d", (char *)prefix, counter);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008367 pref = BAD_CAST buf;
8368 }
8369}
8370
8371/*
8372* xmlDOMWrapNSNormAquireNormalizedNs:
8373* @doc: the doc
8374* @elem: the element-node to declare namespaces on
8375* @ns: the ns-struct to use for the search
8376* @retNs: the found/created ns-struct
8377* @nsMap: the ns-map
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008378* @depth: the current tree depth
8379* @ancestorsOnly: search in ancestor ns-decls only
8380* @prefixed: if the searched ns-decl must have a prefix (for attributes)
8381*
8382* Searches for a matching ns-name in the ns-decls of @nsMap, if not
8383* found it will either declare it on @elem, or store it in doc->oldNs.
8384* If a new ns-decl needs to be declared on @elem, it tries to use the
8385* @ns->prefix for it, if this prefix is already in use on @elem, it will
8386* change the prefix or the new ns-decl.
8387*
8388* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8389*/
8390static int
8391xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc,
8392 xmlNodePtr elem,
8393 xmlNsPtr ns,
8394 xmlNsPtr *retNs,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008395 xmlNsMapPtr *nsMap,
Daniel Veillardaa6de472008-08-25 14:53:31 +00008396
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008397 int depth,
8398 int ancestorsOnly,
8399 int prefixed)
8400{
Daniel Veillardaa6de472008-08-25 14:53:31 +00008401 xmlNsMapItemPtr mi;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008402
8403 if ((doc == NULL) || (ns == NULL) || (retNs == NULL) ||
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008404 (nsMap == NULL))
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008405 return (-1);
8406
8407 *retNs = NULL;
8408 /*
8409 * Handle XML namespace.
8410 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008411 if (IS_STR_XML(ns->prefix)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008412 /*
8413 * Insert XML namespace mapping.
8414 */
8415 *retNs = xmlTreeEnsureXMLDecl(doc);
8416 if (*retNs == NULL)
8417 return (-1);
8418 return (0);
8419 }
8420 /*
8421 * If the search should be done in ancestors only and no
8422 * @elem (the first ancestor) was specified, then skip the search.
8423 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008424 if ((XML_NSMAP_NOTEMPTY(*nsMap)) &&
8425 (! (ancestorsOnly && (elem == NULL))))
Daniel Veillardaa6de472008-08-25 14:53:31 +00008426 {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008427 /*
8428 * Try to find an equal ns-name in in-scope ns-decls.
8429 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008430 XML_NSMAP_FOREACH(*nsMap, mi) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00008431 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8432 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008433 * ancestorsOnly: This should be turned on to gain speed,
8434 * if one knows that the branch itself was already
8435 * ns-wellformed and no stale references existed.
8436 * I.e. it searches in the ancestor axis only.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008437 */
8438 ((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) &&
8439 /* Skip shadowed prefixes. */
Daniel Veillardaa6de472008-08-25 14:53:31 +00008440 (mi->shadowDepth == -1) &&
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008441 /* Skip xmlns="" or xmlns:foo="". */
8442 ((mi->newNs->href != NULL) &&
Daniel Veillardaa6de472008-08-25 14:53:31 +00008443 (mi->newNs->href[0] != 0)) &&
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008444 /* Ensure a prefix if wanted. */
8445 ((! prefixed) || (mi->newNs->prefix != NULL)) &&
8446 /* Equal ns name */
8447 ((mi->newNs->href == ns->href) ||
8448 xmlStrEqual(mi->newNs->href, ns->href))) {
8449 /* Set the mapping. */
8450 mi->oldNs = ns;
8451 *retNs = mi->newNs;
8452 return (0);
8453 }
8454 }
8455 }
8456 /*
8457 * No luck, the namespace is out of scope or shadowed.
8458 */
8459 if (elem == NULL) {
8460 xmlNsPtr tmpns;
8461
8462 /*
8463 * Store ns-decls in "oldNs" of the document-node.
8464 */
8465 tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix);
8466 if (tmpns == NULL)
8467 return (-1);
8468 /*
8469 * Insert mapping.
Daniel Veillardaa6de472008-08-25 14:53:31 +00008470 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008471 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008472 tmpns, XML_TREE_NSMAP_DOC) == NULL) {
8473 xmlFreeNs(tmpns);
8474 return (-1);
8475 }
8476 *retNs = tmpns;
8477 } else {
8478 xmlNsPtr tmpns;
8479
8480 tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href,
8481 ns->prefix, 0);
8482 if (tmpns == NULL)
8483 return (-1);
8484
8485 if (*nsMap != NULL) {
8486 /*
8487 * Does it shadow ancestor ns-decls?
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008488 */
8489 XML_NSMAP_FOREACH(*nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008490 if ((mi->depth < depth) &&
8491 (mi->shadowDepth == -1) &&
8492 ((ns->prefix == mi->newNs->prefix) ||
8493 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8494 /*
8495 * Shadows.
8496 */
8497 mi->shadowDepth = depth;
8498 break;
8499 }
8500 }
8501 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008502 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, depth) == NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008503 xmlFreeNs(tmpns);
8504 return (-1);
8505 }
8506 *retNs = tmpns;
8507 }
8508 return (0);
8509}
8510
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008511typedef enum {
Daniel Veillardaa6de472008-08-25 14:53:31 +00008512 XML_DOM_RECONNS_REMOVEREDUND = 1<<0
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008513} xmlDOMReconcileNSOptions;
8514
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008515/*
8516* xmlDOMWrapReconcileNamespaces:
Daniel Veillard304e78c2005-07-03 16:19:41 +00008517* @ctxt: DOM wrapper context, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008518* @elem: the element-node
8519* @options: option flags
8520*
8521* Ensures that ns-references point to ns-decls hold on element-nodes.
8522* Ensures that the tree is namespace wellformed by creating additional
8523* ns-decls where needed. Note that, since prefixes of already existent
8524* ns-decls can be shadowed by this process, it could break QNames in
8525* attribute values or element content.
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008526*
8527* NOTE: This function was not intensively tested.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008528*
8529* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
Daniel Veillardaa6de472008-08-25 14:53:31 +00008530*/
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008531
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008532int
8533xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,
8534 xmlNodePtr elem,
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008535 int options)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008536{
8537 int depth = -1, adoptns = 0, parnsdone = 0;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008538 xmlNsPtr ns, prevns;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008539 xmlDocPtr doc;
8540 xmlNodePtr cur, curElem = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008541 xmlNsMapPtr nsMap = NULL;
8542 xmlNsMapItemPtr /* topmi = NULL, */ mi;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008543 /* @ancestorsOnly should be set by an option flag. */
8544 int ancestorsOnly = 0;
Daniel Veillardaa6de472008-08-25 14:53:31 +00008545 int optRemoveRedundantNS =
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008546 ((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0;
8547 xmlNsPtr *listRedund = NULL;
8548 int sizeRedund = 0, nbRedund = 0, ret, i, j;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008549
8550 if ((elem == NULL) || (elem->doc == NULL) ||
8551 (elem->type != XML_ELEMENT_NODE))
8552 return (-1);
8553
8554 doc = elem->doc;
8555 cur = elem;
8556 do {
8557 switch (cur->type) {
8558 case XML_ELEMENT_NODE:
8559 adoptns = 1;
8560 curElem = cur;
8561 depth++;
8562 /*
8563 * Namespace declarations.
8564 */
8565 if (cur->nsDef != NULL) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008566 prevns = NULL;
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008567 ns = cur->nsDef;
8568 while (ns != NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008569 if (! parnsdone) {
8570 if ((elem->parent) &&
8571 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8572 /*
8573 * Gather ancestor in-scope ns-decls.
8574 */
8575 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8576 elem->parent) == -1)
8577 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008578 }
8579 parnsdone = 1;
8580 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00008581
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008582 /*
8583 * Lookup the ns ancestor-axis for equal ns-decls in scope.
8584 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008585 if (optRemoveRedundantNS && XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008586 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008587 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8588 (mi->shadowDepth == -1) &&
8589 ((ns->prefix == mi->newNs->prefix) ||
8590 xmlStrEqual(ns->prefix, mi->newNs->prefix)) &&
8591 ((ns->href == mi->newNs->href) ||
8592 xmlStrEqual(ns->href, mi->newNs->href)))
Daniel Veillardaa6de472008-08-25 14:53:31 +00008593 {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008594 /*
8595 * A redundant ns-decl was found.
8596 * Add it to the list of redundant ns-decls.
8597 */
8598 if (xmlDOMWrapNSNormAddNsMapItem2(&listRedund,
8599 &sizeRedund, &nbRedund, ns, mi->newNs) == -1)
8600 goto internal_error;
8601 /*
8602 * Remove the ns-decl from the element-node.
Daniel Veillardaa6de472008-08-25 14:53:31 +00008603 */
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008604 if (prevns)
8605 prevns->next = ns->next;
8606 else
Daniel Veillardaa6de472008-08-25 14:53:31 +00008607 cur->nsDef = ns->next;
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008608 goto next_ns_decl;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008609 }
8610 }
8611 }
8612
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008613 /*
8614 * Skip ns-references handling if the referenced
8615 * ns-decl is declared on the same element.
8616 */
8617 if ((cur->ns != NULL) && adoptns && (cur->ns == ns))
Daniel Veillardaa6de472008-08-25 14:53:31 +00008618 adoptns = 0;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008619 /*
8620 * Does it shadow any ns-decl?
8621 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008622 if (XML_NSMAP_NOTEMPTY(nsMap)) {
8623 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008624 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8625 (mi->shadowDepth == -1) &&
8626 ((ns->prefix == mi->newNs->prefix) ||
8627 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00008628
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008629 mi->shadowDepth = depth;
8630 }
8631 }
8632 }
8633 /*
8634 * Push mapping.
8635 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008636 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008637 depth) == NULL)
Daniel Veillardaa6de472008-08-25 14:53:31 +00008638 goto internal_error;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008639
8640 prevns = ns;
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008641next_ns_decl:
Daniel Veillardaa6de472008-08-25 14:53:31 +00008642 ns = ns->next;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008643 }
8644 }
8645 if (! adoptns)
8646 goto ns_end;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008647 /* No break on purpose. */
8648 case XML_ATTRIBUTE_NODE:
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008649 /* No ns, no fun. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008650 if (cur->ns == NULL)
8651 goto ns_end;
Daniel Veillardaa6de472008-08-25 14:53:31 +00008652
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008653 if (! parnsdone) {
8654 if ((elem->parent) &&
8655 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8656 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8657 elem->parent) == -1)
8658 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008659 }
8660 parnsdone = 1;
8661 }
8662 /*
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008663 * Adjust the reference if this was a redundant ns-decl.
8664 */
8665 if (listRedund) {
8666 for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8667 if (cur->ns == listRedund[j]) {
8668 cur->ns = listRedund[++j];
8669 break;
8670 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00008671 }
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008672 }
8673 /*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008674 * Adopt ns-references.
8675 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008676 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008677 /*
8678 * Search for a mapping.
8679 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008680 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008681 if ((mi->shadowDepth == -1) &&
8682 (cur->ns == mi->oldNs)) {
8683
8684 cur->ns = mi->newNs;
8685 goto ns_end;
8686 }
8687 }
8688 }
8689 /*
8690 * Aquire a normalized ns-decl and add it to the map.
8691 */
8692 if (xmlDOMWrapNSNormAquireNormalizedNs(doc, curElem,
8693 cur->ns, &ns,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008694 &nsMap, depth,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008695 ancestorsOnly,
8696 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8697 goto internal_error;
8698 cur->ns = ns;
8699
8700ns_end:
8701 if ((cur->type == XML_ELEMENT_NODE) &&
8702 (cur->properties != NULL)) {
8703 /*
8704 * Process attributes.
8705 */
8706 cur = (xmlNodePtr) cur->properties;
8707 continue;
8708 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00008709 break;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008710 default:
8711 goto next_sibling;
8712 }
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008713into_content:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008714 if ((cur->type == XML_ELEMENT_NODE) &&
8715 (cur->children != NULL)) {
8716 /*
8717 * Process content of element-nodes only.
8718 */
8719 cur = cur->children;
8720 continue;
8721 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00008722next_sibling:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008723 if (cur == elem)
8724 break;
8725 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00008726 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008727 /*
8728 * Pop mappings.
8729 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008730 while ((nsMap->last != NULL) &&
8731 (nsMap->last->depth >= depth))
8732 {
Daniel Veillardaa6de472008-08-25 14:53:31 +00008733 XML_NSMAP_POP(nsMap, mi)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008734 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008735 /*
8736 * Unshadow.
8737 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008738 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008739 if (mi->shadowDepth >= depth)
8740 mi->shadowDepth = -1;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008741 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00008742 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008743 depth--;
8744 }
8745 if (cur->next != NULL)
8746 cur = cur->next;
8747 else {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008748 if (cur->type == XML_ATTRIBUTE_NODE) {
8749 cur = cur->parent;
8750 goto into_content;
8751 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008752 cur = cur->parent;
8753 goto next_sibling;
8754 }
8755 } while (cur != NULL);
Daniel Veillardaa6de472008-08-25 14:53:31 +00008756
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008757 ret = 0;
8758 goto exit;
8759internal_error:
8760 ret = -1;
8761exit:
Daniel Veillardaa6de472008-08-25 14:53:31 +00008762 if (listRedund) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008763 for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8764 xmlFreeNs(listRedund[j]);
8765 }
8766 xmlFree(listRedund);
8767 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008768 if (nsMap != NULL)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008769 xmlDOMWrapNsMapFree(nsMap);
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008770 return (ret);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008771}
8772
8773/*
8774* xmlDOMWrapAdoptBranch:
8775* @ctxt: the optional context for custom processing
8776* @sourceDoc: the optional sourceDoc
8777* @node: the element-node to start with
8778* @destDoc: the destination doc for adoption
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008779* @destParent: the optional new parent of @node in @destDoc
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008780* @options: option flags
8781*
8782* Ensures that ns-references point to @destDoc: either to
8783* elements->nsDef entries if @destParent is given, or to
8784* @destDoc->oldNs otherwise.
8785* If @destParent is given, it ensures that the tree is namespace
8786* wellformed by creating additional ns-decls where needed.
8787* Note that, since prefixes of already existent ns-decls can be
8788* shadowed by this process, it could break QNames in attribute
8789* values or element content.
8790*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008791* NOTE: This function was not intensively tested.
8792*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008793* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8794*/
8795static int
8796xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
8797 xmlDocPtr sourceDoc,
8798 xmlNodePtr node,
8799 xmlDocPtr destDoc,
8800 xmlNodePtr destParent,
8801 int options ATTRIBUTE_UNUSED)
8802{
8803 int ret = 0;
8804 xmlNodePtr cur, curElem = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008805 xmlNsMapPtr nsMap = NULL;
8806 xmlNsMapItemPtr mi;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008807 xmlNsPtr ns = NULL;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008808 int depth = -1, adoptStr = 1;
8809 /* gather @parent's ns-decls. */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008810 int parnsdone;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008811 /* @ancestorsOnly should be set per option. */
8812 int ancestorsOnly = 0;
Daniel Veillardaa6de472008-08-25 14:53:31 +00008813
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008814 /*
8815 * Optimize string adoption for equal or none dicts.
8816 */
8817 if ((sourceDoc != NULL) &&
8818 (sourceDoc->dict == destDoc->dict))
8819 adoptStr = 0;
8820 else
8821 adoptStr = 1;
8822
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008823 /*
8824 * Get the ns-map from the context if available.
8825 */
8826 if (ctxt)
8827 nsMap = (xmlNsMapPtr) ctxt->namespaceMap;
8828 /*
8829 * Disable search for ns-decls in the parent-axis of the
8830 * desination element, if:
8831 * 1) there's no destination parent
8832 * 2) custom ns-reference handling is used
8833 */
8834 if ((destParent == NULL) ||
8835 (ctxt && ctxt->getNsForNodeFunc))
8836 {
8837 parnsdone = 1;
8838 } else
8839 parnsdone = 0;
8840
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008841 cur = node;
8842 while (cur != NULL) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008843 /*
8844 * Paranoid source-doc sanity check.
8845 */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008846 if (cur->doc != sourceDoc) {
8847 /*
8848 * We'll assume XIncluded nodes if the doc differs.
8849 * TODO: Do we need to reconciliate XIncluded nodes?
8850 * This here skips XIncluded nodes and tries to handle
8851 * broken sequences.
8852 */
8853 if (cur->next == NULL)
8854 goto leave_node;
8855 do {
8856 cur = cur->next;
8857 if ((cur->type == XML_XINCLUDE_END) ||
8858 (cur->doc == node->doc))
8859 break;
8860 } while (cur->next != NULL);
8861
8862 if (cur->doc != node->doc)
8863 goto leave_node;
8864 }
8865 cur->doc = destDoc;
8866 switch (cur->type) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00008867 case XML_XINCLUDE_START:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008868 case XML_XINCLUDE_END:
8869 /*
8870 * TODO
8871 */
8872 return (-1);
Daniel Veillardaa6de472008-08-25 14:53:31 +00008873 case XML_ELEMENT_NODE:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008874 curElem = cur;
8875 depth++;
8876 /*
Daniel Veillardaa6de472008-08-25 14:53:31 +00008877 * Namespace declarations.
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008878 * - ns->href and ns->prefix are never in the dict, so
8879 * we need not move the values over to the destination dict.
8880 * - Note that for custom handling of ns-references,
8881 * the ns-decls need not be stored in the ns-map,
8882 * since they won't be referenced by node->ns.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008883 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008884 if ((cur->nsDef) &&
8885 ((ctxt == NULL) || (ctxt->getNsForNodeFunc == NULL)))
8886 {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008887 if (! parnsdone) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008888 /*
8889 * Gather @parent's in-scope ns-decls.
8890 */
8891 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8892 destParent) == -1)
8893 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008894 parnsdone = 1;
8895 }
8896 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8897 /*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008898 * NOTE: ns->prefix and ns->href are never in the dict.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008899 * XML_TREE_ADOPT_STR(ns->prefix)
8900 * XML_TREE_ADOPT_STR(ns->href)
Daniel Veillardaa6de472008-08-25 14:53:31 +00008901 */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008902 /*
8903 * Does it shadow any ns-decl?
Daniel Veillardaa6de472008-08-25 14:53:31 +00008904 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008905 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008906 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008907 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8908 (mi->shadowDepth == -1) &&
8909 ((ns->prefix == mi->newNs->prefix) ||
8910 xmlStrEqual(ns->prefix,
8911 mi->newNs->prefix))) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00008912
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008913 mi->shadowDepth = depth;
8914 }
8915 }
8916 }
8917 /*
8918 * Push mapping.
8919 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008920 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008921 ns, ns, depth) == NULL)
8922 goto internal_error;
8923 }
8924 }
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008925 /* No break on purpose. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008926 case XML_ATTRIBUTE_NODE:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008927 /* No namespace, no fun. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008928 if (cur->ns == NULL)
8929 goto ns_end;
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008930
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008931 if (! parnsdone) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008932 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8933 destParent) == -1)
8934 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008935 parnsdone = 1;
8936 }
8937 /*
8938 * Adopt ns-references.
8939 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008940 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008941 /*
8942 * Search for a mapping.
8943 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008944 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008945 if ((mi->shadowDepth == -1) &&
8946 (cur->ns == mi->oldNs)) {
8947
8948 cur->ns = mi->newNs;
8949 goto ns_end;
8950 }
8951 }
8952 }
8953 /*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008954 * No matching namespace in scope. We need a new one.
8955 */
8956 if ((ctxt) && (ctxt->getNsForNodeFunc)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008957 /*
8958 * User-defined behaviour.
8959 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008960 ns = ctxt->getNsForNodeFunc(ctxt, cur,
8961 cur->ns->href, cur->ns->prefix);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008962 /*
8963 * Insert mapping if ns is available; it's the users fault
8964 * if not.
8965 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008966 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008967 cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008968 goto internal_error;
8969 cur->ns = ns;
8970 } else {
8971 /*
8972 * Aquire a normalized ns-decl and add it to the map.
8973 */
8974 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
Daniel Veillardaa6de472008-08-25 14:53:31 +00008975 /* ns-decls on curElem or on destDoc->oldNs */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008976 destParent ? curElem : NULL,
8977 cur->ns, &ns,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008978 &nsMap, depth,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008979 ancestorsOnly,
8980 /* ns-decls must be prefixed for attributes. */
8981 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8982 goto internal_error;
8983 cur->ns = ns;
8984 }
8985ns_end:
8986 /*
8987 * Further node properties.
8988 * TODO: Is this all?
8989 */
8990 XML_TREE_ADOPT_STR(cur->name)
8991 if (cur->type == XML_ELEMENT_NODE) {
8992 cur->psvi = NULL;
8993 cur->line = 0;
8994 cur->extra = 0;
8995 /*
8996 * Walk attributes.
8997 */
8998 if (cur->properties != NULL) {
8999 /*
9000 * Process first attribute node.
9001 */
9002 cur = (xmlNodePtr) cur->properties;
9003 continue;
9004 }
9005 } else {
9006 /*
9007 * Attributes.
9008 */
9009 if ((sourceDoc != NULL) &&
9010 (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID))
Daniel Veillardaa6de472008-08-25 14:53:31 +00009011 {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009012 xmlRemoveID(sourceDoc, (xmlAttrPtr) cur);
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009013 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009014 ((xmlAttrPtr) cur)->atype = 0;
9015 ((xmlAttrPtr) cur)->psvi = NULL;
9016 }
9017 break;
9018 case XML_TEXT_NODE:
Daniel Veillardaa6de472008-08-25 14:53:31 +00009019 case XML_CDATA_SECTION_NODE:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009020 /*
9021 * This puts the content in the dest dict, only if
9022 * it was previously in the source dict.
9023 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00009024 XML_TREE_ADOPT_STR_2(cur->content)
9025 goto leave_node;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009026 case XML_ENTITY_REF_NODE:
9027 /*
9028 * Remove reference to the entitity-node.
9029 */
9030 cur->content = NULL;
9031 cur->children = NULL;
9032 cur->last = NULL;
9033 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9034 xmlEntityPtr ent;
9035 /*
9036 * Assign new entity-node if available.
9037 */
9038 ent = xmlGetDocEntity(destDoc, cur->name);
9039 if (ent != NULL) {
9040 cur->content = ent->content;
9041 cur->children = (xmlNodePtr) ent;
9042 cur->last = (xmlNodePtr) ent;
9043 }
9044 }
9045 goto leave_node;
9046 case XML_PI_NODE:
9047 XML_TREE_ADOPT_STR(cur->name)
9048 XML_TREE_ADOPT_STR_2(cur->content)
9049 break;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009050 case XML_COMMENT_NODE:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009051 break;
9052 default:
9053 goto internal_error;
9054 }
9055 /*
9056 * Walk the tree.
9057 */
9058 if (cur->children != NULL) {
9059 cur = cur->children;
9060 continue;
9061 }
9062
9063leave_node:
9064 if (cur == node)
9065 break;
9066 if ((cur->type == XML_ELEMENT_NODE) ||
9067 (cur->type == XML_XINCLUDE_START) ||
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009068 (cur->type == XML_XINCLUDE_END))
9069 {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009070 /*
9071 * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
9072 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00009073 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009074 /*
9075 * Pop mappings.
9076 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009077 while ((nsMap->last != NULL) &&
9078 (nsMap->last->depth >= depth))
9079 {
Daniel Veillardaa6de472008-08-25 14:53:31 +00009080 XML_NSMAP_POP(nsMap, mi)
9081 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009082 /*
9083 * Unshadow.
9084 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009085 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009086 if (mi->shadowDepth >= depth)
9087 mi->shadowDepth = -1;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009088 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009089 }
9090 depth--;
9091 }
9092 if (cur->next != NULL)
9093 cur = cur->next;
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009094 else if ((cur->type == XML_ATTRIBUTE_NODE) &&
9095 (cur->parent->children != NULL))
9096 {
9097 cur = cur->parent->children;
9098 } else {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009099 cur = cur->parent;
9100 goto leave_node;
9101 }
9102 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009103
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009104 goto exit;
9105
Daniel Veillardaa6de472008-08-25 14:53:31 +00009106internal_error:
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009107 ret = -1;
9108
9109exit:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009110 /*
9111 * Cleanup.
9112 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009113 if (nsMap != NULL) {
9114 if ((ctxt) && (ctxt->namespaceMap == nsMap)) {
9115 /*
9116 * Just cleanup the map but don't free.
9117 */
9118 if (nsMap->first) {
9119 if (nsMap->pool)
9120 nsMap->last->next = nsMap->pool;
9121 nsMap->pool = nsMap->first;
9122 nsMap->first = NULL;
9123 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009124 } else
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009125 xmlDOMWrapNsMapFree(nsMap);
9126 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009127 return(ret);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009128}
9129
9130/*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009131* xmlDOMWrapCloneNode:
9132* @ctxt: the optional context for custom processing
9133* @sourceDoc: the optional sourceDoc
9134* @node: the node to start with
9135* @resNode: the clone of the given @node
9136* @destDoc: the destination doc
9137* @destParent: the optional new parent of @node in @destDoc
Daniel Veillardb2f8f1d2006-04-28 16:30:48 +00009138* @deep: descend into child if set
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009139* @options: option flags
9140*
9141* References of out-of scope ns-decls are remapped to point to @destDoc:
9142* 1) If @destParent is given, then nsDef entries on element-nodes are used
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009143* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used.
9144* This is the case when you don't know already where the cloned branch
9145* will be added to.
Daniel Veillardaa6de472008-08-25 14:53:31 +00009146*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009147* If @destParent is given, it ensures that the tree is namespace
9148* wellformed by creating additional ns-decls where needed.
9149* Note that, since prefixes of already existent ns-decls can be
9150* shadowed by this process, it could break QNames in attribute
9151* values or element content.
9152* TODO:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009153* 1) What to do with XInclude? Currently this returns an error for XInclude.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009154*
9155* Returns 0 if the operation succeeded,
9156* 1 if a node of unsupported (or not yet supported) type was given,
9157* -1 on API/internal errors.
9158*/
9159
9160int
9161xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt,
9162 xmlDocPtr sourceDoc,
9163 xmlNodePtr node,
9164 xmlNodePtr *resNode,
9165 xmlDocPtr destDoc,
9166 xmlNodePtr destParent,
9167 int deep,
9168 int options ATTRIBUTE_UNUSED)
9169{
9170 int ret = 0;
9171 xmlNodePtr cur, curElem = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009172 xmlNsMapPtr nsMap = NULL;
9173 xmlNsMapItemPtr mi;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009174 xmlNsPtr ns;
9175 int depth = -1;
9176 /* int adoptStr = 1; */
9177 /* gather @parent's ns-decls. */
9178 int parnsdone = 0;
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009179 /*
Daniel Veillardaa6de472008-08-25 14:53:31 +00009180 * @ancestorsOnly:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009181 * TODO: @ancestorsOnly should be set per option.
9182 *
9183 */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009184 int ancestorsOnly = 0;
9185 xmlNodePtr resultClone = NULL, clone = NULL, parentClone = NULL, prevClone = NULL;
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009186 xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL;
9187 xmlDictPtr dict; /* The destination dict */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009188
Daniel Veillard11ce4002006-03-10 00:36:23 +00009189 if ((node == NULL) || (resNode == NULL) || (destDoc == NULL))
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009190 return(-1);
9191 /*
9192 * TODO: Initially we support only element-nodes.
9193 */
9194 if (node->type != XML_ELEMENT_NODE)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009195 return(1);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009196 /*
9197 * Check node->doc sanity.
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009198 */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009199 if ((node->doc != NULL) && (sourceDoc != NULL) &&
9200 (node->doc != sourceDoc)) {
9201 /*
9202 * Might be an XIncluded node.
9203 */
9204 return (-1);
9205 }
9206 if (sourceDoc == NULL)
Daniel Veillardaa6de472008-08-25 14:53:31 +00009207 sourceDoc = node->doc;
Daniel Veillard11ce4002006-03-10 00:36:23 +00009208 if (sourceDoc == NULL)
9209 return (-1);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009210
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009211 dict = destDoc->dict;
9212 /*
9213 * Reuse the namespace map of the context.
9214 */
9215 if (ctxt)
9216 nsMap = (xmlNsMapPtr) ctxt->namespaceMap;
9217
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009218 *resNode = NULL;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009219
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009220 cur = node;
9221 while (cur != NULL) {
9222 if (cur->doc != sourceDoc) {
9223 /*
9224 * We'll assume XIncluded nodes if the doc differs.
9225 * TODO: Do we need to reconciliate XIncluded nodes?
9226 * TODO: This here returns -1 in this case.
9227 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00009228 goto internal_error;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009229 }
9230 /*
9231 * Create a new node.
9232 */
9233 switch (cur->type) {
9234 case XML_XINCLUDE_START:
9235 case XML_XINCLUDE_END:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009236 /*
9237 * TODO: What to do with XInclude?
9238 */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009239 goto internal_error;
9240 break;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009241 case XML_ELEMENT_NODE:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009242 case XML_TEXT_NODE:
Daniel Veillardaa6de472008-08-25 14:53:31 +00009243 case XML_CDATA_SECTION_NODE:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009244 case XML_COMMENT_NODE:
Daniel Veillardaa6de472008-08-25 14:53:31 +00009245 case XML_PI_NODE:
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009246 case XML_DOCUMENT_FRAG_NODE:
9247 case XML_ENTITY_REF_NODE:
9248 case XML_ENTITY_NODE:
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009249 /*
9250 * Nodes of xmlNode structure.
9251 */
9252 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
9253 if (clone == NULL) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009254 xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating a node");
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009255 goto internal_error;
9256 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009257 memset(clone, 0, sizeof(xmlNode));
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009258 /*
9259 * Set hierachical links.
9260 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00009261 if (resultClone != NULL) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009262 clone->parent = parentClone;
9263 if (prevClone) {
9264 prevClone->next = clone;
9265 clone->prev = prevClone;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009266 } else
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009267 parentClone->children = clone;
9268 } else
9269 resultClone = clone;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009270
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009271 break;
9272 case XML_ATTRIBUTE_NODE:
9273 /*
9274 * Attributes (xmlAttr).
9275 */
9276 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlAttr));
9277 if (clone == NULL) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009278 xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating an attr-node");
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009279 goto internal_error;
9280 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009281 memset(clone, 0, sizeof(xmlAttr));
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009282 /*
9283 * Set hierachical links.
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009284 * TODO: Change this to add to the end of attributes.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009285 */
9286 if (resultClone != NULL) {
9287 clone->parent = parentClone;
9288 if (prevClone) {
9289 prevClone->next = clone;
9290 clone->prev = prevClone;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009291 } else
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009292 parentClone->properties = (xmlAttrPtr) clone;
9293 } else
9294 resultClone = clone;
9295 break;
9296 default:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009297 /*
9298 * TODO QUESTION: Any other nodes expected?
9299 */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009300 goto internal_error;
9301 }
9302
9303 clone->type = cur->type;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009304 clone->doc = destDoc;
9305
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009306 /*
9307 * Clone the name of the node if any.
9308 */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009309 if (cur->name == xmlStringText)
9310 clone->name = xmlStringText;
9311 else if (cur->name == xmlStringTextNoenc)
9312 /*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009313 * NOTE: Although xmlStringTextNoenc is never assigned to a node
9314 * in tree.c, it might be set in Libxslt via
Daniel Veillardaa6de472008-08-25 14:53:31 +00009315 * "xsl:disable-output-escaping".
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009316 */
9317 clone->name = xmlStringTextNoenc;
9318 else if (cur->name == xmlStringComment)
9319 clone->name = xmlStringComment;
9320 else if (cur->name != NULL) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009321 DICT_CONST_COPY(cur->name, clone->name);
Daniel Veillardaa6de472008-08-25 14:53:31 +00009322 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009323
9324 switch (cur->type) {
9325 case XML_XINCLUDE_START:
9326 case XML_XINCLUDE_END:
9327 /*
9328 * TODO
9329 */
9330 return (-1);
9331 case XML_ELEMENT_NODE:
9332 curElem = cur;
9333 depth++;
9334 /*
9335 * Namespace declarations.
9336 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009337 if (cur->nsDef != NULL) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009338 if (! parnsdone) {
9339 if (destParent && (ctxt == NULL)) {
9340 /*
9341 * Gather @parent's in-scope ns-decls.
9342 */
9343 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
9344 destParent) == -1)
Daniel Veillardaa6de472008-08-25 14:53:31 +00009345 goto internal_error;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009346 }
9347 parnsdone = 1;
9348 }
9349 /*
9350 * Clone namespace declarations.
9351 */
9352 cloneNsDefSlot = &(clone->nsDef);
9353 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
9354 /*
9355 * Create a new xmlNs.
9356 */
9357 cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
9358 if (cloneNs == NULL) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009359 xmlTreeErrMemory("xmlDOMWrapCloneNode(): "
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009360 "allocating namespace");
9361 return(-1);
9362 }
9363 memset(cloneNs, 0, sizeof(xmlNs));
9364 cloneNs->type = XML_LOCAL_NAMESPACE;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009365
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009366 if (ns->href != NULL)
9367 cloneNs->href = xmlStrdup(ns->href);
9368 if (ns->prefix != NULL)
9369 cloneNs->prefix = xmlStrdup(ns->prefix);
9370
9371 *cloneNsDefSlot = cloneNs;
9372 cloneNsDefSlot = &(cloneNs->next);
9373
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009374 /*
9375 * Note that for custom handling of ns-references,
9376 * the ns-decls need not be stored in the ns-map,
9377 * since they won't be referenced by node->ns.
9378 */
9379 if ((ctxt == NULL) ||
9380 (ctxt->getNsForNodeFunc == NULL))
9381 {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009382 /*
9383 * Does it shadow any ns-decl?
9384 */
9385 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00009386 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009387 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
9388 (mi->shadowDepth == -1) &&
9389 ((ns->prefix == mi->newNs->prefix) ||
9390 xmlStrEqual(ns->prefix,
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009391 mi->newNs->prefix))) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009392 /*
9393 * Mark as shadowed at the current
9394 * depth.
9395 */
9396 mi->shadowDepth = depth;
9397 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009398 }
9399 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009400 /*
9401 * Push mapping.
9402 */
9403 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
9404 ns, cloneNs, depth) == NULL)
9405 goto internal_error;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009406 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009407 }
9408 }
9409 /* cur->ns will be processed further down. */
9410 break;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009411 case XML_ATTRIBUTE_NODE:
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009412 /* IDs will be processed further down. */
9413 /* cur->ns will be processed further down. */
9414 break;
9415 case XML_TEXT_NODE:
9416 case XML_CDATA_SECTION_NODE:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009417 /*
9418 * Note that this will also cover the values of attributes.
9419 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00009420 DICT_COPY(cur->content, clone->content);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009421 goto leave_node;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009422 case XML_ENTITY_NODE:
9423 /* TODO: What to do here? */
9424 goto leave_node;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009425 case XML_ENTITY_REF_NODE:
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009426 if (sourceDoc != destDoc) {
9427 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9428 xmlEntityPtr ent;
9429 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009430 * Different doc: Assign new entity-node if available.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009431 */
9432 ent = xmlGetDocEntity(destDoc, cur->name);
9433 if (ent != NULL) {
9434 clone->content = ent->content;
9435 clone->children = (xmlNodePtr) ent;
9436 clone->last = (xmlNodePtr) ent;
9437 }
9438 }
9439 } else {
9440 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009441 * Same doc: Use the current node's entity declaration
9442 * and value.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009443 */
9444 clone->content = cur->content;
9445 clone->children = cur->children;
9446 clone->last = cur->last;
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009447 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009448 goto leave_node;
9449 case XML_PI_NODE:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009450 DICT_COPY(cur->content, clone->content);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009451 goto leave_node;
9452 case XML_COMMENT_NODE:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009453 DICT_COPY(cur->content, clone->content);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009454 goto leave_node;
9455 default:
9456 goto internal_error;
9457 }
9458
9459 if (cur->ns == NULL)
9460 goto end_ns_reference;
9461
9462/* handle_ns_reference: */
9463 /*
9464 ** The following will take care of references to ns-decls ********
Daniel Veillardaa6de472008-08-25 14:53:31 +00009465 ** and is intended only for element- and attribute-nodes.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009466 **
9467 */
9468 if (! parnsdone) {
9469 if (destParent && (ctxt == NULL)) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009470 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1)
Daniel Veillardaa6de472008-08-25 14:53:31 +00009471 goto internal_error;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009472 }
9473 parnsdone = 1;
9474 }
9475 /*
9476 * Adopt ns-references.
9477 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009478 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009479 /*
9480 * Search for a mapping.
9481 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00009482 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009483 if ((mi->shadowDepth == -1) &&
9484 (cur->ns == mi->oldNs)) {
9485 /*
9486 * This is the nice case: a mapping was found.
9487 */
9488 clone->ns = mi->newNs;
9489 goto end_ns_reference;
9490 }
9491 }
9492 }
9493 /*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009494 * No matching namespace in scope. We need a new one.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009495 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009496 if ((ctxt != NULL) && (ctxt->getNsForNodeFunc != NULL)) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009497 /*
9498 * User-defined behaviour.
9499 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009500 ns = ctxt->getNsForNodeFunc(ctxt, cur,
9501 cur->ns->href, cur->ns->prefix);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009502 /*
9503 * Add user's mapping.
9504 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009505 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009506 cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
9507 goto internal_error;
9508 clone->ns = ns;
9509 } else {
9510 /*
9511 * Aquire a normalized ns-decl and add it to the map.
9512 */
9513 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
Daniel Veillardaa6de472008-08-25 14:53:31 +00009514 /* ns-decls on curElem or on destDoc->oldNs */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009515 destParent ? curElem : NULL,
9516 cur->ns, &ns,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009517 &nsMap, depth,
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009518 /* if we need to search only in the ancestor-axis */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009519 ancestorsOnly,
9520 /* ns-decls must be prefixed for attributes. */
9521 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
9522 goto internal_error;
9523 clone->ns = ns;
9524 }
9525
9526end_ns_reference:
9527
9528 /*
9529 * Some post-processing.
9530 *
9531 * Handle ID attributes.
9532 */
9533 if ((clone->type == XML_ATTRIBUTE_NODE) &&
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009534 (clone->parent != NULL))
9535 {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009536 if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00009537
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009538 xmlChar *idVal;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009539
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009540 idVal = xmlNodeListGetString(cur->doc, cur->children, 1);
9541 if (idVal != NULL) {
9542 if (xmlAddID(NULL, destDoc, idVal, (xmlAttrPtr) cur) == NULL) {
9543 /* TODO: error message. */
9544 xmlFree(idVal);
9545 goto internal_error;
9546 }
9547 xmlFree(idVal);
9548 }
9549 }
9550 }
9551 /*
9552 **
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009553 ** The following will traverse the tree **************************
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009554 **
Daniel Veillardaa6de472008-08-25 14:53:31 +00009555 *
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009556 * Walk the element's attributes before descending into child-nodes.
9557 */
9558 if ((cur->type == XML_ELEMENT_NODE) && (cur->properties != NULL)) {
9559 prevClone = NULL;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009560 parentClone = clone;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009561 cur = (xmlNodePtr) cur->properties;
9562 continue;
9563 }
9564into_content:
9565 /*
9566 * Descend into child-nodes.
9567 */
9568 if (cur->children != NULL) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009569 if (deep || (cur->type == XML_ATTRIBUTE_NODE)) {
9570 prevClone = NULL;
9571 parentClone = clone;
9572 cur = cur->children;
9573 continue;
9574 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009575 }
9576
9577leave_node:
9578 /*
9579 * At this point we are done with the node, its content
9580 * and an element-nodes's attribute-nodes.
9581 */
9582 if (cur == node)
9583 break;
9584 if ((cur->type == XML_ELEMENT_NODE) ||
9585 (cur->type == XML_XINCLUDE_START) ||
9586 (cur->type == XML_XINCLUDE_END)) {
9587 /*
9588 * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
9589 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00009590 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009591 /*
9592 * Pop mappings.
9593 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009594 while ((nsMap->last != NULL) &&
9595 (nsMap->last->depth >= depth))
9596 {
Daniel Veillardaa6de472008-08-25 14:53:31 +00009597 XML_NSMAP_POP(nsMap, mi)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009598 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009599 /*
9600 * Unshadow.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009601 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009602 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009603 if (mi->shadowDepth >= depth)
9604 mi->shadowDepth = -1;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009605 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009606 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009607 depth--;
9608 }
9609 if (cur->next != NULL) {
9610 prevClone = clone;
9611 cur = cur->next;
9612 } else if (cur->type != XML_ATTRIBUTE_NODE) {
9613 /*
9614 * Set clone->last.
9615 */
Daniel Veillard11ce4002006-03-10 00:36:23 +00009616 if (clone->parent != NULL)
9617 clone->parent->last = clone;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009618 clone = clone->parent;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009619 parentClone = clone->parent;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009620 /*
9621 * Process parent --> next;
9622 */
9623 cur = cur->parent;
9624 goto leave_node;
9625 } else {
9626 /* This is for attributes only. */
9627 clone = clone->parent;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009628 parentClone = clone->parent;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009629 /*
9630 * Process parent-element --> children.
9631 */
9632 cur = cur->parent;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009633 goto into_content;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009634 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009635 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009636 goto exit;
9637
9638internal_error:
9639 ret = -1;
9640
9641exit:
9642 /*
9643 * Cleanup.
9644 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009645 if (nsMap != NULL) {
9646 if ((ctxt) && (ctxt->namespaceMap == nsMap)) {
9647 /*
9648 * Just cleanup the map but don't free.
9649 */
9650 if (nsMap->first) {
9651 if (nsMap->pool)
9652 nsMap->last->next = nsMap->pool;
9653 nsMap->pool = nsMap->first;
9654 nsMap->first = NULL;
9655 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009656 } else
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009657 xmlDOMWrapNsMapFree(nsMap);
9658 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009659 /*
9660 * TODO: Should we try a cleanup of the cloned node in case of a
9661 * fatal error?
9662 */
9663 *resNode = resultClone;
9664 return (ret);
9665}
9666
9667/*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009668* xmlDOMWrapAdoptAttr:
9669* @ctxt: the optional context for custom processing
9670* @sourceDoc: the optional source document of attr
9671* @attr: the attribute-node to be adopted
9672* @destDoc: the destination doc for adoption
9673* @destParent: the optional new parent of @attr in @destDoc
9674* @options: option flags
9675*
9676* @attr is adopted by @destDoc.
9677* Ensures that ns-references point to @destDoc: either to
9678* elements->nsDef entries if @destParent is given, or to
9679* @destDoc->oldNs otherwise.
9680*
9681* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
9682*/
9683static int
9684xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt,
9685 xmlDocPtr sourceDoc,
9686 xmlAttrPtr attr,
9687 xmlDocPtr destDoc,
9688 xmlNodePtr destParent,
9689 int options ATTRIBUTE_UNUSED)
9690{
9691 xmlNodePtr cur;
9692 int adoptStr = 1;
9693
9694 if ((attr == NULL) || (destDoc == NULL))
9695 return (-1);
Daniel Veillardaa6de472008-08-25 14:53:31 +00009696
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009697 attr->doc = destDoc;
9698 if (attr->ns != NULL) {
9699 xmlNsPtr ns = NULL;
9700
9701 if (ctxt != NULL) {
9702 /* TODO: User defined. */
9703 }
9704 /* XML Namespace. */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009705 if (IS_STR_XML(attr->ns->prefix)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009706 ns = xmlTreeEnsureXMLDecl(destDoc);
9707 } else if (destParent == NULL) {
9708 /*
9709 * Store in @destDoc->oldNs.
9710 */
9711 ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix);
9712 } else {
9713 /*
9714 * Declare on @destParent.
9715 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009716 if (xmlSearchNsByNamespaceStrict(destDoc, destParent, attr->ns->href,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009717 &ns, 1) == -1)
9718 goto internal_error;
9719 if (ns == NULL) {
9720 ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent,
9721 attr->ns->href, attr->ns->prefix, 1);
9722 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009723 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009724 if (ns == NULL)
9725 goto internal_error;
9726 attr->ns = ns;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009727 }
9728
9729 XML_TREE_ADOPT_STR(attr->name);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009730 attr->atype = 0;
9731 attr->psvi = NULL;
9732 /*
9733 * Walk content.
9734 */
9735 if (attr->children == NULL)
9736 return (0);
9737 cur = attr->children;
9738 while (cur != NULL) {
9739 cur->doc = destDoc;
9740 switch (cur->type) {
9741 case XML_TEXT_NODE:
9742 case XML_CDATA_SECTION_NODE:
9743 XML_TREE_ADOPT_STR_2(cur->content)
Daniel Veillardaa6de472008-08-25 14:53:31 +00009744 break;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009745 case XML_ENTITY_REF_NODE:
9746 /*
9747 * Remove reference to the entitity-node.
9748 */
9749 cur->content = NULL;
9750 cur->children = NULL;
9751 cur->last = NULL;
9752 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9753 xmlEntityPtr ent;
9754 /*
9755 * Assign new entity-node if available.
9756 */
9757 ent = xmlGetDocEntity(destDoc, cur->name);
9758 if (ent != NULL) {
9759 cur->content = ent->content;
9760 cur->children = (xmlNodePtr) ent;
9761 cur->last = (xmlNodePtr) ent;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009762 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009763 }
9764 break;
9765 default:
9766 break;
9767 }
9768 if (cur->children != NULL) {
9769 cur = cur->children;
9770 continue;
9771 }
9772next_sibling:
9773 if (cur == (xmlNodePtr) attr)
9774 break;
9775 if (cur->next != NULL)
9776 cur = cur->next;
9777 else {
9778 cur = cur->parent;
9779 goto next_sibling;
9780 }
9781 }
9782 return (0);
9783internal_error:
9784 return (-1);
9785}
9786
9787/*
9788* xmlDOMWrapAdoptNode:
9789* @ctxt: the optional context for custom processing
9790* @sourceDoc: the optional sourceDoc
9791* @node: the node to start with
9792* @destDoc: the destination doc
Kasimier T. Buchcik4d9c9482005-06-27 15:04:46 +00009793* @destParent: the optional new parent of @node in @destDoc
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009794* @options: option flags
9795*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009796* References of out-of scope ns-decls are remapped to point to @destDoc:
9797* 1) If @destParent is given, then nsDef entries on element-nodes are used
9798* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used
9799* This is the case when you have an unliked node and just want to move it
Daniel Veillardaa6de472008-08-25 14:53:31 +00009800* to the context of
9801*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009802* If @destParent is given, it ensures that the tree is namespace
9803* wellformed by creating additional ns-decls where needed.
9804* Note that, since prefixes of already existent ns-decls can be
9805* shadowed by this process, it could break QNames in attribute
9806* values or element content.
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009807* NOTE: This function was not intensively tested.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009808*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009809* Returns 0 if the operation succeeded,
9810* 1 if a node of unsupported type was given,
9811* 2 if a node of not yet supported type was given and
9812* -1 on API/internal errors.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009813*/
9814int
9815xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt,
9816 xmlDocPtr sourceDoc,
9817 xmlNodePtr node,
Daniel Veillardaa6de472008-08-25 14:53:31 +00009818 xmlDocPtr destDoc,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009819 xmlNodePtr destParent,
9820 int options)
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009821{
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009822 if ((node == NULL) || (destDoc == NULL) ||
9823 ((destParent != NULL) && (destParent->doc != destDoc)))
9824 return(-1);
9825 /*
9826 * Check node->doc sanity.
Daniel Veillardaa6de472008-08-25 14:53:31 +00009827 */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009828 if ((node->doc != NULL) && (sourceDoc != NULL) &&
9829 (node->doc != sourceDoc)) {
9830 /*
9831 * Might be an XIncluded node.
9832 */
9833 return (-1);
9834 }
9835 if (sourceDoc == NULL)
9836 sourceDoc = node->doc;
9837 if (sourceDoc == destDoc)
9838 return (-1);
9839 switch (node->type) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00009840 case XML_ELEMENT_NODE:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009841 case XML_ATTRIBUTE_NODE:
9842 case XML_TEXT_NODE:
9843 case XML_CDATA_SECTION_NODE:
9844 case XML_ENTITY_REF_NODE:
9845 case XML_PI_NODE:
9846 case XML_COMMENT_NODE:
9847 break;
9848 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009849 /* TODO: Support document-fragment-nodes. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009850 return (2);
9851 default:
9852 return (1);
9853 }
9854 /*
9855 * Unlink only if @node was not already added to @destParent.
9856 */
9857 if ((node->parent != NULL) && (destParent != node->parent))
9858 xmlUnlinkNode(node);
9859
9860 if (node->type == XML_ELEMENT_NODE) {
9861 return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node,
9862 destDoc, destParent, options));
9863 } else if (node->type == XML_ATTRIBUTE_NODE) {
9864 return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc,
9865 (xmlAttrPtr) node, destDoc, destParent, options));
Daniel Veillardaa6de472008-08-25 14:53:31 +00009866 } else {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009867 xmlNodePtr cur = node;
9868 int adoptStr = 1;
9869
9870 cur->doc = destDoc;
9871 /*
9872 * Optimize string adoption.
9873 */
9874 if ((sourceDoc != NULL) &&
9875 (sourceDoc->dict == destDoc->dict))
9876 adoptStr = 0;
9877 switch (node->type) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00009878 case XML_TEXT_NODE:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009879 case XML_CDATA_SECTION_NODE:
9880 XML_TREE_ADOPT_STR_2(node->content)
9881 break;
9882 case XML_ENTITY_REF_NODE:
9883 /*
9884 * Remove reference to the entitity-node.
9885 */
9886 node->content = NULL;
9887 node->children = NULL;
9888 node->last = NULL;
9889 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9890 xmlEntityPtr ent;
9891 /*
9892 * Assign new entity-node if available.
9893 */
9894 ent = xmlGetDocEntity(destDoc, node->name);
9895 if (ent != NULL) {
9896 node->content = ent->content;
9897 node->children = (xmlNodePtr) ent;
9898 node->last = (xmlNodePtr) ent;
9899 }
9900 }
9901 XML_TREE_ADOPT_STR(node->name)
9902 break;
Daniel Veillard7e21fd12005-07-03 21:44:07 +00009903 case XML_PI_NODE: {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009904 XML_TREE_ADOPT_STR(node->name)
9905 XML_TREE_ADOPT_STR_2(node->content)
9906 break;
Daniel Veillard7e21fd12005-07-03 21:44:07 +00009907 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009908 default:
9909 break;
9910 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009911 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009912 return (0);
9913}
9914
Daniel Veillard5d4644e2005-04-01 13:11:58 +00009915#define bottom_tree
9916#include "elfgcchack.h"