blob: df6f608cd343f086a005b0581d24b2fafbe4ffdf [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;
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001270 xmlBufPtr buf;
Owen Taylor3473f882001-02-23 17:55:21 +00001271
1272 if (value == NULL) return(NULL);
1273
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001274 buf = xmlBufCreateSize(0);
1275 if (buf == NULL) return(NULL);
1276 xmlBufSetAllocationScheme(buf, 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) {
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001288 if (xmlBufAdd(buf, q, cur - q))
Conrad Irwin7d553f82012-05-10 20:17:25 -07001289 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
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001365 if (xmlBufCat(buf, ent->content))
Conrad Irwin7d553f82012-05-10 20:17:25 -07001366 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 */
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001372 if (!xmlBufIsEmpty(buf)) {
Conrad Irwin7d553f82012-05-10 20:17:25 -07001373 node = xmlNewDocText(doc, NULL);
1374 if (node == NULL) {
1375 if (val != NULL) xmlFree(val);
1376 goto out;
1377 }
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001378 node->content = xmlBufDetach(buf);
Conrad Irwin7d553f82012-05-10 20:17:25 -07001379
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) {
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001420 xmlChar buffer[10];
Daniel Veillard07cb8222003-09-10 10:51:05 +00001421 int l;
1422
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001423 l = xmlCopyCharMultiByte(buffer, charval);
1424 buffer[l] = 0;
Conrad Irwin7d553f82012-05-10 20:17:25 -07001425
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001426 if (xmlBufCat(buf, buffer))
Conrad Irwin7d553f82012-05-10 20:17:25 -07001427 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 */
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001438 if (xmlBufAdd(buf, q, cur - q))
Conrad Irwin7d553f82012-05-10 20:17:25 -07001439 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00001440 }
Conrad Irwin7d553f82012-05-10 20:17:25 -07001441
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001442 if (!xmlBufIsEmpty(buf)) {
Conrad Irwin7d553f82012-05-10 20:17:25 -07001443 node = xmlNewDocText(doc, NULL);
1444 if (node == NULL) goto out;
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001445 node->content = xmlBufDetach(buf);
Conrad Irwin7d553f82012-05-10 20:17:25 -07001446
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:
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001457 xmlBufFree(buf);
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;
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001478 xmlBufPtr buf;
Owen Taylor3473f882001-02-23 17:55:21 +00001479
1480 if (value == NULL) return(NULL);
1481
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001482 buf = xmlBufCreateSize(0);
1483 if (buf == NULL) return(NULL);
1484 xmlBufSetAllocationScheme(buf, 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) {
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001496 if (xmlBufAdd(buf, q, cur - q))
Conrad Irwin7d553f82012-05-10 20:17:25 -07001497 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
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001561 if (xmlBufCat(buf, ent->content))
Conrad Irwin7d553f82012-05-10 20:17:25 -07001562 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 */
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001568 if (!xmlBufIsEmpty(buf)) {
Conrad Irwin7d553f82012-05-10 20:17:25 -07001569 node = xmlNewDocText(doc, NULL);
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001570 node->content = xmlBufDetach(buf);
Conrad Irwin7d553f82012-05-10 20:17:25 -07001571
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) {
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001611 xmlChar buffer[10];
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001612 int len;
1613
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001614 len = xmlCopyCharMultiByte(buffer, charval);
1615 buffer[len] = 0;
Conrad Irwin7d553f82012-05-10 20:17:25 -07001616
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001617 if (xmlBufCat(buf, buffer))
Conrad Irwin7d553f82012-05-10 20:17:25 -07001618 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 */
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001628 xmlBufAdd(buf, q, cur - q);
Conrad Irwin7d553f82012-05-10 20:17:25 -07001629 }
1630
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001631 if (!xmlBufIsEmpty(buf)) {
Conrad Irwin7d553f82012-05-10 20:17:25 -07001632 node = xmlNewDocText(doc, NULL);
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001633 node->content = xmlBufDetach(buf);
Conrad Irwin7d553f82012-05-10 20:17:25 -07001634
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:
Daniel Veillardc15df7d2012-08-07 15:15:04 +08001643 xmlBufFree(buf);
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
Daniel Veillard3e62adb2012-08-09 14:24:02 +08002782 if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL))
Owen Taylor3473f882001-02-23 17:55:21 +00002783 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
Daniel Veillard3e62adb2012-08-09 14:24:02 +08002810 if ((list == NULL) || (list->type == XML_NAMESPACE_DECL))
Owen Taylor3473f882001-02-23 17:55:21 +00002811 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
Daniel Veillard3e62adb2012-08-09 14:24:02 +08002917 if ((cur == NULL) || (cur->type != XML_ATTRIBUTE_NODE) ||
2918 (prop == NULL) || (prop->type != XML_ATTRIBUTE_NODE) ||
2919 ((prev != NULL) && (prev->type != XML_ATTRIBUTE_NODE)))
Rob Richards65815122006-02-25 17:13:33 +00002920 return(NULL);
2921
2922 /* check if an attribute with the same name exists */
2923 if (prop->ns == NULL)
2924 attr = xmlHasNsProp(cur->parent, prop->name, NULL);
2925 else
2926 attr = xmlHasNsProp(cur->parent, prop->name, prop->ns->href);
2927
2928 if (prop->doc != cur->doc) {
2929 xmlSetTreeDoc(prop, cur->doc);
2930 }
2931 prop->parent = cur->parent;
2932 prop->prev = prev;
2933 if (prev != NULL) {
2934 prop->next = prev->next;
2935 prev->next = prop;
2936 if (prop->next)
2937 prop->next->prev = prop;
2938 } else {
2939 prop->next = cur;
2940 cur->prev = prop;
2941 }
2942 if (prop->prev == NULL && prop->parent != NULL)
2943 prop->parent->properties = (xmlAttrPtr) prop;
2944 if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) {
2945 /* different instance, destroy it (attributes must be unique) */
2946 xmlRemoveProp((xmlAttrPtr) attr);
2947 }
2948 return prop;
2949}
2950
2951/**
Owen Taylor3473f882001-02-23 17:55:21 +00002952 * xmlAddNextSibling:
2953 * @cur: the child node
2954 * @elem: the new node
2955 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002956 * Add a new node @elem as the next sibling of @cur
2957 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002958 * first unlinked from its existing context.
2959 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002960 * If the new node is ATTRIBUTE, it is added into properties instead of children.
Daniel Veillardaa6de472008-08-25 14:53:31 +00002961 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002962 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002963 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002964 */
2965xmlNodePtr
2966xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
Daniel Veillard3e62adb2012-08-09 14:24:02 +08002967 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002968#ifdef DEBUG_TREE
2969 xmlGenericError(xmlGenericErrorContext,
2970 "xmlAddNextSibling : cur == NULL\n");
2971#endif
2972 return(NULL);
2973 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08002974 if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002975#ifdef DEBUG_TREE
2976 xmlGenericError(xmlGenericErrorContext,
2977 "xmlAddNextSibling : elem == NULL\n");
2978#endif
2979 return(NULL);
2980 }
2981
Rob Richards19dc9612005-10-28 16:15:16 +00002982 if (cur == elem) {
2983#ifdef DEBUG_TREE
2984 xmlGenericError(xmlGenericErrorContext,
2985 "xmlAddNextSibling : cur == elem\n");
2986#endif
2987 return(NULL);
2988 }
2989
Owen Taylor3473f882001-02-23 17:55:21 +00002990 xmlUnlinkNode(elem);
2991
2992 if (elem->type == XML_TEXT_NODE) {
2993 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002994 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002995 xmlFreeNode(elem);
2996 return(cur);
2997 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002998 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2999 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003000 xmlChar *tmp;
3001
3002 tmp = xmlStrdup(elem->content);
3003 tmp = xmlStrcat(tmp, cur->next->content);
3004 xmlNodeSetContent(cur->next, tmp);
3005 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00003006 xmlFreeNode(elem);
3007 return(cur->next);
3008 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003009 } else if (elem->type == XML_ATTRIBUTE_NODE) {
Rob Richards65815122006-02-25 17:13:33 +00003010 return xmlAddPropSibling(cur, cur, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00003011 }
3012
3013 if (elem->doc != cur->doc) {
3014 xmlSetTreeDoc(elem, cur->doc);
3015 }
3016 elem->parent = cur->parent;
3017 elem->prev = cur;
3018 elem->next = cur->next;
3019 cur->next = elem;
3020 if (elem->next != NULL)
3021 elem->next->prev = elem;
Rob Richards65815122006-02-25 17:13:33 +00003022 if ((elem->parent != NULL) && (elem->parent->last == cur))
Owen Taylor3473f882001-02-23 17:55:21 +00003023 elem->parent->last = elem;
3024 return(elem);
3025}
3026
William M. Brack21e4ef22005-01-02 09:53:13 +00003027#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
3028 defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003029/**
3030 * xmlAddPrevSibling:
3031 * @cur: the child node
3032 * @elem: the new node
3033 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003034 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00003035 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003036 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003037 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003038 * If the new node is ATTRIBUTE, it is added into properties instead of children.
Daniel Veillardaa6de472008-08-25 14:53:31 +00003039 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00003040 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003041 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003042 */
3043xmlNodePtr
3044xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
Daniel Veillard3e62adb2012-08-09 14:24:02 +08003045 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003046#ifdef DEBUG_TREE
3047 xmlGenericError(xmlGenericErrorContext,
3048 "xmlAddPrevSibling : cur == NULL\n");
3049#endif
3050 return(NULL);
3051 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08003052 if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003053#ifdef DEBUG_TREE
3054 xmlGenericError(xmlGenericErrorContext,
3055 "xmlAddPrevSibling : elem == NULL\n");
3056#endif
3057 return(NULL);
3058 }
3059
Rob Richards19dc9612005-10-28 16:15:16 +00003060 if (cur == elem) {
3061#ifdef DEBUG_TREE
3062 xmlGenericError(xmlGenericErrorContext,
3063 "xmlAddPrevSibling : cur == elem\n");
3064#endif
3065 return(NULL);
3066 }
3067
Owen Taylor3473f882001-02-23 17:55:21 +00003068 xmlUnlinkNode(elem);
3069
3070 if (elem->type == XML_TEXT_NODE) {
3071 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00003072 xmlChar *tmp;
3073
3074 tmp = xmlStrdup(elem->content);
3075 tmp = xmlStrcat(tmp, cur->content);
3076 xmlNodeSetContent(cur, tmp);
3077 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00003078 xmlFreeNode(elem);
3079 return(cur);
3080 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00003081 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
3082 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003083 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003084 xmlFreeNode(elem);
3085 return(cur->prev);
3086 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003087 } else if (elem->type == XML_ATTRIBUTE_NODE) {
Rob Richards65815122006-02-25 17:13:33 +00003088 return xmlAddPropSibling(cur->prev, cur, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00003089 }
3090
3091 if (elem->doc != cur->doc) {
3092 xmlSetTreeDoc(elem, cur->doc);
3093 }
3094 elem->parent = cur->parent;
3095 elem->next = cur;
3096 elem->prev = cur->prev;
3097 cur->prev = elem;
3098 if (elem->prev != NULL)
3099 elem->prev->next = elem;
Rob Richards65815122006-02-25 17:13:33 +00003100 if ((elem->parent != NULL) && (elem->parent->children == cur)) {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003101 elem->parent->children = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003102 }
Owen Taylor3473f882001-02-23 17:55:21 +00003103 return(elem);
3104}
Daniel Veillard652327a2003-09-29 18:02:38 +00003105#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003106
3107/**
3108 * xmlAddSibling:
3109 * @cur: the child node
3110 * @elem: the new node
3111 *
3112 * Add a new element @elem to the list of siblings of @cur
3113 * merging adjacent TEXT nodes (@elem may be freed)
3114 * If the new element was already inserted in a document it is
3115 * first unlinked from its existing context.
3116 *
3117 * Returns the new element or NULL in case of error.
3118 */
3119xmlNodePtr
3120xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
3121 xmlNodePtr parent;
3122
Daniel Veillard3e62adb2012-08-09 14:24:02 +08003123 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003124#ifdef DEBUG_TREE
3125 xmlGenericError(xmlGenericErrorContext,
3126 "xmlAddSibling : cur == NULL\n");
3127#endif
3128 return(NULL);
3129 }
3130
Daniel Veillard3e62adb2012-08-09 14:24:02 +08003131 if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003132#ifdef DEBUG_TREE
3133 xmlGenericError(xmlGenericErrorContext,
3134 "xmlAddSibling : elem == NULL\n");
3135#endif
3136 return(NULL);
3137 }
3138
Daniel Veillard43bc89c2009-03-23 19:32:04 +00003139 if (cur == elem) {
3140#ifdef DEBUG_TREE
3141 xmlGenericError(xmlGenericErrorContext,
3142 "xmlAddSibling : cur == elem\n");
3143#endif
3144 return(NULL);
3145 }
3146
Owen Taylor3473f882001-02-23 17:55:21 +00003147 /*
3148 * Constant time is we can rely on the ->parent->last to find
3149 * the last sibling.
3150 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00003151 if ((cur->type != XML_ATTRIBUTE_NODE) && (cur->parent != NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00003152 (cur->parent->children != NULL) &&
3153 (cur->parent->last != NULL) &&
3154 (cur->parent->last->next == NULL)) {
3155 cur = cur->parent->last;
3156 } else {
3157 while (cur->next != NULL) cur = cur->next;
3158 }
3159
3160 xmlUnlinkNode(elem);
3161
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003162 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3163 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003164 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003165 xmlFreeNode(elem);
3166 return(cur);
Rob Richards65815122006-02-25 17:13:33 +00003167 } else if (elem->type == XML_ATTRIBUTE_NODE) {
3168 return xmlAddPropSibling(cur, cur, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00003169 }
3170
3171 if (elem->doc != cur->doc) {
3172 xmlSetTreeDoc(elem, cur->doc);
3173 }
3174 parent = cur->parent;
3175 elem->prev = cur;
3176 elem->next = NULL;
3177 elem->parent = parent;
3178 cur->next = elem;
3179 if (parent != NULL)
3180 parent->last = elem;
3181
3182 return(elem);
3183}
3184
3185/**
3186 * xmlAddChildList:
3187 * @parent: the parent node
3188 * @cur: the first node in the list
3189 *
3190 * Add a list of node at the end of the child list of the parent
3191 * merging adjacent TEXT nodes (@cur may be freed)
3192 *
3193 * Returns the last child or NULL in case of error.
3194 */
3195xmlNodePtr
3196xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3197 xmlNodePtr prev;
3198
Daniel Veillard3e62adb2012-08-09 14:24:02 +08003199 if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003200#ifdef DEBUG_TREE
3201 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003202 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003203#endif
3204 return(NULL);
3205 }
3206
Daniel Veillard3e62adb2012-08-09 14:24:02 +08003207 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003208#ifdef DEBUG_TREE
3209 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003210 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003211#endif
3212 return(NULL);
3213 }
3214
3215 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3216 (cur->doc != parent->doc)) {
3217#ifdef DEBUG_TREE
3218 xmlGenericError(xmlGenericErrorContext,
3219 "Elements moved to a different document\n");
3220#endif
3221 }
3222
3223 /*
3224 * add the first element at the end of the children list.
3225 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003226
Owen Taylor3473f882001-02-23 17:55:21 +00003227 if (parent->children == NULL) {
3228 parent->children = cur;
3229 } else {
3230 /*
3231 * If cur and parent->last both are TEXT nodes, then merge them.
3232 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00003233 if ((cur->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00003234 (parent->last->type == XML_TEXT_NODE) &&
3235 (cur->name == parent->last->name)) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00003236 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003237 /*
3238 * if it's the only child, nothing more to be done.
3239 */
3240 if (cur->next == NULL) {
3241 xmlFreeNode(cur);
3242 return(parent->last);
3243 }
3244 prev = cur;
3245 cur = cur->next;
3246 xmlFreeNode(prev);
3247 }
3248 prev = parent->last;
3249 prev->next = cur;
3250 cur->prev = prev;
3251 }
3252 while (cur->next != NULL) {
3253 cur->parent = parent;
3254 if (cur->doc != parent->doc) {
3255 xmlSetTreeDoc(cur, parent->doc);
3256 }
3257 cur = cur->next;
3258 }
3259 cur->parent = parent;
Rob Richards810a78b2008-12-31 22:13:57 +00003260 /* the parent may not be linked to a doc ! */
3261 if (cur->doc != parent->doc) {
3262 xmlSetTreeDoc(cur, parent->doc);
3263 }
Owen Taylor3473f882001-02-23 17:55:21 +00003264 parent->last = cur;
3265
3266 return(cur);
3267}
3268
3269/**
3270 * xmlAddChild:
3271 * @parent: the parent node
3272 * @cur: the child node
3273 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003274 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003275 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003276 * If the new node is ATTRIBUTE, it is added into properties instead of children.
Daniel Veillardaa6de472008-08-25 14:53:31 +00003277 * If there is an attribute with equal name, it is first destroyed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003278 *
Owen Taylor3473f882001-02-23 17:55:21 +00003279 * Returns the child or NULL in case of error.
3280 */
3281xmlNodePtr
3282xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3283 xmlNodePtr prev;
3284
Daniel Veillard3e62adb2012-08-09 14:24:02 +08003285 if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003286#ifdef DEBUG_TREE
3287 xmlGenericError(xmlGenericErrorContext,
3288 "xmlAddChild : parent == NULL\n");
3289#endif
3290 return(NULL);
3291 }
3292
Daniel Veillard3e62adb2012-08-09 14:24:02 +08003293 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003294#ifdef DEBUG_TREE
3295 xmlGenericError(xmlGenericErrorContext,
3296 "xmlAddChild : child == NULL\n");
3297#endif
3298 return(NULL);
3299 }
3300
Rob Richards19dc9612005-10-28 16:15:16 +00003301 if (parent == cur) {
3302#ifdef DEBUG_TREE
3303 xmlGenericError(xmlGenericErrorContext,
3304 "xmlAddChild : parent == cur\n");
3305#endif
3306 return(NULL);
3307 }
Owen Taylor3473f882001-02-23 17:55:21 +00003308 /*
3309 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003310 * cur is then freed.
3311 */
3312 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003313 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003314 (parent->content != NULL) &&
Rob Richards19dc9612005-10-28 16:15:16 +00003315 (parent->name == cur->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003316 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003317 xmlFreeNode(cur);
3318 return(parent);
3319 }
3320 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003321 (parent->last->name == cur->name) &&
3322 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003323 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003324 xmlFreeNode(cur);
3325 return(parent->last);
3326 }
3327 }
3328
3329 /*
3330 * add the new element at the end of the children list.
3331 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003332 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003333 cur->parent = parent;
3334 if (cur->doc != parent->doc) {
3335 xmlSetTreeDoc(cur, parent->doc);
3336 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003337 /* this check prevents a loop on tree-traversions if a developer
3338 * tries to add a node to its parent multiple times
3339 */
3340 if (prev == parent)
3341 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003342
3343 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003344 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003345 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003346 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003347 (parent->content != NULL) &&
3348 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003349 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003350 xmlFreeNode(cur);
3351 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003352 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003353 if (cur->type == XML_ATTRIBUTE_NODE) {
Rob Richards19dc9612005-10-28 16:15:16 +00003354 if (parent->type != XML_ELEMENT_NODE)
3355 return(NULL);
Rob Richards810a78b2008-12-31 22:13:57 +00003356 if (parent->properties != NULL) {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003357 /* check if an attribute with the same name exists */
3358 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003359
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003360 if (cur->ns == NULL)
Rob Richardsc342ec62005-10-25 00:10:12 +00003361 lastattr = xmlHasNsProp(parent, cur->name, NULL);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003362 else
3363 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
Rob Richardsc342ec62005-10-25 00:10:12 +00003364 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur) && (lastattr->type != XML_ATTRIBUTE_DECL)) {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003365 /* different instance, destroy it (attributes must be unique) */
Rob Richards19dc9612005-10-28 16:15:16 +00003366 xmlUnlinkNode((xmlNodePtr) lastattr);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003367 xmlFreeProp(lastattr);
3368 }
Rob Richards19dc9612005-10-28 16:15:16 +00003369 if (lastattr == (xmlAttrPtr) cur)
3370 return(cur);
Rob Richards810a78b2008-12-31 22:13:57 +00003371
3372 }
3373 if (parent->properties == NULL) {
3374 parent->properties = (xmlAttrPtr) cur;
3375 } else {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003376 /* find the end */
Rob Richards810a78b2008-12-31 22:13:57 +00003377 xmlAttrPtr lastattr = parent->properties;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003378 while (lastattr->next != NULL) {
3379 lastattr = lastattr->next;
3380 }
3381 lastattr->next = (xmlAttrPtr) cur;
3382 ((xmlAttrPtr) cur)->prev = lastattr;
3383 }
3384 } else {
3385 if (parent->children == NULL) {
3386 parent->children = cur;
3387 parent->last = cur;
3388 } else {
3389 prev = parent->last;
3390 prev->next = cur;
3391 cur->prev = prev;
3392 parent->last = cur;
3393 }
3394 }
Owen Taylor3473f882001-02-23 17:55:21 +00003395 return(cur);
3396}
3397
3398/**
3399 * xmlGetLastChild:
3400 * @parent: the parent node
3401 *
3402 * Search the last child of a node.
3403 * Returns the last child or NULL if none.
3404 */
3405xmlNodePtr
3406xmlGetLastChild(xmlNodePtr parent) {
Daniel Veillard3e62adb2012-08-09 14:24:02 +08003407 if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003408#ifdef DEBUG_TREE
3409 xmlGenericError(xmlGenericErrorContext,
3410 "xmlGetLastChild : parent == NULL\n");
3411#endif
3412 return(NULL);
3413 }
3414 return(parent->last);
3415}
3416
Daniel Veillardbe2bd6a2008-11-27 15:26:28 +00003417#ifdef LIBXML_TREE_ENABLED
3418/*
3419 * 5 interfaces from DOM ElementTraversal
3420 */
3421
3422/**
3423 * xmlChildElementCount:
3424 * @parent: the parent node
3425 *
3426 * Finds the current number of child nodes of that element which are
3427 * element nodes.
3428 * Note the handling of entities references is different than in
3429 * the W3C DOM element traversal spec since we don't have back reference
3430 * from entities content to entities references.
3431 *
3432 * Returns the count of element child or 0 if not available
3433 */
3434unsigned long
3435xmlChildElementCount(xmlNodePtr parent) {
3436 unsigned long ret = 0;
3437 xmlNodePtr cur = NULL;
3438
3439 if (parent == NULL)
3440 return(0);
3441 switch (parent->type) {
3442 case XML_ELEMENT_NODE:
3443 case XML_ENTITY_NODE:
3444 case XML_DOCUMENT_NODE:
3445 case XML_HTML_DOCUMENT_NODE:
3446 cur = parent->children;
3447 break;
3448 default:
3449 return(0);
3450 }
3451 while (cur != NULL) {
3452 if (cur->type == XML_ELEMENT_NODE)
3453 ret++;
3454 cur = cur->next;
3455 }
3456 return(ret);
3457}
3458
3459/**
3460 * xmlFirstElementChild:
3461 * @parent: the parent node
3462 *
3463 * Finds the first child node of that element which is a Element node
3464 * Note the handling of entities references is different than in
3465 * the W3C DOM element traversal spec since we don't have back reference
3466 * from entities content to entities references.
3467 *
3468 * Returns the first element child or NULL if not available
3469 */
3470xmlNodePtr
3471xmlFirstElementChild(xmlNodePtr parent) {
3472 xmlNodePtr cur = NULL;
3473
3474 if (parent == NULL)
3475 return(NULL);
3476 switch (parent->type) {
3477 case XML_ELEMENT_NODE:
3478 case XML_ENTITY_NODE:
3479 case XML_DOCUMENT_NODE:
3480 case XML_HTML_DOCUMENT_NODE:
3481 cur = parent->children;
3482 break;
3483 default:
3484 return(NULL);
3485 }
3486 while (cur != NULL) {
3487 if (cur->type == XML_ELEMENT_NODE)
3488 return(cur);
3489 cur = cur->next;
3490 }
3491 return(NULL);
3492}
3493
3494/**
3495 * xmlLastElementChild:
3496 * @parent: the parent node
3497 *
3498 * Finds the last child node of that element which is a Element node
3499 * Note the handling of entities references is different than in
3500 * the W3C DOM element traversal spec since we don't have back reference
3501 * from entities content to entities references.
3502 *
3503 * Returns the last element child or NULL if not available
3504 */
3505xmlNodePtr
3506xmlLastElementChild(xmlNodePtr parent) {
3507 xmlNodePtr cur = NULL;
3508
3509 if (parent == NULL)
3510 return(NULL);
3511 switch (parent->type) {
3512 case XML_ELEMENT_NODE:
3513 case XML_ENTITY_NODE:
3514 case XML_DOCUMENT_NODE:
3515 case XML_HTML_DOCUMENT_NODE:
3516 cur = parent->last;
3517 break;
3518 default:
3519 return(NULL);
3520 }
3521 while (cur != NULL) {
3522 if (cur->type == XML_ELEMENT_NODE)
3523 return(cur);
3524 cur = cur->prev;
3525 }
3526 return(NULL);
3527}
3528
3529/**
3530 * xmlPreviousElementSibling:
3531 * @node: the current node
3532 *
3533 * Finds the first closest previous sibling of the node which is an
3534 * element node.
3535 * Note the handling of entities references is different than in
3536 * the W3C DOM element traversal spec since we don't have back reference
3537 * from entities content to entities references.
3538 *
3539 * Returns the previous element sibling or NULL if not available
3540 */
3541xmlNodePtr
3542xmlPreviousElementSibling(xmlNodePtr node) {
3543 if (node == NULL)
3544 return(NULL);
3545 switch (node->type) {
3546 case XML_ELEMENT_NODE:
3547 case XML_TEXT_NODE:
3548 case XML_CDATA_SECTION_NODE:
3549 case XML_ENTITY_REF_NODE:
3550 case XML_ENTITY_NODE:
3551 case XML_PI_NODE:
3552 case XML_COMMENT_NODE:
3553 case XML_XINCLUDE_START:
3554 case XML_XINCLUDE_END:
3555 node = node->prev;
3556 break;
3557 default:
3558 return(NULL);
3559 }
3560 while (node != NULL) {
3561 if (node->type == XML_ELEMENT_NODE)
3562 return(node);
François Delyon2f700902010-02-03 17:32:37 +01003563 node = node->prev;
Daniel Veillardbe2bd6a2008-11-27 15:26:28 +00003564 }
3565 return(NULL);
3566}
3567
3568/**
3569 * xmlNextElementSibling:
3570 * @node: the current node
3571 *
3572 * Finds the first closest next sibling of the node which is an
3573 * element node.
3574 * Note the handling of entities references is different than in
3575 * the W3C DOM element traversal spec since we don't have back reference
3576 * from entities content to entities references.
3577 *
3578 * Returns the next element sibling or NULL if not available
3579 */
3580xmlNodePtr
3581xmlNextElementSibling(xmlNodePtr node) {
3582 if (node == NULL)
3583 return(NULL);
3584 switch (node->type) {
3585 case XML_ELEMENT_NODE:
3586 case XML_TEXT_NODE:
3587 case XML_CDATA_SECTION_NODE:
3588 case XML_ENTITY_REF_NODE:
3589 case XML_ENTITY_NODE:
3590 case XML_PI_NODE:
3591 case XML_COMMENT_NODE:
3592 case XML_DTD_NODE:
3593 case XML_XINCLUDE_START:
3594 case XML_XINCLUDE_END:
3595 node = node->next;
3596 break;
3597 default:
3598 return(NULL);
3599 }
3600 while (node != NULL) {
3601 if (node->type == XML_ELEMENT_NODE)
3602 return(node);
3603 node = node->next;
3604 }
3605 return(NULL);
3606}
3607
3608#endif /* LIBXML_TREE_ENABLED */
3609
Owen Taylor3473f882001-02-23 17:55:21 +00003610/**
3611 * xmlFreeNodeList:
3612 * @cur: the first node in the list
3613 *
3614 * Free a node and all its siblings, this is a recursive behaviour, all
3615 * the children are freed too.
3616 */
3617void
3618xmlFreeNodeList(xmlNodePtr cur) {
3619 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003620 xmlDictPtr dict = NULL;
3621
3622 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003623 if (cur->type == XML_NAMESPACE_DECL) {
3624 xmlFreeNsList((xmlNsPtr) cur);
3625 return;
3626 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003627 if ((cur->type == XML_DOCUMENT_NODE) ||
3628#ifdef LIBXML_DOCB_ENABLED
3629 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003630#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003631 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003632 xmlFreeDoc((xmlDocPtr) cur);
3633 return;
3634 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003635 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003636 while (cur != NULL) {
3637 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003638 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003639
Daniel Veillarda880b122003-04-21 21:36:41 +00003640 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003641 xmlDeregisterNodeDefaultValue(cur);
3642
Daniel Veillard02141ea2001-04-30 11:46:40 +00003643 if ((cur->children != NULL) &&
3644 (cur->type != XML_ENTITY_REF_NODE))
3645 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003646 if (((cur->type == XML_ELEMENT_NODE) ||
3647 (cur->type == XML_XINCLUDE_START) ||
3648 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003649 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003650 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003651 if ((cur->type != XML_ELEMENT_NODE) &&
3652 (cur->type != XML_XINCLUDE_START) &&
3653 (cur->type != XML_XINCLUDE_END) &&
Daniel Veillard8874b942005-08-25 13:19:21 +00003654 (cur->type != XML_ENTITY_REF_NODE) &&
3655 (cur->content != (xmlChar *) &(cur->properties))) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003656 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003657 }
3658 if (((cur->type == XML_ELEMENT_NODE) ||
3659 (cur->type == XML_XINCLUDE_START) ||
3660 (cur->type == XML_XINCLUDE_END)) &&
3661 (cur->nsDef != NULL))
3662 xmlFreeNsList(cur->nsDef);
3663
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003664 /*
3665 * When a node is a text node or a comment, it uses a global static
3666 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003667 * Otherwise the node name might come from the document's
3668 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003669 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003670 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003671 (cur->type != XML_TEXT_NODE) &&
3672 (cur->type != XML_COMMENT_NODE))
3673 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003674 xmlFree(cur);
3675 }
Owen Taylor3473f882001-02-23 17:55:21 +00003676 cur = next;
3677 }
3678}
3679
3680/**
3681 * xmlFreeNode:
3682 * @cur: the node
3683 *
3684 * Free a node, this is a recursive behaviour, all the children are freed too.
3685 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3686 */
3687void
3688xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003689 xmlDictPtr dict = NULL;
3690
3691 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003692
Daniel Veillard02141ea2001-04-30 11:46:40 +00003693 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003694 if (cur->type == XML_DTD_NODE) {
3695 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003696 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003697 }
3698 if (cur->type == XML_NAMESPACE_DECL) {
3699 xmlFreeNs((xmlNsPtr) cur);
3700 return;
3701 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003702 if (cur->type == XML_ATTRIBUTE_NODE) {
3703 xmlFreeProp((xmlAttrPtr) cur);
3704 return;
3705 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003706
Daniel Veillarda880b122003-04-21 21:36:41 +00003707 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003708 xmlDeregisterNodeDefaultValue(cur);
3709
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003710 if (cur->doc != NULL) dict = cur->doc->dict;
3711
Daniel Veillard2cba4152008-08-27 11:45:41 +00003712 if (cur->type == XML_ENTITY_DECL) {
3713 xmlEntityPtr ent = (xmlEntityPtr) cur;
3714 DICT_FREE(ent->SystemID);
3715 DICT_FREE(ent->ExternalID);
3716 }
Owen Taylor3473f882001-02-23 17:55:21 +00003717 if ((cur->children != NULL) &&
3718 (cur->type != XML_ENTITY_REF_NODE))
3719 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003720 if (((cur->type == XML_ELEMENT_NODE) ||
3721 (cur->type == XML_XINCLUDE_START) ||
3722 (cur->type == XML_XINCLUDE_END)) &&
3723 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003724 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003725 if ((cur->type != XML_ELEMENT_NODE) &&
3726 (cur->content != NULL) &&
3727 (cur->type != XML_ENTITY_REF_NODE) &&
3728 (cur->type != XML_XINCLUDE_END) &&
Daniel Veillard8874b942005-08-25 13:19:21 +00003729 (cur->type != XML_XINCLUDE_START) &&
3730 (cur->content != (xmlChar *) &(cur->properties))) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003731 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003732 }
3733
Daniel Veillardacd370f2001-06-09 17:17:51 +00003734 /*
3735 * When a node is a text node or a comment, it uses a global static
3736 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003737 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003738 */
Owen Taylor3473f882001-02-23 17:55:21 +00003739 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003740 (cur->type != XML_TEXT_NODE) &&
3741 (cur->type != XML_COMMENT_NODE))
3742 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003743
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003744 if (((cur->type == XML_ELEMENT_NODE) ||
3745 (cur->type == XML_XINCLUDE_START) ||
3746 (cur->type == XML_XINCLUDE_END)) &&
3747 (cur->nsDef != NULL))
3748 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003749 xmlFree(cur);
3750}
3751
3752/**
3753 * xmlUnlinkNode:
3754 * @cur: the node
3755 *
3756 * Unlink a node from it's current context, the node is not freed
Daniel Veillard39d027c2012-05-11 12:38:23 +08003757 * If one need to free the node, use xmlFreeNode() routine after the
3758 * unlink to discard it.
Daniel Veillard6ca24a32012-08-08 15:31:55 +08003759 * Note that namespace nodes can't be unlinked as they do not have
3760 * pointer to their parent.
Owen Taylor3473f882001-02-23 17:55:21 +00003761 */
3762void
3763xmlUnlinkNode(xmlNodePtr cur) {
3764 if (cur == NULL) {
3765#ifdef DEBUG_TREE
3766 xmlGenericError(xmlGenericErrorContext,
3767 "xmlUnlinkNode : node == NULL\n");
3768#endif
3769 return;
3770 }
Daniel Veillard6ca24a32012-08-08 15:31:55 +08003771 if (cur->type == XML_NAMESPACE_DECL)
3772 return;
Daniel Veillard29e43992001-12-13 22:21:58 +00003773 if (cur->type == XML_DTD_NODE) {
3774 xmlDocPtr doc;
3775 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003776 if (doc != NULL) {
3777 if (doc->intSubset == (xmlDtdPtr) cur)
3778 doc->intSubset = NULL;
3779 if (doc->extSubset == (xmlDtdPtr) cur)
3780 doc->extSubset = NULL;
3781 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003782 }
Daniel Veillard2cba4152008-08-27 11:45:41 +00003783 if (cur->type == XML_ENTITY_DECL) {
3784 xmlDocPtr doc;
3785 doc = cur->doc;
3786 if (doc != NULL) {
3787 if (doc->intSubset != NULL) {
3788 if (xmlHashLookup(doc->intSubset->entities, cur->name) == cur)
3789 xmlHashRemoveEntry(doc->intSubset->entities, cur->name,
3790 NULL);
3791 if (xmlHashLookup(doc->intSubset->pentities, cur->name) == cur)
3792 xmlHashRemoveEntry(doc->intSubset->pentities, cur->name,
3793 NULL);
3794 }
3795 if (doc->extSubset != NULL) {
3796 if (xmlHashLookup(doc->extSubset->entities, cur->name) == cur)
3797 xmlHashRemoveEntry(doc->extSubset->entities, cur->name,
3798 NULL);
3799 if (xmlHashLookup(doc->extSubset->pentities, cur->name) == cur)
3800 xmlHashRemoveEntry(doc->extSubset->pentities, cur->name,
3801 NULL);
3802 }
3803 }
3804 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003805 if (cur->parent != NULL) {
3806 xmlNodePtr parent;
3807 parent = cur->parent;
3808 if (cur->type == XML_ATTRIBUTE_NODE) {
3809 if (parent->properties == (xmlAttrPtr) cur)
3810 parent->properties = ((xmlAttrPtr) cur)->next;
3811 } else {
3812 if (parent->children == cur)
3813 parent->children = cur->next;
3814 if (parent->last == cur)
3815 parent->last = cur->prev;
3816 }
3817 cur->parent = NULL;
3818 }
Owen Taylor3473f882001-02-23 17:55:21 +00003819 if (cur->next != NULL)
3820 cur->next->prev = cur->prev;
3821 if (cur->prev != NULL)
3822 cur->prev->next = cur->next;
3823 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003824}
3825
Daniel Veillard2156d432004-03-04 15:59:36 +00003826#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003827/**
3828 * xmlReplaceNode:
3829 * @old: the old node
3830 * @cur: the node
3831 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003832 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003833 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003834 * first unlinked from its existing context.
3835 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003836 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003837 */
3838xmlNodePtr
3839xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00003840 if (old == cur) return(NULL);
Daniel Veillard3e62adb2012-08-09 14:24:02 +08003841 if ((old == NULL) || (old->type == XML_NAMESPACE_DECL) ||
3842 (old->parent == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003843#ifdef DEBUG_TREE
3844 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda03e3652004-11-02 18:45:30 +00003845 "xmlReplaceNode : old == NULL or without parent\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003846#endif
3847 return(NULL);
3848 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08003849 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003850 xmlUnlinkNode(old);
3851 return(old);
3852 }
3853 if (cur == old) {
3854 return(old);
3855 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003856 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3857#ifdef DEBUG_TREE
3858 xmlGenericError(xmlGenericErrorContext,
3859 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3860#endif
3861 return(old);
3862 }
3863 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3864#ifdef DEBUG_TREE
3865 xmlGenericError(xmlGenericErrorContext,
3866 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3867#endif
3868 return(old);
3869 }
Owen Taylor3473f882001-02-23 17:55:21 +00003870 xmlUnlinkNode(cur);
Daniel Veillard64d7d122005-05-11 18:03:42 +00003871 xmlSetTreeDoc(cur, old->doc);
Owen Taylor3473f882001-02-23 17:55:21 +00003872 cur->parent = old->parent;
3873 cur->next = old->next;
3874 if (cur->next != NULL)
3875 cur->next->prev = cur;
3876 cur->prev = old->prev;
3877 if (cur->prev != NULL)
3878 cur->prev->next = cur;
3879 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003880 if (cur->type == XML_ATTRIBUTE_NODE) {
3881 if (cur->parent->properties == (xmlAttrPtr)old)
3882 cur->parent->properties = ((xmlAttrPtr) cur);
3883 } else {
3884 if (cur->parent->children == old)
3885 cur->parent->children = cur;
3886 if (cur->parent->last == old)
3887 cur->parent->last = cur;
3888 }
Owen Taylor3473f882001-02-23 17:55:21 +00003889 }
3890 old->next = old->prev = NULL;
3891 old->parent = NULL;
3892 return(old);
3893}
Daniel Veillard652327a2003-09-29 18:02:38 +00003894#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003895
3896/************************************************************************
3897 * *
3898 * Copy operations *
3899 * *
3900 ************************************************************************/
Daniel Veillardaa6de472008-08-25 14:53:31 +00003901
Owen Taylor3473f882001-02-23 17:55:21 +00003902/**
3903 * xmlCopyNamespace:
3904 * @cur: the namespace
3905 *
3906 * Do a copy of the namespace.
3907 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003908 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003909 */
3910xmlNsPtr
3911xmlCopyNamespace(xmlNsPtr cur) {
3912 xmlNsPtr ret;
3913
3914 if (cur == NULL) return(NULL);
3915 switch (cur->type) {
3916 case XML_LOCAL_NAMESPACE:
3917 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3918 break;
3919 default:
3920#ifdef DEBUG_TREE
3921 xmlGenericError(xmlGenericErrorContext,
3922 "xmlCopyNamespace: invalid type %d\n", cur->type);
3923#endif
3924 return(NULL);
3925 }
3926 return(ret);
3927}
3928
3929/**
3930 * xmlCopyNamespaceList:
3931 * @cur: the first namespace
3932 *
3933 * Do a copy of an namespace list.
3934 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003935 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003936 */
3937xmlNsPtr
3938xmlCopyNamespaceList(xmlNsPtr cur) {
3939 xmlNsPtr ret = NULL;
3940 xmlNsPtr p = NULL,q;
3941
3942 while (cur != NULL) {
3943 q = xmlCopyNamespace(cur);
3944 if (p == NULL) {
3945 ret = p = q;
3946 } else {
3947 p->next = q;
3948 p = q;
3949 }
3950 cur = cur->next;
3951 }
3952 return(ret);
3953}
3954
3955static xmlNodePtr
3956xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
Rob Richards19dc9612005-10-28 16:15:16 +00003957
3958static xmlAttrPtr
3959xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003960 xmlAttrPtr ret;
3961
3962 if (cur == NULL) return(NULL);
Daniel Veillard3e62adb2012-08-09 14:24:02 +08003963 if ((target != NULL) && (target->type != XML_ELEMENT_NODE))
3964 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003965 if (target != NULL)
3966 ret = xmlNewDocProp(target->doc, cur->name, NULL);
Rob Richards19dc9612005-10-28 16:15:16 +00003967 else if (doc != NULL)
3968 ret = xmlNewDocProp(doc, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003969 else if (cur->parent != NULL)
3970 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3971 else if (cur->children != NULL)
3972 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3973 else
3974 ret = xmlNewDocProp(NULL, cur->name, NULL);
3975 if (ret == NULL) return(NULL);
3976 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003977
Owen Taylor3473f882001-02-23 17:55:21 +00003978 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003979 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003980
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003981 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3982 if (ns == NULL) {
3983 /*
3984 * Humm, we are copying an element whose namespace is defined
3985 * out of the new tree scope. Search it in the original tree
3986 * and add it at the top of the new tree
3987 */
3988 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3989 if (ns != NULL) {
3990 xmlNodePtr root = target;
3991 xmlNodePtr pred = NULL;
3992
3993 while (root->parent != NULL) {
3994 pred = root;
3995 root = root->parent;
3996 }
3997 if (root == (xmlNodePtr) target->doc) {
3998 /* correct possibly cycling above the document elt */
3999 root = pred;
4000 }
4001 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
4002 }
4003 } else {
4004 /*
4005 * we have to find something appropriate here since
4006 * we cant be sure, that the namespce we found is identified
4007 * by the prefix
4008 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004009 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00004010 /* this is the nice case */
4011 ret->ns = ns;
4012 } else {
4013 /*
4014 * we are in trouble: we need a new reconcilied namespace.
4015 * This is expensive
4016 */
4017 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
4018 }
4019 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00004020
Owen Taylor3473f882001-02-23 17:55:21 +00004021 } else
4022 ret->ns = NULL;
4023
4024 if (cur->children != NULL) {
4025 xmlNodePtr tmp;
4026
4027 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
4028 ret->last = NULL;
4029 tmp = ret->children;
4030 while (tmp != NULL) {
4031 /* tmp->parent = (xmlNodePtr)ret; */
4032 if (tmp->next == NULL)
4033 ret->last = tmp;
4034 tmp = tmp->next;
4035 }
4036 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00004037 /*
4038 * Try to handle IDs
4039 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00004040 if ((target!= NULL) && (cur!= NULL) &&
4041 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00004042 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
4043 if (xmlIsID(cur->doc, cur->parent, cur)) {
4044 xmlChar *id;
4045
4046 id = xmlNodeListGetString(cur->doc, cur->children, 1);
4047 if (id != NULL) {
4048 xmlAddID(NULL, target->doc, id, ret);
4049 xmlFree(id);
4050 }
4051 }
4052 }
Owen Taylor3473f882001-02-23 17:55:21 +00004053 return(ret);
4054}
4055
4056/**
Rob Richards19dc9612005-10-28 16:15:16 +00004057 * xmlCopyProp:
4058 * @target: the element where the attribute will be grafted
4059 * @cur: the attribute
4060 *
4061 * Do a copy of the attribute.
4062 *
4063 * Returns: a new #xmlAttrPtr, or NULL in case of error.
4064 */
4065xmlAttrPtr
4066xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
4067 return xmlCopyPropInternal(NULL, target, cur);
4068}
4069
4070/**
Owen Taylor3473f882001-02-23 17:55:21 +00004071 * xmlCopyPropList:
4072 * @target: the element where the attributes will be grafted
4073 * @cur: the first attribute
4074 *
4075 * Do a copy of an attribute list.
4076 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004077 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004078 */
4079xmlAttrPtr
4080xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
4081 xmlAttrPtr ret = NULL;
4082 xmlAttrPtr p = NULL,q;
4083
Daniel Veillard3e62adb2012-08-09 14:24:02 +08004084 if ((target != NULL) && (target->type != XML_ELEMENT_NODE))
4085 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004086 while (cur != NULL) {
4087 q = xmlCopyProp(target, cur);
William M. Brack13dfa872004-09-18 04:52:08 +00004088 if (q == NULL)
4089 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004090 if (p == NULL) {
4091 ret = p = q;
4092 } else {
4093 p->next = q;
4094 q->prev = p;
4095 p = q;
4096 }
4097 cur = cur->next;
4098 }
4099 return(ret);
4100}
4101
4102/*
Daniel Veillardd1640922001-12-17 15:30:10 +00004103 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00004104 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004105 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00004106 * tricky reason: namespaces. Doing a direct copy of a node
4107 * say RPM:Copyright without changing the namespace pointer to
4108 * something else can produce stale links. One way to do it is
4109 * to keep a reference counter but this doesn't work as soon
4110 * as one move the element or the subtree out of the scope of
4111 * the existing namespace. The actual solution seems to add
4112 * a copy of the namespace at the top of the copied tree if
4113 * not available in the subtree.
4114 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00004115 * The argument "recursive" normally indicates a recursive copy
4116 * of the node with values 0 (no) and 1 (yes). For XInclude,
4117 * however, we allow a value of 2 to indicate copy properties and
4118 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00004119 */
4120
4121static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00004122xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00004123 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00004124 xmlNodePtr ret;
4125
4126 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00004127 switch (node->type) {
4128 case XML_TEXT_NODE:
4129 case XML_CDATA_SECTION_NODE:
4130 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00004131 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00004132 case XML_ENTITY_REF_NODE:
4133 case XML_ENTITY_NODE:
4134 case XML_PI_NODE:
4135 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00004136 case XML_XINCLUDE_START:
4137 case XML_XINCLUDE_END:
4138 break;
4139 case XML_ATTRIBUTE_NODE:
Rob Richards19dc9612005-10-28 16:15:16 +00004140 return((xmlNodePtr) xmlCopyPropInternal(doc, parent, (xmlAttrPtr) node));
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00004141 case XML_NAMESPACE_DECL:
4142 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
Daniel Veillardaa6de472008-08-25 14:53:31 +00004143
Daniel Veillard39196eb2001-06-19 18:09:42 +00004144 case XML_DOCUMENT_NODE:
4145 case XML_HTML_DOCUMENT_NODE:
4146#ifdef LIBXML_DOCB_ENABLED
4147 case XML_DOCB_DOCUMENT_NODE:
4148#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00004149#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00004150 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00004151#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00004152 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00004153 case XML_NOTATION_NODE:
4154 case XML_DTD_NODE:
4155 case XML_ELEMENT_DECL:
4156 case XML_ATTRIBUTE_DECL:
4157 case XML_ENTITY_DECL:
4158 return(NULL);
4159 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00004160
Owen Taylor3473f882001-02-23 17:55:21 +00004161 /*
4162 * Allocate a new node and fill the fields.
4163 */
4164 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
4165 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004166 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00004167 return(NULL);
4168 }
4169 memset(ret, 0, sizeof(xmlNode));
4170 ret->type = node->type;
4171
4172 ret->doc = doc;
Daniel Veillardaa6de472008-08-25 14:53:31 +00004173 ret->parent = parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004174 if (node->name == xmlStringText)
4175 ret->name = xmlStringText;
4176 else if (node->name == xmlStringTextNoenc)
4177 ret->name = xmlStringTextNoenc;
4178 else if (node->name == xmlStringComment)
4179 ret->name = xmlStringComment;
Daniel Veillard03a53c32004-10-26 16:06:51 +00004180 else if (node->name != NULL) {
4181 if ((doc != NULL) && (doc->dict != NULL))
4182 ret->name = xmlDictLookup(doc->dict, node->name, -1);
4183 else
4184 ret->name = xmlStrdup(node->name);
4185 }
Daniel Veillard7db37732001-07-12 01:20:08 +00004186 if ((node->type != XML_ELEMENT_NODE) &&
4187 (node->content != NULL) &&
4188 (node->type != XML_ENTITY_REF_NODE) &&
4189 (node->type != XML_XINCLUDE_END) &&
4190 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004191 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00004192 }else{
4193 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004194 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00004195 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004196 if (parent != NULL) {
4197 xmlNodePtr tmp;
4198
Daniel Veillard8a1b1852003-01-05 22:37:17 +00004199 /*
4200 * this is a tricky part for the node register thing:
4201 * in case ret does get coalesced in xmlAddChild
4202 * the deregister-node callback is called; so we register ret now already
4203 */
Daniel Veillarda880b122003-04-21 21:36:41 +00004204 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00004205 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
4206
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004207 tmp = xmlAddChild(parent, ret);
4208 /* node could have coalesced */
4209 if (tmp != ret)
4210 return(tmp);
4211 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00004212
William M. Brack57e9e912004-03-09 16:19:02 +00004213 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00004214 goto out;
Petr Pajas2afca4a2009-07-30 17:47:32 +02004215 if (((node->type == XML_ELEMENT_NODE) ||
4216 (node->type == XML_XINCLUDE_START)) && (node->nsDef != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00004217 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
4218
4219 if (node->ns != NULL) {
4220 xmlNsPtr ns;
4221
4222 ns = xmlSearchNs(doc, ret, node->ns->prefix);
4223 if (ns == NULL) {
4224 /*
4225 * Humm, we are copying an element whose namespace is defined
4226 * out of the new tree scope. Search it in the original tree
4227 * and add it at the top of the new tree
4228 */
4229 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
4230 if (ns != NULL) {
4231 xmlNodePtr root = ret;
4232
4233 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00004234 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Rob Richardsddb01cb2010-01-29 13:32:12 -05004235 } else {
4236 ret->ns = xmlNewReconciliedNs(doc, ret, node->ns);
Owen Taylor3473f882001-02-23 17:55:21 +00004237 }
4238 } else {
4239 /*
4240 * reference the existing namespace definition in our own tree.
4241 */
4242 ret->ns = ns;
4243 }
4244 }
Petr Pajas2afca4a2009-07-30 17:47:32 +02004245 if (((node->type == XML_ELEMENT_NODE) ||
4246 (node->type == XML_XINCLUDE_START)) && (node->properties != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00004247 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004248 if (node->type == XML_ENTITY_REF_NODE) {
4249 if ((doc == NULL) || (node->doc != doc)) {
4250 /*
4251 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00004252 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00004253 * we cannot keep the reference. Try to find it in the
4254 * target document.
4255 */
4256 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
4257 } else {
4258 ret->children = node->children;
4259 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00004260 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00004261 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004262 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00004263 UPDATE_LAST_CHILD_AND_PARENT(ret)
4264 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00004265
4266out:
4267 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00004268 if ((parent == NULL) &&
4269 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00004270 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004271 return(ret);
4272}
4273
4274static xmlNodePtr
4275xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
4276 xmlNodePtr ret = NULL;
4277 xmlNodePtr p = NULL,q;
4278
4279 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00004280#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00004281 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00004282 if (doc == NULL) {
4283 node = node->next;
4284 continue;
4285 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00004286 if (doc->intSubset == NULL) {
4287 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
4288 q->doc = doc;
4289 q->parent = parent;
4290 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004291 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004292 } else {
4293 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004294 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004295 }
4296 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00004297#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00004298 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00004299 if (ret == NULL) {
4300 q->prev = NULL;
4301 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004302 } else if (p != q) {
4303 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00004304 p->next = q;
4305 q->prev = p;
4306 p = q;
4307 }
4308 node = node->next;
4309 }
4310 return(ret);
4311}
4312
4313/**
4314 * xmlCopyNode:
4315 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00004316 * @extended: if 1 do a recursive copy (properties, namespaces and children
4317 * when applicable)
4318 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00004319 *
4320 * Do a copy of the node.
4321 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004322 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004323 */
4324xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00004325xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00004326 xmlNodePtr ret;
4327
William M. Brack57e9e912004-03-09 16:19:02 +00004328 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00004329 return(ret);
4330}
4331
4332/**
Daniel Veillard82daa812001-04-12 08:55:36 +00004333 * xmlDocCopyNode:
4334 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00004335 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004336 * @extended: if 1 do a recursive copy (properties, namespaces and children
4337 * when applicable)
4338 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00004339 *
4340 * Do a copy of the node to a given document.
4341 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004342 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00004343 */
4344xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00004345xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00004346 xmlNodePtr ret;
4347
William M. Brack57e9e912004-03-09 16:19:02 +00004348 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00004349 return(ret);
4350}
4351
4352/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00004353 * xmlDocCopyNodeList:
4354 * @doc: the target document
4355 * @node: the first node in the list.
4356 *
4357 * Do a recursive copy of the node list.
4358 *
4359 * Returns: a new #xmlNodePtr, or NULL in case of error.
4360 */
4361xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) {
4362 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
4363 return(ret);
4364}
4365
4366/**
Owen Taylor3473f882001-02-23 17:55:21 +00004367 * xmlCopyNodeList:
4368 * @node: the first node in the list.
4369 *
4370 * Do a recursive copy of the node list.
Daniel Veillard03a53c32004-10-26 16:06:51 +00004371 * Use xmlDocCopyNodeList() if possible to ensure string interning.
Owen Taylor3473f882001-02-23 17:55:21 +00004372 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004373 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004374 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00004375xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00004376 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
4377 return(ret);
4378}
4379
Daniel Veillard2156d432004-03-04 15:59:36 +00004380#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004381/**
Owen Taylor3473f882001-02-23 17:55:21 +00004382 * xmlCopyDtd:
4383 * @dtd: the dtd
4384 *
4385 * Do a copy of the dtd.
4386 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004387 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004388 */
4389xmlDtdPtr
4390xmlCopyDtd(xmlDtdPtr dtd) {
4391 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004392 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00004393
4394 if (dtd == NULL) return(NULL);
4395 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4396 if (ret == NULL) return(NULL);
4397 if (dtd->entities != NULL)
4398 ret->entities = (void *) xmlCopyEntitiesTable(
4399 (xmlEntitiesTablePtr) dtd->entities);
4400 if (dtd->notations != NULL)
4401 ret->notations = (void *) xmlCopyNotationTable(
4402 (xmlNotationTablePtr) dtd->notations);
4403 if (dtd->elements != NULL)
4404 ret->elements = (void *) xmlCopyElementTable(
4405 (xmlElementTablePtr) dtd->elements);
4406 if (dtd->attributes != NULL)
4407 ret->attributes = (void *) xmlCopyAttributeTable(
4408 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004409 if (dtd->pentities != NULL)
4410 ret->pentities = (void *) xmlCopyEntitiesTable(
4411 (xmlEntitiesTablePtr) dtd->pentities);
Daniel Veillardaa6de472008-08-25 14:53:31 +00004412
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004413 cur = dtd->children;
4414 while (cur != NULL) {
4415 q = NULL;
4416
4417 if (cur->type == XML_ENTITY_DECL) {
4418 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4419 switch (tmp->etype) {
4420 case XML_INTERNAL_GENERAL_ENTITY:
4421 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4422 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4423 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4424 break;
4425 case XML_INTERNAL_PARAMETER_ENTITY:
4426 case XML_EXTERNAL_PARAMETER_ENTITY:
Daniel Veillardaa6de472008-08-25 14:53:31 +00004427 q = (xmlNodePtr)
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004428 xmlGetParameterEntityFromDtd(ret, tmp->name);
4429 break;
4430 case XML_INTERNAL_PREDEFINED_ENTITY:
4431 break;
4432 }
4433 } else if (cur->type == XML_ELEMENT_DECL) {
4434 xmlElementPtr tmp = (xmlElementPtr) cur;
4435 q = (xmlNodePtr)
4436 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4437 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4438 xmlAttributePtr tmp = (xmlAttributePtr) cur;
Daniel Veillardaa6de472008-08-25 14:53:31 +00004439 q = (xmlNodePtr)
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004440 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4441 } else if (cur->type == XML_COMMENT_NODE) {
4442 q = xmlCopyNode(cur, 0);
4443 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00004444
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004445 if (q == NULL) {
4446 cur = cur->next;
4447 continue;
4448 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00004449
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004450 if (p == NULL)
4451 ret->children = q;
4452 else
Daniel Veillardaa6de472008-08-25 14:53:31 +00004453 p->next = q;
4454
4455 q->prev = p;
4456 q->parent = (xmlNodePtr) ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004457 q->next = NULL;
4458 ret->last = q;
Daniel Veillardaa6de472008-08-25 14:53:31 +00004459 p = q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004460 cur = cur->next;
4461 }
4462
Owen Taylor3473f882001-02-23 17:55:21 +00004463 return(ret);
4464}
Daniel Veillard2156d432004-03-04 15:59:36 +00004465#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004466
Daniel Veillard2156d432004-03-04 15:59:36 +00004467#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004468/**
4469 * xmlCopyDoc:
4470 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004471 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004472 *
4473 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004474 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004475 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004476 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004477 */
4478xmlDocPtr
4479xmlCopyDoc(xmlDocPtr doc, int recursive) {
4480 xmlDocPtr ret;
4481
4482 if (doc == NULL) return(NULL);
4483 ret = xmlNewDoc(doc->version);
4484 if (ret == NULL) return(NULL);
4485 if (doc->name != NULL)
4486 ret->name = xmlMemStrdup(doc->name);
4487 if (doc->encoding != NULL)
4488 ret->encoding = xmlStrdup(doc->encoding);
Daniel Veillardf59507d2005-01-27 17:26:49 +00004489 if (doc->URL != NULL)
4490 ret->URL = xmlStrdup(doc->URL);
Owen Taylor3473f882001-02-23 17:55:21 +00004491 ret->charset = doc->charset;
4492 ret->compression = doc->compression;
4493 ret->standalone = doc->standalone;
4494 if (!recursive) return(ret);
4495
Daniel Veillardb33c2012001-04-25 12:59:04 +00004496 ret->last = NULL;
4497 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004498#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004499 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004500 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004501 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004502 ret->intSubset->parent = ret;
4503 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004504#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004505 if (doc->oldNs != NULL)
4506 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4507 if (doc->children != NULL) {
4508 xmlNodePtr tmp;
Daniel Veillardaa6de472008-08-25 14:53:31 +00004509
Daniel Veillardb33c2012001-04-25 12:59:04 +00004510 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4511 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004512 ret->last = NULL;
4513 tmp = ret->children;
4514 while (tmp != NULL) {
4515 if (tmp->next == NULL)
4516 ret->last = tmp;
4517 tmp = tmp->next;
4518 }
4519 }
4520 return(ret);
4521}
Daniel Veillard652327a2003-09-29 18:02:38 +00004522#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004523
4524/************************************************************************
4525 * *
4526 * Content access functions *
4527 * *
4528 ************************************************************************/
Daniel Veillardaa6de472008-08-25 14:53:31 +00004529
Owen Taylor3473f882001-02-23 17:55:21 +00004530/**
Daniel Veillard968a03a2012-08-13 12:41:33 +08004531 * xmlGetLineNoInternal:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004532 * @node: valid node
Daniel Veillard968a03a2012-08-13 12:41:33 +08004533 * @depth: used to limit any risk of recursion
Daniel Veillard8faa7832001-11-26 15:58:08 +00004534 *
Daniel Veillard968a03a2012-08-13 12:41:33 +08004535 * Get line number of @node.
4536 * Try to override the limitation of lines being store in 16 bits ints
Daniel Veillard8faa7832001-11-26 15:58:08 +00004537 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004538 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004539 */
Daniel Veillard968a03a2012-08-13 12:41:33 +08004540static long
4541xmlGetLineNoInternal(xmlNodePtr node, int depth)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004542{
4543 long result = -1;
4544
Daniel Veillard968a03a2012-08-13 12:41:33 +08004545 if (depth >= 5)
4546 return(-1);
4547
Daniel Veillard8faa7832001-11-26 15:58:08 +00004548 if (!node)
4549 return result;
Daniel Veillard73da77e2005-08-24 14:05:37 +00004550 if ((node->type == XML_ELEMENT_NODE) ||
4551 (node->type == XML_TEXT_NODE) ||
4552 (node->type == XML_COMMENT_NODE) ||
Daniel Veillard968a03a2012-08-13 12:41:33 +08004553 (node->type == XML_PI_NODE)) {
4554 if (node->line == 65535) {
4555 if ((node->type == XML_TEXT_NODE) && (node->psvi != NULL))
4556 result = (long) node->psvi;
4557 else if ((node->type == XML_ELEMENT_NODE) &&
4558 (node->children != NULL))
4559 result = xmlGetLineNoInternal(node->children, depth + 1);
4560 else if (node->next != NULL)
4561 result = xmlGetLineNoInternal(node->next, depth + 1);
4562 else if (node->prev != NULL)
4563 result = xmlGetLineNoInternal(node->prev, depth + 1);
4564 }
4565 if ((result == -1) || (result == 65535))
4566 result = (long) node->line;
4567 } else if ((node->prev != NULL) &&
Daniel Veillard8faa7832001-11-26 15:58:08 +00004568 ((node->prev->type == XML_ELEMENT_NODE) ||
Daniel Veillard73da77e2005-08-24 14:05:37 +00004569 (node->prev->type == XML_TEXT_NODE) ||
4570 (node->prev->type == XML_COMMENT_NODE) ||
4571 (node->prev->type == XML_PI_NODE)))
Daniel Veillard968a03a2012-08-13 12:41:33 +08004572 result = xmlGetLineNoInternal(node->prev, depth + 1);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004573 else if ((node->parent != NULL) &&
Daniel Veillard73da77e2005-08-24 14:05:37 +00004574 (node->parent->type == XML_ELEMENT_NODE))
Daniel Veillard968a03a2012-08-13 12:41:33 +08004575 result = xmlGetLineNoInternal(node->parent, depth + 1);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004576
4577 return result;
4578}
4579
Daniel Veillard968a03a2012-08-13 12:41:33 +08004580/**
4581 * xmlGetLineNo:
4582 * @node: valid node
4583 *
4584 * Get line number of @node.
4585 * Try to override the limitation of lines being store in 16 bits ints
4586 * if XML_PARSE_BIG_LINES parser option was used
4587 *
4588 * Returns the line number if successful, -1 otherwise
4589 */
4590long
4591xmlGetLineNo(xmlNodePtr node)
4592{
4593 return(xmlGetLineNoInternal(node, 0));
4594}
4595
Daniel Veillard2156d432004-03-04 15:59:36 +00004596#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004597/**
4598 * xmlGetNodePath:
4599 * @node: a node
4600 *
4601 * Build a structure based Path for the given node
4602 *
4603 * Returns the new path or NULL in case of error. The caller must free
4604 * the returned string
4605 */
4606xmlChar *
4607xmlGetNodePath(xmlNodePtr node)
4608{
4609 xmlNodePtr cur, tmp, next;
4610 xmlChar *buffer = NULL, *temp;
4611 size_t buf_len;
4612 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004613 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004614 const char *name;
4615 char nametemp[100];
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004616 int occur = 0, generic;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004617
Daniel Veillard3e62adb2012-08-09 14:24:02 +08004618 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004619 return (NULL);
4620
4621 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004622 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004623 if (buffer == NULL) {
4624 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004625 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004626 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004627 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004628 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004629 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004630 xmlFree(buffer);
4631 return (NULL);
4632 }
4633
4634 buffer[0] = 0;
4635 cur = node;
4636 do {
4637 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004638 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004639 occur = 0;
4640 if ((cur->type == XML_DOCUMENT_NODE) ||
4641 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4642 if (buffer[0] == '/')
4643 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004644 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004645 next = NULL;
4646 } else if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004647 generic = 0;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004648 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004649 name = (const char *) cur->name;
4650 if (cur->ns) {
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004651 if (cur->ns->prefix != NULL) {
William M. Brack13dfa872004-09-18 04:52:08 +00004652 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
Daniel Veillardaa6de472008-08-25 14:53:31 +00004653 (char *)cur->ns->prefix, (char *)cur->name);
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004654 nametemp[sizeof(nametemp) - 1] = 0;
4655 name = nametemp;
4656 } else {
4657 /*
4658 * We cannot express named elements in the default
4659 * namespace, so use "*".
4660 */
4661 generic = 1;
4662 name = "*";
Daniel Veillardaa6de472008-08-25 14:53:31 +00004663 }
Daniel Veillard8faa7832001-11-26 15:58:08 +00004664 }
4665 next = cur->parent;
4666
4667 /*
4668 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004669 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004670 */
4671 tmp = cur->prev;
4672 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004673 if ((tmp->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004674 (generic ||
Kasimier T. Buchcik43ceb1e2006-06-12 11:08:18 +00004675 (xmlStrEqual(cur->name, tmp->name) &&
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004676 ((tmp->ns == cur->ns) ||
4677 ((tmp->ns != NULL) && (cur->ns != NULL) &&
Kasimier T. Buchcik43ceb1e2006-06-12 11:08:18 +00004678 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004679 occur++;
4680 tmp = tmp->prev;
4681 }
4682 if (occur == 0) {
4683 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004684 while (tmp != NULL && occur == 0) {
4685 if ((tmp->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004686 (generic ||
Kasimier T. Buchcik43ceb1e2006-06-12 11:08:18 +00004687 (xmlStrEqual(cur->name, tmp->name) &&
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004688 ((tmp->ns == cur->ns) ||
4689 ((tmp->ns != NULL) && (cur->ns != NULL) &&
Kasimier T. Buchcik43ceb1e2006-06-12 11:08:18 +00004690 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004691 occur++;
4692 tmp = tmp->next;
4693 }
4694 if (occur != 0)
4695 occur = 1;
4696 } else
4697 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004698 } else if (cur->type == XML_COMMENT_NODE) {
4699 sep = "/";
4700 name = "comment()";
4701 next = cur->parent;
4702
4703 /*
4704 * Thumbler index computation
4705 */
4706 tmp = cur->prev;
4707 while (tmp != NULL) {
4708 if (tmp->type == XML_COMMENT_NODE)
4709 occur++;
4710 tmp = tmp->prev;
4711 }
4712 if (occur == 0) {
4713 tmp = cur->next;
4714 while (tmp != NULL && occur == 0) {
4715 if (tmp->type == XML_COMMENT_NODE)
4716 occur++;
4717 tmp = tmp->next;
4718 }
4719 if (occur != 0)
4720 occur = 1;
4721 } else
4722 occur++;
4723 } else if ((cur->type == XML_TEXT_NODE) ||
4724 (cur->type == XML_CDATA_SECTION_NODE)) {
4725 sep = "/";
4726 name = "text()";
4727 next = cur->parent;
4728
4729 /*
4730 * Thumbler index computation
4731 */
4732 tmp = cur->prev;
4733 while (tmp != NULL) {
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004734 if ((tmp->type == XML_TEXT_NODE) ||
4735 (tmp->type == XML_CDATA_SECTION_NODE))
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004736 occur++;
4737 tmp = tmp->prev;
4738 }
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004739 /*
4740 * Evaluate if this is the only text- or CDATA-section-node;
4741 * if yes, then we'll get "text()", otherwise "text()[1]".
4742 */
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004743 if (occur == 0) {
4744 tmp = cur->next;
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004745 while (tmp != NULL) {
4746 if ((tmp->type == XML_TEXT_NODE) ||
4747 (tmp->type == XML_CDATA_SECTION_NODE))
4748 {
4749 occur = 1;
4750 break;
Daniel Veillardaa6de472008-08-25 14:53:31 +00004751 }
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004752 tmp = tmp->next;
4753 }
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004754 } else
4755 occur++;
4756 } else if (cur->type == XML_PI_NODE) {
4757 sep = "/";
4758 snprintf(nametemp, sizeof(nametemp) - 1,
William M. Brack13dfa872004-09-18 04:52:08 +00004759 "processing-instruction('%s')", (char *)cur->name);
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004760 nametemp[sizeof(nametemp) - 1] = 0;
4761 name = nametemp;
4762
4763 next = cur->parent;
4764
4765 /*
4766 * Thumbler index computation
4767 */
4768 tmp = cur->prev;
4769 while (tmp != NULL) {
4770 if ((tmp->type == XML_PI_NODE) &&
4771 (xmlStrEqual(cur->name, tmp->name)))
4772 occur++;
4773 tmp = tmp->prev;
4774 }
4775 if (occur == 0) {
4776 tmp = cur->next;
4777 while (tmp != NULL && occur == 0) {
4778 if ((tmp->type == XML_PI_NODE) &&
4779 (xmlStrEqual(cur->name, tmp->name)))
4780 occur++;
4781 tmp = tmp->next;
4782 }
4783 if (occur != 0)
4784 occur = 1;
4785 } else
4786 occur++;
4787
Daniel Veillard8faa7832001-11-26 15:58:08 +00004788 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004789 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004790 name = (const char *) (((xmlAttrPtr) cur)->name);
Daniel Veillard365c8062005-07-19 11:31:55 +00004791 if (cur->ns) {
4792 if (cur->ns->prefix != NULL)
4793 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
Daniel Veillardaa6de472008-08-25 14:53:31 +00004794 (char *)cur->ns->prefix, (char *)cur->name);
Daniel Veillard365c8062005-07-19 11:31:55 +00004795 else
4796 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
Daniel Veillardaa6de472008-08-25 14:53:31 +00004797 (char *)cur->name);
Daniel Veillard365c8062005-07-19 11:31:55 +00004798 nametemp[sizeof(nametemp) - 1] = 0;
4799 name = nametemp;
4800 }
Daniel Veillard8faa7832001-11-26 15:58:08 +00004801 next = ((xmlAttrPtr) cur)->parent;
4802 } else {
4803 next = cur->parent;
4804 }
4805
4806 /*
4807 * Make sure there is enough room
4808 */
4809 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4810 buf_len =
4811 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4812 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4813 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004814 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004815 xmlFree(buf);
4816 xmlFree(buffer);
4817 return (NULL);
4818 }
4819 buffer = temp;
4820 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4821 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004822 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004823 xmlFree(buf);
4824 xmlFree(buffer);
4825 return (NULL);
4826 }
4827 buf = temp;
4828 }
4829 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004830 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004831 sep, name, (char *) buffer);
4832 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004833 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004834 sep, name, occur, (char *) buffer);
William M. Brack13dfa872004-09-18 04:52:08 +00004835 snprintf((char *) buffer, buf_len, "%s", (char *)buf);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004836 cur = next;
4837 } while (cur != NULL);
4838 xmlFree(buf);
4839 return (buffer);
4840}
Daniel Veillard652327a2003-09-29 18:02:38 +00004841#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004842
4843/**
Owen Taylor3473f882001-02-23 17:55:21 +00004844 * xmlDocGetRootElement:
4845 * @doc: the document
4846 *
4847 * Get the root element of the document (doc->children is a list
4848 * containing possibly comments, PIs, etc ...).
4849 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004850 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004851 */
4852xmlNodePtr
4853xmlDocGetRootElement(xmlDocPtr doc) {
4854 xmlNodePtr ret;
4855
4856 if (doc == NULL) return(NULL);
4857 ret = doc->children;
4858 while (ret != NULL) {
4859 if (ret->type == XML_ELEMENT_NODE)
4860 return(ret);
4861 ret = ret->next;
4862 }
4863 return(ret);
4864}
Daniel Veillardaa6de472008-08-25 14:53:31 +00004865
Daniel Veillard2156d432004-03-04 15:59:36 +00004866#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004867/**
4868 * xmlDocSetRootElement:
4869 * @doc: the document
Daniel Veillard26a45c82006-10-20 12:55:34 +00004870 * @root: the new document root element, if root is NULL no action is taken,
4871 * to remove a node from a document use xmlUnlinkNode(root) instead.
Owen Taylor3473f882001-02-23 17:55:21 +00004872 *
4873 * Set the root element of the document (doc->children is a list
4874 * containing possibly comments, PIs, etc ...).
4875 *
Daniel Veillard26a45c82006-10-20 12:55:34 +00004876 * Returns the old root element if any was found, NULL if root was NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004877 */
4878xmlNodePtr
4879xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4880 xmlNodePtr old = NULL;
4881
4882 if (doc == NULL) return(NULL);
Daniel Veillard3e62adb2012-08-09 14:24:02 +08004883 if ((root == NULL) || (root->type == XML_NAMESPACE_DECL))
Daniel Veillardc575b992002-02-08 13:28:40 +00004884 return(NULL);
4885 xmlUnlinkNode(root);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00004886 xmlSetTreeDoc(root, doc);
Daniel Veillardc575b992002-02-08 13:28:40 +00004887 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004888 old = doc->children;
4889 while (old != NULL) {
4890 if (old->type == XML_ELEMENT_NODE)
4891 break;
4892 old = old->next;
4893 }
4894 if (old == NULL) {
4895 if (doc->children == NULL) {
4896 doc->children = root;
4897 doc->last = root;
4898 } else {
4899 xmlAddSibling(doc->children, root);
4900 }
4901 } else {
4902 xmlReplaceNode(old, root);
4903 }
4904 return(old);
4905}
Daniel Veillard2156d432004-03-04 15:59:36 +00004906#endif
Daniel Veillardaa6de472008-08-25 14:53:31 +00004907
Daniel Veillard2156d432004-03-04 15:59:36 +00004908#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004909/**
4910 * xmlNodeSetLang:
4911 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004912 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004913 *
4914 * Set the language of a node, i.e. the values of the xml:lang
4915 * attribute.
4916 */
4917void
4918xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004919 xmlNsPtr ns;
4920
Owen Taylor3473f882001-02-23 17:55:21 +00004921 if (cur == NULL) return;
4922 switch(cur->type) {
4923 case XML_TEXT_NODE:
4924 case XML_CDATA_SECTION_NODE:
4925 case XML_COMMENT_NODE:
4926 case XML_DOCUMENT_NODE:
4927 case XML_DOCUMENT_TYPE_NODE:
4928 case XML_DOCUMENT_FRAG_NODE:
4929 case XML_NOTATION_NODE:
4930 case XML_HTML_DOCUMENT_NODE:
4931 case XML_DTD_NODE:
4932 case XML_ELEMENT_DECL:
4933 case XML_ATTRIBUTE_DECL:
4934 case XML_ENTITY_DECL:
4935 case XML_PI_NODE:
4936 case XML_ENTITY_REF_NODE:
4937 case XML_ENTITY_NODE:
4938 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004939#ifdef LIBXML_DOCB_ENABLED
4940 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004941#endif
4942 case XML_XINCLUDE_START:
4943 case XML_XINCLUDE_END:
4944 return;
4945 case XML_ELEMENT_NODE:
4946 case XML_ATTRIBUTE_NODE:
4947 break;
4948 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004949 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4950 if (ns == NULL)
4951 return;
4952 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004953}
Daniel Veillard652327a2003-09-29 18:02:38 +00004954#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardaa6de472008-08-25 14:53:31 +00004955
Owen Taylor3473f882001-02-23 17:55:21 +00004956/**
4957 * xmlNodeGetLang:
4958 * @cur: the node being checked
4959 *
4960 * Searches the language of a node, i.e. the values of the xml:lang
4961 * attribute or the one carried by the nearest ancestor.
4962 *
4963 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004964 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004965 */
4966xmlChar *
4967xmlNodeGetLang(xmlNodePtr cur) {
4968 xmlChar *lang;
4969
Daniel Veillard3e62adb2012-08-09 14:24:02 +08004970 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
4971 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004972 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004973 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004974 if (lang != NULL)
4975 return(lang);
4976 cur = cur->parent;
4977 }
4978 return(NULL);
4979}
Daniel Veillardaa6de472008-08-25 14:53:31 +00004980
Owen Taylor3473f882001-02-23 17:55:21 +00004981
Daniel Veillard652327a2003-09-29 18:02:38 +00004982#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004983/**
4984 * xmlNodeSetSpacePreserve:
4985 * @cur: the node being changed
4986 * @val: the xml:space value ("0": default, 1: "preserve")
4987 *
4988 * Set (or reset) the space preserving behaviour of a node, i.e. the
4989 * value of the xml:space attribute.
4990 */
4991void
4992xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004993 xmlNsPtr ns;
4994
Owen Taylor3473f882001-02-23 17:55:21 +00004995 if (cur == NULL) return;
4996 switch(cur->type) {
4997 case XML_TEXT_NODE:
4998 case XML_CDATA_SECTION_NODE:
4999 case XML_COMMENT_NODE:
5000 case XML_DOCUMENT_NODE:
5001 case XML_DOCUMENT_TYPE_NODE:
5002 case XML_DOCUMENT_FRAG_NODE:
5003 case XML_NOTATION_NODE:
5004 case XML_HTML_DOCUMENT_NODE:
5005 case XML_DTD_NODE:
5006 case XML_ELEMENT_DECL:
5007 case XML_ATTRIBUTE_DECL:
5008 case XML_ENTITY_DECL:
5009 case XML_PI_NODE:
5010 case XML_ENTITY_REF_NODE:
5011 case XML_ENTITY_NODE:
5012 case XML_NAMESPACE_DECL:
5013 case XML_XINCLUDE_START:
5014 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005015#ifdef LIBXML_DOCB_ENABLED
5016 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005017#endif
5018 return;
5019 case XML_ELEMENT_NODE:
5020 case XML_ATTRIBUTE_NODE:
5021 break;
5022 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00005023 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
5024 if (ns == NULL)
5025 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005026 switch (val) {
5027 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00005028 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00005029 break;
5030 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00005031 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00005032 break;
5033 }
5034}
Daniel Veillard652327a2003-09-29 18:02:38 +00005035#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005036
5037/**
5038 * xmlNodeGetSpacePreserve:
5039 * @cur: the node being checked
5040 *
5041 * Searches the space preserving behaviour of a node, i.e. the values
5042 * of the xml:space attribute or the one carried by the nearest
5043 * ancestor.
5044 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005045 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00005046 */
5047int
5048xmlNodeGetSpacePreserve(xmlNodePtr cur) {
5049 xmlChar *space;
5050
Daniel Veillard3e62adb2012-08-09 14:24:02 +08005051 if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE))
5052 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005053 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00005054 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00005055 if (space != NULL) {
5056 if (xmlStrEqual(space, BAD_CAST "preserve")) {
5057 xmlFree(space);
5058 return(1);
5059 }
5060 if (xmlStrEqual(space, BAD_CAST "default")) {
5061 xmlFree(space);
5062 return(0);
5063 }
5064 xmlFree(space);
5065 }
5066 cur = cur->parent;
5067 }
5068 return(-1);
5069}
Daniel Veillardaa6de472008-08-25 14:53:31 +00005070
Daniel Veillard652327a2003-09-29 18:02:38 +00005071#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005072/**
5073 * xmlNodeSetName:
5074 * @cur: the node being changed
5075 * @name: the new tag name
5076 *
5077 * Set (or reset) the name of a node.
5078 */
5079void
5080xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00005081 xmlDocPtr doc;
5082 xmlDictPtr dict;
5083
Owen Taylor3473f882001-02-23 17:55:21 +00005084 if (cur == NULL) return;
5085 if (name == NULL) return;
5086 switch(cur->type) {
5087 case XML_TEXT_NODE:
5088 case XML_CDATA_SECTION_NODE:
5089 case XML_COMMENT_NODE:
5090 case XML_DOCUMENT_TYPE_NODE:
5091 case XML_DOCUMENT_FRAG_NODE:
5092 case XML_NOTATION_NODE:
5093 case XML_HTML_DOCUMENT_NODE:
5094 case XML_NAMESPACE_DECL:
5095 case XML_XINCLUDE_START:
5096 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005097#ifdef LIBXML_DOCB_ENABLED
5098 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005099#endif
5100 return;
5101 case XML_ELEMENT_NODE:
5102 case XML_ATTRIBUTE_NODE:
5103 case XML_PI_NODE:
5104 case XML_ENTITY_REF_NODE:
5105 case XML_ENTITY_NODE:
5106 case XML_DTD_NODE:
5107 case XML_DOCUMENT_NODE:
5108 case XML_ELEMENT_DECL:
5109 case XML_ATTRIBUTE_DECL:
5110 case XML_ENTITY_DECL:
5111 break;
5112 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00005113 doc = cur->doc;
5114 if (doc != NULL)
5115 dict = doc->dict;
5116 else
5117 dict = NULL;
5118 if (dict != NULL) {
5119 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
5120 xmlFree((xmlChar *) cur->name);
5121 cur->name = xmlDictLookup(dict, name, -1);
5122 } else {
5123 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
5124 cur->name = xmlStrdup(name);
5125 }
Owen Taylor3473f882001-02-23 17:55:21 +00005126}
Daniel Veillard2156d432004-03-04 15:59:36 +00005127#endif
Daniel Veillardaa6de472008-08-25 14:53:31 +00005128
Daniel Veillard2156d432004-03-04 15:59:36 +00005129#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005130/**
5131 * xmlNodeSetBase:
5132 * @cur: the node being changed
5133 * @uri: the new base URI
5134 *
5135 * Set (or reset) the base URI of a node, i.e. the value of the
5136 * xml:base attribute.
5137 */
5138void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00005139xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00005140 xmlNsPtr ns;
Martin Trappelf3703102010-01-22 12:08:00 +01005141 xmlChar* fixed;
Daniel Veillardcfa0d812002-01-17 08:46:58 +00005142
Owen Taylor3473f882001-02-23 17:55:21 +00005143 if (cur == NULL) return;
5144 switch(cur->type) {
5145 case XML_TEXT_NODE:
5146 case XML_CDATA_SECTION_NODE:
5147 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005148 case XML_DOCUMENT_TYPE_NODE:
5149 case XML_DOCUMENT_FRAG_NODE:
5150 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005151 case XML_DTD_NODE:
5152 case XML_ELEMENT_DECL:
5153 case XML_ATTRIBUTE_DECL:
5154 case XML_ENTITY_DECL:
5155 case XML_PI_NODE:
5156 case XML_ENTITY_REF_NODE:
5157 case XML_ENTITY_NODE:
5158 case XML_NAMESPACE_DECL:
5159 case XML_XINCLUDE_START:
5160 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00005161 return;
5162 case XML_ELEMENT_NODE:
5163 case XML_ATTRIBUTE_NODE:
5164 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00005165 case XML_DOCUMENT_NODE:
5166#ifdef LIBXML_DOCB_ENABLED
5167 case XML_DOCB_DOCUMENT_NODE:
5168#endif
5169 case XML_HTML_DOCUMENT_NODE: {
5170 xmlDocPtr doc = (xmlDocPtr) cur;
5171
5172 if (doc->URL != NULL)
5173 xmlFree((xmlChar *) doc->URL);
5174 if (uri == NULL)
5175 doc->URL = NULL;
5176 else
Daniel Veillardb8efdda2006-10-10 12:37:14 +00005177 doc->URL = xmlPathToURI(uri);
Daniel Veillard4cbe4702002-05-05 06:57:27 +00005178 return;
5179 }
Owen Taylor3473f882001-02-23 17:55:21 +00005180 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00005181
Daniel Veillardcfa0d812002-01-17 08:46:58 +00005182 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
5183 if (ns == NULL)
5184 return;
Daniel Veillardb8efdda2006-10-10 12:37:14 +00005185 fixed = xmlPathToURI(uri);
5186 if (fixed != NULL) {
5187 xmlSetNsProp(cur, ns, BAD_CAST "base", fixed);
Martin Trappelf3703102010-01-22 12:08:00 +01005188 xmlFree(fixed);
Daniel Veillardb8efdda2006-10-10 12:37:14 +00005189 } else {
5190 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
5191 }
Owen Taylor3473f882001-02-23 17:55:21 +00005192}
Daniel Veillard652327a2003-09-29 18:02:38 +00005193#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005194
5195/**
Owen Taylor3473f882001-02-23 17:55:21 +00005196 * xmlNodeGetBase:
5197 * @doc: the document the node pertains to
5198 * @cur: the node being checked
5199 *
5200 * Searches for the BASE URL. The code should work on both XML
5201 * and HTML document even if base mechanisms are completely different.
5202 * It returns the base as defined in RFC 2396 sections
5203 * 5.1.1. Base URI within Document Content
5204 * and
5205 * 5.1.2. Base URI from the Encapsulating Entity
5206 * However it does not return the document base (5.1.3), use
Daniel Veillarde4d18492010-03-09 11:12:30 +01005207 * doc->URL in this case
Owen Taylor3473f882001-02-23 17:55:21 +00005208 *
5209 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005210 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005211 */
5212xmlChar *
5213xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00005214 xmlChar *oldbase = NULL;
5215 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00005216
Daniel Veillardaa6de472008-08-25 14:53:31 +00005217 if ((cur == NULL) && (doc == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00005218 return(NULL);
Daniel Veillard3e62adb2012-08-09 14:24:02 +08005219 if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL))
5220 return(NULL);
Daniel Veillardaa6de472008-08-25 14:53:31 +00005221 if (doc == NULL) doc = cur->doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005222 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
5223 cur = doc->children;
5224 while ((cur != NULL) && (cur->name != NULL)) {
5225 if (cur->type != XML_ELEMENT_NODE) {
5226 cur = cur->next;
5227 continue;
5228 }
5229 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
5230 cur = cur->children;
5231 continue;
5232 }
5233 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
5234 cur = cur->children;
5235 continue;
5236 }
5237 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
5238 return(xmlGetProp(cur, BAD_CAST "href"));
5239 }
5240 cur = cur->next;
5241 }
5242 return(NULL);
5243 }
5244 while (cur != NULL) {
5245 if (cur->type == XML_ENTITY_DECL) {
5246 xmlEntityPtr ent = (xmlEntityPtr) cur;
5247 return(xmlStrdup(ent->URI));
5248 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00005249 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00005250 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00005251 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00005252 if (oldbase != NULL) {
5253 newbase = xmlBuildURI(oldbase, base);
5254 if (newbase != NULL) {
5255 xmlFree(oldbase);
5256 xmlFree(base);
5257 oldbase = newbase;
5258 } else {
5259 xmlFree(oldbase);
5260 xmlFree(base);
5261 return(NULL);
5262 }
5263 } else {
5264 oldbase = base;
5265 }
5266 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
5267 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
5268 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
5269 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00005270 }
5271 }
Owen Taylor3473f882001-02-23 17:55:21 +00005272 cur = cur->parent;
5273 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00005274 if ((doc != NULL) && (doc->URL != NULL)) {
5275 if (oldbase == NULL)
5276 return(xmlStrdup(doc->URL));
5277 newbase = xmlBuildURI(oldbase, doc->URL);
5278 xmlFree(oldbase);
5279 return(newbase);
5280 }
5281 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00005282}
Daniel Veillardaa6de472008-08-25 14:53:31 +00005283
Owen Taylor3473f882001-02-23 17:55:21 +00005284/**
Daniel Veillard78697292003-10-19 20:44:43 +00005285 * xmlNodeBufGetContent:
5286 * @buffer: a buffer
5287 * @cur: the node being read
5288 *
5289 * Read the value of a node @cur, this can be either the text carried
5290 * directly by this node if it's a TEXT node or the aggregate string
5291 * of the values carried by this node child's (TEXT and ENTITY_REF).
5292 * Entity references are substituted.
5293 * Fills up the buffer @buffer with this value
Daniel Veillardaa6de472008-08-25 14:53:31 +00005294 *
Daniel Veillard78697292003-10-19 20:44:43 +00005295 * Returns 0 in case of success and -1 in case of error.
5296 */
5297int
5298xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
5299{
Daniel Veillarddddeede2012-07-16 14:44:26 +08005300 xmlBufPtr buf;
5301 int ret;
5302
Daniel Veillard78697292003-10-19 20:44:43 +00005303 if ((cur == NULL) || (buffer == NULL)) return(-1);
Daniel Veillarddddeede2012-07-16 14:44:26 +08005304 buf = xmlBufFromBuffer(buffer);
5305 ret = xmlBufGetNodeContent(buf, cur);
5306 buffer = xmlBufBackToBuffer(buf);
5307 if ((ret < 0) || (buffer == NULL))
5308 return(-1);
5309 return(0);
5310}
5311
5312/**
5313 * xmlBufGetNodeContent:
Daniel Veillard28cc42d2012-08-10 10:00:18 +08005314 * @buf: a buffer xmlBufPtr
Daniel Veillarddddeede2012-07-16 14:44:26 +08005315 * @cur: the node being read
5316 *
5317 * Read the value of a node @cur, this can be either the text carried
5318 * directly by this node if it's a TEXT node or the aggregate string
5319 * of the values carried by this node child's (TEXT and ENTITY_REF).
5320 * Entity references are substituted.
5321 * Fills up the buffer @buffer with this value
5322 *
5323 * Returns 0 in case of success and -1 in case of error.
5324 */
5325int
5326xmlBufGetNodeContent(xmlBufPtr buf, xmlNodePtr cur)
5327{
5328 if ((cur == NULL) || (buf == NULL)) return(-1);
Daniel Veillard78697292003-10-19 20:44:43 +00005329 switch (cur->type) {
5330 case XML_CDATA_SECTION_NODE:
5331 case XML_TEXT_NODE:
Daniel Veillarddddeede2012-07-16 14:44:26 +08005332 xmlBufCat(buf, cur->content);
Daniel Veillard78697292003-10-19 20:44:43 +00005333 break;
5334 case XML_DOCUMENT_FRAG_NODE:
5335 case XML_ELEMENT_NODE:{
5336 xmlNodePtr tmp = cur;
5337
5338 while (tmp != NULL) {
5339 switch (tmp->type) {
5340 case XML_CDATA_SECTION_NODE:
5341 case XML_TEXT_NODE:
5342 if (tmp->content != NULL)
Daniel Veillarddddeede2012-07-16 14:44:26 +08005343 xmlBufCat(buf, tmp->content);
Daniel Veillard78697292003-10-19 20:44:43 +00005344 break;
5345 case XML_ENTITY_REF_NODE:
Daniel Veillarddddeede2012-07-16 14:44:26 +08005346 xmlBufGetNodeContent(buf, tmp);
Rob Richards77b92ff2005-12-20 15:55:14 +00005347 break;
Daniel Veillard78697292003-10-19 20:44:43 +00005348 default:
5349 break;
5350 }
5351 /*
5352 * Skip to next node
5353 */
5354 if (tmp->children != NULL) {
5355 if (tmp->children->type != XML_ENTITY_DECL) {
5356 tmp = tmp->children;
5357 continue;
5358 }
5359 }
5360 if (tmp == cur)
5361 break;
5362
5363 if (tmp->next != NULL) {
5364 tmp = tmp->next;
5365 continue;
5366 }
5367
5368 do {
5369 tmp = tmp->parent;
5370 if (tmp == NULL)
5371 break;
5372 if (tmp == cur) {
5373 tmp = NULL;
5374 break;
5375 }
5376 if (tmp->next != NULL) {
5377 tmp = tmp->next;
5378 break;
5379 }
5380 } while (tmp != NULL);
5381 }
5382 break;
5383 }
5384 case XML_ATTRIBUTE_NODE:{
5385 xmlAttrPtr attr = (xmlAttrPtr) cur;
5386 xmlNodePtr tmp = attr->children;
5387
5388 while (tmp != NULL) {
5389 if (tmp->type == XML_TEXT_NODE)
Daniel Veillarddddeede2012-07-16 14:44:26 +08005390 xmlBufCat(buf, tmp->content);
Daniel Veillard78697292003-10-19 20:44:43 +00005391 else
Daniel Veillarddddeede2012-07-16 14:44:26 +08005392 xmlBufGetNodeContent(buf, tmp);
Daniel Veillard78697292003-10-19 20:44:43 +00005393 tmp = tmp->next;
5394 }
5395 break;
5396 }
5397 case XML_COMMENT_NODE:
5398 case XML_PI_NODE:
Daniel Veillarddddeede2012-07-16 14:44:26 +08005399 xmlBufCat(buf, cur->content);
Daniel Veillard78697292003-10-19 20:44:43 +00005400 break;
5401 case XML_ENTITY_REF_NODE:{
5402 xmlEntityPtr ent;
5403 xmlNodePtr tmp;
5404
5405 /* lookup entity declaration */
5406 ent = xmlGetDocEntity(cur->doc, cur->name);
5407 if (ent == NULL)
5408 return(-1);
5409
5410 /* an entity content can be any "well balanced chunk",
5411 * i.e. the result of the content [43] production:
5412 * http://www.w3.org/TR/REC-xml#NT-content
5413 * -> we iterate through child nodes and recursive call
5414 * xmlNodeGetContent() which handles all possible node types */
5415 tmp = ent->children;
5416 while (tmp) {
Daniel Veillarddddeede2012-07-16 14:44:26 +08005417 xmlBufGetNodeContent(buf, tmp);
Daniel Veillard78697292003-10-19 20:44:43 +00005418 tmp = tmp->next;
5419 }
5420 break;
5421 }
5422 case XML_ENTITY_NODE:
5423 case XML_DOCUMENT_TYPE_NODE:
5424 case XML_NOTATION_NODE:
5425 case XML_DTD_NODE:
5426 case XML_XINCLUDE_START:
5427 case XML_XINCLUDE_END:
5428 break;
5429 case XML_DOCUMENT_NODE:
5430#ifdef LIBXML_DOCB_ENABLED
5431 case XML_DOCB_DOCUMENT_NODE:
5432#endif
5433 case XML_HTML_DOCUMENT_NODE:
5434 cur = cur->children;
5435 while (cur!= NULL) {
5436 if ((cur->type == XML_ELEMENT_NODE) ||
5437 (cur->type == XML_TEXT_NODE) ||
5438 (cur->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillarddddeede2012-07-16 14:44:26 +08005439 xmlBufGetNodeContent(buf, cur);
Daniel Veillard78697292003-10-19 20:44:43 +00005440 }
5441 cur = cur->next;
5442 }
5443 break;
5444 case XML_NAMESPACE_DECL:
Daniel Veillarddddeede2012-07-16 14:44:26 +08005445 xmlBufCat(buf, ((xmlNsPtr) cur)->href);
Daniel Veillard78697292003-10-19 20:44:43 +00005446 break;
5447 case XML_ELEMENT_DECL:
5448 case XML_ATTRIBUTE_DECL:
5449 case XML_ENTITY_DECL:
5450 break;
5451 }
5452 return(0);
5453}
Daniel Veillarddddeede2012-07-16 14:44:26 +08005454
Daniel Veillard78697292003-10-19 20:44:43 +00005455/**
Owen Taylor3473f882001-02-23 17:55:21 +00005456 * xmlNodeGetContent:
5457 * @cur: the node being read
5458 *
5459 * Read the value of a node, this can be either the text carried
5460 * directly by this node if it's a TEXT node or the aggregate string
5461 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00005462 * Entity references are substituted.
5463 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005464 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005465 */
5466xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00005467xmlNodeGetContent(xmlNodePtr cur)
5468{
5469 if (cur == NULL)
5470 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005471 switch (cur->type) {
5472 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005473 case XML_ELEMENT_NODE:{
Daniel Veillardc15df7d2012-08-07 15:15:04 +08005474 xmlBufPtr buf;
Daniel Veillard7646b182002-04-20 06:41:40 +00005475 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00005476
Daniel Veillardc15df7d2012-08-07 15:15:04 +08005477 buf = xmlBufCreateSize(64);
5478 if (buf == NULL)
Daniel Veillard7646b182002-04-20 06:41:40 +00005479 return (NULL);
Daniel Veillardc15df7d2012-08-07 15:15:04 +08005480 xmlBufGetNodeContent(buf, cur);
5481 ret = xmlBufDetach(buf);
5482 xmlBufFree(buf);
Daniel Veillard7646b182002-04-20 06:41:40 +00005483 return (ret);
5484 }
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00005485 case XML_ATTRIBUTE_NODE:
5486 return(xmlGetPropNodeValueInternal((xmlAttrPtr) cur));
Owen Taylor3473f882001-02-23 17:55:21 +00005487 case XML_COMMENT_NODE:
5488 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005489 if (cur->content != NULL)
5490 return (xmlStrdup(cur->content));
5491 return (NULL);
5492 case XML_ENTITY_REF_NODE:{
5493 xmlEntityPtr ent;
Daniel Veillardc15df7d2012-08-07 15:15:04 +08005494 xmlBufPtr buf;
Daniel Veillard7646b182002-04-20 06:41:40 +00005495 xmlChar *ret;
5496
5497 /* lookup entity declaration */
5498 ent = xmlGetDocEntity(cur->doc, cur->name);
5499 if (ent == NULL)
5500 return (NULL);
5501
Daniel Veillardc15df7d2012-08-07 15:15:04 +08005502 buf = xmlBufCreate();
5503 if (buf == NULL)
Daniel Veillard7646b182002-04-20 06:41:40 +00005504 return (NULL);
5505
Daniel Veillardc15df7d2012-08-07 15:15:04 +08005506 xmlBufGetNodeContent(buf, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005507
Daniel Veillardc15df7d2012-08-07 15:15:04 +08005508 ret = xmlBufDetach(buf);
5509 xmlBufFree(buf);
Daniel Veillard7646b182002-04-20 06:41:40 +00005510 return (ret);
5511 }
Owen Taylor3473f882001-02-23 17:55:21 +00005512 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005513 case XML_DOCUMENT_TYPE_NODE:
5514 case XML_NOTATION_NODE:
5515 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005516 case XML_XINCLUDE_START:
5517 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00005518 return (NULL);
5519 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005520#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005521 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005522#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005523 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc15df7d2012-08-07 15:15:04 +08005524 xmlBufPtr buf;
Daniel Veillardc4696922003-10-19 21:47:14 +00005525 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005526
Daniel Veillardc15df7d2012-08-07 15:15:04 +08005527 buf = xmlBufCreate();
5528 if (buf == NULL)
Daniel Veillardc4696922003-10-19 21:47:14 +00005529 return (NULL);
5530
Daniel Veillardc15df7d2012-08-07 15:15:04 +08005531 xmlBufGetNodeContent(buf, (xmlNodePtr) cur);
Daniel Veillardc4696922003-10-19 21:47:14 +00005532
Daniel Veillardc15df7d2012-08-07 15:15:04 +08005533 ret = xmlBufDetach(buf);
5534 xmlBufFree(buf);
Daniel Veillardc4696922003-10-19 21:47:14 +00005535 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005536 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005537 case XML_NAMESPACE_DECL: {
5538 xmlChar *tmp;
5539
5540 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5541 return (tmp);
5542 }
Owen Taylor3473f882001-02-23 17:55:21 +00005543 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005544 /* TODO !!! */
5545 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005546 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005547 /* TODO !!! */
5548 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005549 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005550 /* TODO !!! */
5551 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005552 case XML_CDATA_SECTION_NODE:
5553 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005554 if (cur->content != NULL)
5555 return (xmlStrdup(cur->content));
5556 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005557 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005558 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005559}
Daniel Veillard652327a2003-09-29 18:02:38 +00005560
Owen Taylor3473f882001-02-23 17:55:21 +00005561/**
5562 * xmlNodeSetContent:
5563 * @cur: the node being modified
5564 * @content: the new value of the content
5565 *
5566 * Replace the content of a node.
Daniel Veillard0e05f4c2006-11-01 15:33:04 +00005567 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
5568 * references, but XML special chars need to be escaped first by using
5569 * xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars().
Owen Taylor3473f882001-02-23 17:55:21 +00005570 */
5571void
5572xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5573 if (cur == NULL) {
5574#ifdef DEBUG_TREE
5575 xmlGenericError(xmlGenericErrorContext,
5576 "xmlNodeSetContent : node == NULL\n");
5577#endif
5578 return;
5579 }
5580 switch (cur->type) {
5581 case XML_DOCUMENT_FRAG_NODE:
5582 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005583 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005584 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5585 cur->children = xmlStringGetNodeList(cur->doc, content);
5586 UPDATE_LAST_CHILD_AND_PARENT(cur)
5587 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005588 case XML_TEXT_NODE:
5589 case XML_CDATA_SECTION_NODE:
5590 case XML_ENTITY_REF_NODE:
5591 case XML_ENTITY_NODE:
5592 case XML_PI_NODE:
5593 case XML_COMMENT_NODE:
Daniel Veillard8874b942005-08-25 13:19:21 +00005594 if ((cur->content != NULL) &&
5595 (cur->content != (xmlChar *) &(cur->properties))) {
William M. Brack7762bb12004-01-04 14:49:01 +00005596 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
Daniel Veillardc587bce2005-05-10 15:28:08 +00005597 (xmlDictOwns(cur->doc->dict, cur->content))))
William M. Brack7762bb12004-01-04 14:49:01 +00005598 xmlFree(cur->content);
Daniel Veillardaa6de472008-08-25 14:53:31 +00005599 }
Owen Taylor3473f882001-02-23 17:55:21 +00005600 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5601 cur->last = cur->children = NULL;
5602 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005603 cur->content = xmlStrdup(content);
Daniel Veillardaa6de472008-08-25 14:53:31 +00005604 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005605 cur->content = NULL;
Daniel Veillard8874b942005-08-25 13:19:21 +00005606 cur->properties = NULL;
5607 cur->nsDef = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00005608 break;
5609 case XML_DOCUMENT_NODE:
5610 case XML_HTML_DOCUMENT_NODE:
5611 case XML_DOCUMENT_TYPE_NODE:
5612 case XML_XINCLUDE_START:
5613 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005614#ifdef LIBXML_DOCB_ENABLED
5615 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005616#endif
5617 break;
5618 case XML_NOTATION_NODE:
5619 break;
5620 case XML_DTD_NODE:
5621 break;
5622 case XML_NAMESPACE_DECL:
5623 break;
5624 case XML_ELEMENT_DECL:
5625 /* TODO !!! */
5626 break;
5627 case XML_ATTRIBUTE_DECL:
5628 /* TODO !!! */
5629 break;
5630 case XML_ENTITY_DECL:
5631 /* TODO !!! */
5632 break;
5633 }
5634}
5635
Daniel Veillard652327a2003-09-29 18:02:38 +00005636#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005637/**
5638 * xmlNodeSetContentLen:
5639 * @cur: the node being modified
5640 * @content: the new value of the content
5641 * @len: the size of @content
5642 *
5643 * Replace the content of a node.
Daniel Veillard0e05f4c2006-11-01 15:33:04 +00005644 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
5645 * references, but XML special chars need to be escaped first by using
5646 * xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars().
Owen Taylor3473f882001-02-23 17:55:21 +00005647 */
5648void
5649xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5650 if (cur == NULL) {
5651#ifdef DEBUG_TREE
5652 xmlGenericError(xmlGenericErrorContext,
5653 "xmlNodeSetContentLen : node == NULL\n");
5654#endif
5655 return;
5656 }
5657 switch (cur->type) {
5658 case XML_DOCUMENT_FRAG_NODE:
5659 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005660 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005661 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5662 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5663 UPDATE_LAST_CHILD_AND_PARENT(cur)
5664 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005665 case XML_TEXT_NODE:
5666 case XML_CDATA_SECTION_NODE:
5667 case XML_ENTITY_REF_NODE:
5668 case XML_ENTITY_NODE:
5669 case XML_PI_NODE:
5670 case XML_COMMENT_NODE:
5671 case XML_NOTATION_NODE:
Daniel Veillard8874b942005-08-25 13:19:21 +00005672 if ((cur->content != NULL) &&
5673 (cur->content != (xmlChar *) &(cur->properties))) {
5674 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5675 (xmlDictOwns(cur->doc->dict, cur->content))))
5676 xmlFree(cur->content);
Daniel Veillardaa6de472008-08-25 14:53:31 +00005677 }
Owen Taylor3473f882001-02-23 17:55:21 +00005678 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5679 cur->children = cur->last = NULL;
5680 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005681 cur->content = xmlStrndup(content, len);
Daniel Veillardaa6de472008-08-25 14:53:31 +00005682 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005683 cur->content = NULL;
Daniel Veillard8874b942005-08-25 13:19:21 +00005684 cur->properties = NULL;
5685 cur->nsDef = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00005686 break;
5687 case XML_DOCUMENT_NODE:
5688 case XML_DTD_NODE:
5689 case XML_HTML_DOCUMENT_NODE:
5690 case XML_DOCUMENT_TYPE_NODE:
5691 case XML_NAMESPACE_DECL:
5692 case XML_XINCLUDE_START:
5693 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005694#ifdef LIBXML_DOCB_ENABLED
5695 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005696#endif
5697 break;
5698 case XML_ELEMENT_DECL:
5699 /* TODO !!! */
5700 break;
5701 case XML_ATTRIBUTE_DECL:
5702 /* TODO !!! */
5703 break;
5704 case XML_ENTITY_DECL:
5705 /* TODO !!! */
5706 break;
5707 }
5708}
Daniel Veillard652327a2003-09-29 18:02:38 +00005709#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005710
5711/**
5712 * xmlNodeAddContentLen:
5713 * @cur: the node being modified
5714 * @content: extra content
5715 * @len: the size of @content
Daniel Veillardaa6de472008-08-25 14:53:31 +00005716 *
Owen Taylor3473f882001-02-23 17:55:21 +00005717 * Append the extra substring to the node content.
Daniel Veillard0e05f4c2006-11-01 15:33:04 +00005718 * NOTE: In contrast to xmlNodeSetContentLen(), @content is supposed to be
5719 * raw text, so unescaped XML special chars are allowed, entity
5720 * references are not supported.
Owen Taylor3473f882001-02-23 17:55:21 +00005721 */
5722void
5723xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5724 if (cur == NULL) {
5725#ifdef DEBUG_TREE
5726 xmlGenericError(xmlGenericErrorContext,
5727 "xmlNodeAddContentLen : node == NULL\n");
5728#endif
5729 return;
5730 }
5731 if (len <= 0) return;
5732 switch (cur->type) {
5733 case XML_DOCUMENT_FRAG_NODE:
5734 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005735 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005736
Daniel Veillard7db37732001-07-12 01:20:08 +00005737 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005738 newNode = xmlNewTextLen(content, len);
5739 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005740 tmp = xmlAddChild(cur, newNode);
5741 if (tmp != newNode)
5742 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005743 if ((last != NULL) && (last->next == newNode)) {
5744 xmlTextMerge(last, newNode);
5745 }
5746 }
5747 break;
5748 }
5749 case XML_ATTRIBUTE_NODE:
5750 break;
5751 case XML_TEXT_NODE:
5752 case XML_CDATA_SECTION_NODE:
5753 case XML_ENTITY_REF_NODE:
5754 case XML_ENTITY_NODE:
5755 case XML_PI_NODE:
5756 case XML_COMMENT_NODE:
5757 case XML_NOTATION_NODE:
5758 if (content != NULL) {
Daniel Veillard8874b942005-08-25 13:19:21 +00005759 if ((cur->content == (xmlChar *) &(cur->properties)) ||
5760 ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5761 xmlDictOwns(cur->doc->dict, cur->content))) {
5762 cur->content = xmlStrncatNew(cur->content, content, len);
5763 cur->properties = NULL;
5764 cur->nsDef = NULL;
William M. Brack7762bb12004-01-04 14:49:01 +00005765 break;
5766 }
Owen Taylor3473f882001-02-23 17:55:21 +00005767 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005768 }
5769 case XML_DOCUMENT_NODE:
5770 case XML_DTD_NODE:
5771 case XML_HTML_DOCUMENT_NODE:
5772 case XML_DOCUMENT_TYPE_NODE:
5773 case XML_NAMESPACE_DECL:
5774 case XML_XINCLUDE_START:
5775 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005776#ifdef LIBXML_DOCB_ENABLED
5777 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005778#endif
5779 break;
5780 case XML_ELEMENT_DECL:
5781 case XML_ATTRIBUTE_DECL:
5782 case XML_ENTITY_DECL:
5783 break;
5784 }
5785}
5786
5787/**
5788 * xmlNodeAddContent:
5789 * @cur: the node being modified
5790 * @content: extra content
Daniel Veillardaa6de472008-08-25 14:53:31 +00005791 *
Owen Taylor3473f882001-02-23 17:55:21 +00005792 * Append the extra substring to the node content.
Daniel Veillard0e05f4c2006-11-01 15:33:04 +00005793 * NOTE: In contrast to xmlNodeSetContent(), @content is supposed to be
5794 * raw text, so unescaped XML special chars are allowed, entity
5795 * references are not supported.
Owen Taylor3473f882001-02-23 17:55:21 +00005796 */
5797void
5798xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5799 int len;
5800
5801 if (cur == NULL) {
5802#ifdef DEBUG_TREE
5803 xmlGenericError(xmlGenericErrorContext,
5804 "xmlNodeAddContent : node == NULL\n");
5805#endif
5806 return;
5807 }
5808 if (content == NULL) return;
5809 len = xmlStrlen(content);
5810 xmlNodeAddContentLen(cur, content, len);
5811}
5812
5813/**
5814 * xmlTextMerge:
5815 * @first: the first text node
5816 * @second: the second text node being merged
Daniel Veillardaa6de472008-08-25 14:53:31 +00005817 *
Owen Taylor3473f882001-02-23 17:55:21 +00005818 * Merge two text nodes into one
5819 * Returns the first text node augmented
5820 */
5821xmlNodePtr
5822xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5823 if (first == NULL) return(second);
5824 if (second == NULL) return(first);
5825 if (first->type != XML_TEXT_NODE) return(first);
5826 if (second->type != XML_TEXT_NODE) return(first);
5827 if (second->name != first->name)
5828 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005829 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005830 xmlUnlinkNode(second);
5831 xmlFreeNode(second);
5832 return(first);
5833}
5834
Daniel Veillardf1a27c62006-10-13 22:33:03 +00005835#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005836/**
5837 * xmlGetNsList:
5838 * @doc: the document
5839 * @node: the current node
5840 *
5841 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005842 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005843 * that need to be freed by the caller or NULL if no
5844 * namespace if defined
5845 */
5846xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005847xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5848{
Owen Taylor3473f882001-02-23 17:55:21 +00005849 xmlNsPtr cur;
5850 xmlNsPtr *ret = NULL;
5851 int nbns = 0;
5852 int maxns = 10;
5853 int i;
5854
Daniel Veillard3e62adb2012-08-09 14:24:02 +08005855 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
5856 return(NULL);
5857
Owen Taylor3473f882001-02-23 17:55:21 +00005858 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005859 if (node->type == XML_ELEMENT_NODE) {
5860 cur = node->nsDef;
5861 while (cur != NULL) {
5862 if (ret == NULL) {
5863 ret =
5864 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5865 sizeof(xmlNsPtr));
5866 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005867 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005868 return (NULL);
5869 }
5870 ret[nbns] = NULL;
5871 }
5872 for (i = 0; i < nbns; i++) {
5873 if ((cur->prefix == ret[i]->prefix) ||
5874 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5875 break;
5876 }
5877 if (i >= nbns) {
5878 if (nbns >= maxns) {
5879 maxns *= 2;
5880 ret = (xmlNsPtr *) xmlRealloc(ret,
5881 (maxns +
5882 1) *
5883 sizeof(xmlNsPtr));
5884 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005885 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005886 return (NULL);
5887 }
5888 }
5889 ret[nbns++] = cur;
5890 ret[nbns] = NULL;
5891 }
Owen Taylor3473f882001-02-23 17:55:21 +00005892
Daniel Veillard77044732001-06-29 21:31:07 +00005893 cur = cur->next;
5894 }
5895 }
5896 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005897 }
Daniel Veillard77044732001-06-29 21:31:07 +00005898 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005899}
Daniel Veillard652327a2003-09-29 18:02:38 +00005900#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005901
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00005902/*
5903* xmlTreeEnsureXMLDecl:
5904* @doc: the doc
Daniel Veillardaa6de472008-08-25 14:53:31 +00005905*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00005906* Ensures that there is an XML namespace declaration on the doc.
Daniel Veillardaa6de472008-08-25 14:53:31 +00005907*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00005908* Returns the XML ns-struct or NULL on API and internal errors.
5909*/
5910static xmlNsPtr
5911xmlTreeEnsureXMLDecl(xmlDocPtr doc)
5912{
5913 if (doc == NULL)
5914 return (NULL);
5915 if (doc->oldNs != NULL)
5916 return (doc->oldNs);
5917 {
5918 xmlNsPtr ns;
5919 ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5920 if (ns == NULL) {
5921 xmlTreeErrMemory(
5922 "allocating the XML namespace");
5923 return (NULL);
5924 }
5925 memset(ns, 0, sizeof(xmlNs));
5926 ns->type = XML_LOCAL_NAMESPACE;
Daniel Veillardaa6de472008-08-25 14:53:31 +00005927 ns->href = xmlStrdup(XML_XML_NAMESPACE);
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00005928 ns->prefix = xmlStrdup((const xmlChar *)"xml");
5929 doc->oldNs = ns;
5930 return (ns);
5931 }
5932}
5933
Owen Taylor3473f882001-02-23 17:55:21 +00005934/**
5935 * xmlSearchNs:
5936 * @doc: the document
5937 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005938 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005939 *
5940 * Search a Ns registered under a given name space for a document.
5941 * recurse on the parents until it finds the defined namespace
5942 * or return NULL otherwise.
5943 * @nameSpace can be NULL, this is a search for the default namespace.
5944 * We don't allow to cross entities boundaries. If you don't declare
5945 * the namespace within those you will be in troubles !!! A warning
5946 * is generated to cover this case.
5947 *
5948 * Returns the namespace pointer or NULL.
5949 */
5950xmlNsPtr
5951xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00005952
Owen Taylor3473f882001-02-23 17:55:21 +00005953 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005954 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005955
Daniel Veillard3e62adb2012-08-09 14:24:02 +08005956 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005957 if ((nameSpace != NULL) &&
5958 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005959 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5960 /*
5961 * The XML-1.0 namespace is normally held on the root
5962 * element. In this case exceptionally create it on the
5963 * node element.
5964 */
5965 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5966 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005967 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005968 return(NULL);
5969 }
5970 memset(cur, 0, sizeof(xmlNs));
5971 cur->type = XML_LOCAL_NAMESPACE;
Daniel Veillardaa6de472008-08-25 14:53:31 +00005972 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5973 cur->prefix = xmlStrdup((const xmlChar *)"xml");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005974 cur->next = node->nsDef;
5975 node->nsDef = cur;
5976 return(cur);
5977 }
Daniel Veillard11ce4002006-03-10 00:36:23 +00005978 if (doc == NULL) {
5979 doc = node->doc;
5980 if (doc == NULL)
5981 return(NULL);
5982 }
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00005983 /*
5984 * Return the XML namespace declaration held by the doc.
5985 */
5986 if (doc->oldNs == NULL)
5987 return(xmlTreeEnsureXMLDecl(doc));
5988 else
5989 return(doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005990 }
5991 while (node != NULL) {
5992 if ((node->type == XML_ENTITY_REF_NODE) ||
5993 (node->type == XML_ENTITY_NODE) ||
5994 (node->type == XML_ENTITY_DECL))
5995 return(NULL);
5996 if (node->type == XML_ELEMENT_NODE) {
5997 cur = node->nsDef;
5998 while (cur != NULL) {
5999 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
6000 (cur->href != NULL))
6001 return(cur);
6002 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
6003 (cur->href != NULL) &&
6004 (xmlStrEqual(cur->prefix, nameSpace)))
6005 return(cur);
6006 cur = cur->next;
6007 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00006008 if (orig != node) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00006009 cur = node->ns;
6010 if (cur != NULL) {
6011 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
6012 (cur->href != NULL))
6013 return(cur);
6014 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
6015 (cur->href != NULL) &&
6016 (xmlStrEqual(cur->prefix, nameSpace)))
6017 return(cur);
6018 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00006019 }
Owen Taylor3473f882001-02-23 17:55:21 +00006020 }
6021 node = node->parent;
6022 }
6023 return(NULL);
6024}
6025
6026/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006027 * xmlNsInScope:
6028 * @doc: the document
6029 * @node: the current node
6030 * @ancestor: the ancestor carrying the namespace
6031 * @prefix: the namespace prefix
6032 *
6033 * Verify that the given namespace held on @ancestor is still in scope
6034 * on node.
Daniel Veillardaa6de472008-08-25 14:53:31 +00006035 *
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006036 * Returns 1 if true, 0 if false and -1 in case of error.
6037 */
6038static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00006039xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
6040 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006041{
6042 xmlNsPtr tst;
6043
6044 while ((node != NULL) && (node != ancestor)) {
6045 if ((node->type == XML_ENTITY_REF_NODE) ||
6046 (node->type == XML_ENTITY_NODE) ||
6047 (node->type == XML_ENTITY_DECL))
6048 return (-1);
6049 if (node->type == XML_ELEMENT_NODE) {
6050 tst = node->nsDef;
6051 while (tst != NULL) {
6052 if ((tst->prefix == NULL)
6053 && (prefix == NULL))
6054 return (0);
6055 if ((tst->prefix != NULL)
6056 && (prefix != NULL)
6057 && (xmlStrEqual(tst->prefix, prefix)))
6058 return (0);
6059 tst = tst->next;
6060 }
6061 }
6062 node = node->parent;
6063 }
6064 if (node != ancestor)
6065 return (-1);
6066 return (1);
6067}
Daniel Veillardaa6de472008-08-25 14:53:31 +00006068
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006069/**
Owen Taylor3473f882001-02-23 17:55:21 +00006070 * xmlSearchNsByHref:
6071 * @doc: the document
6072 * @node: the current node
6073 * @href: the namespace value
6074 *
6075 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
6076 * the defined namespace or return NULL otherwise.
6077 * Returns the namespace pointer or NULL.
6078 */
6079xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006080xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
6081{
Owen Taylor3473f882001-02-23 17:55:21 +00006082 xmlNsPtr cur;
6083 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00006084 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00006085
Daniel Veillard3e62adb2012-08-09 14:24:02 +08006086 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) || (href == NULL))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006087 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006088 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006089 /*
6090 * Only the document can hold the XML spec namespace.
6091 */
6092 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
6093 /*
6094 * The XML-1.0 namespace is normally held on the root
6095 * element. In this case exceptionally create it on the
6096 * node element.
6097 */
6098 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
6099 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006100 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006101 return (NULL);
6102 }
6103 memset(cur, 0, sizeof(xmlNs));
6104 cur->type = XML_LOCAL_NAMESPACE;
6105 cur->href = xmlStrdup(XML_XML_NAMESPACE);
6106 cur->prefix = xmlStrdup((const xmlChar *) "xml");
6107 cur->next = node->nsDef;
6108 node->nsDef = cur;
6109 return (cur);
6110 }
Daniel Veillard11ce4002006-03-10 00:36:23 +00006111 if (doc == NULL) {
6112 doc = node->doc;
6113 if (doc == NULL)
6114 return(NULL);
6115 }
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00006116 /*
6117 * Return the XML namespace declaration held by the doc.
6118 */
6119 if (doc->oldNs == NULL)
6120 return(xmlTreeEnsureXMLDecl(doc));
6121 else
Daniel Veillardaa6de472008-08-25 14:53:31 +00006122 return(doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00006123 }
Daniel Veillard62040be2004-05-17 03:17:26 +00006124 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00006125 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006126 if ((node->type == XML_ENTITY_REF_NODE) ||
6127 (node->type == XML_ENTITY_NODE) ||
6128 (node->type == XML_ENTITY_DECL))
6129 return (NULL);
6130 if (node->type == XML_ELEMENT_NODE) {
6131 cur = node->nsDef;
6132 while (cur != NULL) {
6133 if ((cur->href != NULL) && (href != NULL) &&
6134 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00006135 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00006136 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006137 return (cur);
6138 }
6139 cur = cur->next;
6140 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00006141 if (orig != node) {
6142 cur = node->ns;
6143 if (cur != NULL) {
6144 if ((cur->href != NULL) && (href != NULL) &&
6145 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00006146 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00006147 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00006148 return (cur);
6149 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006150 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00006151 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006152 }
6153 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00006154 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00006155 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006156}
6157
6158/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006159 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00006160 * @doc: the document
6161 * @tree: a node expected to hold the new namespace
6162 * @ns: the original namespace
6163 *
6164 * This function tries to locate a namespace definition in a tree
6165 * ancestors, or create a new namespace definition node similar to
6166 * @ns trying to reuse the same prefix. However if the given prefix is
6167 * null (default namespace) or reused within the subtree defined by
6168 * @tree or on one of its ancestors then a new prefix is generated.
6169 * Returns the (new) namespace definition or NULL in case of error
6170 */
Daniel Veillard8ed10722009-08-20 19:17:36 +02006171static xmlNsPtr
Owen Taylor3473f882001-02-23 17:55:21 +00006172xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
6173 xmlNsPtr def;
6174 xmlChar prefix[50];
6175 int counter = 1;
6176
Daniel Veillard3e62adb2012-08-09 14:24:02 +08006177 if ((tree == NULL) || (tree->type != XML_ELEMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006178#ifdef DEBUG_TREE
6179 xmlGenericError(xmlGenericErrorContext,
6180 "xmlNewReconciliedNs : tree == NULL\n");
6181#endif
6182 return(NULL);
6183 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00006184 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006185#ifdef DEBUG_TREE
6186 xmlGenericError(xmlGenericErrorContext,
6187 "xmlNewReconciliedNs : ns == NULL\n");
6188#endif
6189 return(NULL);
6190 }
6191 /*
6192 * Search an existing namespace definition inherited.
6193 */
6194 def = xmlSearchNsByHref(doc, tree, ns->href);
6195 if (def != NULL)
6196 return(def);
6197
6198 /*
6199 * Find a close prefix which is not already in use.
6200 * Let's strip namespace prefixes longer than 20 chars !
6201 */
Daniel Veillardf742d342002-03-07 00:05:35 +00006202 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00006203 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00006204 else
William M. Brack13dfa872004-09-18 04:52:08 +00006205 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00006206
Owen Taylor3473f882001-02-23 17:55:21 +00006207 def = xmlSearchNs(doc, tree, prefix);
6208 while (def != NULL) {
6209 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00006210 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00006211 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00006212 else
William M. Brack13dfa872004-09-18 04:52:08 +00006213 snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
Daniel Veillardaa6de472008-08-25 14:53:31 +00006214 (char *)ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00006215 def = xmlSearchNs(doc, tree, prefix);
6216 }
6217
6218 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00006219 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00006220 */
6221 def = xmlNewNs(tree, ns->href, prefix);
6222 return(def);
6223}
6224
Daniel Veillard652327a2003-09-29 18:02:38 +00006225#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00006226/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006227 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00006228 * @doc: the document
6229 * @tree: a node defining the subtree to reconciliate
6230 *
6231 * This function checks that all the namespaces declared within the given
6232 * tree are properly declared. This is needed for example after Copy or Cut
6233 * and then paste operations. The subtree may still hold pointers to
6234 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00006235 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00006236 * the new environment. If not possible the new namespaces are redeclared
6237 * on @tree at the top of the given subtree.
6238 * Returns the number of namespace declarations created or -1 in case of error.
6239 */
6240int
6241xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
6242 xmlNsPtr *oldNs = NULL;
6243 xmlNsPtr *newNs = NULL;
6244 int sizeCache = 0;
6245 int nbCache = 0;
6246
6247 xmlNsPtr n;
6248 xmlNodePtr node = tree;
6249 xmlAttrPtr attr;
6250 int ret = 0, i;
6251
Daniel Veillardce244ad2004-11-05 10:03:46 +00006252 if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1);
6253 if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1);
6254 if (node->doc != doc) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006255 while (node != NULL) {
6256 /*
6257 * Reconciliate the node namespace
6258 */
6259 if (node->ns != NULL) {
6260 /*
6261 * initialize the cache if needed
6262 */
6263 if (sizeCache == 0) {
6264 sizeCache = 10;
6265 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
6266 sizeof(xmlNsPtr));
6267 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006268 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00006269 return(-1);
6270 }
6271 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
6272 sizeof(xmlNsPtr));
6273 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006274 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00006275 xmlFree(oldNs);
6276 return(-1);
6277 }
6278 }
6279 for (i = 0;i < nbCache;i++) {
6280 if (oldNs[i] == node->ns) {
6281 node->ns = newNs[i];
6282 break;
6283 }
6284 }
6285 if (i == nbCache) {
6286 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00006287 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00006288 */
6289 n = xmlNewReconciliedNs(doc, tree, node->ns);
6290 if (n != NULL) { /* :-( what if else ??? */
6291 /*
6292 * check if we need to grow the cache buffers.
6293 */
6294 if (sizeCache <= nbCache) {
6295 sizeCache *= 2;
6296 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
6297 sizeof(xmlNsPtr));
6298 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006299 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00006300 xmlFree(newNs);
6301 return(-1);
6302 }
6303 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
6304 sizeof(xmlNsPtr));
6305 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006306 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00006307 xmlFree(oldNs);
6308 return(-1);
6309 }
6310 }
6311 newNs[nbCache] = n;
6312 oldNs[nbCache++] = node->ns;
6313 node->ns = n;
6314 }
6315 }
6316 }
6317 /*
6318 * now check for namespace hold by attributes on the node.
6319 */
Daniel Veillardb5f11972006-10-14 08:46:40 +00006320 if (node->type == XML_ELEMENT_NODE) {
6321 attr = node->properties;
6322 while (attr != NULL) {
6323 if (attr->ns != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006324 /*
Daniel Veillardb5f11972006-10-14 08:46:40 +00006325 * initialize the cache if needed
Owen Taylor3473f882001-02-23 17:55:21 +00006326 */
Daniel Veillardb5f11972006-10-14 08:46:40 +00006327 if (sizeCache == 0) {
6328 sizeCache = 10;
6329 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
6330 sizeof(xmlNsPtr));
6331 if (oldNs == NULL) {
6332 xmlTreeErrMemory("fixing namespaces");
6333 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006334 }
Daniel Veillardb5f11972006-10-14 08:46:40 +00006335 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
6336 sizeof(xmlNsPtr));
6337 if (newNs == NULL) {
6338 xmlTreeErrMemory("fixing namespaces");
6339 xmlFree(oldNs);
6340 return(-1);
6341 }
6342 }
6343 for (i = 0;i < nbCache;i++) {
6344 if (oldNs[i] == attr->ns) {
6345 attr->ns = newNs[i];
6346 break;
6347 }
6348 }
6349 if (i == nbCache) {
6350 /*
6351 * OK we need to recreate a new namespace definition
6352 */
6353 n = xmlNewReconciliedNs(doc, tree, attr->ns);
6354 if (n != NULL) { /* :-( what if else ??? */
6355 /*
6356 * check if we need to grow the cache buffers.
6357 */
6358 if (sizeCache <= nbCache) {
6359 sizeCache *= 2;
6360 oldNs = (xmlNsPtr *) xmlRealloc(oldNs,
6361 sizeCache * sizeof(xmlNsPtr));
6362 if (oldNs == NULL) {
6363 xmlTreeErrMemory("fixing namespaces");
6364 xmlFree(newNs);
6365 return(-1);
6366 }
6367 newNs = (xmlNsPtr *) xmlRealloc(newNs,
6368 sizeCache * sizeof(xmlNsPtr));
6369 if (newNs == NULL) {
6370 xmlTreeErrMemory("fixing namespaces");
6371 xmlFree(oldNs);
6372 return(-1);
6373 }
6374 }
6375 newNs[nbCache] = n;
6376 oldNs[nbCache++] = attr->ns;
6377 attr->ns = n;
6378 }
Owen Taylor3473f882001-02-23 17:55:21 +00006379 }
6380 }
Daniel Veillardb5f11972006-10-14 08:46:40 +00006381 attr = attr->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006382 }
Owen Taylor3473f882001-02-23 17:55:21 +00006383 }
6384
6385 /*
6386 * Browse the full subtree, deep first
6387 */
Daniel Veillardb5f11972006-10-14 08:46:40 +00006388 if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006389 /* deep first */
6390 node = node->children;
6391 } else if ((node != tree) && (node->next != NULL)) {
6392 /* then siblings */
6393 node = node->next;
6394 } else if (node != tree) {
6395 /* go up to parents->next if needed */
6396 while (node != tree) {
6397 if (node->parent != NULL)
6398 node = node->parent;
6399 if ((node != tree) && (node->next != NULL)) {
6400 node = node->next;
6401 break;
6402 }
6403 if (node->parent == NULL) {
6404 node = NULL;
6405 break;
6406 }
6407 }
6408 /* exit condition */
Daniel Veillardaa6de472008-08-25 14:53:31 +00006409 if (node == tree)
Owen Taylor3473f882001-02-23 17:55:21 +00006410 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00006411 } else
6412 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006413 }
Daniel Veillardf742d342002-03-07 00:05:35 +00006414 if (oldNs != NULL)
6415 xmlFree(oldNs);
6416 if (newNs != NULL)
6417 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00006418 return(ret);
6419}
Daniel Veillard652327a2003-09-29 18:02:38 +00006420#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00006421
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006422static xmlAttrPtr
6423xmlGetPropNodeInternal(xmlNodePtr node, const xmlChar *name,
6424 const xmlChar *nsName, int useDTD)
6425{
6426 xmlAttrPtr prop;
6427
6428 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6429 return(NULL);
6430
6431 if (node->properties != NULL) {
6432 prop = node->properties;
6433 if (nsName == NULL) {
6434 /*
6435 * We want the attr to be in no namespace.
6436 */
6437 do {
6438 if ((prop->ns == NULL) && xmlStrEqual(prop->name, name)) {
6439 return(prop);
6440 }
6441 prop = prop->next;
6442 } while (prop != NULL);
6443 } else {
6444 /*
6445 * We want the attr to be in the specified namespace.
6446 */
6447 do {
6448 if ((prop->ns != NULL) && xmlStrEqual(prop->name, name) &&
6449 ((prop->ns->href == nsName) ||
6450 xmlStrEqual(prop->ns->href, nsName)))
6451 {
6452 return(prop);
6453 }
6454 prop = prop->next;
6455 } while (prop != NULL);
6456 }
6457 }
6458
6459#ifdef LIBXML_TREE_ENABLED
6460 if (! useDTD)
6461 return(NULL);
6462 /*
6463 * Check if there is a default/fixed attribute declaration in
6464 * the internal or external subset.
Daniel Veillardaa6de472008-08-25 14:53:31 +00006465 */
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006466 if ((node->doc != NULL) && (node->doc->intSubset != NULL)) {
6467 xmlDocPtr doc = node->doc;
6468 xmlAttributePtr attrDecl = NULL;
6469 xmlChar *elemQName, *tmpstr = NULL;
6470
6471 /*
Daniel Veillardaa6de472008-08-25 14:53:31 +00006472 * We need the QName of the element for the DTD-lookup.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006473 */
6474 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
6475 tmpstr = xmlStrdup(node->ns->prefix);
6476 tmpstr = xmlStrcat(tmpstr, BAD_CAST ":");
6477 tmpstr = xmlStrcat(tmpstr, node->name);
6478 if (tmpstr == NULL)
6479 return(NULL);
6480 elemQName = tmpstr;
6481 } else
6482 elemQName = (xmlChar *) node->name;
6483 if (nsName == NULL) {
6484 /*
6485 * The common and nice case: Attr in no namespace.
6486 */
6487 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset,
6488 elemQName, name, NULL);
6489 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
6490 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset,
6491 elemQName, name, NULL);
6492 }
6493 } else {
6494 xmlNsPtr *nsList, *cur;
6495
6496 /*
6497 * The ugly case: Search using the prefixes of in-scope
6498 * ns-decls corresponding to @nsName.
6499 */
6500 nsList = xmlGetNsList(node->doc, node);
6501 if (nsList == NULL) {
6502 if (tmpstr != NULL)
6503 xmlFree(tmpstr);
6504 return(NULL);
6505 }
6506 cur = nsList;
6507 while (*cur != NULL) {
6508 if (xmlStrEqual((*cur)->href, nsName)) {
6509 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elemQName,
6510 name, (*cur)->prefix);
6511 if (attrDecl)
6512 break;
6513 if (doc->extSubset != NULL) {
6514 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elemQName,
6515 name, (*cur)->prefix);
6516 if (attrDecl)
6517 break;
6518 }
6519 }
6520 cur++;
6521 }
6522 xmlFree(nsList);
Daniel Veillardaa6de472008-08-25 14:53:31 +00006523 }
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006524 if (tmpstr != NULL)
6525 xmlFree(tmpstr);
6526 /*
6527 * Only default/fixed attrs are relevant.
6528 */
6529 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6530 return((xmlAttrPtr) attrDecl);
6531 }
6532#endif /* LIBXML_TREE_ENABLED */
6533 return(NULL);
6534}
6535
6536static xmlChar*
6537xmlGetPropNodeValueInternal(xmlAttrPtr prop)
6538{
6539 if (prop == NULL)
6540 return(NULL);
6541 if (prop->type == XML_ATTRIBUTE_NODE) {
6542 /*
6543 * Note that we return at least the empty string.
6544 * TODO: Do we really always want that?
6545 */
6546 if (prop->children != NULL) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00006547 if ((prop->children->next == NULL) &&
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006548 ((prop->children->type == XML_TEXT_NODE) ||
6549 (prop->children->type == XML_CDATA_SECTION_NODE)))
6550 {
6551 /*
6552 * Optimization for the common case: only 1 text node.
6553 */
6554 return(xmlStrdup(prop->children->content));
6555 } else {
6556 xmlChar *ret;
6557
6558 ret = xmlNodeListGetString(prop->doc, prop->children, 1);
6559 if (ret != NULL)
6560 return(ret);
6561 }
6562 }
6563 return(xmlStrdup((xmlChar *)""));
6564 } else if (prop->type == XML_ATTRIBUTE_DECL) {
6565 return(xmlStrdup(((xmlAttributePtr)prop)->defaultValue));
6566 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00006567 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006568}
6569
Owen Taylor3473f882001-02-23 17:55:21 +00006570/**
6571 * xmlHasProp:
6572 * @node: the node
6573 * @name: the attribute name
6574 *
6575 * Search an attribute associated to a node
6576 * This function also looks in DTD attribute declaration for #FIXED or
6577 * default declaration values unless DTD use has been turned off.
6578 *
Daniel Veillardaa6de472008-08-25 14:53:31 +00006579 * Returns the attribute or the attribute declaration or NULL if
Owen Taylor3473f882001-02-23 17:55:21 +00006580 * neither was found.
6581 */
6582xmlAttrPtr
6583xmlHasProp(xmlNodePtr node, const xmlChar *name) {
6584 xmlAttrPtr prop;
6585 xmlDocPtr doc;
6586
Daniel Veillard8874b942005-08-25 13:19:21 +00006587 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6588 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006589 /*
6590 * Check on the properties attached to the node
6591 */
6592 prop = node->properties;
6593 while (prop != NULL) {
6594 if (xmlStrEqual(prop->name, name)) {
6595 return(prop);
6596 }
6597 prop = prop->next;
6598 }
6599 if (!xmlCheckDTD) return(NULL);
6600
6601 /*
6602 * Check if there is a default declaration in the internal
6603 * or external subsets
6604 */
6605 doc = node->doc;
6606 if (doc != NULL) {
6607 xmlAttributePtr attrDecl;
6608 if (doc->intSubset != NULL) {
6609 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6610 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6611 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006612 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6613 /* return attribute declaration only if a default value is given
6614 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006615 return((xmlAttrPtr) attrDecl);
6616 }
6617 }
6618 return(NULL);
6619}
6620
6621/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00006622 * xmlHasNsProp:
6623 * @node: the node
6624 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006625 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00006626 *
6627 * Search for an attribute associated to a node
6628 * This attribute has to be anchored in the namespace specified.
6629 * This does the entity substitution.
6630 * This function looks in DTD attribute declaration for #FIXED or
6631 * default declaration values unless DTD use has been turned off.
William M. Brack2c228442004-10-03 04:10:00 +00006632 * Note that a namespace of NULL indicates to use the default namespace.
Daniel Veillarde95e2392001-06-06 10:46:28 +00006633 *
6634 * Returns the attribute or the attribute declaration or NULL
6635 * if neither was found.
6636 */
6637xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00006638xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00006639
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006640 return(xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD));
Daniel Veillarde95e2392001-06-06 10:46:28 +00006641}
6642
6643/**
Owen Taylor3473f882001-02-23 17:55:21 +00006644 * xmlGetProp:
6645 * @node: the node
6646 * @name: the attribute name
6647 *
6648 * Search and get the value of an attribute associated to a node
6649 * This does the entity substitution.
6650 * This function looks in DTD attribute declaration for #FIXED or
6651 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00006652 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00006653 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6654 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00006655 *
6656 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006657 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006658 */
6659xmlChar *
6660xmlGetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00006661 xmlAttrPtr prop;
Owen Taylor3473f882001-02-23 17:55:21 +00006662
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006663 prop = xmlHasProp(node, name);
6664 if (prop == NULL)
6665 return(NULL);
Daniel Veillardaa6de472008-08-25 14:53:31 +00006666 return(xmlGetPropNodeValueInternal(prop));
Owen Taylor3473f882001-02-23 17:55:21 +00006667}
6668
6669/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006670 * xmlGetNoNsProp:
6671 * @node: the node
6672 * @name: the attribute name
6673 *
6674 * Search and get the value of an attribute associated to a node
6675 * This does the entity substitution.
6676 * This function looks in DTD attribute declaration for #FIXED or
6677 * default declaration values unless DTD use has been turned off.
6678 * This function is similar to xmlGetProp except it will accept only
6679 * an attribute in no namespace.
6680 *
6681 * Returns the attribute value or NULL if not found.
6682 * It's up to the caller to free the memory with xmlFree().
6683 */
6684xmlChar *
6685xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6686 xmlAttrPtr prop;
Daniel Veillardaa6de472008-08-25 14:53:31 +00006687
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006688 prop = xmlGetPropNodeInternal(node, name, NULL, xmlCheckDTD);
6689 if (prop == NULL)
Daniel Veillard8874b942005-08-25 13:19:21 +00006690 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006691 return(xmlGetPropNodeValueInternal(prop));
Daniel Veillard71531f32003-02-05 13:19:53 +00006692}
6693
6694/**
Owen Taylor3473f882001-02-23 17:55:21 +00006695 * xmlGetNsProp:
6696 * @node: the node
6697 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006698 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006699 *
6700 * Search and get the value of an attribute associated to a node
6701 * This attribute has to be anchored in the namespace specified.
6702 * This does the entity substitution.
6703 * This function looks in DTD attribute declaration for #FIXED or
6704 * default declaration values unless DTD use has been turned off.
6705 *
6706 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006707 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006708 */
6709xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006710xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006711 xmlAttrPtr prop;
Owen Taylor3473f882001-02-23 17:55:21 +00006712
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006713 prop = xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD);
6714 if (prop == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006715 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006716 return(xmlGetPropNodeValueInternal(prop));
Owen Taylor3473f882001-02-23 17:55:21 +00006717}
6718
Daniel Veillard2156d432004-03-04 15:59:36 +00006719#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6720/**
6721 * xmlUnsetProp:
6722 * @node: the node
6723 * @name: the attribute name
6724 *
6725 * Remove an attribute carried by a node.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006726 * This handles only attributes in no namespace.
Daniel Veillard2156d432004-03-04 15:59:36 +00006727 * Returns 0 if successful, -1 if not found
6728 */
6729int
6730xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Kasimier T. Buchcik65c2f1d2005-10-17 12:39:58 +00006731 xmlAttrPtr prop;
Daniel Veillard2156d432004-03-04 15:59:36 +00006732
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006733 prop = xmlGetPropNodeInternal(node, name, NULL, 0);
6734 if (prop == NULL)
Daniel Veillard2156d432004-03-04 15:59:36 +00006735 return(-1);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006736 xmlUnlinkNode((xmlNodePtr) prop);
6737 xmlFreeProp(prop);
6738 return(0);
Daniel Veillard2156d432004-03-04 15:59:36 +00006739}
6740
6741/**
6742 * xmlUnsetNsProp:
6743 * @node: the node
6744 * @ns: the namespace definition
6745 * @name: the attribute name
6746 *
6747 * Remove an attribute carried by a node.
6748 * Returns 0 if successful, -1 if not found
6749 */
6750int
6751xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
Kasimier T. Buchcik65c2f1d2005-10-17 12:39:58 +00006752 xmlAttrPtr prop;
Daniel Veillardaa6de472008-08-25 14:53:31 +00006753
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006754 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
6755 if (prop == NULL)
Daniel Veillard2156d432004-03-04 15:59:36 +00006756 return(-1);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006757 xmlUnlinkNode((xmlNodePtr) prop);
6758 xmlFreeProp(prop);
6759 return(0);
Daniel Veillard2156d432004-03-04 15:59:36 +00006760}
6761#endif
6762
6763#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006764/**
6765 * xmlSetProp:
6766 * @node: the node
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006767 * @name: the attribute name (a QName)
Owen Taylor3473f882001-02-23 17:55:21 +00006768 * @value: the attribute value
6769 *
6770 * Set (or reset) an attribute carried by a node.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006771 * If @name has a prefix, then the corresponding
6772 * namespace-binding will be used, if in scope; it is an
6773 * error it there's no such ns-binding for the prefix in
6774 * scope.
Owen Taylor3473f882001-02-23 17:55:21 +00006775 * Returns the attribute pointer.
Daniel Veillardaa6de472008-08-25 14:53:31 +00006776 *
Owen Taylor3473f882001-02-23 17:55:21 +00006777 */
6778xmlAttrPtr
6779xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006780 int len;
6781 const xmlChar *nqname;
Owen Taylor3473f882001-02-23 17:55:21 +00006782
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006783 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006784 return(NULL);
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006785
6786 /*
6787 * handle QNames
6788 */
6789 nqname = xmlSplitQName3(name, &len);
6790 if (nqname != NULL) {
6791 xmlNsPtr ns;
6792 xmlChar *prefix = xmlStrndup(name, len);
6793 ns = xmlSearchNs(node->doc, node, prefix);
6794 if (prefix != NULL)
6795 xmlFree(prefix);
6796 if (ns != NULL)
6797 return(xmlSetNsProp(node, ns, nqname, value));
6798 }
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006799 return(xmlSetNsProp(node, NULL, name, value));
Owen Taylor3473f882001-02-23 17:55:21 +00006800}
6801
6802/**
6803 * xmlSetNsProp:
6804 * @node: the node
6805 * @ns: the namespace definition
6806 * @name: the attribute name
6807 * @value: the attribute value
6808 *
6809 * Set (or reset) an attribute carried by a node.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006810 * The ns structure must be in scope, this is not checked
Owen Taylor3473f882001-02-23 17:55:21 +00006811 *
6812 * Returns the attribute pointer.
6813 */
6814xmlAttrPtr
6815xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006816 const xmlChar *value)
6817{
Owen Taylor3473f882001-02-23 17:55:21 +00006818 xmlAttrPtr prop;
Daniel Veillardaa6de472008-08-25 14:53:31 +00006819
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006820 if (ns && (ns->href == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006821 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006822 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
6823 if (prop != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006824 /*
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006825 * Modify the attribute's value.
6826 */
6827 if (prop->atype == XML_ATTRIBUTE_ID) {
6828 xmlRemoveID(node->doc, prop);
6829 prop->atype = XML_ATTRIBUTE_ID;
6830 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00006831 if (prop->children != NULL)
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006832 xmlFreeNodeList(prop->children);
6833 prop->children = NULL;
6834 prop->last = NULL;
6835 prop->ns = ns;
6836 if (value != NULL) {
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006837 xmlNodePtr tmp;
Daniel Veillardaa6de472008-08-25 14:53:31 +00006838
Daniel Veillard6f8611f2008-02-15 08:33:21 +00006839 if(!xmlCheckUTF8(value)) {
6840 xmlTreeErr(XML_TREE_NOT_UTF8, (xmlNodePtr) node->doc,
6841 NULL);
6842 if (node->doc != NULL)
6843 node->doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
6844 }
6845 prop->children = xmlNewDocText(node->doc, value);
Owen Taylor3473f882001-02-23 17:55:21 +00006846 prop->last = NULL;
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006847 tmp = prop->children;
6848 while (tmp != NULL) {
6849 tmp->parent = (xmlNodePtr) prop;
6850 if (tmp->next == NULL)
6851 prop->last = tmp;
6852 tmp = tmp->next;
6853 }
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006854 }
6855 if (prop->atype == XML_ATTRIBUTE_ID)
6856 xmlAddID(NULL, node->doc, value, prop);
6857 return(prop);
Owen Taylor3473f882001-02-23 17:55:21 +00006858 }
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006859 /*
6860 * No equal attr found; create a new one.
6861 */
6862 return(xmlNewPropInternal(node, ns, name, value, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006863}
6864
Daniel Veillard652327a2003-09-29 18:02:38 +00006865#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006866
6867/**
Owen Taylor3473f882001-02-23 17:55:21 +00006868 * xmlNodeIsText:
6869 * @node: the node
Daniel Veillardaa6de472008-08-25 14:53:31 +00006870 *
Owen Taylor3473f882001-02-23 17:55:21 +00006871 * Is this node a Text node ?
6872 * Returns 1 yes, 0 no
6873 */
6874int
6875xmlNodeIsText(xmlNodePtr node) {
6876 if (node == NULL) return(0);
6877
6878 if (node->type == XML_TEXT_NODE) return(1);
6879 return(0);
6880}
6881
6882/**
6883 * xmlIsBlankNode:
6884 * @node: the node
Daniel Veillardaa6de472008-08-25 14:53:31 +00006885 *
Owen Taylor3473f882001-02-23 17:55:21 +00006886 * Checks whether this node is an empty or whitespace only
6887 * (and possibly ignorable) text-node.
6888 *
6889 * Returns 1 yes, 0 no
6890 */
6891int
6892xmlIsBlankNode(xmlNodePtr node) {
6893 const xmlChar *cur;
6894 if (node == NULL) return(0);
6895
Daniel Veillard7db37732001-07-12 01:20:08 +00006896 if ((node->type != XML_TEXT_NODE) &&
6897 (node->type != XML_CDATA_SECTION_NODE))
6898 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006899 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006900 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006901 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006902 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006903 cur++;
6904 }
6905
6906 return(1);
6907}
6908
6909/**
6910 * xmlTextConcat:
6911 * @node: the node
6912 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006913 * @len: @content length
Daniel Veillardaa6de472008-08-25 14:53:31 +00006914 *
Owen Taylor3473f882001-02-23 17:55:21 +00006915 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006916 *
6917 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006918 */
6919
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006920int
Owen Taylor3473f882001-02-23 17:55:21 +00006921xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006922 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006923
6924 if ((node->type != XML_TEXT_NODE) &&
Rob Richardsa02f1992006-09-16 14:04:26 +00006925 (node->type != XML_CDATA_SECTION_NODE) &&
6926 (node->type != XML_COMMENT_NODE) &&
6927 (node->type != XML_PI_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006928#ifdef DEBUG_TREE
6929 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006930 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006931#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006932 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006933 }
William M. Brack7762bb12004-01-04 14:49:01 +00006934 /* need to check if content is currently in the dictionary */
Daniel Veillard8874b942005-08-25 13:19:21 +00006935 if ((node->content == (xmlChar *) &(node->properties)) ||
6936 ((node->doc != NULL) && (node->doc->dict != NULL) &&
6937 xmlDictOwns(node->doc->dict, node->content))) {
William M. Brack7762bb12004-01-04 14:49:01 +00006938 node->content = xmlStrncatNew(node->content, content, len);
6939 } else {
6940 node->content = xmlStrncat(node->content, content, len);
6941 }
Daniel Veillard8874b942005-08-25 13:19:21 +00006942 node->properties = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006943 if (node->content == NULL)
6944 return(-1);
6945 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006946}
6947
6948/************************************************************************
6949 * *
6950 * Output : to a FILE or in memory *
6951 * *
6952 ************************************************************************/
6953
Owen Taylor3473f882001-02-23 17:55:21 +00006954/**
6955 * xmlBufferCreate:
6956 *
6957 * routine to create an XML buffer.
6958 * returns the new structure.
6959 */
6960xmlBufferPtr
6961xmlBufferCreate(void) {
6962 xmlBufferPtr ret;
6963
6964 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6965 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006966 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006967 return(NULL);
6968 }
6969 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006970 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006971 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006972 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006973 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006974 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006975 xmlFree(ret);
6976 return(NULL);
6977 }
6978 ret->content[0] = 0;
Daniel Veillarde83e93e2008-08-30 12:52:26 +00006979 ret->contentIO = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00006980 return(ret);
6981}
6982
6983/**
6984 * xmlBufferCreateSize:
6985 * @size: initial size of buffer
6986 *
6987 * routine to create an XML buffer.
6988 * returns the new structure.
6989 */
6990xmlBufferPtr
6991xmlBufferCreateSize(size_t size) {
6992 xmlBufferPtr ret;
6993
6994 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6995 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006996 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006997 return(NULL);
6998 }
6999 ret->use = 0;
7000 ret->alloc = xmlBufferAllocScheme;
7001 ret->size = (size ? size+2 : 0); /* +1 for ending null */
7002 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007003 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00007004 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007005 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00007006 xmlFree(ret);
7007 return(NULL);
7008 }
7009 ret->content[0] = 0;
7010 } else
7011 ret->content = NULL;
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007012 ret->contentIO = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00007013 return(ret);
7014}
7015
7016/**
Daniel Veillard79ee2842012-05-15 10:25:31 +08007017 * xmlBufferDetach:
Conrad Irwin7d553f82012-05-10 20:17:25 -07007018 * @buf: the buffer
7019 *
Daniel Veillard79ee2842012-05-15 10:25:31 +08007020 * Remove the string contained in a buffer and gie it back to the
Daniel Veillard94431ec2012-05-15 10:45:05 +08007021 * caller. The buffer is reset to an empty content.
7022 * This doesn't work with immutable buffers as they can't be reset.
Conrad Irwin7d553f82012-05-10 20:17:25 -07007023 *
Daniel Veillard79ee2842012-05-15 10:25:31 +08007024 * Returns the previous string contained by the buffer.
Conrad Irwin7d553f82012-05-10 20:17:25 -07007025 */
7026xmlChar *
7027xmlBufferDetach(xmlBufferPtr buf) {
7028 xmlChar *ret;
7029
Daniel Veillard94431ec2012-05-15 10:45:05 +08007030 if (buf == NULL)
7031 return(NULL);
7032 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
7033 return(NULL);
Conrad Irwin7d553f82012-05-10 20:17:25 -07007034
7035 ret = buf->content;
7036 buf->content = NULL;
7037 buf->size = 0;
7038 buf->use = 0;
7039
7040 return ret;
7041}
7042
7043
7044/**
Daniel Veillard53350552003-09-18 13:35:51 +00007045 * xmlBufferCreateStatic:
7046 * @mem: the memory area
7047 * @size: the size in byte
7048 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00007049 * routine to create an XML buffer from an immutable memory area.
7050 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00007051 * present until the end of the buffer lifetime.
7052 *
7053 * returns the new structure.
7054 */
7055xmlBufferPtr
7056xmlBufferCreateStatic(void *mem, size_t size) {
7057 xmlBufferPtr ret;
7058
7059 if ((mem == NULL) || (size == 0))
7060 return(NULL);
7061
7062 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
7063 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007064 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00007065 return(NULL);
7066 }
7067 ret->use = size;
7068 ret->size = size;
7069 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
7070 ret->content = (xmlChar *) mem;
7071 return(ret);
7072}
7073
7074/**
Owen Taylor3473f882001-02-23 17:55:21 +00007075 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007076 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00007077 * @scheme: allocation scheme to use
7078 *
7079 * Sets the allocation scheme for this buffer
7080 */
7081void
Daniel Veillardaa6de472008-08-25 14:53:31 +00007082xmlBufferSetAllocationScheme(xmlBufferPtr buf,
Owen Taylor3473f882001-02-23 17:55:21 +00007083 xmlBufferAllocationScheme scheme) {
7084 if (buf == NULL) {
7085#ifdef DEBUG_BUFFER
7086 xmlGenericError(xmlGenericErrorContext,
7087 "xmlBufferSetAllocationScheme: buf == NULL\n");
7088#endif
7089 return;
7090 }
Daniel Veillardda3fee42008-09-01 13:08:57 +00007091 if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) ||
7092 (buf->alloc == XML_BUFFER_ALLOC_IO)) return;
7093 if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
7094 (scheme == XML_BUFFER_ALLOC_EXACT) ||
Conrad Irwin7d0d2a52012-05-14 14:18:58 +08007095 (scheme == XML_BUFFER_ALLOC_HYBRID) ||
Daniel Veillardda3fee42008-09-01 13:08:57 +00007096 (scheme == XML_BUFFER_ALLOC_IMMUTABLE))
7097 buf->alloc = scheme;
Owen Taylor3473f882001-02-23 17:55:21 +00007098}
7099
7100/**
7101 * xmlBufferFree:
7102 * @buf: the buffer to free
7103 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00007104 * Frees an XML buffer. It frees both the content and the structure which
7105 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00007106 */
7107void
7108xmlBufferFree(xmlBufferPtr buf) {
7109 if (buf == NULL) {
7110#ifdef DEBUG_BUFFER
7111 xmlGenericError(xmlGenericErrorContext,
7112 "xmlBufferFree: buf == NULL\n");
7113#endif
7114 return;
7115 }
Daniel Veillard53350552003-09-18 13:35:51 +00007116
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007117 if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
7118 (buf->contentIO != NULL)) {
7119 xmlFree(buf->contentIO);
7120 } else if ((buf->content != NULL) &&
Daniel Veillard53350552003-09-18 13:35:51 +00007121 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007122 xmlFree(buf->content);
7123 }
Owen Taylor3473f882001-02-23 17:55:21 +00007124 xmlFree(buf);
7125}
7126
7127/**
7128 * xmlBufferEmpty:
7129 * @buf: the buffer
7130 *
7131 * empty a buffer.
7132 */
7133void
7134xmlBufferEmpty(xmlBufferPtr buf) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007135 if (buf == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007136 if (buf->content == NULL) return;
7137 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00007138 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00007139 buf->content = BAD_CAST "";
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007140 } else if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
7141 (buf->contentIO != NULL)) {
7142 size_t start_buf = buf->content - buf->contentIO;
7143
7144 buf->size += start_buf;
7145 buf->content = buf->contentIO;
7146 buf->content[0] = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00007147 } else {
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007148 buf->content[0] = 0;
7149 }
Owen Taylor3473f882001-02-23 17:55:21 +00007150}
7151
7152/**
7153 * xmlBufferShrink:
7154 * @buf: the buffer to dump
7155 * @len: the number of xmlChar to remove
7156 *
7157 * Remove the beginning of an XML buffer.
7158 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007159 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007160 */
7161int
7162xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
Daniel Veillard3d97e662004-11-04 10:49:00 +00007163 if (buf == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007164 if (len == 0) return(0);
7165 if (len > buf->use) return(-1);
7166
7167 buf->use -= len;
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007168 if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) ||
7169 ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL))) {
7170 /*
7171 * we just move the content pointer, but also make sure
7172 * the perceived buffer size has shrinked accordingly
7173 */
Daniel Veillard53350552003-09-18 13:35:51 +00007174 buf->content += len;
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007175 buf->size -= len;
7176
7177 /*
7178 * sometimes though it maybe be better to really shrink
7179 * on IO buffers
7180 */
7181 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7182 size_t start_buf = buf->content - buf->contentIO;
7183 if (start_buf >= buf->size) {
7184 memmove(buf->contentIO, &buf->content[0], buf->use);
7185 buf->content = buf->contentIO;
7186 buf->content[buf->use] = 0;
7187 buf->size += start_buf;
7188 }
7189 }
Daniel Veillard53350552003-09-18 13:35:51 +00007190 } else {
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007191 memmove(buf->content, &buf->content[len], buf->use);
Daniel Veillard53350552003-09-18 13:35:51 +00007192 buf->content[buf->use] = 0;
7193 }
Owen Taylor3473f882001-02-23 17:55:21 +00007194 return(len);
7195}
7196
7197/**
7198 * xmlBufferGrow:
7199 * @buf: the buffer
7200 * @len: the minimum free size to allocate
7201 *
7202 * Grow the available space of an XML buffer.
7203 *
7204 * Returns the new available space or -1 in case of error
7205 */
7206int
7207xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
7208 int size;
7209 xmlChar *newbuf;
7210
Daniel Veillard3d97e662004-11-04 10:49:00 +00007211 if (buf == NULL) return(-1);
7212
Daniel Veillard53350552003-09-18 13:35:51 +00007213 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007214 if (len + buf->use < buf->size) return(0);
7215
Daniel Veillardee20cd72009-08-22 15:18:31 +02007216 /*
7217 * Windows has a BIG problem on realloc timing, so we try to double
7218 * the buffer size (if that's enough) (bug 146697)
7219 * Apparently BSD too, and it's probably best for linux too
7220 * On an embedded system this may be something to change
7221 */
7222#if 1
William M. Brack30fe43f2004-07-26 18:00:58 +00007223 if (buf->size > len)
7224 size = buf->size * 2;
7225 else
7226 size = buf->use + len + 100;
7227#else
Owen Taylor3473f882001-02-23 17:55:21 +00007228 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00007229#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007230
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007231 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7232 size_t start_buf = buf->content - buf->contentIO;
7233
7234 newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size);
7235 if (newbuf == NULL) {
7236 xmlTreeErrMemory("growing buffer");
7237 return(-1);
7238 }
7239 buf->contentIO = newbuf;
7240 buf->content = newbuf + start_buf;
7241 } else {
7242 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
7243 if (newbuf == NULL) {
7244 xmlTreeErrMemory("growing buffer");
7245 return(-1);
7246 }
7247 buf->content = newbuf;
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007248 }
Owen Taylor3473f882001-02-23 17:55:21 +00007249 buf->size = size;
7250 return(buf->size - buf->use);
7251}
7252
7253/**
7254 * xmlBufferDump:
7255 * @file: the file output
7256 * @buf: the buffer to dump
7257 *
7258 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00007259 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00007260 */
7261int
7262xmlBufferDump(FILE *file, xmlBufferPtr buf) {
7263 int ret;
7264
7265 if (buf == NULL) {
7266#ifdef DEBUG_BUFFER
7267 xmlGenericError(xmlGenericErrorContext,
7268 "xmlBufferDump: buf == NULL\n");
7269#endif
7270 return(0);
7271 }
7272 if (buf->content == NULL) {
7273#ifdef DEBUG_BUFFER
7274 xmlGenericError(xmlGenericErrorContext,
7275 "xmlBufferDump: buf->content == NULL\n");
7276#endif
7277 return(0);
7278 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00007279 if (file == NULL)
7280 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00007281 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
7282 return(ret);
7283}
7284
7285/**
7286 * xmlBufferContent:
7287 * @buf: the buffer
7288 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007289 * Function to extract the content of a buffer
7290 *
Owen Taylor3473f882001-02-23 17:55:21 +00007291 * Returns the internal content
7292 */
7293
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007294const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007295xmlBufferContent(const xmlBufferPtr buf)
7296{
7297 if(!buf)
7298 return NULL;
7299
7300 return buf->content;
7301}
7302
7303/**
7304 * xmlBufferLength:
Daniel Veillardaa6de472008-08-25 14:53:31 +00007305 * @buf: the buffer
Owen Taylor3473f882001-02-23 17:55:21 +00007306 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007307 * Function to get the length of a buffer
7308 *
Owen Taylor3473f882001-02-23 17:55:21 +00007309 * Returns the length of data in the internal content
7310 */
7311
7312int
7313xmlBufferLength(const xmlBufferPtr buf)
7314{
7315 if(!buf)
7316 return 0;
7317
7318 return buf->use;
7319}
7320
7321/**
7322 * xmlBufferResize:
7323 * @buf: the buffer to resize
7324 * @size: the desired size
7325 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007326 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00007327 *
7328 * Returns 0 in case of problems, 1 otherwise
7329 */
7330int
7331xmlBufferResize(xmlBufferPtr buf, unsigned int size)
7332{
7333 unsigned int newSize;
7334 xmlChar* rebuf = NULL;
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007335 size_t start_buf;
Owen Taylor3473f882001-02-23 17:55:21 +00007336
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007337 if (buf == NULL)
7338 return(0);
7339
Daniel Veillard53350552003-09-18 13:35:51 +00007340 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
7341
Owen Taylor3473f882001-02-23 17:55:21 +00007342 /* Don't resize if we don't have to */
7343 if (size < buf->size)
7344 return 1;
7345
7346 /* figure out new size */
7347 switch (buf->alloc){
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007348 case XML_BUFFER_ALLOC_IO:
7349 case XML_BUFFER_ALLOC_DOUBLEIT:
7350 /*take care of empty case*/
7351 newSize = (buf->size ? buf->size*2 : size + 10);
Daniel Veillard1dc9feb2008-11-17 15:59:21 +00007352 while (size > newSize) {
7353 if (newSize > UINT_MAX / 2) {
7354 xmlTreeErrMemory("growing buffer");
7355 return 0;
7356 }
7357 newSize *= 2;
7358 }
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007359 break;
7360 case XML_BUFFER_ALLOC_EXACT:
7361 newSize = size+10;
7362 break;
Conrad Irwin7d0d2a52012-05-14 14:18:58 +08007363 case XML_BUFFER_ALLOC_HYBRID:
7364 if (buf->use < BASE_BUFFER_SIZE)
7365 newSize = size;
7366 else {
7367 newSize = buf->size * 2;
7368 while (size > newSize) {
7369 if (newSize > UINT_MAX / 2) {
7370 xmlTreeErrMemory("growing buffer");
7371 return 0;
7372 }
7373 newSize *= 2;
7374 }
7375 }
7376 break;
7377
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007378 default:
7379 newSize = size+10;
7380 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007381 }
7382
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007383 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7384 start_buf = buf->content - buf->contentIO;
7385
7386 if (start_buf > newSize) {
7387 /* move data back to start */
7388 memmove(buf->contentIO, buf->content, buf->use);
7389 buf->content = buf->contentIO;
7390 buf->content[buf->use] = 0;
7391 buf->size += start_buf;
7392 } else {
7393 rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize);
7394 if (rebuf == NULL) {
7395 xmlTreeErrMemory("growing buffer");
7396 return 0;
7397 }
7398 buf->contentIO = rebuf;
7399 buf->content = rebuf + start_buf;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00007400 }
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007401 } else {
7402 if (buf->content == NULL) {
7403 rebuf = (xmlChar *) xmlMallocAtomic(newSize);
7404 } else if (buf->size - buf->use < 100) {
7405 rebuf = (xmlChar *) xmlRealloc(buf->content, newSize);
7406 } else {
7407 /*
7408 * if we are reallocating a buffer far from being full, it's
7409 * better to make a new allocation and copy only the used range
7410 * and free the old one.
7411 */
7412 rebuf = (xmlChar *) xmlMallocAtomic(newSize);
7413 if (rebuf != NULL) {
7414 memcpy(rebuf, buf->content, buf->use);
7415 xmlFree(buf->content);
7416 rebuf[buf->use] = 0;
7417 }
7418 }
7419 if (rebuf == NULL) {
7420 xmlTreeErrMemory("growing buffer");
7421 return 0;
7422 }
7423 buf->content = rebuf;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00007424 }
Owen Taylor3473f882001-02-23 17:55:21 +00007425 buf->size = newSize;
7426
7427 return 1;
7428}
7429
7430/**
7431 * xmlBufferAdd:
7432 * @buf: the buffer to dump
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 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007436 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00007437 * 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 +00007443xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
7444 unsigned int needSize;
7445
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007446 if ((str == NULL) || (buf == NULL)) {
William M. Bracka3215c72004-07-31 16:24:01 +00007447 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007448 }
William M. Bracka3215c72004-07-31 16:24:01 +00007449 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007450 if (len < -1) {
7451#ifdef DEBUG_BUFFER
7452 xmlGenericError(xmlGenericErrorContext,
7453 "xmlBufferAdd: len < 0\n");
7454#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007455 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007456 }
William M. Bracka3215c72004-07-31 16:24:01 +00007457 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007458
7459 if (len < 0)
7460 len = xmlStrlen(str);
7461
Daniel Veillardc9923322007-04-24 18:12:06 +00007462 if (len < 0) return -1;
7463 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007464
7465 needSize = buf->use + len + 2;
7466 if (needSize > buf->size){
7467 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007468 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007469 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007470 }
7471 }
7472
7473 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
7474 buf->use += len;
7475 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007476 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007477}
7478
7479/**
7480 * xmlBufferAddHead:
7481 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00007482 * @str: the #xmlChar string
7483 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00007484 *
7485 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00007486 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00007487 *
7488 * Returns 0 successful, a positive error code number otherwise
7489 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007490 */
William M. Bracka3215c72004-07-31 16:24:01 +00007491int
Owen Taylor3473f882001-02-23 17:55:21 +00007492xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
7493 unsigned int needSize;
7494
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007495 if (buf == NULL)
7496 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007497 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007498 if (str == NULL) {
7499#ifdef DEBUG_BUFFER
7500 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007501 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007502#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007503 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007504 }
7505 if (len < -1) {
7506#ifdef DEBUG_BUFFER
7507 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007508 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007509#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007510 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007511 }
William M. Bracka3215c72004-07-31 16:24:01 +00007512 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007513
7514 if (len < 0)
7515 len = xmlStrlen(str);
7516
William M. Bracka3215c72004-07-31 16:24:01 +00007517 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007518
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007519 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7520 size_t start_buf = buf->content - buf->contentIO;
7521
7522 if (start_buf > (unsigned int) len) {
7523 /*
7524 * We can add it in the space previously shrinked
7525 */
7526 buf->content -= len;
7527 memmove(&buf->content[0], str, len);
7528 buf->use += len;
7529 buf->size += len;
7530 return(0);
7531 }
7532 }
Owen Taylor3473f882001-02-23 17:55:21 +00007533 needSize = buf->use + len + 2;
7534 if (needSize > buf->size){
7535 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007536 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007537 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007538 }
7539 }
7540
Daniel Veillarde83e93e2008-08-30 12:52:26 +00007541 memmove(&buf->content[len], &buf->content[0], buf->use);
7542 memmove(&buf->content[0], str, len);
Owen Taylor3473f882001-02-23 17:55:21 +00007543 buf->use += len;
7544 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007545 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007546}
7547
7548/**
7549 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00007550 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00007551 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00007552 *
7553 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007554 *
7555 * Returns 0 successful, a positive error code number otherwise
7556 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007557 */
William M. Bracka3215c72004-07-31 16:24:01 +00007558int
Owen Taylor3473f882001-02-23 17:55:21 +00007559xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007560 if (buf == NULL)
7561 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007562 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
7563 if (str == NULL) return -1;
7564 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00007565}
7566
7567/**
7568 * xmlBufferCCat:
7569 * @buf: the buffer to dump
7570 * @str: the C char string
7571 *
7572 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007573 *
7574 * Returns 0 successful, a positive error code number otherwise
7575 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007576 */
William M. Bracka3215c72004-07-31 16:24:01 +00007577int
Owen Taylor3473f882001-02-23 17:55:21 +00007578xmlBufferCCat(xmlBufferPtr buf, const char *str) {
7579 const char *cur;
7580
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007581 if (buf == NULL)
7582 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007583 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007584 if (str == NULL) {
7585#ifdef DEBUG_BUFFER
7586 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007587 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007588#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007589 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007590 }
7591 for (cur = str;*cur != 0;cur++) {
7592 if (buf->use + 10 >= buf->size) {
7593 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007594 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007595 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007596 }
7597 }
7598 buf->content[buf->use++] = *cur;
7599 }
7600 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007601 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007602}
7603
7604/**
7605 * xmlBufferWriteCHAR:
7606 * @buf: the XML buffer
7607 * @string: the string to add
7608 *
7609 * routine which manages and grows an output buffer. This one adds
7610 * xmlChars at the end of the buffer.
7611 */
7612void
Daniel Veillard53350552003-09-18 13:35:51 +00007613xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007614 if (buf == NULL)
7615 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007616 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007617 xmlBufferCat(buf, string);
7618}
7619
7620/**
7621 * xmlBufferWriteChar:
7622 * @buf: the XML buffer output
7623 * @string: the string to add
7624 *
7625 * routine which manage and grows an output buffer. This one add
7626 * C chars at the end of the array.
7627 */
7628void
7629xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007630 if (buf == NULL)
7631 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007632 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007633 xmlBufferCCat(buf, string);
7634}
7635
7636
7637/**
7638 * xmlBufferWriteQuotedString:
7639 * @buf: the XML buffer output
7640 * @string: the string to add
7641 *
7642 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00007643 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00007644 * quote or double-quotes internally
7645 */
7646void
7647xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00007648 const xmlChar *cur, *base;
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007649 if (buf == NULL)
7650 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007651 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00007652 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00007653 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00007654#ifdef DEBUG_BUFFER
7655 xmlGenericError(xmlGenericErrorContext,
7656 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7657#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00007658 xmlBufferCCat(buf, "\"");
7659 base = cur = string;
7660 while(*cur != 0){
7661 if(*cur == '"'){
7662 if (base != cur)
7663 xmlBufferAdd(buf, base, cur - base);
7664 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7665 cur++;
7666 base = cur;
7667 }
7668 else {
7669 cur++;
7670 }
7671 }
7672 if (base != cur)
7673 xmlBufferAdd(buf, base, cur - base);
7674 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007675 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007676 else{
7677 xmlBufferCCat(buf, "\'");
7678 xmlBufferCat(buf, string);
7679 xmlBufferCCat(buf, "\'");
7680 }
Owen Taylor3473f882001-02-23 17:55:21 +00007681 } else {
7682 xmlBufferCCat(buf, "\"");
7683 xmlBufferCat(buf, string);
7684 xmlBufferCCat(buf, "\"");
7685 }
7686}
7687
7688
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007689/**
7690 * xmlGetDocCompressMode:
7691 * @doc: the document
7692 *
7693 * get the compression ratio for a document, ZLIB based
7694 * Returns 0 (uncompressed) to 9 (max compression)
7695 */
7696int
7697xmlGetDocCompressMode (xmlDocPtr doc) {
7698 if (doc == NULL) return(-1);
7699 return(doc->compression);
7700}
7701
7702/**
7703 * xmlSetDocCompressMode:
7704 * @doc: the document
7705 * @mode: the compression ratio
7706 *
7707 * set the compression ratio for a document, ZLIB based
7708 * Correct values: 0 (uncompressed) to 9 (max compression)
7709 */
7710void
7711xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7712 if (doc == NULL) return;
7713 if (mode < 0) doc->compression = 0;
7714 else if (mode > 9) doc->compression = 9;
7715 else doc->compression = mode;
7716}
7717
7718/**
7719 * xmlGetCompressMode:
7720 *
7721 * get the default compression mode used, ZLIB based.
7722 * Returns 0 (uncompressed) to 9 (max compression)
7723 */
7724int
7725xmlGetCompressMode(void)
7726{
7727 return (xmlCompressMode);
7728}
7729
7730/**
7731 * xmlSetCompressMode:
7732 * @mode: the compression ratio
7733 *
7734 * set the default compression mode used, ZLIB based
7735 * Correct values: 0 (uncompressed) to 9 (max compression)
7736 */
7737void
7738xmlSetCompressMode(int mode) {
7739 if (mode < 0) xmlCompressMode = 0;
7740 else if (mode > 9) xmlCompressMode = 9;
7741 else xmlCompressMode = mode;
7742}
7743
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007744#define XML_TREE_NSMAP_PARENT -1
7745#define XML_TREE_NSMAP_XML -2
7746#define XML_TREE_NSMAP_DOC -3
7747#define XML_TREE_NSMAP_CUSTOM -4
7748
7749typedef struct xmlNsMapItem *xmlNsMapItemPtr;
7750struct xmlNsMapItem {
7751 xmlNsMapItemPtr next;
7752 xmlNsMapItemPtr prev;
7753 xmlNsPtr oldNs; /* old ns decl reference */
7754 xmlNsPtr newNs; /* new ns decl reference */
7755 int shadowDepth; /* Shadowed at this depth */
7756 /*
7757 * depth:
7758 * >= 0 == @node's ns-decls
7759 * -1 == @parent's ns-decls
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00007760 * -2 == the doc->oldNs XML ns-decl
7761 * -3 == the doc->oldNs storage ns-decls
7762 * -4 == ns-decls provided via custom ns-handling
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007763 */
7764 int depth;
7765};
7766
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007767typedef struct xmlNsMap *xmlNsMapPtr;
7768struct xmlNsMap {
7769 xmlNsMapItemPtr first;
7770 xmlNsMapItemPtr last;
7771 xmlNsMapItemPtr pool;
7772};
7773
7774#define XML_NSMAP_NOTEMPTY(m) (((m) != NULL) && ((m)->first != NULL))
7775#define XML_NSMAP_FOREACH(m, i) for (i = (m)->first; i != NULL; i = (i)->next)
7776#define XML_NSMAP_POP(m, i) \
7777 i = (m)->last; \
7778 (m)->last = (i)->prev; \
7779 if ((m)->last == NULL) \
7780 (m)->first = NULL; \
7781 else \
7782 (m)->last->next = NULL; \
7783 (i)->next = (m)->pool; \
7784 (m)->pool = i;
7785
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007786/*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007787* xmlDOMWrapNsMapFree:
7788* @map: the ns-map
Daniel Veillardaa6de472008-08-25 14:53:31 +00007789*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007790* Frees the ns-map
7791*/
7792static void
7793xmlDOMWrapNsMapFree(xmlNsMapPtr nsmap)
7794{
7795 xmlNsMapItemPtr cur, tmp;
7796
7797 if (nsmap == NULL)
7798 return;
7799 cur = nsmap->pool;
7800 while (cur != NULL) {
7801 tmp = cur;
7802 cur = cur->next;
7803 xmlFree(tmp);
7804 }
7805 cur = nsmap->first;
7806 while (cur != NULL) {
7807 tmp = cur;
7808 cur = cur->next;
7809 xmlFree(tmp);
7810 }
7811 xmlFree(nsmap);
7812}
7813
7814/*
7815* xmlDOMWrapNsMapAddItem:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007816* @map: the ns-map
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007817* @oldNs: the old ns-struct
7818* @newNs: the new ns-struct
7819* @depth: depth and ns-kind information
Daniel Veillardaa6de472008-08-25 14:53:31 +00007820*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007821* Adds an ns-mapping item.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007822*/
7823static xmlNsMapItemPtr
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00007824xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007825 xmlNsPtr oldNs, xmlNsPtr newNs, int depth)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007826{
7827 xmlNsMapItemPtr ret;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007828 xmlNsMapPtr map;
7829
7830 if (nsmap == NULL)
7831 return(NULL);
7832 if ((position != -1) && (position != 0))
7833 return(NULL);
7834 map = *nsmap;
7835
7836 if (map == NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007837 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007838 * Create the ns-map.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007839 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007840 map = (xmlNsMapPtr) xmlMalloc(sizeof(struct xmlNsMap));
7841 if (map == NULL) {
7842 xmlTreeErrMemory("allocating namespace map");
7843 return (NULL);
7844 }
7845 memset(map, 0, sizeof(struct xmlNsMap));
7846 *nsmap = map;
7847 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00007848
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007849 if (map->pool != NULL) {
7850 /*
7851 * Reuse an item from the pool.
7852 */
7853 ret = map->pool;
7854 map->pool = ret->next;
7855 memset(ret, 0, sizeof(struct xmlNsMapItem));
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007856 } else {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007857 /*
7858 * Create a new item.
7859 */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007860 ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem));
7861 if (ret == NULL) {
7862 xmlTreeErrMemory("allocating namespace map item");
7863 return (NULL);
7864 }
7865 memset(ret, 0, sizeof(struct xmlNsMapItem));
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007866 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00007867
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007868 if (map->first == NULL) {
7869 /*
7870 * First ever.
Daniel Veillardaa6de472008-08-25 14:53:31 +00007871 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007872 map->first = ret;
7873 map->last = ret;
7874 } else if (position == -1) {
7875 /*
7876 * Append.
7877 */
7878 ret->prev = map->last;
7879 map->last->next = ret;
Daniel Veillardaa6de472008-08-25 14:53:31 +00007880 map->last = ret;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007881 } else if (position == 0) {
7882 /*
7883 * Set on first position.
7884 */
7885 map->first->prev = ret;
Daniel Veillardaa6de472008-08-25 14:53:31 +00007886 ret->next = map->first;
7887 map->first = ret;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007888 } else
7889 return(NULL);
7890
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007891 ret->oldNs = oldNs;
7892 ret->newNs = newNs;
7893 ret->shadowDepth = -1;
7894 ret->depth = depth;
7895 return (ret);
7896}
7897
7898/*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007899* xmlDOMWrapStoreNs:
7900* @doc: the doc
7901* @nsName: the namespace name
7902* @prefix: the prefix
Daniel Veillardaa6de472008-08-25 14:53:31 +00007903*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007904* Creates or reuses an xmlNs struct on doc->oldNs with
7905* the given prefix and namespace name.
Daniel Veillardaa6de472008-08-25 14:53:31 +00007906*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007907* Returns the aquired ns struct or NULL in case of an API
7908* or internal error.
7909*/
7910static xmlNsPtr
7911xmlDOMWrapStoreNs(xmlDocPtr doc,
7912 const xmlChar *nsName,
7913 const xmlChar *prefix)
7914{
7915 xmlNsPtr ns;
7916
7917 if (doc == NULL)
7918 return (NULL);
7919 ns = xmlTreeEnsureXMLDecl(doc);
7920 if (ns == NULL)
7921 return (NULL);
7922 if (ns->next != NULL) {
7923 /* Reuse. */
7924 ns = ns->next;
7925 while (ns != NULL) {
7926 if (((ns->prefix == prefix) ||
7927 xmlStrEqual(ns->prefix, prefix)) &&
7928 xmlStrEqual(ns->href, nsName)) {
7929 return (ns);
7930 }
7931 if (ns->next == NULL)
7932 break;
7933 ns = ns->next;
7934 }
7935 }
7936 /* Create. */
Daniel Veillard76d36452009-09-07 11:19:33 +02007937 if (ns != NULL) {
7938 ns->next = xmlNewNs(NULL, nsName, prefix);
7939 return (ns->next);
7940 }
7941 return(NULL);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007942}
7943
7944/*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00007945* xmlDOMWrapNewCtxt:
7946*
7947* Allocates and initializes a new DOM-wrapper context.
7948*
Daniel Veillardaa6de472008-08-25 14:53:31 +00007949* Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal errror.
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00007950*/
7951xmlDOMWrapCtxtPtr
7952xmlDOMWrapNewCtxt(void)
7953{
7954 xmlDOMWrapCtxtPtr ret;
7955
7956 ret = xmlMalloc(sizeof(xmlDOMWrapCtxt));
7957 if (ret == NULL) {
7958 xmlTreeErrMemory("allocating DOM-wrapper context");
7959 return (NULL);
7960 }
7961 memset(ret, 0, sizeof(xmlDOMWrapCtxt));
7962 return (ret);
7963}
7964
7965/*
7966* xmlDOMWrapFreeCtxt:
7967* @ctxt: the DOM-wrapper context
7968*
7969* Frees the DOM-wrapper context.
7970*/
7971void
7972xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt)
7973{
7974 if (ctxt == NULL)
7975 return;
7976 if (ctxt->namespaceMap != NULL)
7977 xmlDOMWrapNsMapFree((xmlNsMapPtr) ctxt->namespaceMap);
7978 /*
7979 * TODO: Store the namespace map in the context.
7980 */
7981 xmlFree(ctxt);
7982}
7983
7984/*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007985* xmlTreeLookupNsListByPrefix:
7986* @nsList: a list of ns-structs
7987* @prefix: the searched prefix
Daniel Veillardaa6de472008-08-25 14:53:31 +00007988*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007989* Searches for a ns-decl with the given prefix in @nsList.
Daniel Veillardaa6de472008-08-25 14:53:31 +00007990*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007991* Returns the ns-decl if found, NULL if not found and on
7992* API errors.
7993*/
7994static xmlNsPtr
7995xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix)
7996{
7997 if (nsList == NULL)
7998 return (NULL);
7999 {
8000 xmlNsPtr ns;
8001 ns = nsList;
8002 do {
8003 if ((prefix == ns->prefix) ||
8004 xmlStrEqual(prefix, ns->prefix)) {
8005 return (ns);
8006 }
8007 ns = ns->next;
8008 } while (ns != NULL);
8009 }
8010 return (NULL);
8011}
8012
8013/*
8014*
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008015* xmlDOMWrapNSNormGatherInScopeNs:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008016* @map: the namespace map
8017* @node: the node to start with
Daniel Veillardaa6de472008-08-25 14:53:31 +00008018*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008019* Puts in-scope namespaces into the ns-map.
Daniel Veillardaa6de472008-08-25 14:53:31 +00008020*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008021* Returns 0 on success, -1 on API or internal errors.
8022*/
8023static int
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008024xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapPtr *map,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008025 xmlNodePtr node)
8026{
8027 xmlNodePtr cur;
8028 xmlNsPtr ns;
8029 xmlNsMapItemPtr mi;
8030 int shadowed;
8031
8032 if ((map == NULL) || (*map != NULL))
8033 return (-1);
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008034 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
8035 return (-1);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008036 /*
8037 * Get in-scope ns-decls of @parent.
8038 */
8039 cur = node;
8040 while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) {
8041 if (cur->type == XML_ELEMENT_NODE) {
8042 if (cur->nsDef != NULL) {
8043 ns = cur->nsDef;
8044 do {
8045 shadowed = 0;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008046 if (XML_NSMAP_NOTEMPTY(*map)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008047 /*
8048 * Skip shadowed prefixes.
8049 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008050 XML_NSMAP_FOREACH(*map, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008051 if ((ns->prefix == mi->newNs->prefix) ||
8052 xmlStrEqual(ns->prefix, mi->newNs->prefix)) {
8053 shadowed = 1;
8054 break;
8055 }
8056 }
8057 }
8058 /*
8059 * Insert mapping.
8060 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008061 mi = xmlDOMWrapNsMapAddItem(map, 0, NULL,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008062 ns, XML_TREE_NSMAP_PARENT);
8063 if (mi == NULL)
8064 return (-1);
8065 if (shadowed)
8066 mi->shadowDepth = 0;
8067 ns = ns->next;
8068 } while (ns != NULL);
8069 }
8070 }
8071 cur = cur->parent;
8072 }
8073 return (0);
8074}
8075
8076/*
8077* XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict;
8078* otherwise copy it, when it was in the source-dict.
8079*/
8080#define XML_TREE_ADOPT_STR(str) \
8081 if (adoptStr && (str != NULL)) { \
8082 if (destDoc->dict) { \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00008083 const xmlChar *old = str; \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008084 str = xmlDictLookup(destDoc->dict, str, -1); \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00008085 if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \
8086 (!xmlDictOwns(sourceDoc->dict, old))) \
Daniel Veillard39e5c892005-07-03 22:48:50 +00008087 xmlFree((char *)old); \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008088 } else if ((sourceDoc) && (sourceDoc->dict) && \
8089 xmlDictOwns(sourceDoc->dict, str)) { \
8090 str = BAD_CAST xmlStrdup(str); \
8091 } \
8092 }
8093
8094/*
8095* XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then
8096* put it in dest-dict or copy it.
8097*/
8098#define XML_TREE_ADOPT_STR_2(str) \
8099 if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \
8100 (sourceDoc->dict != NULL) && \
8101 xmlDictOwns(sourceDoc->dict, cur->content)) { \
8102 if (destDoc->dict) \
8103 cur->content = (xmlChar *) \
8104 xmlDictLookup(destDoc->dict, cur->content, -1); \
8105 else \
8106 cur->content = xmlStrdup(BAD_CAST cur->content); \
8107 }
8108
8109/*
8110* xmlDOMWrapNSNormAddNsMapItem2:
8111*
8112* For internal use. Adds a ns-decl mapping.
8113*
Daniel Veillardaa6de472008-08-25 14:53:31 +00008114* Returns 0 on success, -1 on internal errors.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008115*/
8116static int
8117xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number,
8118 xmlNsPtr oldNs, xmlNsPtr newNs)
8119{
8120 if (*list == NULL) {
8121 *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr));
8122 if (*list == NULL) {
8123 xmlTreeErrMemory("alloc ns map item");
8124 return(-1);
8125 }
8126 *size = 3;
8127 *number = 0;
8128 } else if ((*number) >= (*size)) {
8129 *size *= 2;
8130 *list = (xmlNsPtr *) xmlRealloc(*list,
8131 (*size) * 2 * sizeof(xmlNsPtr));
8132 if (*list == NULL) {
8133 xmlTreeErrMemory("realloc ns map item");
8134 return(-1);
8135 }
8136 }
8137 (*list)[2 * (*number)] = oldNs;
8138 (*list)[2 * (*number) +1] = newNs;
8139 (*number)++;
8140 return (0);
8141}
8142
8143/*
8144* xmlDOMWrapRemoveNode:
Daniel Veillard304e78c2005-07-03 16:19:41 +00008145* @ctxt: a DOM wrapper context
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008146* @doc: the doc
8147* @node: the node to be removed.
Daniel Veillard304e78c2005-07-03 16:19:41 +00008148* @options: set of options, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008149*
8150* Unlinks the given node from its owner.
8151* This will substitute ns-references to node->nsDef for
8152* ns-references to doc->oldNs, thus ensuring the removed
8153* branch to be autark wrt ns-references.
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008154*
8155* NOTE: This function was not intensively tested.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008156*
8157* Returns 0 on success, 1 if the node is not supported,
Daniel Veillardaa6de472008-08-25 14:53:31 +00008158* -1 on API and internal errors.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008159*/
8160int
8161xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc,
8162 xmlNodePtr node, int options ATTRIBUTE_UNUSED)
8163{
8164 xmlNsPtr *list = NULL;
8165 int sizeList, nbList, i, j;
8166 xmlNsPtr ns;
8167
8168 if ((node == NULL) || (doc == NULL) || (node->doc != doc))
8169 return (-1);
8170
8171 /* TODO: 0 or -1 ? */
8172 if (node->parent == NULL)
8173 return (0);
8174
Daniel Veillardaa6de472008-08-25 14:53:31 +00008175 switch (node->type) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008176 case XML_TEXT_NODE:
8177 case XML_CDATA_SECTION_NODE:
8178 case XML_ENTITY_REF_NODE:
8179 case XML_PI_NODE:
8180 case XML_COMMENT_NODE:
8181 xmlUnlinkNode(node);
8182 return (0);
Daniel Veillardaa6de472008-08-25 14:53:31 +00008183 case XML_ELEMENT_NODE:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008184 case XML_ATTRIBUTE_NODE:
8185 break;
8186 default:
8187 return (1);
8188 }
8189 xmlUnlinkNode(node);
8190 /*
8191 * Save out-of-scope ns-references in doc->oldNs.
8192 */
8193 do {
8194 switch (node->type) {
8195 case XML_ELEMENT_NODE:
8196 if ((ctxt == NULL) && (node->nsDef != NULL)) {
8197 ns = node->nsDef;
8198 do {
8199 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
8200 &nbList, ns, ns) == -1)
8201 goto internal_error;
8202 ns = ns->next;
8203 } while (ns != NULL);
8204 }
8205 /* No break on purpose. */
8206 case XML_ATTRIBUTE_NODE:
Daniel Veillardaa6de472008-08-25 14:53:31 +00008207 if (node->ns != NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008208 /*
8209 * Find a mapping.
8210 */
8211 if (list != NULL) {
8212 for (i = 0, j = 0; i < nbList; i++, j += 2) {
8213 if (node->ns == list[j]) {
8214 node->ns = list[++j];
8215 goto next_node;
8216 }
8217 }
8218 }
8219 ns = NULL;
8220 if (ctxt != NULL) {
8221 /*
8222 * User defined.
8223 */
8224 } else {
8225 /*
8226 * Add to doc's oldNs.
8227 */
8228 ns = xmlDOMWrapStoreNs(doc, node->ns->href,
8229 node->ns->prefix);
8230 if (ns == NULL)
8231 goto internal_error;
8232 }
8233 if (ns != NULL) {
8234 /*
8235 * Add mapping.
8236 */
8237 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
8238 &nbList, node->ns, ns) == -1)
8239 goto internal_error;
8240 }
8241 node->ns = ns;
8242 }
8243 if ((node->type == XML_ELEMENT_NODE) &&
8244 (node->properties != NULL)) {
8245 node = (xmlNodePtr) node->properties;
8246 continue;
8247 }
8248 break;
8249 default:
8250 goto next_sibling;
Daniel Veillardaa6de472008-08-25 14:53:31 +00008251 }
8252next_node:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008253 if ((node->type == XML_ELEMENT_NODE) &&
8254 (node->children != NULL)) {
8255 node = node->children;
8256 continue;
8257 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00008258next_sibling:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008259 if (node == NULL)
8260 break;
8261 if (node->next != NULL)
8262 node = node->next;
8263 else {
8264 node = node->parent;
8265 goto next_sibling;
8266 }
8267 } while (node != NULL);
8268
8269 if (list != NULL)
8270 xmlFree(list);
8271 return (0);
8272
8273internal_error:
8274 if (list != NULL)
8275 xmlFree(list);
8276 return (-1);
8277}
8278
8279/*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008280* xmlSearchNsByNamespaceStrict:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008281* @doc: the document
8282* @node: the start node
8283* @nsName: the searched namespace name
8284* @retNs: the resulting ns-decl
8285* @prefixed: if the found ns-decl must have a prefix (for attributes)
8286*
8287* Dynamically searches for a ns-declaration which matches
8288* the given @nsName in the ancestor-or-self axis of @node.
8289*
8290* Returns 1 if a ns-decl was found, 0 if not and -1 on API
8291* and internal errors.
8292*/
8293static int
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008294xmlSearchNsByNamespaceStrict(xmlDocPtr doc, xmlNodePtr node,
8295 const xmlChar* nsName,
8296 xmlNsPtr *retNs, int prefixed)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008297{
8298 xmlNodePtr cur, prev = NULL, out = NULL;
8299 xmlNsPtr ns, prevns;
8300
8301 if ((doc == NULL) || (nsName == NULL) || (retNs == NULL))
8302 return (-1);
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008303 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
8304 return(-1);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008305
8306 *retNs = NULL;
8307 if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
8308 *retNs = xmlTreeEnsureXMLDecl(doc);
8309 if (*retNs == NULL)
8310 return (-1);
8311 return (1);
8312 }
8313 cur = node;
8314 do {
8315 if (cur->type == XML_ELEMENT_NODE) {
8316 if (cur->nsDef != NULL) {
8317 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8318 if (prefixed && (ns->prefix == NULL))
8319 continue;
8320 if (prev != NULL) {
8321 /*
8322 * Check the last level of ns-decls for a
8323 * shadowing prefix.
8324 */
8325 prevns = prev->nsDef;
8326 do {
8327 if ((prevns->prefix == ns->prefix) ||
8328 ((prevns->prefix != NULL) &&
8329 (ns->prefix != NULL) &&
8330 xmlStrEqual(prevns->prefix, ns->prefix))) {
8331 /*
8332 * Shadowed.
8333 */
8334 break;
8335 }
8336 prevns = prevns->next;
8337 } while (prevns != NULL);
8338 if (prevns != NULL)
8339 continue;
8340 }
8341 /*
8342 * Ns-name comparison.
8343 */
8344 if ((nsName == ns->href) ||
8345 xmlStrEqual(nsName, ns->href)) {
8346 /*
8347 * At this point the prefix can only be shadowed,
8348 * if we are the the (at least) 3rd level of
8349 * ns-decls.
8350 */
8351 if (out) {
8352 int ret;
Daniel Veillardaa6de472008-08-25 14:53:31 +00008353
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008354 ret = xmlNsInScope(doc, node, prev, ns->prefix);
8355 if (ret < 0)
8356 return (-1);
8357 /*
8358 * TODO: Should we try to find a matching ns-name
8359 * only once? This here keeps on searching.
8360 * I think we should try further since, there might
8361 * be an other matching ns-decl with an unshadowed
8362 * prefix.
8363 */
8364 if (! ret)
8365 continue;
8366 }
8367 *retNs = ns;
8368 return (1);
8369 }
8370 }
8371 out = prev;
8372 prev = cur;
8373 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008374 } else if ((cur->type == XML_ENTITY_NODE) ||
8375 (cur->type == XML_ENTITY_DECL))
8376 return (0);
8377 cur = cur->parent;
8378 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
8379 return (0);
8380}
8381
8382/*
8383* xmlSearchNsByPrefixStrict:
8384* @doc: the document
8385* @node: the start node
8386* @prefix: the searched namespace prefix
8387* @retNs: the resulting ns-decl
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008388*
8389* Dynamically searches for a ns-declaration which matches
8390* the given @nsName in the ancestor-or-self axis of @node.
8391*
8392* Returns 1 if a ns-decl was found, 0 if not and -1 on API
8393* and internal errors.
8394*/
8395static int
8396xmlSearchNsByPrefixStrict(xmlDocPtr doc, xmlNodePtr node,
8397 const xmlChar* prefix,
8398 xmlNsPtr *retNs)
8399{
8400 xmlNodePtr cur;
8401 xmlNsPtr ns;
8402
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008403 if ((doc == NULL) || (node == NULL) || (node->type == XML_NAMESPACE_DECL))
8404 return(-1);
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008405
8406 if (retNs)
8407 *retNs = NULL;
8408 if (IS_STR_XML(prefix)) {
8409 if (retNs) {
8410 *retNs = xmlTreeEnsureXMLDecl(doc);
8411 if (*retNs == NULL)
8412 return (-1);
8413 }
8414 return (1);
8415 }
8416 cur = node;
8417 do {
8418 if (cur->type == XML_ELEMENT_NODE) {
8419 if (cur->nsDef != NULL) {
8420 ns = cur->nsDef;
Daniel Veillardaa6de472008-08-25 14:53:31 +00008421 do {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008422 if ((prefix == ns->prefix) ||
8423 xmlStrEqual(prefix, ns->prefix))
8424 {
8425 /*
8426 * Disabled namespaces, e.g. xmlns:abc="".
8427 */
8428 if (ns->href == NULL)
8429 return(0);
8430 if (retNs)
8431 *retNs = ns;
8432 return (1);
8433 }
8434 ns = ns->next;
Daniel Veillardaa6de472008-08-25 14:53:31 +00008435 } while (ns != NULL);
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008436 }
8437 } else if ((cur->type == XML_ENTITY_NODE) ||
8438 (cur->type == XML_ENTITY_DECL))
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008439 return (0);
8440 cur = cur->parent;
8441 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
8442 return (0);
8443}
8444
8445/*
8446* xmlDOMWrapNSNormDeclareNsForced:
8447* @doc: the doc
8448* @elem: the element-node to declare on
8449* @nsName: the namespace-name of the ns-decl
8450* @prefix: the preferred prefix of the ns-decl
8451* @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls
8452*
8453* Declares a new namespace on @elem. It tries to use the
8454* given @prefix; if a ns-decl with the given prefix is already existent
8455* on @elem, it will generate an other prefix.
8456*
8457* Returns 1 if a ns-decl was found, 0 if not and -1 on API
8458* and internal errors.
8459*/
8460static xmlNsPtr
8461xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc,
8462 xmlNodePtr elem,
8463 const xmlChar *nsName,
8464 const xmlChar *prefix,
8465 int checkShadow)
8466{
8467
8468 xmlNsPtr ret;
8469 char buf[50];
8470 const xmlChar *pref;
8471 int counter = 0;
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008472
8473 if ((doc == NULL) || (elem == NULL) || (elem->type != XML_ELEMENT_NODE))
8474 return(NULL);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008475 /*
8476 * Create a ns-decl on @anchor.
8477 */
8478 pref = prefix;
8479 while (1) {
8480 /*
8481 * Lookup whether the prefix is unused in elem's ns-decls.
8482 */
8483 if ((elem->nsDef != NULL) &&
8484 (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL))
8485 goto ns_next_prefix;
8486 if (checkShadow && elem->parent &&
8487 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8488 /*
8489 * Does it shadow ancestor ns-decls?
8490 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008491 if (xmlSearchNsByPrefixStrict(doc, elem->parent, pref, NULL) == 1)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008492 goto ns_next_prefix;
8493 }
8494 ret = xmlNewNs(NULL, nsName, pref);
8495 if (ret == NULL)
8496 return (NULL);
8497 if (elem->nsDef == NULL)
8498 elem->nsDef = ret;
8499 else {
8500 xmlNsPtr ns2 = elem->nsDef;
8501 while (ns2->next != NULL)
8502 ns2 = ns2->next;
8503 ns2->next = ret;
8504 }
8505 return (ret);
8506ns_next_prefix:
8507 counter++;
8508 if (counter > 1000)
8509 return (NULL);
8510 if (prefix == NULL) {
8511 snprintf((char *) buf, sizeof(buf),
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008512 "ns_%d", counter);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008513 } else
8514 snprintf((char *) buf, sizeof(buf),
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008515 "%.30s_%d", (char *)prefix, counter);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008516 pref = BAD_CAST buf;
8517 }
8518}
8519
8520/*
8521* xmlDOMWrapNSNormAquireNormalizedNs:
8522* @doc: the doc
8523* @elem: the element-node to declare namespaces on
8524* @ns: the ns-struct to use for the search
8525* @retNs: the found/created ns-struct
8526* @nsMap: the ns-map
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008527* @depth: the current tree depth
8528* @ancestorsOnly: search in ancestor ns-decls only
8529* @prefixed: if the searched ns-decl must have a prefix (for attributes)
8530*
8531* Searches for a matching ns-name in the ns-decls of @nsMap, if not
8532* found it will either declare it on @elem, or store it in doc->oldNs.
8533* If a new ns-decl needs to be declared on @elem, it tries to use the
8534* @ns->prefix for it, if this prefix is already in use on @elem, it will
8535* change the prefix or the new ns-decl.
8536*
8537* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8538*/
8539static int
8540xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc,
8541 xmlNodePtr elem,
8542 xmlNsPtr ns,
8543 xmlNsPtr *retNs,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008544 xmlNsMapPtr *nsMap,
Daniel Veillardaa6de472008-08-25 14:53:31 +00008545
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008546 int depth,
8547 int ancestorsOnly,
8548 int prefixed)
8549{
Daniel Veillardaa6de472008-08-25 14:53:31 +00008550 xmlNsMapItemPtr mi;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008551
8552 if ((doc == NULL) || (ns == NULL) || (retNs == NULL) ||
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008553 (nsMap == NULL))
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008554 return (-1);
8555
8556 *retNs = NULL;
8557 /*
8558 * Handle XML namespace.
8559 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008560 if (IS_STR_XML(ns->prefix)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008561 /*
8562 * Insert XML namespace mapping.
8563 */
8564 *retNs = xmlTreeEnsureXMLDecl(doc);
8565 if (*retNs == NULL)
8566 return (-1);
8567 return (0);
8568 }
8569 /*
8570 * If the search should be done in ancestors only and no
8571 * @elem (the first ancestor) was specified, then skip the search.
8572 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008573 if ((XML_NSMAP_NOTEMPTY(*nsMap)) &&
8574 (! (ancestorsOnly && (elem == NULL))))
Daniel Veillardaa6de472008-08-25 14:53:31 +00008575 {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008576 /*
8577 * Try to find an equal ns-name in in-scope ns-decls.
8578 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008579 XML_NSMAP_FOREACH(*nsMap, mi) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00008580 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8581 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008582 * ancestorsOnly: This should be turned on to gain speed,
8583 * if one knows that the branch itself was already
8584 * ns-wellformed and no stale references existed.
8585 * I.e. it searches in the ancestor axis only.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008586 */
8587 ((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) &&
8588 /* Skip shadowed prefixes. */
Daniel Veillardaa6de472008-08-25 14:53:31 +00008589 (mi->shadowDepth == -1) &&
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008590 /* Skip xmlns="" or xmlns:foo="". */
8591 ((mi->newNs->href != NULL) &&
Daniel Veillardaa6de472008-08-25 14:53:31 +00008592 (mi->newNs->href[0] != 0)) &&
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008593 /* Ensure a prefix if wanted. */
8594 ((! prefixed) || (mi->newNs->prefix != NULL)) &&
8595 /* Equal ns name */
8596 ((mi->newNs->href == ns->href) ||
8597 xmlStrEqual(mi->newNs->href, ns->href))) {
8598 /* Set the mapping. */
8599 mi->oldNs = ns;
8600 *retNs = mi->newNs;
8601 return (0);
8602 }
8603 }
8604 }
8605 /*
8606 * No luck, the namespace is out of scope or shadowed.
8607 */
8608 if (elem == NULL) {
8609 xmlNsPtr tmpns;
8610
8611 /*
8612 * Store ns-decls in "oldNs" of the document-node.
8613 */
8614 tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix);
8615 if (tmpns == NULL)
8616 return (-1);
8617 /*
8618 * Insert mapping.
Daniel Veillardaa6de472008-08-25 14:53:31 +00008619 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008620 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008621 tmpns, XML_TREE_NSMAP_DOC) == NULL) {
8622 xmlFreeNs(tmpns);
8623 return (-1);
8624 }
8625 *retNs = tmpns;
8626 } else {
8627 xmlNsPtr tmpns;
8628
8629 tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href,
8630 ns->prefix, 0);
8631 if (tmpns == NULL)
8632 return (-1);
8633
8634 if (*nsMap != NULL) {
8635 /*
8636 * Does it shadow ancestor ns-decls?
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008637 */
8638 XML_NSMAP_FOREACH(*nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008639 if ((mi->depth < depth) &&
8640 (mi->shadowDepth == -1) &&
8641 ((ns->prefix == mi->newNs->prefix) ||
8642 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8643 /*
8644 * Shadows.
8645 */
8646 mi->shadowDepth = depth;
8647 break;
8648 }
8649 }
8650 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008651 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, depth) == NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008652 xmlFreeNs(tmpns);
8653 return (-1);
8654 }
8655 *retNs = tmpns;
8656 }
8657 return (0);
8658}
8659
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008660typedef enum {
Daniel Veillardaa6de472008-08-25 14:53:31 +00008661 XML_DOM_RECONNS_REMOVEREDUND = 1<<0
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008662} xmlDOMReconcileNSOptions;
8663
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008664/*
8665* xmlDOMWrapReconcileNamespaces:
Daniel Veillard304e78c2005-07-03 16:19:41 +00008666* @ctxt: DOM wrapper context, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008667* @elem: the element-node
8668* @options: option flags
8669*
8670* Ensures that ns-references point to ns-decls hold on element-nodes.
8671* Ensures that the tree is namespace wellformed by creating additional
8672* ns-decls where needed. Note that, since prefixes of already existent
8673* ns-decls can be shadowed by this process, it could break QNames in
8674* attribute values or element content.
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008675*
8676* NOTE: This function was not intensively tested.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008677*
8678* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
Daniel Veillardaa6de472008-08-25 14:53:31 +00008679*/
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008680
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008681int
8682xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,
8683 xmlNodePtr elem,
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008684 int options)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008685{
8686 int depth = -1, adoptns = 0, parnsdone = 0;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008687 xmlNsPtr ns, prevns;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008688 xmlDocPtr doc;
8689 xmlNodePtr cur, curElem = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008690 xmlNsMapPtr nsMap = NULL;
8691 xmlNsMapItemPtr /* topmi = NULL, */ mi;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008692 /* @ancestorsOnly should be set by an option flag. */
8693 int ancestorsOnly = 0;
Daniel Veillardaa6de472008-08-25 14:53:31 +00008694 int optRemoveRedundantNS =
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008695 ((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0;
8696 xmlNsPtr *listRedund = NULL;
8697 int sizeRedund = 0, nbRedund = 0, ret, i, j;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008698
8699 if ((elem == NULL) || (elem->doc == NULL) ||
8700 (elem->type != XML_ELEMENT_NODE))
8701 return (-1);
8702
8703 doc = elem->doc;
8704 cur = elem;
8705 do {
8706 switch (cur->type) {
8707 case XML_ELEMENT_NODE:
8708 adoptns = 1;
8709 curElem = cur;
8710 depth++;
8711 /*
8712 * Namespace declarations.
8713 */
8714 if (cur->nsDef != NULL) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008715 prevns = NULL;
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008716 ns = cur->nsDef;
8717 while (ns != NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008718 if (! parnsdone) {
8719 if ((elem->parent) &&
8720 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8721 /*
8722 * Gather ancestor in-scope ns-decls.
8723 */
8724 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8725 elem->parent) == -1)
8726 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008727 }
8728 parnsdone = 1;
8729 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00008730
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008731 /*
8732 * Lookup the ns ancestor-axis for equal ns-decls in scope.
8733 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008734 if (optRemoveRedundantNS && XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008735 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008736 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8737 (mi->shadowDepth == -1) &&
8738 ((ns->prefix == mi->newNs->prefix) ||
8739 xmlStrEqual(ns->prefix, mi->newNs->prefix)) &&
8740 ((ns->href == mi->newNs->href) ||
8741 xmlStrEqual(ns->href, mi->newNs->href)))
Daniel Veillardaa6de472008-08-25 14:53:31 +00008742 {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008743 /*
8744 * A redundant ns-decl was found.
8745 * Add it to the list of redundant ns-decls.
8746 */
8747 if (xmlDOMWrapNSNormAddNsMapItem2(&listRedund,
8748 &sizeRedund, &nbRedund, ns, mi->newNs) == -1)
8749 goto internal_error;
8750 /*
8751 * Remove the ns-decl from the element-node.
Daniel Veillardaa6de472008-08-25 14:53:31 +00008752 */
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008753 if (prevns)
8754 prevns->next = ns->next;
8755 else
Daniel Veillardaa6de472008-08-25 14:53:31 +00008756 cur->nsDef = ns->next;
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008757 goto next_ns_decl;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008758 }
8759 }
8760 }
8761
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008762 /*
8763 * Skip ns-references handling if the referenced
8764 * ns-decl is declared on the same element.
8765 */
8766 if ((cur->ns != NULL) && adoptns && (cur->ns == ns))
Daniel Veillardaa6de472008-08-25 14:53:31 +00008767 adoptns = 0;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008768 /*
8769 * Does it shadow any ns-decl?
8770 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008771 if (XML_NSMAP_NOTEMPTY(nsMap)) {
8772 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008773 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8774 (mi->shadowDepth == -1) &&
8775 ((ns->prefix == mi->newNs->prefix) ||
8776 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00008777
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008778 mi->shadowDepth = depth;
8779 }
8780 }
8781 }
8782 /*
8783 * Push mapping.
8784 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008785 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008786 depth) == NULL)
Daniel Veillardaa6de472008-08-25 14:53:31 +00008787 goto internal_error;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008788
8789 prevns = ns;
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008790next_ns_decl:
Daniel Veillardaa6de472008-08-25 14:53:31 +00008791 ns = ns->next;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008792 }
8793 }
8794 if (! adoptns)
8795 goto ns_end;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008796 /* No break on purpose. */
8797 case XML_ATTRIBUTE_NODE:
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008798 /* No ns, no fun. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008799 if (cur->ns == NULL)
8800 goto ns_end;
Daniel Veillardaa6de472008-08-25 14:53:31 +00008801
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008802 if (! parnsdone) {
8803 if ((elem->parent) &&
8804 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8805 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8806 elem->parent) == -1)
8807 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008808 }
8809 parnsdone = 1;
8810 }
8811 /*
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008812 * Adjust the reference if this was a redundant ns-decl.
8813 */
8814 if (listRedund) {
8815 for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8816 if (cur->ns == listRedund[j]) {
8817 cur->ns = listRedund[++j];
8818 break;
8819 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00008820 }
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008821 }
8822 /*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008823 * Adopt ns-references.
8824 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008825 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008826 /*
8827 * Search for a mapping.
8828 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008829 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008830 if ((mi->shadowDepth == -1) &&
8831 (cur->ns == mi->oldNs)) {
8832
8833 cur->ns = mi->newNs;
8834 goto ns_end;
8835 }
8836 }
8837 }
8838 /*
8839 * Aquire a normalized ns-decl and add it to the map.
8840 */
8841 if (xmlDOMWrapNSNormAquireNormalizedNs(doc, curElem,
8842 cur->ns, &ns,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008843 &nsMap, depth,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008844 ancestorsOnly,
8845 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8846 goto internal_error;
8847 cur->ns = ns;
8848
8849ns_end:
8850 if ((cur->type == XML_ELEMENT_NODE) &&
8851 (cur->properties != NULL)) {
8852 /*
8853 * Process attributes.
8854 */
8855 cur = (xmlNodePtr) cur->properties;
8856 continue;
8857 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00008858 break;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008859 default:
8860 goto next_sibling;
8861 }
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008862into_content:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008863 if ((cur->type == XML_ELEMENT_NODE) &&
8864 (cur->children != NULL)) {
8865 /*
8866 * Process content of element-nodes only.
8867 */
8868 cur = cur->children;
8869 continue;
8870 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00008871next_sibling:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008872 if (cur == elem)
8873 break;
8874 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00008875 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008876 /*
8877 * Pop mappings.
8878 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008879 while ((nsMap->last != NULL) &&
8880 (nsMap->last->depth >= depth))
8881 {
Daniel Veillardaa6de472008-08-25 14:53:31 +00008882 XML_NSMAP_POP(nsMap, mi)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008883 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008884 /*
8885 * Unshadow.
8886 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008887 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008888 if (mi->shadowDepth >= depth)
8889 mi->shadowDepth = -1;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008890 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00008891 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008892 depth--;
8893 }
8894 if (cur->next != NULL)
8895 cur = cur->next;
8896 else {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008897 if (cur->type == XML_ATTRIBUTE_NODE) {
8898 cur = cur->parent;
8899 goto into_content;
8900 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008901 cur = cur->parent;
8902 goto next_sibling;
8903 }
8904 } while (cur != NULL);
Daniel Veillardaa6de472008-08-25 14:53:31 +00008905
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008906 ret = 0;
8907 goto exit;
8908internal_error:
8909 ret = -1;
8910exit:
Daniel Veillardaa6de472008-08-25 14:53:31 +00008911 if (listRedund) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008912 for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8913 xmlFreeNs(listRedund[j]);
8914 }
8915 xmlFree(listRedund);
8916 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008917 if (nsMap != NULL)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008918 xmlDOMWrapNsMapFree(nsMap);
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008919 return (ret);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008920}
8921
8922/*
8923* xmlDOMWrapAdoptBranch:
8924* @ctxt: the optional context for custom processing
8925* @sourceDoc: the optional sourceDoc
8926* @node: the element-node to start with
8927* @destDoc: the destination doc for adoption
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008928* @destParent: the optional new parent of @node in @destDoc
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008929* @options: option flags
8930*
8931* Ensures that ns-references point to @destDoc: either to
8932* elements->nsDef entries if @destParent is given, or to
8933* @destDoc->oldNs otherwise.
8934* If @destParent is given, it ensures that the tree is namespace
8935* wellformed by creating additional ns-decls where needed.
8936* Note that, since prefixes of already existent ns-decls can be
8937* shadowed by this process, it could break QNames in attribute
8938* values or element content.
8939*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008940* NOTE: This function was not intensively tested.
8941*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008942* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8943*/
8944static int
8945xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
8946 xmlDocPtr sourceDoc,
8947 xmlNodePtr node,
8948 xmlDocPtr destDoc,
8949 xmlNodePtr destParent,
8950 int options ATTRIBUTE_UNUSED)
8951{
8952 int ret = 0;
8953 xmlNodePtr cur, curElem = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008954 xmlNsMapPtr nsMap = NULL;
8955 xmlNsMapItemPtr mi;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008956 xmlNsPtr ns = NULL;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008957 int depth = -1, adoptStr = 1;
8958 /* gather @parent's ns-decls. */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008959 int parnsdone;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008960 /* @ancestorsOnly should be set per option. */
8961 int ancestorsOnly = 0;
Daniel Veillardaa6de472008-08-25 14:53:31 +00008962
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008963 /*
8964 * Optimize string adoption for equal or none dicts.
8965 */
8966 if ((sourceDoc != NULL) &&
8967 (sourceDoc->dict == destDoc->dict))
8968 adoptStr = 0;
8969 else
8970 adoptStr = 1;
8971
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008972 /*
8973 * Get the ns-map from the context if available.
8974 */
8975 if (ctxt)
8976 nsMap = (xmlNsMapPtr) ctxt->namespaceMap;
8977 /*
8978 * Disable search for ns-decls in the parent-axis of the
8979 * desination element, if:
8980 * 1) there's no destination parent
8981 * 2) custom ns-reference handling is used
8982 */
8983 if ((destParent == NULL) ||
8984 (ctxt && ctxt->getNsForNodeFunc))
8985 {
8986 parnsdone = 1;
8987 } else
8988 parnsdone = 0;
8989
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008990 cur = node;
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008991 if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL))
8992 goto internal_error;
8993
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008994 while (cur != NULL) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008995 /*
8996 * Paranoid source-doc sanity check.
8997 */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008998 if (cur->doc != sourceDoc) {
8999 /*
9000 * We'll assume XIncluded nodes if the doc differs.
9001 * TODO: Do we need to reconciliate XIncluded nodes?
9002 * This here skips XIncluded nodes and tries to handle
9003 * broken sequences.
9004 */
9005 if (cur->next == NULL)
9006 goto leave_node;
9007 do {
9008 cur = cur->next;
9009 if ((cur->type == XML_XINCLUDE_END) ||
9010 (cur->doc == node->doc))
9011 break;
9012 } while (cur->next != NULL);
9013
9014 if (cur->doc != node->doc)
9015 goto leave_node;
9016 }
9017 cur->doc = destDoc;
9018 switch (cur->type) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00009019 case XML_XINCLUDE_START:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009020 case XML_XINCLUDE_END:
9021 /*
9022 * TODO
9023 */
9024 return (-1);
Daniel Veillardaa6de472008-08-25 14:53:31 +00009025 case XML_ELEMENT_NODE:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009026 curElem = cur;
9027 depth++;
9028 /*
Daniel Veillardaa6de472008-08-25 14:53:31 +00009029 * Namespace declarations.
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009030 * - ns->href and ns->prefix are never in the dict, so
9031 * we need not move the values over to the destination dict.
9032 * - Note that for custom handling of ns-references,
9033 * the ns-decls need not be stored in the ns-map,
9034 * since they won't be referenced by node->ns.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009035 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009036 if ((cur->nsDef) &&
9037 ((ctxt == NULL) || (ctxt->getNsForNodeFunc == NULL)))
9038 {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009039 if (! parnsdone) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009040 /*
9041 * Gather @parent's in-scope ns-decls.
9042 */
9043 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
9044 destParent) == -1)
9045 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009046 parnsdone = 1;
9047 }
9048 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
9049 /*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009050 * NOTE: ns->prefix and ns->href are never in the dict.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009051 * XML_TREE_ADOPT_STR(ns->prefix)
9052 * XML_TREE_ADOPT_STR(ns->href)
Daniel Veillardaa6de472008-08-25 14:53:31 +00009053 */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009054 /*
9055 * Does it shadow any ns-decl?
Daniel Veillardaa6de472008-08-25 14:53:31 +00009056 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009057 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009058 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009059 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
9060 (mi->shadowDepth == -1) &&
9061 ((ns->prefix == mi->newNs->prefix) ||
9062 xmlStrEqual(ns->prefix,
9063 mi->newNs->prefix))) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00009064
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009065 mi->shadowDepth = depth;
9066 }
9067 }
9068 }
9069 /*
9070 * Push mapping.
9071 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009072 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009073 ns, ns, depth) == NULL)
9074 goto internal_error;
9075 }
9076 }
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009077 /* No break on purpose. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009078 case XML_ATTRIBUTE_NODE:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009079 /* No namespace, no fun. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009080 if (cur->ns == NULL)
9081 goto ns_end;
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009082
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009083 if (! parnsdone) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009084 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
9085 destParent) == -1)
9086 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009087 parnsdone = 1;
9088 }
9089 /*
9090 * Adopt ns-references.
9091 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009092 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009093 /*
9094 * Search for a mapping.
9095 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009096 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009097 if ((mi->shadowDepth == -1) &&
9098 (cur->ns == mi->oldNs)) {
9099
9100 cur->ns = mi->newNs;
9101 goto ns_end;
9102 }
9103 }
9104 }
9105 /*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009106 * No matching namespace in scope. We need a new one.
9107 */
9108 if ((ctxt) && (ctxt->getNsForNodeFunc)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009109 /*
9110 * User-defined behaviour.
9111 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009112 ns = ctxt->getNsForNodeFunc(ctxt, cur,
9113 cur->ns->href, cur->ns->prefix);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009114 /*
9115 * Insert mapping if ns is available; it's the users fault
9116 * if not.
9117 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009118 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009119 cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009120 goto internal_error;
9121 cur->ns = ns;
9122 } else {
9123 /*
9124 * Aquire a normalized ns-decl and add it to the map.
9125 */
9126 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
Daniel Veillardaa6de472008-08-25 14:53:31 +00009127 /* ns-decls on curElem or on destDoc->oldNs */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009128 destParent ? curElem : NULL,
9129 cur->ns, &ns,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009130 &nsMap, depth,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009131 ancestorsOnly,
9132 /* ns-decls must be prefixed for attributes. */
9133 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
9134 goto internal_error;
9135 cur->ns = ns;
9136 }
9137ns_end:
9138 /*
9139 * Further node properties.
9140 * TODO: Is this all?
9141 */
9142 XML_TREE_ADOPT_STR(cur->name)
9143 if (cur->type == XML_ELEMENT_NODE) {
9144 cur->psvi = NULL;
9145 cur->line = 0;
9146 cur->extra = 0;
9147 /*
9148 * Walk attributes.
9149 */
9150 if (cur->properties != NULL) {
9151 /*
9152 * Process first attribute node.
9153 */
9154 cur = (xmlNodePtr) cur->properties;
9155 continue;
9156 }
9157 } else {
9158 /*
9159 * Attributes.
9160 */
9161 if ((sourceDoc != NULL) &&
9162 (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID))
Daniel Veillardaa6de472008-08-25 14:53:31 +00009163 {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009164 xmlRemoveID(sourceDoc, (xmlAttrPtr) cur);
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009165 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009166 ((xmlAttrPtr) cur)->atype = 0;
9167 ((xmlAttrPtr) cur)->psvi = NULL;
9168 }
9169 break;
9170 case XML_TEXT_NODE:
Daniel Veillardaa6de472008-08-25 14:53:31 +00009171 case XML_CDATA_SECTION_NODE:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009172 /*
9173 * This puts the content in the dest dict, only if
9174 * it was previously in the source dict.
9175 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00009176 XML_TREE_ADOPT_STR_2(cur->content)
9177 goto leave_node;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009178 case XML_ENTITY_REF_NODE:
9179 /*
9180 * Remove reference to the entitity-node.
9181 */
9182 cur->content = NULL;
9183 cur->children = NULL;
9184 cur->last = NULL;
9185 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9186 xmlEntityPtr ent;
9187 /*
9188 * Assign new entity-node if available.
9189 */
9190 ent = xmlGetDocEntity(destDoc, cur->name);
9191 if (ent != NULL) {
9192 cur->content = ent->content;
9193 cur->children = (xmlNodePtr) ent;
9194 cur->last = (xmlNodePtr) ent;
9195 }
9196 }
9197 goto leave_node;
9198 case XML_PI_NODE:
9199 XML_TREE_ADOPT_STR(cur->name)
9200 XML_TREE_ADOPT_STR_2(cur->content)
9201 break;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009202 case XML_COMMENT_NODE:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009203 break;
9204 default:
9205 goto internal_error;
9206 }
9207 /*
9208 * Walk the tree.
9209 */
9210 if (cur->children != NULL) {
9211 cur = cur->children;
9212 continue;
9213 }
9214
9215leave_node:
9216 if (cur == node)
9217 break;
9218 if ((cur->type == XML_ELEMENT_NODE) ||
9219 (cur->type == XML_XINCLUDE_START) ||
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009220 (cur->type == XML_XINCLUDE_END))
9221 {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009222 /*
9223 * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
9224 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00009225 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009226 /*
9227 * Pop mappings.
9228 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009229 while ((nsMap->last != NULL) &&
9230 (nsMap->last->depth >= depth))
9231 {
Daniel Veillardaa6de472008-08-25 14:53:31 +00009232 XML_NSMAP_POP(nsMap, mi)
9233 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009234 /*
9235 * Unshadow.
9236 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009237 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009238 if (mi->shadowDepth >= depth)
9239 mi->shadowDepth = -1;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009240 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009241 }
9242 depth--;
9243 }
9244 if (cur->next != NULL)
9245 cur = cur->next;
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009246 else if ((cur->type == XML_ATTRIBUTE_NODE) &&
9247 (cur->parent->children != NULL))
9248 {
9249 cur = cur->parent->children;
9250 } else {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009251 cur = cur->parent;
9252 goto leave_node;
9253 }
9254 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009255
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009256 goto exit;
9257
Daniel Veillardaa6de472008-08-25 14:53:31 +00009258internal_error:
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009259 ret = -1;
9260
9261exit:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009262 /*
9263 * Cleanup.
9264 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009265 if (nsMap != NULL) {
9266 if ((ctxt) && (ctxt->namespaceMap == nsMap)) {
9267 /*
9268 * Just cleanup the map but don't free.
9269 */
9270 if (nsMap->first) {
9271 if (nsMap->pool)
9272 nsMap->last->next = nsMap->pool;
9273 nsMap->pool = nsMap->first;
9274 nsMap->first = NULL;
9275 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009276 } else
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009277 xmlDOMWrapNsMapFree(nsMap);
9278 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009279 return(ret);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009280}
9281
9282/*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009283* xmlDOMWrapCloneNode:
9284* @ctxt: the optional context for custom processing
9285* @sourceDoc: the optional sourceDoc
9286* @node: the node to start with
9287* @resNode: the clone of the given @node
9288* @destDoc: the destination doc
9289* @destParent: the optional new parent of @node in @destDoc
Daniel Veillardb2f8f1d2006-04-28 16:30:48 +00009290* @deep: descend into child if set
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009291* @options: option flags
9292*
9293* References of out-of scope ns-decls are remapped to point to @destDoc:
9294* 1) If @destParent is given, then nsDef entries on element-nodes are used
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009295* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used.
9296* This is the case when you don't know already where the cloned branch
9297* will be added to.
Daniel Veillardaa6de472008-08-25 14:53:31 +00009298*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009299* If @destParent is given, it ensures that the tree is namespace
9300* wellformed by creating additional ns-decls where needed.
9301* Note that, since prefixes of already existent ns-decls can be
9302* shadowed by this process, it could break QNames in attribute
9303* values or element content.
9304* TODO:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009305* 1) What to do with XInclude? Currently this returns an error for XInclude.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009306*
9307* Returns 0 if the operation succeeded,
9308* 1 if a node of unsupported (or not yet supported) type was given,
9309* -1 on API/internal errors.
9310*/
9311
9312int
9313xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt,
9314 xmlDocPtr sourceDoc,
9315 xmlNodePtr node,
9316 xmlNodePtr *resNode,
9317 xmlDocPtr destDoc,
9318 xmlNodePtr destParent,
9319 int deep,
9320 int options ATTRIBUTE_UNUSED)
9321{
9322 int ret = 0;
9323 xmlNodePtr cur, curElem = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009324 xmlNsMapPtr nsMap = NULL;
9325 xmlNsMapItemPtr mi;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009326 xmlNsPtr ns;
9327 int depth = -1;
9328 /* int adoptStr = 1; */
9329 /* gather @parent's ns-decls. */
9330 int parnsdone = 0;
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009331 /*
Daniel Veillardaa6de472008-08-25 14:53:31 +00009332 * @ancestorsOnly:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009333 * TODO: @ancestorsOnly should be set per option.
9334 *
9335 */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009336 int ancestorsOnly = 0;
9337 xmlNodePtr resultClone = NULL, clone = NULL, parentClone = NULL, prevClone = NULL;
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009338 xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL;
9339 xmlDictPtr dict; /* The destination dict */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009340
Daniel Veillard11ce4002006-03-10 00:36:23 +00009341 if ((node == NULL) || (resNode == NULL) || (destDoc == NULL))
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009342 return(-1);
9343 /*
9344 * TODO: Initially we support only element-nodes.
9345 */
9346 if (node->type != XML_ELEMENT_NODE)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009347 return(1);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009348 /*
9349 * Check node->doc sanity.
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009350 */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009351 if ((node->doc != NULL) && (sourceDoc != NULL) &&
9352 (node->doc != sourceDoc)) {
9353 /*
9354 * Might be an XIncluded node.
9355 */
9356 return (-1);
9357 }
9358 if (sourceDoc == NULL)
Daniel Veillardaa6de472008-08-25 14:53:31 +00009359 sourceDoc = node->doc;
Daniel Veillard11ce4002006-03-10 00:36:23 +00009360 if (sourceDoc == NULL)
9361 return (-1);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009362
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009363 dict = destDoc->dict;
9364 /*
9365 * Reuse the namespace map of the context.
9366 */
9367 if (ctxt)
9368 nsMap = (xmlNsMapPtr) ctxt->namespaceMap;
9369
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009370 *resNode = NULL;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009371
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009372 cur = node;
Daniel Veillard3e62adb2012-08-09 14:24:02 +08009373 if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL))
9374 return(-1);
9375
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009376 while (cur != NULL) {
9377 if (cur->doc != sourceDoc) {
9378 /*
9379 * We'll assume XIncluded nodes if the doc differs.
9380 * TODO: Do we need to reconciliate XIncluded nodes?
9381 * TODO: This here returns -1 in this case.
9382 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00009383 goto internal_error;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009384 }
9385 /*
9386 * Create a new node.
9387 */
9388 switch (cur->type) {
9389 case XML_XINCLUDE_START:
9390 case XML_XINCLUDE_END:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009391 /*
9392 * TODO: What to do with XInclude?
9393 */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009394 goto internal_error;
9395 break;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009396 case XML_ELEMENT_NODE:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009397 case XML_TEXT_NODE:
Daniel Veillardaa6de472008-08-25 14:53:31 +00009398 case XML_CDATA_SECTION_NODE:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009399 case XML_COMMENT_NODE:
Daniel Veillardaa6de472008-08-25 14:53:31 +00009400 case XML_PI_NODE:
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009401 case XML_DOCUMENT_FRAG_NODE:
9402 case XML_ENTITY_REF_NODE:
9403 case XML_ENTITY_NODE:
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009404 /*
9405 * Nodes of xmlNode structure.
9406 */
9407 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
9408 if (clone == NULL) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009409 xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating a node");
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009410 goto internal_error;
9411 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009412 memset(clone, 0, sizeof(xmlNode));
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009413 /*
9414 * Set hierachical links.
9415 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00009416 if (resultClone != NULL) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009417 clone->parent = parentClone;
9418 if (prevClone) {
9419 prevClone->next = clone;
9420 clone->prev = prevClone;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009421 } else
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009422 parentClone->children = clone;
9423 } else
9424 resultClone = clone;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009425
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009426 break;
9427 case XML_ATTRIBUTE_NODE:
9428 /*
9429 * Attributes (xmlAttr).
9430 */
9431 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlAttr));
9432 if (clone == NULL) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009433 xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating an attr-node");
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009434 goto internal_error;
9435 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009436 memset(clone, 0, sizeof(xmlAttr));
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009437 /*
9438 * Set hierachical links.
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009439 * TODO: Change this to add to the end of attributes.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009440 */
9441 if (resultClone != NULL) {
9442 clone->parent = parentClone;
9443 if (prevClone) {
9444 prevClone->next = clone;
9445 clone->prev = prevClone;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009446 } else
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009447 parentClone->properties = (xmlAttrPtr) clone;
9448 } else
9449 resultClone = clone;
9450 break;
9451 default:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009452 /*
9453 * TODO QUESTION: Any other nodes expected?
9454 */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009455 goto internal_error;
9456 }
9457
9458 clone->type = cur->type;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009459 clone->doc = destDoc;
9460
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009461 /*
9462 * Clone the name of the node if any.
9463 */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009464 if (cur->name == xmlStringText)
9465 clone->name = xmlStringText;
9466 else if (cur->name == xmlStringTextNoenc)
9467 /*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009468 * NOTE: Although xmlStringTextNoenc is never assigned to a node
9469 * in tree.c, it might be set in Libxslt via
Daniel Veillardaa6de472008-08-25 14:53:31 +00009470 * "xsl:disable-output-escaping".
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009471 */
9472 clone->name = xmlStringTextNoenc;
9473 else if (cur->name == xmlStringComment)
9474 clone->name = xmlStringComment;
9475 else if (cur->name != NULL) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009476 DICT_CONST_COPY(cur->name, clone->name);
Daniel Veillardaa6de472008-08-25 14:53:31 +00009477 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009478
9479 switch (cur->type) {
9480 case XML_XINCLUDE_START:
9481 case XML_XINCLUDE_END:
9482 /*
9483 * TODO
9484 */
9485 return (-1);
9486 case XML_ELEMENT_NODE:
9487 curElem = cur;
9488 depth++;
9489 /*
9490 * Namespace declarations.
9491 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009492 if (cur->nsDef != NULL) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009493 if (! parnsdone) {
9494 if (destParent && (ctxt == NULL)) {
9495 /*
9496 * Gather @parent's in-scope ns-decls.
9497 */
9498 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
9499 destParent) == -1)
Daniel Veillardaa6de472008-08-25 14:53:31 +00009500 goto internal_error;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009501 }
9502 parnsdone = 1;
9503 }
9504 /*
9505 * Clone namespace declarations.
9506 */
9507 cloneNsDefSlot = &(clone->nsDef);
9508 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
9509 /*
9510 * Create a new xmlNs.
9511 */
9512 cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
9513 if (cloneNs == NULL) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009514 xmlTreeErrMemory("xmlDOMWrapCloneNode(): "
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009515 "allocating namespace");
9516 return(-1);
9517 }
9518 memset(cloneNs, 0, sizeof(xmlNs));
9519 cloneNs->type = XML_LOCAL_NAMESPACE;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009520
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009521 if (ns->href != NULL)
9522 cloneNs->href = xmlStrdup(ns->href);
9523 if (ns->prefix != NULL)
9524 cloneNs->prefix = xmlStrdup(ns->prefix);
9525
9526 *cloneNsDefSlot = cloneNs;
9527 cloneNsDefSlot = &(cloneNs->next);
9528
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009529 /*
9530 * Note that for custom handling of ns-references,
9531 * the ns-decls need not be stored in the ns-map,
9532 * since they won't be referenced by node->ns.
9533 */
9534 if ((ctxt == NULL) ||
9535 (ctxt->getNsForNodeFunc == NULL))
9536 {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009537 /*
9538 * Does it shadow any ns-decl?
9539 */
9540 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00009541 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009542 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
9543 (mi->shadowDepth == -1) &&
9544 ((ns->prefix == mi->newNs->prefix) ||
9545 xmlStrEqual(ns->prefix,
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009546 mi->newNs->prefix))) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009547 /*
9548 * Mark as shadowed at the current
9549 * depth.
9550 */
9551 mi->shadowDepth = depth;
9552 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009553 }
9554 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009555 /*
9556 * Push mapping.
9557 */
9558 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
9559 ns, cloneNs, depth) == NULL)
9560 goto internal_error;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009561 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009562 }
9563 }
9564 /* cur->ns will be processed further down. */
9565 break;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009566 case XML_ATTRIBUTE_NODE:
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009567 /* IDs will be processed further down. */
9568 /* cur->ns will be processed further down. */
9569 break;
9570 case XML_TEXT_NODE:
9571 case XML_CDATA_SECTION_NODE:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009572 /*
9573 * Note that this will also cover the values of attributes.
9574 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00009575 DICT_COPY(cur->content, clone->content);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009576 goto leave_node;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009577 case XML_ENTITY_NODE:
9578 /* TODO: What to do here? */
9579 goto leave_node;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009580 case XML_ENTITY_REF_NODE:
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009581 if (sourceDoc != destDoc) {
9582 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9583 xmlEntityPtr ent;
9584 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009585 * Different doc: Assign new entity-node if available.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009586 */
9587 ent = xmlGetDocEntity(destDoc, cur->name);
9588 if (ent != NULL) {
9589 clone->content = ent->content;
9590 clone->children = (xmlNodePtr) ent;
9591 clone->last = (xmlNodePtr) ent;
9592 }
9593 }
9594 } else {
9595 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009596 * Same doc: Use the current node's entity declaration
9597 * and value.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009598 */
9599 clone->content = cur->content;
9600 clone->children = cur->children;
9601 clone->last = cur->last;
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009602 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009603 goto leave_node;
9604 case XML_PI_NODE:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009605 DICT_COPY(cur->content, clone->content);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009606 goto leave_node;
9607 case XML_COMMENT_NODE:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009608 DICT_COPY(cur->content, clone->content);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009609 goto leave_node;
9610 default:
9611 goto internal_error;
9612 }
9613
9614 if (cur->ns == NULL)
9615 goto end_ns_reference;
9616
9617/* handle_ns_reference: */
9618 /*
9619 ** The following will take care of references to ns-decls ********
Daniel Veillardaa6de472008-08-25 14:53:31 +00009620 ** and is intended only for element- and attribute-nodes.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009621 **
9622 */
9623 if (! parnsdone) {
9624 if (destParent && (ctxt == NULL)) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009625 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1)
Daniel Veillardaa6de472008-08-25 14:53:31 +00009626 goto internal_error;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009627 }
9628 parnsdone = 1;
9629 }
9630 /*
9631 * Adopt ns-references.
9632 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009633 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009634 /*
9635 * Search for a mapping.
9636 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00009637 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009638 if ((mi->shadowDepth == -1) &&
9639 (cur->ns == mi->oldNs)) {
9640 /*
9641 * This is the nice case: a mapping was found.
9642 */
9643 clone->ns = mi->newNs;
9644 goto end_ns_reference;
9645 }
9646 }
9647 }
9648 /*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009649 * No matching namespace in scope. We need a new one.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009650 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009651 if ((ctxt != NULL) && (ctxt->getNsForNodeFunc != NULL)) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009652 /*
9653 * User-defined behaviour.
9654 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009655 ns = ctxt->getNsForNodeFunc(ctxt, cur,
9656 cur->ns->href, cur->ns->prefix);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009657 /*
9658 * Add user's mapping.
9659 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009660 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009661 cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
9662 goto internal_error;
9663 clone->ns = ns;
9664 } else {
9665 /*
9666 * Aquire a normalized ns-decl and add it to the map.
9667 */
9668 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
Daniel Veillardaa6de472008-08-25 14:53:31 +00009669 /* ns-decls on curElem or on destDoc->oldNs */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009670 destParent ? curElem : NULL,
9671 cur->ns, &ns,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009672 &nsMap, depth,
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009673 /* if we need to search only in the ancestor-axis */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009674 ancestorsOnly,
9675 /* ns-decls must be prefixed for attributes. */
9676 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
9677 goto internal_error;
9678 clone->ns = ns;
9679 }
9680
9681end_ns_reference:
9682
9683 /*
9684 * Some post-processing.
9685 *
9686 * Handle ID attributes.
9687 */
9688 if ((clone->type == XML_ATTRIBUTE_NODE) &&
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009689 (clone->parent != NULL))
9690 {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009691 if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00009692
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009693 xmlChar *idVal;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009694
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009695 idVal = xmlNodeListGetString(cur->doc, cur->children, 1);
9696 if (idVal != NULL) {
9697 if (xmlAddID(NULL, destDoc, idVal, (xmlAttrPtr) cur) == NULL) {
9698 /* TODO: error message. */
9699 xmlFree(idVal);
9700 goto internal_error;
9701 }
9702 xmlFree(idVal);
9703 }
9704 }
9705 }
9706 /*
9707 **
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009708 ** The following will traverse the tree **************************
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009709 **
Daniel Veillardaa6de472008-08-25 14:53:31 +00009710 *
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009711 * Walk the element's attributes before descending into child-nodes.
9712 */
9713 if ((cur->type == XML_ELEMENT_NODE) && (cur->properties != NULL)) {
9714 prevClone = NULL;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009715 parentClone = clone;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009716 cur = (xmlNodePtr) cur->properties;
9717 continue;
9718 }
9719into_content:
9720 /*
9721 * Descend into child-nodes.
9722 */
9723 if (cur->children != NULL) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009724 if (deep || (cur->type == XML_ATTRIBUTE_NODE)) {
9725 prevClone = NULL;
9726 parentClone = clone;
9727 cur = cur->children;
9728 continue;
9729 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009730 }
9731
9732leave_node:
9733 /*
9734 * At this point we are done with the node, its content
9735 * and an element-nodes's attribute-nodes.
9736 */
9737 if (cur == node)
9738 break;
9739 if ((cur->type == XML_ELEMENT_NODE) ||
9740 (cur->type == XML_XINCLUDE_START) ||
9741 (cur->type == XML_XINCLUDE_END)) {
9742 /*
9743 * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
9744 */
Daniel Veillardaa6de472008-08-25 14:53:31 +00009745 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009746 /*
9747 * Pop mappings.
9748 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009749 while ((nsMap->last != NULL) &&
9750 (nsMap->last->depth >= depth))
9751 {
Daniel Veillardaa6de472008-08-25 14:53:31 +00009752 XML_NSMAP_POP(nsMap, mi)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009753 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009754 /*
9755 * Unshadow.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009756 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009757 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009758 if (mi->shadowDepth >= depth)
9759 mi->shadowDepth = -1;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009760 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009761 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009762 depth--;
9763 }
9764 if (cur->next != NULL) {
9765 prevClone = clone;
9766 cur = cur->next;
9767 } else if (cur->type != XML_ATTRIBUTE_NODE) {
9768 /*
9769 * Set clone->last.
9770 */
Daniel Veillard11ce4002006-03-10 00:36:23 +00009771 if (clone->parent != NULL)
9772 clone->parent->last = clone;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009773 clone = clone->parent;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009774 parentClone = clone->parent;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009775 /*
9776 * Process parent --> next;
9777 */
9778 cur = cur->parent;
9779 goto leave_node;
9780 } else {
9781 /* This is for attributes only. */
9782 clone = clone->parent;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009783 parentClone = clone->parent;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009784 /*
9785 * Process parent-element --> children.
9786 */
9787 cur = cur->parent;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009788 goto into_content;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009789 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009790 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009791 goto exit;
9792
9793internal_error:
9794 ret = -1;
9795
9796exit:
9797 /*
9798 * Cleanup.
9799 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009800 if (nsMap != NULL) {
9801 if ((ctxt) && (ctxt->namespaceMap == nsMap)) {
9802 /*
9803 * Just cleanup the map but don't free.
9804 */
9805 if (nsMap->first) {
9806 if (nsMap->pool)
9807 nsMap->last->next = nsMap->pool;
9808 nsMap->pool = nsMap->first;
9809 nsMap->first = NULL;
9810 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009811 } else
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009812 xmlDOMWrapNsMapFree(nsMap);
9813 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009814 /*
9815 * TODO: Should we try a cleanup of the cloned node in case of a
9816 * fatal error?
9817 */
9818 *resNode = resultClone;
9819 return (ret);
9820}
9821
9822/*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009823* xmlDOMWrapAdoptAttr:
9824* @ctxt: the optional context for custom processing
9825* @sourceDoc: the optional source document of attr
9826* @attr: the attribute-node to be adopted
9827* @destDoc: the destination doc for adoption
9828* @destParent: the optional new parent of @attr in @destDoc
9829* @options: option flags
9830*
9831* @attr is adopted by @destDoc.
9832* Ensures that ns-references point to @destDoc: either to
9833* elements->nsDef entries if @destParent is given, or to
9834* @destDoc->oldNs otherwise.
9835*
9836* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
9837*/
9838static int
9839xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt,
9840 xmlDocPtr sourceDoc,
9841 xmlAttrPtr attr,
9842 xmlDocPtr destDoc,
9843 xmlNodePtr destParent,
9844 int options ATTRIBUTE_UNUSED)
9845{
9846 xmlNodePtr cur;
9847 int adoptStr = 1;
9848
9849 if ((attr == NULL) || (destDoc == NULL))
9850 return (-1);
Daniel Veillardaa6de472008-08-25 14:53:31 +00009851
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009852 attr->doc = destDoc;
9853 if (attr->ns != NULL) {
9854 xmlNsPtr ns = NULL;
9855
9856 if (ctxt != NULL) {
9857 /* TODO: User defined. */
9858 }
9859 /* XML Namespace. */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009860 if (IS_STR_XML(attr->ns->prefix)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009861 ns = xmlTreeEnsureXMLDecl(destDoc);
9862 } else if (destParent == NULL) {
9863 /*
9864 * Store in @destDoc->oldNs.
9865 */
9866 ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix);
9867 } else {
9868 /*
9869 * Declare on @destParent.
9870 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009871 if (xmlSearchNsByNamespaceStrict(destDoc, destParent, attr->ns->href,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009872 &ns, 1) == -1)
9873 goto internal_error;
9874 if (ns == NULL) {
9875 ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent,
9876 attr->ns->href, attr->ns->prefix, 1);
9877 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00009878 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009879 if (ns == NULL)
9880 goto internal_error;
9881 attr->ns = ns;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009882 }
9883
9884 XML_TREE_ADOPT_STR(attr->name);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009885 attr->atype = 0;
9886 attr->psvi = NULL;
9887 /*
9888 * Walk content.
9889 */
9890 if (attr->children == NULL)
9891 return (0);
9892 cur = attr->children;
Daniel Veillard3e62adb2012-08-09 14:24:02 +08009893 if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL))
9894 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009895 while (cur != NULL) {
9896 cur->doc = destDoc;
9897 switch (cur->type) {
9898 case XML_TEXT_NODE:
9899 case XML_CDATA_SECTION_NODE:
9900 XML_TREE_ADOPT_STR_2(cur->content)
Daniel Veillardaa6de472008-08-25 14:53:31 +00009901 break;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009902 case XML_ENTITY_REF_NODE:
9903 /*
9904 * Remove reference to the entitity-node.
9905 */
9906 cur->content = NULL;
9907 cur->children = NULL;
9908 cur->last = NULL;
9909 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9910 xmlEntityPtr ent;
9911 /*
9912 * Assign new entity-node if available.
9913 */
9914 ent = xmlGetDocEntity(destDoc, cur->name);
9915 if (ent != NULL) {
9916 cur->content = ent->content;
9917 cur->children = (xmlNodePtr) ent;
9918 cur->last = (xmlNodePtr) ent;
Daniel Veillardaa6de472008-08-25 14:53:31 +00009919 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009920 }
9921 break;
9922 default:
9923 break;
9924 }
9925 if (cur->children != NULL) {
9926 cur = cur->children;
9927 continue;
9928 }
9929next_sibling:
9930 if (cur == (xmlNodePtr) attr)
9931 break;
9932 if (cur->next != NULL)
9933 cur = cur->next;
9934 else {
9935 cur = cur->parent;
9936 goto next_sibling;
9937 }
9938 }
9939 return (0);
9940internal_error:
9941 return (-1);
9942}
9943
9944/*
9945* xmlDOMWrapAdoptNode:
9946* @ctxt: the optional context for custom processing
9947* @sourceDoc: the optional sourceDoc
9948* @node: the node to start with
9949* @destDoc: the destination doc
Kasimier T. Buchcik4d9c9482005-06-27 15:04:46 +00009950* @destParent: the optional new parent of @node in @destDoc
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009951* @options: option flags
9952*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009953* References of out-of scope ns-decls are remapped to point to @destDoc:
9954* 1) If @destParent is given, then nsDef entries on element-nodes are used
9955* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used
9956* This is the case when you have an unliked node and just want to move it
Daniel Veillardaa6de472008-08-25 14:53:31 +00009957* to the context of
9958*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009959* If @destParent is given, it ensures that the tree is namespace
9960* wellformed by creating additional ns-decls where needed.
9961* Note that, since prefixes of already existent ns-decls can be
9962* shadowed by this process, it could break QNames in attribute
9963* values or element content.
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009964* NOTE: This function was not intensively tested.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009965*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009966* Returns 0 if the operation succeeded,
9967* 1 if a node of unsupported type was given,
9968* 2 if a node of not yet supported type was given and
9969* -1 on API/internal errors.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009970*/
9971int
9972xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt,
9973 xmlDocPtr sourceDoc,
9974 xmlNodePtr node,
Daniel Veillardaa6de472008-08-25 14:53:31 +00009975 xmlDocPtr destDoc,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009976 xmlNodePtr destParent,
9977 int options)
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009978{
Daniel Veillard3e62adb2012-08-09 14:24:02 +08009979 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) ||
9980 (destDoc == NULL) ||
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009981 ((destParent != NULL) && (destParent->doc != destDoc)))
9982 return(-1);
9983 /*
9984 * Check node->doc sanity.
Daniel Veillardaa6de472008-08-25 14:53:31 +00009985 */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009986 if ((node->doc != NULL) && (sourceDoc != NULL) &&
9987 (node->doc != sourceDoc)) {
9988 /*
9989 * Might be an XIncluded node.
9990 */
9991 return (-1);
9992 }
9993 if (sourceDoc == NULL)
9994 sourceDoc = node->doc;
9995 if (sourceDoc == destDoc)
9996 return (-1);
9997 switch (node->type) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00009998 case XML_ELEMENT_NODE:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009999 case XML_ATTRIBUTE_NODE:
10000 case XML_TEXT_NODE:
10001 case XML_CDATA_SECTION_NODE:
10002 case XML_ENTITY_REF_NODE:
10003 case XML_PI_NODE:
10004 case XML_COMMENT_NODE:
10005 break;
10006 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +000010007 /* TODO: Support document-fragment-nodes. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +000010008 return (2);
10009 default:
10010 return (1);
10011 }
10012 /*
10013 * Unlink only if @node was not already added to @destParent.
10014 */
10015 if ((node->parent != NULL) && (destParent != node->parent))
10016 xmlUnlinkNode(node);
10017
10018 if (node->type == XML_ELEMENT_NODE) {
10019 return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node,
10020 destDoc, destParent, options));
10021 } else if (node->type == XML_ATTRIBUTE_NODE) {
10022 return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc,
10023 (xmlAttrPtr) node, destDoc, destParent, options));
Daniel Veillardaa6de472008-08-25 14:53:31 +000010024 } else {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +000010025 xmlNodePtr cur = node;
10026 int adoptStr = 1;
10027
10028 cur->doc = destDoc;
10029 /*
10030 * Optimize string adoption.
10031 */
10032 if ((sourceDoc != NULL) &&
10033 (sourceDoc->dict == destDoc->dict))
10034 adoptStr = 0;
10035 switch (node->type) {
Daniel Veillardaa6de472008-08-25 14:53:31 +000010036 case XML_TEXT_NODE:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +000010037 case XML_CDATA_SECTION_NODE:
10038 XML_TREE_ADOPT_STR_2(node->content)
10039 break;
10040 case XML_ENTITY_REF_NODE:
10041 /*
10042 * Remove reference to the entitity-node.
10043 */
10044 node->content = NULL;
10045 node->children = NULL;
10046 node->last = NULL;
10047 if ((destDoc->intSubset) || (destDoc->extSubset)) {
10048 xmlEntityPtr ent;
10049 /*
10050 * Assign new entity-node if available.
10051 */
10052 ent = xmlGetDocEntity(destDoc, node->name);
10053 if (ent != NULL) {
10054 node->content = ent->content;
10055 node->children = (xmlNodePtr) ent;
10056 node->last = (xmlNodePtr) ent;
10057 }
10058 }
10059 XML_TREE_ADOPT_STR(node->name)
10060 break;
Daniel Veillard7e21fd12005-07-03 21:44:07 +000010061 case XML_PI_NODE: {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +000010062 XML_TREE_ADOPT_STR(node->name)
10063 XML_TREE_ADOPT_STR_2(node->content)
10064 break;
Daniel Veillard7e21fd12005-07-03 21:44:07 +000010065 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +000010066 default:
10067 break;
10068 }
Daniel Veillardaa6de472008-08-25 14:53:31 +000010069 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +000010070 return (0);
10071}
10072
Daniel Veillard5d4644e2005-04-01 13:11:58 +000010073#define bottom_tree
10074#include "elfgcchack.h"