blob: 62c8e162219d7a7a7b8834c1649f7d62e999108a [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 Veillarddddeede2012-07-16 14:44:26 +080044#include "buf.h"
45
Daniel Veillarda880b122003-04-21 21:36:41 +000046int __xmlRegisterCallbacks = 0;
47
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +000048/************************************************************************
49 * *
Daniel Veillardaa6de472008-08-25 14:53:31 +000050 * Forward declarations *
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +000051 * *
52 ************************************************************************/
53
Daniel Veillard8ed10722009-08-20 19:17:36 +020054static xmlNsPtr
55xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
Daniel Veillard56a4cb82001-03-24 17:00:36 +000056
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +000057static xmlChar* xmlGetPropNodeValueInternal(xmlAttrPtr prop);
58
Daniel Veillard56a4cb82001-03-24 17:00:36 +000059/************************************************************************
60 * *
Daniel Veillardaa6de472008-08-25 14:53:31 +000061 * Tree memory error handler *
Daniel Veillard18ec16e2003-10-07 23:16:40 +000062 * *
63 ************************************************************************/
64/**
65 * xmlTreeErrMemory:
66 * @extra: extra informations
67 *
68 * Handle an out of memory condition
69 */
70static void
71xmlTreeErrMemory(const char *extra)
72{
73 __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
74}
75
76/**
77 * xmlTreeErr:
78 * @code: the error number
79 * @extra: extra informations
80 *
81 * Handle an out of memory condition
82 */
83static void
84xmlTreeErr(int code, xmlNodePtr node, const char *extra)
85{
86 const char *msg = NULL;
87
88 switch(code) {
89 case XML_TREE_INVALID_HEX:
Daniel Veillardac996a12004-07-30 12:02:58 +000090 msg = "invalid hexadecimal character value\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000091 break;
92 case XML_TREE_INVALID_DEC:
Daniel Veillardac996a12004-07-30 12:02:58 +000093 msg = "invalid decimal character value\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000094 break;
95 case XML_TREE_UNTERMINATED_ENTITY:
Daniel Veillardac996a12004-07-30 12:02:58 +000096 msg = "unterminated entity reference %15s\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000097 break;
Daniel Veillard6f8611f2008-02-15 08:33:21 +000098 case XML_TREE_NOT_UTF8:
99 msg = "string is not in UTF-8\n";
100 break;
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000101 default:
Daniel Veillardac996a12004-07-30 12:02:58 +0000102 msg = "unexpected error number\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000103 }
104 __xmlSimpleError(XML_FROM_TREE, code, node, msg, extra);
105}
106
107/************************************************************************
108 * *
Daniel Veillardaa6de472008-08-25 14:53:31 +0000109 * A few static variables and macros *
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000110 * *
111 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +0000112/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +0000113const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +0000114/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +0000115const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +0000116 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +0000117/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +0000118const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
119
Owen Taylor3473f882001-02-23 17:55:21 +0000120static int xmlCompressMode = 0;
121static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000122
Owen Taylor3473f882001-02-23 17:55:21 +0000123#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
124 xmlNodePtr ulccur = (n)->children; \
125 if (ulccur == NULL) { \
126 (n)->last = NULL; \
127 } else { \
128 while (ulccur->next != NULL) { \
Daniel Veillardaa6de472008-08-25 14:53:31 +0000129 ulccur->parent = (n); \
Owen Taylor3473f882001-02-23 17:55:21 +0000130 ulccur = ulccur->next; \
131 } \
132 ulccur->parent = (n); \
133 (n)->last = ulccur; \
134}}
135
Kasimier T. Buchcik44353412006-03-06 13:26:16 +0000136#define IS_STR_XML(str) ((str != NULL) && (str[0] == 'x') && \
137 (str[1] == 'm') && (str[2] == 'l') && (str[3] == 0))
138
Owen Taylor3473f882001-02-23 17:55:21 +0000139/* #define DEBUG_BUFFER */
140/* #define DEBUG_TREE */
141
142/************************************************************************
143 * *
Daniel Veillardaa6de472008-08-25 14:53:31 +0000144 * Functions to move to entities.c once the *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000145 * API freeze is smoothen and they can be made public. *
146 * *
147 ************************************************************************/
148#include <libxml/hash.h>
Daniel Veillardaa6de472008-08-25 14:53:31 +0000149
Daniel Veillard652327a2003-09-29 18:02:38 +0000150#ifdef LIBXML_TREE_ENABLED
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000151/**
152 * xmlGetEntityFromDtd:
153 * @dtd: A pointer to the DTD to search
154 * @name: The entity name
155 *
156 * Do an entity lookup in the DTD entity hash table and
157 * return the corresponding entity, if found.
Daniel Veillardaa6de472008-08-25 14:53:31 +0000158 *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000159 * Returns A pointer to the entity structure or NULL if not found.
160 */
161static xmlEntityPtr
162xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
163 xmlEntitiesTablePtr table;
Daniel Veillardaa6de472008-08-25 14:53:31 +0000164
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000165 if((dtd != NULL) && (dtd->entities != NULL)) {
166 table = (xmlEntitiesTablePtr) dtd->entities;
167 return((xmlEntityPtr) xmlHashLookup(table, name));
Daniel Veillardaa6de472008-08-25 14:53:31 +0000168 /* return(xmlGetEntityFromTable(table, name)); */
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000169 }
170 return(NULL);
171}
172/**
173 * xmlGetParameterEntityFromDtd:
174 * @dtd: A pointer to the DTD to search
175 * @name: The entity name
Daniel Veillardaa6de472008-08-25 14:53:31 +0000176 *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000177 * Do an entity lookup in the DTD pararmeter entity hash table and
178 * return the corresponding entity, if found.
179 *
180 * Returns A pointer to the entity structure or NULL if not found.
181 */
182static xmlEntityPtr
183xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
184 xmlEntitiesTablePtr table;
Daniel Veillardaa6de472008-08-25 14:53:31 +0000185
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000186 if ((dtd != NULL) && (dtd->pentities != NULL)) {
187 table = (xmlEntitiesTablePtr) dtd->pentities;
188 return((xmlEntityPtr) xmlHashLookup(table, name));
189 /* return(xmlGetEntityFromTable(table, name)); */
190 }
191 return(NULL);
192}
Daniel Veillard652327a2003-09-29 18:02:38 +0000193#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000194
195/************************************************************************
196 * *
Daniel Veillardc00cda82003-04-07 10:22:39 +0000197 * QName handling helper *
198 * *
199 ************************************************************************/
200
201/**
202 * xmlBuildQName:
203 * @ncname: the Name
204 * @prefix: the prefix
205 * @memory: preallocated memory
206 * @len: preallocated memory length
207 *
208 * Builds the QName @prefix:@ncname in @memory if there is enough space
209 * and prefix is not NULL nor empty, otherwise allocate a new string.
210 * If prefix is NULL or empty it returns ncname.
211 *
212 * Returns the new string which must be freed by the caller if different from
213 * @memory and @ncname or NULL in case of error
214 */
215xmlChar *
216xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
217 xmlChar *memory, int len) {
218 int lenn, lenp;
219 xmlChar *ret;
220
Daniel Veillard3b7840c2003-09-11 23:42:01 +0000221 if (ncname == NULL) return(NULL);
222 if (prefix == NULL) return((xmlChar *) ncname);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000223
224 lenn = strlen((char *) ncname);
225 lenp = strlen((char *) prefix);
226
227 if ((memory == NULL) || (len < lenn + lenp + 2)) {
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000228 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000229 if (ret == NULL) {
230 xmlTreeErrMemory("building QName");
231 return(NULL);
232 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000233 } else {
234 ret = memory;
235 }
236 memcpy(&ret[0], prefix, lenp);
237 ret[lenp] = ':';
238 memcpy(&ret[lenp + 1], ncname, lenn);
239 ret[lenn + lenp + 1] = 0;
240 return(ret);
241}
242
243/**
244 * xmlSplitQName2:
245 * @name: the full QName
Daniel Veillardaa6de472008-08-25 14:53:31 +0000246 * @prefix: a xmlChar **
Daniel Veillardc00cda82003-04-07 10:22:39 +0000247 *
248 * parse an XML qualified name string
249 *
250 * [NS 5] QName ::= (Prefix ':')? LocalPart
251 *
252 * [NS 6] Prefix ::= NCName
253 *
254 * [NS 7] LocalPart ::= NCName
255 *
256 * Returns NULL if not a QName, otherwise the local part, and prefix
257 * is updated to get the Prefix if any.
258 */
259
260xmlChar *
261xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
262 int len = 0;
263 xmlChar *ret = NULL;
264
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000265 if (prefix == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000266 *prefix = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000267 if (name == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000268
269#ifndef XML_XML_NAMESPACE
270 /* xml: prefix is not really a namespace */
271 if ((name[0] == 'x') && (name[1] == 'm') &&
272 (name[2] == 'l') && (name[3] == ':'))
273 return(NULL);
274#endif
275
276 /* nasty but valid */
277 if (name[0] == ':')
278 return(NULL);
279
280 /*
281 * we are not trying to validate but just to cut, and yes it will
282 * work even if this is as set of UTF-8 encoded chars
283 */
Daniel Veillardaa6de472008-08-25 14:53:31 +0000284 while ((name[len] != 0) && (name[len] != ':'))
Daniel Veillardc00cda82003-04-07 10:22:39 +0000285 len++;
Daniel Veillardaa6de472008-08-25 14:53:31 +0000286
Daniel Veillardc00cda82003-04-07 10:22:39 +0000287 if (name[len] == 0)
288 return(NULL);
289
290 *prefix = xmlStrndup(name, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000291 if (*prefix == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000292 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000293 return(NULL);
294 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000295 ret = xmlStrdup(&name[len + 1]);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000296 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000297 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000298 if (*prefix != NULL) {
299 xmlFree(*prefix);
300 *prefix = NULL;
301 }
302 return(NULL);
303 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000304
305 return(ret);
306}
307
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000308/**
309 * xmlSplitQName3:
310 * @name: the full QName
311 * @len: an int *
312 *
313 * parse an XML qualified name string,i
314 *
315 * returns NULL if it is not a Qualified Name, otherwise, update len
316 * with the lenght in byte of the prefix and return a pointer
Daniel Veillard54f9a4f2005-09-03 13:28:24 +0000317 * to the start of the name without the prefix
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000318 */
319
320const xmlChar *
321xmlSplitQName3(const xmlChar *name, int *len) {
322 int l = 0;
323
324 if (name == NULL) return(NULL);
325 if (len == NULL) return(NULL);
326
327 /* nasty but valid */
328 if (name[0] == ':')
329 return(NULL);
330
331 /*
332 * we are not trying to validate but just to cut, and yes it will
333 * work even if this is as set of UTF-8 encoded chars
334 */
Daniel Veillardaa6de472008-08-25 14:53:31 +0000335 while ((name[l] != 0) && (name[l] != ':'))
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000336 l++;
Daniel Veillardaa6de472008-08-25 14:53:31 +0000337
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000338 if (name[l] == 0)
339 return(NULL);
340
341 *len = l;
342
343 return(&name[l+1]);
344}
345
Daniel Veillardc00cda82003-04-07 10:22:39 +0000346/************************************************************************
347 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000348 * Check Name, NCName and QName strings *
349 * *
350 ************************************************************************/
Daniel Veillardaa6de472008-08-25 14:53:31 +0000351
Daniel Veillardd2298792003-02-14 16:54:11 +0000352#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
353
Daniel Veillardf1a27c62006-10-13 22:33:03 +0000354#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 +0000355/**
356 * xmlValidateNCName:
357 * @value: the value to check
358 * @space: allow spaces in front and end of the string
359 *
360 * Check that a value conforms to the lexical space of NCName
361 *
362 * Returns 0 if this validates, a positive error code number otherwise
363 * and -1 in case of internal or API error.
364 */
365int
366xmlValidateNCName(const xmlChar *value, int space) {
367 const xmlChar *cur = value;
368 int c,l;
369
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000370 if (value == NULL)
371 return(-1);
372
Daniel Veillardd2298792003-02-14 16:54:11 +0000373 /*
374 * First quick algorithm for ASCII range
375 */
376 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000377 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000378 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
379 (*cur == '_'))
380 cur++;
381 else
382 goto try_complex;
383 while (((*cur >= 'a') && (*cur <= 'z')) ||
384 ((*cur >= 'A') && (*cur <= 'Z')) ||
385 ((*cur >= '0') && (*cur <= '9')) ||
386 (*cur == '_') || (*cur == '-') || (*cur == '.'))
387 cur++;
388 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000389 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000390 if (*cur == 0)
391 return(0);
392
393try_complex:
394 /*
395 * Second check for chars outside the ASCII range
396 */
397 cur = value;
398 c = CUR_SCHAR(cur, l);
399 if (space) {
400 while (IS_BLANK(c)) {
401 cur += l;
402 c = CUR_SCHAR(cur, l);
403 }
404 }
William M. Brack871611b2003-10-18 04:53:14 +0000405 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000406 return(1);
407 cur += l;
408 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000409 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
410 (c == '-') || (c == '_') || IS_COMBINING(c) ||
411 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000412 cur += l;
413 c = CUR_SCHAR(cur, l);
414 }
415 if (space) {
416 while (IS_BLANK(c)) {
417 cur += l;
418 c = CUR_SCHAR(cur, l);
419 }
420 }
421 if (c != 0)
422 return(1);
423
424 return(0);
425}
Daniel Veillard2156d432004-03-04 15:59:36 +0000426#endif
Daniel Veillardd2298792003-02-14 16:54:11 +0000427
Daniel Veillard2156d432004-03-04 15:59:36 +0000428#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000429/**
430 * xmlValidateQName:
431 * @value: the value to check
432 * @space: allow spaces in front and end of the string
433 *
434 * Check that a value conforms to the lexical space of QName
435 *
436 * Returns 0 if this validates, a positive error code number otherwise
437 * and -1 in case of internal or API error.
438 */
439int
440xmlValidateQName(const xmlChar *value, int space) {
441 const xmlChar *cur = value;
442 int c,l;
443
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000444 if (value == NULL)
445 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +0000446 /*
447 * First quick algorithm for ASCII range
448 */
449 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000450 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000451 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
452 (*cur == '_'))
453 cur++;
454 else
455 goto try_complex;
456 while (((*cur >= 'a') && (*cur <= 'z')) ||
457 ((*cur >= 'A') && (*cur <= 'Z')) ||
458 ((*cur >= '0') && (*cur <= '9')) ||
459 (*cur == '_') || (*cur == '-') || (*cur == '.'))
460 cur++;
461 if (*cur == ':') {
462 cur++;
463 if (((*cur >= 'a') && (*cur <= 'z')) ||
464 ((*cur >= 'A') && (*cur <= 'Z')) ||
465 (*cur == '_'))
466 cur++;
467 else
468 goto try_complex;
469 while (((*cur >= 'a') && (*cur <= 'z')) ||
470 ((*cur >= 'A') && (*cur <= 'Z')) ||
471 ((*cur >= '0') && (*cur <= '9')) ||
472 (*cur == '_') || (*cur == '-') || (*cur == '.'))
473 cur++;
474 }
475 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000476 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000477 if (*cur == 0)
478 return(0);
479
480try_complex:
481 /*
482 * Second check for chars outside the ASCII range
483 */
484 cur = value;
485 c = CUR_SCHAR(cur, l);
486 if (space) {
487 while (IS_BLANK(c)) {
488 cur += l;
489 c = CUR_SCHAR(cur, l);
490 }
491 }
William M. Brack871611b2003-10-18 04:53:14 +0000492 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000493 return(1);
494 cur += l;
495 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000496 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
497 (c == '-') || (c == '_') || IS_COMBINING(c) ||
498 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000499 cur += l;
500 c = CUR_SCHAR(cur, l);
501 }
502 if (c == ':') {
503 cur += l;
504 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000505 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000506 return(1);
507 cur += l;
508 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000509 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
510 (c == '-') || (c == '_') || IS_COMBINING(c) ||
511 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000512 cur += l;
513 c = CUR_SCHAR(cur, l);
514 }
515 }
516 if (space) {
517 while (IS_BLANK(c)) {
518 cur += l;
519 c = CUR_SCHAR(cur, l);
520 }
521 }
522 if (c != 0)
523 return(1);
524 return(0);
525}
526
527/**
528 * xmlValidateName:
529 * @value: the value to check
530 * @space: allow spaces in front and end of the string
531 *
532 * Check that a value conforms to the lexical space of Name
533 *
534 * Returns 0 if this validates, a positive error code number otherwise
535 * and -1 in case of internal or API error.
536 */
537int
538xmlValidateName(const xmlChar *value, int space) {
539 const xmlChar *cur = value;
540 int c,l;
541
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000542 if (value == NULL)
543 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +0000544 /*
545 * First quick algorithm for ASCII range
546 */
547 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000548 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000549 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
550 (*cur == '_') || (*cur == ':'))
551 cur++;
552 else
553 goto try_complex;
554 while (((*cur >= 'a') && (*cur <= 'z')) ||
555 ((*cur >= 'A') && (*cur <= 'Z')) ||
556 ((*cur >= '0') && (*cur <= '9')) ||
557 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
558 cur++;
559 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000560 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000561 if (*cur == 0)
562 return(0);
563
564try_complex:
565 /*
566 * Second check for chars outside the ASCII range
567 */
568 cur = value;
569 c = CUR_SCHAR(cur, l);
570 if (space) {
571 while (IS_BLANK(c)) {
572 cur += l;
573 c = CUR_SCHAR(cur, l);
574 }
575 }
William M. Brack871611b2003-10-18 04:53:14 +0000576 if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000577 return(1);
578 cur += l;
579 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000580 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
581 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000582 cur += l;
583 c = CUR_SCHAR(cur, l);
584 }
585 if (space) {
586 while (IS_BLANK(c)) {
587 cur += l;
588 c = CUR_SCHAR(cur, l);
589 }
590 }
591 if (c != 0)
592 return(1);
593 return(0);
594}
595
Daniel Veillardd4310742003-02-18 21:12:46 +0000596/**
597 * xmlValidateNMToken:
598 * @value: the value to check
599 * @space: allow spaces in front and end of the string
600 *
601 * Check that a value conforms to the lexical space of NMToken
602 *
603 * Returns 0 if this validates, a positive error code number otherwise
604 * and -1 in case of internal or API error.
605 */
606int
607xmlValidateNMToken(const xmlChar *value, int space) {
608 const xmlChar *cur = value;
609 int c,l;
610
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000611 if (value == NULL)
612 return(-1);
Daniel Veillardd4310742003-02-18 21:12:46 +0000613 /*
614 * First quick algorithm for ASCII range
615 */
616 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000617 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000618 if (((*cur >= 'a') && (*cur <= 'z')) ||
619 ((*cur >= 'A') && (*cur <= 'Z')) ||
620 ((*cur >= '0') && (*cur <= '9')) ||
621 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
622 cur++;
623 else
624 goto try_complex;
625 while (((*cur >= 'a') && (*cur <= 'z')) ||
626 ((*cur >= 'A') && (*cur <= 'Z')) ||
627 ((*cur >= '0') && (*cur <= '9')) ||
628 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
629 cur++;
630 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000631 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000632 if (*cur == 0)
633 return(0);
634
635try_complex:
636 /*
637 * Second check for chars outside the ASCII range
638 */
639 cur = value;
640 c = CUR_SCHAR(cur, l);
641 if (space) {
642 while (IS_BLANK(c)) {
643 cur += l;
644 c = CUR_SCHAR(cur, l);
645 }
646 }
William M. Brack871611b2003-10-18 04:53:14 +0000647 if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
648 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
Daniel Veillardd4310742003-02-18 21:12:46 +0000649 return(1);
650 cur += l;
651 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000652 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
653 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd4310742003-02-18 21:12:46 +0000654 cur += l;
655 c = CUR_SCHAR(cur, l);
656 }
657 if (space) {
658 while (IS_BLANK(c)) {
659 cur += l;
660 c = CUR_SCHAR(cur, l);
661 }
662 }
663 if (c != 0)
664 return(1);
665 return(0);
666}
Daniel Veillard652327a2003-09-29 18:02:38 +0000667#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardd4310742003-02-18 21:12:46 +0000668
Daniel Veillardd2298792003-02-14 16:54:11 +0000669/************************************************************************
670 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000671 * Allocation and deallocation of basic structures *
672 * *
673 ************************************************************************/
Daniel Veillardaa6de472008-08-25 14:53:31 +0000674
Owen Taylor3473f882001-02-23 17:55:21 +0000675/**
676 * xmlSetBufferAllocationScheme:
677 * @scheme: allocation method to use
Daniel Veillardaa6de472008-08-25 14:53:31 +0000678 *
Owen Taylor3473f882001-02-23 17:55:21 +0000679 * Set the buffer allocation method. Types are
680 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
Daniel Veillardaa6de472008-08-25 14:53:31 +0000681 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
Owen Taylor3473f882001-02-23 17:55:21 +0000682 * improves performance
683 */
684void
685xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
Daniel Veillardda3fee42008-09-01 13:08:57 +0000686 if ((scheme == XML_BUFFER_ALLOC_EXACT) ||
Conrad Irwin7d0d2a52012-05-14 14:18:58 +0800687 (scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
688 (scheme == XML_BUFFER_ALLOC_HYBRID))
Daniel Veillardda3fee42008-09-01 13:08:57 +0000689 xmlBufferAllocScheme = scheme;
Owen Taylor3473f882001-02-23 17:55:21 +0000690}
691
692/**
693 * xmlGetBufferAllocationScheme:
694 *
695 * Types are
696 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
Daniel Veillardaa6de472008-08-25 14:53:31 +0000697 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
Owen Taylor3473f882001-02-23 17:55:21 +0000698 * improves performance
Conrad Irwin7d0d2a52012-05-14 14:18:58 +0800699 * XML_BUFFER_ALLOC_HYBRID - use exact sizes on small strings to keep memory usage tight
700 * in normal usage, and doubleit on large strings to avoid
701 * pathological performance.
Daniel Veillardaa6de472008-08-25 14:53:31 +0000702 *
Owen Taylor3473f882001-02-23 17:55:21 +0000703 * Returns the current allocation scheme
704 */
705xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000706xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000707 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000708}
709
710/**
711 * xmlNewNs:
712 * @node: the element carrying the namespace
713 * @href: the URI associated
714 * @prefix: the prefix for the namespace
715 *
716 * Creation of a new Namespace. This function will refuse to create
717 * a namespace with a similar prefix than an existing one present on this
718 * node.
719 * We use href==NULL in the case of an element creation where the namespace
720 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000721 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000722 */
723xmlNsPtr
724xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
725 xmlNsPtr cur;
726
727 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
728 return(NULL);
729
Daniel Veillardaa54d372010-09-09 18:17:47 +0200730 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))) {
731 /* xml namespace is predefined, no need to add it */
732 if (xmlStrEqual(href, XML_XML_NAMESPACE))
733 return(NULL);
734
735 /*
736 * Problem, this is an attempt to bind xml prefix to a wrong
737 * namespace, which breaks
738 * Namespace constraint: Reserved Prefixes and Namespace Names
739 * from XML namespace. But documents authors may not care in
740 * their context so let's proceed.
741 */
742 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000743
Owen Taylor3473f882001-02-23 17:55:21 +0000744 /*
745 * Allocate a new Namespace and fill the fields.
746 */
747 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
748 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000749 xmlTreeErrMemory("building namespace");
Owen Taylor3473f882001-02-23 17:55:21 +0000750 return(NULL);
751 }
752 memset(cur, 0, sizeof(xmlNs));
753 cur->type = XML_LOCAL_NAMESPACE;
754
755 if (href != NULL)
Daniel Veillardaa6de472008-08-25 14:53:31 +0000756 cur->href = xmlStrdup(href);
Owen Taylor3473f882001-02-23 17:55:21 +0000757 if (prefix != NULL)
Daniel Veillardaa6de472008-08-25 14:53:31 +0000758 cur->prefix = xmlStrdup(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000759
760 /*
761 * Add it at the end to preserve parsing order ...
762 * and checks for existing use of the prefix
763 */
764 if (node != NULL) {
765 if (node->nsDef == NULL) {
766 node->nsDef = cur;
767 } else {
768 xmlNsPtr prev = node->nsDef;
769
770 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
771 (xmlStrEqual(prev->prefix, cur->prefix))) {
772 xmlFreeNs(cur);
773 return(NULL);
Daniel Veillardaa6de472008-08-25 14:53:31 +0000774 }
Owen Taylor3473f882001-02-23 17:55:21 +0000775 while (prev->next != NULL) {
776 prev = prev->next;
777 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
778 (xmlStrEqual(prev->prefix, cur->prefix))) {
779 xmlFreeNs(cur);
780 return(NULL);
Daniel Veillardaa6de472008-08-25 14:53:31 +0000781 }
Owen Taylor3473f882001-02-23 17:55:21 +0000782 }
783 prev->next = cur;
784 }
785 }
786 return(cur);
787}
788
789/**
790 * xmlSetNs:
791 * @node: a node in the document
792 * @ns: a namespace pointer
793 *
794 * Associate a namespace to a node, a posteriori.
795 */
796void
797xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
798 if (node == NULL) {
799#ifdef DEBUG_TREE
800 xmlGenericError(xmlGenericErrorContext,
801 "xmlSetNs: node == NULL\n");
802#endif
803 return;
804 }
805 node->ns = ns;
806}
807
808/**
809 * xmlFreeNs:
810 * @cur: the namespace pointer
811 *
812 * Free up the structures associated to a namespace
813 */
814void
815xmlFreeNs(xmlNsPtr cur) {
816 if (cur == NULL) {
817#ifdef DEBUG_TREE
818 xmlGenericError(xmlGenericErrorContext,
819 "xmlFreeNs : ns == NULL\n");
820#endif
821 return;
822 }
823 if (cur->href != NULL) xmlFree((char *) cur->href);
824 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000825 xmlFree(cur);
826}
827
828/**
829 * xmlFreeNsList:
830 * @cur: the first namespace pointer
831 *
832 * Free up all the structures associated to the chained namespaces.
833 */
834void
835xmlFreeNsList(xmlNsPtr cur) {
836 xmlNsPtr next;
837 if (cur == NULL) {
838#ifdef DEBUG_TREE
839 xmlGenericError(xmlGenericErrorContext,
840 "xmlFreeNsList : ns == NULL\n");
841#endif
842 return;
843 }
844 while (cur != NULL) {
845 next = cur->next;
846 xmlFreeNs(cur);
847 cur = next;
848 }
849}
850
851/**
852 * xmlNewDtd:
853 * @doc: the document pointer
854 * @name: the DTD name
855 * @ExternalID: the external ID
856 * @SystemID: the system ID
857 *
858 * Creation of a new DTD for the external subset. To create an
859 * internal subset, use xmlCreateIntSubset().
860 *
861 * Returns a pointer to the new DTD structure
862 */
863xmlDtdPtr
864xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
865 const xmlChar *ExternalID, const xmlChar *SystemID) {
866 xmlDtdPtr cur;
867
868 if ((doc != NULL) && (doc->extSubset != NULL)) {
869#ifdef DEBUG_TREE
870 xmlGenericError(xmlGenericErrorContext,
871 "xmlNewDtd(%s): document %s already have a DTD %s\n",
872 /* !!! */ (char *) name, doc->name,
873 /* !!! */ (char *)doc->extSubset->name);
874#endif
875 return(NULL);
876 }
877
878 /*
879 * Allocate a new DTD and fill the fields.
880 */
881 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
882 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000883 xmlTreeErrMemory("building DTD");
Owen Taylor3473f882001-02-23 17:55:21 +0000884 return(NULL);
885 }
886 memset(cur, 0 , sizeof(xmlDtd));
887 cur->type = XML_DTD_NODE;
888
889 if (name != NULL)
Daniel Veillardaa6de472008-08-25 14:53:31 +0000890 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +0000891 if (ExternalID != NULL)
Daniel Veillardaa6de472008-08-25 14:53:31 +0000892 cur->ExternalID = xmlStrdup(ExternalID);
Owen Taylor3473f882001-02-23 17:55:21 +0000893 if (SystemID != NULL)
Daniel Veillardaa6de472008-08-25 14:53:31 +0000894 cur->SystemID = xmlStrdup(SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +0000895 if (doc != NULL)
896 doc->extSubset = cur;
897 cur->doc = doc;
898
Daniel Veillarda880b122003-04-21 21:36:41 +0000899 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000900 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000901 return(cur);
902}
903
904/**
905 * xmlGetIntSubset:
906 * @doc: the document pointer
907 *
908 * Get the internal subset of a document
909 * Returns a pointer to the DTD structure or NULL if not found
910 */
911
912xmlDtdPtr
913xmlGetIntSubset(xmlDocPtr doc) {
914 xmlNodePtr cur;
915
916 if (doc == NULL)
917 return(NULL);
918 cur = doc->children;
919 while (cur != NULL) {
920 if (cur->type == XML_DTD_NODE)
921 return((xmlDtdPtr) cur);
922 cur = cur->next;
923 }
924 return((xmlDtdPtr) doc->intSubset);
925}
926
927/**
928 * xmlCreateIntSubset:
929 * @doc: the document pointer
930 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000931 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000932 * @SystemID: the system ID
933 *
934 * Create the internal subset of a document
935 * Returns a pointer to the new DTD structure
936 */
937xmlDtdPtr
938xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
939 const xmlChar *ExternalID, const xmlChar *SystemID) {
940 xmlDtdPtr cur;
941
942 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
943#ifdef DEBUG_TREE
944 xmlGenericError(xmlGenericErrorContext,
945
946 "xmlCreateIntSubset(): document %s already have an internal subset\n",
947 doc->name);
948#endif
949 return(NULL);
950 }
951
952 /*
953 * Allocate a new DTD and fill the fields.
954 */
955 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
956 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000957 xmlTreeErrMemory("building internal subset");
Owen Taylor3473f882001-02-23 17:55:21 +0000958 return(NULL);
959 }
960 memset(cur, 0, sizeof(xmlDtd));
961 cur->type = XML_DTD_NODE;
962
William M. Bracka3215c72004-07-31 16:24:01 +0000963 if (name != NULL) {
964 cur->name = xmlStrdup(name);
965 if (cur->name == NULL) {
966 xmlTreeErrMemory("building internal subset");
967 xmlFree(cur);
968 return(NULL);
969 }
970 }
971 if (ExternalID != NULL) {
Daniel Veillardaa6de472008-08-25 14:53:31 +0000972 cur->ExternalID = xmlStrdup(ExternalID);
William M. Bracka3215c72004-07-31 16:24:01 +0000973 if (cur->ExternalID == NULL) {
974 xmlTreeErrMemory("building internal subset");
975 if (cur->name != NULL)
976 xmlFree((char *)cur->name);
977 xmlFree(cur);
978 return(NULL);
979 }
980 }
981 if (SystemID != NULL) {
Daniel Veillardaa6de472008-08-25 14:53:31 +0000982 cur->SystemID = xmlStrdup(SystemID);
William M. Bracka3215c72004-07-31 16:24:01 +0000983 if (cur->SystemID == NULL) {
984 xmlTreeErrMemory("building internal subset");
985 if (cur->name != NULL)
986 xmlFree((char *)cur->name);
987 if (cur->ExternalID != NULL)
988 xmlFree((char *)cur->ExternalID);
989 xmlFree(cur);
990 return(NULL);
991 }
992 }
Owen Taylor3473f882001-02-23 17:55:21 +0000993 if (doc != NULL) {
994 doc->intSubset = cur;
995 cur->parent = doc;
996 cur->doc = doc;
997 if (doc->children == NULL) {
998 doc->children = (xmlNodePtr) cur;
999 doc->last = (xmlNodePtr) cur;
1000 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00001001 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +00001002 xmlNodePtr prev;
1003
Owen Taylor3473f882001-02-23 17:55:21 +00001004 prev = doc->children;
1005 prev->prev = (xmlNodePtr) cur;
1006 cur->next = prev;
1007 doc->children = (xmlNodePtr) cur;
1008 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +00001009 xmlNodePtr next;
1010
1011 next = doc->children;
1012 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
1013 next = next->next;
1014 if (next == NULL) {
1015 cur->prev = doc->last;
1016 cur->prev->next = (xmlNodePtr) cur;
1017 cur->next = NULL;
1018 doc->last = (xmlNodePtr) cur;
1019 } else {
1020 cur->next = next;
1021 cur->prev = next->prev;
1022 if (cur->prev == NULL)
1023 doc->children = (xmlNodePtr) cur;
1024 else
1025 cur->prev->next = (xmlNodePtr) cur;
1026 next->prev = (xmlNodePtr) cur;
1027 }
Owen Taylor3473f882001-02-23 17:55:21 +00001028 }
1029 }
1030 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001031
Daniel Veillarda880b122003-04-21 21:36:41 +00001032 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001033 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001034 return(cur);
1035}
1036
1037/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001038 * DICT_FREE:
1039 * @str: a string
1040 *
1041 * Free a string if it is not owned by the "dict" dictionnary in the
1042 * current scope
1043 */
1044#define DICT_FREE(str) \
Daniel Veillardaa6de472008-08-25 14:53:31 +00001045 if ((str) && ((!dict) || \
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001046 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
1047 xmlFree((char *)(str));
1048
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00001049
1050/**
1051 * DICT_COPY:
1052 * @str: a string
1053 *
1054 * Copy a string using a "dict" dictionnary in the current scope,
1055 * if availabe.
1056 */
1057#define DICT_COPY(str, cpy) \
1058 if (str) { \
1059 if (dict) { \
1060 if (xmlDictOwns(dict, (const xmlChar *)(str))) \
1061 cpy = (xmlChar *) (str); \
1062 else \
1063 cpy = (xmlChar *) xmlDictLookup((dict), (const xmlChar *)(str), -1); \
1064 } else \
1065 cpy = xmlStrdup((const xmlChar *)(str)); }
1066
1067/**
1068 * DICT_CONST_COPY:
1069 * @str: a string
1070 *
1071 * Copy a string using a "dict" dictionnary in the current scope,
1072 * if availabe.
1073 */
1074#define DICT_CONST_COPY(str, cpy) \
1075 if (str) { \
1076 if (dict) { \
1077 if (xmlDictOwns(dict, (const xmlChar *)(str))) \
1078 cpy = (const xmlChar *) (str); \
1079 else \
1080 cpy = xmlDictLookup((dict), (const xmlChar *)(str), -1); \
1081 } else \
1082 cpy = (const xmlChar *) xmlStrdup((const xmlChar *)(str)); }
1083
1084
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001085/**
Owen Taylor3473f882001-02-23 17:55:21 +00001086 * xmlFreeDtd:
1087 * @cur: the DTD structure to free up
1088 *
1089 * Free a DTD structure.
1090 */
1091void
1092xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001093 xmlDictPtr dict = NULL;
1094
Owen Taylor3473f882001-02-23 17:55:21 +00001095 if (cur == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001096 return;
1097 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001098 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001099
Daniel Veillarda880b122003-04-21 21:36:41 +00001100 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001101 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1102
Owen Taylor3473f882001-02-23 17:55:21 +00001103 if (cur->children != NULL) {
1104 xmlNodePtr next, c = cur->children;
1105
1106 /*
William M. Brack18a04f22004-08-03 16:42:37 +00001107 * Cleanup all nodes which are not part of the specific lists
1108 * of notations, elements, attributes and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00001109 */
1110 while (c != NULL) {
1111 next = c->next;
William M. Brack18a04f22004-08-03 16:42:37 +00001112 if ((c->type != XML_NOTATION_NODE) &&
1113 (c->type != XML_ELEMENT_DECL) &&
1114 (c->type != XML_ATTRIBUTE_DECL) &&
1115 (c->type != XML_ENTITY_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001116 xmlUnlinkNode(c);
1117 xmlFreeNode(c);
1118 }
1119 c = next;
1120 }
1121 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001122 DICT_FREE(cur->name)
1123 DICT_FREE(cur->SystemID)
1124 DICT_FREE(cur->ExternalID)
Owen Taylor3473f882001-02-23 17:55:21 +00001125 /* TODO !!! */
1126 if (cur->notations != NULL)
1127 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
Daniel Veillardaa6de472008-08-25 14:53:31 +00001128
Owen Taylor3473f882001-02-23 17:55:21 +00001129 if (cur->elements != NULL)
1130 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1131 if (cur->attributes != NULL)
1132 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1133 if (cur->entities != NULL)
1134 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1135 if (cur->pentities != NULL)
1136 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1137
Owen Taylor3473f882001-02-23 17:55:21 +00001138 xmlFree(cur);
1139}
1140
1141/**
1142 * xmlNewDoc:
1143 * @version: xmlChar string giving the version of XML "1.0"
1144 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001145 * Creates a new XML document
1146 *
Owen Taylor3473f882001-02-23 17:55:21 +00001147 * Returns a new document
1148 */
1149xmlDocPtr
1150xmlNewDoc(const xmlChar *version) {
1151 xmlDocPtr cur;
1152
1153 if (version == NULL)
1154 version = (const xmlChar *) "1.0";
1155
1156 /*
1157 * Allocate a new document and fill the fields.
1158 */
1159 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1160 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001161 xmlTreeErrMemory("building doc");
Owen Taylor3473f882001-02-23 17:55:21 +00001162 return(NULL);
1163 }
1164 memset(cur, 0, sizeof(xmlDoc));
1165 cur->type = XML_DOCUMENT_NODE;
1166
Daniel Veillardaa6de472008-08-25 14:53:31 +00001167 cur->version = xmlStrdup(version);
William M. Bracka3215c72004-07-31 16:24:01 +00001168 if (cur->version == NULL) {
1169 xmlTreeErrMemory("building doc");
1170 xmlFree(cur);
Daniel Veillardae0765b2008-07-31 19:54:59 +00001171 return(NULL);
William M. Bracka3215c72004-07-31 16:24:01 +00001172 }
Owen Taylor3473f882001-02-23 17:55:21 +00001173 cur->standalone = -1;
1174 cur->compression = -1; /* not initialized */
1175 cur->doc = cur;
Daniel Veillardae0765b2008-07-31 19:54:59 +00001176 cur->parseFlags = 0;
1177 cur->properties = XML_DOC_USERBUILT;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001178 /*
1179 * The in memory encoding is always UTF8
1180 * This field will never change and would
1181 * be obsolete if not for binary compatibility.
1182 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001183 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001184
Daniel Veillarda880b122003-04-21 21:36:41 +00001185 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001186 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001187 return(cur);
1188}
1189
1190/**
1191 * xmlFreeDoc:
1192 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001193 *
1194 * Free up all the structures used by a document, tree included.
1195 */
1196void
1197xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001198 xmlDtdPtr extSubset, intSubset;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001199 xmlDictPtr dict = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001200
Owen Taylor3473f882001-02-23 17:55:21 +00001201 if (cur == NULL) {
1202#ifdef DEBUG_TREE
1203 xmlGenericError(xmlGenericErrorContext,
1204 "xmlFreeDoc : document == NULL\n");
1205#endif
1206 return;
1207 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001208#ifdef LIBXML_DEBUG_RUNTIME
Daniel Veillardbca3ad22005-08-23 22:14:02 +00001209#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001210 xmlDebugCheckDocument(stderr, cur);
1211#endif
Daniel Veillardbca3ad22005-08-23 22:14:02 +00001212#endif
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001213
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001214 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001215
Daniel Veillarda880b122003-04-21 21:36:41 +00001216 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001217 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1218
Daniel Veillard76d66f42001-05-16 21:05:17 +00001219 /*
1220 * Do this before freeing the children list to avoid ID lookups
1221 */
1222 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1223 cur->ids = NULL;
1224 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1225 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001226 extSubset = cur->extSubset;
1227 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001228 if (intSubset == extSubset)
1229 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001230 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001231 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001232 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001233 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001234 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001235 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001236 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001237 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001238 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001239 }
1240
1241 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001242 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001243
1244 DICT_FREE(cur->version)
1245 DICT_FREE(cur->name)
1246 DICT_FREE(cur->encoding)
1247 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001248 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001249 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001250}
1251
1252/**
1253 * xmlStringLenGetNodeList:
1254 * @doc: the document
1255 * @value: the value of the text
1256 * @len: the length of the string value
1257 *
1258 * Parse the value string and build the node list associated. Should
1259 * produce a flat tree with only TEXTs and ENTITY_REFs.
1260 * Returns a pointer to the first child
1261 */
1262xmlNodePtr
1263xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1264 xmlNodePtr ret = NULL, last = NULL;
1265 xmlNodePtr node;
1266 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001267 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001268 const xmlChar *q;
1269 xmlEntityPtr ent;
Conrad Irwin7d553f82012-05-10 20:17:25 -07001270 xmlBufferPtr buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001271
1272 if (value == NULL) return(NULL);
1273
Conrad Irwin7d553f82012-05-10 20:17:25 -07001274 buffer = xmlBufferCreateSize(0);
1275 if (buffer == NULL) return(NULL);
Conrad Irwin7d0d2a52012-05-14 14:18:58 +08001276 xmlBufferSetAllocationScheme(buffer, XML_BUFFER_ALLOC_HYBRID);
Conrad Irwin7d553f82012-05-10 20:17:25 -07001277
Owen Taylor3473f882001-02-23 17:55:21 +00001278 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001279 while ((cur < end) && (*cur != 0)) {
1280 if (cur[0] == '&') {
1281 int charval = 0;
1282 xmlChar tmp;
1283
Owen Taylor3473f882001-02-23 17:55:21 +00001284 /*
1285 * Save the current text.
1286 */
1287 if (cur != q) {
Conrad Irwin7d553f82012-05-10 20:17:25 -07001288 if (xmlBufferAdd(buffer, q, cur - q))
1289 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00001290 }
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);
Conrad Irwin7d553f82012-05-10 20:17:25 -07001354 goto out;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001355 }
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)) {
Conrad Irwin7d553f82012-05-10 20:17:25 -07001364
1365 if (xmlBufferCat(buffer, ent->content))
1366 goto out;
Daniel Veillardaa6de472008-08-25 14:53:31 +00001367
Daniel Veillard07cb8222003-09-10 10:51:05 +00001368 } else {
1369 /*
Conrad Irwin7d553f82012-05-10 20:17:25 -07001370 * Flush buffer so far
1371 */
1372 if (buffer->use) {
1373 node = xmlNewDocText(doc, NULL);
1374 if (node == NULL) {
1375 if (val != NULL) xmlFree(val);
1376 goto out;
1377 }
1378 node->content = xmlBufferDetach(buffer);
1379
1380 if (last == NULL) {
1381 last = ret = node;
1382 } else {
1383 last = xmlAddNextSibling(last, node);
1384 }
1385 }
1386
1387 /*
Daniel Veillard07cb8222003-09-10 10:51:05 +00001388 * Create a new REFERENCE_REF node
1389 */
1390 node = xmlNewReference(doc, val);
1391 if (node == NULL) {
1392 if (val != NULL) xmlFree(val);
Conrad Irwin7d553f82012-05-10 20:17:25 -07001393 goto out;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001394 }
1395 else if ((ent != NULL) && (ent->children == NULL)) {
1396 xmlNodePtr temp;
1397
1398 ent->children = xmlStringGetNodeList(doc,
1399 (const xmlChar*)node->content);
1400 ent->owner = 1;
1401 temp = ent->children;
1402 while (temp) {
1403 temp->parent = (xmlNodePtr)ent;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001404 ent->last = temp;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001405 temp = temp->next;
1406 }
1407 }
1408 if (last == NULL) {
1409 last = ret = node;
1410 } else {
1411 last = xmlAddNextSibling(last, node);
1412 }
1413 }
1414 xmlFree(val);
1415 }
1416 cur++;
1417 q = cur;
1418 }
1419 if (charval != 0) {
1420 xmlChar buf[10];
1421 int l;
1422
1423 l = xmlCopyCharMultiByte(buf, charval);
1424 buf[l] = 0;
Conrad Irwin7d553f82012-05-10 20:17:25 -07001425
1426 if (xmlBufferCat(buffer, buf))
1427 goto out;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001428 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001429 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001430 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001431 cur++;
1432 }
Conrad Irwin7d553f82012-05-10 20:17:25 -07001433
1434 if (cur != q) {
Owen Taylor3473f882001-02-23 17:55:21 +00001435 /*
1436 * Handle the last piece of text.
1437 */
Conrad Irwin7d553f82012-05-10 20:17:25 -07001438 if (xmlBufferAdd(buffer, q, cur - q))
1439 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00001440 }
Conrad Irwin7d553f82012-05-10 20:17:25 -07001441
1442 if (buffer->use) {
1443 node = xmlNewDocText(doc, NULL);
1444 if (node == NULL) goto out;
1445 node->content = xmlBufferDetach(buffer);
1446
1447 if (last == NULL) {
1448 last = ret = node;
1449 } else {
1450 last = xmlAddNextSibling(last, node);
1451 }
1452 } else if (ret == NULL) {
1453 ret = xmlNewDocText(doc, BAD_CAST "");
1454 }
1455
1456out:
1457 xmlBufferFree(buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001458 return(ret);
1459}
1460
1461/**
1462 * xmlStringGetNodeList:
1463 * @doc: the document
1464 * @value: the value of the attribute
1465 *
1466 * Parse the value string and build the node list associated. Should
1467 * produce a flat tree with only TEXTs and ENTITY_REFs.
1468 * Returns a pointer to the first child
1469 */
1470xmlNodePtr
1471xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1472 xmlNodePtr ret = NULL, last = NULL;
1473 xmlNodePtr node;
1474 xmlChar *val;
1475 const xmlChar *cur = value;
1476 const xmlChar *q;
1477 xmlEntityPtr ent;
Conrad Irwin7d553f82012-05-10 20:17:25 -07001478 xmlBufferPtr buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001479
1480 if (value == NULL) return(NULL);
1481
Conrad Irwin7d553f82012-05-10 20:17:25 -07001482 buffer = xmlBufferCreateSize(0);
1483 if (buffer == NULL) return(NULL);
Conrad Irwin7d0d2a52012-05-14 14:18:58 +08001484 xmlBufferSetAllocationScheme(buffer, XML_BUFFER_ALLOC_HYBRID);
Conrad Irwin7d553f82012-05-10 20:17:25 -07001485
Owen Taylor3473f882001-02-23 17:55:21 +00001486 q = cur;
1487 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001488 if (cur[0] == '&') {
1489 int charval = 0;
1490 xmlChar tmp;
1491
Owen Taylor3473f882001-02-23 17:55:21 +00001492 /*
1493 * Save the current text.
1494 */
1495 if (cur != q) {
Conrad Irwin7d553f82012-05-10 20:17:25 -07001496 if (xmlBufferAdd(buffer, q, cur - q))
1497 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00001498 }
Owen Taylor3473f882001-02-23 17:55:21 +00001499 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001500 if ((cur[1] == '#') && (cur[2] == 'x')) {
1501 cur += 3;
1502 tmp = *cur;
1503 while (tmp != ';') { /* Non input consuming loop */
Daniel Veillardaa6de472008-08-25 14:53:31 +00001504 if ((tmp >= '0') && (tmp <= '9'))
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001505 charval = charval * 16 + (tmp - '0');
1506 else if ((tmp >= 'a') && (tmp <= 'f'))
1507 charval = charval * 16 + (tmp - 'a') + 10;
1508 else if ((tmp >= 'A') && (tmp <= 'F'))
1509 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001510 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001511 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1512 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001513 charval = 0;
1514 break;
1515 }
1516 cur++;
1517 tmp = *cur;
1518 }
1519 if (tmp == ';')
1520 cur++;
1521 q = cur;
1522 } else if (cur[1] == '#') {
1523 cur += 2;
1524 tmp = *cur;
1525 while (tmp != ';') { /* Non input consuming loops */
Daniel Veillardaa6de472008-08-25 14:53:31 +00001526 if ((tmp >= '0') && (tmp <= '9'))
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001527 charval = charval * 10 + (tmp - '0');
1528 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001529 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1530 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001531 charval = 0;
1532 break;
1533 }
1534 cur++;
1535 tmp = *cur;
1536 }
1537 if (tmp == ';')
1538 cur++;
1539 q = cur;
1540 } else {
1541 /*
1542 * Read the entity string
1543 */
1544 cur++;
1545 q = cur;
1546 while ((*cur != 0) && (*cur != ';')) cur++;
1547 if (*cur == 0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001548 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1549 (xmlNodePtr) doc, (const char *) q);
Conrad Irwin7d553f82012-05-10 20:17:25 -07001550 goto out;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001551 }
1552 if (cur != q) {
1553 /*
1554 * Predefined entities don't generate nodes
1555 */
1556 val = xmlStrndup(q, cur - q);
1557 ent = xmlGetDocEntity(doc, val);
1558 if ((ent != NULL) &&
1559 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
Conrad Irwin7d553f82012-05-10 20:17:25 -07001560
1561 if (xmlBufferCat(buffer, ent->content))
1562 goto out;
Daniel Veillardaa6de472008-08-25 14:53:31 +00001563
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001564 } else {
1565 /*
Conrad Irwin7d553f82012-05-10 20:17:25 -07001566 * Flush buffer so far
1567 */
1568 if (buffer->use) {
1569 node = xmlNewDocText(doc, NULL);
1570 node->content = xmlBufferDetach(buffer);
1571
1572 if (last == NULL) {
1573 last = ret = node;
1574 } else {
1575 last = xmlAddNextSibling(last, node);
1576 }
1577 }
1578
1579 /*
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001580 * Create a new REFERENCE_REF node
1581 */
1582 node = xmlNewReference(doc, val);
1583 if (node == NULL) {
1584 if (val != NULL) xmlFree(val);
Conrad Irwin7d553f82012-05-10 20:17:25 -07001585 goto out;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001586 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001587 else if ((ent != NULL) && (ent->children == NULL)) {
1588 xmlNodePtr temp;
1589
1590 ent->children = xmlStringGetNodeList(doc,
1591 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001592 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001593 temp = ent->children;
1594 while (temp) {
1595 temp->parent = (xmlNodePtr)ent;
1596 temp = temp->next;
1597 }
1598 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001599 if (last == NULL) {
1600 last = ret = node;
1601 } else {
1602 last = xmlAddNextSibling(last, node);
1603 }
1604 }
1605 xmlFree(val);
1606 }
1607 cur++;
1608 q = cur;
1609 }
1610 if (charval != 0) {
1611 xmlChar buf[10];
1612 int len;
1613
1614 len = xmlCopyCharMultiByte(buf, charval);
1615 buf[len] = 0;
Conrad Irwin7d553f82012-05-10 20:17:25 -07001616
1617 if (xmlBufferCat(buffer, buf))
1618 goto out;
1619 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001620 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001621 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001622 cur++;
1623 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001624 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001625 /*
1626 * Handle the last piece of text.
1627 */
Conrad Irwin7d553f82012-05-10 20:17:25 -07001628 xmlBufferAdd(buffer, q, cur - q);
1629 }
1630
1631 if (buffer->use) {
1632 node = xmlNewDocText(doc, NULL);
1633 node->content = xmlBufferDetach(buffer);
1634
1635 if (last == NULL) {
1636 last = ret = node;
Owen Taylor3473f882001-02-23 17:55:21 +00001637 } else {
Conrad Irwin7d553f82012-05-10 20:17:25 -07001638 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001639 }
1640 }
Conrad Irwin7d553f82012-05-10 20:17:25 -07001641
1642out:
1643 xmlBufferFree(buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001644 return(ret);
1645}
1646
1647/**
1648 * xmlNodeListGetString:
1649 * @doc: the document
1650 * @list: a Node list
1651 * @inLine: should we replace entity contents or show their external form
1652 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001653 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001654 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001655 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001656 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001657 */
1658xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001659xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1660{
Owen Taylor3473f882001-02-23 17:55:21 +00001661 xmlNodePtr node = list;
1662 xmlChar *ret = NULL;
1663 xmlEntityPtr ent;
1664
Daniel Veillard7646b182002-04-20 06:41:40 +00001665 if (list == NULL)
1666 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001667
1668 while (node != NULL) {
1669 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001670 (node->type == XML_CDATA_SECTION_NODE)) {
1671 if (inLine) {
1672 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001673 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001674 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001675
Daniel Veillard7646b182002-04-20 06:41:40 +00001676 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1677 if (buffer != NULL) {
1678 ret = xmlStrcat(ret, buffer);
1679 xmlFree(buffer);
1680 }
1681 }
1682 } else if (node->type == XML_ENTITY_REF_NODE) {
1683 if (inLine) {
1684 ent = xmlGetDocEntity(doc, node->name);
1685 if (ent != NULL) {
1686 xmlChar *buffer;
1687
1688 /* an entity content can be any "well balanced chunk",
1689 * i.e. the result of the content [43] production:
1690 * http://www.w3.org/TR/REC-xml#NT-content.
1691 * So it can contain text, CDATA section or nested
1692 * entity reference nodes (among others).
1693 * -> we recursive call xmlNodeListGetString()
1694 * which handles these types */
1695 buffer = xmlNodeListGetString(doc, ent->children, 1);
1696 if (buffer != NULL) {
1697 ret = xmlStrcat(ret, buffer);
1698 xmlFree(buffer);
1699 }
1700 } else {
1701 ret = xmlStrcat(ret, node->content);
1702 }
1703 } else {
1704 xmlChar buf[2];
1705
1706 buf[0] = '&';
1707 buf[1] = 0;
1708 ret = xmlStrncat(ret, buf, 1);
1709 ret = xmlStrcat(ret, node->name);
1710 buf[0] = ';';
1711 buf[1] = 0;
1712 ret = xmlStrncat(ret, buf, 1);
1713 }
1714 }
1715#if 0
1716 else {
1717 xmlGenericError(xmlGenericErrorContext,
1718 "xmlGetNodeListString : invalid node type %d\n",
1719 node->type);
1720 }
1721#endif
1722 node = node->next;
1723 }
1724 return (ret);
1725}
Daniel Veillard652327a2003-09-29 18:02:38 +00001726
1727#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001728/**
1729 * xmlNodeListGetRawString:
1730 * @doc: the document
1731 * @list: a Node list
1732 * @inLine: should we replace entity contents or show their external form
1733 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001734 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001735 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1736 * this function doesn't do any character encoding handling.
1737 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001738 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001739 */
1740xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001741xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1742{
Owen Taylor3473f882001-02-23 17:55:21 +00001743 xmlNodePtr node = list;
1744 xmlChar *ret = NULL;
1745 xmlEntityPtr ent;
1746
Daniel Veillard7646b182002-04-20 06:41:40 +00001747 if (list == NULL)
1748 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001749
1750 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001751 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001752 (node->type == XML_CDATA_SECTION_NODE)) {
1753 if (inLine) {
1754 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001755 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001756 xmlChar *buffer;
1757
1758 buffer = xmlEncodeSpecialChars(doc, node->content);
1759 if (buffer != NULL) {
1760 ret = xmlStrcat(ret, buffer);
1761 xmlFree(buffer);
1762 }
1763 }
1764 } else if (node->type == XML_ENTITY_REF_NODE) {
1765 if (inLine) {
1766 ent = xmlGetDocEntity(doc, node->name);
1767 if (ent != NULL) {
1768 xmlChar *buffer;
1769
1770 /* an entity content can be any "well balanced chunk",
1771 * i.e. the result of the content [43] production:
1772 * http://www.w3.org/TR/REC-xml#NT-content.
1773 * So it can contain text, CDATA section or nested
1774 * entity reference nodes (among others).
1775 * -> we recursive call xmlNodeListGetRawString()
1776 * which handles these types */
1777 buffer =
1778 xmlNodeListGetRawString(doc, ent->children, 1);
1779 if (buffer != NULL) {
1780 ret = xmlStrcat(ret, buffer);
1781 xmlFree(buffer);
1782 }
1783 } else {
1784 ret = xmlStrcat(ret, node->content);
1785 }
1786 } else {
1787 xmlChar buf[2];
1788
1789 buf[0] = '&';
1790 buf[1] = 0;
1791 ret = xmlStrncat(ret, buf, 1);
1792 ret = xmlStrcat(ret, node->name);
1793 buf[0] = ';';
1794 buf[1] = 0;
1795 ret = xmlStrncat(ret, buf, 1);
1796 }
1797 }
Owen Taylor3473f882001-02-23 17:55:21 +00001798#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001799 else {
1800 xmlGenericError(xmlGenericErrorContext,
1801 "xmlGetNodeListString : invalid node type %d\n",
1802 node->type);
1803 }
Owen Taylor3473f882001-02-23 17:55:21 +00001804#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001805 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001806 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001807 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001808}
Daniel Veillard652327a2003-09-29 18:02:38 +00001809#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001810
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001811static xmlAttrPtr
1812xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns,
1813 const xmlChar * name, const xmlChar * value,
1814 int eatname)
1815{
Owen Taylor3473f882001-02-23 17:55:21 +00001816 xmlAttrPtr cur;
1817 xmlDocPtr doc = NULL;
1818
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001819 if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) {
Daniel Veillard8f6c2b12008-04-03 11:17:21 +00001820 if ((eatname == 1) &&
1821 ((node->doc == NULL) ||
Daniel Veillarded939f82008-04-08 08:20:08 +00001822 (!(xmlDictOwns(node->doc->dict, name)))))
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001823 xmlFree((xmlChar *) name);
1824 return (NULL);
1825 }
Owen Taylor3473f882001-02-23 17:55:21 +00001826
1827 /*
1828 * Allocate a new property and fill the fields.
1829 */
1830 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1831 if (cur == NULL) {
Daniel Veillard8f6c2b12008-04-03 11:17:21 +00001832 if ((eatname == 1) &&
Daniel Veillard76d36452009-09-07 11:19:33 +02001833 ((node == NULL) || (node->doc == NULL) ||
Daniel Veillarded939f82008-04-08 08:20:08 +00001834 (!(xmlDictOwns(node->doc->dict, name)))))
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001835 xmlFree((xmlChar *) name);
1836 xmlTreeErrMemory("building attribute");
1837 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001838 }
1839 memset(cur, 0, sizeof(xmlAttr));
1840 cur->type = XML_ATTRIBUTE_NODE;
1841
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001842 cur->parent = node;
Owen Taylor3473f882001-02-23 17:55:21 +00001843 if (node != NULL) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001844 doc = node->doc;
1845 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001846 }
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001847 cur->ns = ns;
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001848
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001849 if (eatname == 0) {
1850 if ((doc != NULL) && (doc->dict != NULL))
1851 cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
1852 else
1853 cur->name = xmlStrdup(name);
1854 } else
1855 cur->name = name;
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001856
Owen Taylor3473f882001-02-23 17:55:21 +00001857 if (value != NULL) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001858 xmlNodePtr tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00001859
Daniel Veillard6f8611f2008-02-15 08:33:21 +00001860 if(!xmlCheckUTF8(value)) {
1861 xmlTreeErr(XML_TREE_NOT_UTF8, (xmlNodePtr) doc,
1862 NULL);
1863 if (doc != NULL)
1864 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
1865 }
1866 cur->children = xmlNewDocText(doc, value);
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001867 cur->last = NULL;
1868 tmp = cur->children;
1869 while (tmp != NULL) {
1870 tmp->parent = (xmlNodePtr) cur;
1871 if (tmp->next == NULL)
1872 cur->last = tmp;
1873 tmp = tmp->next;
1874 }
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001875 }
Owen Taylor3473f882001-02-23 17:55:21 +00001876
1877 /*
1878 * Add it at the end to preserve parsing order ...
1879 */
1880 if (node != NULL) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001881 if (node->properties == NULL) {
1882 node->properties = cur;
1883 } else {
1884 xmlAttrPtr prev = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00001885
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001886 while (prev->next != NULL)
1887 prev = prev->next;
1888 prev->next = cur;
1889 cur->prev = prev;
1890 }
Owen Taylor3473f882001-02-23 17:55:21 +00001891 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001892
Daniel Veillard76d36452009-09-07 11:19:33 +02001893 if ((value != NULL) && (node != NULL) &&
1894 (xmlIsID(node->doc, node, cur) == 1))
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001895 xmlAddID(NULL, node->doc, value, cur);
1896
Daniel Veillarda880b122003-04-21 21:36:41 +00001897 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001898 xmlRegisterNodeDefaultValue((xmlNodePtr) cur);
1899 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001900}
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001901
1902#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
1903 defined(LIBXML_SCHEMAS_ENABLED)
1904/**
1905 * xmlNewProp:
1906 * @node: the holding node
1907 * @name: the name of the attribute
1908 * @value: the value of the attribute
1909 *
1910 * Create a new property carried by a node.
1911 * Returns a pointer to the attribute
1912 */
1913xmlAttrPtr
1914xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1915
1916 if (name == NULL) {
1917#ifdef DEBUG_TREE
1918 xmlGenericError(xmlGenericErrorContext,
1919 "xmlNewProp : name == NULL\n");
1920#endif
1921 return(NULL);
1922 }
1923
1924 return xmlNewPropInternal(node, NULL, name, value, 0);
1925}
Daniel Veillard652327a2003-09-29 18:02:38 +00001926#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001927
1928/**
1929 * xmlNewNsProp:
1930 * @node: the holding node
1931 * @ns: the namespace
1932 * @name: the name of the attribute
1933 * @value: the value of the attribute
1934 *
1935 * Create a new property tagged with a namespace and carried by a node.
1936 * Returns a pointer to the attribute
1937 */
1938xmlAttrPtr
1939xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1940 const xmlChar *value) {
Owen Taylor3473f882001-02-23 17:55:21 +00001941
1942 if (name == NULL) {
1943#ifdef DEBUG_TREE
1944 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001945 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001946#endif
1947 return(NULL);
1948 }
1949
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001950 return xmlNewPropInternal(node, ns, name, value, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001951}
1952
1953/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001954 * xmlNewNsPropEatName:
1955 * @node: the holding node
1956 * @ns: the namespace
1957 * @name: the name of the attribute
1958 * @value: the value of the attribute
1959 *
1960 * Create a new property tagged with a namespace and carried by a node.
1961 * Returns a pointer to the attribute
1962 */
1963xmlAttrPtr
1964xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1965 const xmlChar *value) {
Daniel Veillard46de64e2002-05-29 08:21:33 +00001966
1967 if (name == NULL) {
1968#ifdef DEBUG_TREE
1969 xmlGenericError(xmlGenericErrorContext,
1970 "xmlNewNsPropEatName : name == NULL\n");
1971#endif
1972 return(NULL);
1973 }
1974
Daniel Veillard8f6c2b12008-04-03 11:17:21 +00001975 return xmlNewPropInternal(node, ns, name, value, 1);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001976}
1977
1978/**
Owen Taylor3473f882001-02-23 17:55:21 +00001979 * xmlNewDocProp:
1980 * @doc: the document
1981 * @name: the name of the attribute
1982 * @value: the value of the attribute
1983 *
1984 * Create a new property carried by a document.
1985 * Returns a pointer to the attribute
1986 */
1987xmlAttrPtr
1988xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1989 xmlAttrPtr cur;
1990
1991 if (name == NULL) {
1992#ifdef DEBUG_TREE
1993 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001994 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001995#endif
1996 return(NULL);
1997 }
1998
1999 /*
2000 * Allocate a new property and fill the fields.
2001 */
2002 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
2003 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002004 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00002005 return(NULL);
2006 }
2007 memset(cur, 0, sizeof(xmlAttr));
2008 cur->type = XML_ATTRIBUTE_NODE;
2009
Daniel Veillard03a53c32004-10-26 16:06:51 +00002010 if ((doc != NULL) && (doc->dict != NULL))
2011 cur->name = xmlDictLookup(doc->dict, name, -1);
2012 else
2013 cur->name = xmlStrdup(name);
Daniel Veillardaa6de472008-08-25 14:53:31 +00002014 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002015 if (value != NULL) {
2016 xmlNodePtr tmp;
2017
2018 cur->children = xmlStringGetNodeList(doc, value);
2019 cur->last = NULL;
2020
2021 tmp = cur->children;
2022 while (tmp != NULL) {
2023 tmp->parent = (xmlNodePtr) cur;
2024 if (tmp->next == NULL)
2025 cur->last = tmp;
2026 tmp = tmp->next;
2027 }
2028 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002029
Daniel Veillarda880b122003-04-21 21:36:41 +00002030 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002031 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002032 return(cur);
2033}
2034
2035/**
2036 * xmlFreePropList:
2037 * @cur: the first property in the list
2038 *
2039 * Free a property and all its siblings, all the children are freed too.
2040 */
2041void
2042xmlFreePropList(xmlAttrPtr cur) {
2043 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002044 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002045 while (cur != NULL) {
2046 next = cur->next;
2047 xmlFreeProp(cur);
2048 cur = next;
2049 }
2050}
2051
2052/**
2053 * xmlFreeProp:
2054 * @cur: an attribute
2055 *
2056 * Free one attribute, all the content is freed too
2057 */
2058void
2059xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002060 xmlDictPtr dict = NULL;
2061 if (cur == NULL) return;
2062
2063 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002064
Daniel Veillarda880b122003-04-21 21:36:41 +00002065 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002066 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
2067
Owen Taylor3473f882001-02-23 17:55:21 +00002068 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillardda6f4af2005-06-20 17:17:54 +00002069 if ((cur->doc != NULL) && (cur->atype == XML_ATTRIBUTE_ID)) {
2070 xmlRemoveID(cur->doc, cur);
Daniel Veillard76d66f42001-05-16 21:05:17 +00002071 }
Owen Taylor3473f882001-02-23 17:55:21 +00002072 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002073 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002074 xmlFree(cur);
2075}
2076
2077/**
2078 * xmlRemoveProp:
2079 * @cur: an attribute
2080 *
2081 * Unlink and free one attribute, all the content is freed too
2082 * Note this doesn't work for namespace definition attributes
2083 *
2084 * Returns 0 if success and -1 in case of error.
2085 */
2086int
2087xmlRemoveProp(xmlAttrPtr cur) {
2088 xmlAttrPtr tmp;
2089 if (cur == NULL) {
2090#ifdef DEBUG_TREE
2091 xmlGenericError(xmlGenericErrorContext,
2092 "xmlRemoveProp : cur == NULL\n");
2093#endif
2094 return(-1);
2095 }
2096 if (cur->parent == NULL) {
2097#ifdef DEBUG_TREE
2098 xmlGenericError(xmlGenericErrorContext,
2099 "xmlRemoveProp : cur->parent == NULL\n");
2100#endif
2101 return(-1);
2102 }
2103 tmp = cur->parent->properties;
2104 if (tmp == cur) {
2105 cur->parent->properties = cur->next;
Rob Richards19dc9612005-10-28 16:15:16 +00002106 if (cur->next != NULL)
2107 cur->next->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002108 xmlFreeProp(cur);
2109 return(0);
2110 }
2111 while (tmp != NULL) {
2112 if (tmp->next == cur) {
2113 tmp->next = cur->next;
2114 if (tmp->next != NULL)
2115 tmp->next->prev = tmp;
2116 xmlFreeProp(cur);
2117 return(0);
2118 }
2119 tmp = tmp->next;
2120 }
2121#ifdef DEBUG_TREE
2122 xmlGenericError(xmlGenericErrorContext,
2123 "xmlRemoveProp : attribute not owned by its node\n");
2124#endif
2125 return(-1);
2126}
2127
2128/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002129 * xmlNewDocPI:
2130 * @doc: the target document
Owen Taylor3473f882001-02-23 17:55:21 +00002131 * @name: the processing instruction name
2132 * @content: the PI content
2133 *
2134 * Creation of a processing instruction element.
2135 * Returns a pointer to the new node object.
2136 */
2137xmlNodePtr
Daniel Veillard03a53c32004-10-26 16:06:51 +00002138xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
Owen Taylor3473f882001-02-23 17:55:21 +00002139 xmlNodePtr cur;
2140
2141 if (name == NULL) {
2142#ifdef DEBUG_TREE
2143 xmlGenericError(xmlGenericErrorContext,
2144 "xmlNewPI : name == NULL\n");
2145#endif
2146 return(NULL);
2147 }
2148
2149 /*
2150 * Allocate a new node and fill the fields.
2151 */
2152 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2153 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002154 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002155 return(NULL);
2156 }
2157 memset(cur, 0, sizeof(xmlNode));
2158 cur->type = XML_PI_NODE;
2159
Daniel Veillard03a53c32004-10-26 16:06:51 +00002160 if ((doc != NULL) && (doc->dict != NULL))
2161 cur->name = xmlDictLookup(doc->dict, name, -1);
2162 else
2163 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00002164 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002165 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002166 }
Daniel Veillarda03e3652004-11-02 18:45:30 +00002167 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002168
Daniel Veillarda880b122003-04-21 21:36:41 +00002169 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002170 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002171 return(cur);
2172}
2173
2174/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002175 * xmlNewPI:
2176 * @name: the processing instruction name
2177 * @content: the PI content
2178 *
2179 * Creation of a processing instruction element.
2180 * Use xmlDocNewPI preferably to get string interning
2181 *
2182 * Returns a pointer to the new node object.
2183 */
2184xmlNodePtr
2185xmlNewPI(const xmlChar *name, const xmlChar *content) {
2186 return(xmlNewDocPI(NULL, name, content));
2187}
2188
2189/**
Owen Taylor3473f882001-02-23 17:55:21 +00002190 * xmlNewNode:
2191 * @ns: namespace if any
2192 * @name: the node name
2193 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002194 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002195 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002196 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2197 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002198 */
2199xmlNodePtr
2200xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2201 xmlNodePtr cur;
2202
2203 if (name == NULL) {
2204#ifdef DEBUG_TREE
2205 xmlGenericError(xmlGenericErrorContext,
2206 "xmlNewNode : name == NULL\n");
2207#endif
2208 return(NULL);
2209 }
2210
2211 /*
2212 * Allocate a new node and fill the fields.
2213 */
2214 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2215 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002216 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002217 return(NULL);
2218 }
2219 memset(cur, 0, sizeof(xmlNode));
2220 cur->type = XML_ELEMENT_NODE;
Daniel Veillardaa6de472008-08-25 14:53:31 +00002221
Owen Taylor3473f882001-02-23 17:55:21 +00002222 cur->name = xmlStrdup(name);
2223 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002224
Daniel Veillarda880b122003-04-21 21:36:41 +00002225 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002226 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002227 return(cur);
2228}
2229
2230/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002231 * xmlNewNodeEatName:
2232 * @ns: namespace if any
2233 * @name: the node name
2234 *
2235 * Creation of a new node element. @ns is optional (NULL).
2236 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002237 * Returns a pointer to the new node object, with pointer @name as
2238 * new node's name. Use xmlNewNode() if a copy of @name string is
2239 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002240 */
2241xmlNodePtr
2242xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2243 xmlNodePtr cur;
2244
2245 if (name == NULL) {
2246#ifdef DEBUG_TREE
2247 xmlGenericError(xmlGenericErrorContext,
2248 "xmlNewNode : name == NULL\n");
2249#endif
2250 return(NULL);
2251 }
2252
2253 /*
2254 * Allocate a new node and fill the fields.
2255 */
2256 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2257 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002258 xmlTreeErrMemory("building node");
Daniel Veillard8f6c2b12008-04-03 11:17:21 +00002259 /* we can't check here that name comes from the doc dictionnary */
Daniel Veillard46de64e2002-05-29 08:21:33 +00002260 return(NULL);
2261 }
2262 memset(cur, 0, sizeof(xmlNode));
2263 cur->type = XML_ELEMENT_NODE;
Daniel Veillardaa6de472008-08-25 14:53:31 +00002264
Daniel Veillard46de64e2002-05-29 08:21:33 +00002265 cur->name = name;
2266 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002267
Daniel Veillarda880b122003-04-21 21:36:41 +00002268 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002269 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002270 return(cur);
2271}
2272
2273/**
Owen Taylor3473f882001-02-23 17:55:21 +00002274 * xmlNewDocNode:
2275 * @doc: the document
2276 * @ns: namespace if any
2277 * @name: the node name
2278 * @content: the XML text content if any
2279 *
2280 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002281 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002282 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2283 * references, but XML special chars need to be escaped first by using
2284 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2285 * need entities support.
2286 *
2287 * Returns a pointer to the new node object.
2288 */
2289xmlNodePtr
2290xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2291 const xmlChar *name, const xmlChar *content) {
2292 xmlNodePtr cur;
2293
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002294 if ((doc != NULL) && (doc->dict != NULL))
Daniel Veillard03a53c32004-10-26 16:06:51 +00002295 cur = xmlNewNodeEatName(ns, (xmlChar *)
2296 xmlDictLookup(doc->dict, name, -1));
2297 else
2298 cur = xmlNewNode(ns, name);
Owen Taylor3473f882001-02-23 17:55:21 +00002299 if (cur != NULL) {
2300 cur->doc = doc;
2301 if (content != NULL) {
2302 cur->children = xmlStringGetNodeList(doc, content);
2303 UPDATE_LAST_CHILD_AND_PARENT(cur)
2304 }
2305 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002306
Owen Taylor3473f882001-02-23 17:55:21 +00002307 return(cur);
2308}
2309
Daniel Veillard46de64e2002-05-29 08:21:33 +00002310/**
2311 * xmlNewDocNodeEatName:
2312 * @doc: the document
2313 * @ns: namespace if any
2314 * @name: the node name
2315 * @content: the XML text content if any
2316 *
2317 * Creation of a new node element within a document. @ns and @content
2318 * are optional (NULL).
2319 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2320 * references, but XML special chars need to be escaped first by using
2321 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2322 * need entities support.
2323 *
2324 * Returns a pointer to the new node object.
2325 */
2326xmlNodePtr
2327xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2328 xmlChar *name, const xmlChar *content) {
2329 xmlNodePtr cur;
2330
2331 cur = xmlNewNodeEatName(ns, name);
2332 if (cur != NULL) {
2333 cur->doc = doc;
2334 if (content != NULL) {
2335 cur->children = xmlStringGetNodeList(doc, content);
2336 UPDATE_LAST_CHILD_AND_PARENT(cur)
2337 }
Daniel Veillard8f6c2b12008-04-03 11:17:21 +00002338 } else {
2339 /* if name don't come from the doc dictionnary free it here */
2340 if ((name != NULL) && (doc != NULL) &&
2341 (!(xmlDictOwns(doc->dict, name))))
2342 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002343 }
2344 return(cur);
2345}
2346
Daniel Veillard652327a2003-09-29 18:02:38 +00002347#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002348/**
2349 * xmlNewDocRawNode:
2350 * @doc: the document
2351 * @ns: namespace if any
2352 * @name: the node name
2353 * @content: the text content if any
2354 *
2355 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002356 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002357 *
2358 * Returns a pointer to the new node object.
2359 */
2360xmlNodePtr
2361xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2362 const xmlChar *name, const xmlChar *content) {
2363 xmlNodePtr cur;
2364
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002365 cur = xmlNewDocNode(doc, ns, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002366 if (cur != NULL) {
2367 cur->doc = doc;
2368 if (content != NULL) {
2369 cur->children = xmlNewDocText(doc, content);
2370 UPDATE_LAST_CHILD_AND_PARENT(cur)
2371 }
2372 }
2373 return(cur);
2374}
2375
2376/**
2377 * xmlNewDocFragment:
2378 * @doc: the document owning the fragment
2379 *
2380 * Creation of a new Fragment node.
2381 * Returns a pointer to the new node object.
2382 */
2383xmlNodePtr
2384xmlNewDocFragment(xmlDocPtr doc) {
2385 xmlNodePtr cur;
2386
2387 /*
2388 * Allocate a new DocumentFragment node and fill the fields.
2389 */
2390 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2391 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002392 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002393 return(NULL);
2394 }
2395 memset(cur, 0, sizeof(xmlNode));
2396 cur->type = XML_DOCUMENT_FRAG_NODE;
2397
2398 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002399
Daniel Veillarda880b122003-04-21 21:36:41 +00002400 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002401 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002402 return(cur);
2403}
Daniel Veillard652327a2003-09-29 18:02:38 +00002404#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002405
2406/**
2407 * xmlNewText:
2408 * @content: the text content
2409 *
2410 * Creation of a new text node.
2411 * Returns a pointer to the new node object.
2412 */
2413xmlNodePtr
2414xmlNewText(const xmlChar *content) {
2415 xmlNodePtr cur;
2416
2417 /*
2418 * Allocate a new node and fill the fields.
2419 */
2420 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2421 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002422 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002423 return(NULL);
2424 }
2425 memset(cur, 0, sizeof(xmlNode));
2426 cur->type = XML_TEXT_NODE;
2427
2428 cur->name = xmlStringText;
2429 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002430 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002431 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002432
Daniel Veillarda880b122003-04-21 21:36:41 +00002433 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002434 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002435 return(cur);
2436}
2437
Daniel Veillard652327a2003-09-29 18:02:38 +00002438#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002439/**
2440 * xmlNewTextChild:
2441 * @parent: the parent node
2442 * @ns: a namespace if any
2443 * @name: the name of the child
2444 * @content: the text content of the child if any.
2445 *
2446 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002447 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2448 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002449 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002450 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2451 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
Daniel Veillardaa6de472008-08-25 14:53:31 +00002452 * reserved XML chars that might appear in @content, such as the ampersand,
2453 * greater-than or less-than signs, are automatically replaced by their XML
2454 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002455 *
2456 * Returns a pointer to the new node object.
2457 */
2458xmlNodePtr
2459xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2460 const xmlChar *name, const xmlChar *content) {
2461 xmlNodePtr cur, prev;
2462
2463 if (parent == NULL) {
2464#ifdef DEBUG_TREE
2465 xmlGenericError(xmlGenericErrorContext,
2466 "xmlNewTextChild : parent == NULL\n");
2467#endif
2468 return(NULL);
2469 }
2470
2471 if (name == NULL) {
2472#ifdef DEBUG_TREE
2473 xmlGenericError(xmlGenericErrorContext,
2474 "xmlNewTextChild : name == NULL\n");
2475#endif
2476 return(NULL);
2477 }
2478
2479 /*
2480 * Allocate a new node
2481 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002482 if (parent->type == XML_ELEMENT_NODE) {
2483 if (ns == NULL)
2484 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2485 else
2486 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2487 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2488 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2489 if (ns == NULL)
2490 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2491 else
2492 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2493 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2494 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2495 } else {
2496 return(NULL);
2497 }
Owen Taylor3473f882001-02-23 17:55:21 +00002498 if (cur == NULL) return(NULL);
2499
2500 /*
2501 * add the new element at the end of the children list.
2502 */
2503 cur->type = XML_ELEMENT_NODE;
2504 cur->parent = parent;
2505 cur->doc = parent->doc;
2506 if (parent->children == NULL) {
2507 parent->children = cur;
2508 parent->last = cur;
2509 } else {
2510 prev = parent->last;
2511 prev->next = cur;
2512 cur->prev = prev;
2513 parent->last = cur;
2514 }
2515
2516 return(cur);
2517}
Daniel Veillard652327a2003-09-29 18:02:38 +00002518#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002519
2520/**
2521 * xmlNewCharRef:
2522 * @doc: the document
2523 * @name: the char ref string, starting with # or "&# ... ;"
2524 *
2525 * Creation of a new character reference node.
2526 * Returns a pointer to the new node object.
2527 */
2528xmlNodePtr
2529xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2530 xmlNodePtr cur;
2531
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002532 if (name == NULL)
2533 return(NULL);
2534
Owen Taylor3473f882001-02-23 17:55:21 +00002535 /*
2536 * Allocate a new node and fill the fields.
2537 */
2538 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2539 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002540 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002541 return(NULL);
2542 }
2543 memset(cur, 0, sizeof(xmlNode));
2544 cur->type = XML_ENTITY_REF_NODE;
2545
2546 cur->doc = doc;
2547 if (name[0] == '&') {
2548 int len;
2549 name++;
2550 len = xmlStrlen(name);
2551 if (name[len - 1] == ';')
2552 cur->name = xmlStrndup(name, len - 1);
2553 else
2554 cur->name = xmlStrndup(name, len);
2555 } else
2556 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002557
Daniel Veillarda880b122003-04-21 21:36:41 +00002558 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002559 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002560 return(cur);
2561}
2562
2563/**
2564 * xmlNewReference:
2565 * @doc: the document
2566 * @name: the reference name, or the reference string with & and ;
2567 *
2568 * Creation of a new reference node.
2569 * Returns a pointer to the new node object.
2570 */
2571xmlNodePtr
2572xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2573 xmlNodePtr cur;
2574 xmlEntityPtr ent;
2575
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002576 if (name == NULL)
2577 return(NULL);
2578
Owen Taylor3473f882001-02-23 17:55:21 +00002579 /*
2580 * Allocate a new node and fill the fields.
2581 */
2582 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2583 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002584 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002585 return(NULL);
2586 }
2587 memset(cur, 0, sizeof(xmlNode));
2588 cur->type = XML_ENTITY_REF_NODE;
2589
2590 cur->doc = doc;
2591 if (name[0] == '&') {
2592 int len;
2593 name++;
2594 len = xmlStrlen(name);
2595 if (name[len - 1] == ';')
2596 cur->name = xmlStrndup(name, len - 1);
2597 else
2598 cur->name = xmlStrndup(name, len);
2599 } else
2600 cur->name = xmlStrdup(name);
2601
2602 ent = xmlGetDocEntity(doc, cur->name);
2603 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002604 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002605 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002606 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002607 * updated. Not sure if this is 100% correct.
2608 * -George
2609 */
2610 cur->children = (xmlNodePtr) ent;
2611 cur->last = (xmlNodePtr) ent;
2612 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002613
Daniel Veillarda880b122003-04-21 21:36:41 +00002614 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002615 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002616 return(cur);
2617}
2618
2619/**
2620 * xmlNewDocText:
2621 * @doc: the document
2622 * @content: the text content
2623 *
2624 * Creation of a new text node within a document.
2625 * Returns a pointer to the new node object.
2626 */
2627xmlNodePtr
2628xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2629 xmlNodePtr cur;
2630
2631 cur = xmlNewText(content);
2632 if (cur != NULL) cur->doc = doc;
2633 return(cur);
2634}
2635
2636/**
2637 * xmlNewTextLen:
2638 * @content: the text content
2639 * @len: the text len.
2640 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002641 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002642 * Returns a pointer to the new node object.
2643 */
2644xmlNodePtr
2645xmlNewTextLen(const xmlChar *content, int len) {
2646 xmlNodePtr cur;
2647
2648 /*
2649 * Allocate a new node and fill the fields.
2650 */
2651 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2652 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002653 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002654 return(NULL);
2655 }
2656 memset(cur, 0, sizeof(xmlNode));
2657 cur->type = XML_TEXT_NODE;
2658
2659 cur->name = xmlStringText;
2660 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002661 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002662 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002663
Daniel Veillarda880b122003-04-21 21:36:41 +00002664 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002665 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002666 return(cur);
2667}
2668
2669/**
2670 * xmlNewDocTextLen:
2671 * @doc: the document
2672 * @content: the text content
2673 * @len: the text len.
2674 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002675 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002676 * text node pertain to a given document.
2677 * Returns a pointer to the new node object.
2678 */
2679xmlNodePtr
2680xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2681 xmlNodePtr cur;
2682
2683 cur = xmlNewTextLen(content, len);
2684 if (cur != NULL) cur->doc = doc;
2685 return(cur);
2686}
2687
2688/**
2689 * xmlNewComment:
2690 * @content: the comment content
2691 *
2692 * Creation of a new node containing a comment.
2693 * Returns a pointer to the new node object.
2694 */
2695xmlNodePtr
2696xmlNewComment(const xmlChar *content) {
2697 xmlNodePtr cur;
2698
2699 /*
2700 * Allocate a new node and fill the fields.
2701 */
2702 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2703 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002704 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002705 return(NULL);
2706 }
2707 memset(cur, 0, sizeof(xmlNode));
2708 cur->type = XML_COMMENT_NODE;
2709
2710 cur->name = xmlStringComment;
2711 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002712 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002713 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002714
Daniel Veillarda880b122003-04-21 21:36:41 +00002715 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002716 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002717 return(cur);
2718}
2719
2720/**
2721 * xmlNewCDataBlock:
2722 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002723 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002724 * @len: the length of the block
2725 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002726 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002727 * Returns a pointer to the new node object.
2728 */
2729xmlNodePtr
2730xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2731 xmlNodePtr cur;
2732
2733 /*
2734 * Allocate a new node and fill the fields.
2735 */
2736 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2737 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002738 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002739 return(NULL);
2740 }
2741 memset(cur, 0, sizeof(xmlNode));
2742 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002743 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002744
2745 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002746 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002747 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002748
Daniel Veillarda880b122003-04-21 21:36:41 +00002749 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002750 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002751 return(cur);
2752}
2753
2754/**
2755 * xmlNewDocComment:
2756 * @doc: the document
2757 * @content: the comment content
2758 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002759 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002760 * Returns a pointer to the new node object.
2761 */
2762xmlNodePtr
2763xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2764 xmlNodePtr cur;
2765
2766 cur = xmlNewComment(content);
2767 if (cur != NULL) cur->doc = doc;
2768 return(cur);
2769}
2770
2771/**
2772 * xmlSetTreeDoc:
2773 * @tree: the top element
2774 * @doc: the document
2775 *
2776 * update all nodes under the tree to point to the right document
2777 */
2778void
2779xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002780 xmlAttrPtr prop;
2781
Owen Taylor3473f882001-02-23 17:55:21 +00002782 if (tree == NULL)
2783 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002784 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002785 if(tree->type == XML_ELEMENT_NODE) {
2786 prop = tree->properties;
2787 while (prop != NULL) {
2788 prop->doc = doc;
2789 xmlSetListDoc(prop->children, doc);
2790 prop = prop->next;
2791 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002792 }
Owen Taylor3473f882001-02-23 17:55:21 +00002793 if (tree->children != NULL)
2794 xmlSetListDoc(tree->children, doc);
2795 tree->doc = doc;
2796 }
2797}
2798
2799/**
2800 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002801 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002802 * @doc: the document
2803 *
2804 * update all nodes in the list to point to the right document
2805 */
2806void
2807xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2808 xmlNodePtr cur;
2809
2810 if (list == NULL)
2811 return;
2812 cur = list;
2813 while (cur != NULL) {
2814 if (cur->doc != doc)
2815 xmlSetTreeDoc(cur, doc);
2816 cur = cur->next;
2817 }
2818}
2819
Daniel Veillard2156d432004-03-04 15:59:36 +00002820#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002821/**
2822 * xmlNewChild:
2823 * @parent: the parent node
2824 * @ns: a namespace if any
2825 * @name: the name of the child
2826 * @content: the XML content of the child if any.
2827 *
2828 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002829 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2830 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002831 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002832 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2833 * references. XML special chars must be escaped first by using
2834 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002835 *
2836 * Returns a pointer to the new node object.
2837 */
2838xmlNodePtr
2839xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2840 const xmlChar *name, const xmlChar *content) {
2841 xmlNodePtr cur, prev;
2842
2843 if (parent == NULL) {
2844#ifdef DEBUG_TREE
2845 xmlGenericError(xmlGenericErrorContext,
2846 "xmlNewChild : parent == NULL\n");
2847#endif
2848 return(NULL);
2849 }
2850
2851 if (name == NULL) {
2852#ifdef DEBUG_TREE
2853 xmlGenericError(xmlGenericErrorContext,
2854 "xmlNewChild : name == NULL\n");
2855#endif
2856 return(NULL);
2857 }
2858
2859 /*
2860 * Allocate a new node
2861 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002862 if (parent->type == XML_ELEMENT_NODE) {
2863 if (ns == NULL)
2864 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2865 else
2866 cur = xmlNewDocNode(parent->doc, ns, name, content);
2867 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2868 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2869 if (ns == NULL)
2870 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2871 else
2872 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002873 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2874 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002875 } else {
2876 return(NULL);
2877 }
Owen Taylor3473f882001-02-23 17:55:21 +00002878 if (cur == NULL) return(NULL);
2879
2880 /*
2881 * add the new element at the end of the children list.
2882 */
2883 cur->type = XML_ELEMENT_NODE;
2884 cur->parent = parent;
2885 cur->doc = parent->doc;
2886 if (parent->children == NULL) {
2887 parent->children = cur;
2888 parent->last = cur;
2889 } else {
2890 prev = parent->last;
2891 prev->next = cur;
2892 cur->prev = prev;
2893 parent->last = cur;
2894 }
2895
2896 return(cur);
2897}
Daniel Veillard652327a2003-09-29 18:02:38 +00002898#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002899
2900/**
Rob Richards65815122006-02-25 17:13:33 +00002901 * xmlAddPropSibling:
Daniel Veillardaa6de472008-08-25 14:53:31 +00002902 * @prev: the attribute to which @prop is added after
Rob Richards65815122006-02-25 17:13:33 +00002903 * @cur: the base attribute passed to calling function
2904 * @prop: the new attribute
2905 *
2906 * Add a new attribute after @prev using @cur as base attribute.
2907 * When inserting before @cur, @prev is passed as @cur->prev.
2908 * When inserting after @cur, @prev is passed as @cur.
Daniel Veillardaa6de472008-08-25 14:53:31 +00002909 * If an existing attribute is found it is detroyed prior to adding @prop.
Rob Richards65815122006-02-25 17:13:33 +00002910 *
2911 * Returns the attribute being inserted or NULL in case of error.
2912 */
2913static xmlNodePtr
2914xmlAddPropSibling(xmlNodePtr prev, xmlNodePtr cur, xmlNodePtr prop) {
2915 xmlAttrPtr attr;
2916
2917 if (cur->type != XML_ATTRIBUTE_NODE)
2918 return(NULL);
2919
2920 /* check if an attribute with the same name exists */
2921 if (prop->ns == NULL)
2922 attr = xmlHasNsProp(cur->parent, prop->name, NULL);
2923 else
2924 attr = xmlHasNsProp(cur->parent, prop->name, prop->ns->href);
2925
2926 if (prop->doc != cur->doc) {
2927 xmlSetTreeDoc(prop, cur->doc);
2928 }
2929 prop->parent = cur->parent;
2930 prop->prev = prev;
2931 if (prev != NULL) {
2932 prop->next = prev->next;
2933 prev->next = prop;
2934 if (prop->next)
2935 prop->next->prev = prop;
2936 } else {
2937 prop->next = cur;
2938 cur->prev = prop;
2939 }
2940 if (prop->prev == NULL && prop->parent != NULL)
2941 prop->parent->properties = (xmlAttrPtr) prop;
2942 if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) {
2943 /* different instance, destroy it (attributes must be unique) */
2944 xmlRemoveProp((xmlAttrPtr) attr);
2945 }
2946 return prop;
2947}
2948
2949/**
Owen Taylor3473f882001-02-23 17:55:21 +00002950 * xmlAddNextSibling:
2951 * @cur: the child node
2952 * @elem: the new node
2953 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002954 * Add a new node @elem as the next sibling of @cur
2955 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002956 * first unlinked from its existing context.
2957 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002958 * If the new node is ATTRIBUTE, it is added into properties instead of children.
Daniel Veillardaa6de472008-08-25 14:53:31 +00002959 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002960 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002961 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002962 */
2963xmlNodePtr
2964xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2965 if (cur == NULL) {
2966#ifdef DEBUG_TREE
2967 xmlGenericError(xmlGenericErrorContext,
2968 "xmlAddNextSibling : cur == NULL\n");
2969#endif
2970 return(NULL);
2971 }
2972 if (elem == NULL) {
2973#ifdef DEBUG_TREE
2974 xmlGenericError(xmlGenericErrorContext,
2975 "xmlAddNextSibling : elem == NULL\n");
2976#endif
2977 return(NULL);
2978 }
2979
Rob Richards19dc9612005-10-28 16:15:16 +00002980 if (cur == elem) {
2981#ifdef DEBUG_TREE
2982 xmlGenericError(xmlGenericErrorContext,
2983 "xmlAddNextSibling : cur == elem\n");
2984#endif
2985 return(NULL);
2986 }
2987
Owen Taylor3473f882001-02-23 17:55:21 +00002988 xmlUnlinkNode(elem);
2989
2990 if (elem->type == XML_TEXT_NODE) {
2991 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002992 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002993 xmlFreeNode(elem);
2994 return(cur);
2995 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002996 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2997 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002998 xmlChar *tmp;
2999
3000 tmp = xmlStrdup(elem->content);
3001 tmp = xmlStrcat(tmp, cur->next->content);
3002 xmlNodeSetContent(cur->next, tmp);
3003 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00003004 xmlFreeNode(elem);
3005 return(cur->next);
3006 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003007 } else if (elem->type == XML_ATTRIBUTE_NODE) {
Rob Richards65815122006-02-25 17:13:33 +00003008 return xmlAddPropSibling(cur, cur, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00003009 }
3010
3011 if (elem->doc != cur->doc) {
3012 xmlSetTreeDoc(elem, cur->doc);
3013 }
3014 elem->parent = cur->parent;
3015 elem->prev = cur;
3016 elem->next = cur->next;
3017 cur->next = elem;
3018 if (elem->next != NULL)
3019 elem->next->prev = elem;
Rob Richards65815122006-02-25 17:13:33 +00003020 if ((elem->parent != NULL) && (elem->parent->last == cur))
Owen Taylor3473f882001-02-23 17:55:21 +00003021 elem->parent->last = elem;
3022 return(elem);
3023}
3024
William M. Brack21e4ef22005-01-02 09:53:13 +00003025#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
3026 defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003027/**
3028 * xmlAddPrevSibling:
3029 * @cur: the child node
3030 * @elem: the new node
3031 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003032 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00003033 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003034 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003035 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003036 * If the new node is ATTRIBUTE, it is added into properties instead of children.
Daniel Veillardaa6de472008-08-25 14:53:31 +00003037 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00003038 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003039 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003040 */
3041xmlNodePtr
3042xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
3043 if (cur == NULL) {
3044#ifdef DEBUG_TREE
3045 xmlGenericError(xmlGenericErrorContext,
3046 "xmlAddPrevSibling : cur == NULL\n");
3047#endif
3048 return(NULL);
3049 }
3050 if (elem == NULL) {
3051#ifdef DEBUG_TREE
3052 xmlGenericError(xmlGenericErrorContext,
3053 "xmlAddPrevSibling : elem == NULL\n");
3054#endif
3055 return(NULL);
3056 }
3057
Rob Richards19dc9612005-10-28 16:15:16 +00003058 if (cur == elem) {
3059#ifdef DEBUG_TREE
3060 xmlGenericError(xmlGenericErrorContext,
3061 "xmlAddPrevSibling : cur == elem\n");
3062#endif
3063 return(NULL);
3064 }
3065
Owen Taylor3473f882001-02-23 17:55:21 +00003066 xmlUnlinkNode(elem);
3067
3068 if (elem->type == XML_TEXT_NODE) {
3069 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00003070 xmlChar *tmp;
3071
3072 tmp = xmlStrdup(elem->content);
3073 tmp = xmlStrcat(tmp, cur->content);
3074 xmlNodeSetContent(cur, tmp);
3075 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00003076 xmlFreeNode(elem);
3077 return(cur);
3078 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00003079 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
3080 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003081 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003082 xmlFreeNode(elem);
3083 return(cur->prev);
3084 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003085 } else if (elem->type == XML_ATTRIBUTE_NODE) {
Rob Richards65815122006-02-25 17:13:33 +00003086 return xmlAddPropSibling(cur->prev, cur, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00003087 }
3088
3089 if (elem->doc != cur->doc) {
3090 xmlSetTreeDoc(elem, cur->doc);
3091 }
3092 elem->parent = cur->parent;
3093 elem->next = cur;
3094 elem->prev = cur->prev;
3095 cur->prev = elem;
3096 if (elem->prev != NULL)
3097 elem->prev->next = elem;
Rob Richards65815122006-02-25 17:13:33 +00003098 if ((elem->parent != NULL) && (elem->parent->children == cur)) {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003099 elem->parent->children = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003100 }
Owen Taylor3473f882001-02-23 17:55:21 +00003101 return(elem);
3102}
Daniel Veillard652327a2003-09-29 18:02:38 +00003103#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003104
3105/**
3106 * xmlAddSibling:
3107 * @cur: the child node
3108 * @elem: the new node
3109 *
3110 * Add a new element @elem to the list of siblings of @cur
3111 * merging adjacent TEXT nodes (@elem may be freed)
3112 * If the new element was already inserted in a document it is
3113 * first unlinked from its existing context.
3114 *
3115 * Returns the new element or NULL in case of error.
3116 */
3117xmlNodePtr
3118xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
3119 xmlNodePtr parent;
3120
3121 if (cur == NULL) {
3122#ifdef DEBUG_TREE
3123 xmlGenericError(xmlGenericErrorContext,
3124 "xmlAddSibling : cur == NULL\n");
3125#endif
3126 return(NULL);
3127 }
3128
3129 if (elem == NULL) {
3130#ifdef DEBUG_TREE
3131 xmlGenericError(xmlGenericErrorContext,
3132 "xmlAddSibling : elem == NULL\n");
3133#endif
3134 return(NULL);
3135 }
3136
Daniel Veillard43bc89c2009-03-23 19:32:04 +00003137 if (cur == elem) {
3138#ifdef DEBUG_TREE
3139 xmlGenericError(xmlGenericErrorContext,
3140 "xmlAddSibling : cur == elem\n");
3141#endif
3142 return(NULL);
3143 }
3144
Owen Taylor3473f882001-02-23 17:55:21 +00003145 /*
3146 * Constant time is we can rely on the ->parent->last to find
3147 * the last sibling.
3148 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00003149 if ((cur->type != XML_ATTRIBUTE_NODE) && (cur->parent != NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00003150 (cur->parent->children != NULL) &&
3151 (cur->parent->last != NULL) &&
3152 (cur->parent->last->next == NULL)) {
3153 cur = cur->parent->last;
3154 } else {
3155 while (cur->next != NULL) cur = cur->next;
3156 }
3157
3158 xmlUnlinkNode(elem);
3159
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003160 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3161 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003162 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003163 xmlFreeNode(elem);
3164 return(cur);
Rob Richards65815122006-02-25 17:13:33 +00003165 } else if (elem->type == XML_ATTRIBUTE_NODE) {
3166 return xmlAddPropSibling(cur, cur, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00003167 }
3168
3169 if (elem->doc != cur->doc) {
3170 xmlSetTreeDoc(elem, cur->doc);
3171 }
3172 parent = cur->parent;
3173 elem->prev = cur;
3174 elem->next = NULL;
3175 elem->parent = parent;
3176 cur->next = elem;
3177 if (parent != NULL)
3178 parent->last = elem;
3179
3180 return(elem);
3181}
3182
3183/**
3184 * xmlAddChildList:
3185 * @parent: the parent node
3186 * @cur: the first node in the list
3187 *
3188 * Add a list of node at the end of the child list of the parent
3189 * merging adjacent TEXT nodes (@cur may be freed)
3190 *
3191 * Returns the last child or NULL in case of error.
3192 */
3193xmlNodePtr
3194xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3195 xmlNodePtr prev;
3196
3197 if (parent == NULL) {
3198#ifdef DEBUG_TREE
3199 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003200 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003201#endif
3202 return(NULL);
3203 }
3204
3205 if (cur == NULL) {
3206#ifdef DEBUG_TREE
3207 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003208 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003209#endif
3210 return(NULL);
3211 }
3212
3213 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3214 (cur->doc != parent->doc)) {
3215#ifdef DEBUG_TREE
3216 xmlGenericError(xmlGenericErrorContext,
3217 "Elements moved to a different document\n");
3218#endif
3219 }
3220
3221 /*
3222 * add the first element at the end of the children list.
3223 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003224
Owen Taylor3473f882001-02-23 17:55:21 +00003225 if (parent->children == NULL) {
3226 parent->children = cur;
3227 } else {
3228 /*
3229 * If cur and parent->last both are TEXT nodes, then merge them.
3230 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00003231 if ((cur->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00003232 (parent->last->type == XML_TEXT_NODE) &&
3233 (cur->name == parent->last->name)) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00003234 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003235 /*
3236 * if it's the only child, nothing more to be done.
3237 */
3238 if (cur->next == NULL) {
3239 xmlFreeNode(cur);
3240 return(parent->last);
3241 }
3242 prev = cur;
3243 cur = cur->next;
3244 xmlFreeNode(prev);
3245 }
3246 prev = parent->last;
3247 prev->next = cur;
3248 cur->prev = prev;
3249 }
3250 while (cur->next != NULL) {
3251 cur->parent = parent;
3252 if (cur->doc != parent->doc) {
3253 xmlSetTreeDoc(cur, parent->doc);
3254 }
3255 cur = cur->next;
3256 }
3257 cur->parent = parent;
Rob Richards810a78b2008-12-31 22:13:57 +00003258 /* the parent may not be linked to a doc ! */
3259 if (cur->doc != parent->doc) {
3260 xmlSetTreeDoc(cur, parent->doc);
3261 }
Owen Taylor3473f882001-02-23 17:55:21 +00003262 parent->last = cur;
3263
3264 return(cur);
3265}
3266
3267/**
3268 * xmlAddChild:
3269 * @parent: the parent node
3270 * @cur: the child node
3271 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003272 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003273 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003274 * If the new node is ATTRIBUTE, it is added into properties instead of children.
Daniel Veillardaa6de472008-08-25 14:53:31 +00003275 * If there is an attribute with equal name, it is first destroyed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003276 *
Owen Taylor3473f882001-02-23 17:55:21 +00003277 * Returns the child or NULL in case of error.
3278 */
3279xmlNodePtr
3280xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3281 xmlNodePtr prev;
3282
3283 if (parent == NULL) {
3284#ifdef DEBUG_TREE
3285 xmlGenericError(xmlGenericErrorContext,
3286 "xmlAddChild : parent == NULL\n");
3287#endif
3288 return(NULL);
3289 }
3290
3291 if (cur == NULL) {
3292#ifdef DEBUG_TREE
3293 xmlGenericError(xmlGenericErrorContext,
3294 "xmlAddChild : child == NULL\n");
3295#endif
3296 return(NULL);
3297 }
3298
Rob Richards19dc9612005-10-28 16:15:16 +00003299 if (parent == cur) {
3300#ifdef DEBUG_TREE
3301 xmlGenericError(xmlGenericErrorContext,
3302 "xmlAddChild : parent == cur\n");
3303#endif
3304 return(NULL);
3305 }
Owen Taylor3473f882001-02-23 17:55:21 +00003306 /*
3307 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003308 * cur is then freed.
3309 */
3310 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003311 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003312 (parent->content != NULL) &&
Rob Richards19dc9612005-10-28 16:15:16 +00003313 (parent->name == cur->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003314 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003315 xmlFreeNode(cur);
3316 return(parent);
3317 }
3318 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003319 (parent->last->name == cur->name) &&
3320 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003321 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003322 xmlFreeNode(cur);
3323 return(parent->last);
3324 }
3325 }
3326
3327 /*
3328 * add the new element at the end of the children list.
3329 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003330 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003331 cur->parent = parent;
3332 if (cur->doc != parent->doc) {
3333 xmlSetTreeDoc(cur, parent->doc);
3334 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003335 /* this check prevents a loop on tree-traversions if a developer
3336 * tries to add a node to its parent multiple times
3337 */
3338 if (prev == parent)
3339 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003340
3341 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003342 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003343 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003344 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003345 (parent->content != NULL) &&
3346 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003347 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003348 xmlFreeNode(cur);
3349 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003350 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003351 if (cur->type == XML_ATTRIBUTE_NODE) {
Rob Richards19dc9612005-10-28 16:15:16 +00003352 if (parent->type != XML_ELEMENT_NODE)
3353 return(NULL);
Rob Richards810a78b2008-12-31 22:13:57 +00003354 if (parent->properties != NULL) {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003355 /* check if an attribute with the same name exists */
3356 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003357
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003358 if (cur->ns == NULL)
Rob Richardsc342ec62005-10-25 00:10:12 +00003359 lastattr = xmlHasNsProp(parent, cur->name, NULL);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003360 else
3361 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
Rob Richardsc342ec62005-10-25 00:10:12 +00003362 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur) && (lastattr->type != XML_ATTRIBUTE_DECL)) {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003363 /* different instance, destroy it (attributes must be unique) */
Rob Richards19dc9612005-10-28 16:15:16 +00003364 xmlUnlinkNode((xmlNodePtr) lastattr);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003365 xmlFreeProp(lastattr);
3366 }
Rob Richards19dc9612005-10-28 16:15:16 +00003367 if (lastattr == (xmlAttrPtr) cur)
3368 return(cur);
Rob Richards810a78b2008-12-31 22:13:57 +00003369
3370 }
3371 if (parent->properties == NULL) {
3372 parent->properties = (xmlAttrPtr) cur;
3373 } else {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003374 /* find the end */
Rob Richards810a78b2008-12-31 22:13:57 +00003375 xmlAttrPtr lastattr = parent->properties;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003376 while (lastattr->next != NULL) {
3377 lastattr = lastattr->next;
3378 }
3379 lastattr->next = (xmlAttrPtr) cur;
3380 ((xmlAttrPtr) cur)->prev = lastattr;
3381 }
3382 } else {
3383 if (parent->children == NULL) {
3384 parent->children = cur;
3385 parent->last = cur;
3386 } else {
3387 prev = parent->last;
3388 prev->next = cur;
3389 cur->prev = prev;
3390 parent->last = cur;
3391 }
3392 }
Owen Taylor3473f882001-02-23 17:55:21 +00003393 return(cur);
3394}
3395
3396/**
3397 * xmlGetLastChild:
3398 * @parent: the parent node
3399 *
3400 * Search the last child of a node.
3401 * Returns the last child or NULL if none.
3402 */
3403xmlNodePtr
3404xmlGetLastChild(xmlNodePtr parent) {
3405 if (parent == NULL) {
3406#ifdef DEBUG_TREE
3407 xmlGenericError(xmlGenericErrorContext,
3408 "xmlGetLastChild : parent == NULL\n");
3409#endif
3410 return(NULL);
3411 }
3412 return(parent->last);
3413}
3414
Daniel Veillardbe2bd6a2008-11-27 15:26:28 +00003415#ifdef LIBXML_TREE_ENABLED
3416/*
3417 * 5 interfaces from DOM ElementTraversal
3418 */
3419
3420/**
3421 * xmlChildElementCount:
3422 * @parent: the parent node
3423 *
3424 * Finds the current number of child nodes of that element which are
3425 * element nodes.
3426 * Note the handling of entities references is different than in
3427 * the W3C DOM element traversal spec since we don't have back reference
3428 * from entities content to entities references.
3429 *
3430 * Returns the count of element child or 0 if not available
3431 */
3432unsigned long
3433xmlChildElementCount(xmlNodePtr parent) {
3434 unsigned long ret = 0;
3435 xmlNodePtr cur = NULL;
3436
3437 if (parent == NULL)
3438 return(0);
3439 switch (parent->type) {
3440 case XML_ELEMENT_NODE:
3441 case XML_ENTITY_NODE:
3442 case XML_DOCUMENT_NODE:
3443 case XML_HTML_DOCUMENT_NODE:
3444 cur = parent->children;
3445 break;
3446 default:
3447 return(0);
3448 }
3449 while (cur != NULL) {
3450 if (cur->type == XML_ELEMENT_NODE)
3451 ret++;
3452 cur = cur->next;
3453 }
3454 return(ret);
3455}
3456
3457/**
3458 * xmlFirstElementChild:
3459 * @parent: the parent node
3460 *
3461 * Finds the first child node of that element which is a Element node
3462 * Note the handling of entities references is different than in
3463 * the W3C DOM element traversal spec since we don't have back reference
3464 * from entities content to entities references.
3465 *
3466 * Returns the first element child or NULL if not available
3467 */
3468xmlNodePtr
3469xmlFirstElementChild(xmlNodePtr parent) {
3470 xmlNodePtr cur = NULL;
3471
3472 if (parent == NULL)
3473 return(NULL);
3474 switch (parent->type) {
3475 case XML_ELEMENT_NODE:
3476 case XML_ENTITY_NODE:
3477 case XML_DOCUMENT_NODE:
3478 case XML_HTML_DOCUMENT_NODE:
3479 cur = parent->children;
3480 break;
3481 default:
3482 return(NULL);
3483 }
3484 while (cur != NULL) {
3485 if (cur->type == XML_ELEMENT_NODE)
3486 return(cur);
3487 cur = cur->next;
3488 }
3489 return(NULL);
3490}
3491
3492/**
3493 * xmlLastElementChild:
3494 * @parent: the parent node
3495 *
3496 * Finds the last child node of that element which is a Element node
3497 * Note the handling of entities references is different than in
3498 * the W3C DOM element traversal spec since we don't have back reference
3499 * from entities content to entities references.
3500 *
3501 * Returns the last element child or NULL if not available
3502 */
3503xmlNodePtr
3504xmlLastElementChild(xmlNodePtr parent) {
3505 xmlNodePtr cur = NULL;
3506
3507 if (parent == NULL)
3508 return(NULL);
3509 switch (parent->type) {
3510 case XML_ELEMENT_NODE:
3511 case XML_ENTITY_NODE:
3512 case XML_DOCUMENT_NODE:
3513 case XML_HTML_DOCUMENT_NODE:
3514 cur = parent->last;
3515 break;
3516 default:
3517 return(NULL);
3518 }
3519 while (cur != NULL) {
3520 if (cur->type == XML_ELEMENT_NODE)
3521 return(cur);
3522 cur = cur->prev;
3523 }
3524 return(NULL);
3525}
3526
3527/**
3528 * xmlPreviousElementSibling:
3529 * @node: the current node
3530 *
3531 * Finds the first closest previous sibling of the node which is an
3532 * element node.
3533 * Note the handling of entities references is different than in
3534 * the W3C DOM element traversal spec since we don't have back reference
3535 * from entities content to entities references.
3536 *
3537 * Returns the previous element sibling or NULL if not available
3538 */
3539xmlNodePtr
3540xmlPreviousElementSibling(xmlNodePtr node) {
3541 if (node == NULL)
3542 return(NULL);
3543 switch (node->type) {
3544 case XML_ELEMENT_NODE:
3545 case XML_TEXT_NODE:
3546 case XML_CDATA_SECTION_NODE:
3547 case XML_ENTITY_REF_NODE:
3548 case XML_ENTITY_NODE:
3549 case XML_PI_NODE:
3550 case XML_COMMENT_NODE:
3551 case XML_XINCLUDE_START:
3552 case XML_XINCLUDE_END:
3553 node = node->prev;
3554 break;
3555 default:
3556 return(NULL);
3557 }
3558 while (node != NULL) {
3559 if (node->type == XML_ELEMENT_NODE)
3560 return(node);
François Delyon2f700902010-02-03 17:32:37 +01003561 node = node->prev;
Daniel Veillardbe2bd6a2008-11-27 15:26:28 +00003562 }
3563 return(NULL);
3564}
3565
3566/**
3567 * xmlNextElementSibling:
3568 * @node: the current node
3569 *
3570 * Finds the first closest next sibling of the node which is an
3571 * element node.
3572 * Note the handling of entities references is different than in
3573 * the W3C DOM element traversal spec since we don't have back reference
3574 * from entities content to entities references.
3575 *
3576 * Returns the next element sibling or NULL if not available
3577 */
3578xmlNodePtr
3579xmlNextElementSibling(xmlNodePtr node) {
3580 if (node == NULL)
3581 return(NULL);
3582 switch (node->type) {
3583 case XML_ELEMENT_NODE:
3584 case XML_TEXT_NODE:
3585 case XML_CDATA_SECTION_NODE:
3586 case XML_ENTITY_REF_NODE:
3587 case XML_ENTITY_NODE:
3588 case XML_PI_NODE:
3589 case XML_COMMENT_NODE:
3590 case XML_DTD_NODE:
3591 case XML_XINCLUDE_START:
3592 case XML_XINCLUDE_END:
3593 node = node->next;
3594 break;
3595 default:
3596 return(NULL);
3597 }
3598 while (node != NULL) {
3599 if (node->type == XML_ELEMENT_NODE)
3600 return(node);
3601 node = node->next;
3602 }
3603 return(NULL);
3604}
3605
3606#endif /* LIBXML_TREE_ENABLED */
3607
Owen Taylor3473f882001-02-23 17:55:21 +00003608/**
3609 * xmlFreeNodeList:
3610 * @cur: the first node in the list
3611 *
3612 * Free a node and all its siblings, this is a recursive behaviour, all
3613 * the children are freed too.
3614 */
3615void
3616xmlFreeNodeList(xmlNodePtr cur) {
3617 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003618 xmlDictPtr dict = NULL;
3619
3620 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003621 if (cur->type == XML_NAMESPACE_DECL) {
3622 xmlFreeNsList((xmlNsPtr) cur);
3623 return;
3624 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003625 if ((cur->type == XML_DOCUMENT_NODE) ||
3626#ifdef LIBXML_DOCB_ENABLED
3627 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003628#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003629 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003630 xmlFreeDoc((xmlDocPtr) cur);
3631 return;
3632 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003633 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003634 while (cur != NULL) {
3635 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003636 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003637
Daniel Veillarda880b122003-04-21 21:36:41 +00003638 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003639 xmlDeregisterNodeDefaultValue(cur);
3640
Daniel Veillard02141ea2001-04-30 11:46:40 +00003641 if ((cur->children != NULL) &&
3642 (cur->type != XML_ENTITY_REF_NODE))
3643 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003644 if (((cur->type == XML_ELEMENT_NODE) ||
3645 (cur->type == XML_XINCLUDE_START) ||
3646 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003647 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003648 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003649 if ((cur->type != XML_ELEMENT_NODE) &&
3650 (cur->type != XML_XINCLUDE_START) &&
3651 (cur->type != XML_XINCLUDE_END) &&
Daniel Veillard8874b942005-08-25 13:19:21 +00003652 (cur->type != XML_ENTITY_REF_NODE) &&
3653 (cur->content != (xmlChar *) &(cur->properties))) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003654 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003655 }
3656 if (((cur->type == XML_ELEMENT_NODE) ||
3657 (cur->type == XML_XINCLUDE_START) ||
3658 (cur->type == XML_XINCLUDE_END)) &&
3659 (cur->nsDef != NULL))
3660 xmlFreeNsList(cur->nsDef);
3661
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003662 /*
3663 * When a node is a text node or a comment, it uses a global static
3664 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003665 * Otherwise the node name might come from the document's
3666 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003667 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003668 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003669 (cur->type != XML_TEXT_NODE) &&
3670 (cur->type != XML_COMMENT_NODE))
3671 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003672 xmlFree(cur);
3673 }
Owen Taylor3473f882001-02-23 17:55:21 +00003674 cur = next;
3675 }
3676}
3677
3678/**
3679 * xmlFreeNode:
3680 * @cur: the node
3681 *
3682 * Free a node, this is a recursive behaviour, all the children are freed too.
3683 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3684 */
3685void
3686xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003687 xmlDictPtr dict = NULL;
3688
3689 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003690
Daniel Veillard02141ea2001-04-30 11:46:40 +00003691 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003692 if (cur->type == XML_DTD_NODE) {
3693 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003694 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003695 }
3696 if (cur->type == XML_NAMESPACE_DECL) {
3697 xmlFreeNs((xmlNsPtr) cur);
3698 return;
3699 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003700 if (cur->type == XML_ATTRIBUTE_NODE) {
3701 xmlFreeProp((xmlAttrPtr) cur);
3702 return;
3703 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003704
Daniel Veillarda880b122003-04-21 21:36:41 +00003705 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003706 xmlDeregisterNodeDefaultValue(cur);
3707
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003708 if (cur->doc != NULL) dict = cur->doc->dict;
3709
Daniel Veillard2cba4152008-08-27 11:45:41 +00003710 if (cur->type == XML_ENTITY_DECL) {
3711 xmlEntityPtr ent = (xmlEntityPtr) cur;
3712 DICT_FREE(ent->SystemID);
3713 DICT_FREE(ent->ExternalID);
3714 }
Owen Taylor3473f882001-02-23 17:55:21 +00003715 if ((cur->children != NULL) &&
3716 (cur->type != XML_ENTITY_REF_NODE))
3717 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003718 if (((cur->type == XML_ELEMENT_NODE) ||
3719 (cur->type == XML_XINCLUDE_START) ||
3720 (cur->type == XML_XINCLUDE_END)) &&
3721 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003722 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003723 if ((cur->type != XML_ELEMENT_NODE) &&
3724 (cur->content != NULL) &&
3725 (cur->type != XML_ENTITY_REF_NODE) &&
3726 (cur->type != XML_XINCLUDE_END) &&
Daniel Veillard8874b942005-08-25 13:19:21 +00003727 (cur->type != XML_XINCLUDE_START) &&
3728 (cur->content != (xmlChar *) &(cur->properties))) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003729 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003730 }
3731
Daniel Veillardacd370f2001-06-09 17:17:51 +00003732 /*
3733 * When a node is a text node or a comment, it uses a global static
3734 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003735 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003736 */
Owen Taylor3473f882001-02-23 17:55:21 +00003737 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003738 (cur->type != XML_TEXT_NODE) &&
3739 (cur->type != XML_COMMENT_NODE))
3740 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003741
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003742 if (((cur->type == XML_ELEMENT_NODE) ||
3743 (cur->type == XML_XINCLUDE_START) ||
3744 (cur->type == XML_XINCLUDE_END)) &&
3745 (cur->nsDef != NULL))
3746 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003747 xmlFree(cur);
3748}
3749
3750/**
3751 * xmlUnlinkNode:
3752 * @cur: the node
3753 *
3754 * Unlink a node from it's current context, the node is not freed
Daniel Veillard39d027c2012-05-11 12:38:23 +08003755 * If one need to free the node, use xmlFreeNode() routine after the
3756 * unlink to discard it.
Owen Taylor3473f882001-02-23 17:55:21 +00003757 */
3758void
3759xmlUnlinkNode(xmlNodePtr cur) {
3760 if (cur == NULL) {
3761#ifdef DEBUG_TREE
3762 xmlGenericError(xmlGenericErrorContext,
3763 "xmlUnlinkNode : node == NULL\n");
3764#endif
3765 return;
3766 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003767 if (cur->type == XML_DTD_NODE) {
3768 xmlDocPtr doc;
3769 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003770 if (doc != NULL) {
3771 if (doc->intSubset == (xmlDtdPtr) cur)
3772 doc->intSubset = NULL;
3773 if (doc->extSubset == (xmlDtdPtr) cur)
3774 doc->extSubset = NULL;
3775 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003776 }
Daniel Veillard2cba4152008-08-27 11:45:41 +00003777 if (cur->type == XML_ENTITY_DECL) {
3778 xmlDocPtr doc;
3779 doc = cur->doc;
3780 if (doc != NULL) {
3781 if (doc->intSubset != NULL) {
3782 if (xmlHashLookup(doc->intSubset->entities, cur->name) == cur)
3783 xmlHashRemoveEntry(doc->intSubset->entities, cur->name,
3784 NULL);
3785 if (xmlHashLookup(doc->intSubset->pentities, cur->name) == cur)
3786 xmlHashRemoveEntry(doc->intSubset->pentities, cur->name,
3787 NULL);
3788 }
3789 if (doc->extSubset != NULL) {
3790 if (xmlHashLookup(doc->extSubset->entities, cur->name) == cur)
3791 xmlHashRemoveEntry(doc->extSubset->entities, cur->name,
3792 NULL);
3793 if (xmlHashLookup(doc->extSubset->pentities, cur->name) == cur)
3794 xmlHashRemoveEntry(doc->extSubset->pentities, cur->name,
3795 NULL);
3796 }
3797 }
3798 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003799 if (cur->parent != NULL) {
3800 xmlNodePtr parent;
3801 parent = cur->parent;
3802 if (cur->type == XML_ATTRIBUTE_NODE) {
3803 if (parent->properties == (xmlAttrPtr) cur)
3804 parent->properties = ((xmlAttrPtr) cur)->next;
3805 } else {
3806 if (parent->children == cur)
3807 parent->children = cur->next;
3808 if (parent->last == cur)
3809 parent->last = cur->prev;
3810 }
3811 cur->parent = NULL;
3812 }
Owen Taylor3473f882001-02-23 17:55:21 +00003813 if (cur->next != NULL)
3814 cur->next->prev = cur->prev;
3815 if (cur->prev != NULL)
3816 cur->prev->next = cur->next;
3817 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003818}
3819
Daniel Veillard2156d432004-03-04 15:59:36 +00003820#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003821/**
3822 * xmlReplaceNode:
3823 * @old: the old node
3824 * @cur: the node
3825 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003826 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003827 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003828 * first unlinked from its existing context.
3829 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003830 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003831 */
3832xmlNodePtr
3833xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00003834 if (old == cur) return(NULL);
Daniel Veillarda03e3652004-11-02 18:45:30 +00003835 if ((old == NULL) || (old->parent == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003836#ifdef DEBUG_TREE
3837 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda03e3652004-11-02 18:45:30 +00003838 "xmlReplaceNode : old == NULL or without parent\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003839#endif
3840 return(NULL);
3841 }
3842 if (cur == NULL) {
3843 xmlUnlinkNode(old);
3844 return(old);
3845 }
3846 if (cur == old) {
3847 return(old);
3848 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003849 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3850#ifdef DEBUG_TREE
3851 xmlGenericError(xmlGenericErrorContext,
3852 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3853#endif
3854 return(old);
3855 }
3856 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3857#ifdef DEBUG_TREE
3858 xmlGenericError(xmlGenericErrorContext,
3859 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3860#endif
3861 return(old);
3862 }
Owen Taylor3473f882001-02-23 17:55:21 +00003863 xmlUnlinkNode(cur);
Daniel Veillard64d7d122005-05-11 18:03:42 +00003864 xmlSetTreeDoc(cur, old->doc);
Owen Taylor3473f882001-02-23 17:55:21 +00003865 cur->parent = old->parent;
3866 cur->next = old->next;
3867 if (cur->next != NULL)
3868 cur->next->prev = cur;
3869 cur->prev = old->prev;
3870 if (cur->prev != NULL)
3871 cur->prev->next = cur;
3872 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003873 if (cur->type == XML_ATTRIBUTE_NODE) {
3874 if (cur->parent->properties == (xmlAttrPtr)old)
3875 cur->parent->properties = ((xmlAttrPtr) cur);
3876 } else {
3877 if (cur->parent->children == old)
3878 cur->parent->children = cur;
3879 if (cur->parent->last == old)
3880 cur->parent->last = cur;
3881 }
Owen Taylor3473f882001-02-23 17:55:21 +00003882 }
3883 old->next = old->prev = NULL;
3884 old->parent = NULL;
3885 return(old);
3886}
Daniel Veillard652327a2003-09-29 18:02:38 +00003887#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003888
3889/************************************************************************
3890 * *
3891 * Copy operations *
3892 * *
3893 ************************************************************************/
Daniel Veillardaa6de472008-08-25 14:53:31 +00003894
Owen Taylor3473f882001-02-23 17:55:21 +00003895/**
3896 * xmlCopyNamespace:
3897 * @cur: the namespace
3898 *
3899 * Do a copy of the namespace.
3900 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003901 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003902 */
3903xmlNsPtr
3904xmlCopyNamespace(xmlNsPtr cur) {
3905 xmlNsPtr ret;
3906
3907 if (cur == NULL) return(NULL);
3908 switch (cur->type) {
3909 case XML_LOCAL_NAMESPACE:
3910 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3911 break;
3912 default:
3913#ifdef DEBUG_TREE
3914 xmlGenericError(xmlGenericErrorContext,
3915 "xmlCopyNamespace: invalid type %d\n", cur->type);
3916#endif
3917 return(NULL);
3918 }
3919 return(ret);
3920}
3921
3922/**
3923 * xmlCopyNamespaceList:
3924 * @cur: the first namespace
3925 *
3926 * Do a copy of an namespace list.
3927 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003928 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003929 */
3930xmlNsPtr
3931xmlCopyNamespaceList(xmlNsPtr cur) {
3932 xmlNsPtr ret = NULL;
3933 xmlNsPtr p = NULL,q;
3934
3935 while (cur != NULL) {
3936 q = xmlCopyNamespace(cur);
3937 if (p == NULL) {
3938 ret = p = q;
3939 } else {
3940 p->next = q;
3941 p = q;
3942 }
3943 cur = cur->next;
3944 }
3945 return(ret);
3946}
3947
3948static xmlNodePtr
3949xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
Rob Richards19dc9612005-10-28 16:15:16 +00003950
3951static xmlAttrPtr
3952xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003953 xmlAttrPtr ret;
3954
3955 if (cur == NULL) return(NULL);
3956 if (target != NULL)
3957 ret = xmlNewDocProp(target->doc, cur->name, NULL);
Rob Richards19dc9612005-10-28 16:15:16 +00003958 else if (doc != NULL)
3959 ret = xmlNewDocProp(doc, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003960 else if (cur->parent != NULL)
3961 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3962 else if (cur->children != NULL)
3963 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3964 else
3965 ret = xmlNewDocProp(NULL, cur->name, NULL);
3966 if (ret == NULL) return(NULL);
3967 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003968
Owen Taylor3473f882001-02-23 17:55:21 +00003969 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003970 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003971
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003972 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3973 if (ns == NULL) {
3974 /*
3975 * Humm, we are copying an element whose namespace is defined
3976 * out of the new tree scope. Search it in the original tree
3977 * and add it at the top of the new tree
3978 */
3979 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3980 if (ns != NULL) {
3981 xmlNodePtr root = target;
3982 xmlNodePtr pred = NULL;
3983
3984 while (root->parent != NULL) {
3985 pred = root;
3986 root = root->parent;
3987 }
3988 if (root == (xmlNodePtr) target->doc) {
3989 /* correct possibly cycling above the document elt */
3990 root = pred;
3991 }
3992 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3993 }
3994 } else {
3995 /*
3996 * we have to find something appropriate here since
3997 * we cant be sure, that the namespce we found is identified
3998 * by the prefix
3999 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004000 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00004001 /* this is the nice case */
4002 ret->ns = ns;
4003 } else {
4004 /*
4005 * we are in trouble: we need a new reconcilied namespace.
4006 * This is expensive
4007 */
4008 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
4009 }
4010 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00004011
Owen Taylor3473f882001-02-23 17:55:21 +00004012 } else
4013 ret->ns = NULL;
4014
4015 if (cur->children != NULL) {
4016 xmlNodePtr tmp;
4017
4018 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
4019 ret->last = NULL;
4020 tmp = ret->children;
4021 while (tmp != NULL) {
4022 /* tmp->parent = (xmlNodePtr)ret; */
4023 if (tmp->next == NULL)
4024 ret->last = tmp;
4025 tmp = tmp->next;
4026 }
4027 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00004028 /*
4029 * Try to handle IDs
4030 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00004031 if ((target!= NULL) && (cur!= NULL) &&
4032 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00004033 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
4034 if (xmlIsID(cur->doc, cur->parent, cur)) {
4035 xmlChar *id;
4036
4037 id = xmlNodeListGetString(cur->doc, cur->children, 1);
4038 if (id != NULL) {
4039 xmlAddID(NULL, target->doc, id, ret);
4040 xmlFree(id);
4041 }
4042 }
4043 }
Owen Taylor3473f882001-02-23 17:55:21 +00004044 return(ret);
4045}
4046
4047/**
Rob Richards19dc9612005-10-28 16:15:16 +00004048 * xmlCopyProp:
4049 * @target: the element where the attribute will be grafted
4050 * @cur: the attribute
4051 *
4052 * Do a copy of the attribute.
4053 *
4054 * Returns: a new #xmlAttrPtr, or NULL in case of error.
4055 */
4056xmlAttrPtr
4057xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
4058 return xmlCopyPropInternal(NULL, target, cur);
4059}
4060
4061/**
Owen Taylor3473f882001-02-23 17:55:21 +00004062 * xmlCopyPropList:
4063 * @target: the element where the attributes will be grafted
4064 * @cur: the first attribute
4065 *
4066 * Do a copy of an attribute list.
4067 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004068 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004069 */
4070xmlAttrPtr
4071xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
4072 xmlAttrPtr ret = NULL;
4073 xmlAttrPtr p = NULL,q;
4074
4075 while (cur != NULL) {
4076 q = xmlCopyProp(target, cur);
William M. Brack13dfa872004-09-18 04:52:08 +00004077 if (q == NULL)
4078 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004079 if (p == NULL) {
4080 ret = p = q;
4081 } else {
4082 p->next = q;
4083 q->prev = p;
4084 p = q;
4085 }
4086 cur = cur->next;
4087 }
4088 return(ret);
4089}
4090
4091/*
Daniel Veillardd1640922001-12-17 15:30:10 +00004092 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00004093 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004094 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00004095 * tricky reason: namespaces. Doing a direct copy of a node
4096 * say RPM:Copyright without changing the namespace pointer to
4097 * something else can produce stale links. One way to do it is
4098 * to keep a reference counter but this doesn't work as soon
4099 * as one move the element or the subtree out of the scope of
4100 * the existing namespace. The actual solution seems to add
4101 * a copy of the namespace at the top of the copied tree if
4102 * not available in the subtree.
4103 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00004104 * The argument "recursive" normally indicates a recursive copy
4105 * of the node with values 0 (no) and 1 (yes). For XInclude,
4106 * however, we allow a value of 2 to indicate copy properties and
4107 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00004108 */
4109
4110static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00004111xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00004112 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00004113 xmlNodePtr ret;
4114
4115 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00004116 switch (node->type) {
4117 case XML_TEXT_NODE:
4118 case XML_CDATA_SECTION_NODE:
4119 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00004120 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00004121 case XML_ENTITY_REF_NODE:
4122 case XML_ENTITY_NODE:
4123 case XML_PI_NODE:
4124 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00004125 case XML_XINCLUDE_START:
4126 case XML_XINCLUDE_END:
4127 break;
4128 case XML_ATTRIBUTE_NODE:
Rob Richards19dc9612005-10-28 16:15:16 +00004129 return((xmlNodePtr) xmlCopyPropInternal(doc, parent, (xmlAttrPtr) node));
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00004130 case XML_NAMESPACE_DECL:
4131 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
Daniel Veillardaa6de472008-08-25 14:53:31 +00004132
Daniel Veillard39196eb2001-06-19 18:09:42 +00004133 case XML_DOCUMENT_NODE:
4134 case XML_HTML_DOCUMENT_NODE:
4135#ifdef LIBXML_DOCB_ENABLED
4136 case XML_DOCB_DOCUMENT_NODE:
4137#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00004138#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00004139 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00004140#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00004141 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00004142 case XML_NOTATION_NODE:
4143 case XML_DTD_NODE:
4144 case XML_ELEMENT_DECL:
4145 case XML_ATTRIBUTE_DECL:
4146 case XML_ENTITY_DECL:
4147 return(NULL);
4148 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00004149
Owen Taylor3473f882001-02-23 17:55:21 +00004150 /*
4151 * Allocate a new node and fill the fields.
4152 */
4153 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
4154 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004155 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00004156 return(NULL);
4157 }
4158 memset(ret, 0, sizeof(xmlNode));
4159 ret->type = node->type;
4160
4161 ret->doc = doc;
Daniel Veillardaa6de472008-08-25 14:53:31 +00004162 ret->parent = parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004163 if (node->name == xmlStringText)
4164 ret->name = xmlStringText;
4165 else if (node->name == xmlStringTextNoenc)
4166 ret->name = xmlStringTextNoenc;
4167 else if (node->name == xmlStringComment)
4168 ret->name = xmlStringComment;
Daniel Veillard03a53c32004-10-26 16:06:51 +00004169 else if (node->name != NULL) {
4170 if ((doc != NULL) && (doc->dict != NULL))
4171 ret->name = xmlDictLookup(doc->dict, node->name, -1);
4172 else
4173 ret->name = xmlStrdup(node->name);
4174 }
Daniel Veillard7db37732001-07-12 01:20:08 +00004175 if ((node->type != XML_ELEMENT_NODE) &&
4176 (node->content != NULL) &&
4177 (node->type != XML_ENTITY_REF_NODE) &&
4178 (node->type != XML_XINCLUDE_END) &&
4179 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004180 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00004181 }else{
4182 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004183 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00004184 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004185 if (parent != NULL) {
4186 xmlNodePtr tmp;
4187
Daniel Veillard8a1b1852003-01-05 22:37:17 +00004188 /*
4189 * this is a tricky part for the node register thing:
4190 * in case ret does get coalesced in xmlAddChild
4191 * the deregister-node callback is called; so we register ret now already
4192 */
Daniel Veillarda880b122003-04-21 21:36:41 +00004193 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00004194 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
4195
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004196 tmp = xmlAddChild(parent, ret);
4197 /* node could have coalesced */
4198 if (tmp != ret)
4199 return(tmp);
4200 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00004201
William M. Brack57e9e912004-03-09 16:19:02 +00004202 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00004203 goto out;
Petr Pajas2afca4a2009-07-30 17:47:32 +02004204 if (((node->type == XML_ELEMENT_NODE) ||
4205 (node->type == XML_XINCLUDE_START)) && (node->nsDef != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00004206 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
4207
4208 if (node->ns != NULL) {
4209 xmlNsPtr ns;
4210
4211 ns = xmlSearchNs(doc, ret, node->ns->prefix);
4212 if (ns == NULL) {
4213 /*
4214 * Humm, we are copying an element whose namespace is defined
4215 * out of the new tree scope. Search it in the original tree
4216 * and add it at the top of the new tree
4217 */
4218 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
4219 if (ns != NULL) {
4220 xmlNodePtr root = ret;
4221
4222 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00004223 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Rob Richardsddb01cb2010-01-29 13:32:12 -05004224 } else {
4225 ret->ns = xmlNewReconciliedNs(doc, ret, node->ns);
Owen Taylor3473f882001-02-23 17:55:21 +00004226 }
4227 } else {
4228 /*
4229 * reference the existing namespace definition in our own tree.
4230 */
4231 ret->ns = ns;
4232 }
4233 }
Petr Pajas2afca4a2009-07-30 17:47:32 +02004234 if (((node->type == XML_ELEMENT_NODE) ||
4235 (node->type == XML_XINCLUDE_START)) && (node->properties != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00004236 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004237 if (node->type == XML_ENTITY_REF_NODE) {
4238 if ((doc == NULL) || (node->doc != doc)) {
4239 /*
4240 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00004241 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00004242 * we cannot keep the reference. Try to find it in the
4243 * target document.
4244 */
4245 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
4246 } else {
4247 ret->children = node->children;
4248 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00004249 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00004250 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004251 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00004252 UPDATE_LAST_CHILD_AND_PARENT(ret)
4253 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00004254
4255out:
4256 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00004257 if ((parent == NULL) &&
4258 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00004259 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004260 return(ret);
4261}
4262
4263static xmlNodePtr
4264xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
4265 xmlNodePtr ret = NULL;
4266 xmlNodePtr p = NULL,q;
4267
4268 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00004269#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00004270 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00004271 if (doc == NULL) {
4272 node = node->next;
4273 continue;
4274 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00004275 if (doc->intSubset == NULL) {
4276 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
4277 q->doc = doc;
4278 q->parent = parent;
4279 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004280 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004281 } else {
4282 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004283 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004284 }
4285 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00004286#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00004287 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00004288 if (ret == NULL) {
4289 q->prev = NULL;
4290 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004291 } else if (p != q) {
4292 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00004293 p->next = q;
4294 q->prev = p;
4295 p = q;
4296 }
4297 node = node->next;
4298 }
4299 return(ret);
4300}
4301
4302/**
4303 * xmlCopyNode:
4304 * @node: the node
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)
Owen Taylor3473f882001-02-23 17:55:21 +00004308 *
4309 * Do a copy of the node.
4310 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004311 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004312 */
4313xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00004314xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00004315 xmlNodePtr ret;
4316
William M. Brack57e9e912004-03-09 16:19:02 +00004317 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00004318 return(ret);
4319}
4320
4321/**
Daniel Veillard82daa812001-04-12 08:55:36 +00004322 * xmlDocCopyNode:
4323 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00004324 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004325 * @extended: if 1 do a recursive copy (properties, namespaces and children
4326 * when applicable)
4327 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00004328 *
4329 * Do a copy of the node to a given document.
4330 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004331 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00004332 */
4333xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00004334xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00004335 xmlNodePtr ret;
4336
William M. Brack57e9e912004-03-09 16:19:02 +00004337 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00004338 return(ret);
4339}
4340
4341/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00004342 * xmlDocCopyNodeList:
4343 * @doc: the target document
4344 * @node: the first node in the list.
4345 *
4346 * Do a recursive copy of the node list.
4347 *
4348 * Returns: a new #xmlNodePtr, or NULL in case of error.
4349 */
4350xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) {
4351 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
4352 return(ret);
4353}
4354
4355/**
Owen Taylor3473f882001-02-23 17:55:21 +00004356 * xmlCopyNodeList:
4357 * @node: the first node in the list.
4358 *
4359 * Do a recursive copy of the node list.
Daniel Veillard03a53c32004-10-26 16:06:51 +00004360 * Use xmlDocCopyNodeList() if possible to ensure string interning.
Owen Taylor3473f882001-02-23 17:55:21 +00004361 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004362 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004363 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00004364xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00004365 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
4366 return(ret);
4367}
4368
Daniel Veillard2156d432004-03-04 15:59:36 +00004369#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004370/**
Owen Taylor3473f882001-02-23 17:55:21 +00004371 * xmlCopyDtd:
4372 * @dtd: the dtd
4373 *
4374 * Do a copy of the dtd.
4375 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004376 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004377 */
4378xmlDtdPtr
4379xmlCopyDtd(xmlDtdPtr dtd) {
4380 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004381 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00004382
4383 if (dtd == NULL) return(NULL);
4384 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4385 if (ret == NULL) return(NULL);
4386 if (dtd->entities != NULL)
4387 ret->entities = (void *) xmlCopyEntitiesTable(
4388 (xmlEntitiesTablePtr) dtd->entities);
4389 if (dtd->notations != NULL)
4390 ret->notations = (void *) xmlCopyNotationTable(
4391 (xmlNotationTablePtr) dtd->notations);
4392 if (dtd->elements != NULL)
4393 ret->elements = (void *) xmlCopyElementTable(
4394 (xmlElementTablePtr) dtd->elements);
4395 if (dtd->attributes != NULL)
4396 ret->attributes = (void *) xmlCopyAttributeTable(
4397 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004398 if (dtd->pentities != NULL)
4399 ret->pentities = (void *) xmlCopyEntitiesTable(
4400 (xmlEntitiesTablePtr) dtd->pentities);
Daniel Veillardaa6de472008-08-25 14:53:31 +00004401
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004402 cur = dtd->children;
4403 while (cur != NULL) {
4404 q = NULL;
4405
4406 if (cur->type == XML_ENTITY_DECL) {
4407 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4408 switch (tmp->etype) {
4409 case XML_INTERNAL_GENERAL_ENTITY:
4410 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4411 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4412 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4413 break;
4414 case XML_INTERNAL_PARAMETER_ENTITY:
4415 case XML_EXTERNAL_PARAMETER_ENTITY:
Daniel Veillardaa6de472008-08-25 14:53:31 +00004416 q = (xmlNodePtr)
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004417 xmlGetParameterEntityFromDtd(ret, tmp->name);
4418 break;
4419 case XML_INTERNAL_PREDEFINED_ENTITY:
4420 break;
4421 }
4422 } else if (cur->type == XML_ELEMENT_DECL) {
4423 xmlElementPtr tmp = (xmlElementPtr) cur;
4424 q = (xmlNodePtr)
4425 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4426 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4427 xmlAttributePtr tmp = (xmlAttributePtr) cur;
Daniel Veillardaa6de472008-08-25 14:53:31 +00004428 q = (xmlNodePtr)
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004429 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4430 } else if (cur->type == XML_COMMENT_NODE) {
4431 q = xmlCopyNode(cur, 0);
4432 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00004433
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004434 if (q == NULL) {
4435 cur = cur->next;
4436 continue;
4437 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00004438
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004439 if (p == NULL)
4440 ret->children = q;
4441 else
Daniel Veillardaa6de472008-08-25 14:53:31 +00004442 p->next = q;
4443
4444 q->prev = p;
4445 q->parent = (xmlNodePtr) ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004446 q->next = NULL;
4447 ret->last = q;
Daniel Veillardaa6de472008-08-25 14:53:31 +00004448 p = q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004449 cur = cur->next;
4450 }
4451
Owen Taylor3473f882001-02-23 17:55:21 +00004452 return(ret);
4453}
Daniel Veillard2156d432004-03-04 15:59:36 +00004454#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004455
Daniel Veillard2156d432004-03-04 15:59:36 +00004456#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004457/**
4458 * xmlCopyDoc:
4459 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004460 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004461 *
4462 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004463 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004464 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004465 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004466 */
4467xmlDocPtr
4468xmlCopyDoc(xmlDocPtr doc, int recursive) {
4469 xmlDocPtr ret;
4470
4471 if (doc == NULL) return(NULL);
4472 ret = xmlNewDoc(doc->version);
4473 if (ret == NULL) return(NULL);
4474 if (doc->name != NULL)
4475 ret->name = xmlMemStrdup(doc->name);
4476 if (doc->encoding != NULL)
4477 ret->encoding = xmlStrdup(doc->encoding);
Daniel Veillardf59507d2005-01-27 17:26:49 +00004478 if (doc->URL != NULL)
4479 ret->URL = xmlStrdup(doc->URL);
Owen Taylor3473f882001-02-23 17:55:21 +00004480 ret->charset = doc->charset;
4481 ret->compression = doc->compression;
4482 ret->standalone = doc->standalone;
4483 if (!recursive) return(ret);
4484
Daniel Veillardb33c2012001-04-25 12:59:04 +00004485 ret->last = NULL;
4486 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004487#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004488 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004489 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004490 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004491 ret->intSubset->parent = ret;
4492 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004493#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004494 if (doc->oldNs != NULL)
4495 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4496 if (doc->children != NULL) {
4497 xmlNodePtr tmp;
Daniel Veillardaa6de472008-08-25 14:53:31 +00004498
Daniel Veillardb33c2012001-04-25 12:59:04 +00004499 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4500 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004501 ret->last = NULL;
4502 tmp = ret->children;
4503 while (tmp != NULL) {
4504 if (tmp->next == NULL)
4505 ret->last = tmp;
4506 tmp = tmp->next;
4507 }
4508 }
4509 return(ret);
4510}
Daniel Veillard652327a2003-09-29 18:02:38 +00004511#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004512
4513/************************************************************************
4514 * *
4515 * Content access functions *
4516 * *
4517 ************************************************************************/
Daniel Veillardaa6de472008-08-25 14:53:31 +00004518
Owen Taylor3473f882001-02-23 17:55:21 +00004519/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004520 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004521 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004522 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004523 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004524 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004525 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004526 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004527 */
4528long
4529xmlGetLineNo(xmlNodePtr node)
4530{
4531 long result = -1;
4532
4533 if (!node)
4534 return result;
Daniel Veillard73da77e2005-08-24 14:05:37 +00004535 if ((node->type == XML_ELEMENT_NODE) ||
4536 (node->type == XML_TEXT_NODE) ||
4537 (node->type == XML_COMMENT_NODE) ||
4538 (node->type == XML_PI_NODE))
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004539 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004540 else if ((node->prev != NULL) &&
4541 ((node->prev->type == XML_ELEMENT_NODE) ||
Daniel Veillard73da77e2005-08-24 14:05:37 +00004542 (node->prev->type == XML_TEXT_NODE) ||
4543 (node->prev->type == XML_COMMENT_NODE) ||
4544 (node->prev->type == XML_PI_NODE)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004545 result = xmlGetLineNo(node->prev);
4546 else if ((node->parent != NULL) &&
Daniel Veillard73da77e2005-08-24 14:05:37 +00004547 (node->parent->type == XML_ELEMENT_NODE))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004548 result = xmlGetLineNo(node->parent);
4549
4550 return result;
4551}
4552
Daniel Veillard2156d432004-03-04 15:59:36 +00004553#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004554/**
4555 * xmlGetNodePath:
4556 * @node: a node
4557 *
4558 * Build a structure based Path for the given node
4559 *
4560 * Returns the new path or NULL in case of error. The caller must free
4561 * the returned string
4562 */
4563xmlChar *
4564xmlGetNodePath(xmlNodePtr node)
4565{
4566 xmlNodePtr cur, tmp, next;
4567 xmlChar *buffer = NULL, *temp;
4568 size_t buf_len;
4569 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004570 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004571 const char *name;
4572 char nametemp[100];
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004573 int occur = 0, generic;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004574
4575 if (node == NULL)
4576 return (NULL);
4577
4578 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004579 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004580 if (buffer == NULL) {
4581 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004582 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004583 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004584 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004585 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004586 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004587 xmlFree(buffer);
4588 return (NULL);
4589 }
4590
4591 buffer[0] = 0;
4592 cur = node;
4593 do {
4594 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004595 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004596 occur = 0;
4597 if ((cur->type == XML_DOCUMENT_NODE) ||
4598 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4599 if (buffer[0] == '/')
4600 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004601 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004602 next = NULL;
4603 } else if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004604 generic = 0;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004605 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004606 name = (const char *) cur->name;
4607 if (cur->ns) {
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004608 if (cur->ns->prefix != NULL) {
William M. Brack13dfa872004-09-18 04:52:08 +00004609 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
Daniel Veillardaa6de472008-08-25 14:53:31 +00004610 (char *)cur->ns->prefix, (char *)cur->name);
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004611 nametemp[sizeof(nametemp) - 1] = 0;
4612 name = nametemp;
4613 } else {
4614 /*
4615 * We cannot express named elements in the default
4616 * namespace, so use "*".
4617 */
4618 generic = 1;
4619 name = "*";
Daniel Veillardaa6de472008-08-25 14:53:31 +00004620 }
Daniel Veillard8faa7832001-11-26 15:58:08 +00004621 }
4622 next = cur->parent;
4623
4624 /*
4625 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004626 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004627 */
4628 tmp = cur->prev;
4629 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004630 if ((tmp->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004631 (generic ||
Kasimier T. Buchcik43ceb1e2006-06-12 11:08:18 +00004632 (xmlStrEqual(cur->name, tmp->name) &&
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004633 ((tmp->ns == cur->ns) ||
4634 ((tmp->ns != NULL) && (cur->ns != NULL) &&
Kasimier T. Buchcik43ceb1e2006-06-12 11:08:18 +00004635 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004636 occur++;
4637 tmp = tmp->prev;
4638 }
4639 if (occur == 0) {
4640 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004641 while (tmp != NULL && occur == 0) {
4642 if ((tmp->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004643 (generic ||
Kasimier T. Buchcik43ceb1e2006-06-12 11:08:18 +00004644 (xmlStrEqual(cur->name, tmp->name) &&
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004645 ((tmp->ns == cur->ns) ||
4646 ((tmp->ns != NULL) && (cur->ns != NULL) &&
Kasimier T. Buchcik43ceb1e2006-06-12 11:08:18 +00004647 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004648 occur++;
4649 tmp = tmp->next;
4650 }
4651 if (occur != 0)
4652 occur = 1;
4653 } else
4654 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004655 } else if (cur->type == XML_COMMENT_NODE) {
4656 sep = "/";
4657 name = "comment()";
4658 next = cur->parent;
4659
4660 /*
4661 * Thumbler index computation
4662 */
4663 tmp = cur->prev;
4664 while (tmp != NULL) {
4665 if (tmp->type == XML_COMMENT_NODE)
4666 occur++;
4667 tmp = tmp->prev;
4668 }
4669 if (occur == 0) {
4670 tmp = cur->next;
4671 while (tmp != NULL && occur == 0) {
4672 if (tmp->type == XML_COMMENT_NODE)
4673 occur++;
4674 tmp = tmp->next;
4675 }
4676 if (occur != 0)
4677 occur = 1;
4678 } else
4679 occur++;
4680 } else if ((cur->type == XML_TEXT_NODE) ||
4681 (cur->type == XML_CDATA_SECTION_NODE)) {
4682 sep = "/";
4683 name = "text()";
4684 next = cur->parent;
4685
4686 /*
4687 * Thumbler index computation
4688 */
4689 tmp = cur->prev;
4690 while (tmp != NULL) {
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004691 if ((tmp->type == XML_TEXT_NODE) ||
4692 (tmp->type == XML_CDATA_SECTION_NODE))
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004693 occur++;
4694 tmp = tmp->prev;
4695 }
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004696 /*
4697 * Evaluate if this is the only text- or CDATA-section-node;
4698 * if yes, then we'll get "text()", otherwise "text()[1]".
4699 */
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004700 if (occur == 0) {
4701 tmp = cur->next;
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004702 while (tmp != NULL) {
4703 if ((tmp->type == XML_TEXT_NODE) ||
4704 (tmp->type == XML_CDATA_SECTION_NODE))
4705 {
4706 occur = 1;
4707 break;
Daniel Veillardaa6de472008-08-25 14:53:31 +00004708 }
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004709 tmp = tmp->next;
4710 }
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004711 } else
4712 occur++;
4713 } else if (cur->type == XML_PI_NODE) {
4714 sep = "/";
4715 snprintf(nametemp, sizeof(nametemp) - 1,
William M. Brack13dfa872004-09-18 04:52:08 +00004716 "processing-instruction('%s')", (char *)cur->name);
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004717 nametemp[sizeof(nametemp) - 1] = 0;
4718 name = nametemp;
4719
4720 next = cur->parent;
4721
4722 /*
4723 * Thumbler index computation
4724 */
4725 tmp = cur->prev;
4726 while (tmp != NULL) {
4727 if ((tmp->type == XML_PI_NODE) &&
4728 (xmlStrEqual(cur->name, tmp->name)))
4729 occur++;
4730 tmp = tmp->prev;
4731 }
4732 if (occur == 0) {
4733 tmp = cur->next;
4734 while (tmp != NULL && occur == 0) {
4735 if ((tmp->type == XML_PI_NODE) &&
4736 (xmlStrEqual(cur->name, tmp->name)))
4737 occur++;
4738 tmp = tmp->next;
4739 }
4740 if (occur != 0)
4741 occur = 1;
4742 } else
4743 occur++;
4744
Daniel Veillard8faa7832001-11-26 15:58:08 +00004745 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004746 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004747 name = (const char *) (((xmlAttrPtr) cur)->name);
Daniel Veillard365c8062005-07-19 11:31:55 +00004748 if (cur->ns) {
4749 if (cur->ns->prefix != NULL)
4750 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
Daniel Veillardaa6de472008-08-25 14:53:31 +00004751 (char *)cur->ns->prefix, (char *)cur->name);
Daniel Veillard365c8062005-07-19 11:31:55 +00004752 else
4753 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
Daniel Veillardaa6de472008-08-25 14:53:31 +00004754 (char *)cur->name);
Daniel Veillard365c8062005-07-19 11:31:55 +00004755 nametemp[sizeof(nametemp) - 1] = 0;
4756 name = nametemp;
4757 }
Daniel Veillard8faa7832001-11-26 15:58:08 +00004758 next = ((xmlAttrPtr) cur)->parent;
4759 } else {
4760 next = cur->parent;
4761 }
4762
4763 /*
4764 * Make sure there is enough room
4765 */
4766 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4767 buf_len =
4768 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4769 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4770 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004771 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004772 xmlFree(buf);
4773 xmlFree(buffer);
4774 return (NULL);
4775 }
4776 buffer = temp;
4777 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4778 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004779 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004780 xmlFree(buf);
4781 xmlFree(buffer);
4782 return (NULL);
4783 }
4784 buf = temp;
4785 }
4786 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004787 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004788 sep, name, (char *) buffer);
4789 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004790 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004791 sep, name, occur, (char *) buffer);
William M. Brack13dfa872004-09-18 04:52:08 +00004792 snprintf((char *) buffer, buf_len, "%s", (char *)buf);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004793 cur = next;
4794 } while (cur != NULL);
4795 xmlFree(buf);
4796 return (buffer);
4797}
Daniel Veillard652327a2003-09-29 18:02:38 +00004798#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004799
4800/**
Owen Taylor3473f882001-02-23 17:55:21 +00004801 * xmlDocGetRootElement:
4802 * @doc: the document
4803 *
4804 * Get the root element of the document (doc->children is a list
4805 * containing possibly comments, PIs, etc ...).
4806 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004807 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004808 */
4809xmlNodePtr
4810xmlDocGetRootElement(xmlDocPtr doc) {
4811 xmlNodePtr ret;
4812
4813 if (doc == NULL) return(NULL);
4814 ret = doc->children;
4815 while (ret != NULL) {
4816 if (ret->type == XML_ELEMENT_NODE)
4817 return(ret);
4818 ret = ret->next;
4819 }
4820 return(ret);
4821}
Daniel Veillardaa6de472008-08-25 14:53:31 +00004822
Daniel Veillard2156d432004-03-04 15:59:36 +00004823#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004824/**
4825 * xmlDocSetRootElement:
4826 * @doc: the document
Daniel Veillard26a45c82006-10-20 12:55:34 +00004827 * @root: the new document root element, if root is NULL no action is taken,
4828 * to remove a node from a document use xmlUnlinkNode(root) instead.
Owen Taylor3473f882001-02-23 17:55:21 +00004829 *
4830 * Set the root element of the document (doc->children is a list
4831 * containing possibly comments, PIs, etc ...).
4832 *
Daniel Veillard26a45c82006-10-20 12:55:34 +00004833 * Returns the old root element if any was found, NULL if root was NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004834 */
4835xmlNodePtr
4836xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4837 xmlNodePtr old = NULL;
4838
4839 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004840 if (root == NULL)
4841 return(NULL);
4842 xmlUnlinkNode(root);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00004843 xmlSetTreeDoc(root, doc);
Daniel Veillardc575b992002-02-08 13:28:40 +00004844 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004845 old = doc->children;
4846 while (old != NULL) {
4847 if (old->type == XML_ELEMENT_NODE)
4848 break;
4849 old = old->next;
4850 }
4851 if (old == NULL) {
4852 if (doc->children == NULL) {
4853 doc->children = root;
4854 doc->last = root;
4855 } else {
4856 xmlAddSibling(doc->children, root);
4857 }
4858 } else {
4859 xmlReplaceNode(old, root);
4860 }
4861 return(old);
4862}
Daniel Veillard2156d432004-03-04 15:59:36 +00004863#endif
Daniel Veillardaa6de472008-08-25 14:53:31 +00004864
Daniel Veillard2156d432004-03-04 15:59:36 +00004865#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004866/**
4867 * xmlNodeSetLang:
4868 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004869 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004870 *
4871 * Set the language of a node, i.e. the values of the xml:lang
4872 * attribute.
4873 */
4874void
4875xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004876 xmlNsPtr ns;
4877
Owen Taylor3473f882001-02-23 17:55:21 +00004878 if (cur == NULL) return;
4879 switch(cur->type) {
4880 case XML_TEXT_NODE:
4881 case XML_CDATA_SECTION_NODE:
4882 case XML_COMMENT_NODE:
4883 case XML_DOCUMENT_NODE:
4884 case XML_DOCUMENT_TYPE_NODE:
4885 case XML_DOCUMENT_FRAG_NODE:
4886 case XML_NOTATION_NODE:
4887 case XML_HTML_DOCUMENT_NODE:
4888 case XML_DTD_NODE:
4889 case XML_ELEMENT_DECL:
4890 case XML_ATTRIBUTE_DECL:
4891 case XML_ENTITY_DECL:
4892 case XML_PI_NODE:
4893 case XML_ENTITY_REF_NODE:
4894 case XML_ENTITY_NODE:
4895 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004896#ifdef LIBXML_DOCB_ENABLED
4897 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004898#endif
4899 case XML_XINCLUDE_START:
4900 case XML_XINCLUDE_END:
4901 return;
4902 case XML_ELEMENT_NODE:
4903 case XML_ATTRIBUTE_NODE:
4904 break;
4905 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004906 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4907 if (ns == NULL)
4908 return;
4909 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004910}
Daniel Veillard652327a2003-09-29 18:02:38 +00004911#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardaa6de472008-08-25 14:53:31 +00004912
Owen Taylor3473f882001-02-23 17:55:21 +00004913/**
4914 * xmlNodeGetLang:
4915 * @cur: the node being checked
4916 *
4917 * Searches the language of a node, i.e. the values of the xml:lang
4918 * attribute or the one carried by the nearest ancestor.
4919 *
4920 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004921 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004922 */
4923xmlChar *
4924xmlNodeGetLang(xmlNodePtr cur) {
4925 xmlChar *lang;
4926
4927 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004928 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004929 if (lang != NULL)
4930 return(lang);
4931 cur = cur->parent;
4932 }
4933 return(NULL);
4934}
Daniel Veillardaa6de472008-08-25 14:53:31 +00004935
Owen Taylor3473f882001-02-23 17:55:21 +00004936
Daniel Veillard652327a2003-09-29 18:02:38 +00004937#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004938/**
4939 * xmlNodeSetSpacePreserve:
4940 * @cur: the node being changed
4941 * @val: the xml:space value ("0": default, 1: "preserve")
4942 *
4943 * Set (or reset) the space preserving behaviour of a node, i.e. the
4944 * value of the xml:space attribute.
4945 */
4946void
4947xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004948 xmlNsPtr ns;
4949
Owen Taylor3473f882001-02-23 17:55:21 +00004950 if (cur == NULL) return;
4951 switch(cur->type) {
4952 case XML_TEXT_NODE:
4953 case XML_CDATA_SECTION_NODE:
4954 case XML_COMMENT_NODE:
4955 case XML_DOCUMENT_NODE:
4956 case XML_DOCUMENT_TYPE_NODE:
4957 case XML_DOCUMENT_FRAG_NODE:
4958 case XML_NOTATION_NODE:
4959 case XML_HTML_DOCUMENT_NODE:
4960 case XML_DTD_NODE:
4961 case XML_ELEMENT_DECL:
4962 case XML_ATTRIBUTE_DECL:
4963 case XML_ENTITY_DECL:
4964 case XML_PI_NODE:
4965 case XML_ENTITY_REF_NODE:
4966 case XML_ENTITY_NODE:
4967 case XML_NAMESPACE_DECL:
4968 case XML_XINCLUDE_START:
4969 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004970#ifdef LIBXML_DOCB_ENABLED
4971 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004972#endif
4973 return;
4974 case XML_ELEMENT_NODE:
4975 case XML_ATTRIBUTE_NODE:
4976 break;
4977 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004978 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4979 if (ns == NULL)
4980 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004981 switch (val) {
4982 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004983 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004984 break;
4985 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004986 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004987 break;
4988 }
4989}
Daniel Veillard652327a2003-09-29 18:02:38 +00004990#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004991
4992/**
4993 * xmlNodeGetSpacePreserve:
4994 * @cur: the node being checked
4995 *
4996 * Searches the space preserving behaviour of a node, i.e. the values
4997 * of the xml:space attribute or the one carried by the nearest
4998 * ancestor.
4999 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005000 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00005001 */
5002int
5003xmlNodeGetSpacePreserve(xmlNodePtr cur) {
5004 xmlChar *space;
5005
5006 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00005007 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00005008 if (space != NULL) {
5009 if (xmlStrEqual(space, BAD_CAST "preserve")) {
5010 xmlFree(space);
5011 return(1);
5012 }
5013 if (xmlStrEqual(space, BAD_CAST "default")) {
5014 xmlFree(space);
5015 return(0);
5016 }
5017 xmlFree(space);
5018 }
5019 cur = cur->parent;
5020 }
5021 return(-1);
5022}
Daniel Veillardaa6de472008-08-25 14:53:31 +00005023
Daniel Veillard652327a2003-09-29 18:02:38 +00005024#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005025/**
5026 * xmlNodeSetName:
5027 * @cur: the node being changed
5028 * @name: the new tag name
5029 *
5030 * Set (or reset) the name of a node.
5031 */
5032void
5033xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00005034 xmlDocPtr doc;
5035 xmlDictPtr dict;
5036
Owen Taylor3473f882001-02-23 17:55:21 +00005037 if (cur == NULL) return;
5038 if (name == NULL) return;
5039 switch(cur->type) {
5040 case XML_TEXT_NODE:
5041 case XML_CDATA_SECTION_NODE:
5042 case XML_COMMENT_NODE:
5043 case XML_DOCUMENT_TYPE_NODE:
5044 case XML_DOCUMENT_FRAG_NODE:
5045 case XML_NOTATION_NODE:
5046 case XML_HTML_DOCUMENT_NODE:
5047 case XML_NAMESPACE_DECL:
5048 case XML_XINCLUDE_START:
5049 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005050#ifdef LIBXML_DOCB_ENABLED
5051 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005052#endif
5053 return;
5054 case XML_ELEMENT_NODE:
5055 case XML_ATTRIBUTE_NODE:
5056 case XML_PI_NODE:
5057 case XML_ENTITY_REF_NODE:
5058 case XML_ENTITY_NODE:
5059 case XML_DTD_NODE:
5060 case XML_DOCUMENT_NODE:
5061 case XML_ELEMENT_DECL:
5062 case XML_ATTRIBUTE_DECL:
5063 case XML_ENTITY_DECL:
5064 break;
5065 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00005066 doc = cur->doc;
5067 if (doc != NULL)
5068 dict = doc->dict;
5069 else
5070 dict = NULL;
5071 if (dict != NULL) {
5072 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
5073 xmlFree((xmlChar *) cur->name);
5074 cur->name = xmlDictLookup(dict, name, -1);
5075 } else {
5076 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
5077 cur->name = xmlStrdup(name);
5078 }
Owen Taylor3473f882001-02-23 17:55:21 +00005079}
Daniel Veillard2156d432004-03-04 15:59:36 +00005080#endif
Daniel Veillardaa6de472008-08-25 14:53:31 +00005081
Daniel Veillard2156d432004-03-04 15:59:36 +00005082#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005083/**
5084 * xmlNodeSetBase:
5085 * @cur: the node being changed
5086 * @uri: the new base URI
5087 *
5088 * Set (or reset) the base URI of a node, i.e. the value of the
5089 * xml:base attribute.
5090 */
5091void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00005092xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00005093 xmlNsPtr ns;
Martin Trappelf3703102010-01-22 12:08:00 +01005094 xmlChar* fixed;
Daniel Veillardcfa0d812002-01-17 08:46:58 +00005095
Owen Taylor3473f882001-02-23 17:55:21 +00005096 if (cur == NULL) return;
5097 switch(cur->type) {
5098 case XML_TEXT_NODE:
5099 case XML_CDATA_SECTION_NODE:
5100 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005101 case XML_DOCUMENT_TYPE_NODE:
5102 case XML_DOCUMENT_FRAG_NODE:
5103 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005104 case XML_DTD_NODE:
5105 case XML_ELEMENT_DECL:
5106 case XML_ATTRIBUTE_DECL:
5107 case XML_ENTITY_DECL:
5108 case XML_PI_NODE:
5109 case XML_ENTITY_REF_NODE:
5110 case XML_ENTITY_NODE:
5111 case XML_NAMESPACE_DECL:
5112 case XML_XINCLUDE_START:
5113 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00005114 return;
5115 case XML_ELEMENT_NODE:
5116 case XML_ATTRIBUTE_NODE:
5117 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00005118 case XML_DOCUMENT_NODE:
5119#ifdef LIBXML_DOCB_ENABLED
5120 case XML_DOCB_DOCUMENT_NODE:
5121#endif
5122 case XML_HTML_DOCUMENT_NODE: {
5123 xmlDocPtr doc = (xmlDocPtr) cur;
5124
5125 if (doc->URL != NULL)
5126 xmlFree((xmlChar *) doc->URL);
5127 if (uri == NULL)
5128 doc->URL = NULL;
5129 else
Daniel Veillardb8efdda2006-10-10 12:37:14 +00005130 doc->URL = xmlPathToURI(uri);
Daniel Veillard4cbe4702002-05-05 06:57:27 +00005131 return;
5132 }
Owen Taylor3473f882001-02-23 17:55:21 +00005133 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00005134
Daniel Veillardcfa0d812002-01-17 08:46:58 +00005135 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
5136 if (ns == NULL)
5137 return;
Daniel Veillardb8efdda2006-10-10 12:37:14 +00005138 fixed = xmlPathToURI(uri);
5139 if (fixed != NULL) {
5140 xmlSetNsProp(cur, ns, BAD_CAST "base", fixed);
Martin Trappelf3703102010-01-22 12:08:00 +01005141 xmlFree(fixed);
Daniel Veillardb8efdda2006-10-10 12:37:14 +00005142 } else {
5143 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
5144 }
Owen Taylor3473f882001-02-23 17:55:21 +00005145}
Daniel Veillard652327a2003-09-29 18:02:38 +00005146#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005147
5148/**
Owen Taylor3473f882001-02-23 17:55:21 +00005149 * xmlNodeGetBase:
5150 * @doc: the document the node pertains to
5151 * @cur: the node being checked
5152 *
5153 * Searches for the BASE URL. The code should work on both XML
5154 * and HTML document even if base mechanisms are completely different.
5155 * It returns the base as defined in RFC 2396 sections
5156 * 5.1.1. Base URI within Document Content
5157 * and
5158 * 5.1.2. Base URI from the Encapsulating Entity
5159 * However it does not return the document base (5.1.3), use
Daniel Veillarde4d18492010-03-09 11:12:30 +01005160 * doc->URL in this case
Owen Taylor3473f882001-02-23 17:55:21 +00005161 *
5162 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005163 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005164 */
5165xmlChar *
5166xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00005167 xmlChar *oldbase = NULL;
5168 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00005169
Daniel Veillardaa6de472008-08-25 14:53:31 +00005170 if ((cur == NULL) && (doc == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00005171 return(NULL);
Daniel Veillardaa6de472008-08-25 14:53:31 +00005172 if (doc == NULL) doc = cur->doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005173 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
5174 cur = doc->children;
5175 while ((cur != NULL) && (cur->name != NULL)) {
5176 if (cur->type != XML_ELEMENT_NODE) {
5177 cur = cur->next;
5178 continue;
5179 }
5180 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
5181 cur = cur->children;
5182 continue;
5183 }
5184 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
5185 cur = cur->children;
5186 continue;
5187 }
5188 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
5189 return(xmlGetProp(cur, BAD_CAST "href"));
5190 }
5191 cur = cur->next;
5192 }
5193 return(NULL);
5194 }
5195 while (cur != NULL) {
5196 if (cur->type == XML_ENTITY_DECL) {
5197 xmlEntityPtr ent = (xmlEntityPtr) cur;
5198 return(xmlStrdup(ent->URI));
5199 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00005200 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00005201 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00005202 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00005203 if (oldbase != NULL) {
5204 newbase = xmlBuildURI(oldbase, base);
5205 if (newbase != NULL) {
5206 xmlFree(oldbase);
5207 xmlFree(base);
5208 oldbase = newbase;
5209 } else {
5210 xmlFree(oldbase);
5211 xmlFree(base);
5212 return(NULL);
5213 }
5214 } else {
5215 oldbase = base;
5216 }
5217 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
5218 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
5219 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
5220 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00005221 }
5222 }
Owen Taylor3473f882001-02-23 17:55:21 +00005223 cur = cur->parent;
5224 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00005225 if ((doc != NULL) && (doc->URL != NULL)) {
5226 if (oldbase == NULL)
5227 return(xmlStrdup(doc->URL));
5228 newbase = xmlBuildURI(oldbase, doc->URL);
5229 xmlFree(oldbase);
5230 return(newbase);
5231 }
5232 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00005233}
Daniel Veillardaa6de472008-08-25 14:53:31 +00005234
Owen Taylor3473f882001-02-23 17:55:21 +00005235/**
Daniel Veillard78697292003-10-19 20:44:43 +00005236 * xmlNodeBufGetContent:
5237 * @buffer: a buffer
5238 * @cur: the node being read
5239 *
5240 * Read the value of a node @cur, this can be either the text carried
5241 * directly by this node if it's a TEXT node or the aggregate string
5242 * of the values carried by this node child's (TEXT and ENTITY_REF).
5243 * Entity references are substituted.
5244 * Fills up the buffer @buffer with this value
Daniel Veillardaa6de472008-08-25 14:53:31 +00005245 *
Daniel Veillard78697292003-10-19 20:44:43 +00005246 * Returns 0 in case of success and -1 in case of error.
5247 */
5248int
5249xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
5250{
Daniel Veillarddddeede2012-07-16 14:44:26 +08005251 xmlBufPtr buf;
5252 int ret;
5253
Daniel Veillard78697292003-10-19 20:44:43 +00005254 if ((cur == NULL) || (buffer == NULL)) return(-1);
Daniel Veillarddddeede2012-07-16 14:44:26 +08005255 buf = xmlBufFromBuffer(buffer);
5256 ret = xmlBufGetNodeContent(buf, cur);
5257 buffer = xmlBufBackToBuffer(buf);
5258 if ((ret < 0) || (buffer == NULL))
5259 return(-1);
5260 return(0);
5261}
5262
5263/**
5264 * xmlBufGetNodeContent:
5265 * @buffer: a buffer
5266 * @cur: the node being read
5267 *
5268 * Read the value of a node @cur, this can be either the text carried
5269 * directly by this node if it's a TEXT node or the aggregate string
5270 * of the values carried by this node child's (TEXT and ENTITY_REF).
5271 * Entity references are substituted.
5272 * Fills up the buffer @buffer with this value
5273 *
5274 * Returns 0 in case of success and -1 in case of error.
5275 */
5276int
5277xmlBufGetNodeContent(xmlBufPtr buf, xmlNodePtr cur)
5278{
5279 if ((cur == NULL) || (buf == NULL)) return(-1);
Daniel Veillard78697292003-10-19 20:44:43 +00005280 switch (cur->type) {
5281 case XML_CDATA_SECTION_NODE:
5282 case XML_TEXT_NODE:
Daniel Veillarddddeede2012-07-16 14:44:26 +08005283 xmlBufCat(buf, cur->content);
Daniel Veillard78697292003-10-19 20:44:43 +00005284 break;
5285 case XML_DOCUMENT_FRAG_NODE:
5286 case XML_ELEMENT_NODE:{
5287 xmlNodePtr tmp = cur;
5288
5289 while (tmp != NULL) {
5290 switch (tmp->type) {
5291 case XML_CDATA_SECTION_NODE:
5292 case XML_TEXT_NODE:
5293 if (tmp->content != NULL)
Daniel Veillarddddeede2012-07-16 14:44:26 +08005294 xmlBufCat(buf, tmp->content);
Daniel Veillard78697292003-10-19 20:44:43 +00005295 break;
5296 case XML_ENTITY_REF_NODE:
Daniel Veillarddddeede2012-07-16 14:44:26 +08005297 xmlBufGetNodeContent(buf, tmp);
Rob Richards77b92ff2005-12-20 15:55:14 +00005298 break;
Daniel Veillard78697292003-10-19 20:44:43 +00005299 default:
5300 break;
5301 }
5302 /*
5303 * Skip to next node
5304 */
5305 if (tmp->children != NULL) {
5306 if (tmp->children->type != XML_ENTITY_DECL) {
5307 tmp = tmp->children;
5308 continue;
5309 }
5310 }
5311 if (tmp == cur)
5312 break;
5313
5314 if (tmp->next != NULL) {
5315 tmp = tmp->next;
5316 continue;
5317 }
5318
5319 do {
5320 tmp = tmp->parent;
5321 if (tmp == NULL)
5322 break;
5323 if (tmp == cur) {
5324 tmp = NULL;
5325 break;
5326 }
5327 if (tmp->next != NULL) {
5328 tmp = tmp->next;
5329 break;
5330 }
5331 } while (tmp != NULL);
5332 }
5333 break;
5334 }
5335 case XML_ATTRIBUTE_NODE:{
5336 xmlAttrPtr attr = (xmlAttrPtr) cur;
5337 xmlNodePtr tmp = attr->children;
5338
5339 while (tmp != NULL) {
5340 if (tmp->type == XML_TEXT_NODE)
Daniel Veillarddddeede2012-07-16 14:44:26 +08005341 xmlBufCat(buf, tmp->content);
Daniel Veillard78697292003-10-19 20:44:43 +00005342 else
Daniel Veillarddddeede2012-07-16 14:44:26 +08005343 xmlBufGetNodeContent(buf, tmp);
Daniel Veillard78697292003-10-19 20:44:43 +00005344 tmp = tmp->next;
5345 }
5346 break;
5347 }
5348 case XML_COMMENT_NODE:
5349 case XML_PI_NODE:
Daniel Veillarddddeede2012-07-16 14:44:26 +08005350 xmlBufCat(buf, cur->content);
Daniel Veillard78697292003-10-19 20:44:43 +00005351 break;
5352 case XML_ENTITY_REF_NODE:{
5353 xmlEntityPtr ent;
5354 xmlNodePtr tmp;
5355
5356 /* lookup entity declaration */
5357 ent = xmlGetDocEntity(cur->doc, cur->name);
5358 if (ent == NULL)
5359 return(-1);
5360
5361 /* an entity content can be any "well balanced chunk",
5362 * i.e. the result of the content [43] production:
5363 * http://www.w3.org/TR/REC-xml#NT-content
5364 * -> we iterate through child nodes and recursive call
5365 * xmlNodeGetContent() which handles all possible node types */
5366 tmp = ent->children;
5367 while (tmp) {
Daniel Veillarddddeede2012-07-16 14:44:26 +08005368 xmlBufGetNodeContent(buf, tmp);
Daniel Veillard78697292003-10-19 20:44:43 +00005369 tmp = tmp->next;
5370 }
5371 break;
5372 }
5373 case XML_ENTITY_NODE:
5374 case XML_DOCUMENT_TYPE_NODE:
5375 case XML_NOTATION_NODE:
5376 case XML_DTD_NODE:
5377 case XML_XINCLUDE_START:
5378 case XML_XINCLUDE_END:
5379 break;
5380 case XML_DOCUMENT_NODE:
5381#ifdef LIBXML_DOCB_ENABLED
5382 case XML_DOCB_DOCUMENT_NODE:
5383#endif
5384 case XML_HTML_DOCUMENT_NODE:
5385 cur = cur->children;
5386 while (cur!= NULL) {
5387 if ((cur->type == XML_ELEMENT_NODE) ||
5388 (cur->type == XML_TEXT_NODE) ||
5389 (cur->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillarddddeede2012-07-16 14:44:26 +08005390 xmlBufGetNodeContent(buf, cur);
Daniel Veillard78697292003-10-19 20:44:43 +00005391 }
5392 cur = cur->next;
5393 }
5394 break;
5395 case XML_NAMESPACE_DECL:
Daniel Veillarddddeede2012-07-16 14:44:26 +08005396 xmlBufCat(buf, ((xmlNsPtr) cur)->href);
Daniel Veillard78697292003-10-19 20:44:43 +00005397 break;
5398 case XML_ELEMENT_DECL:
5399 case XML_ATTRIBUTE_DECL:
5400 case XML_ENTITY_DECL:
5401 break;
5402 }
5403 return(0);
5404}
Daniel Veillarddddeede2012-07-16 14:44:26 +08005405
Daniel Veillard78697292003-10-19 20:44:43 +00005406/**
Owen Taylor3473f882001-02-23 17:55:21 +00005407 * xmlNodeGetContent:
5408 * @cur: the node being read
5409 *
5410 * Read the value of a node, this can be either the text carried
5411 * directly by this node if it's a TEXT node or the aggregate string
5412 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00005413 * Entity references are substituted.
5414 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005415 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005416 */
5417xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00005418xmlNodeGetContent(xmlNodePtr cur)
5419{
5420 if (cur == NULL)
5421 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005422 switch (cur->type) {
5423 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005424 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00005425 xmlBufferPtr buffer;
5426 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00005427
Daniel Veillard814a76d2003-01-23 18:24:20 +00005428 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00005429 if (buffer == NULL)
5430 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00005431 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005432 ret = buffer->content;
5433 buffer->content = NULL;
5434 xmlBufferFree(buffer);
5435 return (ret);
5436 }
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00005437 case XML_ATTRIBUTE_NODE:
5438 return(xmlGetPropNodeValueInternal((xmlAttrPtr) cur));
Owen Taylor3473f882001-02-23 17:55:21 +00005439 case XML_COMMENT_NODE:
5440 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005441 if (cur->content != NULL)
5442 return (xmlStrdup(cur->content));
5443 return (NULL);
5444 case XML_ENTITY_REF_NODE:{
5445 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00005446 xmlBufferPtr buffer;
5447 xmlChar *ret;
5448
5449 /* lookup entity declaration */
5450 ent = xmlGetDocEntity(cur->doc, cur->name);
5451 if (ent == NULL)
5452 return (NULL);
5453
5454 buffer = xmlBufferCreate();
5455 if (buffer == NULL)
5456 return (NULL);
5457
Daniel Veillardc4696922003-10-19 21:47:14 +00005458 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005459
5460 ret = buffer->content;
5461 buffer->content = NULL;
5462 xmlBufferFree(buffer);
5463 return (ret);
5464 }
Owen Taylor3473f882001-02-23 17:55:21 +00005465 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005466 case XML_DOCUMENT_TYPE_NODE:
5467 case XML_NOTATION_NODE:
5468 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005469 case XML_XINCLUDE_START:
5470 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00005471 return (NULL);
5472 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005473#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005474 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005475#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005476 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00005477 xmlBufferPtr buffer;
5478 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005479
Daniel Veillardc4696922003-10-19 21:47:14 +00005480 buffer = xmlBufferCreate();
5481 if (buffer == NULL)
5482 return (NULL);
5483
5484 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5485
5486 ret = buffer->content;
5487 buffer->content = NULL;
5488 xmlBufferFree(buffer);
5489 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005490 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005491 case XML_NAMESPACE_DECL: {
5492 xmlChar *tmp;
5493
5494 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5495 return (tmp);
5496 }
Owen Taylor3473f882001-02-23 17:55:21 +00005497 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005498 /* TODO !!! */
5499 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005500 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005501 /* TODO !!! */
5502 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005503 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005504 /* TODO !!! */
5505 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005506 case XML_CDATA_SECTION_NODE:
5507 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005508 if (cur->content != NULL)
5509 return (xmlStrdup(cur->content));
5510 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005511 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005512 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005513}
Daniel Veillard652327a2003-09-29 18:02:38 +00005514
Owen Taylor3473f882001-02-23 17:55:21 +00005515/**
5516 * xmlNodeSetContent:
5517 * @cur: the node being modified
5518 * @content: the new value of the content
5519 *
5520 * Replace the content of a node.
Daniel Veillard0e05f4c2006-11-01 15:33:04 +00005521 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
5522 * references, but XML special chars need to be escaped first by using
5523 * xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars().
Owen Taylor3473f882001-02-23 17:55:21 +00005524 */
5525void
5526xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5527 if (cur == NULL) {
5528#ifdef DEBUG_TREE
5529 xmlGenericError(xmlGenericErrorContext,
5530 "xmlNodeSetContent : node == NULL\n");
5531#endif
5532 return;
5533 }
5534 switch (cur->type) {
5535 case XML_DOCUMENT_FRAG_NODE:
5536 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005537 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005538 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5539 cur->children = xmlStringGetNodeList(cur->doc, content);
5540 UPDATE_LAST_CHILD_AND_PARENT(cur)
5541 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005542 case XML_TEXT_NODE:
5543 case XML_CDATA_SECTION_NODE:
5544 case XML_ENTITY_REF_NODE:
5545 case XML_ENTITY_NODE:
5546 case XML_PI_NODE:
5547 case XML_COMMENT_NODE:
Daniel Veillard8874b942005-08-25 13:19:21 +00005548 if ((cur->content != NULL) &&
5549 (cur->content != (xmlChar *) &(cur->properties))) {
William M. Brack7762bb12004-01-04 14:49:01 +00005550 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
Daniel Veillardc587bce2005-05-10 15:28:08 +00005551 (xmlDictOwns(cur->doc->dict, cur->content))))
William M. Brack7762bb12004-01-04 14:49:01 +00005552 xmlFree(cur->content);
Daniel Veillardaa6de472008-08-25 14:53:31 +00005553 }
Owen Taylor3473f882001-02-23 17:55:21 +00005554 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5555 cur->last = cur->children = NULL;
5556 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005557 cur->content = xmlStrdup(content);
Daniel Veillardaa6de472008-08-25 14:53:31 +00005558 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005559 cur->content = NULL;
Daniel Veillard8874b942005-08-25 13:19:21 +00005560 cur->properties = NULL;
5561 cur->nsDef = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00005562 break;
5563 case XML_DOCUMENT_NODE:
5564 case XML_HTML_DOCUMENT_NODE:
5565 case XML_DOCUMENT_TYPE_NODE:
5566 case XML_XINCLUDE_START:
5567 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005568#ifdef LIBXML_DOCB_ENABLED
5569 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005570#endif
5571 break;
5572 case XML_NOTATION_NODE:
5573 break;
5574 case XML_DTD_NODE:
5575 break;
5576 case XML_NAMESPACE_DECL:
5577 break;
5578 case XML_ELEMENT_DECL:
5579 /* TODO !!! */
5580 break;
5581 case XML_ATTRIBUTE_DECL:
5582 /* TODO !!! */
5583 break;
5584 case XML_ENTITY_DECL:
5585 /* TODO !!! */
5586 break;
5587 }
5588}
5589
Daniel Veillard652327a2003-09-29 18:02:38 +00005590#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005591/**
5592 * xmlNodeSetContentLen:
5593 * @cur: the node being modified
5594 * @content: the new value of the content
5595 * @len: the size of @content
5596 *
5597 * Replace the content of a node.
Daniel Veillard0e05f4c2006-11-01 15:33:04 +00005598 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
5599 * references, but XML special chars need to be escaped first by using
5600 * xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars().
Owen Taylor3473f882001-02-23 17:55:21 +00005601 */
5602void
5603xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5604 if (cur == NULL) {
5605#ifdef DEBUG_TREE
5606 xmlGenericError(xmlGenericErrorContext,
5607 "xmlNodeSetContentLen : node == NULL\n");
5608#endif
5609 return;
5610 }
5611 switch (cur->type) {
5612 case XML_DOCUMENT_FRAG_NODE:
5613 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005614 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005615 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5616 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5617 UPDATE_LAST_CHILD_AND_PARENT(cur)
5618 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005619 case XML_TEXT_NODE:
5620 case XML_CDATA_SECTION_NODE:
5621 case XML_ENTITY_REF_NODE:
5622 case XML_ENTITY_NODE:
5623 case XML_PI_NODE:
5624 case XML_COMMENT_NODE:
5625 case XML_NOTATION_NODE:
Daniel Veillard8874b942005-08-25 13:19:21 +00005626 if ((cur->content != NULL) &&
5627 (cur->content != (xmlChar *) &(cur->properties))) {
5628 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5629 (xmlDictOwns(cur->doc->dict, cur->content))))
5630 xmlFree(cur->content);
Daniel Veillardaa6de472008-08-25 14:53:31 +00005631 }
Owen Taylor3473f882001-02-23 17:55:21 +00005632 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5633 cur->children = cur->last = NULL;
5634 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005635 cur->content = xmlStrndup(content, len);
Daniel Veillardaa6de472008-08-25 14:53:31 +00005636 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005637 cur->content = NULL;
Daniel Veillard8874b942005-08-25 13:19:21 +00005638 cur->properties = NULL;
5639 cur->nsDef = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00005640 break;
5641 case XML_DOCUMENT_NODE:
5642 case XML_DTD_NODE:
5643 case XML_HTML_DOCUMENT_NODE:
5644 case XML_DOCUMENT_TYPE_NODE:
5645 case XML_NAMESPACE_DECL:
5646 case XML_XINCLUDE_START:
5647 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005648#ifdef LIBXML_DOCB_ENABLED
5649 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005650#endif
5651 break;
5652 case XML_ELEMENT_DECL:
5653 /* TODO !!! */
5654 break;
5655 case XML_ATTRIBUTE_DECL:
5656 /* TODO !!! */
5657 break;
5658 case XML_ENTITY_DECL:
5659 /* TODO !!! */
5660 break;
5661 }
5662}
Daniel Veillard652327a2003-09-29 18:02:38 +00005663#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005664
5665/**
5666 * xmlNodeAddContentLen:
5667 * @cur: the node being modified
5668 * @content: extra content
5669 * @len: the size of @content
Daniel Veillardaa6de472008-08-25 14:53:31 +00005670 *
Owen Taylor3473f882001-02-23 17:55:21 +00005671 * Append the extra substring to the node content.
Daniel Veillard0e05f4c2006-11-01 15:33:04 +00005672 * NOTE: In contrast to xmlNodeSetContentLen(), @content is supposed to be
5673 * raw text, so unescaped XML special chars are allowed, entity
5674 * references are not supported.
Owen Taylor3473f882001-02-23 17:55:21 +00005675 */
5676void
5677xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5678 if (cur == NULL) {
5679#ifdef DEBUG_TREE
5680 xmlGenericError(xmlGenericErrorContext,
5681 "xmlNodeAddContentLen : node == NULL\n");
5682#endif
5683 return;
5684 }
5685 if (len <= 0) return;
5686 switch (cur->type) {
5687 case XML_DOCUMENT_FRAG_NODE:
5688 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005689 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005690
Daniel Veillard7db37732001-07-12 01:20:08 +00005691 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005692 newNode = xmlNewTextLen(content, len);
5693 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005694 tmp = xmlAddChild(cur, newNode);
5695 if (tmp != newNode)
5696 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005697 if ((last != NULL) && (last->next == newNode)) {
5698 xmlTextMerge(last, newNode);
5699 }
5700 }
5701 break;
5702 }
5703 case XML_ATTRIBUTE_NODE:
5704 break;
5705 case XML_TEXT_NODE:
5706 case XML_CDATA_SECTION_NODE:
5707 case XML_ENTITY_REF_NODE:
5708 case XML_ENTITY_NODE:
5709 case XML_PI_NODE:
5710 case XML_COMMENT_NODE:
5711 case XML_NOTATION_NODE:
5712 if (content != NULL) {
Daniel Veillard8874b942005-08-25 13:19:21 +00005713 if ((cur->content == (xmlChar *) &(cur->properties)) ||
5714 ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5715 xmlDictOwns(cur->doc->dict, cur->content))) {
5716 cur->content = xmlStrncatNew(cur->content, content, len);
5717 cur->properties = NULL;
5718 cur->nsDef = NULL;
William M. Brack7762bb12004-01-04 14:49:01 +00005719 break;
5720 }
Owen Taylor3473f882001-02-23 17:55:21 +00005721 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005722 }
5723 case XML_DOCUMENT_NODE:
5724 case XML_DTD_NODE:
5725 case XML_HTML_DOCUMENT_NODE:
5726 case XML_DOCUMENT_TYPE_NODE:
5727 case XML_NAMESPACE_DECL:
5728 case XML_XINCLUDE_START:
5729 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005730#ifdef LIBXML_DOCB_ENABLED
5731 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005732#endif
5733 break;
5734 case XML_ELEMENT_DECL:
5735 case XML_ATTRIBUTE_DECL:
5736 case XML_ENTITY_DECL:
5737 break;
5738 }
5739}
5740
5741/**
5742 * xmlNodeAddContent:
5743 * @cur: the node being modified
5744 * @content: extra content
Daniel Veillardaa6de472008-08-25 14:53:31 +00005745 *
Owen Taylor3473f882001-02-23 17:55:21 +00005746 * Append the extra substring to the node content.
Daniel Veillard0e05f4c2006-11-01 15:33:04 +00005747 * NOTE: In contrast to xmlNodeSetContent(), @content is supposed to be
5748 * raw text, so unescaped XML special chars are allowed, entity
5749 * references are not supported.
Owen Taylor3473f882001-02-23 17:55:21 +00005750 */
5751void
5752xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5753 int len;
5754
5755 if (cur == NULL) {
5756#ifdef DEBUG_TREE
5757 xmlGenericError(xmlGenericErrorContext,
5758 "xmlNodeAddContent : node == NULL\n");
5759#endif
5760 return;
5761 }
5762 if (content == NULL) return;
5763 len = xmlStrlen(content);
5764 xmlNodeAddContentLen(cur, content, len);
5765}
5766
5767/**
5768 * xmlTextMerge:
5769 * @first: the first text node
5770 * @second: the second text node being merged
Daniel Veillardaa6de472008-08-25 14:53:31 +00005771 *
Owen Taylor3473f882001-02-23 17:55:21 +00005772 * Merge two text nodes into one
5773 * Returns the first text node augmented
5774 */
5775xmlNodePtr
5776xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5777 if (first == NULL) return(second);
5778 if (second == NULL) return(first);
5779 if (first->type != XML_TEXT_NODE) return(first);
5780 if (second->type != XML_TEXT_NODE) return(first);
5781 if (second->name != first->name)
5782 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005783 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005784 xmlUnlinkNode(second);
5785 xmlFreeNode(second);
5786 return(first);
5787}
5788
Daniel Veillardf1a27c62006-10-13 22:33:03 +00005789#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005790/**
5791 * xmlGetNsList:
5792 * @doc: the document
5793 * @node: the current node
5794 *
5795 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005796 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005797 * that need to be freed by the caller or NULL if no
5798 * namespace if defined
5799 */
5800xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005801xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5802{
Owen Taylor3473f882001-02-23 17:55:21 +00005803 xmlNsPtr cur;
5804 xmlNsPtr *ret = NULL;
5805 int nbns = 0;
5806 int maxns = 10;
5807 int i;
5808
5809 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005810 if (node->type == XML_ELEMENT_NODE) {
5811 cur = node->nsDef;
5812 while (cur != NULL) {
5813 if (ret == NULL) {
5814 ret =
5815 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5816 sizeof(xmlNsPtr));
5817 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005818 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005819 return (NULL);
5820 }
5821 ret[nbns] = NULL;
5822 }
5823 for (i = 0; i < nbns; i++) {
5824 if ((cur->prefix == ret[i]->prefix) ||
5825 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5826 break;
5827 }
5828 if (i >= nbns) {
5829 if (nbns >= maxns) {
5830 maxns *= 2;
5831 ret = (xmlNsPtr *) xmlRealloc(ret,
5832 (maxns +
5833 1) *
5834 sizeof(xmlNsPtr));
5835 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005836 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005837 return (NULL);
5838 }
5839 }
5840 ret[nbns++] = cur;
5841 ret[nbns] = NULL;
5842 }
Owen Taylor3473f882001-02-23 17:55:21 +00005843
Daniel Veillard77044732001-06-29 21:31:07 +00005844 cur = cur->next;
5845 }
5846 }
5847 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005848 }
Daniel Veillard77044732001-06-29 21:31:07 +00005849 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005850}
Daniel Veillard652327a2003-09-29 18:02:38 +00005851#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005852
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00005853/*
5854* xmlTreeEnsureXMLDecl:
5855* @doc: the doc
Daniel Veillardaa6de472008-08-25 14:53:31 +00005856*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00005857* Ensures that there is an XML namespace declaration on the doc.
Daniel Veillardaa6de472008-08-25 14:53:31 +00005858*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00005859* Returns the XML ns-struct or NULL on API and internal errors.
5860*/
5861static xmlNsPtr
5862xmlTreeEnsureXMLDecl(xmlDocPtr doc)
5863{
5864 if (doc == NULL)
5865 return (NULL);
5866 if (doc->oldNs != NULL)
5867 return (doc->oldNs);
5868 {
5869 xmlNsPtr ns;
5870 ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5871 if (ns == NULL) {
5872 xmlTreeErrMemory(
5873 "allocating the XML namespace");
5874 return (NULL);
5875 }
5876 memset(ns, 0, sizeof(xmlNs));
5877 ns->type = XML_LOCAL_NAMESPACE;
Daniel Veillardaa6de472008-08-25 14:53:31 +00005878 ns->href = xmlStrdup(XML_XML_NAMESPACE);
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00005879 ns->prefix = xmlStrdup((const xmlChar *)"xml");
5880 doc->oldNs = ns;
5881 return (ns);
5882 }
5883}
5884
Owen Taylor3473f882001-02-23 17:55:21 +00005885/**
5886 * xmlSearchNs:
5887 * @doc: the document
5888 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005889 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005890 *
5891 * Search a Ns registered under a given name space for a document.
5892 * recurse on the parents until it finds the defined namespace
5893 * or return NULL otherwise.
5894 * @nameSpace can be NULL, this is a search for the default namespace.
5895 * We don't allow to cross entities boundaries. If you don't declare
5896 * the namespace within those you will be in troubles !!! A warning
5897 * is generated to cover this case.
5898 *
5899 * Returns the namespace pointer or NULL.
5900 */
5901xmlNsPtr
5902xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00005903
Owen Taylor3473f882001-02-23 17:55:21 +00005904 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005905 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005906
5907 if (node == NULL) return(NULL);
5908 if ((nameSpace != NULL) &&
5909 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005910 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5911 /*
5912 * The XML-1.0 namespace is normally held on the root
5913 * element. In this case exceptionally create it on the
5914 * node element.
5915 */
5916 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5917 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005918 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005919 return(NULL);
5920 }
5921 memset(cur, 0, sizeof(xmlNs));
5922 cur->type = XML_LOCAL_NAMESPACE;
Daniel Veillardaa6de472008-08-25 14:53:31 +00005923 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5924 cur->prefix = xmlStrdup((const xmlChar *)"xml");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005925 cur->next = node->nsDef;
5926 node->nsDef = cur;
5927 return(cur);
5928 }
Daniel Veillard11ce4002006-03-10 00:36:23 +00005929 if (doc == NULL) {
5930 doc = node->doc;
5931 if (doc == NULL)
5932 return(NULL);
5933 }
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00005934 /*
5935 * Return the XML namespace declaration held by the doc.
5936 */
5937 if (doc->oldNs == NULL)
5938 return(xmlTreeEnsureXMLDecl(doc));
5939 else
5940 return(doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005941 }
5942 while (node != NULL) {
5943 if ((node->type == XML_ENTITY_REF_NODE) ||
5944 (node->type == XML_ENTITY_NODE) ||
5945 (node->type == XML_ENTITY_DECL))
5946 return(NULL);
5947 if (node->type == XML_ELEMENT_NODE) {
5948 cur = node->nsDef;
5949 while (cur != NULL) {
5950 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5951 (cur->href != NULL))
5952 return(cur);
5953 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5954 (cur->href != NULL) &&
5955 (xmlStrEqual(cur->prefix, nameSpace)))
5956 return(cur);
5957 cur = cur->next;
5958 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00005959 if (orig != node) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005960 cur = node->ns;
5961 if (cur != NULL) {
5962 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5963 (cur->href != NULL))
5964 return(cur);
5965 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5966 (cur->href != NULL) &&
5967 (xmlStrEqual(cur->prefix, nameSpace)))
5968 return(cur);
5969 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00005970 }
Owen Taylor3473f882001-02-23 17:55:21 +00005971 }
5972 node = node->parent;
5973 }
5974 return(NULL);
5975}
5976
5977/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005978 * xmlNsInScope:
5979 * @doc: the document
5980 * @node: the current node
5981 * @ancestor: the ancestor carrying the namespace
5982 * @prefix: the namespace prefix
5983 *
5984 * Verify that the given namespace held on @ancestor is still in scope
5985 * on node.
Daniel Veillardaa6de472008-08-25 14:53:31 +00005986 *
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005987 * Returns 1 if true, 0 if false and -1 in case of error.
5988 */
5989static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005990xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5991 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005992{
5993 xmlNsPtr tst;
5994
5995 while ((node != NULL) && (node != ancestor)) {
5996 if ((node->type == XML_ENTITY_REF_NODE) ||
5997 (node->type == XML_ENTITY_NODE) ||
5998 (node->type == XML_ENTITY_DECL))
5999 return (-1);
6000 if (node->type == XML_ELEMENT_NODE) {
6001 tst = node->nsDef;
6002 while (tst != NULL) {
6003 if ((tst->prefix == NULL)
6004 && (prefix == NULL))
6005 return (0);
6006 if ((tst->prefix != NULL)
6007 && (prefix != NULL)
6008 && (xmlStrEqual(tst->prefix, prefix)))
6009 return (0);
6010 tst = tst->next;
6011 }
6012 }
6013 node = node->parent;
6014 }
6015 if (node != ancestor)
6016 return (-1);
6017 return (1);
6018}
Daniel Veillardaa6de472008-08-25 14:53:31 +00006019
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006020/**
Owen Taylor3473f882001-02-23 17:55:21 +00006021 * xmlSearchNsByHref:
6022 * @doc: the document
6023 * @node: the current node
6024 * @href: the namespace value
6025 *
6026 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
6027 * the defined namespace or return NULL otherwise.
6028 * Returns the namespace pointer or NULL.
6029 */
6030xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006031xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
6032{
Owen Taylor3473f882001-02-23 17:55:21 +00006033 xmlNsPtr cur;
6034 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00006035 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00006036
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006037 if ((node == NULL) || (href == NULL))
6038 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006039 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006040 /*
6041 * Only the document can hold the XML spec namespace.
6042 */
6043 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
6044 /*
6045 * The XML-1.0 namespace is normally held on the root
6046 * element. In this case exceptionally create it on the
6047 * node element.
6048 */
6049 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
6050 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006051 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006052 return (NULL);
6053 }
6054 memset(cur, 0, sizeof(xmlNs));
6055 cur->type = XML_LOCAL_NAMESPACE;
6056 cur->href = xmlStrdup(XML_XML_NAMESPACE);
6057 cur->prefix = xmlStrdup((const xmlChar *) "xml");
6058 cur->next = node->nsDef;
6059 node->nsDef = cur;
6060 return (cur);
6061 }
Daniel Veillard11ce4002006-03-10 00:36:23 +00006062 if (doc == NULL) {
6063 doc = node->doc;
6064 if (doc == NULL)
6065 return(NULL);
6066 }
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00006067 /*
6068 * Return the XML namespace declaration held by the doc.
6069 */
6070 if (doc->oldNs == NULL)
6071 return(xmlTreeEnsureXMLDecl(doc));
6072 else
Daniel Veillardaa6de472008-08-25 14:53:31 +00006073 return(doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00006074 }
Daniel Veillard62040be2004-05-17 03:17:26 +00006075 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00006076 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006077 if ((node->type == XML_ENTITY_REF_NODE) ||
6078 (node->type == XML_ENTITY_NODE) ||
6079 (node->type == XML_ENTITY_DECL))
6080 return (NULL);
6081 if (node->type == XML_ELEMENT_NODE) {
6082 cur = node->nsDef;
6083 while (cur != NULL) {
6084 if ((cur->href != NULL) && (href != NULL) &&
6085 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00006086 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00006087 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006088 return (cur);
6089 }
6090 cur = cur->next;
6091 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00006092 if (orig != node) {
6093 cur = node->ns;
6094 if (cur != NULL) {
6095 if ((cur->href != NULL) && (href != NULL) &&
6096 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00006097 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00006098 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00006099 return (cur);
6100 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006101 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00006102 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006103 }
6104 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00006105 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006106 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006107}
6108
6109/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006110 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00006111 * @doc: the document
6112 * @tree: a node expected to hold the new namespace
6113 * @ns: the original namespace
6114 *
6115 * This function tries to locate a namespace definition in a tree
6116 * ancestors, or create a new namespace definition node similar to
6117 * @ns trying to reuse the same prefix. However if the given prefix is
6118 * null (default namespace) or reused within the subtree defined by
6119 * @tree or on one of its ancestors then a new prefix is generated.
6120 * Returns the (new) namespace definition or NULL in case of error
6121 */
Daniel Veillard8ed10722009-08-20 19:17:36 +02006122static xmlNsPtr
Owen Taylor3473f882001-02-23 17:55:21 +00006123xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
6124 xmlNsPtr def;
6125 xmlChar prefix[50];
6126 int counter = 1;
6127
6128 if (tree == NULL) {
6129#ifdef DEBUG_TREE
6130 xmlGenericError(xmlGenericErrorContext,
6131 "xmlNewReconciliedNs : tree == NULL\n");
6132#endif
6133 return(NULL);
6134 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00006135 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006136#ifdef DEBUG_TREE
6137 xmlGenericError(xmlGenericErrorContext,
6138 "xmlNewReconciliedNs : ns == NULL\n");
6139#endif
6140 return(NULL);
6141 }
6142 /*
6143 * Search an existing namespace definition inherited.
6144 */
6145 def = xmlSearchNsByHref(doc, tree, ns->href);
6146 if (def != NULL)
6147 return(def);
6148
6149 /*
6150 * Find a close prefix which is not already in use.
6151 * Let's strip namespace prefixes longer than 20 chars !
6152 */
Daniel Veillardf742d342002-03-07 00:05:35 +00006153 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00006154 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00006155 else
William M. Brack13dfa872004-09-18 04:52:08 +00006156 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00006157
Owen Taylor3473f882001-02-23 17:55:21 +00006158 def = xmlSearchNs(doc, tree, prefix);
6159 while (def != NULL) {
6160 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00006161 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00006162 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00006163 else
William M. Brack13dfa872004-09-18 04:52:08 +00006164 snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
Daniel Veillardaa6de472008-08-25 14:53:31 +00006165 (char *)ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00006166 def = xmlSearchNs(doc, tree, prefix);
6167 }
6168
6169 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00006170 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00006171 */
6172 def = xmlNewNs(tree, ns->href, prefix);
6173 return(def);
6174}
6175
Daniel Veillard652327a2003-09-29 18:02:38 +00006176#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00006177/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006178 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00006179 * @doc: the document
6180 * @tree: a node defining the subtree to reconciliate
6181 *
6182 * This function checks that all the namespaces declared within the given
6183 * tree are properly declared. This is needed for example after Copy or Cut
6184 * and then paste operations. The subtree may still hold pointers to
6185 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00006186 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00006187 * the new environment. If not possible the new namespaces are redeclared
6188 * on @tree at the top of the given subtree.
6189 * Returns the number of namespace declarations created or -1 in case of error.
6190 */
6191int
6192xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
6193 xmlNsPtr *oldNs = NULL;
6194 xmlNsPtr *newNs = NULL;
6195 int sizeCache = 0;
6196 int nbCache = 0;
6197
6198 xmlNsPtr n;
6199 xmlNodePtr node = tree;
6200 xmlAttrPtr attr;
6201 int ret = 0, i;
6202
Daniel Veillardce244ad2004-11-05 10:03:46 +00006203 if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1);
6204 if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1);
6205 if (node->doc != doc) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006206 while (node != NULL) {
6207 /*
6208 * Reconciliate the node namespace
6209 */
6210 if (node->ns != NULL) {
6211 /*
6212 * initialize the cache if needed
6213 */
6214 if (sizeCache == 0) {
6215 sizeCache = 10;
6216 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
6217 sizeof(xmlNsPtr));
6218 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006219 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00006220 return(-1);
6221 }
6222 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
6223 sizeof(xmlNsPtr));
6224 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006225 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00006226 xmlFree(oldNs);
6227 return(-1);
6228 }
6229 }
6230 for (i = 0;i < nbCache;i++) {
6231 if (oldNs[i] == node->ns) {
6232 node->ns = newNs[i];
6233 break;
6234 }
6235 }
6236 if (i == nbCache) {
6237 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00006238 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00006239 */
6240 n = xmlNewReconciliedNs(doc, tree, node->ns);
6241 if (n != NULL) { /* :-( what if else ??? */
6242 /*
6243 * check if we need to grow the cache buffers.
6244 */
6245 if (sizeCache <= nbCache) {
6246 sizeCache *= 2;
6247 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
6248 sizeof(xmlNsPtr));
6249 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006250 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00006251 xmlFree(newNs);
6252 return(-1);
6253 }
6254 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
6255 sizeof(xmlNsPtr));
6256 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006257 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00006258 xmlFree(oldNs);
6259 return(-1);
6260 }
6261 }
6262 newNs[nbCache] = n;
6263 oldNs[nbCache++] = node->ns;
6264 node->ns = n;
6265 }
6266 }
6267 }
6268 /*
6269 * now check for namespace hold by attributes on the node.
6270 */
Daniel Veillardb5f11972006-10-14 08:46:40 +00006271 if (node->type == XML_ELEMENT_NODE) {
6272 attr = node->properties;
6273 while (attr != NULL) {
6274 if (attr->ns != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006275 /*
Daniel Veillardb5f11972006-10-14 08:46:40 +00006276 * initialize the cache if needed
Owen Taylor3473f882001-02-23 17:55:21 +00006277 */
Daniel Veillardb5f11972006-10-14 08:46:40 +00006278 if (sizeCache == 0) {
6279 sizeCache = 10;
6280 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
6281 sizeof(xmlNsPtr));
6282 if (oldNs == NULL) {
6283 xmlTreeErrMemory("fixing namespaces");
6284 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006285 }
Daniel Veillardb5f11972006-10-14 08:46:40 +00006286 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
6287 sizeof(xmlNsPtr));
6288 if (newNs == NULL) {
6289 xmlTreeErrMemory("fixing namespaces");
6290 xmlFree(oldNs);
6291 return(-1);
6292 }
6293 }
6294 for (i = 0;i < nbCache;i++) {
6295 if (oldNs[i] == attr->ns) {
6296 attr->ns = newNs[i];
6297 break;
6298 }
6299 }
6300 if (i == nbCache) {
6301 /*
6302 * OK we need to recreate a new namespace definition
6303 */
6304 n = xmlNewReconciliedNs(doc, tree, attr->ns);
6305 if (n != NULL) { /* :-( what if else ??? */
6306 /*
6307 * check if we need to grow the cache buffers.
6308 */
6309 if (sizeCache <= nbCache) {
6310 sizeCache *= 2;
6311 oldNs = (xmlNsPtr *) xmlRealloc(oldNs,
6312 sizeCache * sizeof(xmlNsPtr));
6313 if (oldNs == NULL) {
6314 xmlTreeErrMemory("fixing namespaces");
6315 xmlFree(newNs);
6316 return(-1);
6317 }
6318 newNs = (xmlNsPtr *) xmlRealloc(newNs,
6319 sizeCache * sizeof(xmlNsPtr));
6320 if (newNs == NULL) {
6321 xmlTreeErrMemory("fixing namespaces");
6322 xmlFree(oldNs);
6323 return(-1);
6324 }
6325 }
6326 newNs[nbCache] = n;
6327 oldNs[nbCache++] = attr->ns;
6328 attr->ns = n;
6329 }
Owen Taylor3473f882001-02-23 17:55:21 +00006330 }
6331 }
Daniel Veillardb5f11972006-10-14 08:46:40 +00006332 attr = attr->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006333 }
Owen Taylor3473f882001-02-23 17:55:21 +00006334 }
6335
6336 /*
6337 * Browse the full subtree, deep first
6338 */
Daniel Veillardb5f11972006-10-14 08:46:40 +00006339 if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006340 /* deep first */
6341 node = node->children;
6342 } else if ((node != tree) && (node->next != NULL)) {
6343 /* then siblings */
6344 node = node->next;
6345 } else if (node != tree) {
6346 /* go up to parents->next if needed */
6347 while (node != tree) {
6348 if (node->parent != NULL)
6349 node = node->parent;
6350 if ((node != tree) && (node->next != NULL)) {
6351 node = node->next;
6352 break;
6353 }
6354 if (node->parent == NULL) {
6355 node = NULL;
6356 break;
6357 }
6358 }
6359 /* exit condition */
Daniel Veillardaa6de472008-08-25 14:53:31 +00006360 if (node == tree)
Owen Taylor3473f882001-02-23 17:55:21 +00006361 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00006362 } else
6363 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006364 }
Daniel Veillardf742d342002-03-07 00:05:35 +00006365 if (oldNs != NULL)
6366 xmlFree(oldNs);
6367 if (newNs != NULL)
6368 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00006369 return(ret);
6370}
Daniel Veillard652327a2003-09-29 18:02:38 +00006371#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00006372
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006373static xmlAttrPtr
6374xmlGetPropNodeInternal(xmlNodePtr node, const xmlChar *name,
6375 const xmlChar *nsName, int useDTD)
6376{
6377 xmlAttrPtr prop;
6378
6379 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6380 return(NULL);
6381
6382 if (node->properties != NULL) {
6383 prop = node->properties;
6384 if (nsName == NULL) {
6385 /*
6386 * We want the attr to be in no namespace.
6387 */
6388 do {
6389 if ((prop->ns == NULL) && xmlStrEqual(prop->name, name)) {
6390 return(prop);
6391 }
6392 prop = prop->next;
6393 } while (prop != NULL);
6394 } else {
6395 /*
6396 * We want the attr to be in the specified namespace.
6397 */
6398 do {
6399 if ((prop->ns != NULL) && xmlStrEqual(prop->name, name) &&
6400 ((prop->ns->href == nsName) ||
6401 xmlStrEqual(prop->ns->href, nsName)))
6402 {
6403 return(prop);
6404 }
6405 prop = prop->next;
6406 } while (prop != NULL);
6407 }
6408 }
6409
6410#ifdef LIBXML_TREE_ENABLED
6411 if (! useDTD)
6412 return(NULL);
6413 /*
6414 * Check if there is a default/fixed attribute declaration in
6415 * the internal or external subset.
Daniel Veillardaa6de472008-08-25 14:53:31 +00006416 */
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006417 if ((node->doc != NULL) && (node->doc->intSubset != NULL)) {
6418 xmlDocPtr doc = node->doc;
6419 xmlAttributePtr attrDecl = NULL;
6420 xmlChar *elemQName, *tmpstr = NULL;
6421
6422 /*
Daniel Veillardaa6de472008-08-25 14:53:31 +00006423 * We need the QName of the element for the DTD-lookup.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006424 */
6425 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
6426 tmpstr = xmlStrdup(node->ns->prefix);
6427 tmpstr = xmlStrcat(tmpstr, BAD_CAST ":");
6428 tmpstr = xmlStrcat(tmpstr, node->name);
6429 if (tmpstr == NULL)
6430 return(NULL);
6431 elemQName = tmpstr;
6432 } else
6433 elemQName = (xmlChar *) node->name;
6434 if (nsName == NULL) {
6435 /*
6436 * The common and nice case: Attr in no namespace.
6437 */
6438 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset,
6439 elemQName, name, NULL);
6440 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
6441 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset,
6442 elemQName, name, NULL);
6443 }
6444 } else {
6445 xmlNsPtr *nsList, *cur;
6446
6447 /*
6448 * The ugly case: Search using the prefixes of in-scope
6449 * ns-decls corresponding to @nsName.
6450 */
6451 nsList = xmlGetNsList(node->doc, node);
6452 if (nsList == NULL) {
6453 if (tmpstr != NULL)
6454 xmlFree(tmpstr);
6455 return(NULL);
6456 }
6457 cur = nsList;
6458 while (*cur != NULL) {
6459 if (xmlStrEqual((*cur)->href, nsName)) {
6460 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elemQName,
6461 name, (*cur)->prefix);
6462 if (attrDecl)
6463 break;
6464 if (doc->extSubset != NULL) {
6465 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elemQName,
6466 name, (*cur)->prefix);
6467 if (attrDecl)
6468 break;
6469 }
6470 }
6471 cur++;
6472 }
6473 xmlFree(nsList);
Daniel Veillardaa6de472008-08-25 14:53:31 +00006474 }
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006475 if (tmpstr != NULL)
6476 xmlFree(tmpstr);
6477 /*
6478 * Only default/fixed attrs are relevant.
6479 */
6480 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6481 return((xmlAttrPtr) attrDecl);
6482 }
6483#endif /* LIBXML_TREE_ENABLED */
6484 return(NULL);
6485}
6486
6487static xmlChar*
6488xmlGetPropNodeValueInternal(xmlAttrPtr prop)
6489{
6490 if (prop == NULL)
6491 return(NULL);
6492 if (prop->type == XML_ATTRIBUTE_NODE) {
6493 /*
6494 * Note that we return at least the empty string.
6495 * TODO: Do we really always want that?
6496 */
6497 if (prop->children != NULL) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00006498 if ((prop->children->next == NULL) &&
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006499 ((prop->children->type == XML_TEXT_NODE) ||
6500 (prop->children->type == XML_CDATA_SECTION_NODE)))
6501 {
6502 /*
6503 * Optimization for the common case: only 1 text node.
6504 */
6505 return(xmlStrdup(prop->children->content));
6506 } else {
6507 xmlChar *ret;
6508
6509 ret = xmlNodeListGetString(prop->doc, prop->children, 1);
6510 if (ret != NULL)
6511 return(ret);
6512 }
6513 }
6514 return(xmlStrdup((xmlChar *)""));
6515 } else if (prop->type == XML_ATTRIBUTE_DECL) {
6516 return(xmlStrdup(((xmlAttributePtr)prop)->defaultValue));
6517 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00006518 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006519}
6520
Owen Taylor3473f882001-02-23 17:55:21 +00006521/**
6522 * xmlHasProp:
6523 * @node: the node
6524 * @name: the attribute name
6525 *
6526 * Search an attribute associated to a node
6527 * This function also looks in DTD attribute declaration for #FIXED or
6528 * default declaration values unless DTD use has been turned off.
6529 *
Daniel Veillardaa6de472008-08-25 14:53:31 +00006530 * Returns the attribute or the attribute declaration or NULL if
Owen Taylor3473f882001-02-23 17:55:21 +00006531 * neither was found.
6532 */
6533xmlAttrPtr
6534xmlHasProp(xmlNodePtr node, const xmlChar *name) {
6535 xmlAttrPtr prop;
6536 xmlDocPtr doc;
6537
Daniel Veillard8874b942005-08-25 13:19:21 +00006538 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6539 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006540 /*
6541 * Check on the properties attached to the node
6542 */
6543 prop = node->properties;
6544 while (prop != NULL) {
6545 if (xmlStrEqual(prop->name, name)) {
6546 return(prop);
6547 }
6548 prop = prop->next;
6549 }
6550 if (!xmlCheckDTD) return(NULL);
6551
6552 /*
6553 * Check if there is a default declaration in the internal
6554 * or external subsets
6555 */
6556 doc = node->doc;
6557 if (doc != NULL) {
6558 xmlAttributePtr attrDecl;
6559 if (doc->intSubset != NULL) {
6560 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6561 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6562 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006563 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6564 /* return attribute declaration only if a default value is given
6565 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006566 return((xmlAttrPtr) attrDecl);
6567 }
6568 }
6569 return(NULL);
6570}
6571
6572/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00006573 * xmlHasNsProp:
6574 * @node: the node
6575 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006576 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00006577 *
6578 * Search for an attribute associated to a node
6579 * This attribute has to be anchored in the namespace specified.
6580 * This does the entity substitution.
6581 * This function looks in DTD attribute declaration for #FIXED or
6582 * default declaration values unless DTD use has been turned off.
William M. Brack2c228442004-10-03 04:10:00 +00006583 * Note that a namespace of NULL indicates to use the default namespace.
Daniel Veillarde95e2392001-06-06 10:46:28 +00006584 *
6585 * Returns the attribute or the attribute declaration or NULL
6586 * if neither was found.
6587 */
6588xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00006589xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00006590
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006591 return(xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD));
Daniel Veillarde95e2392001-06-06 10:46:28 +00006592}
6593
6594/**
Owen Taylor3473f882001-02-23 17:55:21 +00006595 * xmlGetProp:
6596 * @node: the node
6597 * @name: the attribute name
6598 *
6599 * Search and get the value of an attribute associated to a node
6600 * This does the entity substitution.
6601 * This function looks in DTD attribute declaration for #FIXED or
6602 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00006603 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00006604 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6605 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00006606 *
6607 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006608 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006609 */
6610xmlChar *
6611xmlGetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00006612 xmlAttrPtr prop;
Owen Taylor3473f882001-02-23 17:55:21 +00006613
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006614 prop = xmlHasProp(node, name);
6615 if (prop == NULL)
6616 return(NULL);
Daniel Veillardaa6de472008-08-25 14:53:31 +00006617 return(xmlGetPropNodeValueInternal(prop));
Owen Taylor3473f882001-02-23 17:55:21 +00006618}
6619
6620/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006621 * xmlGetNoNsProp:
6622 * @node: the node
6623 * @name: the attribute name
6624 *
6625 * Search and get the value of an attribute associated to a node
6626 * This does the entity substitution.
6627 * This function looks in DTD attribute declaration for #FIXED or
6628 * default declaration values unless DTD use has been turned off.
6629 * This function is similar to xmlGetProp except it will accept only
6630 * an attribute in no namespace.
6631 *
6632 * Returns the attribute value or NULL if not found.
6633 * It's up to the caller to free the memory with xmlFree().
6634 */
6635xmlChar *
6636xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6637 xmlAttrPtr prop;
Daniel Veillardaa6de472008-08-25 14:53:31 +00006638
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006639 prop = xmlGetPropNodeInternal(node, name, NULL, xmlCheckDTD);
6640 if (prop == NULL)
Daniel Veillard8874b942005-08-25 13:19:21 +00006641 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006642 return(xmlGetPropNodeValueInternal(prop));
Daniel Veillard71531f32003-02-05 13:19:53 +00006643}
6644
6645/**
Owen Taylor3473f882001-02-23 17:55:21 +00006646 * xmlGetNsProp:
6647 * @node: the node
6648 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006649 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006650 *
6651 * Search and get the value of an attribute associated to a node
6652 * This attribute has to be anchored in the namespace specified.
6653 * This does the entity substitution.
6654 * This function looks in DTD attribute declaration for #FIXED or
6655 * default declaration values unless DTD use has been turned off.
6656 *
6657 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006658 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006659 */
6660xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006661xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006662 xmlAttrPtr prop;
Owen Taylor3473f882001-02-23 17:55:21 +00006663
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006664 prop = xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD);
6665 if (prop == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006666 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006667 return(xmlGetPropNodeValueInternal(prop));
Owen Taylor3473f882001-02-23 17:55:21 +00006668}
6669
Daniel Veillard2156d432004-03-04 15:59:36 +00006670#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6671/**
6672 * xmlUnsetProp:
6673 * @node: the node
6674 * @name: the attribute name
6675 *
6676 * Remove an attribute carried by a node.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006677 * This handles only attributes in no namespace.
Daniel Veillard2156d432004-03-04 15:59:36 +00006678 * Returns 0 if successful, -1 if not found
6679 */
6680int
6681xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Kasimier T. Buchcik65c2f1d2005-10-17 12:39:58 +00006682 xmlAttrPtr prop;
Daniel Veillard2156d432004-03-04 15:59:36 +00006683
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006684 prop = xmlGetPropNodeInternal(node, name, NULL, 0);
6685 if (prop == NULL)
Daniel Veillard2156d432004-03-04 15:59:36 +00006686 return(-1);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006687 xmlUnlinkNode((xmlNodePtr) prop);
6688 xmlFreeProp(prop);
6689 return(0);
Daniel Veillard2156d432004-03-04 15:59:36 +00006690}
6691
6692/**
6693 * xmlUnsetNsProp:
6694 * @node: the node
6695 * @ns: the namespace definition
6696 * @name: the attribute name
6697 *
6698 * Remove an attribute carried by a node.
6699 * Returns 0 if successful, -1 if not found
6700 */
6701int
6702xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
Kasimier T. Buchcik65c2f1d2005-10-17 12:39:58 +00006703 xmlAttrPtr prop;
Daniel Veillardaa6de472008-08-25 14:53:31 +00006704
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006705 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
6706 if (prop == NULL)
Daniel Veillard2156d432004-03-04 15:59:36 +00006707 return(-1);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006708 xmlUnlinkNode((xmlNodePtr) prop);
6709 xmlFreeProp(prop);
6710 return(0);
Daniel Veillard2156d432004-03-04 15:59:36 +00006711}
6712#endif
6713
6714#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006715/**
6716 * xmlSetProp:
6717 * @node: the node
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006718 * @name: the attribute name (a QName)
Owen Taylor3473f882001-02-23 17:55:21 +00006719 * @value: the attribute value
6720 *
6721 * Set (or reset) an attribute carried by a node.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006722 * If @name has a prefix, then the corresponding
6723 * namespace-binding will be used, if in scope; it is an
6724 * error it there's no such ns-binding for the prefix in
6725 * scope.
Owen Taylor3473f882001-02-23 17:55:21 +00006726 * Returns the attribute pointer.
Daniel Veillardaa6de472008-08-25 14:53:31 +00006727 *
Owen Taylor3473f882001-02-23 17:55:21 +00006728 */
6729xmlAttrPtr
6730xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006731 int len;
6732 const xmlChar *nqname;
Owen Taylor3473f882001-02-23 17:55:21 +00006733
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006734 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006735 return(NULL);
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006736
6737 /*
6738 * handle QNames
6739 */
6740 nqname = xmlSplitQName3(name, &len);
6741 if (nqname != NULL) {
6742 xmlNsPtr ns;
6743 xmlChar *prefix = xmlStrndup(name, len);
6744 ns = xmlSearchNs(node->doc, node, prefix);
6745 if (prefix != NULL)
6746 xmlFree(prefix);
6747 if (ns != NULL)
6748 return(xmlSetNsProp(node, ns, nqname, value));
6749 }
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006750 return(xmlSetNsProp(node, NULL, name, value));
Owen Taylor3473f882001-02-23 17:55:21 +00006751}
6752
6753/**
6754 * xmlSetNsProp:
6755 * @node: the node
6756 * @ns: the namespace definition
6757 * @name: the attribute name
6758 * @value: the attribute value
6759 *
6760 * Set (or reset) an attribute carried by a node.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006761 * The ns structure must be in scope, this is not checked
Owen Taylor3473f882001-02-23 17:55:21 +00006762 *
6763 * Returns the attribute pointer.
6764 */
6765xmlAttrPtr
6766xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006767 const xmlChar *value)
6768{
Owen Taylor3473f882001-02-23 17:55:21 +00006769 xmlAttrPtr prop;
Daniel Veillardaa6de472008-08-25 14:53:31 +00006770
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006771 if (ns && (ns->href == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006772 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006773 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
6774 if (prop != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006775 /*
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006776 * Modify the attribute's value.
6777 */
6778 if (prop->atype == XML_ATTRIBUTE_ID) {
6779 xmlRemoveID(node->doc, prop);
6780 prop->atype = XML_ATTRIBUTE_ID;
6781 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00006782 if (prop->children != NULL)
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006783 xmlFreeNodeList(prop->children);
6784 prop->children = NULL;
6785 prop->last = NULL;
6786 prop->ns = ns;
6787 if (value != NULL) {
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006788 xmlNodePtr tmp;
Daniel Veillardaa6de472008-08-25 14:53:31 +00006789
Daniel Veillard6f8611f2008-02-15 08:33:21 +00006790 if(!xmlCheckUTF8(value)) {
6791 xmlTreeErr(XML_TREE_NOT_UTF8, (xmlNodePtr) node->doc,
6792 NULL);
6793 if (node->doc != NULL)
6794 node->doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
6795 }
6796 prop->children = xmlNewDocText(node->doc, value);
Owen Taylor3473f882001-02-23 17:55:21 +00006797 prop->last = NULL;
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006798 tmp = prop->children;
6799 while (tmp != NULL) {
6800 tmp->parent = (xmlNodePtr) prop;
6801 if (tmp->next == NULL)
6802 prop->last = tmp;
6803 tmp = tmp->next;
6804 }
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006805 }
6806 if (prop->atype == XML_ATTRIBUTE_ID)
6807 xmlAddID(NULL, node->doc, value, prop);
6808 return(prop);
Owen Taylor3473f882001-02-23 17:55:21 +00006809 }
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006810 /*
6811 * No equal attr found; create a new one.
6812 */
6813 return(xmlNewPropInternal(node, ns, name, value, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006814}
6815
Daniel Veillard652327a2003-09-29 18:02:38 +00006816#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006817
6818/**
Owen Taylor3473f882001-02-23 17:55:21 +00006819 * xmlNodeIsText:
6820 * @node: the node
Daniel Veillardaa6de472008-08-25 14:53:31 +00006821 *
Owen Taylor3473f882001-02-23 17:55:21 +00006822 * Is this node a Text node ?
6823 * Returns 1 yes, 0 no
6824 */
6825int
6826xmlNodeIsText(xmlNodePtr node) {
6827 if (node == NULL) return(0);
6828
6829 if (node->type == XML_TEXT_NODE) return(1);
6830 return(0);
6831}
6832
6833/**
6834 * xmlIsBlankNode:
6835 * @node: the node
Daniel Veillardaa6de472008-08-25 14:53:31 +00006836 *
Owen Taylor3473f882001-02-23 17:55:21 +00006837 * Checks whether this node is an empty or whitespace only
6838 * (and possibly ignorable) text-node.
6839 *
6840 * Returns 1 yes, 0 no
6841 */
6842int
6843xmlIsBlankNode(xmlNodePtr node) {
6844 const xmlChar *cur;
6845 if (node == NULL) return(0);
6846
Daniel Veillard7db37732001-07-12 01:20:08 +00006847 if ((node->type != XML_TEXT_NODE) &&
6848 (node->type != XML_CDATA_SECTION_NODE))
6849 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006850 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006851 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006852 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006853 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006854 cur++;
6855 }
6856
6857 return(1);
6858}
6859
6860/**
6861 * xmlTextConcat:
6862 * @node: the node
6863 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006864 * @len: @content length
Daniel Veillardaa6de472008-08-25 14:53:31 +00006865 *
Owen Taylor3473f882001-02-23 17:55:21 +00006866 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006867 *
6868 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006869 */
6870
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006871int
Owen Taylor3473f882001-02-23 17:55:21 +00006872xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006873 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006874
6875 if ((node->type != XML_TEXT_NODE) &&
Rob Richardsa02f1992006-09-16 14:04:26 +00006876 (node->type != XML_CDATA_SECTION_NODE) &&
6877 (node->type != XML_COMMENT_NODE) &&
6878 (node->type != XML_PI_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006879#ifdef DEBUG_TREE
6880 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006881 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006882#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006883 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006884 }
William M. Brack7762bb12004-01-04 14:49:01 +00006885 /* need to check if content is currently in the dictionary */
Daniel Veillard8874b942005-08-25 13:19:21 +00006886 if ((node->content == (xmlChar *) &(node->properties)) ||
6887 ((node->doc != NULL) && (node->doc->dict != NULL) &&
6888 xmlDictOwns(node->doc->dict, node->content))) {
William M. Brack7762bb12004-01-04 14:49:01 +00006889 node->content = xmlStrncatNew(node->content, content, len);
6890 } else {
6891 node->content = xmlStrncat(node->content, content, len);
6892 }
Daniel Veillard8874b942005-08-25 13:19:21 +00006893 node->properties = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006894 if (node->content == NULL)
6895 return(-1);
6896 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006897}
6898
6899/************************************************************************
6900 * *
6901 * Output : to a FILE or in memory *
6902 * *
6903 ************************************************************************/
6904
Owen Taylor3473f882001-02-23 17:55:21 +00006905/**
6906 * xmlBufferCreate:
6907 *
6908 * routine to create an XML buffer.
6909 * returns the new structure.
6910 */
6911xmlBufferPtr
6912xmlBufferCreate(void) {
6913 xmlBufferPtr ret;
6914
6915 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6916 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006917 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006918 return(NULL);
6919 }
6920 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006921 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006922 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006923 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006924 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006925 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006926 xmlFree(ret);
6927 return(NULL);
6928 }
6929 ret->content[0] = 0;
Daniel Veillarde83e93e2008-08-30 12:52:26 +00006930 ret->contentIO = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00006931 return(ret);
6932}
6933
6934/**
6935 * xmlBufferCreateSize:
6936 * @size: initial size of buffer
6937 *
6938 * routine to create an XML buffer.
6939 * returns the new structure.
6940 */
6941xmlBufferPtr
6942xmlBufferCreateSize(size_t size) {
6943 xmlBufferPtr ret;
6944
6945 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6946 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006947 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006948 return(NULL);
6949 }
6950 ret->use = 0;
6951 ret->alloc = xmlBufferAllocScheme;
6952 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6953 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006954 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006955 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006956 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006957 xmlFree(ret);
6958 return(NULL);
6959 }
6960 ret->content[0] = 0;
6961 } else
6962 ret->content = NULL;
Daniel Veillarde83e93e2008-08-30 12:52:26 +00006963 ret->contentIO = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00006964 return(ret);
6965}
6966
6967/**
Daniel Veillard79ee2842012-05-15 10:25:31 +08006968 * xmlBufferDetach:
Conrad Irwin7d553f82012-05-10 20:17:25 -07006969 * @buf: the buffer
6970 *
Daniel Veillard79ee2842012-05-15 10:25:31 +08006971 * Remove the string contained in a buffer and gie it back to the
Daniel Veillard94431ec2012-05-15 10:45:05 +08006972 * caller. The buffer is reset to an empty content.
6973 * This doesn't work with immutable buffers as they can't be reset.
Conrad Irwin7d553f82012-05-10 20:17:25 -07006974 *
Daniel Veillard79ee2842012-05-15 10:25:31 +08006975 * Returns the previous string contained by the buffer.
Conrad Irwin7d553f82012-05-10 20:17:25 -07006976 */
6977xmlChar *
6978xmlBufferDetach(xmlBufferPtr buf) {
6979 xmlChar *ret;
6980
Daniel Veillard94431ec2012-05-15 10:45:05 +08006981 if (buf == NULL)
6982 return(NULL);
6983 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
6984 return(NULL);
Conrad Irwin7d553f82012-05-10 20:17:25 -07006985
6986 ret = buf->content;
6987 buf->content = NULL;
6988 buf->size = 0;
6989 buf->use = 0;
6990
6991 return ret;
6992}
6993
6994
6995/**
Daniel Veillard53350552003-09-18 13:35:51 +00006996 * xmlBufferCreateStatic:
6997 * @mem: the memory area
6998 * @size: the size in byte
6999 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00007000 * routine to create an XML buffer from an immutable memory area.
7001 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00007002 * present until the end of the buffer lifetime.
7003 *
7004 * returns the new structure.
7005 */
7006xmlBufferPtr
7007xmlBufferCreateStatic(void *mem, size_t size) {
7008 xmlBufferPtr ret;
7009
7010 if ((mem == NULL) || (size == 0))
7011 return(NULL);
7012
7013 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
7014 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007015 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00007016 return(NULL);
7017 }
7018 ret->use = size;
7019 ret->size = size;
7020 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
7021 ret->content = (xmlChar *) mem;
7022 return(ret);
7023}
7024
7025/**
Owen Taylor3473f882001-02-23 17:55:21 +00007026 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007027 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00007028 * @scheme: allocation scheme to use
7029 *
7030 * Sets the allocation scheme for this buffer
7031 */
7032void
Daniel Veillardaa6de472008-08-25 14:53:31 +00007033xmlBufferSetAllocationScheme(xmlBufferPtr buf,
Owen Taylor3473f882001-02-23 17:55:21 +00007034 xmlBufferAllocationScheme scheme) {
7035 if (buf == NULL) {
7036#ifdef DEBUG_BUFFER
7037 xmlGenericError(xmlGenericErrorContext,
7038 "xmlBufferSetAllocationScheme: buf == NULL\n");
7039#endif
7040 return;
7041 }
Daniel Veillardda3fee42008-09-01 13:08:57 +00007042 if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) ||
7043 (buf->alloc == XML_BUFFER_ALLOC_IO)) return;
7044 if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
7045 (scheme == XML_BUFFER_ALLOC_EXACT) ||
Conrad Irwin7d0d2a52012-05-14 14:18:58 +08007046 (scheme == XML_BUFFER_ALLOC_HYBRID) ||
Daniel Veillardda3fee42008-09-01 13:08:57 +00007047 (scheme == XML_BUFFER_ALLOC_IMMUTABLE))
7048 buf->alloc = scheme;
Owen Taylor3473f882001-02-23 17:55:21 +00007049}
7050
7051/**
7052 * xmlBufferFree:
7053 * @buf: the buffer to free
7054 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00007055 * Frees an XML buffer. It frees both the content and the structure which
7056 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00007057 */
7058void
7059xmlBufferFree(xmlBufferPtr buf) {
7060 if (buf == NULL) {
7061#ifdef DEBUG_BUFFER
7062 xmlGenericError(xmlGenericErrorContext,
7063 "xmlBufferFree: buf == NULL\n");
7064#endif
7065 return;
7066 }
Daniel Veillard53350552003-09-18 13:35:51 +00007067
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007068 if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
7069 (buf->contentIO != NULL)) {
7070 xmlFree(buf->contentIO);
7071 } else if ((buf->content != NULL) &&
Daniel Veillard53350552003-09-18 13:35:51 +00007072 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007073 xmlFree(buf->content);
7074 }
Owen Taylor3473f882001-02-23 17:55:21 +00007075 xmlFree(buf);
7076}
7077
7078/**
7079 * xmlBufferEmpty:
7080 * @buf: the buffer
7081 *
7082 * empty a buffer.
7083 */
7084void
7085xmlBufferEmpty(xmlBufferPtr buf) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007086 if (buf == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007087 if (buf->content == NULL) return;
7088 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00007089 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00007090 buf->content = BAD_CAST "";
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007091 } else if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
7092 (buf->contentIO != NULL)) {
7093 size_t start_buf = buf->content - buf->contentIO;
7094
7095 buf->size += start_buf;
7096 buf->content = buf->contentIO;
7097 buf->content[0] = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00007098 } else {
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007099 buf->content[0] = 0;
7100 }
Owen Taylor3473f882001-02-23 17:55:21 +00007101}
7102
7103/**
7104 * xmlBufferShrink:
7105 * @buf: the buffer to dump
7106 * @len: the number of xmlChar to remove
7107 *
7108 * Remove the beginning of an XML buffer.
7109 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007110 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007111 */
7112int
7113xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
Daniel Veillard3d97e662004-11-04 10:49:00 +00007114 if (buf == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007115 if (len == 0) return(0);
7116 if (len > buf->use) return(-1);
7117
7118 buf->use -= len;
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007119 if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) ||
7120 ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL))) {
7121 /*
7122 * we just move the content pointer, but also make sure
7123 * the perceived buffer size has shrinked accordingly
7124 */
Daniel Veillard53350552003-09-18 13:35:51 +00007125 buf->content += len;
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007126 buf->size -= len;
7127
7128 /*
7129 * sometimes though it maybe be better to really shrink
7130 * on IO buffers
7131 */
7132 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7133 size_t start_buf = buf->content - buf->contentIO;
7134 if (start_buf >= buf->size) {
7135 memmove(buf->contentIO, &buf->content[0], buf->use);
7136 buf->content = buf->contentIO;
7137 buf->content[buf->use] = 0;
7138 buf->size += start_buf;
7139 }
7140 }
Daniel Veillard53350552003-09-18 13:35:51 +00007141 } else {
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007142 memmove(buf->content, &buf->content[len], buf->use);
Daniel Veillard53350552003-09-18 13:35:51 +00007143 buf->content[buf->use] = 0;
7144 }
Owen Taylor3473f882001-02-23 17:55:21 +00007145 return(len);
7146}
7147
7148/**
7149 * xmlBufferGrow:
7150 * @buf: the buffer
7151 * @len: the minimum free size to allocate
7152 *
7153 * Grow the available space of an XML buffer.
7154 *
7155 * Returns the new available space or -1 in case of error
7156 */
7157int
7158xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
7159 int size;
7160 xmlChar *newbuf;
7161
Daniel Veillard3d97e662004-11-04 10:49:00 +00007162 if (buf == NULL) return(-1);
7163
Daniel Veillard53350552003-09-18 13:35:51 +00007164 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007165 if (len + buf->use < buf->size) return(0);
7166
Daniel Veillardee20cd72009-08-22 15:18:31 +02007167 /*
7168 * Windows has a BIG problem on realloc timing, so we try to double
7169 * the buffer size (if that's enough) (bug 146697)
7170 * Apparently BSD too, and it's probably best for linux too
7171 * On an embedded system this may be something to change
7172 */
7173#if 1
William M. Brack30fe43f2004-07-26 18:00:58 +00007174 if (buf->size > len)
7175 size = buf->size * 2;
7176 else
7177 size = buf->use + len + 100;
7178#else
Owen Taylor3473f882001-02-23 17:55:21 +00007179 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00007180#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007181
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007182 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7183 size_t start_buf = buf->content - buf->contentIO;
7184
7185 newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size);
7186 if (newbuf == NULL) {
7187 xmlTreeErrMemory("growing buffer");
7188 return(-1);
7189 }
7190 buf->contentIO = newbuf;
7191 buf->content = newbuf + start_buf;
7192 } else {
7193 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
7194 if (newbuf == NULL) {
7195 xmlTreeErrMemory("growing buffer");
7196 return(-1);
7197 }
7198 buf->content = newbuf;
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007199 }
Owen Taylor3473f882001-02-23 17:55:21 +00007200 buf->size = size;
7201 return(buf->size - buf->use);
7202}
7203
7204/**
7205 * xmlBufferDump:
7206 * @file: the file output
7207 * @buf: the buffer to dump
7208 *
7209 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00007210 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00007211 */
7212int
7213xmlBufferDump(FILE *file, xmlBufferPtr buf) {
7214 int ret;
7215
7216 if (buf == NULL) {
7217#ifdef DEBUG_BUFFER
7218 xmlGenericError(xmlGenericErrorContext,
7219 "xmlBufferDump: buf == NULL\n");
7220#endif
7221 return(0);
7222 }
7223 if (buf->content == NULL) {
7224#ifdef DEBUG_BUFFER
7225 xmlGenericError(xmlGenericErrorContext,
7226 "xmlBufferDump: buf->content == NULL\n");
7227#endif
7228 return(0);
7229 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00007230 if (file == NULL)
7231 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00007232 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
7233 return(ret);
7234}
7235
7236/**
7237 * xmlBufferContent:
7238 * @buf: the buffer
7239 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007240 * Function to extract the content of a buffer
7241 *
Owen Taylor3473f882001-02-23 17:55:21 +00007242 * Returns the internal content
7243 */
7244
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007245const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007246xmlBufferContent(const xmlBufferPtr buf)
7247{
7248 if(!buf)
7249 return NULL;
7250
7251 return buf->content;
7252}
7253
7254/**
7255 * xmlBufferLength:
Daniel Veillardaa6de472008-08-25 14:53:31 +00007256 * @buf: the buffer
Owen Taylor3473f882001-02-23 17:55:21 +00007257 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007258 * Function to get the length of a buffer
7259 *
Owen Taylor3473f882001-02-23 17:55:21 +00007260 * Returns the length of data in the internal content
7261 */
7262
7263int
7264xmlBufferLength(const xmlBufferPtr buf)
7265{
7266 if(!buf)
7267 return 0;
7268
7269 return buf->use;
7270}
7271
7272/**
7273 * xmlBufferResize:
7274 * @buf: the buffer to resize
7275 * @size: the desired size
7276 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007277 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00007278 *
7279 * Returns 0 in case of problems, 1 otherwise
7280 */
7281int
7282xmlBufferResize(xmlBufferPtr buf, unsigned int size)
7283{
7284 unsigned int newSize;
7285 xmlChar* rebuf = NULL;
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007286 size_t start_buf;
Owen Taylor3473f882001-02-23 17:55:21 +00007287
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007288 if (buf == NULL)
7289 return(0);
7290
Daniel Veillard53350552003-09-18 13:35:51 +00007291 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
7292
Owen Taylor3473f882001-02-23 17:55:21 +00007293 /* Don't resize if we don't have to */
7294 if (size < buf->size)
7295 return 1;
7296
7297 /* figure out new size */
7298 switch (buf->alloc){
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007299 case XML_BUFFER_ALLOC_IO:
7300 case XML_BUFFER_ALLOC_DOUBLEIT:
7301 /*take care of empty case*/
7302 newSize = (buf->size ? buf->size*2 : size + 10);
Daniel Veillard1dc9feb2008-11-17 15:59:21 +00007303 while (size > newSize) {
7304 if (newSize > UINT_MAX / 2) {
7305 xmlTreeErrMemory("growing buffer");
7306 return 0;
7307 }
7308 newSize *= 2;
7309 }
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007310 break;
7311 case XML_BUFFER_ALLOC_EXACT:
7312 newSize = size+10;
7313 break;
Conrad Irwin7d0d2a52012-05-14 14:18:58 +08007314 case XML_BUFFER_ALLOC_HYBRID:
7315 if (buf->use < BASE_BUFFER_SIZE)
7316 newSize = size;
7317 else {
7318 newSize = buf->size * 2;
7319 while (size > newSize) {
7320 if (newSize > UINT_MAX / 2) {
7321 xmlTreeErrMemory("growing buffer");
7322 return 0;
7323 }
7324 newSize *= 2;
7325 }
7326 }
7327 break;
7328
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007329 default:
7330 newSize = size+10;
7331 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007332 }
7333
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007334 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7335 start_buf = buf->content - buf->contentIO;
7336
7337 if (start_buf > newSize) {
7338 /* move data back to start */
7339 memmove(buf->contentIO, buf->content, buf->use);
7340 buf->content = buf->contentIO;
7341 buf->content[buf->use] = 0;
7342 buf->size += start_buf;
7343 } else {
7344 rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize);
7345 if (rebuf == NULL) {
7346 xmlTreeErrMemory("growing buffer");
7347 return 0;
7348 }
7349 buf->contentIO = rebuf;
7350 buf->content = rebuf + start_buf;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00007351 }
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007352 } else {
7353 if (buf->content == NULL) {
7354 rebuf = (xmlChar *) xmlMallocAtomic(newSize);
7355 } else if (buf->size - buf->use < 100) {
7356 rebuf = (xmlChar *) xmlRealloc(buf->content, newSize);
7357 } else {
7358 /*
7359 * if we are reallocating a buffer far from being full, it's
7360 * better to make a new allocation and copy only the used range
7361 * and free the old one.
7362 */
7363 rebuf = (xmlChar *) xmlMallocAtomic(newSize);
7364 if (rebuf != NULL) {
7365 memcpy(rebuf, buf->content, buf->use);
7366 xmlFree(buf->content);
7367 rebuf[buf->use] = 0;
7368 }
7369 }
7370 if (rebuf == NULL) {
7371 xmlTreeErrMemory("growing buffer");
7372 return 0;
7373 }
7374 buf->content = rebuf;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00007375 }
Owen Taylor3473f882001-02-23 17:55:21 +00007376 buf->size = newSize;
7377
7378 return 1;
7379}
7380
7381/**
7382 * xmlBufferAdd:
7383 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00007384 * @str: the #xmlChar string
7385 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00007386 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007387 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00007388 * str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00007389 *
7390 * Returns 0 successful, a positive error code number otherwise
7391 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007392 */
William M. Bracka3215c72004-07-31 16:24:01 +00007393int
Owen Taylor3473f882001-02-23 17:55:21 +00007394xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
7395 unsigned int needSize;
7396
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007397 if ((str == NULL) || (buf == NULL)) {
William M. Bracka3215c72004-07-31 16:24:01 +00007398 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007399 }
William M. Bracka3215c72004-07-31 16:24:01 +00007400 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007401 if (len < -1) {
7402#ifdef DEBUG_BUFFER
7403 xmlGenericError(xmlGenericErrorContext,
7404 "xmlBufferAdd: len < 0\n");
7405#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007406 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007407 }
William M. Bracka3215c72004-07-31 16:24:01 +00007408 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007409
7410 if (len < 0)
7411 len = xmlStrlen(str);
7412
Daniel Veillardc9923322007-04-24 18:12:06 +00007413 if (len < 0) return -1;
7414 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007415
7416 needSize = buf->use + len + 2;
7417 if (needSize > buf->size){
7418 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007419 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007420 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007421 }
7422 }
7423
7424 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
7425 buf->use += len;
7426 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007427 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007428}
7429
7430/**
7431 * xmlBufferAddHead:
7432 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00007433 * @str: the #xmlChar string
7434 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00007435 *
7436 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00007437 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00007438 *
7439 * Returns 0 successful, a positive error code number otherwise
7440 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007441 */
William M. Bracka3215c72004-07-31 16:24:01 +00007442int
Owen Taylor3473f882001-02-23 17:55:21 +00007443xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
7444 unsigned int needSize;
7445
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007446 if (buf == NULL)
7447 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007448 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007449 if (str == NULL) {
7450#ifdef DEBUG_BUFFER
7451 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007452 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007453#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007454 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007455 }
7456 if (len < -1) {
7457#ifdef DEBUG_BUFFER
7458 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007459 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007460#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007461 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007462 }
William M. Bracka3215c72004-07-31 16:24:01 +00007463 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007464
7465 if (len < 0)
7466 len = xmlStrlen(str);
7467
William M. Bracka3215c72004-07-31 16:24:01 +00007468 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007469
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007470 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7471 size_t start_buf = buf->content - buf->contentIO;
7472
7473 if (start_buf > (unsigned int) len) {
7474 /*
7475 * We can add it in the space previously shrinked
7476 */
7477 buf->content -= len;
7478 memmove(&buf->content[0], str, len);
7479 buf->use += len;
7480 buf->size += len;
7481 return(0);
7482 }
7483 }
Owen Taylor3473f882001-02-23 17:55:21 +00007484 needSize = buf->use + len + 2;
7485 if (needSize > buf->size){
7486 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007487 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007488 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007489 }
7490 }
7491
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007492 memmove(&buf->content[len], &buf->content[0], buf->use);
7493 memmove(&buf->content[0], str, len);
Owen Taylor3473f882001-02-23 17:55:21 +00007494 buf->use += len;
7495 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007496 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007497}
7498
7499/**
7500 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00007501 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00007502 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00007503 *
7504 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007505 *
7506 * Returns 0 successful, a positive error code number otherwise
7507 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007508 */
William M. Bracka3215c72004-07-31 16:24:01 +00007509int
Owen Taylor3473f882001-02-23 17:55:21 +00007510xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007511 if (buf == NULL)
7512 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007513 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
7514 if (str == NULL) return -1;
7515 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00007516}
7517
7518/**
7519 * xmlBufferCCat:
7520 * @buf: the buffer to dump
7521 * @str: the C char string
7522 *
7523 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007524 *
7525 * Returns 0 successful, a positive error code number otherwise
7526 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007527 */
William M. Bracka3215c72004-07-31 16:24:01 +00007528int
Owen Taylor3473f882001-02-23 17:55:21 +00007529xmlBufferCCat(xmlBufferPtr buf, const char *str) {
7530 const char *cur;
7531
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007532 if (buf == NULL)
7533 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007534 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007535 if (str == NULL) {
7536#ifdef DEBUG_BUFFER
7537 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007538 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007539#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007540 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007541 }
7542 for (cur = str;*cur != 0;cur++) {
7543 if (buf->use + 10 >= buf->size) {
7544 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007545 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007546 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007547 }
7548 }
7549 buf->content[buf->use++] = *cur;
7550 }
7551 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007552 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007553}
7554
7555/**
7556 * xmlBufferWriteCHAR:
7557 * @buf: the XML buffer
7558 * @string: the string to add
7559 *
7560 * routine which manages and grows an output buffer. This one adds
7561 * xmlChars at the end of the buffer.
7562 */
7563void
Daniel Veillard53350552003-09-18 13:35:51 +00007564xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007565 if (buf == NULL)
7566 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007567 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007568 xmlBufferCat(buf, string);
7569}
7570
7571/**
7572 * xmlBufferWriteChar:
7573 * @buf: the XML buffer output
7574 * @string: the string to add
7575 *
7576 * routine which manage and grows an output buffer. This one add
7577 * C chars at the end of the array.
7578 */
7579void
7580xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007581 if (buf == NULL)
7582 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007583 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007584 xmlBufferCCat(buf, string);
7585}
7586
7587
7588/**
7589 * xmlBufferWriteQuotedString:
7590 * @buf: the XML buffer output
7591 * @string: the string to add
7592 *
7593 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00007594 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00007595 * quote or double-quotes internally
7596 */
7597void
7598xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00007599 const xmlChar *cur, *base;
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007600 if (buf == NULL)
7601 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007602 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00007603 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00007604 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00007605#ifdef DEBUG_BUFFER
7606 xmlGenericError(xmlGenericErrorContext,
7607 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7608#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00007609 xmlBufferCCat(buf, "\"");
7610 base = cur = string;
7611 while(*cur != 0){
7612 if(*cur == '"'){
7613 if (base != cur)
7614 xmlBufferAdd(buf, base, cur - base);
7615 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7616 cur++;
7617 base = cur;
7618 }
7619 else {
7620 cur++;
7621 }
7622 }
7623 if (base != cur)
7624 xmlBufferAdd(buf, base, cur - base);
7625 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007626 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007627 else{
7628 xmlBufferCCat(buf, "\'");
7629 xmlBufferCat(buf, string);
7630 xmlBufferCCat(buf, "\'");
7631 }
Owen Taylor3473f882001-02-23 17:55:21 +00007632 } else {
7633 xmlBufferCCat(buf, "\"");
7634 xmlBufferCat(buf, string);
7635 xmlBufferCCat(buf, "\"");
7636 }
7637}
7638
7639
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007640/**
7641 * xmlGetDocCompressMode:
7642 * @doc: the document
7643 *
7644 * get the compression ratio for a document, ZLIB based
7645 * Returns 0 (uncompressed) to 9 (max compression)
7646 */
7647int
7648xmlGetDocCompressMode (xmlDocPtr doc) {
7649 if (doc == NULL) return(-1);
7650 return(doc->compression);
7651}
7652
7653/**
7654 * xmlSetDocCompressMode:
7655 * @doc: the document
7656 * @mode: the compression ratio
7657 *
7658 * set the compression ratio for a document, ZLIB based
7659 * Correct values: 0 (uncompressed) to 9 (max compression)
7660 */
7661void
7662xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7663 if (doc == NULL) return;
7664 if (mode < 0) doc->compression = 0;
7665 else if (mode > 9) doc->compression = 9;
7666 else doc->compression = mode;
7667}
7668
7669/**
7670 * xmlGetCompressMode:
7671 *
7672 * get the default compression mode used, ZLIB based.
7673 * Returns 0 (uncompressed) to 9 (max compression)
7674 */
7675int
7676xmlGetCompressMode(void)
7677{
7678 return (xmlCompressMode);
7679}
7680
7681/**
7682 * xmlSetCompressMode:
7683 * @mode: the compression ratio
7684 *
7685 * set the default compression mode used, ZLIB based
7686 * Correct values: 0 (uncompressed) to 9 (max compression)
7687 */
7688void
7689xmlSetCompressMode(int mode) {
7690 if (mode < 0) xmlCompressMode = 0;
7691 else if (mode > 9) xmlCompressMode = 9;
7692 else xmlCompressMode = mode;
7693}
7694
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007695#define XML_TREE_NSMAP_PARENT -1
7696#define XML_TREE_NSMAP_XML -2
7697#define XML_TREE_NSMAP_DOC -3
7698#define XML_TREE_NSMAP_CUSTOM -4
7699
7700typedef struct xmlNsMapItem *xmlNsMapItemPtr;
7701struct xmlNsMapItem {
7702 xmlNsMapItemPtr next;
7703 xmlNsMapItemPtr prev;
7704 xmlNsPtr oldNs; /* old ns decl reference */
7705 xmlNsPtr newNs; /* new ns decl reference */
7706 int shadowDepth; /* Shadowed at this depth */
7707 /*
7708 * depth:
7709 * >= 0 == @node's ns-decls
7710 * -1 == @parent's ns-decls
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00007711 * -2 == the doc->oldNs XML ns-decl
7712 * -3 == the doc->oldNs storage ns-decls
7713 * -4 == ns-decls provided via custom ns-handling
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007714 */
7715 int depth;
7716};
7717
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007718typedef struct xmlNsMap *xmlNsMapPtr;
7719struct xmlNsMap {
7720 xmlNsMapItemPtr first;
7721 xmlNsMapItemPtr last;
7722 xmlNsMapItemPtr pool;
7723};
7724
7725#define XML_NSMAP_NOTEMPTY(m) (((m) != NULL) && ((m)->first != NULL))
7726#define XML_NSMAP_FOREACH(m, i) for (i = (m)->first; i != NULL; i = (i)->next)
7727#define XML_NSMAP_POP(m, i) \
7728 i = (m)->last; \
7729 (m)->last = (i)->prev; \
7730 if ((m)->last == NULL) \
7731 (m)->first = NULL; \
7732 else \
7733 (m)->last->next = NULL; \
7734 (i)->next = (m)->pool; \
7735 (m)->pool = i;
7736
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007737/*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007738* xmlDOMWrapNsMapFree:
7739* @map: the ns-map
Daniel Veillardaa6de472008-08-25 14:53:31 +00007740*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007741* Frees the ns-map
7742*/
7743static void
7744xmlDOMWrapNsMapFree(xmlNsMapPtr nsmap)
7745{
7746 xmlNsMapItemPtr cur, tmp;
7747
7748 if (nsmap == NULL)
7749 return;
7750 cur = nsmap->pool;
7751 while (cur != NULL) {
7752 tmp = cur;
7753 cur = cur->next;
7754 xmlFree(tmp);
7755 }
7756 cur = nsmap->first;
7757 while (cur != NULL) {
7758 tmp = cur;
7759 cur = cur->next;
7760 xmlFree(tmp);
7761 }
7762 xmlFree(nsmap);
7763}
7764
7765/*
7766* xmlDOMWrapNsMapAddItem:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007767* @map: the ns-map
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007768* @oldNs: the old ns-struct
7769* @newNs: the new ns-struct
7770* @depth: depth and ns-kind information
Daniel Veillardaa6de472008-08-25 14:53:31 +00007771*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007772* Adds an ns-mapping item.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007773*/
7774static xmlNsMapItemPtr
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00007775xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007776 xmlNsPtr oldNs, xmlNsPtr newNs, int depth)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007777{
7778 xmlNsMapItemPtr ret;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007779 xmlNsMapPtr map;
7780
7781 if (nsmap == NULL)
7782 return(NULL);
7783 if ((position != -1) && (position != 0))
7784 return(NULL);
7785 map = *nsmap;
7786
7787 if (map == NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007788 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007789 * Create the ns-map.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007790 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007791 map = (xmlNsMapPtr) xmlMalloc(sizeof(struct xmlNsMap));
7792 if (map == NULL) {
7793 xmlTreeErrMemory("allocating namespace map");
7794 return (NULL);
7795 }
7796 memset(map, 0, sizeof(struct xmlNsMap));
7797 *nsmap = map;
7798 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00007799
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007800 if (map->pool != NULL) {
7801 /*
7802 * Reuse an item from the pool.
7803 */
7804 ret = map->pool;
7805 map->pool = ret->next;
7806 memset(ret, 0, sizeof(struct xmlNsMapItem));
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007807 } else {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007808 /*
7809 * Create a new item.
7810 */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007811 ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem));
7812 if (ret == NULL) {
7813 xmlTreeErrMemory("allocating namespace map item");
7814 return (NULL);
7815 }
7816 memset(ret, 0, sizeof(struct xmlNsMapItem));
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007817 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00007818
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007819 if (map->first == NULL) {
7820 /*
7821 * First ever.
Daniel Veillardaa6de472008-08-25 14:53:31 +00007822 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007823 map->first = ret;
7824 map->last = ret;
7825 } else if (position == -1) {
7826 /*
7827 * Append.
7828 */
7829 ret->prev = map->last;
7830 map->last->next = ret;
Daniel Veillardaa6de472008-08-25 14:53:31 +00007831 map->last = ret;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007832 } else if (position == 0) {
7833 /*
7834 * Set on first position.
7835 */
7836 map->first->prev = ret;
Daniel Veillardaa6de472008-08-25 14:53:31 +00007837 ret->next = map->first;
7838 map->first = ret;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007839 } else
7840 return(NULL);
7841
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007842 ret->oldNs = oldNs;
7843 ret->newNs = newNs;
7844 ret->shadowDepth = -1;
7845 ret->depth = depth;
7846 return (ret);
7847}
7848
7849/*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007850* xmlDOMWrapStoreNs:
7851* @doc: the doc
7852* @nsName: the namespace name
7853* @prefix: the prefix
Daniel Veillardaa6de472008-08-25 14:53:31 +00007854*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007855* Creates or reuses an xmlNs struct on doc->oldNs with
7856* the given prefix and namespace name.
Daniel Veillardaa6de472008-08-25 14:53:31 +00007857*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007858* Returns the aquired ns struct or NULL in case of an API
7859* or internal error.
7860*/
7861static xmlNsPtr
7862xmlDOMWrapStoreNs(xmlDocPtr doc,
7863 const xmlChar *nsName,
7864 const xmlChar *prefix)
7865{
7866 xmlNsPtr ns;
7867
7868 if (doc == NULL)
7869 return (NULL);
7870 ns = xmlTreeEnsureXMLDecl(doc);
7871 if (ns == NULL)
7872 return (NULL);
7873 if (ns->next != NULL) {
7874 /* Reuse. */
7875 ns = ns->next;
7876 while (ns != NULL) {
7877 if (((ns->prefix == prefix) ||
7878 xmlStrEqual(ns->prefix, prefix)) &&
7879 xmlStrEqual(ns->href, nsName)) {
7880 return (ns);
7881 }
7882 if (ns->next == NULL)
7883 break;
7884 ns = ns->next;
7885 }
7886 }
7887 /* Create. */
Daniel Veillard76d36452009-09-07 11:19:33 +02007888 if (ns != NULL) {
7889 ns->next = xmlNewNs(NULL, nsName, prefix);
7890 return (ns->next);
7891 }
7892 return(NULL);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007893}
7894
7895/*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00007896* xmlDOMWrapNewCtxt:
7897*
7898* Allocates and initializes a new DOM-wrapper context.
7899*
Daniel Veillardaa6de472008-08-25 14:53:31 +00007900* Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal errror.
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00007901*/
7902xmlDOMWrapCtxtPtr
7903xmlDOMWrapNewCtxt(void)
7904{
7905 xmlDOMWrapCtxtPtr ret;
7906
7907 ret = xmlMalloc(sizeof(xmlDOMWrapCtxt));
7908 if (ret == NULL) {
7909 xmlTreeErrMemory("allocating DOM-wrapper context");
7910 return (NULL);
7911 }
7912 memset(ret, 0, sizeof(xmlDOMWrapCtxt));
7913 return (ret);
7914}
7915
7916/*
7917* xmlDOMWrapFreeCtxt:
7918* @ctxt: the DOM-wrapper context
7919*
7920* Frees the DOM-wrapper context.
7921*/
7922void
7923xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt)
7924{
7925 if (ctxt == NULL)
7926 return;
7927 if (ctxt->namespaceMap != NULL)
7928 xmlDOMWrapNsMapFree((xmlNsMapPtr) ctxt->namespaceMap);
7929 /*
7930 * TODO: Store the namespace map in the context.
7931 */
7932 xmlFree(ctxt);
7933}
7934
7935/*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007936* xmlTreeLookupNsListByPrefix:
7937* @nsList: a list of ns-structs
7938* @prefix: the searched prefix
Daniel Veillardaa6de472008-08-25 14:53:31 +00007939*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007940* Searches for a ns-decl with the given prefix in @nsList.
Daniel Veillardaa6de472008-08-25 14:53:31 +00007941*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007942* Returns the ns-decl if found, NULL if not found and on
7943* API errors.
7944*/
7945static xmlNsPtr
7946xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix)
7947{
7948 if (nsList == NULL)
7949 return (NULL);
7950 {
7951 xmlNsPtr ns;
7952 ns = nsList;
7953 do {
7954 if ((prefix == ns->prefix) ||
7955 xmlStrEqual(prefix, ns->prefix)) {
7956 return (ns);
7957 }
7958 ns = ns->next;
7959 } while (ns != NULL);
7960 }
7961 return (NULL);
7962}
7963
7964/*
7965*
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00007966* xmlDOMWrapNSNormGatherInScopeNs:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007967* @map: the namespace map
7968* @node: the node to start with
Daniel Veillardaa6de472008-08-25 14:53:31 +00007969*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007970* Puts in-scope namespaces into the ns-map.
Daniel Veillardaa6de472008-08-25 14:53:31 +00007971*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007972* Returns 0 on success, -1 on API or internal errors.
7973*/
7974static int
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007975xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapPtr *map,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007976 xmlNodePtr node)
7977{
7978 xmlNodePtr cur;
7979 xmlNsPtr ns;
7980 xmlNsMapItemPtr mi;
7981 int shadowed;
7982
7983 if ((map == NULL) || (*map != NULL))
7984 return (-1);
7985 /*
7986 * Get in-scope ns-decls of @parent.
7987 */
7988 cur = node;
7989 while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) {
7990 if (cur->type == XML_ELEMENT_NODE) {
7991 if (cur->nsDef != NULL) {
7992 ns = cur->nsDef;
7993 do {
7994 shadowed = 0;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007995 if (XML_NSMAP_NOTEMPTY(*map)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007996 /*
7997 * Skip shadowed prefixes.
7998 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007999 XML_NSMAP_FOREACH(*map, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008000 if ((ns->prefix == mi->newNs->prefix) ||
8001 xmlStrEqual(ns->prefix, mi->newNs->prefix)) {
8002 shadowed = 1;
8003 break;
8004 }
8005 }
8006 }
8007 /*
8008 * Insert mapping.
8009 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008010 mi = xmlDOMWrapNsMapAddItem(map, 0, NULL,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008011 ns, XML_TREE_NSMAP_PARENT);
8012 if (mi == NULL)
8013 return (-1);
8014 if (shadowed)
8015 mi->shadowDepth = 0;
8016 ns = ns->next;
8017 } while (ns != NULL);
8018 }
8019 }
8020 cur = cur->parent;
8021 }
8022 return (0);
8023}
8024
8025/*
8026* XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict;
8027* otherwise copy it, when it was in the source-dict.
8028*/
8029#define XML_TREE_ADOPT_STR(str) \
8030 if (adoptStr && (str != NULL)) { \
8031 if (destDoc->dict) { \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00008032 const xmlChar *old = str; \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008033 str = xmlDictLookup(destDoc->dict, str, -1); \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00008034 if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \
8035 (!xmlDictOwns(sourceDoc->dict, old))) \
Daniel Veillard39e5c892005-07-03 22:48:50 +00008036 xmlFree((char *)old); \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008037 } else if ((sourceDoc) && (sourceDoc->dict) && \
8038 xmlDictOwns(sourceDoc->dict, str)) { \
8039 str = BAD_CAST xmlStrdup(str); \
8040 } \
8041 }
8042
8043/*
8044* XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then
8045* put it in dest-dict or copy it.
8046*/
8047#define XML_TREE_ADOPT_STR_2(str) \
8048 if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \
8049 (sourceDoc->dict != NULL) && \
8050 xmlDictOwns(sourceDoc->dict, cur->content)) { \
8051 if (destDoc->dict) \
8052 cur->content = (xmlChar *) \
8053 xmlDictLookup(destDoc->dict, cur->content, -1); \
8054 else \
8055 cur->content = xmlStrdup(BAD_CAST cur->content); \
8056 }
8057
8058/*
8059* xmlDOMWrapNSNormAddNsMapItem2:
8060*
8061* For internal use. Adds a ns-decl mapping.
8062*
Daniel Veillardaa6de472008-08-25 14:53:31 +00008063* Returns 0 on success, -1 on internal errors.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008064*/
8065static int
8066xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number,
8067 xmlNsPtr oldNs, xmlNsPtr newNs)
8068{
8069 if (*list == NULL) {
8070 *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr));
8071 if (*list == NULL) {
8072 xmlTreeErrMemory("alloc ns map item");
8073 return(-1);
8074 }
8075 *size = 3;
8076 *number = 0;
8077 } else if ((*number) >= (*size)) {
8078 *size *= 2;
8079 *list = (xmlNsPtr *) xmlRealloc(*list,
8080 (*size) * 2 * sizeof(xmlNsPtr));
8081 if (*list == NULL) {
8082 xmlTreeErrMemory("realloc ns map item");
8083 return(-1);
8084 }
8085 }
8086 (*list)[2 * (*number)] = oldNs;
8087 (*list)[2 * (*number) +1] = newNs;
8088 (*number)++;
8089 return (0);
8090}
8091
8092/*
8093* xmlDOMWrapRemoveNode:
Daniel Veillard304e78c2005-07-03 16:19:41 +00008094* @ctxt: a DOM wrapper context
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008095* @doc: the doc
8096* @node: the node to be removed.
Daniel Veillard304e78c2005-07-03 16:19:41 +00008097* @options: set of options, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008098*
8099* Unlinks the given node from its owner.
8100* This will substitute ns-references to node->nsDef for
8101* ns-references to doc->oldNs, thus ensuring the removed
8102* branch to be autark wrt ns-references.
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008103*
8104* NOTE: This function was not intensively tested.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008105*
8106* Returns 0 on success, 1 if the node is not supported,
Daniel Veillardaa6de472008-08-25 14:53:31 +00008107* -1 on API and internal errors.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008108*/
8109int
8110xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc,
8111 xmlNodePtr node, int options ATTRIBUTE_UNUSED)
8112{
8113 xmlNsPtr *list = NULL;
8114 int sizeList, nbList, i, j;
8115 xmlNsPtr ns;
8116
8117 if ((node == NULL) || (doc == NULL) || (node->doc != doc))
8118 return (-1);
8119
8120 /* TODO: 0 or -1 ? */
8121 if (node->parent == NULL)
8122 return (0);
8123
Daniel Veillardaa6de472008-08-25 14:53:31 +00008124 switch (node->type) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008125 case XML_TEXT_NODE:
8126 case XML_CDATA_SECTION_NODE:
8127 case XML_ENTITY_REF_NODE:
8128 case XML_PI_NODE:
8129 case XML_COMMENT_NODE:
8130 xmlUnlinkNode(node);
8131 return (0);
Daniel Veillardaa6de472008-08-25 14:53:31 +00008132 case XML_ELEMENT_NODE:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008133 case XML_ATTRIBUTE_NODE:
8134 break;
8135 default:
8136 return (1);
8137 }
8138 xmlUnlinkNode(node);
8139 /*
8140 * Save out-of-scope ns-references in doc->oldNs.
8141 */
8142 do {
8143 switch (node->type) {
8144 case XML_ELEMENT_NODE:
8145 if ((ctxt == NULL) && (node->nsDef != NULL)) {
8146 ns = node->nsDef;
8147 do {
8148 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
8149 &nbList, ns, ns) == -1)
8150 goto internal_error;
8151 ns = ns->next;
8152 } while (ns != NULL);
8153 }
8154 /* No break on purpose. */
8155 case XML_ATTRIBUTE_NODE:
Daniel Veillardaa6de472008-08-25 14:53:31 +00008156 if (node->ns != NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008157 /*
8158 * Find a mapping.
8159 */
8160 if (list != NULL) {
8161 for (i = 0, j = 0; i < nbList; i++, j += 2) {
8162 if (node->ns == list[j]) {
8163 node->ns = list[++j];
8164 goto next_node;
8165 }
8166 }
8167 }
8168 ns = NULL;
8169 if (ctxt != NULL) {
8170 /*
8171 * User defined.
8172 */
8173 } else {
8174 /*
8175 * Add to doc's oldNs.
8176 */
8177 ns = xmlDOMWrapStoreNs(doc, node->ns->href,
8178 node->ns->prefix);
8179 if (ns == NULL)
8180 goto internal_error;
8181 }
8182 if (ns != NULL) {
8183 /*
8184 * Add mapping.
8185 */
8186 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
8187 &nbList, node->ns, ns) == -1)
8188 goto internal_error;
8189 }
8190 node->ns = ns;
8191 }
8192 if ((node->type == XML_ELEMENT_NODE) &&
8193 (node->properties != NULL)) {
8194 node = (xmlNodePtr) node->properties;
8195 continue;
8196 }
8197 break;
8198 default:
8199 goto next_sibling;
Daniel Veillardaa6de472008-08-25 14:53:31 +00008200 }
8201next_node:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008202 if ((node->type == XML_ELEMENT_NODE) &&
8203 (node->children != NULL)) {
8204 node = node->children;
8205 continue;
8206 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00008207next_sibling:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008208 if (node == NULL)
8209 break;
8210 if (node->next != NULL)
8211 node = node->next;
8212 else {
8213 node = node->parent;
8214 goto next_sibling;
8215 }
8216 } while (node != NULL);
8217
8218 if (list != NULL)
8219 xmlFree(list);
8220 return (0);
8221
8222internal_error:
8223 if (list != NULL)
8224 xmlFree(list);
8225 return (-1);
8226}
8227
8228/*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008229* xmlSearchNsByNamespaceStrict:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008230* @doc: the document
8231* @node: the start node
8232* @nsName: the searched namespace name
8233* @retNs: the resulting ns-decl
8234* @prefixed: if the found ns-decl must have a prefix (for attributes)
8235*
8236* Dynamically searches for a ns-declaration which matches
8237* the given @nsName in the ancestor-or-self axis of @node.
8238*
8239* Returns 1 if a ns-decl was found, 0 if not and -1 on API
8240* and internal errors.
8241*/
8242static int
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008243xmlSearchNsByNamespaceStrict(xmlDocPtr doc, xmlNodePtr node,
8244 const xmlChar* nsName,
8245 xmlNsPtr *retNs, int prefixed)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008246{
8247 xmlNodePtr cur, prev = NULL, out = NULL;
8248 xmlNsPtr ns, prevns;
8249
8250 if ((doc == NULL) || (nsName == NULL) || (retNs == NULL))
8251 return (-1);
8252
8253 *retNs = NULL;
8254 if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
8255 *retNs = xmlTreeEnsureXMLDecl(doc);
8256 if (*retNs == NULL)
8257 return (-1);
8258 return (1);
8259 }
8260 cur = node;
8261 do {
8262 if (cur->type == XML_ELEMENT_NODE) {
8263 if (cur->nsDef != NULL) {
8264 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8265 if (prefixed && (ns->prefix == NULL))
8266 continue;
8267 if (prev != NULL) {
8268 /*
8269 * Check the last level of ns-decls for a
8270 * shadowing prefix.
8271 */
8272 prevns = prev->nsDef;
8273 do {
8274 if ((prevns->prefix == ns->prefix) ||
8275 ((prevns->prefix != NULL) &&
8276 (ns->prefix != NULL) &&
8277 xmlStrEqual(prevns->prefix, ns->prefix))) {
8278 /*
8279 * Shadowed.
8280 */
8281 break;
8282 }
8283 prevns = prevns->next;
8284 } while (prevns != NULL);
8285 if (prevns != NULL)
8286 continue;
8287 }
8288 /*
8289 * Ns-name comparison.
8290 */
8291 if ((nsName == ns->href) ||
8292 xmlStrEqual(nsName, ns->href)) {
8293 /*
8294 * At this point the prefix can only be shadowed,
8295 * if we are the the (at least) 3rd level of
8296 * ns-decls.
8297 */
8298 if (out) {
8299 int ret;
Daniel Veillardaa6de472008-08-25 14:53:31 +00008300
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008301 ret = xmlNsInScope(doc, node, prev, ns->prefix);
8302 if (ret < 0)
8303 return (-1);
8304 /*
8305 * TODO: Should we try to find a matching ns-name
8306 * only once? This here keeps on searching.
8307 * I think we should try further since, there might
8308 * be an other matching ns-decl with an unshadowed
8309 * prefix.
8310 */
8311 if (! ret)
8312 continue;
8313 }
8314 *retNs = ns;
8315 return (1);
8316 }
8317 }
8318 out = prev;
8319 prev = cur;
8320 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008321 } else if ((cur->type == XML_ENTITY_NODE) ||
8322 (cur->type == XML_ENTITY_DECL))
8323 return (0);
8324 cur = cur->parent;
8325 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
8326 return (0);
8327}
8328
8329/*
8330* xmlSearchNsByPrefixStrict:
8331* @doc: the document
8332* @node: the start node
8333* @prefix: the searched namespace prefix
8334* @retNs: the resulting ns-decl
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008335*
8336* Dynamically searches for a ns-declaration which matches
8337* the given @nsName in the ancestor-or-self axis of @node.
8338*
8339* Returns 1 if a ns-decl was found, 0 if not and -1 on API
8340* and internal errors.
8341*/
8342static int
8343xmlSearchNsByPrefixStrict(xmlDocPtr doc, xmlNodePtr node,
8344 const xmlChar* prefix,
8345 xmlNsPtr *retNs)
8346{
8347 xmlNodePtr cur;
8348 xmlNsPtr ns;
8349
8350 if ((doc == NULL) || (node == NULL))
8351 return (-1);
8352
8353 if (retNs)
8354 *retNs = NULL;
8355 if (IS_STR_XML(prefix)) {
8356 if (retNs) {
8357 *retNs = xmlTreeEnsureXMLDecl(doc);
8358 if (*retNs == NULL)
8359 return (-1);
8360 }
8361 return (1);
8362 }
8363 cur = node;
8364 do {
8365 if (cur->type == XML_ELEMENT_NODE) {
8366 if (cur->nsDef != NULL) {
8367 ns = cur->nsDef;
Daniel Veillardaa6de472008-08-25 14:53:31 +00008368 do {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008369 if ((prefix == ns->prefix) ||
8370 xmlStrEqual(prefix, ns->prefix))
8371 {
8372 /*
8373 * Disabled namespaces, e.g. xmlns:abc="".
8374 */
8375 if (ns->href == NULL)
8376 return(0);
8377 if (retNs)
8378 *retNs = ns;
8379 return (1);
8380 }
8381 ns = ns->next;
Daniel Veillardaa6de472008-08-25 14:53:31 +00008382 } while (ns != NULL);
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008383 }
8384 } else if ((cur->type == XML_ENTITY_NODE) ||
8385 (cur->type == XML_ENTITY_DECL))
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008386 return (0);
8387 cur = cur->parent;
8388 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
8389 return (0);
8390}
8391
8392/*
8393* xmlDOMWrapNSNormDeclareNsForced:
8394* @doc: the doc
8395* @elem: the element-node to declare on
8396* @nsName: the namespace-name of the ns-decl
8397* @prefix: the preferred prefix of the ns-decl
8398* @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls
8399*
8400* Declares a new namespace on @elem. It tries to use the
8401* given @prefix; if a ns-decl with the given prefix is already existent
8402* on @elem, it will generate an other prefix.
8403*
8404* Returns 1 if a ns-decl was found, 0 if not and -1 on API
8405* and internal errors.
8406*/
8407static xmlNsPtr
8408xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc,
8409 xmlNodePtr elem,
8410 const xmlChar *nsName,
8411 const xmlChar *prefix,
8412 int checkShadow)
8413{
8414
8415 xmlNsPtr ret;
8416 char buf[50];
8417 const xmlChar *pref;
8418 int counter = 0;
8419 /*
8420 * Create a ns-decl on @anchor.
8421 */
8422 pref = prefix;
8423 while (1) {
8424 /*
8425 * Lookup whether the prefix is unused in elem's ns-decls.
8426 */
8427 if ((elem->nsDef != NULL) &&
8428 (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL))
8429 goto ns_next_prefix;
8430 if (checkShadow && elem->parent &&
8431 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8432 /*
8433 * Does it shadow ancestor ns-decls?
8434 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008435 if (xmlSearchNsByPrefixStrict(doc, elem->parent, pref, NULL) == 1)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008436 goto ns_next_prefix;
8437 }
8438 ret = xmlNewNs(NULL, nsName, pref);
8439 if (ret == NULL)
8440 return (NULL);
8441 if (elem->nsDef == NULL)
8442 elem->nsDef = ret;
8443 else {
8444 xmlNsPtr ns2 = elem->nsDef;
8445 while (ns2->next != NULL)
8446 ns2 = ns2->next;
8447 ns2->next = ret;
8448 }
8449 return (ret);
8450ns_next_prefix:
8451 counter++;
8452 if (counter > 1000)
8453 return (NULL);
8454 if (prefix == NULL) {
8455 snprintf((char *) buf, sizeof(buf),
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008456 "ns_%d", counter);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008457 } else
8458 snprintf((char *) buf, sizeof(buf),
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008459 "%.30s_%d", (char *)prefix, counter);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008460 pref = BAD_CAST buf;
8461 }
8462}
8463
8464/*
8465* xmlDOMWrapNSNormAquireNormalizedNs:
8466* @doc: the doc
8467* @elem: the element-node to declare namespaces on
8468* @ns: the ns-struct to use for the search
8469* @retNs: the found/created ns-struct
8470* @nsMap: the ns-map
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008471* @depth: the current tree depth
8472* @ancestorsOnly: search in ancestor ns-decls only
8473* @prefixed: if the searched ns-decl must have a prefix (for attributes)
8474*
8475* Searches for a matching ns-name in the ns-decls of @nsMap, if not
8476* found it will either declare it on @elem, or store it in doc->oldNs.
8477* If a new ns-decl needs to be declared on @elem, it tries to use the
8478* @ns->prefix for it, if this prefix is already in use on @elem, it will
8479* change the prefix or the new ns-decl.
8480*
8481* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8482*/
8483static int
8484xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc,
8485 xmlNodePtr elem,
8486 xmlNsPtr ns,
8487 xmlNsPtr *retNs,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008488 xmlNsMapPtr *nsMap,
Daniel Veillardaa6de472008-08-25 14:53:31 +00008489
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008490 int depth,
8491 int ancestorsOnly,
8492 int prefixed)
8493{
Daniel Veillardaa6de472008-08-25 14:53:31 +00008494 xmlNsMapItemPtr mi;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008495
8496 if ((doc == NULL) || (ns == NULL) || (retNs == NULL) ||
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008497 (nsMap == NULL))
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008498 return (-1);
8499
8500 *retNs = NULL;
8501 /*
8502 * Handle XML namespace.
8503 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008504 if (IS_STR_XML(ns->prefix)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008505 /*
8506 * Insert XML namespace mapping.
8507 */
8508 *retNs = xmlTreeEnsureXMLDecl(doc);
8509 if (*retNs == NULL)
8510 return (-1);
8511 return (0);
8512 }
8513 /*
8514 * If the search should be done in ancestors only and no
8515 * @elem (the first ancestor) was specified, then skip the search.
8516 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008517 if ((XML_NSMAP_NOTEMPTY(*nsMap)) &&
8518 (! (ancestorsOnly && (elem == NULL))))
Daniel Veillardaa6de472008-08-25 14:53:31 +00008519 {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008520 /*
8521 * Try to find an equal ns-name in in-scope ns-decls.
8522 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008523 XML_NSMAP_FOREACH(*nsMap, mi) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00008524 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8525 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008526 * ancestorsOnly: This should be turned on to gain speed,
8527 * if one knows that the branch itself was already
8528 * ns-wellformed and no stale references existed.
8529 * I.e. it searches in the ancestor axis only.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008530 */
8531 ((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) &&
8532 /* Skip shadowed prefixes. */
Daniel Veillardaa6de472008-08-25 14:53:31 +00008533 (mi->shadowDepth == -1) &&
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008534 /* Skip xmlns="" or xmlns:foo="". */
8535 ((mi->newNs->href != NULL) &&
Daniel Veillardaa6de472008-08-25 14:53:31 +00008536 (mi->newNs->href[0] != 0)) &&
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008537 /* Ensure a prefix if wanted. */
8538 ((! prefixed) || (mi->newNs->prefix != NULL)) &&
8539 /* Equal ns name */
8540 ((mi->newNs->href == ns->href) ||
8541 xmlStrEqual(mi->newNs->href, ns->href))) {
8542 /* Set the mapping. */
8543 mi->oldNs = ns;
8544 *retNs = mi->newNs;
8545 return (0);
8546 }
8547 }
8548 }
8549 /*
8550 * No luck, the namespace is out of scope or shadowed.
8551 */
8552 if (elem == NULL) {
8553 xmlNsPtr tmpns;
8554
8555 /*
8556 * Store ns-decls in "oldNs" of the document-node.
8557 */
8558 tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix);
8559 if (tmpns == NULL)
8560 return (-1);
8561 /*
8562 * Insert mapping.
Daniel Veillardaa6de472008-08-25 14:53:31 +00008563 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008564 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008565 tmpns, XML_TREE_NSMAP_DOC) == NULL) {
8566 xmlFreeNs(tmpns);
8567 return (-1);
8568 }
8569 *retNs = tmpns;
8570 } else {
8571 xmlNsPtr tmpns;
8572
8573 tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href,
8574 ns->prefix, 0);
8575 if (tmpns == NULL)
8576 return (-1);
8577
8578 if (*nsMap != NULL) {
8579 /*
8580 * Does it shadow ancestor ns-decls?
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008581 */
8582 XML_NSMAP_FOREACH(*nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008583 if ((mi->depth < depth) &&
8584 (mi->shadowDepth == -1) &&
8585 ((ns->prefix == mi->newNs->prefix) ||
8586 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8587 /*
8588 * Shadows.
8589 */
8590 mi->shadowDepth = depth;
8591 break;
8592 }
8593 }
8594 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008595 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, depth) == NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008596 xmlFreeNs(tmpns);
8597 return (-1);
8598 }
8599 *retNs = tmpns;
8600 }
8601 return (0);
8602}
8603
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008604typedef enum {
Daniel Veillardaa6de472008-08-25 14:53:31 +00008605 XML_DOM_RECONNS_REMOVEREDUND = 1<<0
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008606} xmlDOMReconcileNSOptions;
8607
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008608/*
8609* xmlDOMWrapReconcileNamespaces:
Daniel Veillard304e78c2005-07-03 16:19:41 +00008610* @ctxt: DOM wrapper context, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008611* @elem: the element-node
8612* @options: option flags
8613*
8614* Ensures that ns-references point to ns-decls hold on element-nodes.
8615* Ensures that the tree is namespace wellformed by creating additional
8616* ns-decls where needed. Note that, since prefixes of already existent
8617* ns-decls can be shadowed by this process, it could break QNames in
8618* attribute values or element content.
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008619*
8620* NOTE: This function was not intensively tested.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008621*
8622* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
Daniel Veillardaa6de472008-08-25 14:53:31 +00008623*/
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008624
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008625int
8626xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,
8627 xmlNodePtr elem,
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008628 int options)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008629{
8630 int depth = -1, adoptns = 0, parnsdone = 0;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008631 xmlNsPtr ns, prevns;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008632 xmlDocPtr doc;
8633 xmlNodePtr cur, curElem = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008634 xmlNsMapPtr nsMap = NULL;
8635 xmlNsMapItemPtr /* topmi = NULL, */ mi;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008636 /* @ancestorsOnly should be set by an option flag. */
8637 int ancestorsOnly = 0;
Daniel Veillardaa6de472008-08-25 14:53:31 +00008638 int optRemoveRedundantNS =
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008639 ((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0;
8640 xmlNsPtr *listRedund = NULL;
8641 int sizeRedund = 0, nbRedund = 0, ret, i, j;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008642
8643 if ((elem == NULL) || (elem->doc == NULL) ||
8644 (elem->type != XML_ELEMENT_NODE))
8645 return (-1);
8646
8647 doc = elem->doc;
8648 cur = elem;
8649 do {
8650 switch (cur->type) {
8651 case XML_ELEMENT_NODE:
8652 adoptns = 1;
8653 curElem = cur;
8654 depth++;
8655 /*
8656 * Namespace declarations.
8657 */
8658 if (cur->nsDef != NULL) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008659 prevns = NULL;
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008660 ns = cur->nsDef;
8661 while (ns != NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008662 if (! parnsdone) {
8663 if ((elem->parent) &&
8664 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8665 /*
8666 * Gather ancestor in-scope ns-decls.
8667 */
8668 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8669 elem->parent) == -1)
8670 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008671 }
8672 parnsdone = 1;
8673 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00008674
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008675 /*
8676 * Lookup the ns ancestor-axis for equal ns-decls in scope.
8677 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008678 if (optRemoveRedundantNS && XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008679 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008680 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8681 (mi->shadowDepth == -1) &&
8682 ((ns->prefix == mi->newNs->prefix) ||
8683 xmlStrEqual(ns->prefix, mi->newNs->prefix)) &&
8684 ((ns->href == mi->newNs->href) ||
8685 xmlStrEqual(ns->href, mi->newNs->href)))
Daniel Veillardaa6de472008-08-25 14:53:31 +00008686 {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008687 /*
8688 * A redundant ns-decl was found.
8689 * Add it to the list of redundant ns-decls.
8690 */
8691 if (xmlDOMWrapNSNormAddNsMapItem2(&listRedund,
8692 &sizeRedund, &nbRedund, ns, mi->newNs) == -1)
8693 goto internal_error;
8694 /*
8695 * Remove the ns-decl from the element-node.
Daniel Veillardaa6de472008-08-25 14:53:31 +00008696 */
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008697 if (prevns)
8698 prevns->next = ns->next;
8699 else
Daniel Veillardaa6de472008-08-25 14:53:31 +00008700 cur->nsDef = ns->next;
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008701 goto next_ns_decl;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008702 }
8703 }
8704 }
8705
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008706 /*
8707 * Skip ns-references handling if the referenced
8708 * ns-decl is declared on the same element.
8709 */
8710 if ((cur->ns != NULL) && adoptns && (cur->ns == ns))
Daniel Veillardaa6de472008-08-25 14:53:31 +00008711 adoptns = 0;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008712 /*
8713 * Does it shadow any ns-decl?
8714 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008715 if (XML_NSMAP_NOTEMPTY(nsMap)) {
8716 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008717 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8718 (mi->shadowDepth == -1) &&
8719 ((ns->prefix == mi->newNs->prefix) ||
8720 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00008721
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008722 mi->shadowDepth = depth;
8723 }
8724 }
8725 }
8726 /*
8727 * Push mapping.
8728 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008729 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008730 depth) == NULL)
Daniel Veillardaa6de472008-08-25 14:53:31 +00008731 goto internal_error;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008732
8733 prevns = ns;
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008734next_ns_decl:
Daniel Veillardaa6de472008-08-25 14:53:31 +00008735 ns = ns->next;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008736 }
8737 }
8738 if (! adoptns)
8739 goto ns_end;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008740 /* No break on purpose. */
8741 case XML_ATTRIBUTE_NODE:
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008742 /* No ns, no fun. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008743 if (cur->ns == NULL)
8744 goto ns_end;
Daniel Veillardaa6de472008-08-25 14:53:31 +00008745
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008746 if (! parnsdone) {
8747 if ((elem->parent) &&
8748 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8749 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8750 elem->parent) == -1)
8751 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008752 }
8753 parnsdone = 1;
8754 }
8755 /*
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008756 * Adjust the reference if this was a redundant ns-decl.
8757 */
8758 if (listRedund) {
8759 for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8760 if (cur->ns == listRedund[j]) {
8761 cur->ns = listRedund[++j];
8762 break;
8763 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00008764 }
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008765 }
8766 /*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008767 * Adopt ns-references.
8768 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008769 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008770 /*
8771 * Search for a mapping.
8772 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008773 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008774 if ((mi->shadowDepth == -1) &&
8775 (cur->ns == mi->oldNs)) {
8776
8777 cur->ns = mi->newNs;
8778 goto ns_end;
8779 }
8780 }
8781 }
8782 /*
8783 * Aquire a normalized ns-decl and add it to the map.
8784 */
8785 if (xmlDOMWrapNSNormAquireNormalizedNs(doc, curElem,
8786 cur->ns, &ns,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008787 &nsMap, depth,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008788 ancestorsOnly,
8789 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8790 goto internal_error;
8791 cur->ns = ns;
8792
8793ns_end:
8794 if ((cur->type == XML_ELEMENT_NODE) &&
8795 (cur->properties != NULL)) {
8796 /*
8797 * Process attributes.
8798 */
8799 cur = (xmlNodePtr) cur->properties;
8800 continue;
8801 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00008802 break;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008803 default:
8804 goto next_sibling;
8805 }
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008806into_content:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008807 if ((cur->type == XML_ELEMENT_NODE) &&
8808 (cur->children != NULL)) {
8809 /*
8810 * Process content of element-nodes only.
8811 */
8812 cur = cur->children;
8813 continue;
8814 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00008815next_sibling:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008816 if (cur == elem)
8817 break;
8818 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00008819 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008820 /*
8821 * Pop mappings.
8822 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008823 while ((nsMap->last != NULL) &&
8824 (nsMap->last->depth >= depth))
8825 {
Daniel Veillardaa6de472008-08-25 14:53:31 +00008826 XML_NSMAP_POP(nsMap, mi)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008827 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008828 /*
8829 * Unshadow.
8830 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008831 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008832 if (mi->shadowDepth >= depth)
8833 mi->shadowDepth = -1;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008834 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00008835 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008836 depth--;
8837 }
8838 if (cur->next != NULL)
8839 cur = cur->next;
8840 else {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008841 if (cur->type == XML_ATTRIBUTE_NODE) {
8842 cur = cur->parent;
8843 goto into_content;
8844 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008845 cur = cur->parent;
8846 goto next_sibling;
8847 }
8848 } while (cur != NULL);
Daniel Veillardaa6de472008-08-25 14:53:31 +00008849
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008850 ret = 0;
8851 goto exit;
8852internal_error:
8853 ret = -1;
8854exit:
Daniel Veillardaa6de472008-08-25 14:53:31 +00008855 if (listRedund) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008856 for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8857 xmlFreeNs(listRedund[j]);
8858 }
8859 xmlFree(listRedund);
8860 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008861 if (nsMap != NULL)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008862 xmlDOMWrapNsMapFree(nsMap);
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008863 return (ret);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008864}
8865
8866/*
8867* xmlDOMWrapAdoptBranch:
8868* @ctxt: the optional context for custom processing
8869* @sourceDoc: the optional sourceDoc
8870* @node: the element-node to start with
8871* @destDoc: the destination doc for adoption
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008872* @destParent: the optional new parent of @node in @destDoc
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008873* @options: option flags
8874*
8875* Ensures that ns-references point to @destDoc: either to
8876* elements->nsDef entries if @destParent is given, or to
8877* @destDoc->oldNs otherwise.
8878* If @destParent is given, it ensures that the tree is namespace
8879* wellformed by creating additional ns-decls where needed.
8880* Note that, since prefixes of already existent ns-decls can be
8881* shadowed by this process, it could break QNames in attribute
8882* values or element content.
8883*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008884* NOTE: This function was not intensively tested.
8885*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008886* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8887*/
8888static int
8889xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
8890 xmlDocPtr sourceDoc,
8891 xmlNodePtr node,
8892 xmlDocPtr destDoc,
8893 xmlNodePtr destParent,
8894 int options ATTRIBUTE_UNUSED)
8895{
8896 int ret = 0;
8897 xmlNodePtr cur, curElem = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008898 xmlNsMapPtr nsMap = NULL;
8899 xmlNsMapItemPtr mi;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008900 xmlNsPtr ns = NULL;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008901 int depth = -1, adoptStr = 1;
8902 /* gather @parent's ns-decls. */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008903 int parnsdone;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008904 /* @ancestorsOnly should be set per option. */
8905 int ancestorsOnly = 0;
Daniel Veillardaa6de472008-08-25 14:53:31 +00008906
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008907 /*
8908 * Optimize string adoption for equal or none dicts.
8909 */
8910 if ((sourceDoc != NULL) &&
8911 (sourceDoc->dict == destDoc->dict))
8912 adoptStr = 0;
8913 else
8914 adoptStr = 1;
8915
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008916 /*
8917 * Get the ns-map from the context if available.
8918 */
8919 if (ctxt)
8920 nsMap = (xmlNsMapPtr) ctxt->namespaceMap;
8921 /*
8922 * Disable search for ns-decls in the parent-axis of the
8923 * desination element, if:
8924 * 1) there's no destination parent
8925 * 2) custom ns-reference handling is used
8926 */
8927 if ((destParent == NULL) ||
8928 (ctxt && ctxt->getNsForNodeFunc))
8929 {
8930 parnsdone = 1;
8931 } else
8932 parnsdone = 0;
8933
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008934 cur = node;
8935 while (cur != NULL) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008936 /*
8937 * Paranoid source-doc sanity check.
8938 */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008939 if (cur->doc != sourceDoc) {
8940 /*
8941 * We'll assume XIncluded nodes if the doc differs.
8942 * TODO: Do we need to reconciliate XIncluded nodes?
8943 * This here skips XIncluded nodes and tries to handle
8944 * broken sequences.
8945 */
8946 if (cur->next == NULL)
8947 goto leave_node;
8948 do {
8949 cur = cur->next;
8950 if ((cur->type == XML_XINCLUDE_END) ||
8951 (cur->doc == node->doc))
8952 break;
8953 } while (cur->next != NULL);
8954
8955 if (cur->doc != node->doc)
8956 goto leave_node;
8957 }
8958 cur->doc = destDoc;
8959 switch (cur->type) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00008960 case XML_XINCLUDE_START:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008961 case XML_XINCLUDE_END:
8962 /*
8963 * TODO
8964 */
8965 return (-1);
Daniel Veillardaa6de472008-08-25 14:53:31 +00008966 case XML_ELEMENT_NODE:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008967 curElem = cur;
8968 depth++;
8969 /*
Daniel Veillardaa6de472008-08-25 14:53:31 +00008970 * Namespace declarations.
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008971 * - ns->href and ns->prefix are never in the dict, so
8972 * we need not move the values over to the destination dict.
8973 * - Note that for custom handling of ns-references,
8974 * the ns-decls need not be stored in the ns-map,
8975 * since they won't be referenced by node->ns.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008976 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008977 if ((cur->nsDef) &&
8978 ((ctxt == NULL) || (ctxt->getNsForNodeFunc == NULL)))
8979 {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008980 if (! parnsdone) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008981 /*
8982 * Gather @parent's in-scope ns-decls.
8983 */
8984 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8985 destParent) == -1)
8986 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008987 parnsdone = 1;
8988 }
8989 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8990 /*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008991 * NOTE: ns->prefix and ns->href are never in the dict.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008992 * XML_TREE_ADOPT_STR(ns->prefix)
8993 * XML_TREE_ADOPT_STR(ns->href)
Daniel Veillardaa6de472008-08-25 14:53:31 +00008994 */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008995 /*
8996 * Does it shadow any ns-decl?
Daniel Veillardaa6de472008-08-25 14:53:31 +00008997 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008998 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008999 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009000 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
9001 (mi->shadowDepth == -1) &&
9002 ((ns->prefix == mi->newNs->prefix) ||
9003 xmlStrEqual(ns->prefix,
9004 mi->newNs->prefix))) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00009005
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009006 mi->shadowDepth = depth;
9007 }
9008 }
9009 }
9010 /*
9011 * Push mapping.
9012 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009013 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009014 ns, ns, depth) == NULL)
9015 goto internal_error;
9016 }
9017 }
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009018 /* No break on purpose. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009019 case XML_ATTRIBUTE_NODE:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009020 /* No namespace, no fun. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009021 if (cur->ns == NULL)
9022 goto ns_end;
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009023
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009024 if (! parnsdone) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009025 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
9026 destParent) == -1)
9027 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009028 parnsdone = 1;
9029 }
9030 /*
9031 * Adopt ns-references.
9032 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009033 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009034 /*
9035 * Search for a mapping.
9036 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009037 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009038 if ((mi->shadowDepth == -1) &&
9039 (cur->ns == mi->oldNs)) {
9040
9041 cur->ns = mi->newNs;
9042 goto ns_end;
9043 }
9044 }
9045 }
9046 /*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009047 * No matching namespace in scope. We need a new one.
9048 */
9049 if ((ctxt) && (ctxt->getNsForNodeFunc)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009050 /*
9051 * User-defined behaviour.
9052 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009053 ns = ctxt->getNsForNodeFunc(ctxt, cur,
9054 cur->ns->href, cur->ns->prefix);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009055 /*
9056 * Insert mapping if ns is available; it's the users fault
9057 * if not.
9058 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009059 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009060 cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009061 goto internal_error;
9062 cur->ns = ns;
9063 } else {
9064 /*
9065 * Aquire a normalized ns-decl and add it to the map.
9066 */
9067 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
Daniel Veillardaa6de472008-08-25 14:53:31 +00009068 /* ns-decls on curElem or on destDoc->oldNs */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009069 destParent ? curElem : NULL,
9070 cur->ns, &ns,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009071 &nsMap, depth,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009072 ancestorsOnly,
9073 /* ns-decls must be prefixed for attributes. */
9074 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
9075 goto internal_error;
9076 cur->ns = ns;
9077 }
9078ns_end:
9079 /*
9080 * Further node properties.
9081 * TODO: Is this all?
9082 */
9083 XML_TREE_ADOPT_STR(cur->name)
9084 if (cur->type == XML_ELEMENT_NODE) {
9085 cur->psvi = NULL;
9086 cur->line = 0;
9087 cur->extra = 0;
9088 /*
9089 * Walk attributes.
9090 */
9091 if (cur->properties != NULL) {
9092 /*
9093 * Process first attribute node.
9094 */
9095 cur = (xmlNodePtr) cur->properties;
9096 continue;
9097 }
9098 } else {
9099 /*
9100 * Attributes.
9101 */
9102 if ((sourceDoc != NULL) &&
9103 (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID))
Daniel Veillardaa6de472008-08-25 14:53:31 +00009104 {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009105 xmlRemoveID(sourceDoc, (xmlAttrPtr) cur);
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009106 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009107 ((xmlAttrPtr) cur)->atype = 0;
9108 ((xmlAttrPtr) cur)->psvi = NULL;
9109 }
9110 break;
9111 case XML_TEXT_NODE:
Daniel Veillardaa6de472008-08-25 14:53:31 +00009112 case XML_CDATA_SECTION_NODE:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009113 /*
9114 * This puts the content in the dest dict, only if
9115 * it was previously in the source dict.
9116 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00009117 XML_TREE_ADOPT_STR_2(cur->content)
9118 goto leave_node;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009119 case XML_ENTITY_REF_NODE:
9120 /*
9121 * Remove reference to the entitity-node.
9122 */
9123 cur->content = NULL;
9124 cur->children = NULL;
9125 cur->last = NULL;
9126 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9127 xmlEntityPtr ent;
9128 /*
9129 * Assign new entity-node if available.
9130 */
9131 ent = xmlGetDocEntity(destDoc, cur->name);
9132 if (ent != NULL) {
9133 cur->content = ent->content;
9134 cur->children = (xmlNodePtr) ent;
9135 cur->last = (xmlNodePtr) ent;
9136 }
9137 }
9138 goto leave_node;
9139 case XML_PI_NODE:
9140 XML_TREE_ADOPT_STR(cur->name)
9141 XML_TREE_ADOPT_STR_2(cur->content)
9142 break;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009143 case XML_COMMENT_NODE:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009144 break;
9145 default:
9146 goto internal_error;
9147 }
9148 /*
9149 * Walk the tree.
9150 */
9151 if (cur->children != NULL) {
9152 cur = cur->children;
9153 continue;
9154 }
9155
9156leave_node:
9157 if (cur == node)
9158 break;
9159 if ((cur->type == XML_ELEMENT_NODE) ||
9160 (cur->type == XML_XINCLUDE_START) ||
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009161 (cur->type == XML_XINCLUDE_END))
9162 {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009163 /*
9164 * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
9165 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00009166 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009167 /*
9168 * Pop mappings.
9169 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009170 while ((nsMap->last != NULL) &&
9171 (nsMap->last->depth >= depth))
9172 {
Daniel Veillardaa6de472008-08-25 14:53:31 +00009173 XML_NSMAP_POP(nsMap, mi)
9174 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009175 /*
9176 * Unshadow.
9177 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009178 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009179 if (mi->shadowDepth >= depth)
9180 mi->shadowDepth = -1;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009181 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009182 }
9183 depth--;
9184 }
9185 if (cur->next != NULL)
9186 cur = cur->next;
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009187 else if ((cur->type == XML_ATTRIBUTE_NODE) &&
9188 (cur->parent->children != NULL))
9189 {
9190 cur = cur->parent->children;
9191 } else {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009192 cur = cur->parent;
9193 goto leave_node;
9194 }
9195 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009196
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009197 goto exit;
9198
Daniel Veillardaa6de472008-08-25 14:53:31 +00009199internal_error:
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009200 ret = -1;
9201
9202exit:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009203 /*
9204 * Cleanup.
9205 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009206 if (nsMap != NULL) {
9207 if ((ctxt) && (ctxt->namespaceMap == nsMap)) {
9208 /*
9209 * Just cleanup the map but don't free.
9210 */
9211 if (nsMap->first) {
9212 if (nsMap->pool)
9213 nsMap->last->next = nsMap->pool;
9214 nsMap->pool = nsMap->first;
9215 nsMap->first = NULL;
9216 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009217 } else
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009218 xmlDOMWrapNsMapFree(nsMap);
9219 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009220 return(ret);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009221}
9222
9223/*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009224* xmlDOMWrapCloneNode:
9225* @ctxt: the optional context for custom processing
9226* @sourceDoc: the optional sourceDoc
9227* @node: the node to start with
9228* @resNode: the clone of the given @node
9229* @destDoc: the destination doc
9230* @destParent: the optional new parent of @node in @destDoc
Daniel Veillardb2f8f1d2006-04-28 16:30:48 +00009231* @deep: descend into child if set
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009232* @options: option flags
9233*
9234* References of out-of scope ns-decls are remapped to point to @destDoc:
9235* 1) If @destParent is given, then nsDef entries on element-nodes are used
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009236* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used.
9237* This is the case when you don't know already where the cloned branch
9238* will be added to.
Daniel Veillardaa6de472008-08-25 14:53:31 +00009239*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009240* If @destParent is given, it ensures that the tree is namespace
9241* wellformed by creating additional ns-decls where needed.
9242* Note that, since prefixes of already existent ns-decls can be
9243* shadowed by this process, it could break QNames in attribute
9244* values or element content.
9245* TODO:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009246* 1) What to do with XInclude? Currently this returns an error for XInclude.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009247*
9248* Returns 0 if the operation succeeded,
9249* 1 if a node of unsupported (or not yet supported) type was given,
9250* -1 on API/internal errors.
9251*/
9252
9253int
9254xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt,
9255 xmlDocPtr sourceDoc,
9256 xmlNodePtr node,
9257 xmlNodePtr *resNode,
9258 xmlDocPtr destDoc,
9259 xmlNodePtr destParent,
9260 int deep,
9261 int options ATTRIBUTE_UNUSED)
9262{
9263 int ret = 0;
9264 xmlNodePtr cur, curElem = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009265 xmlNsMapPtr nsMap = NULL;
9266 xmlNsMapItemPtr mi;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009267 xmlNsPtr ns;
9268 int depth = -1;
9269 /* int adoptStr = 1; */
9270 /* gather @parent's ns-decls. */
9271 int parnsdone = 0;
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009272 /*
Daniel Veillardaa6de472008-08-25 14:53:31 +00009273 * @ancestorsOnly:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009274 * TODO: @ancestorsOnly should be set per option.
9275 *
9276 */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009277 int ancestorsOnly = 0;
9278 xmlNodePtr resultClone = NULL, clone = NULL, parentClone = NULL, prevClone = NULL;
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009279 xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL;
9280 xmlDictPtr dict; /* The destination dict */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009281
Daniel Veillard11ce4002006-03-10 00:36:23 +00009282 if ((node == NULL) || (resNode == NULL) || (destDoc == NULL))
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009283 return(-1);
9284 /*
9285 * TODO: Initially we support only element-nodes.
9286 */
9287 if (node->type != XML_ELEMENT_NODE)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009288 return(1);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009289 /*
9290 * Check node->doc sanity.
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009291 */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009292 if ((node->doc != NULL) && (sourceDoc != NULL) &&
9293 (node->doc != sourceDoc)) {
9294 /*
9295 * Might be an XIncluded node.
9296 */
9297 return (-1);
9298 }
9299 if (sourceDoc == NULL)
Daniel Veillardaa6de472008-08-25 14:53:31 +00009300 sourceDoc = node->doc;
Daniel Veillard11ce4002006-03-10 00:36:23 +00009301 if (sourceDoc == NULL)
9302 return (-1);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009303
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009304 dict = destDoc->dict;
9305 /*
9306 * Reuse the namespace map of the context.
9307 */
9308 if (ctxt)
9309 nsMap = (xmlNsMapPtr) ctxt->namespaceMap;
9310
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009311 *resNode = NULL;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009312
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009313 cur = node;
9314 while (cur != NULL) {
9315 if (cur->doc != sourceDoc) {
9316 /*
9317 * We'll assume XIncluded nodes if the doc differs.
9318 * TODO: Do we need to reconciliate XIncluded nodes?
9319 * TODO: This here returns -1 in this case.
9320 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00009321 goto internal_error;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009322 }
9323 /*
9324 * Create a new node.
9325 */
9326 switch (cur->type) {
9327 case XML_XINCLUDE_START:
9328 case XML_XINCLUDE_END:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009329 /*
9330 * TODO: What to do with XInclude?
9331 */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009332 goto internal_error;
9333 break;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009334 case XML_ELEMENT_NODE:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009335 case XML_TEXT_NODE:
Daniel Veillardaa6de472008-08-25 14:53:31 +00009336 case XML_CDATA_SECTION_NODE:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009337 case XML_COMMENT_NODE:
Daniel Veillardaa6de472008-08-25 14:53:31 +00009338 case XML_PI_NODE:
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009339 case XML_DOCUMENT_FRAG_NODE:
9340 case XML_ENTITY_REF_NODE:
9341 case XML_ENTITY_NODE:
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009342 /*
9343 * Nodes of xmlNode structure.
9344 */
9345 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
9346 if (clone == NULL) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009347 xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating a node");
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009348 goto internal_error;
9349 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009350 memset(clone, 0, sizeof(xmlNode));
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009351 /*
9352 * Set hierachical links.
9353 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00009354 if (resultClone != NULL) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009355 clone->parent = parentClone;
9356 if (prevClone) {
9357 prevClone->next = clone;
9358 clone->prev = prevClone;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009359 } else
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009360 parentClone->children = clone;
9361 } else
9362 resultClone = clone;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009363
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009364 break;
9365 case XML_ATTRIBUTE_NODE:
9366 /*
9367 * Attributes (xmlAttr).
9368 */
9369 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlAttr));
9370 if (clone == NULL) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009371 xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating an attr-node");
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009372 goto internal_error;
9373 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009374 memset(clone, 0, sizeof(xmlAttr));
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009375 /*
9376 * Set hierachical links.
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009377 * TODO: Change this to add to the end of attributes.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009378 */
9379 if (resultClone != NULL) {
9380 clone->parent = parentClone;
9381 if (prevClone) {
9382 prevClone->next = clone;
9383 clone->prev = prevClone;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009384 } else
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009385 parentClone->properties = (xmlAttrPtr) clone;
9386 } else
9387 resultClone = clone;
9388 break;
9389 default:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009390 /*
9391 * TODO QUESTION: Any other nodes expected?
9392 */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009393 goto internal_error;
9394 }
9395
9396 clone->type = cur->type;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009397 clone->doc = destDoc;
9398
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009399 /*
9400 * Clone the name of the node if any.
9401 */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009402 if (cur->name == xmlStringText)
9403 clone->name = xmlStringText;
9404 else if (cur->name == xmlStringTextNoenc)
9405 /*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009406 * NOTE: Although xmlStringTextNoenc is never assigned to a node
9407 * in tree.c, it might be set in Libxslt via
Daniel Veillardaa6de472008-08-25 14:53:31 +00009408 * "xsl:disable-output-escaping".
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009409 */
9410 clone->name = xmlStringTextNoenc;
9411 else if (cur->name == xmlStringComment)
9412 clone->name = xmlStringComment;
9413 else if (cur->name != NULL) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009414 DICT_CONST_COPY(cur->name, clone->name);
Daniel Veillardaa6de472008-08-25 14:53:31 +00009415 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009416
9417 switch (cur->type) {
9418 case XML_XINCLUDE_START:
9419 case XML_XINCLUDE_END:
9420 /*
9421 * TODO
9422 */
9423 return (-1);
9424 case XML_ELEMENT_NODE:
9425 curElem = cur;
9426 depth++;
9427 /*
9428 * Namespace declarations.
9429 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009430 if (cur->nsDef != NULL) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009431 if (! parnsdone) {
9432 if (destParent && (ctxt == NULL)) {
9433 /*
9434 * Gather @parent's in-scope ns-decls.
9435 */
9436 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
9437 destParent) == -1)
Daniel Veillardaa6de472008-08-25 14:53:31 +00009438 goto internal_error;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009439 }
9440 parnsdone = 1;
9441 }
9442 /*
9443 * Clone namespace declarations.
9444 */
9445 cloneNsDefSlot = &(clone->nsDef);
9446 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
9447 /*
9448 * Create a new xmlNs.
9449 */
9450 cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
9451 if (cloneNs == NULL) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009452 xmlTreeErrMemory("xmlDOMWrapCloneNode(): "
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009453 "allocating namespace");
9454 return(-1);
9455 }
9456 memset(cloneNs, 0, sizeof(xmlNs));
9457 cloneNs->type = XML_LOCAL_NAMESPACE;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009458
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009459 if (ns->href != NULL)
9460 cloneNs->href = xmlStrdup(ns->href);
9461 if (ns->prefix != NULL)
9462 cloneNs->prefix = xmlStrdup(ns->prefix);
9463
9464 *cloneNsDefSlot = cloneNs;
9465 cloneNsDefSlot = &(cloneNs->next);
9466
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009467 /*
9468 * Note that for custom handling of ns-references,
9469 * the ns-decls need not be stored in the ns-map,
9470 * since they won't be referenced by node->ns.
9471 */
9472 if ((ctxt == NULL) ||
9473 (ctxt->getNsForNodeFunc == NULL))
9474 {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009475 /*
9476 * Does it shadow any ns-decl?
9477 */
9478 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00009479 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009480 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
9481 (mi->shadowDepth == -1) &&
9482 ((ns->prefix == mi->newNs->prefix) ||
9483 xmlStrEqual(ns->prefix,
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009484 mi->newNs->prefix))) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009485 /*
9486 * Mark as shadowed at the current
9487 * depth.
9488 */
9489 mi->shadowDepth = depth;
9490 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009491 }
9492 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009493 /*
9494 * Push mapping.
9495 */
9496 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
9497 ns, cloneNs, depth) == NULL)
9498 goto internal_error;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009499 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009500 }
9501 }
9502 /* cur->ns will be processed further down. */
9503 break;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009504 case XML_ATTRIBUTE_NODE:
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009505 /* IDs will be processed further down. */
9506 /* cur->ns will be processed further down. */
9507 break;
9508 case XML_TEXT_NODE:
9509 case XML_CDATA_SECTION_NODE:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009510 /*
9511 * Note that this will also cover the values of attributes.
9512 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00009513 DICT_COPY(cur->content, clone->content);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009514 goto leave_node;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009515 case XML_ENTITY_NODE:
9516 /* TODO: What to do here? */
9517 goto leave_node;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009518 case XML_ENTITY_REF_NODE:
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009519 if (sourceDoc != destDoc) {
9520 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9521 xmlEntityPtr ent;
9522 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009523 * Different doc: Assign new entity-node if available.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009524 */
9525 ent = xmlGetDocEntity(destDoc, cur->name);
9526 if (ent != NULL) {
9527 clone->content = ent->content;
9528 clone->children = (xmlNodePtr) ent;
9529 clone->last = (xmlNodePtr) ent;
9530 }
9531 }
9532 } else {
9533 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009534 * Same doc: Use the current node's entity declaration
9535 * and value.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009536 */
9537 clone->content = cur->content;
9538 clone->children = cur->children;
9539 clone->last = cur->last;
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009540 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009541 goto leave_node;
9542 case XML_PI_NODE:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009543 DICT_COPY(cur->content, clone->content);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009544 goto leave_node;
9545 case XML_COMMENT_NODE:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009546 DICT_COPY(cur->content, clone->content);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009547 goto leave_node;
9548 default:
9549 goto internal_error;
9550 }
9551
9552 if (cur->ns == NULL)
9553 goto end_ns_reference;
9554
9555/* handle_ns_reference: */
9556 /*
9557 ** The following will take care of references to ns-decls ********
Daniel Veillardaa6de472008-08-25 14:53:31 +00009558 ** and is intended only for element- and attribute-nodes.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009559 **
9560 */
9561 if (! parnsdone) {
9562 if (destParent && (ctxt == NULL)) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009563 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1)
Daniel Veillardaa6de472008-08-25 14:53:31 +00009564 goto internal_error;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009565 }
9566 parnsdone = 1;
9567 }
9568 /*
9569 * Adopt ns-references.
9570 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009571 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009572 /*
9573 * Search for a mapping.
9574 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00009575 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009576 if ((mi->shadowDepth == -1) &&
9577 (cur->ns == mi->oldNs)) {
9578 /*
9579 * This is the nice case: a mapping was found.
9580 */
9581 clone->ns = mi->newNs;
9582 goto end_ns_reference;
9583 }
9584 }
9585 }
9586 /*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009587 * No matching namespace in scope. We need a new one.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009588 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009589 if ((ctxt != NULL) && (ctxt->getNsForNodeFunc != NULL)) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009590 /*
9591 * User-defined behaviour.
9592 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009593 ns = ctxt->getNsForNodeFunc(ctxt, cur,
9594 cur->ns->href, cur->ns->prefix);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009595 /*
9596 * Add user's mapping.
9597 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009598 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009599 cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
9600 goto internal_error;
9601 clone->ns = ns;
9602 } else {
9603 /*
9604 * Aquire a normalized ns-decl and add it to the map.
9605 */
9606 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
Daniel Veillardaa6de472008-08-25 14:53:31 +00009607 /* ns-decls on curElem or on destDoc->oldNs */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009608 destParent ? curElem : NULL,
9609 cur->ns, &ns,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009610 &nsMap, depth,
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009611 /* if we need to search only in the ancestor-axis */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009612 ancestorsOnly,
9613 /* ns-decls must be prefixed for attributes. */
9614 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
9615 goto internal_error;
9616 clone->ns = ns;
9617 }
9618
9619end_ns_reference:
9620
9621 /*
9622 * Some post-processing.
9623 *
9624 * Handle ID attributes.
9625 */
9626 if ((clone->type == XML_ATTRIBUTE_NODE) &&
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009627 (clone->parent != NULL))
9628 {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009629 if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00009630
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009631 xmlChar *idVal;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009632
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009633 idVal = xmlNodeListGetString(cur->doc, cur->children, 1);
9634 if (idVal != NULL) {
9635 if (xmlAddID(NULL, destDoc, idVal, (xmlAttrPtr) cur) == NULL) {
9636 /* TODO: error message. */
9637 xmlFree(idVal);
9638 goto internal_error;
9639 }
9640 xmlFree(idVal);
9641 }
9642 }
9643 }
9644 /*
9645 **
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009646 ** The following will traverse the tree **************************
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009647 **
Daniel Veillardaa6de472008-08-25 14:53:31 +00009648 *
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009649 * Walk the element's attributes before descending into child-nodes.
9650 */
9651 if ((cur->type == XML_ELEMENT_NODE) && (cur->properties != NULL)) {
9652 prevClone = NULL;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009653 parentClone = clone;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009654 cur = (xmlNodePtr) cur->properties;
9655 continue;
9656 }
9657into_content:
9658 /*
9659 * Descend into child-nodes.
9660 */
9661 if (cur->children != NULL) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009662 if (deep || (cur->type == XML_ATTRIBUTE_NODE)) {
9663 prevClone = NULL;
9664 parentClone = clone;
9665 cur = cur->children;
9666 continue;
9667 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009668 }
9669
9670leave_node:
9671 /*
9672 * At this point we are done with the node, its content
9673 * and an element-nodes's attribute-nodes.
9674 */
9675 if (cur == node)
9676 break;
9677 if ((cur->type == XML_ELEMENT_NODE) ||
9678 (cur->type == XML_XINCLUDE_START) ||
9679 (cur->type == XML_XINCLUDE_END)) {
9680 /*
9681 * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
9682 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00009683 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009684 /*
9685 * Pop mappings.
9686 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009687 while ((nsMap->last != NULL) &&
9688 (nsMap->last->depth >= depth))
9689 {
Daniel Veillardaa6de472008-08-25 14:53:31 +00009690 XML_NSMAP_POP(nsMap, mi)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009691 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009692 /*
9693 * Unshadow.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009694 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009695 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009696 if (mi->shadowDepth >= depth)
9697 mi->shadowDepth = -1;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009698 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009699 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009700 depth--;
9701 }
9702 if (cur->next != NULL) {
9703 prevClone = clone;
9704 cur = cur->next;
9705 } else if (cur->type != XML_ATTRIBUTE_NODE) {
9706 /*
9707 * Set clone->last.
9708 */
Daniel Veillard11ce4002006-03-10 00:36:23 +00009709 if (clone->parent != NULL)
9710 clone->parent->last = clone;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009711 clone = clone->parent;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009712 parentClone = clone->parent;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009713 /*
9714 * Process parent --> next;
9715 */
9716 cur = cur->parent;
9717 goto leave_node;
9718 } else {
9719 /* This is for attributes only. */
9720 clone = clone->parent;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009721 parentClone = clone->parent;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009722 /*
9723 * Process parent-element --> children.
9724 */
9725 cur = cur->parent;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009726 goto into_content;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009727 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009728 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009729 goto exit;
9730
9731internal_error:
9732 ret = -1;
9733
9734exit:
9735 /*
9736 * Cleanup.
9737 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009738 if (nsMap != NULL) {
9739 if ((ctxt) && (ctxt->namespaceMap == nsMap)) {
9740 /*
9741 * Just cleanup the map but don't free.
9742 */
9743 if (nsMap->first) {
9744 if (nsMap->pool)
9745 nsMap->last->next = nsMap->pool;
9746 nsMap->pool = nsMap->first;
9747 nsMap->first = NULL;
9748 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009749 } else
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009750 xmlDOMWrapNsMapFree(nsMap);
9751 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009752 /*
9753 * TODO: Should we try a cleanup of the cloned node in case of a
9754 * fatal error?
9755 */
9756 *resNode = resultClone;
9757 return (ret);
9758}
9759
9760/*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009761* xmlDOMWrapAdoptAttr:
9762* @ctxt: the optional context for custom processing
9763* @sourceDoc: the optional source document of attr
9764* @attr: the attribute-node to be adopted
9765* @destDoc: the destination doc for adoption
9766* @destParent: the optional new parent of @attr in @destDoc
9767* @options: option flags
9768*
9769* @attr is adopted by @destDoc.
9770* Ensures that ns-references point to @destDoc: either to
9771* elements->nsDef entries if @destParent is given, or to
9772* @destDoc->oldNs otherwise.
9773*
9774* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
9775*/
9776static int
9777xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt,
9778 xmlDocPtr sourceDoc,
9779 xmlAttrPtr attr,
9780 xmlDocPtr destDoc,
9781 xmlNodePtr destParent,
9782 int options ATTRIBUTE_UNUSED)
9783{
9784 xmlNodePtr cur;
9785 int adoptStr = 1;
9786
9787 if ((attr == NULL) || (destDoc == NULL))
9788 return (-1);
Daniel Veillardaa6de472008-08-25 14:53:31 +00009789
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009790 attr->doc = destDoc;
9791 if (attr->ns != NULL) {
9792 xmlNsPtr ns = NULL;
9793
9794 if (ctxt != NULL) {
9795 /* TODO: User defined. */
9796 }
9797 /* XML Namespace. */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009798 if (IS_STR_XML(attr->ns->prefix)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009799 ns = xmlTreeEnsureXMLDecl(destDoc);
9800 } else if (destParent == NULL) {
9801 /*
9802 * Store in @destDoc->oldNs.
9803 */
9804 ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix);
9805 } else {
9806 /*
9807 * Declare on @destParent.
9808 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009809 if (xmlSearchNsByNamespaceStrict(destDoc, destParent, attr->ns->href,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009810 &ns, 1) == -1)
9811 goto internal_error;
9812 if (ns == NULL) {
9813 ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent,
9814 attr->ns->href, attr->ns->prefix, 1);
9815 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009816 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009817 if (ns == NULL)
9818 goto internal_error;
9819 attr->ns = ns;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009820 }
9821
9822 XML_TREE_ADOPT_STR(attr->name);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009823 attr->atype = 0;
9824 attr->psvi = NULL;
9825 /*
9826 * Walk content.
9827 */
9828 if (attr->children == NULL)
9829 return (0);
9830 cur = attr->children;
9831 while (cur != NULL) {
9832 cur->doc = destDoc;
9833 switch (cur->type) {
9834 case XML_TEXT_NODE:
9835 case XML_CDATA_SECTION_NODE:
9836 XML_TREE_ADOPT_STR_2(cur->content)
Daniel Veillardaa6de472008-08-25 14:53:31 +00009837 break;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009838 case XML_ENTITY_REF_NODE:
9839 /*
9840 * Remove reference to the entitity-node.
9841 */
9842 cur->content = NULL;
9843 cur->children = NULL;
9844 cur->last = NULL;
9845 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9846 xmlEntityPtr ent;
9847 /*
9848 * Assign new entity-node if available.
9849 */
9850 ent = xmlGetDocEntity(destDoc, cur->name);
9851 if (ent != NULL) {
9852 cur->content = ent->content;
9853 cur->children = (xmlNodePtr) ent;
9854 cur->last = (xmlNodePtr) ent;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009855 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009856 }
9857 break;
9858 default:
9859 break;
9860 }
9861 if (cur->children != NULL) {
9862 cur = cur->children;
9863 continue;
9864 }
9865next_sibling:
9866 if (cur == (xmlNodePtr) attr)
9867 break;
9868 if (cur->next != NULL)
9869 cur = cur->next;
9870 else {
9871 cur = cur->parent;
9872 goto next_sibling;
9873 }
9874 }
9875 return (0);
9876internal_error:
9877 return (-1);
9878}
9879
9880/*
9881* xmlDOMWrapAdoptNode:
9882* @ctxt: the optional context for custom processing
9883* @sourceDoc: the optional sourceDoc
9884* @node: the node to start with
9885* @destDoc: the destination doc
Kasimier T. Buchcik4d9c9482005-06-27 15:04:46 +00009886* @destParent: the optional new parent of @node in @destDoc
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009887* @options: option flags
9888*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009889* References of out-of scope ns-decls are remapped to point to @destDoc:
9890* 1) If @destParent is given, then nsDef entries on element-nodes are used
9891* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used
9892* This is the case when you have an unliked node and just want to move it
Daniel Veillardaa6de472008-08-25 14:53:31 +00009893* to the context of
9894*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009895* If @destParent is given, it ensures that the tree is namespace
9896* wellformed by creating additional ns-decls where needed.
9897* Note that, since prefixes of already existent ns-decls can be
9898* shadowed by this process, it could break QNames in attribute
9899* values or element content.
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009900* NOTE: This function was not intensively tested.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009901*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009902* Returns 0 if the operation succeeded,
9903* 1 if a node of unsupported type was given,
9904* 2 if a node of not yet supported type was given and
9905* -1 on API/internal errors.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009906*/
9907int
9908xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt,
9909 xmlDocPtr sourceDoc,
9910 xmlNodePtr node,
Daniel Veillardaa6de472008-08-25 14:53:31 +00009911 xmlDocPtr destDoc,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009912 xmlNodePtr destParent,
9913 int options)
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009914{
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009915 if ((node == NULL) || (destDoc == NULL) ||
9916 ((destParent != NULL) && (destParent->doc != destDoc)))
9917 return(-1);
9918 /*
9919 * Check node->doc sanity.
Daniel Veillardaa6de472008-08-25 14:53:31 +00009920 */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009921 if ((node->doc != NULL) && (sourceDoc != NULL) &&
9922 (node->doc != sourceDoc)) {
9923 /*
9924 * Might be an XIncluded node.
9925 */
9926 return (-1);
9927 }
9928 if (sourceDoc == NULL)
9929 sourceDoc = node->doc;
9930 if (sourceDoc == destDoc)
9931 return (-1);
9932 switch (node->type) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00009933 case XML_ELEMENT_NODE:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009934 case XML_ATTRIBUTE_NODE:
9935 case XML_TEXT_NODE:
9936 case XML_CDATA_SECTION_NODE:
9937 case XML_ENTITY_REF_NODE:
9938 case XML_PI_NODE:
9939 case XML_COMMENT_NODE:
9940 break;
9941 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009942 /* TODO: Support document-fragment-nodes. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009943 return (2);
9944 default:
9945 return (1);
9946 }
9947 /*
9948 * Unlink only if @node was not already added to @destParent.
9949 */
9950 if ((node->parent != NULL) && (destParent != node->parent))
9951 xmlUnlinkNode(node);
9952
9953 if (node->type == XML_ELEMENT_NODE) {
9954 return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node,
9955 destDoc, destParent, options));
9956 } else if (node->type == XML_ATTRIBUTE_NODE) {
9957 return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc,
9958 (xmlAttrPtr) node, destDoc, destParent, options));
Daniel Veillardaa6de472008-08-25 14:53:31 +00009959 } else {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009960 xmlNodePtr cur = node;
9961 int adoptStr = 1;
9962
9963 cur->doc = destDoc;
9964 /*
9965 * Optimize string adoption.
9966 */
9967 if ((sourceDoc != NULL) &&
9968 (sourceDoc->dict == destDoc->dict))
9969 adoptStr = 0;
9970 switch (node->type) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00009971 case XML_TEXT_NODE:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009972 case XML_CDATA_SECTION_NODE:
9973 XML_TREE_ADOPT_STR_2(node->content)
9974 break;
9975 case XML_ENTITY_REF_NODE:
9976 /*
9977 * Remove reference to the entitity-node.
9978 */
9979 node->content = NULL;
9980 node->children = NULL;
9981 node->last = NULL;
9982 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9983 xmlEntityPtr ent;
9984 /*
9985 * Assign new entity-node if available.
9986 */
9987 ent = xmlGetDocEntity(destDoc, node->name);
9988 if (ent != NULL) {
9989 node->content = ent->content;
9990 node->children = (xmlNodePtr) ent;
9991 node->last = (xmlNodePtr) ent;
9992 }
9993 }
9994 XML_TREE_ADOPT_STR(node->name)
9995 break;
Daniel Veillard7e21fd12005-07-03 21:44:07 +00009996 case XML_PI_NODE: {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009997 XML_TREE_ADOPT_STR(node->name)
9998 XML_TREE_ADOPT_STR_2(node->content)
9999 break;
Daniel Veillard7e21fd12005-07-03 21:44:07 +000010000 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +000010001 default:
10002 break;
10003 }
Daniel Veillardaa6de472008-08-25 14:53:31 +000010004 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +000010005 return (0);
10006}
10007
Daniel Veillard5d4644e2005-04-01 13:11:58 +000010008#define bottom_tree
10009#include "elfgcchack.h"