blob: fb1704240750cf20e26cf01c5e957790e277f32c [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
Daniel Veillardd5c2f922002-11-21 14:10:52 +00004 * References:
5 * XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
6 *
Owen Taylor3473f882001-02-23 17:55:21 +00007 * See Copyright for the status of this software.
8 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00009 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000010 *
Owen Taylor3473f882001-02-23 17:55:21 +000011 */
12
Daniel Veillard34ce8be2002-03-18 19:37:11 +000013#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000014#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000015
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24#ifdef HAVE_ZLIB_H
25#include <zlib.h>
26#endif
27
28#include <libxml/xmlmemory.h>
29#include <libxml/tree.h>
30#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000031#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000032#include <libxml/entities.h>
33#include <libxml/valid.h>
34#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000035#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000036#include <libxml/globals.h>
Daniel Veillardd5c2f922002-11-21 14:10:52 +000037#ifdef LIBXML_HTML_ENABLED
38#include <libxml/HTMLtree.h>
39#endif
William M. Brack1d8c9b22004-12-25 10:14:57 +000040#ifdef LIBXML_DEBUG_ENABLED
41#include <libxml/debugXML.h>
42#endif
Owen Taylor3473f882001-02-23 17:55:21 +000043
Daniel Veillarda880b122003-04-21 21:36:41 +000044int __xmlRegisterCallbacks = 0;
45
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +000046/************************************************************************
47 * *
48 * Forward declarations *
49 * *
50 ************************************************************************/
51
Daniel Veillard56a4cb82001-03-24 17:00:36 +000052xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
53
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +000054static xmlChar* xmlGetPropNodeValueInternal(xmlAttrPtr prop);
55
Daniel Veillard56a4cb82001-03-24 17:00:36 +000056/************************************************************************
57 * *
Daniel Veillard18ec16e2003-10-07 23:16:40 +000058 * Tree memory error handler *
59 * *
60 ************************************************************************/
61/**
62 * xmlTreeErrMemory:
63 * @extra: extra informations
64 *
65 * Handle an out of memory condition
66 */
67static void
68xmlTreeErrMemory(const char *extra)
69{
70 __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
71}
72
73/**
74 * xmlTreeErr:
75 * @code: the error number
76 * @extra: extra informations
77 *
78 * Handle an out of memory condition
79 */
80static void
81xmlTreeErr(int code, xmlNodePtr node, const char *extra)
82{
83 const char *msg = NULL;
84
85 switch(code) {
86 case XML_TREE_INVALID_HEX:
Daniel Veillardac996a12004-07-30 12:02:58 +000087 msg = "invalid hexadecimal character value\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000088 break;
89 case XML_TREE_INVALID_DEC:
Daniel Veillardac996a12004-07-30 12:02:58 +000090 msg = "invalid decimal character value\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000091 break;
92 case XML_TREE_UNTERMINATED_ENTITY:
Daniel Veillardac996a12004-07-30 12:02:58 +000093 msg = "unterminated entity reference %15s\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000094 break;
95 default:
Daniel Veillardac996a12004-07-30 12:02:58 +000096 msg = "unexpected error number\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000097 }
98 __xmlSimpleError(XML_FROM_TREE, code, node, msg, extra);
99}
100
101/************************************************************************
102 * *
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000103 * A few static variables and macros *
104 * *
105 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +0000106/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +0000107const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +0000108/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +0000109const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +0000110 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +0000111/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +0000112const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
113
Owen Taylor3473f882001-02-23 17:55:21 +0000114static int xmlCompressMode = 0;
115static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000116
Owen Taylor3473f882001-02-23 17:55:21 +0000117#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
118 xmlNodePtr ulccur = (n)->children; \
119 if (ulccur == NULL) { \
120 (n)->last = NULL; \
121 } else { \
122 while (ulccur->next != NULL) { \
123 ulccur->parent = (n); \
124 ulccur = ulccur->next; \
125 } \
126 ulccur->parent = (n); \
127 (n)->last = ulccur; \
128}}
129
Kasimier T. Buchcik44353412006-03-06 13:26:16 +0000130#define IS_STR_XML(str) ((str != NULL) && (str[0] == 'x') && \
131 (str[1] == 'm') && (str[2] == 'l') && (str[3] == 0))
132
Owen Taylor3473f882001-02-23 17:55:21 +0000133/* #define DEBUG_BUFFER */
134/* #define DEBUG_TREE */
135
136/************************************************************************
137 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000138 * Functions to move to entities.c once the *
139 * API freeze is smoothen and they can be made public. *
140 * *
141 ************************************************************************/
142#include <libxml/hash.h>
143
Daniel Veillard652327a2003-09-29 18:02:38 +0000144#ifdef LIBXML_TREE_ENABLED
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000145/**
146 * xmlGetEntityFromDtd:
147 * @dtd: A pointer to the DTD to search
148 * @name: The entity name
149 *
150 * Do an entity lookup in the DTD entity hash table and
151 * return the corresponding entity, if found.
152 *
153 * Returns A pointer to the entity structure or NULL if not found.
154 */
155static xmlEntityPtr
156xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
157 xmlEntitiesTablePtr table;
158
159 if((dtd != NULL) && (dtd->entities != NULL)) {
160 table = (xmlEntitiesTablePtr) dtd->entities;
161 return((xmlEntityPtr) xmlHashLookup(table, name));
162 /* return(xmlGetEntityFromTable(table, name)); */
163 }
164 return(NULL);
165}
166/**
167 * xmlGetParameterEntityFromDtd:
168 * @dtd: A pointer to the DTD to search
169 * @name: The entity name
170 *
171 * Do an entity lookup in the DTD pararmeter entity hash table and
172 * return the corresponding entity, if found.
173 *
174 * Returns A pointer to the entity structure or NULL if not found.
175 */
176static xmlEntityPtr
177xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
178 xmlEntitiesTablePtr table;
179
180 if ((dtd != NULL) && (dtd->pentities != NULL)) {
181 table = (xmlEntitiesTablePtr) dtd->pentities;
182 return((xmlEntityPtr) xmlHashLookup(table, name));
183 /* return(xmlGetEntityFromTable(table, name)); */
184 }
185 return(NULL);
186}
Daniel Veillard652327a2003-09-29 18:02:38 +0000187#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000188
189/************************************************************************
190 * *
Daniel Veillardc00cda82003-04-07 10:22:39 +0000191 * QName handling helper *
192 * *
193 ************************************************************************/
194
195/**
196 * xmlBuildQName:
197 * @ncname: the Name
198 * @prefix: the prefix
199 * @memory: preallocated memory
200 * @len: preallocated memory length
201 *
202 * Builds the QName @prefix:@ncname in @memory if there is enough space
203 * and prefix is not NULL nor empty, otherwise allocate a new string.
204 * If prefix is NULL or empty it returns ncname.
205 *
206 * Returns the new string which must be freed by the caller if different from
207 * @memory and @ncname or NULL in case of error
208 */
209xmlChar *
210xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
211 xmlChar *memory, int len) {
212 int lenn, lenp;
213 xmlChar *ret;
214
Daniel Veillard3b7840c2003-09-11 23:42:01 +0000215 if (ncname == NULL) return(NULL);
216 if (prefix == NULL) return((xmlChar *) ncname);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000217
218 lenn = strlen((char *) ncname);
219 lenp = strlen((char *) prefix);
220
221 if ((memory == NULL) || (len < lenn + lenp + 2)) {
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000222 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000223 if (ret == NULL) {
224 xmlTreeErrMemory("building QName");
225 return(NULL);
226 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000227 } else {
228 ret = memory;
229 }
230 memcpy(&ret[0], prefix, lenp);
231 ret[lenp] = ':';
232 memcpy(&ret[lenp + 1], ncname, lenn);
233 ret[lenn + lenp + 1] = 0;
234 return(ret);
235}
236
237/**
238 * xmlSplitQName2:
239 * @name: the full QName
240 * @prefix: a xmlChar **
241 *
242 * parse an XML qualified name string
243 *
244 * [NS 5] QName ::= (Prefix ':')? LocalPart
245 *
246 * [NS 6] Prefix ::= NCName
247 *
248 * [NS 7] LocalPart ::= NCName
249 *
250 * Returns NULL if not a QName, otherwise the local part, and prefix
251 * is updated to get the Prefix if any.
252 */
253
254xmlChar *
255xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
256 int len = 0;
257 xmlChar *ret = NULL;
258
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000259 if (prefix == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000260 *prefix = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000261 if (name == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000262
263#ifndef XML_XML_NAMESPACE
264 /* xml: prefix is not really a namespace */
265 if ((name[0] == 'x') && (name[1] == 'm') &&
266 (name[2] == 'l') && (name[3] == ':'))
267 return(NULL);
268#endif
269
270 /* nasty but valid */
271 if (name[0] == ':')
272 return(NULL);
273
274 /*
275 * we are not trying to validate but just to cut, and yes it will
276 * work even if this is as set of UTF-8 encoded chars
277 */
278 while ((name[len] != 0) && (name[len] != ':'))
279 len++;
280
281 if (name[len] == 0)
282 return(NULL);
283
284 *prefix = xmlStrndup(name, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000285 if (*prefix == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000286 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000287 return(NULL);
288 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000289 ret = xmlStrdup(&name[len + 1]);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000290 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000291 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000292 if (*prefix != NULL) {
293 xmlFree(*prefix);
294 *prefix = NULL;
295 }
296 return(NULL);
297 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000298
299 return(ret);
300}
301
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000302/**
303 * xmlSplitQName3:
304 * @name: the full QName
305 * @len: an int *
306 *
307 * parse an XML qualified name string,i
308 *
309 * returns NULL if it is not a Qualified Name, otherwise, update len
310 * with the lenght in byte of the prefix and return a pointer
Daniel Veillard54f9a4f2005-09-03 13:28:24 +0000311 * to the start of the name without the prefix
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000312 */
313
314const xmlChar *
315xmlSplitQName3(const xmlChar *name, int *len) {
316 int l = 0;
317
318 if (name == NULL) return(NULL);
319 if (len == NULL) return(NULL);
320
321 /* nasty but valid */
322 if (name[0] == ':')
323 return(NULL);
324
325 /*
326 * we are not trying to validate but just to cut, and yes it will
327 * work even if this is as set of UTF-8 encoded chars
328 */
329 while ((name[l] != 0) && (name[l] != ':'))
330 l++;
331
332 if (name[l] == 0)
333 return(NULL);
334
335 *len = l;
336
337 return(&name[l+1]);
338}
339
Daniel Veillardc00cda82003-04-07 10:22:39 +0000340/************************************************************************
341 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000342 * Check Name, NCName and QName strings *
343 * *
344 ************************************************************************/
345
346#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
347
Daniel Veillardf1a27c62006-10-13 22:33:03 +0000348#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 +0000349/**
350 * xmlValidateNCName:
351 * @value: the value to check
352 * @space: allow spaces in front and end of the string
353 *
354 * Check that a value conforms to the lexical space of NCName
355 *
356 * Returns 0 if this validates, a positive error code number otherwise
357 * and -1 in case of internal or API error.
358 */
359int
360xmlValidateNCName(const xmlChar *value, int space) {
361 const xmlChar *cur = value;
362 int c,l;
363
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000364 if (value == NULL)
365 return(-1);
366
Daniel Veillardd2298792003-02-14 16:54:11 +0000367 /*
368 * First quick algorithm for ASCII range
369 */
370 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000371 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000372 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
373 (*cur == '_'))
374 cur++;
375 else
376 goto try_complex;
377 while (((*cur >= 'a') && (*cur <= 'z')) ||
378 ((*cur >= 'A') && (*cur <= 'Z')) ||
379 ((*cur >= '0') && (*cur <= '9')) ||
380 (*cur == '_') || (*cur == '-') || (*cur == '.'))
381 cur++;
382 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000383 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000384 if (*cur == 0)
385 return(0);
386
387try_complex:
388 /*
389 * Second check for chars outside the ASCII range
390 */
391 cur = value;
392 c = CUR_SCHAR(cur, l);
393 if (space) {
394 while (IS_BLANK(c)) {
395 cur += l;
396 c = CUR_SCHAR(cur, l);
397 }
398 }
William M. Brack871611b2003-10-18 04:53:14 +0000399 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000400 return(1);
401 cur += l;
402 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000403 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
404 (c == '-') || (c == '_') || IS_COMBINING(c) ||
405 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000406 cur += l;
407 c = CUR_SCHAR(cur, l);
408 }
409 if (space) {
410 while (IS_BLANK(c)) {
411 cur += l;
412 c = CUR_SCHAR(cur, l);
413 }
414 }
415 if (c != 0)
416 return(1);
417
418 return(0);
419}
Daniel Veillard2156d432004-03-04 15:59:36 +0000420#endif
Daniel Veillardd2298792003-02-14 16:54:11 +0000421
Daniel Veillard2156d432004-03-04 15:59:36 +0000422#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000423/**
424 * xmlValidateQName:
425 * @value: the value to check
426 * @space: allow spaces in front and end of the string
427 *
428 * Check that a value conforms to the lexical space of QName
429 *
430 * Returns 0 if this validates, a positive error code number otherwise
431 * and -1 in case of internal or API error.
432 */
433int
434xmlValidateQName(const xmlChar *value, int space) {
435 const xmlChar *cur = value;
436 int c,l;
437
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000438 if (value == NULL)
439 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +0000440 /*
441 * First quick algorithm for ASCII range
442 */
443 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000444 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000445 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
446 (*cur == '_'))
447 cur++;
448 else
449 goto try_complex;
450 while (((*cur >= 'a') && (*cur <= 'z')) ||
451 ((*cur >= 'A') && (*cur <= 'Z')) ||
452 ((*cur >= '0') && (*cur <= '9')) ||
453 (*cur == '_') || (*cur == '-') || (*cur == '.'))
454 cur++;
455 if (*cur == ':') {
456 cur++;
457 if (((*cur >= 'a') && (*cur <= 'z')) ||
458 ((*cur >= 'A') && (*cur <= 'Z')) ||
459 (*cur == '_'))
460 cur++;
461 else
462 goto try_complex;
463 while (((*cur >= 'a') && (*cur <= 'z')) ||
464 ((*cur >= 'A') && (*cur <= 'Z')) ||
465 ((*cur >= '0') && (*cur <= '9')) ||
466 (*cur == '_') || (*cur == '-') || (*cur == '.'))
467 cur++;
468 }
469 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000470 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000471 if (*cur == 0)
472 return(0);
473
474try_complex:
475 /*
476 * Second check for chars outside the ASCII range
477 */
478 cur = value;
479 c = CUR_SCHAR(cur, l);
480 if (space) {
481 while (IS_BLANK(c)) {
482 cur += l;
483 c = CUR_SCHAR(cur, l);
484 }
485 }
William M. Brack871611b2003-10-18 04:53:14 +0000486 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000487 return(1);
488 cur += l;
489 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000490 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
491 (c == '-') || (c == '_') || IS_COMBINING(c) ||
492 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000493 cur += l;
494 c = CUR_SCHAR(cur, l);
495 }
496 if (c == ':') {
497 cur += l;
498 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000499 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000500 return(1);
501 cur += l;
502 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000503 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
504 (c == '-') || (c == '_') || IS_COMBINING(c) ||
505 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000506 cur += l;
507 c = CUR_SCHAR(cur, l);
508 }
509 }
510 if (space) {
511 while (IS_BLANK(c)) {
512 cur += l;
513 c = CUR_SCHAR(cur, l);
514 }
515 }
516 if (c != 0)
517 return(1);
518 return(0);
519}
520
521/**
522 * xmlValidateName:
523 * @value: the value to check
524 * @space: allow spaces in front and end of the string
525 *
526 * Check that a value conforms to the lexical space of Name
527 *
528 * Returns 0 if this validates, a positive error code number otherwise
529 * and -1 in case of internal or API error.
530 */
531int
532xmlValidateName(const xmlChar *value, int space) {
533 const xmlChar *cur = value;
534 int c,l;
535
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000536 if (value == NULL)
537 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +0000538 /*
539 * First quick algorithm for ASCII range
540 */
541 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000542 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000543 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
544 (*cur == '_') || (*cur == ':'))
545 cur++;
546 else
547 goto try_complex;
548 while (((*cur >= 'a') && (*cur <= 'z')) ||
549 ((*cur >= 'A') && (*cur <= 'Z')) ||
550 ((*cur >= '0') && (*cur <= '9')) ||
551 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
552 cur++;
553 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000554 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000555 if (*cur == 0)
556 return(0);
557
558try_complex:
559 /*
560 * Second check for chars outside the ASCII range
561 */
562 cur = value;
563 c = CUR_SCHAR(cur, l);
564 if (space) {
565 while (IS_BLANK(c)) {
566 cur += l;
567 c = CUR_SCHAR(cur, l);
568 }
569 }
William M. Brack871611b2003-10-18 04:53:14 +0000570 if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000571 return(1);
572 cur += l;
573 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000574 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
575 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000576 cur += l;
577 c = CUR_SCHAR(cur, l);
578 }
579 if (space) {
580 while (IS_BLANK(c)) {
581 cur += l;
582 c = CUR_SCHAR(cur, l);
583 }
584 }
585 if (c != 0)
586 return(1);
587 return(0);
588}
589
Daniel Veillardd4310742003-02-18 21:12:46 +0000590/**
591 * xmlValidateNMToken:
592 * @value: the value to check
593 * @space: allow spaces in front and end of the string
594 *
595 * Check that a value conforms to the lexical space of NMToken
596 *
597 * Returns 0 if this validates, a positive error code number otherwise
598 * and -1 in case of internal or API error.
599 */
600int
601xmlValidateNMToken(const xmlChar *value, int space) {
602 const xmlChar *cur = value;
603 int c,l;
604
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000605 if (value == NULL)
606 return(-1);
Daniel Veillardd4310742003-02-18 21:12:46 +0000607 /*
608 * First quick algorithm for ASCII range
609 */
610 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000611 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000612 if (((*cur >= 'a') && (*cur <= 'z')) ||
613 ((*cur >= 'A') && (*cur <= 'Z')) ||
614 ((*cur >= '0') && (*cur <= '9')) ||
615 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
616 cur++;
617 else
618 goto try_complex;
619 while (((*cur >= 'a') && (*cur <= 'z')) ||
620 ((*cur >= 'A') && (*cur <= 'Z')) ||
621 ((*cur >= '0') && (*cur <= '9')) ||
622 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
623 cur++;
624 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000625 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000626 if (*cur == 0)
627 return(0);
628
629try_complex:
630 /*
631 * Second check for chars outside the ASCII range
632 */
633 cur = value;
634 c = CUR_SCHAR(cur, l);
635 if (space) {
636 while (IS_BLANK(c)) {
637 cur += l;
638 c = CUR_SCHAR(cur, l);
639 }
640 }
William M. Brack871611b2003-10-18 04:53:14 +0000641 if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
642 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
Daniel Veillardd4310742003-02-18 21:12:46 +0000643 return(1);
644 cur += l;
645 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000646 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
647 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd4310742003-02-18 21:12:46 +0000648 cur += l;
649 c = CUR_SCHAR(cur, l);
650 }
651 if (space) {
652 while (IS_BLANK(c)) {
653 cur += l;
654 c = CUR_SCHAR(cur, l);
655 }
656 }
657 if (c != 0)
658 return(1);
659 return(0);
660}
Daniel Veillard652327a2003-09-29 18:02:38 +0000661#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardd4310742003-02-18 21:12:46 +0000662
Daniel Veillardd2298792003-02-14 16:54:11 +0000663/************************************************************************
664 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000665 * Allocation and deallocation of basic structures *
666 * *
667 ************************************************************************/
668
669/**
670 * xmlSetBufferAllocationScheme:
671 * @scheme: allocation method to use
672 *
673 * Set the buffer allocation method. Types are
674 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
675 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
676 * improves performance
677 */
678void
679xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
680 xmlBufferAllocScheme = scheme;
681}
682
683/**
684 * xmlGetBufferAllocationScheme:
685 *
686 * Types are
687 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
688 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
689 * improves performance
690 *
691 * Returns the current allocation scheme
692 */
693xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000694xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000695 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000696}
697
698/**
699 * xmlNewNs:
700 * @node: the element carrying the namespace
701 * @href: the URI associated
702 * @prefix: the prefix for the namespace
703 *
704 * Creation of a new Namespace. This function will refuse to create
705 * a namespace with a similar prefix than an existing one present on this
706 * node.
707 * We use href==NULL in the case of an element creation where the namespace
708 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000709 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000710 */
711xmlNsPtr
712xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
713 xmlNsPtr cur;
714
715 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
716 return(NULL);
717
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000718 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
719 return(NULL);
720
Owen Taylor3473f882001-02-23 17:55:21 +0000721 /*
722 * Allocate a new Namespace and fill the fields.
723 */
724 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
725 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000726 xmlTreeErrMemory("building namespace");
Owen Taylor3473f882001-02-23 17:55:21 +0000727 return(NULL);
728 }
729 memset(cur, 0, sizeof(xmlNs));
730 cur->type = XML_LOCAL_NAMESPACE;
731
732 if (href != NULL)
733 cur->href = xmlStrdup(href);
734 if (prefix != NULL)
735 cur->prefix = xmlStrdup(prefix);
736
737 /*
738 * Add it at the end to preserve parsing order ...
739 * and checks for existing use of the prefix
740 */
741 if (node != NULL) {
742 if (node->nsDef == NULL) {
743 node->nsDef = cur;
744 } else {
745 xmlNsPtr prev = node->nsDef;
746
747 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
748 (xmlStrEqual(prev->prefix, cur->prefix))) {
749 xmlFreeNs(cur);
750 return(NULL);
751 }
752 while (prev->next != NULL) {
753 prev = prev->next;
754 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
755 (xmlStrEqual(prev->prefix, cur->prefix))) {
756 xmlFreeNs(cur);
757 return(NULL);
758 }
759 }
760 prev->next = cur;
761 }
762 }
763 return(cur);
764}
765
766/**
767 * xmlSetNs:
768 * @node: a node in the document
769 * @ns: a namespace pointer
770 *
771 * Associate a namespace to a node, a posteriori.
772 */
773void
774xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
775 if (node == NULL) {
776#ifdef DEBUG_TREE
777 xmlGenericError(xmlGenericErrorContext,
778 "xmlSetNs: node == NULL\n");
779#endif
780 return;
781 }
782 node->ns = ns;
783}
784
785/**
786 * xmlFreeNs:
787 * @cur: the namespace pointer
788 *
789 * Free up the structures associated to a namespace
790 */
791void
792xmlFreeNs(xmlNsPtr cur) {
793 if (cur == NULL) {
794#ifdef DEBUG_TREE
795 xmlGenericError(xmlGenericErrorContext,
796 "xmlFreeNs : ns == NULL\n");
797#endif
798 return;
799 }
800 if (cur->href != NULL) xmlFree((char *) cur->href);
801 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000802 xmlFree(cur);
803}
804
805/**
806 * xmlFreeNsList:
807 * @cur: the first namespace pointer
808 *
809 * Free up all the structures associated to the chained namespaces.
810 */
811void
812xmlFreeNsList(xmlNsPtr cur) {
813 xmlNsPtr next;
814 if (cur == NULL) {
815#ifdef DEBUG_TREE
816 xmlGenericError(xmlGenericErrorContext,
817 "xmlFreeNsList : ns == NULL\n");
818#endif
819 return;
820 }
821 while (cur != NULL) {
822 next = cur->next;
823 xmlFreeNs(cur);
824 cur = next;
825 }
826}
827
828/**
829 * xmlNewDtd:
830 * @doc: the document pointer
831 * @name: the DTD name
832 * @ExternalID: the external ID
833 * @SystemID: the system ID
834 *
835 * Creation of a new DTD for the external subset. To create an
836 * internal subset, use xmlCreateIntSubset().
837 *
838 * Returns a pointer to the new DTD structure
839 */
840xmlDtdPtr
841xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
842 const xmlChar *ExternalID, const xmlChar *SystemID) {
843 xmlDtdPtr cur;
844
845 if ((doc != NULL) && (doc->extSubset != NULL)) {
846#ifdef DEBUG_TREE
847 xmlGenericError(xmlGenericErrorContext,
848 "xmlNewDtd(%s): document %s already have a DTD %s\n",
849 /* !!! */ (char *) name, doc->name,
850 /* !!! */ (char *)doc->extSubset->name);
851#endif
852 return(NULL);
853 }
854
855 /*
856 * Allocate a new DTD and fill the fields.
857 */
858 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
859 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000860 xmlTreeErrMemory("building DTD");
Owen Taylor3473f882001-02-23 17:55:21 +0000861 return(NULL);
862 }
863 memset(cur, 0 , sizeof(xmlDtd));
864 cur->type = XML_DTD_NODE;
865
866 if (name != NULL)
867 cur->name = xmlStrdup(name);
868 if (ExternalID != NULL)
869 cur->ExternalID = xmlStrdup(ExternalID);
870 if (SystemID != NULL)
871 cur->SystemID = xmlStrdup(SystemID);
872 if (doc != NULL)
873 doc->extSubset = cur;
874 cur->doc = doc;
875
Daniel Veillarda880b122003-04-21 21:36:41 +0000876 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000877 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000878 return(cur);
879}
880
881/**
882 * xmlGetIntSubset:
883 * @doc: the document pointer
884 *
885 * Get the internal subset of a document
886 * Returns a pointer to the DTD structure or NULL if not found
887 */
888
889xmlDtdPtr
890xmlGetIntSubset(xmlDocPtr doc) {
891 xmlNodePtr cur;
892
893 if (doc == NULL)
894 return(NULL);
895 cur = doc->children;
896 while (cur != NULL) {
897 if (cur->type == XML_DTD_NODE)
898 return((xmlDtdPtr) cur);
899 cur = cur->next;
900 }
901 return((xmlDtdPtr) doc->intSubset);
902}
903
904/**
905 * xmlCreateIntSubset:
906 * @doc: the document pointer
907 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000908 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000909 * @SystemID: the system ID
910 *
911 * Create the internal subset of a document
912 * Returns a pointer to the new DTD structure
913 */
914xmlDtdPtr
915xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
916 const xmlChar *ExternalID, const xmlChar *SystemID) {
917 xmlDtdPtr cur;
918
919 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
920#ifdef DEBUG_TREE
921 xmlGenericError(xmlGenericErrorContext,
922
923 "xmlCreateIntSubset(): document %s already have an internal subset\n",
924 doc->name);
925#endif
926 return(NULL);
927 }
928
929 /*
930 * Allocate a new DTD and fill the fields.
931 */
932 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
933 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000934 xmlTreeErrMemory("building internal subset");
Owen Taylor3473f882001-02-23 17:55:21 +0000935 return(NULL);
936 }
937 memset(cur, 0, sizeof(xmlDtd));
938 cur->type = XML_DTD_NODE;
939
William M. Bracka3215c72004-07-31 16:24:01 +0000940 if (name != NULL) {
941 cur->name = xmlStrdup(name);
942 if (cur->name == NULL) {
943 xmlTreeErrMemory("building internal subset");
944 xmlFree(cur);
945 return(NULL);
946 }
947 }
948 if (ExternalID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000949 cur->ExternalID = xmlStrdup(ExternalID);
William M. Bracka3215c72004-07-31 16:24:01 +0000950 if (cur->ExternalID == NULL) {
951 xmlTreeErrMemory("building internal subset");
952 if (cur->name != NULL)
953 xmlFree((char *)cur->name);
954 xmlFree(cur);
955 return(NULL);
956 }
957 }
958 if (SystemID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000959 cur->SystemID = xmlStrdup(SystemID);
William M. Bracka3215c72004-07-31 16:24:01 +0000960 if (cur->SystemID == NULL) {
961 xmlTreeErrMemory("building internal subset");
962 if (cur->name != NULL)
963 xmlFree((char *)cur->name);
964 if (cur->ExternalID != NULL)
965 xmlFree((char *)cur->ExternalID);
966 xmlFree(cur);
967 return(NULL);
968 }
969 }
Owen Taylor3473f882001-02-23 17:55:21 +0000970 if (doc != NULL) {
971 doc->intSubset = cur;
972 cur->parent = doc;
973 cur->doc = doc;
974 if (doc->children == NULL) {
975 doc->children = (xmlNodePtr) cur;
976 doc->last = (xmlNodePtr) cur;
977 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000978 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000979 xmlNodePtr prev;
980
Owen Taylor3473f882001-02-23 17:55:21 +0000981 prev = doc->children;
982 prev->prev = (xmlNodePtr) cur;
983 cur->next = prev;
984 doc->children = (xmlNodePtr) cur;
985 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000986 xmlNodePtr next;
987
988 next = doc->children;
989 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
990 next = next->next;
991 if (next == NULL) {
992 cur->prev = doc->last;
993 cur->prev->next = (xmlNodePtr) cur;
994 cur->next = NULL;
995 doc->last = (xmlNodePtr) cur;
996 } else {
997 cur->next = next;
998 cur->prev = next->prev;
999 if (cur->prev == NULL)
1000 doc->children = (xmlNodePtr) cur;
1001 else
1002 cur->prev->next = (xmlNodePtr) cur;
1003 next->prev = (xmlNodePtr) cur;
1004 }
Owen Taylor3473f882001-02-23 17:55:21 +00001005 }
1006 }
1007 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001008
Daniel Veillarda880b122003-04-21 21:36:41 +00001009 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001010 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001011 return(cur);
1012}
1013
1014/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001015 * DICT_FREE:
1016 * @str: a string
1017 *
1018 * Free a string if it is not owned by the "dict" dictionnary in the
1019 * current scope
1020 */
1021#define DICT_FREE(str) \
1022 if ((str) && ((!dict) || \
1023 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
1024 xmlFree((char *)(str));
1025
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00001026
1027/**
1028 * DICT_COPY:
1029 * @str: a string
1030 *
1031 * Copy a string using a "dict" dictionnary in the current scope,
1032 * if availabe.
1033 */
1034#define DICT_COPY(str, cpy) \
1035 if (str) { \
1036 if (dict) { \
1037 if (xmlDictOwns(dict, (const xmlChar *)(str))) \
1038 cpy = (xmlChar *) (str); \
1039 else \
1040 cpy = (xmlChar *) xmlDictLookup((dict), (const xmlChar *)(str), -1); \
1041 } else \
1042 cpy = xmlStrdup((const xmlChar *)(str)); }
1043
1044/**
1045 * DICT_CONST_COPY:
1046 * @str: a string
1047 *
1048 * Copy a string using a "dict" dictionnary in the current scope,
1049 * if availabe.
1050 */
1051#define DICT_CONST_COPY(str, cpy) \
1052 if (str) { \
1053 if (dict) { \
1054 if (xmlDictOwns(dict, (const xmlChar *)(str))) \
1055 cpy = (const xmlChar *) (str); \
1056 else \
1057 cpy = xmlDictLookup((dict), (const xmlChar *)(str), -1); \
1058 } else \
1059 cpy = (const xmlChar *) xmlStrdup((const xmlChar *)(str)); }
1060
1061
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001062/**
Owen Taylor3473f882001-02-23 17:55:21 +00001063 * xmlFreeDtd:
1064 * @cur: the DTD structure to free up
1065 *
1066 * Free a DTD structure.
1067 */
1068void
1069xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001070 xmlDictPtr dict = NULL;
1071
Owen Taylor3473f882001-02-23 17:55:21 +00001072 if (cur == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001073 return;
1074 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001075 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001076
Daniel Veillarda880b122003-04-21 21:36:41 +00001077 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001078 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1079
Owen Taylor3473f882001-02-23 17:55:21 +00001080 if (cur->children != NULL) {
1081 xmlNodePtr next, c = cur->children;
1082
1083 /*
William M. Brack18a04f22004-08-03 16:42:37 +00001084 * Cleanup all nodes which are not part of the specific lists
1085 * of notations, elements, attributes and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00001086 */
1087 while (c != NULL) {
1088 next = c->next;
William M. Brack18a04f22004-08-03 16:42:37 +00001089 if ((c->type != XML_NOTATION_NODE) &&
1090 (c->type != XML_ELEMENT_DECL) &&
1091 (c->type != XML_ATTRIBUTE_DECL) &&
1092 (c->type != XML_ENTITY_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001093 xmlUnlinkNode(c);
1094 xmlFreeNode(c);
1095 }
1096 c = next;
1097 }
1098 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001099 DICT_FREE(cur->name)
1100 DICT_FREE(cur->SystemID)
1101 DICT_FREE(cur->ExternalID)
Owen Taylor3473f882001-02-23 17:55:21 +00001102 /* TODO !!! */
1103 if (cur->notations != NULL)
1104 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1105
1106 if (cur->elements != NULL)
1107 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1108 if (cur->attributes != NULL)
1109 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1110 if (cur->entities != NULL)
1111 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1112 if (cur->pentities != NULL)
1113 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1114
Owen Taylor3473f882001-02-23 17:55:21 +00001115 xmlFree(cur);
1116}
1117
1118/**
1119 * xmlNewDoc:
1120 * @version: xmlChar string giving the version of XML "1.0"
1121 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001122 * Creates a new XML document
1123 *
Owen Taylor3473f882001-02-23 17:55:21 +00001124 * Returns a new document
1125 */
1126xmlDocPtr
1127xmlNewDoc(const xmlChar *version) {
1128 xmlDocPtr cur;
1129
1130 if (version == NULL)
1131 version = (const xmlChar *) "1.0";
1132
1133 /*
1134 * Allocate a new document and fill the fields.
1135 */
1136 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1137 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001138 xmlTreeErrMemory("building doc");
Owen Taylor3473f882001-02-23 17:55:21 +00001139 return(NULL);
1140 }
1141 memset(cur, 0, sizeof(xmlDoc));
1142 cur->type = XML_DOCUMENT_NODE;
1143
1144 cur->version = xmlStrdup(version);
William M. Bracka3215c72004-07-31 16:24:01 +00001145 if (cur->version == NULL) {
1146 xmlTreeErrMemory("building doc");
1147 xmlFree(cur);
1148 return(NULL);
1149 }
Owen Taylor3473f882001-02-23 17:55:21 +00001150 cur->standalone = -1;
1151 cur->compression = -1; /* not initialized */
1152 cur->doc = cur;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001153 /*
1154 * The in memory encoding is always UTF8
1155 * This field will never change and would
1156 * be obsolete if not for binary compatibility.
1157 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001158 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001159
Daniel Veillarda880b122003-04-21 21:36:41 +00001160 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001161 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001162 return(cur);
1163}
1164
1165/**
1166 * xmlFreeDoc:
1167 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001168 *
1169 * Free up all the structures used by a document, tree included.
1170 */
1171void
1172xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001173 xmlDtdPtr extSubset, intSubset;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001174 xmlDictPtr dict = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001175
Owen Taylor3473f882001-02-23 17:55:21 +00001176 if (cur == NULL) {
1177#ifdef DEBUG_TREE
1178 xmlGenericError(xmlGenericErrorContext,
1179 "xmlFreeDoc : document == NULL\n");
1180#endif
1181 return;
1182 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001183#ifdef LIBXML_DEBUG_RUNTIME
Daniel Veillardbca3ad22005-08-23 22:14:02 +00001184#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001185 xmlDebugCheckDocument(stderr, cur);
1186#endif
Daniel Veillardbca3ad22005-08-23 22:14:02 +00001187#endif
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001188
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001189 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001190
Daniel Veillarda880b122003-04-21 21:36:41 +00001191 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001192 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1193
Daniel Veillard76d66f42001-05-16 21:05:17 +00001194 /*
1195 * Do this before freeing the children list to avoid ID lookups
1196 */
1197 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1198 cur->ids = NULL;
1199 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1200 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001201 extSubset = cur->extSubset;
1202 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001203 if (intSubset == extSubset)
1204 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001205 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001206 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001207 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001208 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001209 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001210 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001211 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001212 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001213 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001214 }
1215
1216 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001217 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001218
1219 DICT_FREE(cur->version)
1220 DICT_FREE(cur->name)
1221 DICT_FREE(cur->encoding)
1222 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001223 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001224 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001225}
1226
1227/**
1228 * xmlStringLenGetNodeList:
1229 * @doc: the document
1230 * @value: the value of the text
1231 * @len: the length of the string value
1232 *
1233 * Parse the value string and build the node list associated. Should
1234 * produce a flat tree with only TEXTs and ENTITY_REFs.
1235 * Returns a pointer to the first child
1236 */
1237xmlNodePtr
1238xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1239 xmlNodePtr ret = NULL, last = NULL;
1240 xmlNodePtr node;
1241 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001242 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001243 const xmlChar *q;
1244 xmlEntityPtr ent;
1245
1246 if (value == NULL) return(NULL);
1247
1248 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001249 while ((cur < end) && (*cur != 0)) {
1250 if (cur[0] == '&') {
1251 int charval = 0;
1252 xmlChar tmp;
1253
Owen Taylor3473f882001-02-23 17:55:21 +00001254 /*
1255 * Save the current text.
1256 */
1257 if (cur != q) {
1258 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1259 xmlNodeAddContentLen(last, q, cur - q);
1260 } else {
1261 node = xmlNewDocTextLen(doc, q, cur - q);
1262 if (node == NULL) return(ret);
1263 if (last == NULL)
1264 last = ret = node;
1265 else {
1266 last->next = node;
1267 node->prev = last;
1268 last = node;
1269 }
1270 }
1271 }
Owen Taylor3473f882001-02-23 17:55:21 +00001272 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001273 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1274 cur += 3;
1275 if (cur < end)
1276 tmp = *cur;
1277 else
1278 tmp = 0;
1279 while (tmp != ';') { /* Non input consuming loop */
1280 if ((tmp >= '0') && (tmp <= '9'))
1281 charval = charval * 16 + (tmp - '0');
1282 else if ((tmp >= 'a') && (tmp <= 'f'))
1283 charval = charval * 16 + (tmp - 'a') + 10;
1284 else if ((tmp >= 'A') && (tmp <= 'F'))
1285 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001286 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001287 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1288 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001289 charval = 0;
1290 break;
1291 }
1292 cur++;
1293 if (cur < end)
1294 tmp = *cur;
1295 else
1296 tmp = 0;
1297 }
1298 if (tmp == ';')
1299 cur++;
1300 q = cur;
1301 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1302 cur += 2;
1303 if (cur < end)
1304 tmp = *cur;
1305 else
1306 tmp = 0;
1307 while (tmp != ';') { /* Non input consuming loops */
1308 if ((tmp >= '0') && (tmp <= '9'))
1309 charval = charval * 10 + (tmp - '0');
1310 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001311 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1312 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001313 charval = 0;
1314 break;
1315 }
1316 cur++;
1317 if (cur < end)
1318 tmp = *cur;
1319 else
1320 tmp = 0;
1321 }
1322 if (tmp == ';')
1323 cur++;
1324 q = cur;
1325 } else {
1326 /*
1327 * Read the entity string
1328 */
1329 cur++;
1330 q = cur;
1331 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1332 if ((cur >= end) || (*cur == 0)) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001333 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1334 (const char *) q);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001335 return(ret);
1336 }
1337 if (cur != q) {
1338 /*
1339 * Predefined entities don't generate nodes
1340 */
1341 val = xmlStrndup(q, cur - q);
1342 ent = xmlGetDocEntity(doc, val);
1343 if ((ent != NULL) &&
1344 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1345 if (last == NULL) {
1346 node = xmlNewDocText(doc, ent->content);
1347 last = ret = node;
1348 } else if (last->type != XML_TEXT_NODE) {
1349 node = xmlNewDocText(doc, ent->content);
1350 last = xmlAddNextSibling(last, node);
1351 } else
1352 xmlNodeAddContent(last, ent->content);
1353
1354 } else {
1355 /*
1356 * Create a new REFERENCE_REF node
1357 */
1358 node = xmlNewReference(doc, val);
1359 if (node == NULL) {
1360 if (val != NULL) xmlFree(val);
1361 return(ret);
1362 }
1363 else if ((ent != NULL) && (ent->children == NULL)) {
1364 xmlNodePtr temp;
1365
1366 ent->children = xmlStringGetNodeList(doc,
1367 (const xmlChar*)node->content);
1368 ent->owner = 1;
1369 temp = ent->children;
1370 while (temp) {
1371 temp->parent = (xmlNodePtr)ent;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001372 ent->last = temp;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001373 temp = temp->next;
1374 }
1375 }
1376 if (last == NULL) {
1377 last = ret = node;
1378 } else {
1379 last = xmlAddNextSibling(last, node);
1380 }
1381 }
1382 xmlFree(val);
1383 }
1384 cur++;
1385 q = cur;
1386 }
1387 if (charval != 0) {
1388 xmlChar buf[10];
1389 int l;
1390
1391 l = xmlCopyCharMultiByte(buf, charval);
1392 buf[l] = 0;
1393 node = xmlNewDocText(doc, buf);
1394 if (node != NULL) {
1395 if (last == NULL) {
1396 last = ret = node;
1397 } else {
1398 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001399 }
1400 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001401 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001402 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001403 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001404 cur++;
1405 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001406 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001407 /*
1408 * Handle the last piece of text.
1409 */
1410 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1411 xmlNodeAddContentLen(last, q, cur - q);
1412 } else {
1413 node = xmlNewDocTextLen(doc, q, cur - q);
1414 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001415 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001416 last = ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001417 } else {
1418 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001419 }
1420 }
1421 }
1422 return(ret);
1423}
1424
1425/**
1426 * xmlStringGetNodeList:
1427 * @doc: the document
1428 * @value: the value of the attribute
1429 *
1430 * Parse the value string and build the node list associated. Should
1431 * produce a flat tree with only TEXTs and ENTITY_REFs.
1432 * Returns a pointer to the first child
1433 */
1434xmlNodePtr
1435xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1436 xmlNodePtr ret = NULL, last = NULL;
1437 xmlNodePtr node;
1438 xmlChar *val;
1439 const xmlChar *cur = value;
1440 const xmlChar *q;
1441 xmlEntityPtr ent;
1442
1443 if (value == NULL) return(NULL);
1444
1445 q = cur;
1446 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001447 if (cur[0] == '&') {
1448 int charval = 0;
1449 xmlChar tmp;
1450
Owen Taylor3473f882001-02-23 17:55:21 +00001451 /*
1452 * Save the current text.
1453 */
1454 if (cur != q) {
1455 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1456 xmlNodeAddContentLen(last, q, cur - q);
1457 } else {
1458 node = xmlNewDocTextLen(doc, q, cur - q);
1459 if (node == NULL) return(ret);
1460 if (last == NULL)
1461 last = ret = node;
1462 else {
1463 last->next = node;
1464 node->prev = last;
1465 last = node;
1466 }
1467 }
1468 }
Owen Taylor3473f882001-02-23 17:55:21 +00001469 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001470 if ((cur[1] == '#') && (cur[2] == 'x')) {
1471 cur += 3;
1472 tmp = *cur;
1473 while (tmp != ';') { /* Non input consuming loop */
1474 if ((tmp >= '0') && (tmp <= '9'))
1475 charval = charval * 16 + (tmp - '0');
1476 else if ((tmp >= 'a') && (tmp <= 'f'))
1477 charval = charval * 16 + (tmp - 'a') + 10;
1478 else if ((tmp >= 'A') && (tmp <= 'F'))
1479 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001480 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001481 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1482 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001483 charval = 0;
1484 break;
1485 }
1486 cur++;
1487 tmp = *cur;
1488 }
1489 if (tmp == ';')
1490 cur++;
1491 q = cur;
1492 } else if (cur[1] == '#') {
1493 cur += 2;
1494 tmp = *cur;
1495 while (tmp != ';') { /* Non input consuming loops */
1496 if ((tmp >= '0') && (tmp <= '9'))
1497 charval = charval * 10 + (tmp - '0');
1498 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001499 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1500 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001501 charval = 0;
1502 break;
1503 }
1504 cur++;
1505 tmp = *cur;
1506 }
1507 if (tmp == ';')
1508 cur++;
1509 q = cur;
1510 } else {
1511 /*
1512 * Read the entity string
1513 */
1514 cur++;
1515 q = cur;
1516 while ((*cur != 0) && (*cur != ';')) cur++;
1517 if (*cur == 0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001518 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1519 (xmlNodePtr) doc, (const char *) q);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001520 return(ret);
1521 }
1522 if (cur != q) {
1523 /*
1524 * Predefined entities don't generate nodes
1525 */
1526 val = xmlStrndup(q, cur - q);
1527 ent = xmlGetDocEntity(doc, val);
1528 if ((ent != NULL) &&
1529 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1530 if (last == NULL) {
1531 node = xmlNewDocText(doc, ent->content);
1532 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001533 } else if (last->type != XML_TEXT_NODE) {
1534 node = xmlNewDocText(doc, ent->content);
1535 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001536 } else
1537 xmlNodeAddContent(last, ent->content);
1538
1539 } else {
1540 /*
1541 * Create a new REFERENCE_REF node
1542 */
1543 node = xmlNewReference(doc, val);
1544 if (node == NULL) {
1545 if (val != NULL) xmlFree(val);
1546 return(ret);
1547 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001548 else if ((ent != NULL) && (ent->children == NULL)) {
1549 xmlNodePtr temp;
1550
1551 ent->children = xmlStringGetNodeList(doc,
1552 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001553 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001554 temp = ent->children;
1555 while (temp) {
1556 temp->parent = (xmlNodePtr)ent;
1557 temp = temp->next;
1558 }
1559 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001560 if (last == NULL) {
1561 last = ret = node;
1562 } else {
1563 last = xmlAddNextSibling(last, node);
1564 }
1565 }
1566 xmlFree(val);
1567 }
1568 cur++;
1569 q = cur;
1570 }
1571 if (charval != 0) {
1572 xmlChar buf[10];
1573 int len;
1574
1575 len = xmlCopyCharMultiByte(buf, charval);
1576 buf[len] = 0;
1577 node = xmlNewDocText(doc, buf);
1578 if (node != NULL) {
1579 if (last == NULL) {
1580 last = ret = node;
1581 } else {
1582 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001583 }
1584 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001585
1586 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001587 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001588 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001589 cur++;
1590 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001591 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001592 /*
1593 * Handle the last piece of text.
1594 */
1595 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1596 xmlNodeAddContentLen(last, q, cur - q);
1597 } else {
1598 node = xmlNewDocTextLen(doc, q, cur - q);
1599 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001600 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001601 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001602 } else {
1603 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001604 }
1605 }
1606 }
1607 return(ret);
1608}
1609
1610/**
1611 * xmlNodeListGetString:
1612 * @doc: the document
1613 * @list: a Node list
1614 * @inLine: should we replace entity contents or show their external form
1615 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001616 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001617 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001618 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001619 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001620 */
1621xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001622xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1623{
Owen Taylor3473f882001-02-23 17:55:21 +00001624 xmlNodePtr node = list;
1625 xmlChar *ret = NULL;
1626 xmlEntityPtr ent;
1627
Daniel Veillard7646b182002-04-20 06:41:40 +00001628 if (list == NULL)
1629 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001630
1631 while (node != NULL) {
1632 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001633 (node->type == XML_CDATA_SECTION_NODE)) {
1634 if (inLine) {
1635 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001636 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001637 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001638
Daniel Veillard7646b182002-04-20 06:41:40 +00001639 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1640 if (buffer != NULL) {
1641 ret = xmlStrcat(ret, buffer);
1642 xmlFree(buffer);
1643 }
1644 }
1645 } else if (node->type == XML_ENTITY_REF_NODE) {
1646 if (inLine) {
1647 ent = xmlGetDocEntity(doc, node->name);
1648 if (ent != NULL) {
1649 xmlChar *buffer;
1650
1651 /* an entity content can be any "well balanced chunk",
1652 * i.e. the result of the content [43] production:
1653 * http://www.w3.org/TR/REC-xml#NT-content.
1654 * So it can contain text, CDATA section or nested
1655 * entity reference nodes (among others).
1656 * -> we recursive call xmlNodeListGetString()
1657 * which handles these types */
1658 buffer = xmlNodeListGetString(doc, ent->children, 1);
1659 if (buffer != NULL) {
1660 ret = xmlStrcat(ret, buffer);
1661 xmlFree(buffer);
1662 }
1663 } else {
1664 ret = xmlStrcat(ret, node->content);
1665 }
1666 } else {
1667 xmlChar buf[2];
1668
1669 buf[0] = '&';
1670 buf[1] = 0;
1671 ret = xmlStrncat(ret, buf, 1);
1672 ret = xmlStrcat(ret, node->name);
1673 buf[0] = ';';
1674 buf[1] = 0;
1675 ret = xmlStrncat(ret, buf, 1);
1676 }
1677 }
1678#if 0
1679 else {
1680 xmlGenericError(xmlGenericErrorContext,
1681 "xmlGetNodeListString : invalid node type %d\n",
1682 node->type);
1683 }
1684#endif
1685 node = node->next;
1686 }
1687 return (ret);
1688}
Daniel Veillard652327a2003-09-29 18:02:38 +00001689
1690#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001691/**
1692 * xmlNodeListGetRawString:
1693 * @doc: the document
1694 * @list: a Node list
1695 * @inLine: should we replace entity contents or show their external form
1696 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001697 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001698 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1699 * this function doesn't do any character encoding handling.
1700 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001701 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001702 */
1703xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001704xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1705{
Owen Taylor3473f882001-02-23 17:55:21 +00001706 xmlNodePtr node = list;
1707 xmlChar *ret = NULL;
1708 xmlEntityPtr ent;
1709
Daniel Veillard7646b182002-04-20 06:41:40 +00001710 if (list == NULL)
1711 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001712
1713 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001714 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001715 (node->type == XML_CDATA_SECTION_NODE)) {
1716 if (inLine) {
1717 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001718 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001719 xmlChar *buffer;
1720
1721 buffer = xmlEncodeSpecialChars(doc, node->content);
1722 if (buffer != NULL) {
1723 ret = xmlStrcat(ret, buffer);
1724 xmlFree(buffer);
1725 }
1726 }
1727 } else if (node->type == XML_ENTITY_REF_NODE) {
1728 if (inLine) {
1729 ent = xmlGetDocEntity(doc, node->name);
1730 if (ent != NULL) {
1731 xmlChar *buffer;
1732
1733 /* an entity content can be any "well balanced chunk",
1734 * i.e. the result of the content [43] production:
1735 * http://www.w3.org/TR/REC-xml#NT-content.
1736 * So it can contain text, CDATA section or nested
1737 * entity reference nodes (among others).
1738 * -> we recursive call xmlNodeListGetRawString()
1739 * which handles these types */
1740 buffer =
1741 xmlNodeListGetRawString(doc, ent->children, 1);
1742 if (buffer != NULL) {
1743 ret = xmlStrcat(ret, buffer);
1744 xmlFree(buffer);
1745 }
1746 } else {
1747 ret = xmlStrcat(ret, node->content);
1748 }
1749 } else {
1750 xmlChar buf[2];
1751
1752 buf[0] = '&';
1753 buf[1] = 0;
1754 ret = xmlStrncat(ret, buf, 1);
1755 ret = xmlStrcat(ret, node->name);
1756 buf[0] = ';';
1757 buf[1] = 0;
1758 ret = xmlStrncat(ret, buf, 1);
1759 }
1760 }
Owen Taylor3473f882001-02-23 17:55:21 +00001761#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001762 else {
1763 xmlGenericError(xmlGenericErrorContext,
1764 "xmlGetNodeListString : invalid node type %d\n",
1765 node->type);
1766 }
Owen Taylor3473f882001-02-23 17:55:21 +00001767#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001768 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001769 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001770 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001771}
Daniel Veillard652327a2003-09-29 18:02:38 +00001772#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001773
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001774static xmlAttrPtr
1775xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns,
1776 const xmlChar * name, const xmlChar * value,
1777 int eatname)
1778{
Owen Taylor3473f882001-02-23 17:55:21 +00001779 xmlAttrPtr cur;
1780 xmlDocPtr doc = NULL;
1781
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001782 if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001783 if (eatname == 1)
1784 xmlFree((xmlChar *) name);
1785 return (NULL);
1786 }
Owen Taylor3473f882001-02-23 17:55:21 +00001787
1788 /*
1789 * Allocate a new property and fill the fields.
1790 */
1791 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1792 if (cur == NULL) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001793 if (eatname == 1)
1794 xmlFree((xmlChar *) name);
1795 xmlTreeErrMemory("building attribute");
1796 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001797 }
1798 memset(cur, 0, sizeof(xmlAttr));
1799 cur->type = XML_ATTRIBUTE_NODE;
1800
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001801 cur->parent = node;
Owen Taylor3473f882001-02-23 17:55:21 +00001802 if (node != NULL) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001803 doc = node->doc;
1804 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001805 }
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001806 cur->ns = ns;
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001807
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001808 if (eatname == 0) {
1809 if ((doc != NULL) && (doc->dict != NULL))
1810 cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
1811 else
1812 cur->name = xmlStrdup(name);
1813 } else
1814 cur->name = name;
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001815
Owen Taylor3473f882001-02-23 17:55:21 +00001816 if (value != NULL) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001817 xmlChar *buffer;
1818 xmlNodePtr tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00001819
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001820 buffer = xmlEncodeEntitiesReentrant(doc, value);
1821 cur->children = xmlStringGetNodeList(doc, buffer);
1822 cur->last = NULL;
1823 tmp = cur->children;
1824 while (tmp != NULL) {
1825 tmp->parent = (xmlNodePtr) cur;
1826 if (tmp->next == NULL)
1827 cur->last = tmp;
1828 tmp = tmp->next;
1829 }
1830 xmlFree(buffer);
1831 }
Owen Taylor3473f882001-02-23 17:55:21 +00001832
1833 /*
1834 * Add it at the end to preserve parsing order ...
1835 */
1836 if (node != NULL) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001837 if (node->properties == NULL) {
1838 node->properties = cur;
1839 } else {
1840 xmlAttrPtr prev = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00001841
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001842 while (prev->next != NULL)
1843 prev = prev->next;
1844 prev->next = cur;
1845 cur->prev = prev;
1846 }
Owen Taylor3473f882001-02-23 17:55:21 +00001847 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001848
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001849 if (xmlIsID((node == NULL) ? NULL : node->doc, node, cur) == 1)
1850 xmlAddID(NULL, node->doc, value, cur);
1851
Daniel Veillarda880b122003-04-21 21:36:41 +00001852 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00001853 xmlRegisterNodeDefaultValue((xmlNodePtr) cur);
1854 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001855}
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001856
1857#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
1858 defined(LIBXML_SCHEMAS_ENABLED)
1859/**
1860 * xmlNewProp:
1861 * @node: the holding node
1862 * @name: the name of the attribute
1863 * @value: the value of the attribute
1864 *
1865 * Create a new property carried by a node.
1866 * Returns a pointer to the attribute
1867 */
1868xmlAttrPtr
1869xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1870
1871 if (name == NULL) {
1872#ifdef DEBUG_TREE
1873 xmlGenericError(xmlGenericErrorContext,
1874 "xmlNewProp : name == NULL\n");
1875#endif
1876 return(NULL);
1877 }
1878
1879 return xmlNewPropInternal(node, NULL, name, value, 0);
1880}
Daniel Veillard652327a2003-09-29 18:02:38 +00001881#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001882
1883/**
1884 * xmlNewNsProp:
1885 * @node: the holding node
1886 * @ns: the namespace
1887 * @name: the name of the attribute
1888 * @value: the value of the attribute
1889 *
1890 * Create a new property tagged with a namespace and carried by a node.
1891 * Returns a pointer to the attribute
1892 */
1893xmlAttrPtr
1894xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1895 const xmlChar *value) {
Owen Taylor3473f882001-02-23 17:55:21 +00001896
1897 if (name == NULL) {
1898#ifdef DEBUG_TREE
1899 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001900 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001901#endif
1902 return(NULL);
1903 }
1904
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001905 return xmlNewPropInternal(node, ns, name, value, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001906}
1907
1908/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001909 * xmlNewNsPropEatName:
1910 * @node: the holding node
1911 * @ns: the namespace
1912 * @name: the name of the attribute
1913 * @value: the value of the attribute
1914 *
1915 * Create a new property tagged with a namespace and carried by a node.
1916 * Returns a pointer to the attribute
1917 */
1918xmlAttrPtr
1919xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1920 const xmlChar *value) {
Daniel Veillard46de64e2002-05-29 08:21:33 +00001921
1922 if (name == NULL) {
1923#ifdef DEBUG_TREE
1924 xmlGenericError(xmlGenericErrorContext,
1925 "xmlNewNsPropEatName : name == NULL\n");
1926#endif
1927 return(NULL);
1928 }
1929
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00001930 return xmlNewPropInternal(node, ns, name, value, 1);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001931}
1932
1933/**
Owen Taylor3473f882001-02-23 17:55:21 +00001934 * xmlNewDocProp:
1935 * @doc: the document
1936 * @name: the name of the attribute
1937 * @value: the value of the attribute
1938 *
1939 * Create a new property carried by a document.
1940 * Returns a pointer to the attribute
1941 */
1942xmlAttrPtr
1943xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1944 xmlAttrPtr cur;
1945
1946 if (name == NULL) {
1947#ifdef DEBUG_TREE
1948 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001949 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001950#endif
1951 return(NULL);
1952 }
1953
1954 /*
1955 * Allocate a new property and fill the fields.
1956 */
1957 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1958 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001959 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001960 return(NULL);
1961 }
1962 memset(cur, 0, sizeof(xmlAttr));
1963 cur->type = XML_ATTRIBUTE_NODE;
1964
Daniel Veillard03a53c32004-10-26 16:06:51 +00001965 if ((doc != NULL) && (doc->dict != NULL))
1966 cur->name = xmlDictLookup(doc->dict, name, -1);
1967 else
1968 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00001969 cur->doc = doc;
1970 if (value != NULL) {
1971 xmlNodePtr tmp;
1972
1973 cur->children = xmlStringGetNodeList(doc, value);
1974 cur->last = NULL;
1975
1976 tmp = cur->children;
1977 while (tmp != NULL) {
1978 tmp->parent = (xmlNodePtr) cur;
1979 if (tmp->next == NULL)
1980 cur->last = tmp;
1981 tmp = tmp->next;
1982 }
1983 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001984
Daniel Veillarda880b122003-04-21 21:36:41 +00001985 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001986 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001987 return(cur);
1988}
1989
1990/**
1991 * xmlFreePropList:
1992 * @cur: the first property in the list
1993 *
1994 * Free a property and all its siblings, all the children are freed too.
1995 */
1996void
1997xmlFreePropList(xmlAttrPtr cur) {
1998 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001999 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002000 while (cur != NULL) {
2001 next = cur->next;
2002 xmlFreeProp(cur);
2003 cur = next;
2004 }
2005}
2006
2007/**
2008 * xmlFreeProp:
2009 * @cur: an attribute
2010 *
2011 * Free one attribute, all the content is freed too
2012 */
2013void
2014xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002015 xmlDictPtr dict = NULL;
2016 if (cur == NULL) return;
2017
2018 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002019
Daniel Veillarda880b122003-04-21 21:36:41 +00002020 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002021 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
2022
Owen Taylor3473f882001-02-23 17:55:21 +00002023 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillardda6f4af2005-06-20 17:17:54 +00002024 if ((cur->doc != NULL) && (cur->atype == XML_ATTRIBUTE_ID)) {
2025 xmlRemoveID(cur->doc, cur);
Daniel Veillard76d66f42001-05-16 21:05:17 +00002026 }
Owen Taylor3473f882001-02-23 17:55:21 +00002027 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002028 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002029 xmlFree(cur);
2030}
2031
2032/**
2033 * xmlRemoveProp:
2034 * @cur: an attribute
2035 *
2036 * Unlink and free one attribute, all the content is freed too
2037 * Note this doesn't work for namespace definition attributes
2038 *
2039 * Returns 0 if success and -1 in case of error.
2040 */
2041int
2042xmlRemoveProp(xmlAttrPtr cur) {
2043 xmlAttrPtr tmp;
2044 if (cur == NULL) {
2045#ifdef DEBUG_TREE
2046 xmlGenericError(xmlGenericErrorContext,
2047 "xmlRemoveProp : cur == NULL\n");
2048#endif
2049 return(-1);
2050 }
2051 if (cur->parent == NULL) {
2052#ifdef DEBUG_TREE
2053 xmlGenericError(xmlGenericErrorContext,
2054 "xmlRemoveProp : cur->parent == NULL\n");
2055#endif
2056 return(-1);
2057 }
2058 tmp = cur->parent->properties;
2059 if (tmp == cur) {
2060 cur->parent->properties = cur->next;
Rob Richards19dc9612005-10-28 16:15:16 +00002061 if (cur->next != NULL)
2062 cur->next->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002063 xmlFreeProp(cur);
2064 return(0);
2065 }
2066 while (tmp != NULL) {
2067 if (tmp->next == cur) {
2068 tmp->next = cur->next;
2069 if (tmp->next != NULL)
2070 tmp->next->prev = tmp;
2071 xmlFreeProp(cur);
2072 return(0);
2073 }
2074 tmp = tmp->next;
2075 }
2076#ifdef DEBUG_TREE
2077 xmlGenericError(xmlGenericErrorContext,
2078 "xmlRemoveProp : attribute not owned by its node\n");
2079#endif
2080 return(-1);
2081}
2082
2083/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002084 * xmlNewDocPI:
2085 * @doc: the target document
Owen Taylor3473f882001-02-23 17:55:21 +00002086 * @name: the processing instruction name
2087 * @content: the PI content
2088 *
2089 * Creation of a processing instruction element.
2090 * Returns a pointer to the new node object.
2091 */
2092xmlNodePtr
Daniel Veillard03a53c32004-10-26 16:06:51 +00002093xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
Owen Taylor3473f882001-02-23 17:55:21 +00002094 xmlNodePtr cur;
2095
2096 if (name == NULL) {
2097#ifdef DEBUG_TREE
2098 xmlGenericError(xmlGenericErrorContext,
2099 "xmlNewPI : name == NULL\n");
2100#endif
2101 return(NULL);
2102 }
2103
2104 /*
2105 * Allocate a new node and fill the fields.
2106 */
2107 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2108 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002109 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002110 return(NULL);
2111 }
2112 memset(cur, 0, sizeof(xmlNode));
2113 cur->type = XML_PI_NODE;
2114
Daniel Veillard03a53c32004-10-26 16:06:51 +00002115 if ((doc != NULL) && (doc->dict != NULL))
2116 cur->name = xmlDictLookup(doc->dict, name, -1);
2117 else
2118 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00002119 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002120 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002121 }
Daniel Veillarda03e3652004-11-02 18:45:30 +00002122 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002123
Daniel Veillarda880b122003-04-21 21:36:41 +00002124 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002125 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002126 return(cur);
2127}
2128
2129/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002130 * xmlNewPI:
2131 * @name: the processing instruction name
2132 * @content: the PI content
2133 *
2134 * Creation of a processing instruction element.
2135 * Use xmlDocNewPI preferably to get string interning
2136 *
2137 * Returns a pointer to the new node object.
2138 */
2139xmlNodePtr
2140xmlNewPI(const xmlChar *name, const xmlChar *content) {
2141 return(xmlNewDocPI(NULL, name, content));
2142}
2143
2144/**
Owen Taylor3473f882001-02-23 17:55:21 +00002145 * xmlNewNode:
2146 * @ns: namespace if any
2147 * @name: the node name
2148 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002149 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002150 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002151 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2152 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002153 */
2154xmlNodePtr
2155xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2156 xmlNodePtr cur;
2157
2158 if (name == NULL) {
2159#ifdef DEBUG_TREE
2160 xmlGenericError(xmlGenericErrorContext,
2161 "xmlNewNode : name == NULL\n");
2162#endif
2163 return(NULL);
2164 }
2165
2166 /*
2167 * Allocate a new node and fill the fields.
2168 */
2169 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2170 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002171 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002172 return(NULL);
2173 }
2174 memset(cur, 0, sizeof(xmlNode));
2175 cur->type = XML_ELEMENT_NODE;
2176
2177 cur->name = xmlStrdup(name);
2178 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002179
Daniel Veillarda880b122003-04-21 21:36:41 +00002180 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002181 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002182 return(cur);
2183}
2184
2185/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002186 * xmlNewNodeEatName:
2187 * @ns: namespace if any
2188 * @name: the node name
2189 *
2190 * Creation of a new node element. @ns is optional (NULL).
2191 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002192 * Returns a pointer to the new node object, with pointer @name as
2193 * new node's name. Use xmlNewNode() if a copy of @name string is
2194 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002195 */
2196xmlNodePtr
2197xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2198 xmlNodePtr cur;
2199
2200 if (name == NULL) {
2201#ifdef DEBUG_TREE
2202 xmlGenericError(xmlGenericErrorContext,
2203 "xmlNewNode : name == NULL\n");
2204#endif
2205 return(NULL);
2206 }
2207
2208 /*
2209 * Allocate a new node and fill the fields.
2210 */
2211 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2212 if (cur == NULL) {
Daniel Veillard5cd3e8c2005-03-27 11:25:28 +00002213 xmlFree(name);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002214 xmlTreeErrMemory("building node");
Daniel Veillard46de64e2002-05-29 08:21:33 +00002215 return(NULL);
2216 }
2217 memset(cur, 0, sizeof(xmlNode));
2218 cur->type = XML_ELEMENT_NODE;
2219
2220 cur->name = name;
2221 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002222
Daniel Veillarda880b122003-04-21 21:36:41 +00002223 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002224 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002225 return(cur);
2226}
2227
2228/**
Owen Taylor3473f882001-02-23 17:55:21 +00002229 * xmlNewDocNode:
2230 * @doc: the document
2231 * @ns: namespace if any
2232 * @name: the node name
2233 * @content: the XML text content if any
2234 *
2235 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002236 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002237 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2238 * references, but XML special chars need to be escaped first by using
2239 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2240 * need entities support.
2241 *
2242 * Returns a pointer to the new node object.
2243 */
2244xmlNodePtr
2245xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2246 const xmlChar *name, const xmlChar *content) {
2247 xmlNodePtr cur;
2248
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002249 if ((doc != NULL) && (doc->dict != NULL))
Daniel Veillard03a53c32004-10-26 16:06:51 +00002250 cur = xmlNewNodeEatName(ns, (xmlChar *)
2251 xmlDictLookup(doc->dict, name, -1));
2252 else
2253 cur = xmlNewNode(ns, name);
Owen Taylor3473f882001-02-23 17:55:21 +00002254 if (cur != NULL) {
2255 cur->doc = doc;
2256 if (content != NULL) {
2257 cur->children = xmlStringGetNodeList(doc, content);
2258 UPDATE_LAST_CHILD_AND_PARENT(cur)
2259 }
2260 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002261
Owen Taylor3473f882001-02-23 17:55:21 +00002262 return(cur);
2263}
2264
Daniel Veillard46de64e2002-05-29 08:21:33 +00002265/**
2266 * xmlNewDocNodeEatName:
2267 * @doc: the document
2268 * @ns: namespace if any
2269 * @name: the node name
2270 * @content: the XML text content if any
2271 *
2272 * Creation of a new node element within a document. @ns and @content
2273 * are optional (NULL).
2274 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2275 * references, but XML special chars need to be escaped first by using
2276 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2277 * need entities support.
2278 *
2279 * Returns a pointer to the new node object.
2280 */
2281xmlNodePtr
2282xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2283 xmlChar *name, const xmlChar *content) {
2284 xmlNodePtr cur;
2285
2286 cur = xmlNewNodeEatName(ns, name);
2287 if (cur != NULL) {
2288 cur->doc = doc;
2289 if (content != NULL) {
2290 cur->children = xmlStringGetNodeList(doc, content);
2291 UPDATE_LAST_CHILD_AND_PARENT(cur)
2292 }
2293 }
2294 return(cur);
2295}
2296
Daniel Veillard652327a2003-09-29 18:02:38 +00002297#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002298/**
2299 * xmlNewDocRawNode:
2300 * @doc: the document
2301 * @ns: namespace if any
2302 * @name: the node name
2303 * @content: the text content if any
2304 *
2305 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002306 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002307 *
2308 * Returns a pointer to the new node object.
2309 */
2310xmlNodePtr
2311xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2312 const xmlChar *name, const xmlChar *content) {
2313 xmlNodePtr cur;
2314
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002315 cur = xmlNewDocNode(doc, ns, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002316 if (cur != NULL) {
2317 cur->doc = doc;
2318 if (content != NULL) {
2319 cur->children = xmlNewDocText(doc, content);
2320 UPDATE_LAST_CHILD_AND_PARENT(cur)
2321 }
2322 }
2323 return(cur);
2324}
2325
2326/**
2327 * xmlNewDocFragment:
2328 * @doc: the document owning the fragment
2329 *
2330 * Creation of a new Fragment node.
2331 * Returns a pointer to the new node object.
2332 */
2333xmlNodePtr
2334xmlNewDocFragment(xmlDocPtr doc) {
2335 xmlNodePtr cur;
2336
2337 /*
2338 * Allocate a new DocumentFragment node and fill the fields.
2339 */
2340 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2341 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002342 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002343 return(NULL);
2344 }
2345 memset(cur, 0, sizeof(xmlNode));
2346 cur->type = XML_DOCUMENT_FRAG_NODE;
2347
2348 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002349
Daniel Veillarda880b122003-04-21 21:36:41 +00002350 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002351 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002352 return(cur);
2353}
Daniel Veillard652327a2003-09-29 18:02:38 +00002354#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002355
2356/**
2357 * xmlNewText:
2358 * @content: the text content
2359 *
2360 * Creation of a new text node.
2361 * Returns a pointer to the new node object.
2362 */
2363xmlNodePtr
2364xmlNewText(const xmlChar *content) {
2365 xmlNodePtr cur;
2366
2367 /*
2368 * Allocate a new node and fill the fields.
2369 */
2370 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2371 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002372 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002373 return(NULL);
2374 }
2375 memset(cur, 0, sizeof(xmlNode));
2376 cur->type = XML_TEXT_NODE;
2377
2378 cur->name = xmlStringText;
2379 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002380 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002381 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002382
Daniel Veillarda880b122003-04-21 21:36:41 +00002383 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002384 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002385 return(cur);
2386}
2387
Daniel Veillard652327a2003-09-29 18:02:38 +00002388#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002389/**
2390 * xmlNewTextChild:
2391 * @parent: the parent node
2392 * @ns: a namespace if any
2393 * @name: the name of the child
2394 * @content: the text content of the child if any.
2395 *
2396 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002397 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2398 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002399 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002400 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2401 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2402 * reserved XML chars that might appear in @content, such as the ampersand,
2403 * greater-than or less-than signs, are automatically replaced by their XML
2404 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002405 *
2406 * Returns a pointer to the new node object.
2407 */
2408xmlNodePtr
2409xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2410 const xmlChar *name, const xmlChar *content) {
2411 xmlNodePtr cur, prev;
2412
2413 if (parent == NULL) {
2414#ifdef DEBUG_TREE
2415 xmlGenericError(xmlGenericErrorContext,
2416 "xmlNewTextChild : parent == NULL\n");
2417#endif
2418 return(NULL);
2419 }
2420
2421 if (name == NULL) {
2422#ifdef DEBUG_TREE
2423 xmlGenericError(xmlGenericErrorContext,
2424 "xmlNewTextChild : name == NULL\n");
2425#endif
2426 return(NULL);
2427 }
2428
2429 /*
2430 * Allocate a new node
2431 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002432 if (parent->type == XML_ELEMENT_NODE) {
2433 if (ns == NULL)
2434 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2435 else
2436 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2437 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2438 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2439 if (ns == NULL)
2440 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2441 else
2442 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2443 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2444 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2445 } else {
2446 return(NULL);
2447 }
Owen Taylor3473f882001-02-23 17:55:21 +00002448 if (cur == NULL) return(NULL);
2449
2450 /*
2451 * add the new element at the end of the children list.
2452 */
2453 cur->type = XML_ELEMENT_NODE;
2454 cur->parent = parent;
2455 cur->doc = parent->doc;
2456 if (parent->children == NULL) {
2457 parent->children = cur;
2458 parent->last = cur;
2459 } else {
2460 prev = parent->last;
2461 prev->next = cur;
2462 cur->prev = prev;
2463 parent->last = cur;
2464 }
2465
2466 return(cur);
2467}
Daniel Veillard652327a2003-09-29 18:02:38 +00002468#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002469
2470/**
2471 * xmlNewCharRef:
2472 * @doc: the document
2473 * @name: the char ref string, starting with # or "&# ... ;"
2474 *
2475 * Creation of a new character reference node.
2476 * Returns a pointer to the new node object.
2477 */
2478xmlNodePtr
2479xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2480 xmlNodePtr cur;
2481
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002482 if (name == NULL)
2483 return(NULL);
2484
Owen Taylor3473f882001-02-23 17:55:21 +00002485 /*
2486 * Allocate a new node and fill the fields.
2487 */
2488 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2489 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002490 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002491 return(NULL);
2492 }
2493 memset(cur, 0, sizeof(xmlNode));
2494 cur->type = XML_ENTITY_REF_NODE;
2495
2496 cur->doc = doc;
2497 if (name[0] == '&') {
2498 int len;
2499 name++;
2500 len = xmlStrlen(name);
2501 if (name[len - 1] == ';')
2502 cur->name = xmlStrndup(name, len - 1);
2503 else
2504 cur->name = xmlStrndup(name, len);
2505 } else
2506 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002507
Daniel Veillarda880b122003-04-21 21:36:41 +00002508 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002509 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002510 return(cur);
2511}
2512
2513/**
2514 * xmlNewReference:
2515 * @doc: the document
2516 * @name: the reference name, or the reference string with & and ;
2517 *
2518 * Creation of a new reference node.
2519 * Returns a pointer to the new node object.
2520 */
2521xmlNodePtr
2522xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2523 xmlNodePtr cur;
2524 xmlEntityPtr ent;
2525
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002526 if (name == NULL)
2527 return(NULL);
2528
Owen Taylor3473f882001-02-23 17:55:21 +00002529 /*
2530 * Allocate a new node and fill the fields.
2531 */
2532 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2533 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002534 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002535 return(NULL);
2536 }
2537 memset(cur, 0, sizeof(xmlNode));
2538 cur->type = XML_ENTITY_REF_NODE;
2539
2540 cur->doc = doc;
2541 if (name[0] == '&') {
2542 int len;
2543 name++;
2544 len = xmlStrlen(name);
2545 if (name[len - 1] == ';')
2546 cur->name = xmlStrndup(name, len - 1);
2547 else
2548 cur->name = xmlStrndup(name, len);
2549 } else
2550 cur->name = xmlStrdup(name);
2551
2552 ent = xmlGetDocEntity(doc, cur->name);
2553 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002554 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002555 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002556 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002557 * updated. Not sure if this is 100% correct.
2558 * -George
2559 */
2560 cur->children = (xmlNodePtr) ent;
2561 cur->last = (xmlNodePtr) ent;
2562 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002563
Daniel Veillarda880b122003-04-21 21:36:41 +00002564 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002565 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002566 return(cur);
2567}
2568
2569/**
2570 * xmlNewDocText:
2571 * @doc: the document
2572 * @content: the text content
2573 *
2574 * Creation of a new text node within a document.
2575 * Returns a pointer to the new node object.
2576 */
2577xmlNodePtr
2578xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2579 xmlNodePtr cur;
2580
2581 cur = xmlNewText(content);
2582 if (cur != NULL) cur->doc = doc;
2583 return(cur);
2584}
2585
2586/**
2587 * xmlNewTextLen:
2588 * @content: the text content
2589 * @len: the text len.
2590 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002591 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002592 * Returns a pointer to the new node object.
2593 */
2594xmlNodePtr
2595xmlNewTextLen(const xmlChar *content, int len) {
2596 xmlNodePtr cur;
2597
2598 /*
2599 * Allocate a new node and fill the fields.
2600 */
2601 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2602 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002603 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002604 return(NULL);
2605 }
2606 memset(cur, 0, sizeof(xmlNode));
2607 cur->type = XML_TEXT_NODE;
2608
2609 cur->name = xmlStringText;
2610 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002611 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002612 }
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 * xmlNewDocTextLen:
2621 * @doc: the document
2622 * @content: the text content
2623 * @len: the text len.
2624 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002625 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002626 * text node pertain to a given document.
2627 * Returns a pointer to the new node object.
2628 */
2629xmlNodePtr
2630xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2631 xmlNodePtr cur;
2632
2633 cur = xmlNewTextLen(content, len);
2634 if (cur != NULL) cur->doc = doc;
2635 return(cur);
2636}
2637
2638/**
2639 * xmlNewComment:
2640 * @content: the comment content
2641 *
2642 * Creation of a new node containing a comment.
2643 * Returns a pointer to the new node object.
2644 */
2645xmlNodePtr
2646xmlNewComment(const xmlChar *content) {
2647 xmlNodePtr cur;
2648
2649 /*
2650 * Allocate a new node and fill the fields.
2651 */
2652 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2653 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002654 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002655 return(NULL);
2656 }
2657 memset(cur, 0, sizeof(xmlNode));
2658 cur->type = XML_COMMENT_NODE;
2659
2660 cur->name = xmlStringComment;
2661 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002662 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002663 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002664
Daniel Veillarda880b122003-04-21 21:36:41 +00002665 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002666 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002667 return(cur);
2668}
2669
2670/**
2671 * xmlNewCDataBlock:
2672 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002673 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002674 * @len: the length of the block
2675 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002676 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002677 * Returns a pointer to the new node object.
2678 */
2679xmlNodePtr
2680xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2681 xmlNodePtr cur;
2682
2683 /*
2684 * Allocate a new node and fill the fields.
2685 */
2686 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2687 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002688 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002689 return(NULL);
2690 }
2691 memset(cur, 0, sizeof(xmlNode));
2692 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002693 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002694
2695 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002696 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002697 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002698
Daniel Veillarda880b122003-04-21 21:36:41 +00002699 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002700 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002701 return(cur);
2702}
2703
2704/**
2705 * xmlNewDocComment:
2706 * @doc: the document
2707 * @content: the comment content
2708 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002709 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002710 * Returns a pointer to the new node object.
2711 */
2712xmlNodePtr
2713xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2714 xmlNodePtr cur;
2715
2716 cur = xmlNewComment(content);
2717 if (cur != NULL) cur->doc = doc;
2718 return(cur);
2719}
2720
2721/**
2722 * xmlSetTreeDoc:
2723 * @tree: the top element
2724 * @doc: the document
2725 *
2726 * update all nodes under the tree to point to the right document
2727 */
2728void
2729xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002730 xmlAttrPtr prop;
2731
Owen Taylor3473f882001-02-23 17:55:21 +00002732 if (tree == NULL)
2733 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002734 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002735 if(tree->type == XML_ELEMENT_NODE) {
2736 prop = tree->properties;
2737 while (prop != NULL) {
2738 prop->doc = doc;
2739 xmlSetListDoc(prop->children, doc);
2740 prop = prop->next;
2741 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002742 }
Owen Taylor3473f882001-02-23 17:55:21 +00002743 if (tree->children != NULL)
2744 xmlSetListDoc(tree->children, doc);
2745 tree->doc = doc;
2746 }
2747}
2748
2749/**
2750 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002751 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002752 * @doc: the document
2753 *
2754 * update all nodes in the list to point to the right document
2755 */
2756void
2757xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2758 xmlNodePtr cur;
2759
2760 if (list == NULL)
2761 return;
2762 cur = list;
2763 while (cur != NULL) {
2764 if (cur->doc != doc)
2765 xmlSetTreeDoc(cur, doc);
2766 cur = cur->next;
2767 }
2768}
2769
Daniel Veillard2156d432004-03-04 15:59:36 +00002770#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002771/**
2772 * xmlNewChild:
2773 * @parent: the parent node
2774 * @ns: a namespace if any
2775 * @name: the name of the child
2776 * @content: the XML content of the child if any.
2777 *
2778 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002779 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2780 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002781 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002782 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2783 * references. XML special chars must be escaped first by using
2784 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002785 *
2786 * Returns a pointer to the new node object.
2787 */
2788xmlNodePtr
2789xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2790 const xmlChar *name, const xmlChar *content) {
2791 xmlNodePtr cur, prev;
2792
2793 if (parent == NULL) {
2794#ifdef DEBUG_TREE
2795 xmlGenericError(xmlGenericErrorContext,
2796 "xmlNewChild : parent == NULL\n");
2797#endif
2798 return(NULL);
2799 }
2800
2801 if (name == NULL) {
2802#ifdef DEBUG_TREE
2803 xmlGenericError(xmlGenericErrorContext,
2804 "xmlNewChild : name == NULL\n");
2805#endif
2806 return(NULL);
2807 }
2808
2809 /*
2810 * Allocate a new node
2811 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002812 if (parent->type == XML_ELEMENT_NODE) {
2813 if (ns == NULL)
2814 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2815 else
2816 cur = xmlNewDocNode(parent->doc, ns, name, content);
2817 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2818 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2819 if (ns == NULL)
2820 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2821 else
2822 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002823 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2824 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002825 } else {
2826 return(NULL);
2827 }
Owen Taylor3473f882001-02-23 17:55:21 +00002828 if (cur == NULL) return(NULL);
2829
2830 /*
2831 * add the new element at the end of the children list.
2832 */
2833 cur->type = XML_ELEMENT_NODE;
2834 cur->parent = parent;
2835 cur->doc = parent->doc;
2836 if (parent->children == NULL) {
2837 parent->children = cur;
2838 parent->last = cur;
2839 } else {
2840 prev = parent->last;
2841 prev->next = cur;
2842 cur->prev = prev;
2843 parent->last = cur;
2844 }
2845
2846 return(cur);
2847}
Daniel Veillard652327a2003-09-29 18:02:38 +00002848#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002849
2850/**
Rob Richards65815122006-02-25 17:13:33 +00002851 * xmlAddPropSibling:
2852 * @prev: the attribute to which @prop is added after
2853 * @cur: the base attribute passed to calling function
2854 * @prop: the new attribute
2855 *
2856 * Add a new attribute after @prev using @cur as base attribute.
2857 * When inserting before @cur, @prev is passed as @cur->prev.
2858 * When inserting after @cur, @prev is passed as @cur.
2859 * If an existing attribute is found it is detroyed prior to adding @prop.
2860 *
2861 * Returns the attribute being inserted or NULL in case of error.
2862 */
2863static xmlNodePtr
2864xmlAddPropSibling(xmlNodePtr prev, xmlNodePtr cur, xmlNodePtr prop) {
2865 xmlAttrPtr attr;
2866
2867 if (cur->type != XML_ATTRIBUTE_NODE)
2868 return(NULL);
2869
2870 /* check if an attribute with the same name exists */
2871 if (prop->ns == NULL)
2872 attr = xmlHasNsProp(cur->parent, prop->name, NULL);
2873 else
2874 attr = xmlHasNsProp(cur->parent, prop->name, prop->ns->href);
2875
2876 if (prop->doc != cur->doc) {
2877 xmlSetTreeDoc(prop, cur->doc);
2878 }
2879 prop->parent = cur->parent;
2880 prop->prev = prev;
2881 if (prev != NULL) {
2882 prop->next = prev->next;
2883 prev->next = prop;
2884 if (prop->next)
2885 prop->next->prev = prop;
2886 } else {
2887 prop->next = cur;
2888 cur->prev = prop;
2889 }
2890 if (prop->prev == NULL && prop->parent != NULL)
2891 prop->parent->properties = (xmlAttrPtr) prop;
2892 if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) {
2893 /* different instance, destroy it (attributes must be unique) */
2894 xmlRemoveProp((xmlAttrPtr) attr);
2895 }
2896 return prop;
2897}
2898
2899/**
Owen Taylor3473f882001-02-23 17:55:21 +00002900 * xmlAddNextSibling:
2901 * @cur: the child node
2902 * @elem: the new node
2903 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002904 * Add a new node @elem as the next sibling of @cur
2905 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002906 * first unlinked from its existing context.
2907 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002908 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2909 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002910 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002911 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002912 */
2913xmlNodePtr
2914xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2915 if (cur == NULL) {
2916#ifdef DEBUG_TREE
2917 xmlGenericError(xmlGenericErrorContext,
2918 "xmlAddNextSibling : cur == NULL\n");
2919#endif
2920 return(NULL);
2921 }
2922 if (elem == NULL) {
2923#ifdef DEBUG_TREE
2924 xmlGenericError(xmlGenericErrorContext,
2925 "xmlAddNextSibling : elem == NULL\n");
2926#endif
2927 return(NULL);
2928 }
2929
Rob Richards19dc9612005-10-28 16:15:16 +00002930 if (cur == elem) {
2931#ifdef DEBUG_TREE
2932 xmlGenericError(xmlGenericErrorContext,
2933 "xmlAddNextSibling : cur == elem\n");
2934#endif
2935 return(NULL);
2936 }
2937
Owen Taylor3473f882001-02-23 17:55:21 +00002938 xmlUnlinkNode(elem);
2939
2940 if (elem->type == XML_TEXT_NODE) {
2941 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002942 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002943 xmlFreeNode(elem);
2944 return(cur);
2945 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002946 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2947 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002948 xmlChar *tmp;
2949
2950 tmp = xmlStrdup(elem->content);
2951 tmp = xmlStrcat(tmp, cur->next->content);
2952 xmlNodeSetContent(cur->next, tmp);
2953 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002954 xmlFreeNode(elem);
2955 return(cur->next);
2956 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002957 } else if (elem->type == XML_ATTRIBUTE_NODE) {
Rob Richards65815122006-02-25 17:13:33 +00002958 return xmlAddPropSibling(cur, cur, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00002959 }
2960
2961 if (elem->doc != cur->doc) {
2962 xmlSetTreeDoc(elem, cur->doc);
2963 }
2964 elem->parent = cur->parent;
2965 elem->prev = cur;
2966 elem->next = cur->next;
2967 cur->next = elem;
2968 if (elem->next != NULL)
2969 elem->next->prev = elem;
Rob Richards65815122006-02-25 17:13:33 +00002970 if ((elem->parent != NULL) && (elem->parent->last == cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002971 elem->parent->last = elem;
2972 return(elem);
2973}
2974
William M. Brack21e4ef22005-01-02 09:53:13 +00002975#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
2976 defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002977/**
2978 * xmlAddPrevSibling:
2979 * @cur: the child node
2980 * @elem: the new node
2981 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002982 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002983 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002984 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002985 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002986 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2987 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002988 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002989 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002990 */
2991xmlNodePtr
2992xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2993 if (cur == NULL) {
2994#ifdef DEBUG_TREE
2995 xmlGenericError(xmlGenericErrorContext,
2996 "xmlAddPrevSibling : cur == NULL\n");
2997#endif
2998 return(NULL);
2999 }
3000 if (elem == NULL) {
3001#ifdef DEBUG_TREE
3002 xmlGenericError(xmlGenericErrorContext,
3003 "xmlAddPrevSibling : elem == NULL\n");
3004#endif
3005 return(NULL);
3006 }
3007
Rob Richards19dc9612005-10-28 16:15:16 +00003008 if (cur == elem) {
3009#ifdef DEBUG_TREE
3010 xmlGenericError(xmlGenericErrorContext,
3011 "xmlAddPrevSibling : cur == elem\n");
3012#endif
3013 return(NULL);
3014 }
3015
Owen Taylor3473f882001-02-23 17:55:21 +00003016 xmlUnlinkNode(elem);
3017
3018 if (elem->type == XML_TEXT_NODE) {
3019 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00003020 xmlChar *tmp;
3021
3022 tmp = xmlStrdup(elem->content);
3023 tmp = xmlStrcat(tmp, cur->content);
3024 xmlNodeSetContent(cur, tmp);
3025 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00003026 xmlFreeNode(elem);
3027 return(cur);
3028 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00003029 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
3030 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003031 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003032 xmlFreeNode(elem);
3033 return(cur->prev);
3034 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003035 } else if (elem->type == XML_ATTRIBUTE_NODE) {
Rob Richards65815122006-02-25 17:13:33 +00003036 return xmlAddPropSibling(cur->prev, cur, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00003037 }
3038
3039 if (elem->doc != cur->doc) {
3040 xmlSetTreeDoc(elem, cur->doc);
3041 }
3042 elem->parent = cur->parent;
3043 elem->next = cur;
3044 elem->prev = cur->prev;
3045 cur->prev = elem;
3046 if (elem->prev != NULL)
3047 elem->prev->next = elem;
Rob Richards65815122006-02-25 17:13:33 +00003048 if ((elem->parent != NULL) && (elem->parent->children == cur)) {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003049 elem->parent->children = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003050 }
Owen Taylor3473f882001-02-23 17:55:21 +00003051 return(elem);
3052}
Daniel Veillard652327a2003-09-29 18:02:38 +00003053#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003054
3055/**
3056 * xmlAddSibling:
3057 * @cur: the child node
3058 * @elem: the new node
3059 *
3060 * Add a new element @elem to the list of siblings of @cur
3061 * merging adjacent TEXT nodes (@elem may be freed)
3062 * If the new element was already inserted in a document it is
3063 * first unlinked from its existing context.
3064 *
3065 * Returns the new element or NULL in case of error.
3066 */
3067xmlNodePtr
3068xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
3069 xmlNodePtr parent;
3070
3071 if (cur == NULL) {
3072#ifdef DEBUG_TREE
3073 xmlGenericError(xmlGenericErrorContext,
3074 "xmlAddSibling : cur == NULL\n");
3075#endif
3076 return(NULL);
3077 }
3078
3079 if (elem == NULL) {
3080#ifdef DEBUG_TREE
3081 xmlGenericError(xmlGenericErrorContext,
3082 "xmlAddSibling : elem == NULL\n");
3083#endif
3084 return(NULL);
3085 }
3086
3087 /*
3088 * Constant time is we can rely on the ->parent->last to find
3089 * the last sibling.
3090 */
Rob Richards65815122006-02-25 17:13:33 +00003091 if ((cur->type != XML_ATTRIBUTE_NODE) && (cur->parent != NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00003092 (cur->parent->children != NULL) &&
3093 (cur->parent->last != NULL) &&
3094 (cur->parent->last->next == NULL)) {
3095 cur = cur->parent->last;
3096 } else {
3097 while (cur->next != NULL) cur = cur->next;
3098 }
3099
3100 xmlUnlinkNode(elem);
3101
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003102 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3103 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003104 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003105 xmlFreeNode(elem);
3106 return(cur);
Rob Richards65815122006-02-25 17:13:33 +00003107 } else if (elem->type == XML_ATTRIBUTE_NODE) {
3108 return xmlAddPropSibling(cur, cur, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00003109 }
3110
3111 if (elem->doc != cur->doc) {
3112 xmlSetTreeDoc(elem, cur->doc);
3113 }
3114 parent = cur->parent;
3115 elem->prev = cur;
3116 elem->next = NULL;
3117 elem->parent = parent;
3118 cur->next = elem;
3119 if (parent != NULL)
3120 parent->last = elem;
3121
3122 return(elem);
3123}
3124
3125/**
3126 * xmlAddChildList:
3127 * @parent: the parent node
3128 * @cur: the first node in the list
3129 *
3130 * Add a list of node at the end of the child list of the parent
3131 * merging adjacent TEXT nodes (@cur may be freed)
3132 *
3133 * Returns the last child or NULL in case of error.
3134 */
3135xmlNodePtr
3136xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3137 xmlNodePtr prev;
3138
3139 if (parent == NULL) {
3140#ifdef DEBUG_TREE
3141 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003142 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003143#endif
3144 return(NULL);
3145 }
3146
3147 if (cur == NULL) {
3148#ifdef DEBUG_TREE
3149 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003150 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003151#endif
3152 return(NULL);
3153 }
3154
3155 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3156 (cur->doc != parent->doc)) {
3157#ifdef DEBUG_TREE
3158 xmlGenericError(xmlGenericErrorContext,
3159 "Elements moved to a different document\n");
3160#endif
3161 }
3162
3163 /*
3164 * add the first element at the end of the children list.
3165 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003166
Owen Taylor3473f882001-02-23 17:55:21 +00003167 if (parent->children == NULL) {
3168 parent->children = cur;
3169 } else {
3170 /*
3171 * If cur and parent->last both are TEXT nodes, then merge them.
3172 */
3173 if ((cur->type == XML_TEXT_NODE) &&
3174 (parent->last->type == XML_TEXT_NODE) &&
3175 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003176 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003177 /*
3178 * if it's the only child, nothing more to be done.
3179 */
3180 if (cur->next == NULL) {
3181 xmlFreeNode(cur);
3182 return(parent->last);
3183 }
3184 prev = cur;
3185 cur = cur->next;
3186 xmlFreeNode(prev);
3187 }
3188 prev = parent->last;
3189 prev->next = cur;
3190 cur->prev = prev;
3191 }
3192 while (cur->next != NULL) {
3193 cur->parent = parent;
3194 if (cur->doc != parent->doc) {
3195 xmlSetTreeDoc(cur, parent->doc);
3196 }
3197 cur = cur->next;
3198 }
3199 cur->parent = parent;
3200 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3201 parent->last = cur;
3202
3203 return(cur);
3204}
3205
3206/**
3207 * xmlAddChild:
3208 * @parent: the parent node
3209 * @cur: the child node
3210 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003211 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003212 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003213 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3214 * If there is an attribute with equal name, it is first destroyed.
3215 *
Owen Taylor3473f882001-02-23 17:55:21 +00003216 * Returns the child or NULL in case of error.
3217 */
3218xmlNodePtr
3219xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3220 xmlNodePtr prev;
3221
3222 if (parent == NULL) {
3223#ifdef DEBUG_TREE
3224 xmlGenericError(xmlGenericErrorContext,
3225 "xmlAddChild : parent == NULL\n");
3226#endif
3227 return(NULL);
3228 }
3229
3230 if (cur == NULL) {
3231#ifdef DEBUG_TREE
3232 xmlGenericError(xmlGenericErrorContext,
3233 "xmlAddChild : child == NULL\n");
3234#endif
3235 return(NULL);
3236 }
3237
Rob Richards19dc9612005-10-28 16:15:16 +00003238 if (parent == cur) {
3239#ifdef DEBUG_TREE
3240 xmlGenericError(xmlGenericErrorContext,
3241 "xmlAddChild : parent == cur\n");
3242#endif
3243 return(NULL);
3244 }
Owen Taylor3473f882001-02-23 17:55:21 +00003245 /*
3246 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003247 * cur is then freed.
3248 */
3249 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003250 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003251 (parent->content != NULL) &&
Rob Richards19dc9612005-10-28 16:15:16 +00003252 (parent->name == cur->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003253 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003254 xmlFreeNode(cur);
3255 return(parent);
3256 }
3257 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003258 (parent->last->name == cur->name) &&
3259 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003260 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003261 xmlFreeNode(cur);
3262 return(parent->last);
3263 }
3264 }
3265
3266 /*
3267 * add the new element at the end of the children list.
3268 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003269 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003270 cur->parent = parent;
3271 if (cur->doc != parent->doc) {
3272 xmlSetTreeDoc(cur, parent->doc);
3273 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003274 /* this check prevents a loop on tree-traversions if a developer
3275 * tries to add a node to its parent multiple times
3276 */
3277 if (prev == parent)
3278 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003279
3280 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003281 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003282 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003283 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003284 (parent->content != NULL) &&
3285 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003286 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003287 xmlFreeNode(cur);
3288 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003289 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003290 if (cur->type == XML_ATTRIBUTE_NODE) {
Rob Richards19dc9612005-10-28 16:15:16 +00003291 if (parent->type != XML_ELEMENT_NODE)
3292 return(NULL);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003293 if (parent->properties == NULL) {
3294 parent->properties = (xmlAttrPtr) cur;
3295 } else {
3296 /* check if an attribute with the same name exists */
3297 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003298
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003299 if (cur->ns == NULL)
Rob Richardsc342ec62005-10-25 00:10:12 +00003300 lastattr = xmlHasNsProp(parent, cur->name, NULL);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003301 else
3302 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
Rob Richardsc342ec62005-10-25 00:10:12 +00003303 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur) && (lastattr->type != XML_ATTRIBUTE_DECL)) {
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003304 /* different instance, destroy it (attributes must be unique) */
Rob Richards19dc9612005-10-28 16:15:16 +00003305 xmlUnlinkNode((xmlNodePtr) lastattr);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003306 xmlFreeProp(lastattr);
3307 }
Rob Richards19dc9612005-10-28 16:15:16 +00003308 if (lastattr == (xmlAttrPtr) cur)
3309 return(cur);
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003310 /* find the end */
3311 lastattr = parent->properties;
3312 while (lastattr->next != NULL) {
3313 lastattr = lastattr->next;
3314 }
3315 lastattr->next = (xmlAttrPtr) cur;
3316 ((xmlAttrPtr) cur)->prev = lastattr;
3317 }
3318 } else {
3319 if (parent->children == NULL) {
3320 parent->children = cur;
3321 parent->last = cur;
3322 } else {
3323 prev = parent->last;
3324 prev->next = cur;
3325 cur->prev = prev;
3326 parent->last = cur;
3327 }
3328 }
Owen Taylor3473f882001-02-23 17:55:21 +00003329 return(cur);
3330}
3331
3332/**
3333 * xmlGetLastChild:
3334 * @parent: the parent node
3335 *
3336 * Search the last child of a node.
3337 * Returns the last child or NULL if none.
3338 */
3339xmlNodePtr
3340xmlGetLastChild(xmlNodePtr parent) {
3341 if (parent == NULL) {
3342#ifdef DEBUG_TREE
3343 xmlGenericError(xmlGenericErrorContext,
3344 "xmlGetLastChild : parent == NULL\n");
3345#endif
3346 return(NULL);
3347 }
3348 return(parent->last);
3349}
3350
3351/**
3352 * xmlFreeNodeList:
3353 * @cur: the first node in the list
3354 *
3355 * Free a node and all its siblings, this is a recursive behaviour, all
3356 * the children are freed too.
3357 */
3358void
3359xmlFreeNodeList(xmlNodePtr cur) {
3360 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003361 xmlDictPtr dict = NULL;
3362
3363 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003364 if (cur->type == XML_NAMESPACE_DECL) {
3365 xmlFreeNsList((xmlNsPtr) cur);
3366 return;
3367 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003368 if ((cur->type == XML_DOCUMENT_NODE) ||
3369#ifdef LIBXML_DOCB_ENABLED
3370 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003371#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003372 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003373 xmlFreeDoc((xmlDocPtr) cur);
3374 return;
3375 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003376 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003377 while (cur != NULL) {
3378 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003379 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003380
Daniel Veillarda880b122003-04-21 21:36:41 +00003381 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003382 xmlDeregisterNodeDefaultValue(cur);
3383
Daniel Veillard02141ea2001-04-30 11:46:40 +00003384 if ((cur->children != NULL) &&
3385 (cur->type != XML_ENTITY_REF_NODE))
3386 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003387 if (((cur->type == XML_ELEMENT_NODE) ||
3388 (cur->type == XML_XINCLUDE_START) ||
3389 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003390 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003391 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003392 if ((cur->type != XML_ELEMENT_NODE) &&
3393 (cur->type != XML_XINCLUDE_START) &&
3394 (cur->type != XML_XINCLUDE_END) &&
Daniel Veillard8874b942005-08-25 13:19:21 +00003395 (cur->type != XML_ENTITY_REF_NODE) &&
3396 (cur->content != (xmlChar *) &(cur->properties))) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003397 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003398 }
3399 if (((cur->type == XML_ELEMENT_NODE) ||
3400 (cur->type == XML_XINCLUDE_START) ||
3401 (cur->type == XML_XINCLUDE_END)) &&
3402 (cur->nsDef != NULL))
3403 xmlFreeNsList(cur->nsDef);
3404
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003405 /*
3406 * When a node is a text node or a comment, it uses a global static
3407 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003408 * Otherwise the node name might come from the document's
3409 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003410 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003411 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003412 (cur->type != XML_TEXT_NODE) &&
3413 (cur->type != XML_COMMENT_NODE))
3414 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003415 xmlFree(cur);
3416 }
Owen Taylor3473f882001-02-23 17:55:21 +00003417 cur = next;
3418 }
3419}
3420
3421/**
3422 * xmlFreeNode:
3423 * @cur: the node
3424 *
3425 * Free a node, this is a recursive behaviour, all the children are freed too.
3426 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3427 */
3428void
3429xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003430 xmlDictPtr dict = NULL;
3431
3432 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003433
Daniel Veillard02141ea2001-04-30 11:46:40 +00003434 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003435 if (cur->type == XML_DTD_NODE) {
3436 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003437 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003438 }
3439 if (cur->type == XML_NAMESPACE_DECL) {
3440 xmlFreeNs((xmlNsPtr) cur);
3441 return;
3442 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003443 if (cur->type == XML_ATTRIBUTE_NODE) {
3444 xmlFreeProp((xmlAttrPtr) cur);
3445 return;
3446 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003447
Daniel Veillarda880b122003-04-21 21:36:41 +00003448 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003449 xmlDeregisterNodeDefaultValue(cur);
3450
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003451 if (cur->doc != NULL) dict = cur->doc->dict;
3452
Owen Taylor3473f882001-02-23 17:55:21 +00003453 if ((cur->children != NULL) &&
3454 (cur->type != XML_ENTITY_REF_NODE))
3455 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003456 if (((cur->type == XML_ELEMENT_NODE) ||
3457 (cur->type == XML_XINCLUDE_START) ||
3458 (cur->type == XML_XINCLUDE_END)) &&
3459 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003460 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003461 if ((cur->type != XML_ELEMENT_NODE) &&
3462 (cur->content != NULL) &&
3463 (cur->type != XML_ENTITY_REF_NODE) &&
3464 (cur->type != XML_XINCLUDE_END) &&
Daniel Veillard8874b942005-08-25 13:19:21 +00003465 (cur->type != XML_XINCLUDE_START) &&
3466 (cur->content != (xmlChar *) &(cur->properties))) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003467 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003468 }
3469
Daniel Veillardacd370f2001-06-09 17:17:51 +00003470 /*
3471 * When a node is a text node or a comment, it uses a global static
3472 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003473 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003474 */
Owen Taylor3473f882001-02-23 17:55:21 +00003475 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003476 (cur->type != XML_TEXT_NODE) &&
3477 (cur->type != XML_COMMENT_NODE))
3478 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003479
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003480 if (((cur->type == XML_ELEMENT_NODE) ||
3481 (cur->type == XML_XINCLUDE_START) ||
3482 (cur->type == XML_XINCLUDE_END)) &&
3483 (cur->nsDef != NULL))
3484 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003485 xmlFree(cur);
3486}
3487
3488/**
3489 * xmlUnlinkNode:
3490 * @cur: the node
3491 *
3492 * Unlink a node from it's current context, the node is not freed
3493 */
3494void
3495xmlUnlinkNode(xmlNodePtr cur) {
3496 if (cur == NULL) {
3497#ifdef DEBUG_TREE
3498 xmlGenericError(xmlGenericErrorContext,
3499 "xmlUnlinkNode : node == NULL\n");
3500#endif
3501 return;
3502 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003503 if (cur->type == XML_DTD_NODE) {
3504 xmlDocPtr doc;
3505 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003506 if (doc != NULL) {
3507 if (doc->intSubset == (xmlDtdPtr) cur)
3508 doc->intSubset = NULL;
3509 if (doc->extSubset == (xmlDtdPtr) cur)
3510 doc->extSubset = NULL;
3511 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003512 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003513 if (cur->parent != NULL) {
3514 xmlNodePtr parent;
3515 parent = cur->parent;
3516 if (cur->type == XML_ATTRIBUTE_NODE) {
3517 if (parent->properties == (xmlAttrPtr) cur)
3518 parent->properties = ((xmlAttrPtr) cur)->next;
3519 } else {
3520 if (parent->children == cur)
3521 parent->children = cur->next;
3522 if (parent->last == cur)
3523 parent->last = cur->prev;
3524 }
3525 cur->parent = NULL;
3526 }
Owen Taylor3473f882001-02-23 17:55:21 +00003527 if (cur->next != NULL)
3528 cur->next->prev = cur->prev;
3529 if (cur->prev != NULL)
3530 cur->prev->next = cur->next;
3531 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003532}
3533
Daniel Veillard2156d432004-03-04 15:59:36 +00003534#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003535/**
3536 * xmlReplaceNode:
3537 * @old: the old node
3538 * @cur: the node
3539 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003540 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003541 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003542 * first unlinked from its existing context.
3543 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003544 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003545 */
3546xmlNodePtr
3547xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00003548 if (old == cur) return(NULL);
Daniel Veillarda03e3652004-11-02 18:45:30 +00003549 if ((old == NULL) || (old->parent == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003550#ifdef DEBUG_TREE
3551 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda03e3652004-11-02 18:45:30 +00003552 "xmlReplaceNode : old == NULL or without parent\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003553#endif
3554 return(NULL);
3555 }
3556 if (cur == NULL) {
3557 xmlUnlinkNode(old);
3558 return(old);
3559 }
3560 if (cur == old) {
3561 return(old);
3562 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003563 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3564#ifdef DEBUG_TREE
3565 xmlGenericError(xmlGenericErrorContext,
3566 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3567#endif
3568 return(old);
3569 }
3570 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3571#ifdef DEBUG_TREE
3572 xmlGenericError(xmlGenericErrorContext,
3573 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3574#endif
3575 return(old);
3576 }
Owen Taylor3473f882001-02-23 17:55:21 +00003577 xmlUnlinkNode(cur);
Daniel Veillard64d7d122005-05-11 18:03:42 +00003578 xmlSetTreeDoc(cur, old->doc);
Owen Taylor3473f882001-02-23 17:55:21 +00003579 cur->parent = old->parent;
3580 cur->next = old->next;
3581 if (cur->next != NULL)
3582 cur->next->prev = cur;
3583 cur->prev = old->prev;
3584 if (cur->prev != NULL)
3585 cur->prev->next = cur;
3586 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003587 if (cur->type == XML_ATTRIBUTE_NODE) {
3588 if (cur->parent->properties == (xmlAttrPtr)old)
3589 cur->parent->properties = ((xmlAttrPtr) cur);
3590 } else {
3591 if (cur->parent->children == old)
3592 cur->parent->children = cur;
3593 if (cur->parent->last == old)
3594 cur->parent->last = cur;
3595 }
Owen Taylor3473f882001-02-23 17:55:21 +00003596 }
3597 old->next = old->prev = NULL;
3598 old->parent = NULL;
3599 return(old);
3600}
Daniel Veillard652327a2003-09-29 18:02:38 +00003601#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003602
3603/************************************************************************
3604 * *
3605 * Copy operations *
3606 * *
3607 ************************************************************************/
3608
3609/**
3610 * xmlCopyNamespace:
3611 * @cur: the namespace
3612 *
3613 * Do a copy of the namespace.
3614 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003615 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003616 */
3617xmlNsPtr
3618xmlCopyNamespace(xmlNsPtr cur) {
3619 xmlNsPtr ret;
3620
3621 if (cur == NULL) return(NULL);
3622 switch (cur->type) {
3623 case XML_LOCAL_NAMESPACE:
3624 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3625 break;
3626 default:
3627#ifdef DEBUG_TREE
3628 xmlGenericError(xmlGenericErrorContext,
3629 "xmlCopyNamespace: invalid type %d\n", cur->type);
3630#endif
3631 return(NULL);
3632 }
3633 return(ret);
3634}
3635
3636/**
3637 * xmlCopyNamespaceList:
3638 * @cur: the first namespace
3639 *
3640 * Do a copy of an namespace list.
3641 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003642 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003643 */
3644xmlNsPtr
3645xmlCopyNamespaceList(xmlNsPtr cur) {
3646 xmlNsPtr ret = NULL;
3647 xmlNsPtr p = NULL,q;
3648
3649 while (cur != NULL) {
3650 q = xmlCopyNamespace(cur);
3651 if (p == NULL) {
3652 ret = p = q;
3653 } else {
3654 p->next = q;
3655 p = q;
3656 }
3657 cur = cur->next;
3658 }
3659 return(ret);
3660}
3661
3662static xmlNodePtr
3663xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
Rob Richards19dc9612005-10-28 16:15:16 +00003664
3665static xmlAttrPtr
3666xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003667 xmlAttrPtr ret;
3668
3669 if (cur == NULL) return(NULL);
3670 if (target != NULL)
3671 ret = xmlNewDocProp(target->doc, cur->name, NULL);
Rob Richards19dc9612005-10-28 16:15:16 +00003672 else if (doc != NULL)
3673 ret = xmlNewDocProp(doc, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003674 else if (cur->parent != NULL)
3675 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3676 else if (cur->children != NULL)
3677 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3678 else
3679 ret = xmlNewDocProp(NULL, cur->name, NULL);
3680 if (ret == NULL) return(NULL);
3681 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003682
Owen Taylor3473f882001-02-23 17:55:21 +00003683 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003684 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003685
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003686 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3687 if (ns == NULL) {
3688 /*
3689 * Humm, we are copying an element whose namespace is defined
3690 * out of the new tree scope. Search it in the original tree
3691 * and add it at the top of the new tree
3692 */
3693 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3694 if (ns != NULL) {
3695 xmlNodePtr root = target;
3696 xmlNodePtr pred = NULL;
3697
3698 while (root->parent != NULL) {
3699 pred = root;
3700 root = root->parent;
3701 }
3702 if (root == (xmlNodePtr) target->doc) {
3703 /* correct possibly cycling above the document elt */
3704 root = pred;
3705 }
3706 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3707 }
3708 } else {
3709 /*
3710 * we have to find something appropriate here since
3711 * we cant be sure, that the namespce we found is identified
3712 * by the prefix
3713 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003714 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003715 /* this is the nice case */
3716 ret->ns = ns;
3717 } else {
3718 /*
3719 * we are in trouble: we need a new reconcilied namespace.
3720 * This is expensive
3721 */
3722 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3723 }
3724 }
3725
Owen Taylor3473f882001-02-23 17:55:21 +00003726 } else
3727 ret->ns = NULL;
3728
3729 if (cur->children != NULL) {
3730 xmlNodePtr tmp;
3731
3732 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3733 ret->last = NULL;
3734 tmp = ret->children;
3735 while (tmp != NULL) {
3736 /* tmp->parent = (xmlNodePtr)ret; */
3737 if (tmp->next == NULL)
3738 ret->last = tmp;
3739 tmp = tmp->next;
3740 }
3741 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003742 /*
3743 * Try to handle IDs
3744 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003745 if ((target!= NULL) && (cur!= NULL) &&
3746 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003747 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3748 if (xmlIsID(cur->doc, cur->parent, cur)) {
3749 xmlChar *id;
3750
3751 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3752 if (id != NULL) {
3753 xmlAddID(NULL, target->doc, id, ret);
3754 xmlFree(id);
3755 }
3756 }
3757 }
Owen Taylor3473f882001-02-23 17:55:21 +00003758 return(ret);
3759}
3760
3761/**
Rob Richards19dc9612005-10-28 16:15:16 +00003762 * xmlCopyProp:
3763 * @target: the element where the attribute will be grafted
3764 * @cur: the attribute
3765 *
3766 * Do a copy of the attribute.
3767 *
3768 * Returns: a new #xmlAttrPtr, or NULL in case of error.
3769 */
3770xmlAttrPtr
3771xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3772 return xmlCopyPropInternal(NULL, target, cur);
3773}
3774
3775/**
Owen Taylor3473f882001-02-23 17:55:21 +00003776 * xmlCopyPropList:
3777 * @target: the element where the attributes will be grafted
3778 * @cur: the first attribute
3779 *
3780 * Do a copy of an attribute list.
3781 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003782 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003783 */
3784xmlAttrPtr
3785xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3786 xmlAttrPtr ret = NULL;
3787 xmlAttrPtr p = NULL,q;
3788
3789 while (cur != NULL) {
3790 q = xmlCopyProp(target, cur);
William M. Brack13dfa872004-09-18 04:52:08 +00003791 if (q == NULL)
3792 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003793 if (p == NULL) {
3794 ret = p = q;
3795 } else {
3796 p->next = q;
3797 q->prev = p;
3798 p = q;
3799 }
3800 cur = cur->next;
3801 }
3802 return(ret);
3803}
3804
3805/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003806 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003807 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003808 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003809 * tricky reason: namespaces. Doing a direct copy of a node
3810 * say RPM:Copyright without changing the namespace pointer to
3811 * something else can produce stale links. One way to do it is
3812 * to keep a reference counter but this doesn't work as soon
3813 * as one move the element or the subtree out of the scope of
3814 * the existing namespace. The actual solution seems to add
3815 * a copy of the namespace at the top of the copied tree if
3816 * not available in the subtree.
3817 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00003818 * The argument "recursive" normally indicates a recursive copy
3819 * of the node with values 0 (no) and 1 (yes). For XInclude,
3820 * however, we allow a value of 2 to indicate copy properties and
3821 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00003822 */
3823
3824static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003825xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00003826 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003827 xmlNodePtr ret;
3828
3829 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003830 switch (node->type) {
3831 case XML_TEXT_NODE:
3832 case XML_CDATA_SECTION_NODE:
3833 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003834 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003835 case XML_ENTITY_REF_NODE:
3836 case XML_ENTITY_NODE:
3837 case XML_PI_NODE:
3838 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003839 case XML_XINCLUDE_START:
3840 case XML_XINCLUDE_END:
3841 break;
3842 case XML_ATTRIBUTE_NODE:
Rob Richards19dc9612005-10-28 16:15:16 +00003843 return((xmlNodePtr) xmlCopyPropInternal(doc, parent, (xmlAttrPtr) node));
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003844 case XML_NAMESPACE_DECL:
3845 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3846
Daniel Veillard39196eb2001-06-19 18:09:42 +00003847 case XML_DOCUMENT_NODE:
3848 case XML_HTML_DOCUMENT_NODE:
3849#ifdef LIBXML_DOCB_ENABLED
3850 case XML_DOCB_DOCUMENT_NODE:
3851#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003852#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00003853 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00003854#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003855 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003856 case XML_NOTATION_NODE:
3857 case XML_DTD_NODE:
3858 case XML_ELEMENT_DECL:
3859 case XML_ATTRIBUTE_DECL:
3860 case XML_ENTITY_DECL:
3861 return(NULL);
3862 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003863
Owen Taylor3473f882001-02-23 17:55:21 +00003864 /*
3865 * Allocate a new node and fill the fields.
3866 */
3867 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3868 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003869 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003870 return(NULL);
3871 }
3872 memset(ret, 0, sizeof(xmlNode));
3873 ret->type = node->type;
3874
3875 ret->doc = doc;
3876 ret->parent = parent;
3877 if (node->name == xmlStringText)
3878 ret->name = xmlStringText;
3879 else if (node->name == xmlStringTextNoenc)
3880 ret->name = xmlStringTextNoenc;
3881 else if (node->name == xmlStringComment)
3882 ret->name = xmlStringComment;
Daniel Veillard03a53c32004-10-26 16:06:51 +00003883 else if (node->name != NULL) {
3884 if ((doc != NULL) && (doc->dict != NULL))
3885 ret->name = xmlDictLookup(doc->dict, node->name, -1);
3886 else
3887 ret->name = xmlStrdup(node->name);
3888 }
Daniel Veillard7db37732001-07-12 01:20:08 +00003889 if ((node->type != XML_ELEMENT_NODE) &&
3890 (node->content != NULL) &&
3891 (node->type != XML_ENTITY_REF_NODE) &&
3892 (node->type != XML_XINCLUDE_END) &&
3893 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003894 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003895 }else{
3896 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003897 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003898 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003899 if (parent != NULL) {
3900 xmlNodePtr tmp;
3901
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003902 /*
3903 * this is a tricky part for the node register thing:
3904 * in case ret does get coalesced in xmlAddChild
3905 * the deregister-node callback is called; so we register ret now already
3906 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003907 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003908 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3909
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003910 tmp = xmlAddChild(parent, ret);
3911 /* node could have coalesced */
3912 if (tmp != ret)
3913 return(tmp);
3914 }
Owen Taylor3473f882001-02-23 17:55:21 +00003915
William M. Brack57e9e912004-03-09 16:19:02 +00003916 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003917 goto out;
Daniel Veillard8874b942005-08-25 13:19:21 +00003918 if ((node->type == XML_ELEMENT_NODE) && (node->nsDef != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00003919 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3920
3921 if (node->ns != NULL) {
3922 xmlNsPtr ns;
3923
3924 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3925 if (ns == NULL) {
3926 /*
3927 * Humm, we are copying an element whose namespace is defined
3928 * out of the new tree scope. Search it in the original tree
3929 * and add it at the top of the new tree
3930 */
3931 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3932 if (ns != NULL) {
3933 xmlNodePtr root = ret;
3934
3935 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003936 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003937 }
3938 } else {
3939 /*
3940 * reference the existing namespace definition in our own tree.
3941 */
3942 ret->ns = ns;
3943 }
3944 }
Daniel Veillard8874b942005-08-25 13:19:21 +00003945 if ((node->type == XML_ELEMENT_NODE) && (node->properties != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00003946 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003947 if (node->type == XML_ENTITY_REF_NODE) {
3948 if ((doc == NULL) || (node->doc != doc)) {
3949 /*
3950 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003951 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003952 * we cannot keep the reference. Try to find it in the
3953 * target document.
3954 */
3955 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3956 } else {
3957 ret->children = node->children;
3958 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003959 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00003960 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003961 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003962 UPDATE_LAST_CHILD_AND_PARENT(ret)
3963 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003964
3965out:
3966 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00003967 if ((parent == NULL) &&
3968 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003969 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003970 return(ret);
3971}
3972
3973static xmlNodePtr
3974xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3975 xmlNodePtr ret = NULL;
3976 xmlNodePtr p = NULL,q;
3977
3978 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003979#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003980 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003981 if (doc == NULL) {
3982 node = node->next;
3983 continue;
3984 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003985 if (doc->intSubset == NULL) {
3986 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3987 q->doc = doc;
3988 q->parent = parent;
3989 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003990 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003991 } else {
3992 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003993 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003994 }
3995 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003996#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003997 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003998 if (ret == NULL) {
3999 q->prev = NULL;
4000 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004001 } else if (p != q) {
4002 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00004003 p->next = q;
4004 q->prev = p;
4005 p = q;
4006 }
4007 node = node->next;
4008 }
4009 return(ret);
4010}
4011
4012/**
4013 * xmlCopyNode:
4014 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00004015 * @extended: if 1 do a recursive copy (properties, namespaces and children
4016 * when applicable)
4017 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00004018 *
4019 * Do a copy of the node.
4020 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004021 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004022 */
4023xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00004024xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00004025 xmlNodePtr ret;
4026
William M. Brack57e9e912004-03-09 16:19:02 +00004027 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00004028 return(ret);
4029}
4030
4031/**
Daniel Veillard82daa812001-04-12 08:55:36 +00004032 * xmlDocCopyNode:
4033 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00004034 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004035 * @extended: if 1 do a recursive copy (properties, namespaces and children
4036 * when applicable)
4037 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00004038 *
4039 * Do a copy of the node to a given document.
4040 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004041 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00004042 */
4043xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00004044xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00004045 xmlNodePtr ret;
4046
William M. Brack57e9e912004-03-09 16:19:02 +00004047 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00004048 return(ret);
4049}
4050
4051/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00004052 * xmlDocCopyNodeList:
4053 * @doc: the target document
4054 * @node: the first node in the list.
4055 *
4056 * Do a recursive copy of the node list.
4057 *
4058 * Returns: a new #xmlNodePtr, or NULL in case of error.
4059 */
4060xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) {
4061 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
4062 return(ret);
4063}
4064
4065/**
Owen Taylor3473f882001-02-23 17:55:21 +00004066 * xmlCopyNodeList:
4067 * @node: the first node in the list.
4068 *
4069 * Do a recursive copy of the node list.
Daniel Veillard03a53c32004-10-26 16:06:51 +00004070 * Use xmlDocCopyNodeList() if possible to ensure string interning.
Owen Taylor3473f882001-02-23 17:55:21 +00004071 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004072 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004073 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00004074xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00004075 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
4076 return(ret);
4077}
4078
Daniel Veillard2156d432004-03-04 15:59:36 +00004079#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004080/**
Owen Taylor3473f882001-02-23 17:55:21 +00004081 * xmlCopyDtd:
4082 * @dtd: the dtd
4083 *
4084 * Do a copy of the dtd.
4085 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004086 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004087 */
4088xmlDtdPtr
4089xmlCopyDtd(xmlDtdPtr dtd) {
4090 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004091 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00004092
4093 if (dtd == NULL) return(NULL);
4094 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4095 if (ret == NULL) return(NULL);
4096 if (dtd->entities != NULL)
4097 ret->entities = (void *) xmlCopyEntitiesTable(
4098 (xmlEntitiesTablePtr) dtd->entities);
4099 if (dtd->notations != NULL)
4100 ret->notations = (void *) xmlCopyNotationTable(
4101 (xmlNotationTablePtr) dtd->notations);
4102 if (dtd->elements != NULL)
4103 ret->elements = (void *) xmlCopyElementTable(
4104 (xmlElementTablePtr) dtd->elements);
4105 if (dtd->attributes != NULL)
4106 ret->attributes = (void *) xmlCopyAttributeTable(
4107 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004108 if (dtd->pentities != NULL)
4109 ret->pentities = (void *) xmlCopyEntitiesTable(
4110 (xmlEntitiesTablePtr) dtd->pentities);
4111
4112 cur = dtd->children;
4113 while (cur != NULL) {
4114 q = NULL;
4115
4116 if (cur->type == XML_ENTITY_DECL) {
4117 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4118 switch (tmp->etype) {
4119 case XML_INTERNAL_GENERAL_ENTITY:
4120 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4121 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4122 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4123 break;
4124 case XML_INTERNAL_PARAMETER_ENTITY:
4125 case XML_EXTERNAL_PARAMETER_ENTITY:
4126 q = (xmlNodePtr)
4127 xmlGetParameterEntityFromDtd(ret, tmp->name);
4128 break;
4129 case XML_INTERNAL_PREDEFINED_ENTITY:
4130 break;
4131 }
4132 } else if (cur->type == XML_ELEMENT_DECL) {
4133 xmlElementPtr tmp = (xmlElementPtr) cur;
4134 q = (xmlNodePtr)
4135 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4136 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4137 xmlAttributePtr tmp = (xmlAttributePtr) cur;
4138 q = (xmlNodePtr)
4139 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4140 } else if (cur->type == XML_COMMENT_NODE) {
4141 q = xmlCopyNode(cur, 0);
4142 }
4143
4144 if (q == NULL) {
4145 cur = cur->next;
4146 continue;
4147 }
4148
4149 if (p == NULL)
4150 ret->children = q;
4151 else
4152 p->next = q;
4153
4154 q->prev = p;
4155 q->parent = (xmlNodePtr) ret;
4156 q->next = NULL;
4157 ret->last = q;
4158 p = q;
4159 cur = cur->next;
4160 }
4161
Owen Taylor3473f882001-02-23 17:55:21 +00004162 return(ret);
4163}
Daniel Veillard2156d432004-03-04 15:59:36 +00004164#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004165
Daniel Veillard2156d432004-03-04 15:59:36 +00004166#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004167/**
4168 * xmlCopyDoc:
4169 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004170 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004171 *
4172 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004173 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004174 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004175 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004176 */
4177xmlDocPtr
4178xmlCopyDoc(xmlDocPtr doc, int recursive) {
4179 xmlDocPtr ret;
4180
4181 if (doc == NULL) return(NULL);
4182 ret = xmlNewDoc(doc->version);
4183 if (ret == NULL) return(NULL);
4184 if (doc->name != NULL)
4185 ret->name = xmlMemStrdup(doc->name);
4186 if (doc->encoding != NULL)
4187 ret->encoding = xmlStrdup(doc->encoding);
Daniel Veillardf59507d2005-01-27 17:26:49 +00004188 if (doc->URL != NULL)
4189 ret->URL = xmlStrdup(doc->URL);
Owen Taylor3473f882001-02-23 17:55:21 +00004190 ret->charset = doc->charset;
4191 ret->compression = doc->compression;
4192 ret->standalone = doc->standalone;
4193 if (!recursive) return(ret);
4194
Daniel Veillardb33c2012001-04-25 12:59:04 +00004195 ret->last = NULL;
4196 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004197#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004198 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004199 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004200 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004201 ret->intSubset->parent = ret;
4202 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004203#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004204 if (doc->oldNs != NULL)
4205 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4206 if (doc->children != NULL) {
4207 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004208
4209 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4210 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004211 ret->last = NULL;
4212 tmp = ret->children;
4213 while (tmp != NULL) {
4214 if (tmp->next == NULL)
4215 ret->last = tmp;
4216 tmp = tmp->next;
4217 }
4218 }
4219 return(ret);
4220}
Daniel Veillard652327a2003-09-29 18:02:38 +00004221#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004222
4223/************************************************************************
4224 * *
4225 * Content access functions *
4226 * *
4227 ************************************************************************/
4228
4229/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004230 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004231 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004232 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004233 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004234 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004235 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004236 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004237 */
4238long
4239xmlGetLineNo(xmlNodePtr node)
4240{
4241 long result = -1;
4242
4243 if (!node)
4244 return result;
Daniel Veillard73da77e2005-08-24 14:05:37 +00004245 if ((node->type == XML_ELEMENT_NODE) ||
4246 (node->type == XML_TEXT_NODE) ||
4247 (node->type == XML_COMMENT_NODE) ||
4248 (node->type == XML_PI_NODE))
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004249 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004250 else if ((node->prev != NULL) &&
4251 ((node->prev->type == XML_ELEMENT_NODE) ||
Daniel Veillard73da77e2005-08-24 14:05:37 +00004252 (node->prev->type == XML_TEXT_NODE) ||
4253 (node->prev->type == XML_COMMENT_NODE) ||
4254 (node->prev->type == XML_PI_NODE)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004255 result = xmlGetLineNo(node->prev);
4256 else if ((node->parent != NULL) &&
Daniel Veillard73da77e2005-08-24 14:05:37 +00004257 (node->parent->type == XML_ELEMENT_NODE))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004258 result = xmlGetLineNo(node->parent);
4259
4260 return result;
4261}
4262
Daniel Veillard2156d432004-03-04 15:59:36 +00004263#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004264/**
4265 * xmlGetNodePath:
4266 * @node: a node
4267 *
4268 * Build a structure based Path for the given node
4269 *
4270 * Returns the new path or NULL in case of error. The caller must free
4271 * the returned string
4272 */
4273xmlChar *
4274xmlGetNodePath(xmlNodePtr node)
4275{
4276 xmlNodePtr cur, tmp, next;
4277 xmlChar *buffer = NULL, *temp;
4278 size_t buf_len;
4279 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004280 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004281 const char *name;
4282 char nametemp[100];
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004283 int occur = 0, generic;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004284
4285 if (node == NULL)
4286 return (NULL);
4287
4288 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004289 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004290 if (buffer == NULL) {
4291 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004292 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004293 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004294 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004295 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004296 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004297 xmlFree(buffer);
4298 return (NULL);
4299 }
4300
4301 buffer[0] = 0;
4302 cur = node;
4303 do {
4304 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004305 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004306 occur = 0;
4307 if ((cur->type == XML_DOCUMENT_NODE) ||
4308 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4309 if (buffer[0] == '/')
4310 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004311 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004312 next = NULL;
4313 } else if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004314 generic = 0;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004315 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004316 name = (const char *) cur->name;
4317 if (cur->ns) {
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004318 if (cur->ns->prefix != NULL) {
William M. Brack13dfa872004-09-18 04:52:08 +00004319 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4320 (char *)cur->ns->prefix, (char *)cur->name);
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004321 nametemp[sizeof(nametemp) - 1] = 0;
4322 name = nametemp;
4323 } else {
4324 /*
4325 * We cannot express named elements in the default
4326 * namespace, so use "*".
4327 */
4328 generic = 1;
4329 name = "*";
4330 }
Daniel Veillard8faa7832001-11-26 15:58:08 +00004331 }
4332 next = cur->parent;
4333
4334 /*
4335 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004336 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004337 */
4338 tmp = cur->prev;
4339 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004340 if ((tmp->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004341 (generic ||
Kasimier T. Buchcik43ceb1e2006-06-12 11:08:18 +00004342 (xmlStrEqual(cur->name, tmp->name) &&
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004343 ((tmp->ns == cur->ns) ||
4344 ((tmp->ns != NULL) && (cur->ns != NULL) &&
Kasimier T. Buchcik43ceb1e2006-06-12 11:08:18 +00004345 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004346 occur++;
4347 tmp = tmp->prev;
4348 }
4349 if (occur == 0) {
4350 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004351 while (tmp != NULL && occur == 0) {
4352 if ((tmp->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004353 (generic ||
Kasimier T. Buchcik43ceb1e2006-06-12 11:08:18 +00004354 (xmlStrEqual(cur->name, tmp->name) &&
Kasimier T. Buchcikd38c63f2006-06-12 10:58:24 +00004355 ((tmp->ns == cur->ns) ||
4356 ((tmp->ns != NULL) && (cur->ns != NULL) &&
Kasimier T. Buchcik43ceb1e2006-06-12 11:08:18 +00004357 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004358 occur++;
4359 tmp = tmp->next;
4360 }
4361 if (occur != 0)
4362 occur = 1;
4363 } else
4364 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004365 } else if (cur->type == XML_COMMENT_NODE) {
4366 sep = "/";
4367 name = "comment()";
4368 next = cur->parent;
4369
4370 /*
4371 * Thumbler index computation
4372 */
4373 tmp = cur->prev;
4374 while (tmp != NULL) {
4375 if (tmp->type == XML_COMMENT_NODE)
4376 occur++;
4377 tmp = tmp->prev;
4378 }
4379 if (occur == 0) {
4380 tmp = cur->next;
4381 while (tmp != NULL && occur == 0) {
4382 if (tmp->type == XML_COMMENT_NODE)
4383 occur++;
4384 tmp = tmp->next;
4385 }
4386 if (occur != 0)
4387 occur = 1;
4388 } else
4389 occur++;
4390 } else if ((cur->type == XML_TEXT_NODE) ||
4391 (cur->type == XML_CDATA_SECTION_NODE)) {
4392 sep = "/";
4393 name = "text()";
4394 next = cur->parent;
4395
4396 /*
4397 * Thumbler index computation
4398 */
4399 tmp = cur->prev;
4400 while (tmp != NULL) {
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004401 if ((tmp->type == XML_TEXT_NODE) ||
4402 (tmp->type == XML_CDATA_SECTION_NODE))
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004403 occur++;
4404 tmp = tmp->prev;
4405 }
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004406 /*
4407 * Evaluate if this is the only text- or CDATA-section-node;
4408 * if yes, then we'll get "text()", otherwise "text()[1]".
4409 */
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004410 if (occur == 0) {
4411 tmp = cur->next;
Kasimier T. Buchcikeb468702006-02-15 10:57:50 +00004412 while (tmp != NULL) {
4413 if ((tmp->type == XML_TEXT_NODE) ||
4414 (tmp->type == XML_CDATA_SECTION_NODE))
4415 {
4416 occur = 1;
4417 break;
4418 }
4419 tmp = tmp->next;
4420 }
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004421 } else
4422 occur++;
4423 } else if (cur->type == XML_PI_NODE) {
4424 sep = "/";
4425 snprintf(nametemp, sizeof(nametemp) - 1,
William M. Brack13dfa872004-09-18 04:52:08 +00004426 "processing-instruction('%s')", (char *)cur->name);
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004427 nametemp[sizeof(nametemp) - 1] = 0;
4428 name = nametemp;
4429
4430 next = cur->parent;
4431
4432 /*
4433 * Thumbler index computation
4434 */
4435 tmp = cur->prev;
4436 while (tmp != NULL) {
4437 if ((tmp->type == XML_PI_NODE) &&
4438 (xmlStrEqual(cur->name, tmp->name)))
4439 occur++;
4440 tmp = tmp->prev;
4441 }
4442 if (occur == 0) {
4443 tmp = cur->next;
4444 while (tmp != NULL && occur == 0) {
4445 if ((tmp->type == XML_PI_NODE) &&
4446 (xmlStrEqual(cur->name, tmp->name)))
4447 occur++;
4448 tmp = tmp->next;
4449 }
4450 if (occur != 0)
4451 occur = 1;
4452 } else
4453 occur++;
4454
Daniel Veillard8faa7832001-11-26 15:58:08 +00004455 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004456 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004457 name = (const char *) (((xmlAttrPtr) cur)->name);
Daniel Veillard365c8062005-07-19 11:31:55 +00004458 if (cur->ns) {
4459 if (cur->ns->prefix != NULL)
4460 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4461 (char *)cur->ns->prefix, (char *)cur->name);
4462 else
4463 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4464 (char *)cur->name);
4465 nametemp[sizeof(nametemp) - 1] = 0;
4466 name = nametemp;
4467 }
Daniel Veillard8faa7832001-11-26 15:58:08 +00004468 next = ((xmlAttrPtr) cur)->parent;
4469 } else {
4470 next = cur->parent;
4471 }
4472
4473 /*
4474 * Make sure there is enough room
4475 */
4476 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4477 buf_len =
4478 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4479 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4480 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004481 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004482 xmlFree(buf);
4483 xmlFree(buffer);
4484 return (NULL);
4485 }
4486 buffer = temp;
4487 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4488 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004489 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004490 xmlFree(buf);
4491 xmlFree(buffer);
4492 return (NULL);
4493 }
4494 buf = temp;
4495 }
4496 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004497 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004498 sep, name, (char *) buffer);
4499 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004500 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004501 sep, name, occur, (char *) buffer);
William M. Brack13dfa872004-09-18 04:52:08 +00004502 snprintf((char *) buffer, buf_len, "%s", (char *)buf);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004503 cur = next;
4504 } while (cur != NULL);
4505 xmlFree(buf);
4506 return (buffer);
4507}
Daniel Veillard652327a2003-09-29 18:02:38 +00004508#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004509
4510/**
Owen Taylor3473f882001-02-23 17:55:21 +00004511 * xmlDocGetRootElement:
4512 * @doc: the document
4513 *
4514 * Get the root element of the document (doc->children is a list
4515 * containing possibly comments, PIs, etc ...).
4516 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004517 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004518 */
4519xmlNodePtr
4520xmlDocGetRootElement(xmlDocPtr doc) {
4521 xmlNodePtr ret;
4522
4523 if (doc == NULL) return(NULL);
4524 ret = doc->children;
4525 while (ret != NULL) {
4526 if (ret->type == XML_ELEMENT_NODE)
4527 return(ret);
4528 ret = ret->next;
4529 }
4530 return(ret);
4531}
4532
Daniel Veillard2156d432004-03-04 15:59:36 +00004533#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004534/**
4535 * xmlDocSetRootElement:
4536 * @doc: the document
4537 * @root: the new document root element
4538 *
4539 * Set the root element of the document (doc->children is a list
4540 * containing possibly comments, PIs, etc ...).
4541 *
4542 * Returns the old root element if any was found
4543 */
4544xmlNodePtr
4545xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4546 xmlNodePtr old = NULL;
4547
4548 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004549 if (root == NULL)
4550 return(NULL);
4551 xmlUnlinkNode(root);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00004552 xmlSetTreeDoc(root, doc);
Daniel Veillardc575b992002-02-08 13:28:40 +00004553 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004554 old = doc->children;
4555 while (old != NULL) {
4556 if (old->type == XML_ELEMENT_NODE)
4557 break;
4558 old = old->next;
4559 }
4560 if (old == NULL) {
4561 if (doc->children == NULL) {
4562 doc->children = root;
4563 doc->last = root;
4564 } else {
4565 xmlAddSibling(doc->children, root);
4566 }
4567 } else {
4568 xmlReplaceNode(old, root);
4569 }
4570 return(old);
4571}
Daniel Veillard2156d432004-03-04 15:59:36 +00004572#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004573
Daniel Veillard2156d432004-03-04 15:59:36 +00004574#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004575/**
4576 * xmlNodeSetLang:
4577 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004578 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004579 *
4580 * Set the language of a node, i.e. the values of the xml:lang
4581 * attribute.
4582 */
4583void
4584xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004585 xmlNsPtr ns;
4586
Owen Taylor3473f882001-02-23 17:55:21 +00004587 if (cur == NULL) return;
4588 switch(cur->type) {
4589 case XML_TEXT_NODE:
4590 case XML_CDATA_SECTION_NODE:
4591 case XML_COMMENT_NODE:
4592 case XML_DOCUMENT_NODE:
4593 case XML_DOCUMENT_TYPE_NODE:
4594 case XML_DOCUMENT_FRAG_NODE:
4595 case XML_NOTATION_NODE:
4596 case XML_HTML_DOCUMENT_NODE:
4597 case XML_DTD_NODE:
4598 case XML_ELEMENT_DECL:
4599 case XML_ATTRIBUTE_DECL:
4600 case XML_ENTITY_DECL:
4601 case XML_PI_NODE:
4602 case XML_ENTITY_REF_NODE:
4603 case XML_ENTITY_NODE:
4604 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004605#ifdef LIBXML_DOCB_ENABLED
4606 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004607#endif
4608 case XML_XINCLUDE_START:
4609 case XML_XINCLUDE_END:
4610 return;
4611 case XML_ELEMENT_NODE:
4612 case XML_ATTRIBUTE_NODE:
4613 break;
4614 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004615 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4616 if (ns == NULL)
4617 return;
4618 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004619}
Daniel Veillard652327a2003-09-29 18:02:38 +00004620#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004621
4622/**
4623 * xmlNodeGetLang:
4624 * @cur: the node being checked
4625 *
4626 * Searches the language of a node, i.e. the values of the xml:lang
4627 * attribute or the one carried by the nearest ancestor.
4628 *
4629 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004630 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004631 */
4632xmlChar *
4633xmlNodeGetLang(xmlNodePtr cur) {
4634 xmlChar *lang;
4635
4636 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004637 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004638 if (lang != NULL)
4639 return(lang);
4640 cur = cur->parent;
4641 }
4642 return(NULL);
4643}
4644
4645
Daniel Veillard652327a2003-09-29 18:02:38 +00004646#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004647/**
4648 * xmlNodeSetSpacePreserve:
4649 * @cur: the node being changed
4650 * @val: the xml:space value ("0": default, 1: "preserve")
4651 *
4652 * Set (or reset) the space preserving behaviour of a node, i.e. the
4653 * value of the xml:space attribute.
4654 */
4655void
4656xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004657 xmlNsPtr ns;
4658
Owen Taylor3473f882001-02-23 17:55:21 +00004659 if (cur == NULL) return;
4660 switch(cur->type) {
4661 case XML_TEXT_NODE:
4662 case XML_CDATA_SECTION_NODE:
4663 case XML_COMMENT_NODE:
4664 case XML_DOCUMENT_NODE:
4665 case XML_DOCUMENT_TYPE_NODE:
4666 case XML_DOCUMENT_FRAG_NODE:
4667 case XML_NOTATION_NODE:
4668 case XML_HTML_DOCUMENT_NODE:
4669 case XML_DTD_NODE:
4670 case XML_ELEMENT_DECL:
4671 case XML_ATTRIBUTE_DECL:
4672 case XML_ENTITY_DECL:
4673 case XML_PI_NODE:
4674 case XML_ENTITY_REF_NODE:
4675 case XML_ENTITY_NODE:
4676 case XML_NAMESPACE_DECL:
4677 case XML_XINCLUDE_START:
4678 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004679#ifdef LIBXML_DOCB_ENABLED
4680 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004681#endif
4682 return;
4683 case XML_ELEMENT_NODE:
4684 case XML_ATTRIBUTE_NODE:
4685 break;
4686 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004687 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4688 if (ns == NULL)
4689 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004690 switch (val) {
4691 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004692 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004693 break;
4694 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004695 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004696 break;
4697 }
4698}
Daniel Veillard652327a2003-09-29 18:02:38 +00004699#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004700
4701/**
4702 * xmlNodeGetSpacePreserve:
4703 * @cur: the node being checked
4704 *
4705 * Searches the space preserving behaviour of a node, i.e. the values
4706 * of the xml:space attribute or the one carried by the nearest
4707 * ancestor.
4708 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004709 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004710 */
4711int
4712xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4713 xmlChar *space;
4714
4715 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004716 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004717 if (space != NULL) {
4718 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4719 xmlFree(space);
4720 return(1);
4721 }
4722 if (xmlStrEqual(space, BAD_CAST "default")) {
4723 xmlFree(space);
4724 return(0);
4725 }
4726 xmlFree(space);
4727 }
4728 cur = cur->parent;
4729 }
4730 return(-1);
4731}
4732
Daniel Veillard652327a2003-09-29 18:02:38 +00004733#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004734/**
4735 * xmlNodeSetName:
4736 * @cur: the node being changed
4737 * @name: the new tag name
4738 *
4739 * Set (or reset) the name of a node.
4740 */
4741void
4742xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00004743 xmlDocPtr doc;
4744 xmlDictPtr dict;
4745
Owen Taylor3473f882001-02-23 17:55:21 +00004746 if (cur == NULL) return;
4747 if (name == NULL) return;
4748 switch(cur->type) {
4749 case XML_TEXT_NODE:
4750 case XML_CDATA_SECTION_NODE:
4751 case XML_COMMENT_NODE:
4752 case XML_DOCUMENT_TYPE_NODE:
4753 case XML_DOCUMENT_FRAG_NODE:
4754 case XML_NOTATION_NODE:
4755 case XML_HTML_DOCUMENT_NODE:
4756 case XML_NAMESPACE_DECL:
4757 case XML_XINCLUDE_START:
4758 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004759#ifdef LIBXML_DOCB_ENABLED
4760 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004761#endif
4762 return;
4763 case XML_ELEMENT_NODE:
4764 case XML_ATTRIBUTE_NODE:
4765 case XML_PI_NODE:
4766 case XML_ENTITY_REF_NODE:
4767 case XML_ENTITY_NODE:
4768 case XML_DTD_NODE:
4769 case XML_DOCUMENT_NODE:
4770 case XML_ELEMENT_DECL:
4771 case XML_ATTRIBUTE_DECL:
4772 case XML_ENTITY_DECL:
4773 break;
4774 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00004775 doc = cur->doc;
4776 if (doc != NULL)
4777 dict = doc->dict;
4778 else
4779 dict = NULL;
4780 if (dict != NULL) {
4781 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
4782 xmlFree((xmlChar *) cur->name);
4783 cur->name = xmlDictLookup(dict, name, -1);
4784 } else {
4785 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4786 cur->name = xmlStrdup(name);
4787 }
Owen Taylor3473f882001-02-23 17:55:21 +00004788}
Daniel Veillard2156d432004-03-04 15:59:36 +00004789#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004790
Daniel Veillard2156d432004-03-04 15:59:36 +00004791#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004792/**
4793 * xmlNodeSetBase:
4794 * @cur: the node being changed
4795 * @uri: the new base URI
4796 *
4797 * Set (or reset) the base URI of a node, i.e. the value of the
4798 * xml:base attribute.
4799 */
4800void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004801xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004802 xmlNsPtr ns;
Daniel Veillardb8efdda2006-10-10 12:37:14 +00004803 const xmlChar* fixed;
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004804
Owen Taylor3473f882001-02-23 17:55:21 +00004805 if (cur == NULL) return;
4806 switch(cur->type) {
4807 case XML_TEXT_NODE:
4808 case XML_CDATA_SECTION_NODE:
4809 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004810 case XML_DOCUMENT_TYPE_NODE:
4811 case XML_DOCUMENT_FRAG_NODE:
4812 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004813 case XML_DTD_NODE:
4814 case XML_ELEMENT_DECL:
4815 case XML_ATTRIBUTE_DECL:
4816 case XML_ENTITY_DECL:
4817 case XML_PI_NODE:
4818 case XML_ENTITY_REF_NODE:
4819 case XML_ENTITY_NODE:
4820 case XML_NAMESPACE_DECL:
4821 case XML_XINCLUDE_START:
4822 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004823 return;
4824 case XML_ELEMENT_NODE:
4825 case XML_ATTRIBUTE_NODE:
4826 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004827 case XML_DOCUMENT_NODE:
4828#ifdef LIBXML_DOCB_ENABLED
4829 case XML_DOCB_DOCUMENT_NODE:
4830#endif
4831 case XML_HTML_DOCUMENT_NODE: {
4832 xmlDocPtr doc = (xmlDocPtr) cur;
4833
4834 if (doc->URL != NULL)
4835 xmlFree((xmlChar *) doc->URL);
4836 if (uri == NULL)
4837 doc->URL = NULL;
4838 else
Daniel Veillardb8efdda2006-10-10 12:37:14 +00004839 doc->URL = xmlPathToURI(uri);
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004840 return;
4841 }
Owen Taylor3473f882001-02-23 17:55:21 +00004842 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004843
4844 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4845 if (ns == NULL)
4846 return;
Daniel Veillardb8efdda2006-10-10 12:37:14 +00004847 fixed = xmlPathToURI(uri);
4848 if (fixed != NULL) {
4849 xmlSetNsProp(cur, ns, BAD_CAST "base", fixed);
4850 xmlFree(fixed);
4851 } else {
4852 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
4853 }
Owen Taylor3473f882001-02-23 17:55:21 +00004854}
Daniel Veillard652327a2003-09-29 18:02:38 +00004855#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004856
4857/**
Owen Taylor3473f882001-02-23 17:55:21 +00004858 * xmlNodeGetBase:
4859 * @doc: the document the node pertains to
4860 * @cur: the node being checked
4861 *
4862 * Searches for the BASE URL. The code should work on both XML
4863 * and HTML document even if base mechanisms are completely different.
4864 * It returns the base as defined in RFC 2396 sections
4865 * 5.1.1. Base URI within Document Content
4866 * and
4867 * 5.1.2. Base URI from the Encapsulating Entity
4868 * However it does not return the document base (5.1.3), use
4869 * xmlDocumentGetBase() for this
4870 *
4871 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004872 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004873 */
4874xmlChar *
4875xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004876 xmlChar *oldbase = NULL;
4877 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004878
4879 if ((cur == NULL) && (doc == NULL))
4880 return(NULL);
4881 if (doc == NULL) doc = cur->doc;
4882 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4883 cur = doc->children;
4884 while ((cur != NULL) && (cur->name != NULL)) {
4885 if (cur->type != XML_ELEMENT_NODE) {
4886 cur = cur->next;
4887 continue;
4888 }
4889 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4890 cur = cur->children;
4891 continue;
4892 }
4893 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4894 cur = cur->children;
4895 continue;
4896 }
4897 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4898 return(xmlGetProp(cur, BAD_CAST "href"));
4899 }
4900 cur = cur->next;
4901 }
4902 return(NULL);
4903 }
4904 while (cur != NULL) {
4905 if (cur->type == XML_ENTITY_DECL) {
4906 xmlEntityPtr ent = (xmlEntityPtr) cur;
4907 return(xmlStrdup(ent->URI));
4908 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004909 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004910 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004911 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004912 if (oldbase != NULL) {
4913 newbase = xmlBuildURI(oldbase, base);
4914 if (newbase != NULL) {
4915 xmlFree(oldbase);
4916 xmlFree(base);
4917 oldbase = newbase;
4918 } else {
4919 xmlFree(oldbase);
4920 xmlFree(base);
4921 return(NULL);
4922 }
4923 } else {
4924 oldbase = base;
4925 }
4926 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4927 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4928 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4929 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004930 }
4931 }
Owen Taylor3473f882001-02-23 17:55:21 +00004932 cur = cur->parent;
4933 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004934 if ((doc != NULL) && (doc->URL != NULL)) {
4935 if (oldbase == NULL)
4936 return(xmlStrdup(doc->URL));
4937 newbase = xmlBuildURI(oldbase, doc->URL);
4938 xmlFree(oldbase);
4939 return(newbase);
4940 }
4941 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004942}
4943
4944/**
Daniel Veillard78697292003-10-19 20:44:43 +00004945 * xmlNodeBufGetContent:
4946 * @buffer: a buffer
4947 * @cur: the node being read
4948 *
4949 * Read the value of a node @cur, this can be either the text carried
4950 * directly by this node if it's a TEXT node or the aggregate string
4951 * of the values carried by this node child's (TEXT and ENTITY_REF).
4952 * Entity references are substituted.
4953 * Fills up the buffer @buffer with this value
4954 *
4955 * Returns 0 in case of success and -1 in case of error.
4956 */
4957int
4958xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4959{
4960 if ((cur == NULL) || (buffer == NULL)) return(-1);
4961 switch (cur->type) {
4962 case XML_CDATA_SECTION_NODE:
4963 case XML_TEXT_NODE:
4964 xmlBufferCat(buffer, cur->content);
4965 break;
4966 case XML_DOCUMENT_FRAG_NODE:
4967 case XML_ELEMENT_NODE:{
4968 xmlNodePtr tmp = cur;
4969
4970 while (tmp != NULL) {
4971 switch (tmp->type) {
4972 case XML_CDATA_SECTION_NODE:
4973 case XML_TEXT_NODE:
4974 if (tmp->content != NULL)
4975 xmlBufferCat(buffer, tmp->content);
4976 break;
4977 case XML_ENTITY_REF_NODE:
Rob Richards77b92ff2005-12-20 15:55:14 +00004978 xmlNodeBufGetContent(buffer, tmp);
4979 break;
Daniel Veillard78697292003-10-19 20:44:43 +00004980 default:
4981 break;
4982 }
4983 /*
4984 * Skip to next node
4985 */
4986 if (tmp->children != NULL) {
4987 if (tmp->children->type != XML_ENTITY_DECL) {
4988 tmp = tmp->children;
4989 continue;
4990 }
4991 }
4992 if (tmp == cur)
4993 break;
4994
4995 if (tmp->next != NULL) {
4996 tmp = tmp->next;
4997 continue;
4998 }
4999
5000 do {
5001 tmp = tmp->parent;
5002 if (tmp == NULL)
5003 break;
5004 if (tmp == cur) {
5005 tmp = NULL;
5006 break;
5007 }
5008 if (tmp->next != NULL) {
5009 tmp = tmp->next;
5010 break;
5011 }
5012 } while (tmp != NULL);
5013 }
5014 break;
5015 }
5016 case XML_ATTRIBUTE_NODE:{
5017 xmlAttrPtr attr = (xmlAttrPtr) cur;
5018 xmlNodePtr tmp = attr->children;
5019
5020 while (tmp != NULL) {
5021 if (tmp->type == XML_TEXT_NODE)
5022 xmlBufferCat(buffer, tmp->content);
5023 else
5024 xmlNodeBufGetContent(buffer, tmp);
5025 tmp = tmp->next;
5026 }
5027 break;
5028 }
5029 case XML_COMMENT_NODE:
5030 case XML_PI_NODE:
5031 xmlBufferCat(buffer, cur->content);
5032 break;
5033 case XML_ENTITY_REF_NODE:{
5034 xmlEntityPtr ent;
5035 xmlNodePtr tmp;
5036
5037 /* lookup entity declaration */
5038 ent = xmlGetDocEntity(cur->doc, cur->name);
5039 if (ent == NULL)
5040 return(-1);
5041
5042 /* an entity content can be any "well balanced chunk",
5043 * i.e. the result of the content [43] production:
5044 * http://www.w3.org/TR/REC-xml#NT-content
5045 * -> we iterate through child nodes and recursive call
5046 * xmlNodeGetContent() which handles all possible node types */
5047 tmp = ent->children;
5048 while (tmp) {
5049 xmlNodeBufGetContent(buffer, tmp);
5050 tmp = tmp->next;
5051 }
5052 break;
5053 }
5054 case XML_ENTITY_NODE:
5055 case XML_DOCUMENT_TYPE_NODE:
5056 case XML_NOTATION_NODE:
5057 case XML_DTD_NODE:
5058 case XML_XINCLUDE_START:
5059 case XML_XINCLUDE_END:
5060 break;
5061 case XML_DOCUMENT_NODE:
5062#ifdef LIBXML_DOCB_ENABLED
5063 case XML_DOCB_DOCUMENT_NODE:
5064#endif
5065 case XML_HTML_DOCUMENT_NODE:
5066 cur = cur->children;
5067 while (cur!= NULL) {
5068 if ((cur->type == XML_ELEMENT_NODE) ||
5069 (cur->type == XML_TEXT_NODE) ||
5070 (cur->type == XML_CDATA_SECTION_NODE)) {
5071 xmlNodeBufGetContent(buffer, cur);
5072 }
5073 cur = cur->next;
5074 }
5075 break;
5076 case XML_NAMESPACE_DECL:
5077 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
5078 break;
5079 case XML_ELEMENT_DECL:
5080 case XML_ATTRIBUTE_DECL:
5081 case XML_ENTITY_DECL:
5082 break;
5083 }
5084 return(0);
5085}
5086/**
Owen Taylor3473f882001-02-23 17:55:21 +00005087 * xmlNodeGetContent:
5088 * @cur: the node being read
5089 *
5090 * Read the value of a node, this can be either the text carried
5091 * directly by this node if it's a TEXT node or the aggregate string
5092 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00005093 * Entity references are substituted.
5094 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005095 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005096 */
5097xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00005098xmlNodeGetContent(xmlNodePtr cur)
5099{
5100 if (cur == NULL)
5101 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005102 switch (cur->type) {
5103 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005104 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00005105 xmlBufferPtr buffer;
5106 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00005107
Daniel Veillard814a76d2003-01-23 18:24:20 +00005108 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00005109 if (buffer == NULL)
5110 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00005111 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005112 ret = buffer->content;
5113 buffer->content = NULL;
5114 xmlBufferFree(buffer);
5115 return (ret);
5116 }
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00005117 case XML_ATTRIBUTE_NODE:
5118 return(xmlGetPropNodeValueInternal((xmlAttrPtr) cur));
Owen Taylor3473f882001-02-23 17:55:21 +00005119 case XML_COMMENT_NODE:
5120 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005121 if (cur->content != NULL)
5122 return (xmlStrdup(cur->content));
5123 return (NULL);
5124 case XML_ENTITY_REF_NODE:{
5125 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00005126 xmlBufferPtr buffer;
5127 xmlChar *ret;
5128
5129 /* lookup entity declaration */
5130 ent = xmlGetDocEntity(cur->doc, cur->name);
5131 if (ent == NULL)
5132 return (NULL);
5133
5134 buffer = xmlBufferCreate();
5135 if (buffer == NULL)
5136 return (NULL);
5137
Daniel Veillardc4696922003-10-19 21:47:14 +00005138 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005139
5140 ret = buffer->content;
5141 buffer->content = NULL;
5142 xmlBufferFree(buffer);
5143 return (ret);
5144 }
Owen Taylor3473f882001-02-23 17:55:21 +00005145 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005146 case XML_DOCUMENT_TYPE_NODE:
5147 case XML_NOTATION_NODE:
5148 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005149 case XML_XINCLUDE_START:
5150 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00005151 return (NULL);
5152 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005153#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005154 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005155#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005156 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00005157 xmlBufferPtr buffer;
5158 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005159
Daniel Veillardc4696922003-10-19 21:47:14 +00005160 buffer = xmlBufferCreate();
5161 if (buffer == NULL)
5162 return (NULL);
5163
5164 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5165
5166 ret = buffer->content;
5167 buffer->content = NULL;
5168 xmlBufferFree(buffer);
5169 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005170 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005171 case XML_NAMESPACE_DECL: {
5172 xmlChar *tmp;
5173
5174 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5175 return (tmp);
5176 }
Owen Taylor3473f882001-02-23 17:55:21 +00005177 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005178 /* TODO !!! */
5179 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005180 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005181 /* TODO !!! */
5182 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005183 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005184 /* TODO !!! */
5185 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005186 case XML_CDATA_SECTION_NODE:
5187 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005188 if (cur->content != NULL)
5189 return (xmlStrdup(cur->content));
5190 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005191 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005192 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005193}
Daniel Veillard652327a2003-09-29 18:02:38 +00005194
Owen Taylor3473f882001-02-23 17:55:21 +00005195/**
5196 * xmlNodeSetContent:
5197 * @cur: the node being modified
5198 * @content: the new value of the content
5199 *
5200 * Replace the content of a node.
5201 */
5202void
5203xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5204 if (cur == NULL) {
5205#ifdef DEBUG_TREE
5206 xmlGenericError(xmlGenericErrorContext,
5207 "xmlNodeSetContent : node == NULL\n");
5208#endif
5209 return;
5210 }
5211 switch (cur->type) {
5212 case XML_DOCUMENT_FRAG_NODE:
5213 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005214 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005215 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5216 cur->children = xmlStringGetNodeList(cur->doc, content);
5217 UPDATE_LAST_CHILD_AND_PARENT(cur)
5218 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005219 case XML_TEXT_NODE:
5220 case XML_CDATA_SECTION_NODE:
5221 case XML_ENTITY_REF_NODE:
5222 case XML_ENTITY_NODE:
5223 case XML_PI_NODE:
5224 case XML_COMMENT_NODE:
Daniel Veillard8874b942005-08-25 13:19:21 +00005225 if ((cur->content != NULL) &&
5226 (cur->content != (xmlChar *) &(cur->properties))) {
William M. Brack7762bb12004-01-04 14:49:01 +00005227 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
Daniel Veillardc587bce2005-05-10 15:28:08 +00005228 (xmlDictOwns(cur->doc->dict, cur->content))))
William M. Brack7762bb12004-01-04 14:49:01 +00005229 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005230 }
5231 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5232 cur->last = cur->children = NULL;
5233 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005234 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005235 } else
5236 cur->content = NULL;
Daniel Veillard8874b942005-08-25 13:19:21 +00005237 cur->properties = NULL;
5238 cur->nsDef = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00005239 break;
5240 case XML_DOCUMENT_NODE:
5241 case XML_HTML_DOCUMENT_NODE:
5242 case XML_DOCUMENT_TYPE_NODE:
5243 case XML_XINCLUDE_START:
5244 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005245#ifdef LIBXML_DOCB_ENABLED
5246 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005247#endif
5248 break;
5249 case XML_NOTATION_NODE:
5250 break;
5251 case XML_DTD_NODE:
5252 break;
5253 case XML_NAMESPACE_DECL:
5254 break;
5255 case XML_ELEMENT_DECL:
5256 /* TODO !!! */
5257 break;
5258 case XML_ATTRIBUTE_DECL:
5259 /* TODO !!! */
5260 break;
5261 case XML_ENTITY_DECL:
5262 /* TODO !!! */
5263 break;
5264 }
5265}
5266
Daniel Veillard652327a2003-09-29 18:02:38 +00005267#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005268/**
5269 * xmlNodeSetContentLen:
5270 * @cur: the node being modified
5271 * @content: the new value of the content
5272 * @len: the size of @content
5273 *
5274 * Replace the content of a node.
5275 */
5276void
5277xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5278 if (cur == NULL) {
5279#ifdef DEBUG_TREE
5280 xmlGenericError(xmlGenericErrorContext,
5281 "xmlNodeSetContentLen : node == NULL\n");
5282#endif
5283 return;
5284 }
5285 switch (cur->type) {
5286 case XML_DOCUMENT_FRAG_NODE:
5287 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005288 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005289 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5290 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5291 UPDATE_LAST_CHILD_AND_PARENT(cur)
5292 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005293 case XML_TEXT_NODE:
5294 case XML_CDATA_SECTION_NODE:
5295 case XML_ENTITY_REF_NODE:
5296 case XML_ENTITY_NODE:
5297 case XML_PI_NODE:
5298 case XML_COMMENT_NODE:
5299 case XML_NOTATION_NODE:
Daniel Veillard8874b942005-08-25 13:19:21 +00005300 if ((cur->content != NULL) &&
5301 (cur->content != (xmlChar *) &(cur->properties))) {
5302 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5303 (xmlDictOwns(cur->doc->dict, cur->content))))
5304 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005305 }
5306 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5307 cur->children = cur->last = NULL;
5308 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005309 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005310 } else
5311 cur->content = NULL;
Daniel Veillard8874b942005-08-25 13:19:21 +00005312 cur->properties = NULL;
5313 cur->nsDef = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00005314 break;
5315 case XML_DOCUMENT_NODE:
5316 case XML_DTD_NODE:
5317 case XML_HTML_DOCUMENT_NODE:
5318 case XML_DOCUMENT_TYPE_NODE:
5319 case XML_NAMESPACE_DECL:
5320 case XML_XINCLUDE_START:
5321 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005322#ifdef LIBXML_DOCB_ENABLED
5323 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005324#endif
5325 break;
5326 case XML_ELEMENT_DECL:
5327 /* TODO !!! */
5328 break;
5329 case XML_ATTRIBUTE_DECL:
5330 /* TODO !!! */
5331 break;
5332 case XML_ENTITY_DECL:
5333 /* TODO !!! */
5334 break;
5335 }
5336}
Daniel Veillard652327a2003-09-29 18:02:38 +00005337#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005338
5339/**
5340 * xmlNodeAddContentLen:
5341 * @cur: the node being modified
5342 * @content: extra content
5343 * @len: the size of @content
5344 *
5345 * Append the extra substring to the node content.
5346 */
5347void
5348xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5349 if (cur == NULL) {
5350#ifdef DEBUG_TREE
5351 xmlGenericError(xmlGenericErrorContext,
5352 "xmlNodeAddContentLen : node == NULL\n");
5353#endif
5354 return;
5355 }
5356 if (len <= 0) return;
5357 switch (cur->type) {
5358 case XML_DOCUMENT_FRAG_NODE:
5359 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005360 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005361
Daniel Veillard7db37732001-07-12 01:20:08 +00005362 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005363 newNode = xmlNewTextLen(content, len);
5364 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005365 tmp = xmlAddChild(cur, newNode);
5366 if (tmp != newNode)
5367 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005368 if ((last != NULL) && (last->next == newNode)) {
5369 xmlTextMerge(last, newNode);
5370 }
5371 }
5372 break;
5373 }
5374 case XML_ATTRIBUTE_NODE:
5375 break;
5376 case XML_TEXT_NODE:
5377 case XML_CDATA_SECTION_NODE:
5378 case XML_ENTITY_REF_NODE:
5379 case XML_ENTITY_NODE:
5380 case XML_PI_NODE:
5381 case XML_COMMENT_NODE:
5382 case XML_NOTATION_NODE:
5383 if (content != NULL) {
Daniel Veillard8874b942005-08-25 13:19:21 +00005384 if ((cur->content == (xmlChar *) &(cur->properties)) ||
5385 ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5386 xmlDictOwns(cur->doc->dict, cur->content))) {
5387 cur->content = xmlStrncatNew(cur->content, content, len);
5388 cur->properties = NULL;
5389 cur->nsDef = NULL;
William M. Brack7762bb12004-01-04 14:49:01 +00005390 break;
5391 }
Owen Taylor3473f882001-02-23 17:55:21 +00005392 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005393 }
5394 case XML_DOCUMENT_NODE:
5395 case XML_DTD_NODE:
5396 case XML_HTML_DOCUMENT_NODE:
5397 case XML_DOCUMENT_TYPE_NODE:
5398 case XML_NAMESPACE_DECL:
5399 case XML_XINCLUDE_START:
5400 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005401#ifdef LIBXML_DOCB_ENABLED
5402 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005403#endif
5404 break;
5405 case XML_ELEMENT_DECL:
5406 case XML_ATTRIBUTE_DECL:
5407 case XML_ENTITY_DECL:
5408 break;
5409 }
5410}
5411
5412/**
5413 * xmlNodeAddContent:
5414 * @cur: the node being modified
5415 * @content: extra content
5416 *
5417 * Append the extra substring to the node content.
5418 */
5419void
5420xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5421 int len;
5422
5423 if (cur == NULL) {
5424#ifdef DEBUG_TREE
5425 xmlGenericError(xmlGenericErrorContext,
5426 "xmlNodeAddContent : node == NULL\n");
5427#endif
5428 return;
5429 }
5430 if (content == NULL) return;
5431 len = xmlStrlen(content);
5432 xmlNodeAddContentLen(cur, content, len);
5433}
5434
5435/**
5436 * xmlTextMerge:
5437 * @first: the first text node
5438 * @second: the second text node being merged
5439 *
5440 * Merge two text nodes into one
5441 * Returns the first text node augmented
5442 */
5443xmlNodePtr
5444xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5445 if (first == NULL) return(second);
5446 if (second == NULL) return(first);
5447 if (first->type != XML_TEXT_NODE) return(first);
5448 if (second->type != XML_TEXT_NODE) return(first);
5449 if (second->name != first->name)
5450 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005451 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005452 xmlUnlinkNode(second);
5453 xmlFreeNode(second);
5454 return(first);
5455}
5456
Daniel Veillardf1a27c62006-10-13 22:33:03 +00005457#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005458/**
5459 * xmlGetNsList:
5460 * @doc: the document
5461 * @node: the current node
5462 *
5463 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005464 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005465 * that need to be freed by the caller or NULL if no
5466 * namespace if defined
5467 */
5468xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005469xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5470{
Owen Taylor3473f882001-02-23 17:55:21 +00005471 xmlNsPtr cur;
5472 xmlNsPtr *ret = NULL;
5473 int nbns = 0;
5474 int maxns = 10;
5475 int i;
5476
5477 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005478 if (node->type == XML_ELEMENT_NODE) {
5479 cur = node->nsDef;
5480 while (cur != NULL) {
5481 if (ret == NULL) {
5482 ret =
5483 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5484 sizeof(xmlNsPtr));
5485 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005486 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005487 return (NULL);
5488 }
5489 ret[nbns] = NULL;
5490 }
5491 for (i = 0; i < nbns; i++) {
5492 if ((cur->prefix == ret[i]->prefix) ||
5493 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5494 break;
5495 }
5496 if (i >= nbns) {
5497 if (nbns >= maxns) {
5498 maxns *= 2;
5499 ret = (xmlNsPtr *) xmlRealloc(ret,
5500 (maxns +
5501 1) *
5502 sizeof(xmlNsPtr));
5503 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005504 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005505 return (NULL);
5506 }
5507 }
5508 ret[nbns++] = cur;
5509 ret[nbns] = NULL;
5510 }
Owen Taylor3473f882001-02-23 17:55:21 +00005511
Daniel Veillard77044732001-06-29 21:31:07 +00005512 cur = cur->next;
5513 }
5514 }
5515 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005516 }
Daniel Veillard77044732001-06-29 21:31:07 +00005517 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005518}
Daniel Veillard652327a2003-09-29 18:02:38 +00005519#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005520
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00005521/*
5522* xmlTreeEnsureXMLDecl:
5523* @doc: the doc
5524*
5525* Ensures that there is an XML namespace declaration on the doc.
5526*
5527* Returns the XML ns-struct or NULL on API and internal errors.
5528*/
5529static xmlNsPtr
5530xmlTreeEnsureXMLDecl(xmlDocPtr doc)
5531{
5532 if (doc == NULL)
5533 return (NULL);
5534 if (doc->oldNs != NULL)
5535 return (doc->oldNs);
5536 {
5537 xmlNsPtr ns;
5538 ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5539 if (ns == NULL) {
5540 xmlTreeErrMemory(
5541 "allocating the XML namespace");
5542 return (NULL);
5543 }
5544 memset(ns, 0, sizeof(xmlNs));
5545 ns->type = XML_LOCAL_NAMESPACE;
5546 ns->href = xmlStrdup(XML_XML_NAMESPACE);
5547 ns->prefix = xmlStrdup((const xmlChar *)"xml");
5548 doc->oldNs = ns;
5549 return (ns);
5550 }
5551}
5552
Owen Taylor3473f882001-02-23 17:55:21 +00005553/**
5554 * xmlSearchNs:
5555 * @doc: the document
5556 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005557 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005558 *
5559 * Search a Ns registered under a given name space for a document.
5560 * recurse on the parents until it finds the defined namespace
5561 * or return NULL otherwise.
5562 * @nameSpace can be NULL, this is a search for the default namespace.
5563 * We don't allow to cross entities boundaries. If you don't declare
5564 * the namespace within those you will be in troubles !!! A warning
5565 * is generated to cover this case.
5566 *
5567 * Returns the namespace pointer or NULL.
5568 */
5569xmlNsPtr
5570xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005571
Owen Taylor3473f882001-02-23 17:55:21 +00005572 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005573 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005574
5575 if (node == NULL) return(NULL);
5576 if ((nameSpace != NULL) &&
5577 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005578 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5579 /*
5580 * The XML-1.0 namespace is normally held on the root
5581 * element. In this case exceptionally create it on the
5582 * node element.
5583 */
5584 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5585 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005586 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005587 return(NULL);
5588 }
5589 memset(cur, 0, sizeof(xmlNs));
5590 cur->type = XML_LOCAL_NAMESPACE;
5591 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5592 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5593 cur->next = node->nsDef;
5594 node->nsDef = cur;
5595 return(cur);
5596 }
Daniel Veillard11ce4002006-03-10 00:36:23 +00005597 if (doc == NULL) {
5598 doc = node->doc;
5599 if (doc == NULL)
5600 return(NULL);
5601 }
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00005602 /*
5603 * Return the XML namespace declaration held by the doc.
5604 */
5605 if (doc->oldNs == NULL)
5606 return(xmlTreeEnsureXMLDecl(doc));
5607 else
5608 return(doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005609 }
5610 while (node != NULL) {
5611 if ((node->type == XML_ENTITY_REF_NODE) ||
5612 (node->type == XML_ENTITY_NODE) ||
5613 (node->type == XML_ENTITY_DECL))
5614 return(NULL);
5615 if (node->type == XML_ELEMENT_NODE) {
5616 cur = node->nsDef;
5617 while (cur != NULL) {
5618 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5619 (cur->href != NULL))
5620 return(cur);
5621 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5622 (cur->href != NULL) &&
5623 (xmlStrEqual(cur->prefix, nameSpace)))
5624 return(cur);
5625 cur = cur->next;
5626 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005627 if (orig != node) {
5628 cur = node->ns;
5629 if (cur != NULL) {
5630 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5631 (cur->href != NULL))
5632 return(cur);
5633 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5634 (cur->href != NULL) &&
5635 (xmlStrEqual(cur->prefix, nameSpace)))
5636 return(cur);
5637 }
5638 }
Owen Taylor3473f882001-02-23 17:55:21 +00005639 }
5640 node = node->parent;
5641 }
5642 return(NULL);
5643}
5644
5645/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005646 * xmlNsInScope:
5647 * @doc: the document
5648 * @node: the current node
5649 * @ancestor: the ancestor carrying the namespace
5650 * @prefix: the namespace prefix
5651 *
5652 * Verify that the given namespace held on @ancestor is still in scope
5653 * on node.
5654 *
5655 * Returns 1 if true, 0 if false and -1 in case of error.
5656 */
5657static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005658xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5659 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005660{
5661 xmlNsPtr tst;
5662
5663 while ((node != NULL) && (node != ancestor)) {
5664 if ((node->type == XML_ENTITY_REF_NODE) ||
5665 (node->type == XML_ENTITY_NODE) ||
5666 (node->type == XML_ENTITY_DECL))
5667 return (-1);
5668 if (node->type == XML_ELEMENT_NODE) {
5669 tst = node->nsDef;
5670 while (tst != NULL) {
5671 if ((tst->prefix == NULL)
5672 && (prefix == NULL))
5673 return (0);
5674 if ((tst->prefix != NULL)
5675 && (prefix != NULL)
5676 && (xmlStrEqual(tst->prefix, prefix)))
5677 return (0);
5678 tst = tst->next;
5679 }
5680 }
5681 node = node->parent;
5682 }
5683 if (node != ancestor)
5684 return (-1);
5685 return (1);
5686}
5687
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005688/**
Owen Taylor3473f882001-02-23 17:55:21 +00005689 * xmlSearchNsByHref:
5690 * @doc: the document
5691 * @node: the current node
5692 * @href: the namespace value
5693 *
5694 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5695 * the defined namespace or return NULL otherwise.
5696 * Returns the namespace pointer or NULL.
5697 */
5698xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005699xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5700{
Owen Taylor3473f882001-02-23 17:55:21 +00005701 xmlNsPtr cur;
5702 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005703 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005704
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005705 if ((node == NULL) || (href == NULL))
5706 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005707 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005708 /*
5709 * Only the document can hold the XML spec namespace.
5710 */
5711 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5712 /*
5713 * The XML-1.0 namespace is normally held on the root
5714 * element. In this case exceptionally create it on the
5715 * node element.
5716 */
5717 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5718 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005719 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005720 return (NULL);
5721 }
5722 memset(cur, 0, sizeof(xmlNs));
5723 cur->type = XML_LOCAL_NAMESPACE;
5724 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5725 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5726 cur->next = node->nsDef;
5727 node->nsDef = cur;
5728 return (cur);
5729 }
Daniel Veillard11ce4002006-03-10 00:36:23 +00005730 if (doc == NULL) {
5731 doc = node->doc;
5732 if (doc == NULL)
5733 return(NULL);
5734 }
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00005735 /*
5736 * Return the XML namespace declaration held by the doc.
5737 */
5738 if (doc->oldNs == NULL)
5739 return(xmlTreeEnsureXMLDecl(doc));
5740 else
5741 return(doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005742 }
Daniel Veillard62040be2004-05-17 03:17:26 +00005743 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00005744 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005745 if ((node->type == XML_ENTITY_REF_NODE) ||
5746 (node->type == XML_ENTITY_NODE) ||
5747 (node->type == XML_ENTITY_DECL))
5748 return (NULL);
5749 if (node->type == XML_ELEMENT_NODE) {
5750 cur = node->nsDef;
5751 while (cur != NULL) {
5752 if ((cur->href != NULL) && (href != NULL) &&
5753 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005754 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00005755 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005756 return (cur);
5757 }
5758 cur = cur->next;
5759 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005760 if (orig != node) {
5761 cur = node->ns;
5762 if (cur != NULL) {
5763 if ((cur->href != NULL) && (href != NULL) &&
5764 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005765 if (((!is_attr) || (cur->prefix != NULL)) &&
Kasimier T. Buchcikba70cc02005-02-28 10:28:21 +00005766 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00005767 return (cur);
5768 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005769 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005770 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005771 }
5772 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005773 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005774 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005775}
5776
5777/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005778 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005779 * @doc: the document
5780 * @tree: a node expected to hold the new namespace
5781 * @ns: the original namespace
5782 *
5783 * This function tries to locate a namespace definition in a tree
5784 * ancestors, or create a new namespace definition node similar to
5785 * @ns trying to reuse the same prefix. However if the given prefix is
5786 * null (default namespace) or reused within the subtree defined by
5787 * @tree or on one of its ancestors then a new prefix is generated.
5788 * Returns the (new) namespace definition or NULL in case of error
5789 */
5790xmlNsPtr
5791xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5792 xmlNsPtr def;
5793 xmlChar prefix[50];
5794 int counter = 1;
5795
5796 if (tree == NULL) {
5797#ifdef DEBUG_TREE
5798 xmlGenericError(xmlGenericErrorContext,
5799 "xmlNewReconciliedNs : tree == NULL\n");
5800#endif
5801 return(NULL);
5802 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00005803 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005804#ifdef DEBUG_TREE
5805 xmlGenericError(xmlGenericErrorContext,
5806 "xmlNewReconciliedNs : ns == NULL\n");
5807#endif
5808 return(NULL);
5809 }
5810 /*
5811 * Search an existing namespace definition inherited.
5812 */
5813 def = xmlSearchNsByHref(doc, tree, ns->href);
5814 if (def != NULL)
5815 return(def);
5816
5817 /*
5818 * Find a close prefix which is not already in use.
5819 * Let's strip namespace prefixes longer than 20 chars !
5820 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005821 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005822 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005823 else
William M. Brack13dfa872004-09-18 04:52:08 +00005824 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005825
Owen Taylor3473f882001-02-23 17:55:21 +00005826 def = xmlSearchNs(doc, tree, prefix);
5827 while (def != NULL) {
5828 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005829 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005830 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005831 else
William M. Brack13dfa872004-09-18 04:52:08 +00005832 snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
5833 (char *)ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005834 def = xmlSearchNs(doc, tree, prefix);
5835 }
5836
5837 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005838 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005839 */
5840 def = xmlNewNs(tree, ns->href, prefix);
5841 return(def);
5842}
5843
Daniel Veillard652327a2003-09-29 18:02:38 +00005844#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005845/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005846 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005847 * @doc: the document
5848 * @tree: a node defining the subtree to reconciliate
5849 *
5850 * This function checks that all the namespaces declared within the given
5851 * tree are properly declared. This is needed for example after Copy or Cut
5852 * and then paste operations. The subtree may still hold pointers to
5853 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005854 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005855 * the new environment. If not possible the new namespaces are redeclared
5856 * on @tree at the top of the given subtree.
5857 * Returns the number of namespace declarations created or -1 in case of error.
5858 */
5859int
5860xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5861 xmlNsPtr *oldNs = NULL;
5862 xmlNsPtr *newNs = NULL;
5863 int sizeCache = 0;
5864 int nbCache = 0;
5865
5866 xmlNsPtr n;
5867 xmlNodePtr node = tree;
5868 xmlAttrPtr attr;
5869 int ret = 0, i;
5870
Daniel Veillardce244ad2004-11-05 10:03:46 +00005871 if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1);
5872 if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1);
5873 if (node->doc != doc) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005874 while (node != NULL) {
5875 /*
5876 * Reconciliate the node namespace
5877 */
5878 if (node->ns != NULL) {
5879 /*
5880 * initialize the cache if needed
5881 */
5882 if (sizeCache == 0) {
5883 sizeCache = 10;
5884 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5885 sizeof(xmlNsPtr));
5886 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005887 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005888 return(-1);
5889 }
5890 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5891 sizeof(xmlNsPtr));
5892 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005893 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005894 xmlFree(oldNs);
5895 return(-1);
5896 }
5897 }
5898 for (i = 0;i < nbCache;i++) {
5899 if (oldNs[i] == node->ns) {
5900 node->ns = newNs[i];
5901 break;
5902 }
5903 }
5904 if (i == nbCache) {
5905 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005906 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005907 */
5908 n = xmlNewReconciliedNs(doc, tree, node->ns);
5909 if (n != NULL) { /* :-( what if else ??? */
5910 /*
5911 * check if we need to grow the cache buffers.
5912 */
5913 if (sizeCache <= nbCache) {
5914 sizeCache *= 2;
5915 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5916 sizeof(xmlNsPtr));
5917 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005918 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005919 xmlFree(newNs);
5920 return(-1);
5921 }
5922 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5923 sizeof(xmlNsPtr));
5924 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005925 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005926 xmlFree(oldNs);
5927 return(-1);
5928 }
5929 }
5930 newNs[nbCache] = n;
5931 oldNs[nbCache++] = node->ns;
5932 node->ns = n;
5933 }
5934 }
5935 }
5936 /*
5937 * now check for namespace hold by attributes on the node.
5938 */
Daniel Veillardb5f11972006-10-14 08:46:40 +00005939 if (node->type == XML_ELEMENT_NODE) {
5940 attr = node->properties;
5941 while (attr != NULL) {
5942 if (attr->ns != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005943 /*
Daniel Veillardb5f11972006-10-14 08:46:40 +00005944 * initialize the cache if needed
Owen Taylor3473f882001-02-23 17:55:21 +00005945 */
Daniel Veillardb5f11972006-10-14 08:46:40 +00005946 if (sizeCache == 0) {
5947 sizeCache = 10;
5948 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5949 sizeof(xmlNsPtr));
5950 if (oldNs == NULL) {
5951 xmlTreeErrMemory("fixing namespaces");
5952 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005953 }
Daniel Veillardb5f11972006-10-14 08:46:40 +00005954 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5955 sizeof(xmlNsPtr));
5956 if (newNs == NULL) {
5957 xmlTreeErrMemory("fixing namespaces");
5958 xmlFree(oldNs);
5959 return(-1);
5960 }
5961 }
5962 for (i = 0;i < nbCache;i++) {
5963 if (oldNs[i] == attr->ns) {
5964 attr->ns = newNs[i];
5965 break;
5966 }
5967 }
5968 if (i == nbCache) {
5969 /*
5970 * OK we need to recreate a new namespace definition
5971 */
5972 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5973 if (n != NULL) { /* :-( what if else ??? */
5974 /*
5975 * check if we need to grow the cache buffers.
5976 */
5977 if (sizeCache <= nbCache) {
5978 sizeCache *= 2;
5979 oldNs = (xmlNsPtr *) xmlRealloc(oldNs,
5980 sizeCache * sizeof(xmlNsPtr));
5981 if (oldNs == NULL) {
5982 xmlTreeErrMemory("fixing namespaces");
5983 xmlFree(newNs);
5984 return(-1);
5985 }
5986 newNs = (xmlNsPtr *) xmlRealloc(newNs,
5987 sizeCache * sizeof(xmlNsPtr));
5988 if (newNs == NULL) {
5989 xmlTreeErrMemory("fixing namespaces");
5990 xmlFree(oldNs);
5991 return(-1);
5992 }
5993 }
5994 newNs[nbCache] = n;
5995 oldNs[nbCache++] = attr->ns;
5996 attr->ns = n;
5997 }
Owen Taylor3473f882001-02-23 17:55:21 +00005998 }
5999 }
Daniel Veillardb5f11972006-10-14 08:46:40 +00006000 attr = attr->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006001 }
Owen Taylor3473f882001-02-23 17:55:21 +00006002 }
6003
6004 /*
6005 * Browse the full subtree, deep first
6006 */
Daniel Veillardb5f11972006-10-14 08:46:40 +00006007 if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006008 /* deep first */
6009 node = node->children;
6010 } else if ((node != tree) && (node->next != NULL)) {
6011 /* then siblings */
6012 node = node->next;
6013 } else if (node != tree) {
6014 /* go up to parents->next if needed */
6015 while (node != tree) {
6016 if (node->parent != NULL)
6017 node = node->parent;
6018 if ((node != tree) && (node->next != NULL)) {
6019 node = node->next;
6020 break;
6021 }
6022 if (node->parent == NULL) {
6023 node = NULL;
6024 break;
6025 }
6026 }
6027 /* exit condition */
6028 if (node == tree)
6029 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00006030 } else
6031 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006032 }
Daniel Veillardf742d342002-03-07 00:05:35 +00006033 if (oldNs != NULL)
6034 xmlFree(oldNs);
6035 if (newNs != NULL)
6036 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00006037 return(ret);
6038}
Daniel Veillard652327a2003-09-29 18:02:38 +00006039#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00006040
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006041static xmlAttrPtr
6042xmlGetPropNodeInternal(xmlNodePtr node, const xmlChar *name,
6043 const xmlChar *nsName, int useDTD)
6044{
6045 xmlAttrPtr prop;
6046
6047 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6048 return(NULL);
6049
6050 if (node->properties != NULL) {
6051 prop = node->properties;
6052 if (nsName == NULL) {
6053 /*
6054 * We want the attr to be in no namespace.
6055 */
6056 do {
6057 if ((prop->ns == NULL) && xmlStrEqual(prop->name, name)) {
6058 return(prop);
6059 }
6060 prop = prop->next;
6061 } while (prop != NULL);
6062 } else {
6063 /*
6064 * We want the attr to be in the specified namespace.
6065 */
6066 do {
6067 if ((prop->ns != NULL) && xmlStrEqual(prop->name, name) &&
6068 ((prop->ns->href == nsName) ||
6069 xmlStrEqual(prop->ns->href, nsName)))
6070 {
6071 return(prop);
6072 }
6073 prop = prop->next;
6074 } while (prop != NULL);
6075 }
6076 }
6077
6078#ifdef LIBXML_TREE_ENABLED
6079 if (! useDTD)
6080 return(NULL);
6081 /*
6082 * Check if there is a default/fixed attribute declaration in
6083 * the internal or external subset.
6084 */
6085 if ((node->doc != NULL) && (node->doc->intSubset != NULL)) {
6086 xmlDocPtr doc = node->doc;
6087 xmlAttributePtr attrDecl = NULL;
6088 xmlChar *elemQName, *tmpstr = NULL;
6089
6090 /*
6091 * We need the QName of the element for the DTD-lookup.
6092 */
6093 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
6094 tmpstr = xmlStrdup(node->ns->prefix);
6095 tmpstr = xmlStrcat(tmpstr, BAD_CAST ":");
6096 tmpstr = xmlStrcat(tmpstr, node->name);
6097 if (tmpstr == NULL)
6098 return(NULL);
6099 elemQName = tmpstr;
6100 } else
6101 elemQName = (xmlChar *) node->name;
6102 if (nsName == NULL) {
6103 /*
6104 * The common and nice case: Attr in no namespace.
6105 */
6106 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset,
6107 elemQName, name, NULL);
6108 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
6109 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset,
6110 elemQName, name, NULL);
6111 }
6112 } else {
6113 xmlNsPtr *nsList, *cur;
6114
6115 /*
6116 * The ugly case: Search using the prefixes of in-scope
6117 * ns-decls corresponding to @nsName.
6118 */
6119 nsList = xmlGetNsList(node->doc, node);
6120 if (nsList == NULL) {
6121 if (tmpstr != NULL)
6122 xmlFree(tmpstr);
6123 return(NULL);
6124 }
6125 cur = nsList;
6126 while (*cur != NULL) {
6127 if (xmlStrEqual((*cur)->href, nsName)) {
6128 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elemQName,
6129 name, (*cur)->prefix);
6130 if (attrDecl)
6131 break;
6132 if (doc->extSubset != NULL) {
6133 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elemQName,
6134 name, (*cur)->prefix);
6135 if (attrDecl)
6136 break;
6137 }
6138 }
6139 cur++;
6140 }
6141 xmlFree(nsList);
6142 }
6143 if (tmpstr != NULL)
6144 xmlFree(tmpstr);
6145 /*
6146 * Only default/fixed attrs are relevant.
6147 */
6148 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6149 return((xmlAttrPtr) attrDecl);
6150 }
6151#endif /* LIBXML_TREE_ENABLED */
6152 return(NULL);
6153}
6154
6155static xmlChar*
6156xmlGetPropNodeValueInternal(xmlAttrPtr prop)
6157{
6158 if (prop == NULL)
6159 return(NULL);
6160 if (prop->type == XML_ATTRIBUTE_NODE) {
6161 /*
6162 * Note that we return at least the empty string.
6163 * TODO: Do we really always want that?
6164 */
6165 if (prop->children != NULL) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00006166 if ((prop->children->next == NULL) &&
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006167 ((prop->children->type == XML_TEXT_NODE) ||
6168 (prop->children->type == XML_CDATA_SECTION_NODE)))
6169 {
6170 /*
6171 * Optimization for the common case: only 1 text node.
6172 */
6173 return(xmlStrdup(prop->children->content));
6174 } else {
6175 xmlChar *ret;
6176
6177 ret = xmlNodeListGetString(prop->doc, prop->children, 1);
6178 if (ret != NULL)
6179 return(ret);
6180 }
6181 }
6182 return(xmlStrdup((xmlChar *)""));
6183 } else if (prop->type == XML_ATTRIBUTE_DECL) {
6184 return(xmlStrdup(((xmlAttributePtr)prop)->defaultValue));
6185 }
6186 return(NULL);
6187}
6188
Owen Taylor3473f882001-02-23 17:55:21 +00006189/**
6190 * xmlHasProp:
6191 * @node: the node
6192 * @name: the attribute name
6193 *
6194 * Search an attribute associated to a node
6195 * This function also looks in DTD attribute declaration for #FIXED or
6196 * default declaration values unless DTD use has been turned off.
6197 *
6198 * Returns the attribute or the attribute declaration or NULL if
6199 * neither was found.
6200 */
6201xmlAttrPtr
6202xmlHasProp(xmlNodePtr node, const xmlChar *name) {
6203 xmlAttrPtr prop;
6204 xmlDocPtr doc;
6205
Daniel Veillard8874b942005-08-25 13:19:21 +00006206 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6207 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006208 /*
6209 * Check on the properties attached to the node
6210 */
6211 prop = node->properties;
6212 while (prop != NULL) {
6213 if (xmlStrEqual(prop->name, name)) {
6214 return(prop);
6215 }
6216 prop = prop->next;
6217 }
6218 if (!xmlCheckDTD) return(NULL);
6219
6220 /*
6221 * Check if there is a default declaration in the internal
6222 * or external subsets
6223 */
6224 doc = node->doc;
6225 if (doc != NULL) {
6226 xmlAttributePtr attrDecl;
6227 if (doc->intSubset != NULL) {
6228 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6229 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6230 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006231 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6232 /* return attribute declaration only if a default value is given
6233 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006234 return((xmlAttrPtr) attrDecl);
6235 }
6236 }
6237 return(NULL);
6238}
6239
6240/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00006241 * xmlHasNsProp:
6242 * @node: the node
6243 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006244 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00006245 *
6246 * Search for an attribute associated to a node
6247 * This attribute has to be anchored in the namespace specified.
6248 * This does the entity substitution.
6249 * This function looks in DTD attribute declaration for #FIXED or
6250 * default declaration values unless DTD use has been turned off.
William M. Brack2c228442004-10-03 04:10:00 +00006251 * Note that a namespace of NULL indicates to use the default namespace.
Daniel Veillarde95e2392001-06-06 10:46:28 +00006252 *
6253 * Returns the attribute or the attribute declaration or NULL
6254 * if neither was found.
6255 */
6256xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00006257xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00006258
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006259 return(xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD));
Daniel Veillarde95e2392001-06-06 10:46:28 +00006260}
6261
6262/**
Owen Taylor3473f882001-02-23 17:55:21 +00006263 * xmlGetProp:
6264 * @node: the node
6265 * @name: the attribute name
6266 *
6267 * Search and get the value of an attribute associated to a node
6268 * This does the entity substitution.
6269 * This function looks in DTD attribute declaration for #FIXED or
6270 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00006271 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00006272 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6273 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00006274 *
6275 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006276 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006277 */
6278xmlChar *
6279xmlGetProp(xmlNodePtr node, const xmlChar *name) {
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006280 xmlAttrPtr prop;
Owen Taylor3473f882001-02-23 17:55:21 +00006281
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006282 prop = xmlHasProp(node, name);
6283 if (prop == NULL)
6284 return(NULL);
6285 return(xmlGetPropNodeValueInternal(prop));
Owen Taylor3473f882001-02-23 17:55:21 +00006286}
6287
6288/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006289 * xmlGetNoNsProp:
6290 * @node: the node
6291 * @name: the attribute name
6292 *
6293 * Search and get the value of an attribute associated to a node
6294 * This does the entity substitution.
6295 * This function looks in DTD attribute declaration for #FIXED or
6296 * default declaration values unless DTD use has been turned off.
6297 * This function is similar to xmlGetProp except it will accept only
6298 * an attribute in no namespace.
6299 *
6300 * Returns the attribute value or NULL if not found.
6301 * It's up to the caller to free the memory with xmlFree().
6302 */
6303xmlChar *
6304xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6305 xmlAttrPtr prop;
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006306
6307 prop = xmlGetPropNodeInternal(node, name, NULL, xmlCheckDTD);
6308 if (prop == NULL)
Daniel Veillard8874b942005-08-25 13:19:21 +00006309 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006310 return(xmlGetPropNodeValueInternal(prop));
Daniel Veillard71531f32003-02-05 13:19:53 +00006311}
6312
6313/**
Owen Taylor3473f882001-02-23 17:55:21 +00006314 * xmlGetNsProp:
6315 * @node: the node
6316 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006317 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006318 *
6319 * Search and get the value of an attribute associated to a node
6320 * This attribute has to be anchored in the namespace specified.
6321 * This does the entity substitution.
6322 * This function looks in DTD attribute declaration for #FIXED or
6323 * default declaration values unless DTD use has been turned off.
6324 *
6325 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006326 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006327 */
6328xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006329xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006330 xmlAttrPtr prop;
Owen Taylor3473f882001-02-23 17:55:21 +00006331
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006332 prop = xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD);
6333 if (prop == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006334 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006335 return(xmlGetPropNodeValueInternal(prop));
Owen Taylor3473f882001-02-23 17:55:21 +00006336}
6337
Daniel Veillard2156d432004-03-04 15:59:36 +00006338#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6339/**
6340 * xmlUnsetProp:
6341 * @node: the node
6342 * @name: the attribute name
6343 *
6344 * Remove an attribute carried by a node.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006345 * This handles only attributes in no namespace.
Daniel Veillard2156d432004-03-04 15:59:36 +00006346 * Returns 0 if successful, -1 if not found
6347 */
6348int
6349xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Kasimier T. Buchcik65c2f1d2005-10-17 12:39:58 +00006350 xmlAttrPtr prop;
Daniel Veillard2156d432004-03-04 15:59:36 +00006351
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006352 prop = xmlGetPropNodeInternal(node, name, NULL, 0);
6353 if (prop == NULL)
Daniel Veillard2156d432004-03-04 15:59:36 +00006354 return(-1);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006355 xmlUnlinkNode((xmlNodePtr) prop);
6356 xmlFreeProp(prop);
6357 return(0);
Daniel Veillard2156d432004-03-04 15:59:36 +00006358}
6359
6360/**
6361 * xmlUnsetNsProp:
6362 * @node: the node
6363 * @ns: the namespace definition
6364 * @name: the attribute name
6365 *
6366 * Remove an attribute carried by a node.
6367 * Returns 0 if successful, -1 if not found
6368 */
6369int
6370xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
Kasimier T. Buchcik65c2f1d2005-10-17 12:39:58 +00006371 xmlAttrPtr prop;
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006372
6373 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
6374 if (prop == NULL)
Daniel Veillard2156d432004-03-04 15:59:36 +00006375 return(-1);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006376 xmlUnlinkNode((xmlNodePtr) prop);
6377 xmlFreeProp(prop);
6378 return(0);
Daniel Veillard2156d432004-03-04 15:59:36 +00006379}
6380#endif
6381
6382#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006383/**
6384 * xmlSetProp:
6385 * @node: the node
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006386 * @name: the attribute name (a QName)
Owen Taylor3473f882001-02-23 17:55:21 +00006387 * @value: the attribute value
6388 *
6389 * Set (or reset) an attribute carried by a node.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006390 * If @name has a prefix, then the corresponding
6391 * namespace-binding will be used, if in scope; it is an
6392 * error it there's no such ns-binding for the prefix in
6393 * scope.
Owen Taylor3473f882001-02-23 17:55:21 +00006394 * Returns the attribute pointer.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006395 *
Owen Taylor3473f882001-02-23 17:55:21 +00006396 */
6397xmlAttrPtr
6398xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006399 int len;
6400 const xmlChar *nqname;
Owen Taylor3473f882001-02-23 17:55:21 +00006401
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006402 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006403 return(NULL);
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00006404
6405 /*
6406 * handle QNames
6407 */
6408 nqname = xmlSplitQName3(name, &len);
6409 if (nqname != NULL) {
6410 xmlNsPtr ns;
6411 xmlChar *prefix = xmlStrndup(name, len);
6412 ns = xmlSearchNs(node->doc, node, prefix);
6413 if (prefix != NULL)
6414 xmlFree(prefix);
6415 if (ns != NULL)
6416 return(xmlSetNsProp(node, ns, nqname, value));
6417 }
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006418 return(xmlSetNsProp(node, NULL, name, value));
Owen Taylor3473f882001-02-23 17:55:21 +00006419}
6420
6421/**
6422 * xmlSetNsProp:
6423 * @node: the node
6424 * @ns: the namespace definition
6425 * @name: the attribute name
6426 * @value: the attribute value
6427 *
6428 * Set (or reset) an attribute carried by a node.
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006429 * The ns structure must be in scope, this is not checked
Owen Taylor3473f882001-02-23 17:55:21 +00006430 *
6431 * Returns the attribute pointer.
6432 */
6433xmlAttrPtr
6434xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006435 const xmlChar *value)
6436{
Owen Taylor3473f882001-02-23 17:55:21 +00006437 xmlAttrPtr prop;
6438
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006439 if (ns && (ns->href == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006440 return(NULL);
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006441 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
6442 if (prop != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006443 /*
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006444 * Modify the attribute's value.
6445 */
6446 if (prop->atype == XML_ATTRIBUTE_ID) {
6447 xmlRemoveID(node->doc, prop);
6448 prop->atype = XML_ATTRIBUTE_ID;
6449 }
6450 if (prop->children != NULL)
6451 xmlFreeNodeList(prop->children);
6452 prop->children = NULL;
6453 prop->last = NULL;
6454 prop->ns = ns;
6455 if (value != NULL) {
6456 xmlChar *buffer;
6457 xmlNodePtr tmp;
6458
6459 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6460 prop->children = xmlStringGetNodeList(node->doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00006461 prop->last = NULL;
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006462 tmp = prop->children;
6463 while (tmp != NULL) {
6464 tmp->parent = (xmlNodePtr) prop;
6465 if (tmp->next == NULL)
6466 prop->last = tmp;
6467 tmp = tmp->next;
6468 }
6469 xmlFree(buffer);
6470 }
6471 if (prop->atype == XML_ATTRIBUTE_ID)
6472 xmlAddID(NULL, node->doc, value, prop);
6473 return(prop);
Owen Taylor3473f882001-02-23 17:55:21 +00006474 }
Kasimier T. Buchcik30f874d2006-03-02 18:04:29 +00006475 /*
6476 * No equal attr found; create a new one.
6477 */
6478 return(xmlNewPropInternal(node, ns, name, value, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006479}
6480
Daniel Veillard652327a2003-09-29 18:02:38 +00006481#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006482
6483/**
Owen Taylor3473f882001-02-23 17:55:21 +00006484 * xmlNodeIsText:
6485 * @node: the node
6486 *
6487 * Is this node a Text node ?
6488 * Returns 1 yes, 0 no
6489 */
6490int
6491xmlNodeIsText(xmlNodePtr node) {
6492 if (node == NULL) return(0);
6493
6494 if (node->type == XML_TEXT_NODE) return(1);
6495 return(0);
6496}
6497
6498/**
6499 * xmlIsBlankNode:
6500 * @node: the node
6501 *
6502 * Checks whether this node is an empty or whitespace only
6503 * (and possibly ignorable) text-node.
6504 *
6505 * Returns 1 yes, 0 no
6506 */
6507int
6508xmlIsBlankNode(xmlNodePtr node) {
6509 const xmlChar *cur;
6510 if (node == NULL) return(0);
6511
Daniel Veillard7db37732001-07-12 01:20:08 +00006512 if ((node->type != XML_TEXT_NODE) &&
6513 (node->type != XML_CDATA_SECTION_NODE))
6514 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006515 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006516 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006517 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006518 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006519 cur++;
6520 }
6521
6522 return(1);
6523}
6524
6525/**
6526 * xmlTextConcat:
6527 * @node: the node
6528 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006529 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006530 *
6531 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006532 *
6533 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006534 */
6535
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006536int
Owen Taylor3473f882001-02-23 17:55:21 +00006537xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006538 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006539
6540 if ((node->type != XML_TEXT_NODE) &&
Rob Richardsa02f1992006-09-16 14:04:26 +00006541 (node->type != XML_CDATA_SECTION_NODE) &&
6542 (node->type != XML_COMMENT_NODE) &&
6543 (node->type != XML_PI_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006544#ifdef DEBUG_TREE
6545 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006546 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006547#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006548 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006549 }
William M. Brack7762bb12004-01-04 14:49:01 +00006550 /* need to check if content is currently in the dictionary */
Daniel Veillard8874b942005-08-25 13:19:21 +00006551 if ((node->content == (xmlChar *) &(node->properties)) ||
6552 ((node->doc != NULL) && (node->doc->dict != NULL) &&
6553 xmlDictOwns(node->doc->dict, node->content))) {
William M. Brack7762bb12004-01-04 14:49:01 +00006554 node->content = xmlStrncatNew(node->content, content, len);
6555 } else {
6556 node->content = xmlStrncat(node->content, content, len);
6557 }
Daniel Veillard8874b942005-08-25 13:19:21 +00006558 node->properties = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006559 if (node->content == NULL)
6560 return(-1);
6561 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006562}
6563
6564/************************************************************************
6565 * *
6566 * Output : to a FILE or in memory *
6567 * *
6568 ************************************************************************/
6569
Owen Taylor3473f882001-02-23 17:55:21 +00006570/**
6571 * xmlBufferCreate:
6572 *
6573 * routine to create an XML buffer.
6574 * returns the new structure.
6575 */
6576xmlBufferPtr
6577xmlBufferCreate(void) {
6578 xmlBufferPtr ret;
6579
6580 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6581 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006582 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006583 return(NULL);
6584 }
6585 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006586 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006587 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006588 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006589 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006590 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006591 xmlFree(ret);
6592 return(NULL);
6593 }
6594 ret->content[0] = 0;
6595 return(ret);
6596}
6597
6598/**
6599 * xmlBufferCreateSize:
6600 * @size: initial size of buffer
6601 *
6602 * routine to create an XML buffer.
6603 * returns the new structure.
6604 */
6605xmlBufferPtr
6606xmlBufferCreateSize(size_t size) {
6607 xmlBufferPtr ret;
6608
6609 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6610 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006611 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006612 return(NULL);
6613 }
6614 ret->use = 0;
6615 ret->alloc = xmlBufferAllocScheme;
6616 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6617 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006618 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006619 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006620 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006621 xmlFree(ret);
6622 return(NULL);
6623 }
6624 ret->content[0] = 0;
6625 } else
6626 ret->content = NULL;
6627 return(ret);
6628}
6629
6630/**
Daniel Veillard53350552003-09-18 13:35:51 +00006631 * xmlBufferCreateStatic:
6632 * @mem: the memory area
6633 * @size: the size in byte
6634 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006635 * routine to create an XML buffer from an immutable memory area.
6636 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006637 * present until the end of the buffer lifetime.
6638 *
6639 * returns the new structure.
6640 */
6641xmlBufferPtr
6642xmlBufferCreateStatic(void *mem, size_t size) {
6643 xmlBufferPtr ret;
6644
6645 if ((mem == NULL) || (size == 0))
6646 return(NULL);
6647
6648 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6649 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006650 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006651 return(NULL);
6652 }
6653 ret->use = size;
6654 ret->size = size;
6655 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6656 ret->content = (xmlChar *) mem;
6657 return(ret);
6658}
6659
6660/**
Owen Taylor3473f882001-02-23 17:55:21 +00006661 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006662 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006663 * @scheme: allocation scheme to use
6664 *
6665 * Sets the allocation scheme for this buffer
6666 */
6667void
6668xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6669 xmlBufferAllocationScheme scheme) {
6670 if (buf == NULL) {
6671#ifdef DEBUG_BUFFER
6672 xmlGenericError(xmlGenericErrorContext,
6673 "xmlBufferSetAllocationScheme: buf == NULL\n");
6674#endif
6675 return;
6676 }
Daniel Veillard53350552003-09-18 13:35:51 +00006677 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006678
6679 buf->alloc = scheme;
6680}
6681
6682/**
6683 * xmlBufferFree:
6684 * @buf: the buffer to free
6685 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006686 * Frees an XML buffer. It frees both the content and the structure which
6687 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006688 */
6689void
6690xmlBufferFree(xmlBufferPtr buf) {
6691 if (buf == NULL) {
6692#ifdef DEBUG_BUFFER
6693 xmlGenericError(xmlGenericErrorContext,
6694 "xmlBufferFree: buf == NULL\n");
6695#endif
6696 return;
6697 }
Daniel Veillard53350552003-09-18 13:35:51 +00006698
6699 if ((buf->content != NULL) &&
6700 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006701 xmlFree(buf->content);
6702 }
Owen Taylor3473f882001-02-23 17:55:21 +00006703 xmlFree(buf);
6704}
6705
6706/**
6707 * xmlBufferEmpty:
6708 * @buf: the buffer
6709 *
6710 * empty a buffer.
6711 */
6712void
6713xmlBufferEmpty(xmlBufferPtr buf) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006714 if (buf == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006715 if (buf->content == NULL) return;
6716 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006717 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006718 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006719 } else {
6720 memset(buf->content, 0, buf->size);
6721 }
Owen Taylor3473f882001-02-23 17:55:21 +00006722}
6723
6724/**
6725 * xmlBufferShrink:
6726 * @buf: the buffer to dump
6727 * @len: the number of xmlChar to remove
6728 *
6729 * Remove the beginning of an XML buffer.
6730 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006731 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006732 */
6733int
6734xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
Daniel Veillard3d97e662004-11-04 10:49:00 +00006735 if (buf == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006736 if (len == 0) return(0);
6737 if (len > buf->use) return(-1);
6738
6739 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006740 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6741 buf->content += len;
6742 } else {
6743 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6744 buf->content[buf->use] = 0;
6745 }
Owen Taylor3473f882001-02-23 17:55:21 +00006746 return(len);
6747}
6748
6749/**
6750 * xmlBufferGrow:
6751 * @buf: the buffer
6752 * @len: the minimum free size to allocate
6753 *
6754 * Grow the available space of an XML buffer.
6755 *
6756 * Returns the new available space or -1 in case of error
6757 */
6758int
6759xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6760 int size;
6761 xmlChar *newbuf;
6762
Daniel Veillard3d97e662004-11-04 10:49:00 +00006763 if (buf == NULL) return(-1);
6764
Daniel Veillard53350552003-09-18 13:35:51 +00006765 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006766 if (len + buf->use < buf->size) return(0);
6767
William M. Brack30fe43f2004-07-26 18:00:58 +00006768/*
6769 * Windows has a BIG problem on realloc timing, so we try to double
6770 * the buffer size (if that's enough) (bug 146697)
6771 */
6772#ifdef WIN32
6773 if (buf->size > len)
6774 size = buf->size * 2;
6775 else
6776 size = buf->use + len + 100;
6777#else
Owen Taylor3473f882001-02-23 17:55:21 +00006778 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00006779#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006780
6781 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006782 if (newbuf == NULL) {
6783 xmlTreeErrMemory("growing buffer");
6784 return(-1);
6785 }
Owen Taylor3473f882001-02-23 17:55:21 +00006786 buf->content = newbuf;
6787 buf->size = size;
6788 return(buf->size - buf->use);
6789}
6790
6791/**
6792 * xmlBufferDump:
6793 * @file: the file output
6794 * @buf: the buffer to dump
6795 *
6796 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006797 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006798 */
6799int
6800xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6801 int ret;
6802
6803 if (buf == NULL) {
6804#ifdef DEBUG_BUFFER
6805 xmlGenericError(xmlGenericErrorContext,
6806 "xmlBufferDump: buf == NULL\n");
6807#endif
6808 return(0);
6809 }
6810 if (buf->content == NULL) {
6811#ifdef DEBUG_BUFFER
6812 xmlGenericError(xmlGenericErrorContext,
6813 "xmlBufferDump: buf->content == NULL\n");
6814#endif
6815 return(0);
6816 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006817 if (file == NULL)
6818 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006819 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6820 return(ret);
6821}
6822
6823/**
6824 * xmlBufferContent:
6825 * @buf: the buffer
6826 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006827 * Function to extract the content of a buffer
6828 *
Owen Taylor3473f882001-02-23 17:55:21 +00006829 * Returns the internal content
6830 */
6831
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006832const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006833xmlBufferContent(const xmlBufferPtr buf)
6834{
6835 if(!buf)
6836 return NULL;
6837
6838 return buf->content;
6839}
6840
6841/**
6842 * xmlBufferLength:
6843 * @buf: the buffer
6844 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006845 * Function to get the length of a buffer
6846 *
Owen Taylor3473f882001-02-23 17:55:21 +00006847 * Returns the length of data in the internal content
6848 */
6849
6850int
6851xmlBufferLength(const xmlBufferPtr buf)
6852{
6853 if(!buf)
6854 return 0;
6855
6856 return buf->use;
6857}
6858
6859/**
6860 * xmlBufferResize:
6861 * @buf: the buffer to resize
6862 * @size: the desired size
6863 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006864 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006865 *
6866 * Returns 0 in case of problems, 1 otherwise
6867 */
6868int
6869xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6870{
6871 unsigned int newSize;
6872 xmlChar* rebuf = NULL;
6873
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006874 if (buf == NULL)
6875 return(0);
6876
Daniel Veillard53350552003-09-18 13:35:51 +00006877 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6878
Owen Taylor3473f882001-02-23 17:55:21 +00006879 /* Don't resize if we don't have to */
6880 if (size < buf->size)
6881 return 1;
6882
6883 /* figure out new size */
6884 switch (buf->alloc){
6885 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillardbf629492004-04-20 22:20:59 +00006886 /*take care of empty case*/
6887 newSize = (buf->size ? buf->size*2 : size + 10);
Owen Taylor3473f882001-02-23 17:55:21 +00006888 while (size > newSize) newSize *= 2;
6889 break;
6890 case XML_BUFFER_ALLOC_EXACT:
6891 newSize = size+10;
6892 break;
6893 default:
6894 newSize = size+10;
6895 break;
6896 }
6897
6898 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006899 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006900 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006901 rebuf = (xmlChar *) xmlRealloc(buf->content,
6902 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006903 } else {
6904 /*
6905 * if we are reallocating a buffer far from being full, it's
6906 * better to make a new allocation and copy only the used range
6907 * and free the old one.
6908 */
6909 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6910 if (rebuf != NULL) {
6911 memcpy(rebuf, buf->content, buf->use);
6912 xmlFree(buf->content);
William M. Brack42331a92004-07-29 07:07:16 +00006913 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006914 }
6915 }
Owen Taylor3473f882001-02-23 17:55:21 +00006916 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006917 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006918 return 0;
6919 }
6920 buf->content = rebuf;
6921 buf->size = newSize;
6922
6923 return 1;
6924}
6925
6926/**
6927 * xmlBufferAdd:
6928 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006929 * @str: the #xmlChar string
6930 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006931 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006932 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006933 * str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006934 *
6935 * Returns 0 successful, a positive error code number otherwise
6936 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006937 */
William M. Bracka3215c72004-07-31 16:24:01 +00006938int
Owen Taylor3473f882001-02-23 17:55:21 +00006939xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6940 unsigned int needSize;
6941
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006942 if ((str == NULL) || (buf == NULL)) {
William M. Bracka3215c72004-07-31 16:24:01 +00006943 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006944 }
William M. Bracka3215c72004-07-31 16:24:01 +00006945 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006946 if (len < -1) {
6947#ifdef DEBUG_BUFFER
6948 xmlGenericError(xmlGenericErrorContext,
6949 "xmlBufferAdd: len < 0\n");
6950#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006951 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006952 }
William M. Bracka3215c72004-07-31 16:24:01 +00006953 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006954
6955 if (len < 0)
6956 len = xmlStrlen(str);
6957
William M. Bracka3215c72004-07-31 16:24:01 +00006958 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006959
6960 needSize = buf->use + len + 2;
6961 if (needSize > buf->size){
6962 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006963 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006964 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006965 }
6966 }
6967
6968 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6969 buf->use += len;
6970 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006971 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006972}
6973
6974/**
6975 * xmlBufferAddHead:
6976 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006977 * @str: the #xmlChar string
6978 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006979 *
6980 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006981 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006982 *
6983 * Returns 0 successful, a positive error code number otherwise
6984 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006985 */
William M. Bracka3215c72004-07-31 16:24:01 +00006986int
Owen Taylor3473f882001-02-23 17:55:21 +00006987xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6988 unsigned int needSize;
6989
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006990 if (buf == NULL)
6991 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00006992 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006993 if (str == NULL) {
6994#ifdef DEBUG_BUFFER
6995 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006996 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006997#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006998 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006999 }
7000 if (len < -1) {
7001#ifdef DEBUG_BUFFER
7002 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007003 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007004#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007005 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007006 }
William M. Bracka3215c72004-07-31 16:24:01 +00007007 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007008
7009 if (len < 0)
7010 len = xmlStrlen(str);
7011
William M. Bracka3215c72004-07-31 16:24:01 +00007012 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007013
7014 needSize = buf->use + len + 2;
7015 if (needSize > buf->size){
7016 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007017 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007018 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007019 }
7020 }
7021
7022 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
7023 memmove(&buf->content[0], str, len * sizeof(xmlChar));
7024 buf->use += len;
7025 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007026 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007027}
7028
7029/**
7030 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00007031 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00007032 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00007033 *
7034 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007035 *
7036 * Returns 0 successful, a positive error code number otherwise
7037 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007038 */
William M. Bracka3215c72004-07-31 16:24:01 +00007039int
Owen Taylor3473f882001-02-23 17:55:21 +00007040xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007041 if (buf == NULL)
7042 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007043 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
7044 if (str == NULL) return -1;
7045 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00007046}
7047
7048/**
7049 * xmlBufferCCat:
7050 * @buf: the buffer to dump
7051 * @str: the C char string
7052 *
7053 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007054 *
7055 * Returns 0 successful, a positive error code number otherwise
7056 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007057 */
William M. Bracka3215c72004-07-31 16:24:01 +00007058int
Owen Taylor3473f882001-02-23 17:55:21 +00007059xmlBufferCCat(xmlBufferPtr buf, const char *str) {
7060 const char *cur;
7061
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007062 if (buf == NULL)
7063 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007064 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007065 if (str == NULL) {
7066#ifdef DEBUG_BUFFER
7067 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007068 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007069#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007070 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007071 }
7072 for (cur = str;*cur != 0;cur++) {
7073 if (buf->use + 10 >= buf->size) {
7074 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007075 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007076 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007077 }
7078 }
7079 buf->content[buf->use++] = *cur;
7080 }
7081 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007082 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007083}
7084
7085/**
7086 * xmlBufferWriteCHAR:
7087 * @buf: the XML buffer
7088 * @string: the string to add
7089 *
7090 * routine which manages and grows an output buffer. This one adds
7091 * xmlChars at the end of the buffer.
7092 */
7093void
Daniel Veillard53350552003-09-18 13:35:51 +00007094xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007095 if (buf == NULL)
7096 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007097 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007098 xmlBufferCat(buf, string);
7099}
7100
7101/**
7102 * xmlBufferWriteChar:
7103 * @buf: the XML buffer output
7104 * @string: the string to add
7105 *
7106 * routine which manage and grows an output buffer. This one add
7107 * C chars at the end of the array.
7108 */
7109void
7110xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007111 if (buf == NULL)
7112 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007113 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007114 xmlBufferCCat(buf, string);
7115}
7116
7117
7118/**
7119 * xmlBufferWriteQuotedString:
7120 * @buf: the XML buffer output
7121 * @string: the string to add
7122 *
7123 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00007124 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00007125 * quote or double-quotes internally
7126 */
7127void
7128xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00007129 const xmlChar *cur, *base;
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007130 if (buf == NULL)
7131 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007132 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00007133 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00007134 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00007135#ifdef DEBUG_BUFFER
7136 xmlGenericError(xmlGenericErrorContext,
7137 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7138#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00007139 xmlBufferCCat(buf, "\"");
7140 base = cur = string;
7141 while(*cur != 0){
7142 if(*cur == '"'){
7143 if (base != cur)
7144 xmlBufferAdd(buf, base, cur - base);
7145 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7146 cur++;
7147 base = cur;
7148 }
7149 else {
7150 cur++;
7151 }
7152 }
7153 if (base != cur)
7154 xmlBufferAdd(buf, base, cur - base);
7155 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007156 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007157 else{
7158 xmlBufferCCat(buf, "\'");
7159 xmlBufferCat(buf, string);
7160 xmlBufferCCat(buf, "\'");
7161 }
Owen Taylor3473f882001-02-23 17:55:21 +00007162 } else {
7163 xmlBufferCCat(buf, "\"");
7164 xmlBufferCat(buf, string);
7165 xmlBufferCCat(buf, "\"");
7166 }
7167}
7168
7169
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007170/**
7171 * xmlGetDocCompressMode:
7172 * @doc: the document
7173 *
7174 * get the compression ratio for a document, ZLIB based
7175 * Returns 0 (uncompressed) to 9 (max compression)
7176 */
7177int
7178xmlGetDocCompressMode (xmlDocPtr doc) {
7179 if (doc == NULL) return(-1);
7180 return(doc->compression);
7181}
7182
7183/**
7184 * xmlSetDocCompressMode:
7185 * @doc: the document
7186 * @mode: the compression ratio
7187 *
7188 * set the compression ratio for a document, ZLIB based
7189 * Correct values: 0 (uncompressed) to 9 (max compression)
7190 */
7191void
7192xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7193 if (doc == NULL) return;
7194 if (mode < 0) doc->compression = 0;
7195 else if (mode > 9) doc->compression = 9;
7196 else doc->compression = mode;
7197}
7198
7199/**
7200 * xmlGetCompressMode:
7201 *
7202 * get the default compression mode used, ZLIB based.
7203 * Returns 0 (uncompressed) to 9 (max compression)
7204 */
7205int
7206xmlGetCompressMode(void)
7207{
7208 return (xmlCompressMode);
7209}
7210
7211/**
7212 * xmlSetCompressMode:
7213 * @mode: the compression ratio
7214 *
7215 * set the default compression mode used, ZLIB based
7216 * Correct values: 0 (uncompressed) to 9 (max compression)
7217 */
7218void
7219xmlSetCompressMode(int mode) {
7220 if (mode < 0) xmlCompressMode = 0;
7221 else if (mode > 9) xmlCompressMode = 9;
7222 else xmlCompressMode = mode;
7223}
7224
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007225#define XML_TREE_NSMAP_PARENT -1
7226#define XML_TREE_NSMAP_XML -2
7227#define XML_TREE_NSMAP_DOC -3
7228#define XML_TREE_NSMAP_CUSTOM -4
7229
7230typedef struct xmlNsMapItem *xmlNsMapItemPtr;
7231struct xmlNsMapItem {
7232 xmlNsMapItemPtr next;
7233 xmlNsMapItemPtr prev;
7234 xmlNsPtr oldNs; /* old ns decl reference */
7235 xmlNsPtr newNs; /* new ns decl reference */
7236 int shadowDepth; /* Shadowed at this depth */
7237 /*
7238 * depth:
7239 * >= 0 == @node's ns-decls
7240 * -1 == @parent's ns-decls
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00007241 * -2 == the doc->oldNs XML ns-decl
7242 * -3 == the doc->oldNs storage ns-decls
7243 * -4 == ns-decls provided via custom ns-handling
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007244 */
7245 int depth;
7246};
7247
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007248typedef struct xmlNsMap *xmlNsMapPtr;
7249struct xmlNsMap {
7250 xmlNsMapItemPtr first;
7251 xmlNsMapItemPtr last;
7252 xmlNsMapItemPtr pool;
7253};
7254
7255#define XML_NSMAP_NOTEMPTY(m) (((m) != NULL) && ((m)->first != NULL))
7256#define XML_NSMAP_FOREACH(m, i) for (i = (m)->first; i != NULL; i = (i)->next)
7257#define XML_NSMAP_POP(m, i) \
7258 i = (m)->last; \
7259 (m)->last = (i)->prev; \
7260 if ((m)->last == NULL) \
7261 (m)->first = NULL; \
7262 else \
7263 (m)->last->next = NULL; \
7264 (i)->next = (m)->pool; \
7265 (m)->pool = i;
7266
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007267/*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007268* xmlDOMWrapNsMapFree:
7269* @map: the ns-map
7270*
7271* Frees the ns-map
7272*/
7273static void
7274xmlDOMWrapNsMapFree(xmlNsMapPtr nsmap)
7275{
7276 xmlNsMapItemPtr cur, tmp;
7277
7278 if (nsmap == NULL)
7279 return;
7280 cur = nsmap->pool;
7281 while (cur != NULL) {
7282 tmp = cur;
7283 cur = cur->next;
7284 xmlFree(tmp);
7285 }
7286 cur = nsmap->first;
7287 while (cur != NULL) {
7288 tmp = cur;
7289 cur = cur->next;
7290 xmlFree(tmp);
7291 }
7292 xmlFree(nsmap);
7293}
7294
7295/*
7296* xmlDOMWrapNsMapAddItem:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007297* @map: the ns-map
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007298* @oldNs: the old ns-struct
7299* @newNs: the new ns-struct
7300* @depth: depth and ns-kind information
7301*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007302* Adds an ns-mapping item.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007303*/
7304static xmlNsMapItemPtr
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00007305xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007306 xmlNsPtr oldNs, xmlNsPtr newNs, int depth)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007307{
7308 xmlNsMapItemPtr ret;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007309 xmlNsMapPtr map;
7310
7311 if (nsmap == NULL)
7312 return(NULL);
7313 if ((position != -1) && (position != 0))
7314 return(NULL);
7315 map = *nsmap;
7316
7317 if (map == NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007318 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007319 * Create the ns-map.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007320 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007321 map = (xmlNsMapPtr) xmlMalloc(sizeof(struct xmlNsMap));
7322 if (map == NULL) {
7323 xmlTreeErrMemory("allocating namespace map");
7324 return (NULL);
7325 }
7326 memset(map, 0, sizeof(struct xmlNsMap));
7327 *nsmap = map;
7328 }
7329
7330 if (map->pool != NULL) {
7331 /*
7332 * Reuse an item from the pool.
7333 */
7334 ret = map->pool;
7335 map->pool = ret->next;
7336 memset(ret, 0, sizeof(struct xmlNsMapItem));
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007337 } else {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007338 /*
7339 * Create a new item.
7340 */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007341 ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem));
7342 if (ret == NULL) {
7343 xmlTreeErrMemory("allocating namespace map item");
7344 return (NULL);
7345 }
7346 memset(ret, 0, sizeof(struct xmlNsMapItem));
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007347 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007348
7349 if (map->first == NULL) {
7350 /*
7351 * First ever.
7352 */
7353 map->first = ret;
7354 map->last = ret;
7355 } else if (position == -1) {
7356 /*
7357 * Append.
7358 */
7359 ret->prev = map->last;
7360 map->last->next = ret;
7361 map->last = ret;
7362 } else if (position == 0) {
7363 /*
7364 * Set on first position.
7365 */
7366 map->first->prev = ret;
7367 ret->next = map->first;
7368 map->first = ret;
7369 } else
7370 return(NULL);
7371
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007372 ret->oldNs = oldNs;
7373 ret->newNs = newNs;
7374 ret->shadowDepth = -1;
7375 ret->depth = depth;
7376 return (ret);
7377}
7378
7379/*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007380* xmlDOMWrapStoreNs:
7381* @doc: the doc
7382* @nsName: the namespace name
7383* @prefix: the prefix
7384*
7385* Creates or reuses an xmlNs struct on doc->oldNs with
7386* the given prefix and namespace name.
7387*
7388* Returns the aquired ns struct or NULL in case of an API
7389* or internal error.
7390*/
7391static xmlNsPtr
7392xmlDOMWrapStoreNs(xmlDocPtr doc,
7393 const xmlChar *nsName,
7394 const xmlChar *prefix)
7395{
7396 xmlNsPtr ns;
7397
7398 if (doc == NULL)
7399 return (NULL);
7400 ns = xmlTreeEnsureXMLDecl(doc);
7401 if (ns == NULL)
7402 return (NULL);
7403 if (ns->next != NULL) {
7404 /* Reuse. */
7405 ns = ns->next;
7406 while (ns != NULL) {
7407 if (((ns->prefix == prefix) ||
7408 xmlStrEqual(ns->prefix, prefix)) &&
7409 xmlStrEqual(ns->href, nsName)) {
7410 return (ns);
7411 }
7412 if (ns->next == NULL)
7413 break;
7414 ns = ns->next;
7415 }
7416 }
7417 /* Create. */
7418 ns->next = xmlNewNs(NULL, nsName, prefix);
7419 return (ns->next);
7420}
7421
7422/*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00007423* xmlDOMWrapNewCtxt:
7424*
7425* Allocates and initializes a new DOM-wrapper context.
7426*
7427* Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal errror.
7428*/
7429xmlDOMWrapCtxtPtr
7430xmlDOMWrapNewCtxt(void)
7431{
7432 xmlDOMWrapCtxtPtr ret;
7433
7434 ret = xmlMalloc(sizeof(xmlDOMWrapCtxt));
7435 if (ret == NULL) {
7436 xmlTreeErrMemory("allocating DOM-wrapper context");
7437 return (NULL);
7438 }
7439 memset(ret, 0, sizeof(xmlDOMWrapCtxt));
7440 return (ret);
7441}
7442
7443/*
7444* xmlDOMWrapFreeCtxt:
7445* @ctxt: the DOM-wrapper context
7446*
7447* Frees the DOM-wrapper context.
7448*/
7449void
7450xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt)
7451{
7452 if (ctxt == NULL)
7453 return;
7454 if (ctxt->namespaceMap != NULL)
7455 xmlDOMWrapNsMapFree((xmlNsMapPtr) ctxt->namespaceMap);
7456 /*
7457 * TODO: Store the namespace map in the context.
7458 */
7459 xmlFree(ctxt);
7460}
7461
7462/*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007463* xmlTreeLookupNsListByPrefix:
7464* @nsList: a list of ns-structs
7465* @prefix: the searched prefix
7466*
7467* Searches for a ns-decl with the given prefix in @nsList.
7468*
7469* Returns the ns-decl if found, NULL if not found and on
7470* API errors.
7471*/
7472static xmlNsPtr
7473xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix)
7474{
7475 if (nsList == NULL)
7476 return (NULL);
7477 {
7478 xmlNsPtr ns;
7479 ns = nsList;
7480 do {
7481 if ((prefix == ns->prefix) ||
7482 xmlStrEqual(prefix, ns->prefix)) {
7483 return (ns);
7484 }
7485 ns = ns->next;
7486 } while (ns != NULL);
7487 }
7488 return (NULL);
7489}
7490
7491/*
7492*
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00007493* xmlDOMWrapNSNormGatherInScopeNs:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007494* @map: the namespace map
7495* @node: the node to start with
7496*
7497* Puts in-scope namespaces into the ns-map.
7498*
7499* Returns 0 on success, -1 on API or internal errors.
7500*/
7501static int
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007502xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapPtr *map,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007503 xmlNodePtr node)
7504{
7505 xmlNodePtr cur;
7506 xmlNsPtr ns;
7507 xmlNsMapItemPtr mi;
7508 int shadowed;
7509
7510 if ((map == NULL) || (*map != NULL))
7511 return (-1);
7512 /*
7513 * Get in-scope ns-decls of @parent.
7514 */
7515 cur = node;
7516 while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) {
7517 if (cur->type == XML_ELEMENT_NODE) {
7518 if (cur->nsDef != NULL) {
7519 ns = cur->nsDef;
7520 do {
7521 shadowed = 0;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007522 if (XML_NSMAP_NOTEMPTY(*map)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007523 /*
7524 * Skip shadowed prefixes.
7525 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007526 XML_NSMAP_FOREACH(*map, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007527 if ((ns->prefix == mi->newNs->prefix) ||
7528 xmlStrEqual(ns->prefix, mi->newNs->prefix)) {
7529 shadowed = 1;
7530 break;
7531 }
7532 }
7533 }
7534 /*
7535 * Insert mapping.
7536 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007537 mi = xmlDOMWrapNsMapAddItem(map, 0, NULL,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007538 ns, XML_TREE_NSMAP_PARENT);
7539 if (mi == NULL)
7540 return (-1);
7541 if (shadowed)
7542 mi->shadowDepth = 0;
7543 ns = ns->next;
7544 } while (ns != NULL);
7545 }
7546 }
7547 cur = cur->parent;
7548 }
7549 return (0);
7550}
7551
7552/*
7553* XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict;
7554* otherwise copy it, when it was in the source-dict.
7555*/
7556#define XML_TREE_ADOPT_STR(str) \
7557 if (adoptStr && (str != NULL)) { \
7558 if (destDoc->dict) { \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00007559 const xmlChar *old = str; \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007560 str = xmlDictLookup(destDoc->dict, str, -1); \
Daniel Veillard7e21fd12005-07-03 21:44:07 +00007561 if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \
7562 (!xmlDictOwns(sourceDoc->dict, old))) \
Daniel Veillard39e5c892005-07-03 22:48:50 +00007563 xmlFree((char *)old); \
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007564 } else if ((sourceDoc) && (sourceDoc->dict) && \
7565 xmlDictOwns(sourceDoc->dict, str)) { \
7566 str = BAD_CAST xmlStrdup(str); \
7567 } \
7568 }
7569
7570/*
7571* XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then
7572* put it in dest-dict or copy it.
7573*/
7574#define XML_TREE_ADOPT_STR_2(str) \
7575 if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \
7576 (sourceDoc->dict != NULL) && \
7577 xmlDictOwns(sourceDoc->dict, cur->content)) { \
7578 if (destDoc->dict) \
7579 cur->content = (xmlChar *) \
7580 xmlDictLookup(destDoc->dict, cur->content, -1); \
7581 else \
7582 cur->content = xmlStrdup(BAD_CAST cur->content); \
7583 }
7584
7585/*
7586* xmlDOMWrapNSNormAddNsMapItem2:
7587*
7588* For internal use. Adds a ns-decl mapping.
7589*
7590* Returns 0 on success, -1 on internal errors.
7591*/
7592static int
7593xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number,
7594 xmlNsPtr oldNs, xmlNsPtr newNs)
7595{
7596 if (*list == NULL) {
7597 *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr));
7598 if (*list == NULL) {
7599 xmlTreeErrMemory("alloc ns map item");
7600 return(-1);
7601 }
7602 *size = 3;
7603 *number = 0;
7604 } else if ((*number) >= (*size)) {
7605 *size *= 2;
7606 *list = (xmlNsPtr *) xmlRealloc(*list,
7607 (*size) * 2 * sizeof(xmlNsPtr));
7608 if (*list == NULL) {
7609 xmlTreeErrMemory("realloc ns map item");
7610 return(-1);
7611 }
7612 }
7613 (*list)[2 * (*number)] = oldNs;
7614 (*list)[2 * (*number) +1] = newNs;
7615 (*number)++;
7616 return (0);
7617}
7618
7619/*
7620* xmlDOMWrapRemoveNode:
Daniel Veillard304e78c2005-07-03 16:19:41 +00007621* @ctxt: a DOM wrapper context
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007622* @doc: the doc
7623* @node: the node to be removed.
Daniel Veillard304e78c2005-07-03 16:19:41 +00007624* @options: set of options, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007625*
7626* Unlinks the given node from its owner.
7627* This will substitute ns-references to node->nsDef for
7628* ns-references to doc->oldNs, thus ensuring the removed
7629* branch to be autark wrt ns-references.
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00007630*
7631* NOTE: This function was not intensively tested.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007632*
7633* Returns 0 on success, 1 if the node is not supported,
7634* -1 on API and internal errors.
7635*/
7636int
7637xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc,
7638 xmlNodePtr node, int options ATTRIBUTE_UNUSED)
7639{
7640 xmlNsPtr *list = NULL;
7641 int sizeList, nbList, i, j;
7642 xmlNsPtr ns;
7643
7644 if ((node == NULL) || (doc == NULL) || (node->doc != doc))
7645 return (-1);
7646
7647 /* TODO: 0 or -1 ? */
7648 if (node->parent == NULL)
7649 return (0);
7650
7651 switch (node->type) {
7652 case XML_TEXT_NODE:
7653 case XML_CDATA_SECTION_NODE:
7654 case XML_ENTITY_REF_NODE:
7655 case XML_PI_NODE:
7656 case XML_COMMENT_NODE:
7657 xmlUnlinkNode(node);
7658 return (0);
7659 case XML_ELEMENT_NODE:
7660 case XML_ATTRIBUTE_NODE:
7661 break;
7662 default:
7663 return (1);
7664 }
7665 xmlUnlinkNode(node);
7666 /*
7667 * Save out-of-scope ns-references in doc->oldNs.
7668 */
7669 do {
7670 switch (node->type) {
7671 case XML_ELEMENT_NODE:
7672 if ((ctxt == NULL) && (node->nsDef != NULL)) {
7673 ns = node->nsDef;
7674 do {
7675 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
7676 &nbList, ns, ns) == -1)
7677 goto internal_error;
7678 ns = ns->next;
7679 } while (ns != NULL);
7680 }
7681 /* No break on purpose. */
7682 case XML_ATTRIBUTE_NODE:
7683 if (node->ns != NULL) {
7684 /*
7685 * Find a mapping.
7686 */
7687 if (list != NULL) {
7688 for (i = 0, j = 0; i < nbList; i++, j += 2) {
7689 if (node->ns == list[j]) {
7690 node->ns = list[++j];
7691 goto next_node;
7692 }
7693 }
7694 }
7695 ns = NULL;
7696 if (ctxt != NULL) {
7697 /*
7698 * User defined.
7699 */
7700 } else {
7701 /*
7702 * Add to doc's oldNs.
7703 */
7704 ns = xmlDOMWrapStoreNs(doc, node->ns->href,
7705 node->ns->prefix);
7706 if (ns == NULL)
7707 goto internal_error;
7708 }
7709 if (ns != NULL) {
7710 /*
7711 * Add mapping.
7712 */
7713 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
7714 &nbList, node->ns, ns) == -1)
7715 goto internal_error;
7716 }
7717 node->ns = ns;
7718 }
7719 if ((node->type == XML_ELEMENT_NODE) &&
7720 (node->properties != NULL)) {
7721 node = (xmlNodePtr) node->properties;
7722 continue;
7723 }
7724 break;
7725 default:
7726 goto next_sibling;
7727 }
7728next_node:
7729 if ((node->type == XML_ELEMENT_NODE) &&
7730 (node->children != NULL)) {
7731 node = node->children;
7732 continue;
7733 }
7734next_sibling:
7735 if (node == NULL)
7736 break;
7737 if (node->next != NULL)
7738 node = node->next;
7739 else {
7740 node = node->parent;
7741 goto next_sibling;
7742 }
7743 } while (node != NULL);
7744
7745 if (list != NULL)
7746 xmlFree(list);
7747 return (0);
7748
7749internal_error:
7750 if (list != NULL)
7751 xmlFree(list);
7752 return (-1);
7753}
7754
7755/*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007756* xmlSearchNsByNamespaceStrict:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007757* @doc: the document
7758* @node: the start node
7759* @nsName: the searched namespace name
7760* @retNs: the resulting ns-decl
7761* @prefixed: if the found ns-decl must have a prefix (for attributes)
7762*
7763* Dynamically searches for a ns-declaration which matches
7764* the given @nsName in the ancestor-or-self axis of @node.
7765*
7766* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7767* and internal errors.
7768*/
7769static int
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007770xmlSearchNsByNamespaceStrict(xmlDocPtr doc, xmlNodePtr node,
7771 const xmlChar* nsName,
7772 xmlNsPtr *retNs, int prefixed)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007773{
7774 xmlNodePtr cur, prev = NULL, out = NULL;
7775 xmlNsPtr ns, prevns;
7776
7777 if ((doc == NULL) || (nsName == NULL) || (retNs == NULL))
7778 return (-1);
7779
7780 *retNs = NULL;
7781 if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
7782 *retNs = xmlTreeEnsureXMLDecl(doc);
7783 if (*retNs == NULL)
7784 return (-1);
7785 return (1);
7786 }
7787 cur = node;
7788 do {
7789 if (cur->type == XML_ELEMENT_NODE) {
7790 if (cur->nsDef != NULL) {
7791 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
7792 if (prefixed && (ns->prefix == NULL))
7793 continue;
7794 if (prev != NULL) {
7795 /*
7796 * Check the last level of ns-decls for a
7797 * shadowing prefix.
7798 */
7799 prevns = prev->nsDef;
7800 do {
7801 if ((prevns->prefix == ns->prefix) ||
7802 ((prevns->prefix != NULL) &&
7803 (ns->prefix != NULL) &&
7804 xmlStrEqual(prevns->prefix, ns->prefix))) {
7805 /*
7806 * Shadowed.
7807 */
7808 break;
7809 }
7810 prevns = prevns->next;
7811 } while (prevns != NULL);
7812 if (prevns != NULL)
7813 continue;
7814 }
7815 /*
7816 * Ns-name comparison.
7817 */
7818 if ((nsName == ns->href) ||
7819 xmlStrEqual(nsName, ns->href)) {
7820 /*
7821 * At this point the prefix can only be shadowed,
7822 * if we are the the (at least) 3rd level of
7823 * ns-decls.
7824 */
7825 if (out) {
7826 int ret;
7827
7828 ret = xmlNsInScope(doc, node, prev, ns->prefix);
7829 if (ret < 0)
7830 return (-1);
7831 /*
7832 * TODO: Should we try to find a matching ns-name
7833 * only once? This here keeps on searching.
7834 * I think we should try further since, there might
7835 * be an other matching ns-decl with an unshadowed
7836 * prefix.
7837 */
7838 if (! ret)
7839 continue;
7840 }
7841 *retNs = ns;
7842 return (1);
7843 }
7844 }
7845 out = prev;
7846 prev = cur;
7847 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007848 } else if ((cur->type == XML_ENTITY_NODE) ||
7849 (cur->type == XML_ENTITY_DECL))
7850 return (0);
7851 cur = cur->parent;
7852 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
7853 return (0);
7854}
7855
7856/*
7857* xmlSearchNsByPrefixStrict:
7858* @doc: the document
7859* @node: the start node
7860* @prefix: the searched namespace prefix
7861* @retNs: the resulting ns-decl
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007862*
7863* Dynamically searches for a ns-declaration which matches
7864* the given @nsName in the ancestor-or-self axis of @node.
7865*
7866* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7867* and internal errors.
7868*/
7869static int
7870xmlSearchNsByPrefixStrict(xmlDocPtr doc, xmlNodePtr node,
7871 const xmlChar* prefix,
7872 xmlNsPtr *retNs)
7873{
7874 xmlNodePtr cur;
7875 xmlNsPtr ns;
7876
7877 if ((doc == NULL) || (node == NULL))
7878 return (-1);
7879
7880 if (retNs)
7881 *retNs = NULL;
7882 if (IS_STR_XML(prefix)) {
7883 if (retNs) {
7884 *retNs = xmlTreeEnsureXMLDecl(doc);
7885 if (*retNs == NULL)
7886 return (-1);
7887 }
7888 return (1);
7889 }
7890 cur = node;
7891 do {
7892 if (cur->type == XML_ELEMENT_NODE) {
7893 if (cur->nsDef != NULL) {
7894 ns = cur->nsDef;
7895 do {
7896 if ((prefix == ns->prefix) ||
7897 xmlStrEqual(prefix, ns->prefix))
7898 {
7899 /*
7900 * Disabled namespaces, e.g. xmlns:abc="".
7901 */
7902 if (ns->href == NULL)
7903 return(0);
7904 if (retNs)
7905 *retNs = ns;
7906 return (1);
7907 }
7908 ns = ns->next;
7909 } while (ns != NULL);
7910 }
7911 } else if ((cur->type == XML_ENTITY_NODE) ||
7912 (cur->type == XML_ENTITY_DECL))
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007913 return (0);
7914 cur = cur->parent;
7915 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
7916 return (0);
7917}
7918
7919/*
7920* xmlDOMWrapNSNormDeclareNsForced:
7921* @doc: the doc
7922* @elem: the element-node to declare on
7923* @nsName: the namespace-name of the ns-decl
7924* @prefix: the preferred prefix of the ns-decl
7925* @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls
7926*
7927* Declares a new namespace on @elem. It tries to use the
7928* given @prefix; if a ns-decl with the given prefix is already existent
7929* on @elem, it will generate an other prefix.
7930*
7931* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7932* and internal errors.
7933*/
7934static xmlNsPtr
7935xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc,
7936 xmlNodePtr elem,
7937 const xmlChar *nsName,
7938 const xmlChar *prefix,
7939 int checkShadow)
7940{
7941
7942 xmlNsPtr ret;
7943 char buf[50];
7944 const xmlChar *pref;
7945 int counter = 0;
7946 /*
7947 * Create a ns-decl on @anchor.
7948 */
7949 pref = prefix;
7950 while (1) {
7951 /*
7952 * Lookup whether the prefix is unused in elem's ns-decls.
7953 */
7954 if ((elem->nsDef != NULL) &&
7955 (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL))
7956 goto ns_next_prefix;
7957 if (checkShadow && elem->parent &&
7958 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
7959 /*
7960 * Does it shadow ancestor ns-decls?
7961 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00007962 if (xmlSearchNsByPrefixStrict(doc, elem->parent, pref, NULL) == 1)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007963 goto ns_next_prefix;
7964 }
7965 ret = xmlNewNs(NULL, nsName, pref);
7966 if (ret == NULL)
7967 return (NULL);
7968 if (elem->nsDef == NULL)
7969 elem->nsDef = ret;
7970 else {
7971 xmlNsPtr ns2 = elem->nsDef;
7972 while (ns2->next != NULL)
7973 ns2 = ns2->next;
7974 ns2->next = ret;
7975 }
7976 return (ret);
7977ns_next_prefix:
7978 counter++;
7979 if (counter > 1000)
7980 return (NULL);
7981 if (prefix == NULL) {
7982 snprintf((char *) buf, sizeof(buf),
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00007983 "ns_%d", counter);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007984 } else
7985 snprintf((char *) buf, sizeof(buf),
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00007986 "%.30s_%d", (char *)prefix, counter);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007987 pref = BAD_CAST buf;
7988 }
7989}
7990
7991/*
7992* xmlDOMWrapNSNormAquireNormalizedNs:
7993* @doc: the doc
7994* @elem: the element-node to declare namespaces on
7995* @ns: the ns-struct to use for the search
7996* @retNs: the found/created ns-struct
7997* @nsMap: the ns-map
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00007998* @depth: the current tree depth
7999* @ancestorsOnly: search in ancestor ns-decls only
8000* @prefixed: if the searched ns-decl must have a prefix (for attributes)
8001*
8002* Searches for a matching ns-name in the ns-decls of @nsMap, if not
8003* found it will either declare it on @elem, or store it in doc->oldNs.
8004* If a new ns-decl needs to be declared on @elem, it tries to use the
8005* @ns->prefix for it, if this prefix is already in use on @elem, it will
8006* change the prefix or the new ns-decl.
8007*
8008* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8009*/
8010static int
8011xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc,
8012 xmlNodePtr elem,
8013 xmlNsPtr ns,
8014 xmlNsPtr *retNs,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008015 xmlNsMapPtr *nsMap,
8016
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008017 int depth,
8018 int ancestorsOnly,
8019 int prefixed)
8020{
8021 xmlNsMapItemPtr mi;
8022
8023 if ((doc == NULL) || (ns == NULL) || (retNs == NULL) ||
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008024 (nsMap == NULL))
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008025 return (-1);
8026
8027 *retNs = NULL;
8028 /*
8029 * Handle XML namespace.
8030 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008031 if (IS_STR_XML(ns->prefix)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008032 /*
8033 * Insert XML namespace mapping.
8034 */
8035 *retNs = xmlTreeEnsureXMLDecl(doc);
8036 if (*retNs == NULL)
8037 return (-1);
8038 return (0);
8039 }
8040 /*
8041 * If the search should be done in ancestors only and no
8042 * @elem (the first ancestor) was specified, then skip the search.
8043 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008044 if ((XML_NSMAP_NOTEMPTY(*nsMap)) &&
8045 (! (ancestorsOnly && (elem == NULL))))
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008046 {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008047 /*
8048 * Try to find an equal ns-name in in-scope ns-decls.
8049 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008050 XML_NSMAP_FOREACH(*nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008051 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8052 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008053 * ancestorsOnly: This should be turned on to gain speed,
8054 * if one knows that the branch itself was already
8055 * ns-wellformed and no stale references existed.
8056 * I.e. it searches in the ancestor axis only.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008057 */
8058 ((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) &&
8059 /* Skip shadowed prefixes. */
8060 (mi->shadowDepth == -1) &&
8061 /* Skip xmlns="" or xmlns:foo="". */
8062 ((mi->newNs->href != NULL) &&
8063 (mi->newNs->href[0] != 0)) &&
8064 /* Ensure a prefix if wanted. */
8065 ((! prefixed) || (mi->newNs->prefix != NULL)) &&
8066 /* Equal ns name */
8067 ((mi->newNs->href == ns->href) ||
8068 xmlStrEqual(mi->newNs->href, ns->href))) {
8069 /* Set the mapping. */
8070 mi->oldNs = ns;
8071 *retNs = mi->newNs;
8072 return (0);
8073 }
8074 }
8075 }
8076 /*
8077 * No luck, the namespace is out of scope or shadowed.
8078 */
8079 if (elem == NULL) {
8080 xmlNsPtr tmpns;
8081
8082 /*
8083 * Store ns-decls in "oldNs" of the document-node.
8084 */
8085 tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix);
8086 if (tmpns == NULL)
8087 return (-1);
8088 /*
8089 * Insert mapping.
8090 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008091 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008092 tmpns, XML_TREE_NSMAP_DOC) == NULL) {
8093 xmlFreeNs(tmpns);
8094 return (-1);
8095 }
8096 *retNs = tmpns;
8097 } else {
8098 xmlNsPtr tmpns;
8099
8100 tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href,
8101 ns->prefix, 0);
8102 if (tmpns == NULL)
8103 return (-1);
8104
8105 if (*nsMap != NULL) {
8106 /*
8107 * Does it shadow ancestor ns-decls?
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008108 */
8109 XML_NSMAP_FOREACH(*nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008110 if ((mi->depth < depth) &&
8111 (mi->shadowDepth == -1) &&
8112 ((ns->prefix == mi->newNs->prefix) ||
8113 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8114 /*
8115 * Shadows.
8116 */
8117 mi->shadowDepth = depth;
8118 break;
8119 }
8120 }
8121 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008122 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, depth) == NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008123 xmlFreeNs(tmpns);
8124 return (-1);
8125 }
8126 *retNs = tmpns;
8127 }
8128 return (0);
8129}
8130
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008131typedef enum {
8132 XML_DOM_RECONNS_REMOVEREDUND = 1<<0
8133} xmlDOMReconcileNSOptions;
8134
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008135/*
8136* xmlDOMWrapReconcileNamespaces:
Daniel Veillard304e78c2005-07-03 16:19:41 +00008137* @ctxt: DOM wrapper context, unused at the moment
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008138* @elem: the element-node
8139* @options: option flags
8140*
8141* Ensures that ns-references point to ns-decls hold on element-nodes.
8142* Ensures that the tree is namespace wellformed by creating additional
8143* ns-decls where needed. Note that, since prefixes of already existent
8144* ns-decls can be shadowed by this process, it could break QNames in
8145* attribute values or element content.
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008146*
8147* NOTE: This function was not intensively tested.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008148*
8149* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008150*/
8151
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008152int
8153xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,
8154 xmlNodePtr elem,
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008155 int options)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008156{
8157 int depth = -1, adoptns = 0, parnsdone = 0;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008158 xmlNsPtr ns, prevns;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008159 xmlDocPtr doc;
8160 xmlNodePtr cur, curElem = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008161 xmlNsMapPtr nsMap = NULL;
8162 xmlNsMapItemPtr /* topmi = NULL, */ mi;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008163 /* @ancestorsOnly should be set by an option flag. */
8164 int ancestorsOnly = 0;
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008165 int optRemoveRedundantNS =
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008166 ((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0;
8167 xmlNsPtr *listRedund = NULL;
8168 int sizeRedund = 0, nbRedund = 0, ret, i, j;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008169
8170 if ((elem == NULL) || (elem->doc == NULL) ||
8171 (elem->type != XML_ELEMENT_NODE))
8172 return (-1);
8173
8174 doc = elem->doc;
8175 cur = elem;
8176 do {
8177 switch (cur->type) {
8178 case XML_ELEMENT_NODE:
8179 adoptns = 1;
8180 curElem = cur;
8181 depth++;
8182 /*
8183 * Namespace declarations.
8184 */
8185 if (cur->nsDef != NULL) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008186 prevns = NULL;
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008187 ns = cur->nsDef;
8188 while (ns != NULL) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008189 if (! parnsdone) {
8190 if ((elem->parent) &&
8191 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8192 /*
8193 * Gather ancestor in-scope ns-decls.
8194 */
8195 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8196 elem->parent) == -1)
8197 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008198 }
8199 parnsdone = 1;
8200 }
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008201
8202 /*
8203 * Lookup the ns ancestor-axis for equal ns-decls in scope.
8204 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008205 if (optRemoveRedundantNS && XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008206 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008207 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8208 (mi->shadowDepth == -1) &&
8209 ((ns->prefix == mi->newNs->prefix) ||
8210 xmlStrEqual(ns->prefix, mi->newNs->prefix)) &&
8211 ((ns->href == mi->newNs->href) ||
8212 xmlStrEqual(ns->href, mi->newNs->href)))
8213 {
8214 /*
8215 * A redundant ns-decl was found.
8216 * Add it to the list of redundant ns-decls.
8217 */
8218 if (xmlDOMWrapNSNormAddNsMapItem2(&listRedund,
8219 &sizeRedund, &nbRedund, ns, mi->newNs) == -1)
8220 goto internal_error;
8221 /*
8222 * Remove the ns-decl from the element-node.
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008223 */
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008224 if (prevns)
8225 prevns->next = ns->next;
8226 else
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008227 cur->nsDef = ns->next;
8228 goto next_ns_decl;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008229 }
8230 }
8231 }
8232
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008233 /*
8234 * Skip ns-references handling if the referenced
8235 * ns-decl is declared on the same element.
8236 */
8237 if ((cur->ns != NULL) && adoptns && (cur->ns == ns))
8238 adoptns = 0;
8239 /*
8240 * Does it shadow any ns-decl?
8241 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008242 if (XML_NSMAP_NOTEMPTY(nsMap)) {
8243 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008244 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8245 (mi->shadowDepth == -1) &&
8246 ((ns->prefix == mi->newNs->prefix) ||
8247 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8248
8249 mi->shadowDepth = depth;
8250 }
8251 }
8252 }
8253 /*
8254 * Push mapping.
8255 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008256 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008257 depth) == NULL)
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008258 goto internal_error;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008259
8260 prevns = ns;
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008261next_ns_decl:
8262 ns = ns->next;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008263 }
8264 }
8265 if (! adoptns)
8266 goto ns_end;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008267 /* No break on purpose. */
8268 case XML_ATTRIBUTE_NODE:
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008269 /* No ns, no fun. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008270 if (cur->ns == NULL)
8271 goto ns_end;
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008272
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008273 if (! parnsdone) {
8274 if ((elem->parent) &&
8275 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8276 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8277 elem->parent) == -1)
8278 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008279 }
8280 parnsdone = 1;
8281 }
8282 /*
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008283 * Adjust the reference if this was a redundant ns-decl.
8284 */
8285 if (listRedund) {
8286 for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8287 if (cur->ns == listRedund[j]) {
8288 cur->ns = listRedund[++j];
8289 break;
8290 }
8291 }
8292 }
8293 /*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008294 * Adopt ns-references.
8295 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008296 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008297 /*
8298 * Search for a mapping.
8299 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008300 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008301 if ((mi->shadowDepth == -1) &&
8302 (cur->ns == mi->oldNs)) {
8303
8304 cur->ns = mi->newNs;
8305 goto ns_end;
8306 }
8307 }
8308 }
8309 /*
8310 * Aquire a normalized ns-decl and add it to the map.
8311 */
8312 if (xmlDOMWrapNSNormAquireNormalizedNs(doc, curElem,
8313 cur->ns, &ns,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008314 &nsMap, depth,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008315 ancestorsOnly,
8316 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8317 goto internal_error;
8318 cur->ns = ns;
8319
8320ns_end:
8321 if ((cur->type == XML_ELEMENT_NODE) &&
8322 (cur->properties != NULL)) {
8323 /*
8324 * Process attributes.
8325 */
8326 cur = (xmlNodePtr) cur->properties;
8327 continue;
8328 }
8329 break;
8330 default:
8331 goto next_sibling;
8332 }
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008333into_content:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008334 if ((cur->type == XML_ELEMENT_NODE) &&
8335 (cur->children != NULL)) {
8336 /*
8337 * Process content of element-nodes only.
8338 */
8339 cur = cur->children;
8340 continue;
8341 }
8342next_sibling:
8343 if (cur == elem)
8344 break;
8345 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008346 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008347 /*
8348 * Pop mappings.
8349 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008350 while ((nsMap->last != NULL) &&
8351 (nsMap->last->depth >= depth))
8352 {
8353 XML_NSMAP_POP(nsMap, mi)
8354 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008355 /*
8356 * Unshadow.
8357 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008358 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008359 if (mi->shadowDepth >= depth)
8360 mi->shadowDepth = -1;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008361 }
8362 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008363 depth--;
8364 }
8365 if (cur->next != NULL)
8366 cur = cur->next;
8367 else {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008368 if (cur->type == XML_ATTRIBUTE_NODE) {
8369 cur = cur->parent;
8370 goto into_content;
8371 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008372 cur = cur->parent;
8373 goto next_sibling;
8374 }
8375 } while (cur != NULL);
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008376
8377 ret = 0;
8378 goto exit;
8379internal_error:
8380 ret = -1;
8381exit:
Kasimier T. Buchcike8f8d752006-02-02 12:13:07 +00008382 if (listRedund) {
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008383 for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8384 xmlFreeNs(listRedund[j]);
8385 }
8386 xmlFree(listRedund);
8387 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008388 if (nsMap != NULL)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008389 xmlDOMWrapNsMapFree(nsMap);
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008390 return (ret);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008391}
8392
8393/*
8394* xmlDOMWrapAdoptBranch:
8395* @ctxt: the optional context for custom processing
8396* @sourceDoc: the optional sourceDoc
8397* @node: the element-node to start with
8398* @destDoc: the destination doc for adoption
Kasimier T. Buchcike01b2fd2006-02-01 16:36:13 +00008399* @destParent: the optional new parent of @node in @destDoc
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008400* @options: option flags
8401*
8402* Ensures that ns-references point to @destDoc: either to
8403* elements->nsDef entries if @destParent is given, or to
8404* @destDoc->oldNs otherwise.
8405* If @destParent is given, it ensures that the tree is namespace
8406* wellformed by creating additional ns-decls where needed.
8407* Note that, since prefixes of already existent ns-decls can be
8408* shadowed by this process, it could break QNames in attribute
8409* values or element content.
8410*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008411* NOTE: This function was not intensively tested.
8412*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008413* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8414*/
8415static int
8416xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
8417 xmlDocPtr sourceDoc,
8418 xmlNodePtr node,
8419 xmlDocPtr destDoc,
8420 xmlNodePtr destParent,
8421 int options ATTRIBUTE_UNUSED)
8422{
8423 int ret = 0;
8424 xmlNodePtr cur, curElem = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008425 xmlNsMapPtr nsMap = NULL;
8426 xmlNsMapItemPtr mi;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008427 xmlNsPtr ns = NULL;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008428 int depth = -1, adoptStr = 1;
8429 /* gather @parent's ns-decls. */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008430 int parnsdone;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008431 /* @ancestorsOnly should be set per option. */
8432 int ancestorsOnly = 0;
8433
8434 /*
8435 * Optimize string adoption for equal or none dicts.
8436 */
8437 if ((sourceDoc != NULL) &&
8438 (sourceDoc->dict == destDoc->dict))
8439 adoptStr = 0;
8440 else
8441 adoptStr = 1;
8442
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008443 /*
8444 * Get the ns-map from the context if available.
8445 */
8446 if (ctxt)
8447 nsMap = (xmlNsMapPtr) ctxt->namespaceMap;
8448 /*
8449 * Disable search for ns-decls in the parent-axis of the
8450 * desination element, if:
8451 * 1) there's no destination parent
8452 * 2) custom ns-reference handling is used
8453 */
8454 if ((destParent == NULL) ||
8455 (ctxt && ctxt->getNsForNodeFunc))
8456 {
8457 parnsdone = 1;
8458 } else
8459 parnsdone = 0;
8460
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008461 cur = node;
8462 while (cur != NULL) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008463 /*
8464 * Paranoid source-doc sanity check.
8465 */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008466 if (cur->doc != sourceDoc) {
8467 /*
8468 * We'll assume XIncluded nodes if the doc differs.
8469 * TODO: Do we need to reconciliate XIncluded nodes?
8470 * This here skips XIncluded nodes and tries to handle
8471 * broken sequences.
8472 */
8473 if (cur->next == NULL)
8474 goto leave_node;
8475 do {
8476 cur = cur->next;
8477 if ((cur->type == XML_XINCLUDE_END) ||
8478 (cur->doc == node->doc))
8479 break;
8480 } while (cur->next != NULL);
8481
8482 if (cur->doc != node->doc)
8483 goto leave_node;
8484 }
8485 cur->doc = destDoc;
8486 switch (cur->type) {
8487 case XML_XINCLUDE_START:
8488 case XML_XINCLUDE_END:
8489 /*
8490 * TODO
8491 */
8492 return (-1);
8493 case XML_ELEMENT_NODE:
8494 curElem = cur;
8495 depth++;
8496 /*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008497 * Namespace declarations.
8498 * - ns->href and ns->prefix are never in the dict, so
8499 * we need not move the values over to the destination dict.
8500 * - Note that for custom handling of ns-references,
8501 * the ns-decls need not be stored in the ns-map,
8502 * since they won't be referenced by node->ns.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008503 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008504 if ((cur->nsDef) &&
8505 ((ctxt == NULL) || (ctxt->getNsForNodeFunc == NULL)))
8506 {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008507 if (! parnsdone) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008508 /*
8509 * Gather @parent's in-scope ns-decls.
8510 */
8511 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8512 destParent) == -1)
8513 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008514 parnsdone = 1;
8515 }
8516 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8517 /*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008518 * NOTE: ns->prefix and ns->href are never in the dict.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008519 * XML_TREE_ADOPT_STR(ns->prefix)
8520 * XML_TREE_ADOPT_STR(ns->href)
8521 */
8522 /*
8523 * Does it shadow any ns-decl?
8524 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008525 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008526 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008527 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8528 (mi->shadowDepth == -1) &&
8529 ((ns->prefix == mi->newNs->prefix) ||
8530 xmlStrEqual(ns->prefix,
8531 mi->newNs->prefix))) {
8532
8533 mi->shadowDepth = depth;
8534 }
8535 }
8536 }
8537 /*
8538 * Push mapping.
8539 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008540 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008541 ns, ns, depth) == NULL)
8542 goto internal_error;
8543 }
8544 }
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008545 /* No break on purpose. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008546 case XML_ATTRIBUTE_NODE:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008547 /* No namespace, no fun. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008548 if (cur->ns == NULL)
8549 goto ns_end;
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008550
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008551 if (! parnsdone) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008552 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8553 destParent) == -1)
8554 goto internal_error;
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008555 parnsdone = 1;
8556 }
8557 /*
8558 * Adopt ns-references.
8559 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008560 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008561 /*
8562 * Search for a mapping.
8563 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008564 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008565 if ((mi->shadowDepth == -1) &&
8566 (cur->ns == mi->oldNs)) {
8567
8568 cur->ns = mi->newNs;
8569 goto ns_end;
8570 }
8571 }
8572 }
8573 /*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008574 * No matching namespace in scope. We need a new one.
8575 */
8576 if ((ctxt) && (ctxt->getNsForNodeFunc)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008577 /*
8578 * User-defined behaviour.
8579 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008580 ns = ctxt->getNsForNodeFunc(ctxt, cur,
8581 cur->ns->href, cur->ns->prefix);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008582 /*
8583 * Insert mapping if ns is available; it's the users fault
8584 * if not.
8585 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008586 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008587 cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008588 goto internal_error;
8589 cur->ns = ns;
8590 } else {
8591 /*
8592 * Aquire a normalized ns-decl and add it to the map.
8593 */
8594 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
8595 /* ns-decls on curElem or on destDoc->oldNs */
8596 destParent ? curElem : NULL,
8597 cur->ns, &ns,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008598 &nsMap, depth,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008599 ancestorsOnly,
8600 /* ns-decls must be prefixed for attributes. */
8601 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8602 goto internal_error;
8603 cur->ns = ns;
8604 }
8605ns_end:
8606 /*
8607 * Further node properties.
8608 * TODO: Is this all?
8609 */
8610 XML_TREE_ADOPT_STR(cur->name)
8611 if (cur->type == XML_ELEMENT_NODE) {
8612 cur->psvi = NULL;
8613 cur->line = 0;
8614 cur->extra = 0;
8615 /*
8616 * Walk attributes.
8617 */
8618 if (cur->properties != NULL) {
8619 /*
8620 * Process first attribute node.
8621 */
8622 cur = (xmlNodePtr) cur->properties;
8623 continue;
8624 }
8625 } else {
8626 /*
8627 * Attributes.
8628 */
8629 if ((sourceDoc != NULL) &&
8630 (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID))
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008631 {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008632 xmlRemoveID(sourceDoc, (xmlAttrPtr) cur);
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008633 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008634 ((xmlAttrPtr) cur)->atype = 0;
8635 ((xmlAttrPtr) cur)->psvi = NULL;
8636 }
8637 break;
8638 case XML_TEXT_NODE:
8639 case XML_CDATA_SECTION_NODE:
8640 /*
8641 * This puts the content in the dest dict, only if
8642 * it was previously in the source dict.
8643 */
8644 XML_TREE_ADOPT_STR_2(cur->content)
8645 goto leave_node;
8646 case XML_ENTITY_REF_NODE:
8647 /*
8648 * Remove reference to the entitity-node.
8649 */
8650 cur->content = NULL;
8651 cur->children = NULL;
8652 cur->last = NULL;
8653 if ((destDoc->intSubset) || (destDoc->extSubset)) {
8654 xmlEntityPtr ent;
8655 /*
8656 * Assign new entity-node if available.
8657 */
8658 ent = xmlGetDocEntity(destDoc, cur->name);
8659 if (ent != NULL) {
8660 cur->content = ent->content;
8661 cur->children = (xmlNodePtr) ent;
8662 cur->last = (xmlNodePtr) ent;
8663 }
8664 }
8665 goto leave_node;
8666 case XML_PI_NODE:
8667 XML_TREE_ADOPT_STR(cur->name)
8668 XML_TREE_ADOPT_STR_2(cur->content)
8669 break;
8670 case XML_COMMENT_NODE:
8671 break;
8672 default:
8673 goto internal_error;
8674 }
8675 /*
8676 * Walk the tree.
8677 */
8678 if (cur->children != NULL) {
8679 cur = cur->children;
8680 continue;
8681 }
8682
8683leave_node:
8684 if (cur == node)
8685 break;
8686 if ((cur->type == XML_ELEMENT_NODE) ||
8687 (cur->type == XML_XINCLUDE_START) ||
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008688 (cur->type == XML_XINCLUDE_END))
8689 {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008690 /*
8691 * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
8692 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008693 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008694 /*
8695 * Pop mappings.
8696 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008697 while ((nsMap->last != NULL) &&
8698 (nsMap->last->depth >= depth))
8699 {
8700 XML_NSMAP_POP(nsMap, mi)
8701 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008702 /*
8703 * Unshadow.
8704 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008705 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008706 if (mi->shadowDepth >= depth)
8707 mi->shadowDepth = -1;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008708 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008709 }
8710 depth--;
8711 }
8712 if (cur->next != NULL)
8713 cur = cur->next;
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008714 else if ((cur->type == XML_ATTRIBUTE_NODE) &&
8715 (cur->parent->children != NULL))
8716 {
8717 cur = cur->parent->children;
8718 } else {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008719 cur = cur->parent;
8720 goto leave_node;
8721 }
8722 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008723
8724 goto exit;
8725
8726internal_error:
8727 ret = -1;
8728
8729exit:
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008730 /*
8731 * Cleanup.
8732 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008733 if (nsMap != NULL) {
8734 if ((ctxt) && (ctxt->namespaceMap == nsMap)) {
8735 /*
8736 * Just cleanup the map but don't free.
8737 */
8738 if (nsMap->first) {
8739 if (nsMap->pool)
8740 nsMap->last->next = nsMap->pool;
8741 nsMap->pool = nsMap->first;
8742 nsMap->first = NULL;
8743 }
8744 } else
8745 xmlDOMWrapNsMapFree(nsMap);
8746 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008747 return(ret);
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00008748}
8749
8750/*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008751* xmlDOMWrapCloneNode:
8752* @ctxt: the optional context for custom processing
8753* @sourceDoc: the optional sourceDoc
8754* @node: the node to start with
8755* @resNode: the clone of the given @node
8756* @destDoc: the destination doc
8757* @destParent: the optional new parent of @node in @destDoc
Daniel Veillardb2f8f1d2006-04-28 16:30:48 +00008758* @deep: descend into child if set
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008759* @options: option flags
8760*
8761* References of out-of scope ns-decls are remapped to point to @destDoc:
8762* 1) If @destParent is given, then nsDef entries on element-nodes are used
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008763* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used.
8764* This is the case when you don't know already where the cloned branch
8765* will be added to.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008766*
8767* If @destParent is given, it ensures that the tree is namespace
8768* wellformed by creating additional ns-decls where needed.
8769* Note that, since prefixes of already existent ns-decls can be
8770* shadowed by this process, it could break QNames in attribute
8771* values or element content.
8772* TODO:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008773* 1) What to do with XInclude? Currently this returns an error for XInclude.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008774*
8775* Returns 0 if the operation succeeded,
8776* 1 if a node of unsupported (or not yet supported) type was given,
8777* -1 on API/internal errors.
8778*/
8779
8780int
8781xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt,
8782 xmlDocPtr sourceDoc,
8783 xmlNodePtr node,
8784 xmlNodePtr *resNode,
8785 xmlDocPtr destDoc,
8786 xmlNodePtr destParent,
8787 int deep,
8788 int options ATTRIBUTE_UNUSED)
8789{
8790 int ret = 0;
8791 xmlNodePtr cur, curElem = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008792 xmlNsMapPtr nsMap = NULL;
8793 xmlNsMapItemPtr mi;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008794 xmlNsPtr ns;
8795 int depth = -1;
8796 /* int adoptStr = 1; */
8797 /* gather @parent's ns-decls. */
8798 int parnsdone = 0;
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008799 /*
8800 * @ancestorsOnly:
8801 * TODO: @ancestorsOnly should be set per option.
8802 *
8803 */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008804 int ancestorsOnly = 0;
8805 xmlNodePtr resultClone = NULL, clone = NULL, parentClone = NULL, prevClone = NULL;
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008806 xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL;
8807 xmlDictPtr dict; /* The destination dict */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008808
Daniel Veillard11ce4002006-03-10 00:36:23 +00008809 if ((node == NULL) || (resNode == NULL) || (destDoc == NULL))
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008810 return(-1);
8811 /*
8812 * TODO: Initially we support only element-nodes.
8813 */
8814 if (node->type != XML_ELEMENT_NODE)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008815 return(1);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008816 /*
8817 * Check node->doc sanity.
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008818 */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008819 if ((node->doc != NULL) && (sourceDoc != NULL) &&
8820 (node->doc != sourceDoc)) {
8821 /*
8822 * Might be an XIncluded node.
8823 */
8824 return (-1);
8825 }
8826 if (sourceDoc == NULL)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008827 sourceDoc = node->doc;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008828 if (sourceDoc == NULL)
8829 return (-1);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008830
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008831 dict = destDoc->dict;
8832 /*
8833 * Reuse the namespace map of the context.
8834 */
8835 if (ctxt)
8836 nsMap = (xmlNsMapPtr) ctxt->namespaceMap;
8837
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008838 *resNode = NULL;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008839
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008840 cur = node;
8841 while (cur != NULL) {
8842 if (cur->doc != sourceDoc) {
8843 /*
8844 * We'll assume XIncluded nodes if the doc differs.
8845 * TODO: Do we need to reconciliate XIncluded nodes?
8846 * TODO: This here returns -1 in this case.
8847 */
8848 goto internal_error;
8849 }
8850 /*
8851 * Create a new node.
8852 */
8853 switch (cur->type) {
8854 case XML_XINCLUDE_START:
8855 case XML_XINCLUDE_END:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008856 /*
8857 * TODO: What to do with XInclude?
8858 */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008859 goto internal_error;
8860 break;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008861 case XML_ELEMENT_NODE:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008862 case XML_TEXT_NODE:
8863 case XML_CDATA_SECTION_NODE:
8864 case XML_COMMENT_NODE:
8865 case XML_PI_NODE:
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008866 case XML_DOCUMENT_FRAG_NODE:
8867 case XML_ENTITY_REF_NODE:
8868 case XML_ENTITY_NODE:
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008869 /*
8870 * Nodes of xmlNode structure.
8871 */
8872 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
8873 if (clone == NULL) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008874 xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating a node");
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008875 goto internal_error;
8876 }
8877 memset(clone, 0, sizeof(xmlNode));
8878 /*
8879 * Set hierachical links.
8880 */
8881 if (resultClone != NULL) {
8882 clone->parent = parentClone;
8883 if (prevClone) {
8884 prevClone->next = clone;
8885 clone->prev = prevClone;
8886 } else
8887 parentClone->children = clone;
8888 } else
8889 resultClone = clone;
8890
8891 break;
8892 case XML_ATTRIBUTE_NODE:
8893 /*
8894 * Attributes (xmlAttr).
8895 */
8896 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlAttr));
8897 if (clone == NULL) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008898 xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating an attr-node");
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008899 goto internal_error;
8900 }
8901 memset(clone, 0, sizeof(xmlAttr));
8902 /*
8903 * Set hierachical links.
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008904 * TODO: Change this to add to the end of attributes.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008905 */
8906 if (resultClone != NULL) {
8907 clone->parent = parentClone;
8908 if (prevClone) {
8909 prevClone->next = clone;
8910 clone->prev = prevClone;
8911 } else
8912 parentClone->properties = (xmlAttrPtr) clone;
8913 } else
8914 resultClone = clone;
8915 break;
8916 default:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008917 /*
8918 * TODO QUESTION: Any other nodes expected?
8919 */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008920 goto internal_error;
8921 }
8922
8923 clone->type = cur->type;
8924 clone->doc = destDoc;
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008925
8926 /*
8927 * Clone the name of the node if any.
8928 */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008929 if (cur->name == xmlStringText)
8930 clone->name = xmlStringText;
8931 else if (cur->name == xmlStringTextNoenc)
8932 /*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008933 * NOTE: Although xmlStringTextNoenc is never assigned to a node
8934 * in tree.c, it might be set in Libxslt via
8935 * "xsl:disable-output-escaping".
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008936 */
8937 clone->name = xmlStringTextNoenc;
8938 else if (cur->name == xmlStringComment)
8939 clone->name = xmlStringComment;
8940 else if (cur->name != NULL) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008941 DICT_CONST_COPY(cur->name, clone->name);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008942 }
8943
8944 switch (cur->type) {
8945 case XML_XINCLUDE_START:
8946 case XML_XINCLUDE_END:
8947 /*
8948 * TODO
8949 */
8950 return (-1);
8951 case XML_ELEMENT_NODE:
8952 curElem = cur;
8953 depth++;
8954 /*
8955 * Namespace declarations.
8956 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008957 if (cur->nsDef != NULL) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008958 if (! parnsdone) {
8959 if (destParent && (ctxt == NULL)) {
8960 /*
8961 * Gather @parent's in-scope ns-decls.
8962 */
8963 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8964 destParent) == -1)
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00008965 goto internal_error;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008966 }
8967 parnsdone = 1;
8968 }
8969 /*
8970 * Clone namespace declarations.
8971 */
8972 cloneNsDefSlot = &(clone->nsDef);
8973 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8974 /*
8975 * Create a new xmlNs.
8976 */
8977 cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
8978 if (cloneNs == NULL) {
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008979 xmlTreeErrMemory("xmlDOMWrapCloneNode(): "
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00008980 "allocating namespace");
8981 return(-1);
8982 }
8983 memset(cloneNs, 0, sizeof(xmlNs));
8984 cloneNs->type = XML_LOCAL_NAMESPACE;
8985
8986 if (ns->href != NULL)
8987 cloneNs->href = xmlStrdup(ns->href);
8988 if (ns->prefix != NULL)
8989 cloneNs->prefix = xmlStrdup(ns->prefix);
8990
8991 *cloneNsDefSlot = cloneNs;
8992 cloneNsDefSlot = &(cloneNs->next);
8993
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00008994 /*
8995 * Note that for custom handling of ns-references,
8996 * the ns-decls need not be stored in the ns-map,
8997 * since they won't be referenced by node->ns.
8998 */
8999 if ((ctxt == NULL) ||
9000 (ctxt->getNsForNodeFunc == NULL))
9001 {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009002 /*
9003 * Does it shadow any ns-decl?
9004 */
9005 if (XML_NSMAP_NOTEMPTY(nsMap)) {
9006 XML_NSMAP_FOREACH(nsMap, mi) {
9007 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
9008 (mi->shadowDepth == -1) &&
9009 ((ns->prefix == mi->newNs->prefix) ||
9010 xmlStrEqual(ns->prefix,
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009011 mi->newNs->prefix))) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009012 /*
9013 * Mark as shadowed at the current
9014 * depth.
9015 */
9016 mi->shadowDepth = depth;
9017 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009018 }
9019 }
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009020 /*
9021 * Push mapping.
9022 */
9023 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
9024 ns, cloneNs, depth) == NULL)
9025 goto internal_error;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009026 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009027 }
9028 }
9029 /* cur->ns will be processed further down. */
9030 break;
9031 case XML_ATTRIBUTE_NODE:
9032 /* IDs will be processed further down. */
9033 /* cur->ns will be processed further down. */
9034 break;
9035 case XML_TEXT_NODE:
9036 case XML_CDATA_SECTION_NODE:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009037 /*
9038 * Note that this will also cover the values of attributes.
9039 */
9040 DICT_COPY(cur->content, clone->content);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009041 goto leave_node;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009042 case XML_ENTITY_NODE:
9043 /* TODO: What to do here? */
9044 goto leave_node;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009045 case XML_ENTITY_REF_NODE:
9046 if (sourceDoc != destDoc) {
9047 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9048 xmlEntityPtr ent;
9049 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009050 * Different doc: Assign new entity-node if available.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009051 */
9052 ent = xmlGetDocEntity(destDoc, cur->name);
9053 if (ent != NULL) {
9054 clone->content = ent->content;
9055 clone->children = (xmlNodePtr) ent;
9056 clone->last = (xmlNodePtr) ent;
9057 }
9058 }
9059 } else {
9060 /*
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009061 * Same doc: Use the current node's entity declaration
9062 * and value.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009063 */
9064 clone->content = cur->content;
9065 clone->children = cur->children;
9066 clone->last = cur->last;
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009067 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009068 goto leave_node;
9069 case XML_PI_NODE:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009070 DICT_COPY(cur->content, clone->content);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009071 goto leave_node;
9072 case XML_COMMENT_NODE:
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009073 DICT_COPY(cur->content, clone->content);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009074 goto leave_node;
9075 default:
9076 goto internal_error;
9077 }
9078
9079 if (cur->ns == NULL)
9080 goto end_ns_reference;
9081
9082/* handle_ns_reference: */
9083 /*
9084 ** The following will take care of references to ns-decls ********
9085 ** and is intended only for element- and attribute-nodes.
9086 **
9087 */
9088 if (! parnsdone) {
9089 if (destParent && (ctxt == NULL)) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009090 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1)
9091 goto internal_error;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009092 }
9093 parnsdone = 1;
9094 }
9095 /*
9096 * Adopt ns-references.
9097 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009098 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009099 /*
9100 * Search for a mapping.
9101 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009102 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009103 if ((mi->shadowDepth == -1) &&
9104 (cur->ns == mi->oldNs)) {
9105 /*
9106 * This is the nice case: a mapping was found.
9107 */
9108 clone->ns = mi->newNs;
9109 goto end_ns_reference;
9110 }
9111 }
9112 }
9113 /*
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009114 * No matching namespace in scope. We need a new one.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009115 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009116 if ((ctxt != NULL) && (ctxt->getNsForNodeFunc != NULL)) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009117 /*
9118 * User-defined behaviour.
9119 */
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009120 ns = ctxt->getNsForNodeFunc(ctxt, cur,
9121 cur->ns->href, cur->ns->prefix);
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009122 /*
9123 * Add user's mapping.
9124 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009125 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009126 cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
9127 goto internal_error;
9128 clone->ns = ns;
9129 } else {
9130 /*
9131 * Aquire a normalized ns-decl and add it to the map.
9132 */
9133 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
9134 /* ns-decls on curElem or on destDoc->oldNs */
9135 destParent ? curElem : NULL,
9136 cur->ns, &ns,
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009137 &nsMap, depth,
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009138 /* if we need to search only in the ancestor-axis */
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009139 ancestorsOnly,
9140 /* ns-decls must be prefixed for attributes. */
9141 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
9142 goto internal_error;
9143 clone->ns = ns;
9144 }
9145
9146end_ns_reference:
9147
9148 /*
9149 * Some post-processing.
9150 *
9151 * Handle ID attributes.
9152 */
9153 if ((clone->type == XML_ATTRIBUTE_NODE) &&
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009154 (clone->parent != NULL))
9155 {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009156 if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) {
9157
9158 xmlChar *idVal;
9159
9160 idVal = xmlNodeListGetString(cur->doc, cur->children, 1);
9161 if (idVal != NULL) {
9162 if (xmlAddID(NULL, destDoc, idVal, (xmlAttrPtr) cur) == NULL) {
9163 /* TODO: error message. */
9164 xmlFree(idVal);
9165 goto internal_error;
9166 }
9167 xmlFree(idVal);
9168 }
9169 }
9170 }
9171 /*
9172 **
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009173 ** The following will traverse the tree **************************
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009174 **
9175 *
9176 * Walk the element's attributes before descending into child-nodes.
9177 */
9178 if ((cur->type == XML_ELEMENT_NODE) && (cur->properties != NULL)) {
9179 prevClone = NULL;
9180 parentClone = clone;
9181 cur = (xmlNodePtr) cur->properties;
9182 continue;
9183 }
9184into_content:
9185 /*
9186 * Descend into child-nodes.
9187 */
9188 if (cur->children != NULL) {
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009189 if (deep || (cur->type == XML_ATTRIBUTE_NODE)) {
9190 prevClone = NULL;
9191 parentClone = clone;
9192 cur = cur->children;
9193 continue;
9194 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009195 }
9196
9197leave_node:
9198 /*
9199 * At this point we are done with the node, its content
9200 * and an element-nodes's attribute-nodes.
9201 */
9202 if (cur == node)
9203 break;
9204 if ((cur->type == XML_ELEMENT_NODE) ||
9205 (cur->type == XML_XINCLUDE_START) ||
9206 (cur->type == XML_XINCLUDE_END)) {
9207 /*
9208 * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
9209 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009210 if (XML_NSMAP_NOTEMPTY(nsMap)) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009211 /*
9212 * Pop mappings.
9213 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009214 while ((nsMap->last != NULL) &&
9215 (nsMap->last->depth >= depth))
9216 {
9217 XML_NSMAP_POP(nsMap, mi)
9218 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009219 /*
9220 * Unshadow.
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009221 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009222 XML_NSMAP_FOREACH(nsMap, mi) {
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009223 if (mi->shadowDepth >= depth)
9224 mi->shadowDepth = -1;
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009225 }
9226 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009227 depth--;
9228 }
9229 if (cur->next != NULL) {
9230 prevClone = clone;
9231 cur = cur->next;
9232 } else if (cur->type != XML_ATTRIBUTE_NODE) {
9233 /*
9234 * Set clone->last.
9235 */
Daniel Veillard11ce4002006-03-10 00:36:23 +00009236 if (clone->parent != NULL)
9237 clone->parent->last = clone;
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009238 clone = clone->parent;
9239 parentClone = clone->parent;
9240 /*
9241 * Process parent --> next;
9242 */
9243 cur = cur->parent;
9244 goto leave_node;
9245 } else {
9246 /* This is for attributes only. */
9247 clone = clone->parent;
9248 parentClone = clone->parent;
9249 /*
9250 * Process parent-element --> children.
9251 */
9252 cur = cur->parent;
9253 goto into_content;
9254 }
9255 }
9256 goto exit;
9257
9258internal_error:
9259 ret = -1;
9260
9261exit:
9262 /*
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 }
9276 } else
9277 xmlDOMWrapNsMapFree(nsMap);
9278 }
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009279 /*
9280 * TODO: Should we try a cleanup of the cloned node in case of a
9281 * fatal error?
9282 */
9283 *resNode = resultClone;
9284 return (ret);
9285}
9286
9287/*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009288* xmlDOMWrapAdoptAttr:
9289* @ctxt: the optional context for custom processing
9290* @sourceDoc: the optional source document of attr
9291* @attr: the attribute-node to be adopted
9292* @destDoc: the destination doc for adoption
9293* @destParent: the optional new parent of @attr in @destDoc
9294* @options: option flags
9295*
9296* @attr is adopted by @destDoc.
9297* Ensures that ns-references point to @destDoc: either to
9298* elements->nsDef entries if @destParent is given, or to
9299* @destDoc->oldNs otherwise.
9300*
9301* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
9302*/
9303static int
9304xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt,
9305 xmlDocPtr sourceDoc,
9306 xmlAttrPtr attr,
9307 xmlDocPtr destDoc,
9308 xmlNodePtr destParent,
9309 int options ATTRIBUTE_UNUSED)
9310{
9311 xmlNodePtr cur;
9312 int adoptStr = 1;
9313
9314 if ((attr == NULL) || (destDoc == NULL))
9315 return (-1);
9316
9317 attr->doc = destDoc;
9318 if (attr->ns != NULL) {
9319 xmlNsPtr ns = NULL;
9320
9321 if (ctxt != NULL) {
9322 /* TODO: User defined. */
9323 }
9324 /* XML Namespace. */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009325 if (IS_STR_XML(attr->ns->prefix)) {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009326 ns = xmlTreeEnsureXMLDecl(destDoc);
9327 } else if (destParent == NULL) {
9328 /*
9329 * Store in @destDoc->oldNs.
9330 */
9331 ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix);
9332 } else {
9333 /*
9334 * Declare on @destParent.
9335 */
Kasimier T. Buchcik44353412006-03-06 13:26:16 +00009336 if (xmlSearchNsByNamespaceStrict(destDoc, destParent, attr->ns->href,
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009337 &ns, 1) == -1)
9338 goto internal_error;
9339 if (ns == NULL) {
9340 ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent,
9341 attr->ns->href, attr->ns->prefix, 1);
9342 }
9343 }
9344 if (ns == NULL)
9345 goto internal_error;
9346 attr->ns = ns;
9347 }
9348
9349 XML_TREE_ADOPT_STR(attr->name);
9350 attr->atype = 0;
9351 attr->psvi = NULL;
9352 /*
9353 * Walk content.
9354 */
9355 if (attr->children == NULL)
9356 return (0);
9357 cur = attr->children;
9358 while (cur != NULL) {
9359 cur->doc = destDoc;
9360 switch (cur->type) {
9361 case XML_TEXT_NODE:
9362 case XML_CDATA_SECTION_NODE:
9363 XML_TREE_ADOPT_STR_2(cur->content)
9364 break;
9365 case XML_ENTITY_REF_NODE:
9366 /*
9367 * Remove reference to the entitity-node.
9368 */
9369 cur->content = NULL;
9370 cur->children = NULL;
9371 cur->last = NULL;
9372 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9373 xmlEntityPtr ent;
9374 /*
9375 * Assign new entity-node if available.
9376 */
9377 ent = xmlGetDocEntity(destDoc, cur->name);
9378 if (ent != NULL) {
9379 cur->content = ent->content;
9380 cur->children = (xmlNodePtr) ent;
9381 cur->last = (xmlNodePtr) ent;
9382 }
9383 }
9384 break;
9385 default:
9386 break;
9387 }
9388 if (cur->children != NULL) {
9389 cur = cur->children;
9390 continue;
9391 }
9392next_sibling:
9393 if (cur == (xmlNodePtr) attr)
9394 break;
9395 if (cur->next != NULL)
9396 cur = cur->next;
9397 else {
9398 cur = cur->parent;
9399 goto next_sibling;
9400 }
9401 }
9402 return (0);
9403internal_error:
9404 return (-1);
9405}
9406
9407/*
9408* xmlDOMWrapAdoptNode:
9409* @ctxt: the optional context for custom processing
9410* @sourceDoc: the optional sourceDoc
9411* @node: the node to start with
9412* @destDoc: the destination doc
Kasimier T. Buchcik4d9c9482005-06-27 15:04:46 +00009413* @destParent: the optional new parent of @node in @destDoc
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009414* @options: option flags
9415*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009416* References of out-of scope ns-decls are remapped to point to @destDoc:
9417* 1) If @destParent is given, then nsDef entries on element-nodes are used
9418* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used
9419* This is the case when you have an unliked node and just want to move it
9420* to the context of
9421*
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009422* If @destParent is given, it ensures that the tree is namespace
9423* wellformed by creating additional ns-decls where needed.
9424* Note that, since prefixes of already existent ns-decls can be
9425* shadowed by this process, it could break QNames in attribute
9426* values or element content.
Kasimier T. Buchcik978039b2006-06-16 19:46:26 +00009427* NOTE: This function was not intensively tested.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009428*
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009429* Returns 0 if the operation succeeded,
9430* 1 if a node of unsupported type was given,
9431* 2 if a node of not yet supported type was given and
9432* -1 on API/internal errors.
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009433*/
9434int
9435xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt,
9436 xmlDocPtr sourceDoc,
9437 xmlNodePtr node,
9438 xmlDocPtr destDoc,
9439 xmlNodePtr destParent,
9440 int options)
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009441{
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009442 if ((node == NULL) || (destDoc == NULL) ||
9443 ((destParent != NULL) && (destParent->doc != destDoc)))
9444 return(-1);
9445 /*
9446 * Check node->doc sanity.
9447 */
9448 if ((node->doc != NULL) && (sourceDoc != NULL) &&
9449 (node->doc != sourceDoc)) {
9450 /*
9451 * Might be an XIncluded node.
9452 */
9453 return (-1);
9454 }
9455 if (sourceDoc == NULL)
9456 sourceDoc = node->doc;
9457 if (sourceDoc == destDoc)
9458 return (-1);
9459 switch (node->type) {
9460 case XML_ELEMENT_NODE:
9461 case XML_ATTRIBUTE_NODE:
9462 case XML_TEXT_NODE:
9463 case XML_CDATA_SECTION_NODE:
9464 case XML_ENTITY_REF_NODE:
9465 case XML_PI_NODE:
9466 case XML_COMMENT_NODE:
9467 break;
9468 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikcab801b2006-02-03 16:35:27 +00009469 /* TODO: Support document-fragment-nodes. */
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009470 return (2);
9471 default:
9472 return (1);
9473 }
9474 /*
9475 * Unlink only if @node was not already added to @destParent.
9476 */
9477 if ((node->parent != NULL) && (destParent != node->parent))
9478 xmlUnlinkNode(node);
9479
9480 if (node->type == XML_ELEMENT_NODE) {
9481 return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node,
9482 destDoc, destParent, options));
9483 } else if (node->type == XML_ATTRIBUTE_NODE) {
9484 return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc,
9485 (xmlAttrPtr) node, destDoc, destParent, options));
9486 } else {
9487 xmlNodePtr cur = node;
9488 int adoptStr = 1;
9489
9490 cur->doc = destDoc;
9491 /*
9492 * Optimize string adoption.
9493 */
9494 if ((sourceDoc != NULL) &&
9495 (sourceDoc->dict == destDoc->dict))
9496 adoptStr = 0;
9497 switch (node->type) {
9498 case XML_TEXT_NODE:
9499 case XML_CDATA_SECTION_NODE:
9500 XML_TREE_ADOPT_STR_2(node->content)
9501 break;
9502 case XML_ENTITY_REF_NODE:
9503 /*
9504 * Remove reference to the entitity-node.
9505 */
9506 node->content = NULL;
9507 node->children = NULL;
9508 node->last = NULL;
9509 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9510 xmlEntityPtr ent;
9511 /*
9512 * Assign new entity-node if available.
9513 */
9514 ent = xmlGetDocEntity(destDoc, node->name);
9515 if (ent != NULL) {
9516 node->content = ent->content;
9517 node->children = (xmlNodePtr) ent;
9518 node->last = (xmlNodePtr) ent;
9519 }
9520 }
9521 XML_TREE_ADOPT_STR(node->name)
9522 break;
Daniel Veillard7e21fd12005-07-03 21:44:07 +00009523 case XML_PI_NODE: {
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009524 XML_TREE_ADOPT_STR(node->name)
9525 XML_TREE_ADOPT_STR_2(node->content)
9526 break;
Daniel Veillard7e21fd12005-07-03 21:44:07 +00009527 }
Kasimier T. Buchcikbc0e3c62005-06-27 10:28:23 +00009528 default:
9529 break;
9530 }
9531 }
9532 return (0);
9533}
9534
Daniel Veillard5d4644e2005-04-01 13:11:58 +00009535#define bottom_tree
9536#include "elfgcchack.h"