blob: 87b158ea5744a92dc43aa83e56bbcd9368a7d287 [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
Owen Taylor3473f882001-02-23 17:55:21 +000040
Daniel Veillarda880b122003-04-21 21:36:41 +000041int __xmlRegisterCallbacks = 0;
42
Daniel Veillard56a4cb82001-03-24 17:00:36 +000043xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
44
45/************************************************************************
46 * *
Daniel Veillard18ec16e2003-10-07 23:16:40 +000047 * Tree memory error handler *
48 * *
49 ************************************************************************/
50/**
51 * xmlTreeErrMemory:
52 * @extra: extra informations
53 *
54 * Handle an out of memory condition
55 */
56static void
57xmlTreeErrMemory(const char *extra)
58{
59 __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
60}
61
62/**
63 * xmlTreeErr:
64 * @code: the error number
65 * @extra: extra informations
66 *
67 * Handle an out of memory condition
68 */
69static void
70xmlTreeErr(int code, xmlNodePtr node, const char *extra)
71{
72 const char *msg = NULL;
73
74 switch(code) {
75 case XML_TREE_INVALID_HEX:
Daniel Veillardac996a12004-07-30 12:02:58 +000076 msg = "invalid hexadecimal character value\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000077 break;
78 case XML_TREE_INVALID_DEC:
Daniel Veillardac996a12004-07-30 12:02:58 +000079 msg = "invalid decimal character value\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000080 break;
81 case XML_TREE_UNTERMINATED_ENTITY:
Daniel Veillardac996a12004-07-30 12:02:58 +000082 msg = "unterminated entity reference %15s\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000083 break;
84 default:
Daniel Veillardac996a12004-07-30 12:02:58 +000085 msg = "unexpected error number\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000086 }
87 __xmlSimpleError(XML_FROM_TREE, code, node, msg, extra);
88}
89
90/************************************************************************
91 * *
Daniel Veillard56a4cb82001-03-24 17:00:36 +000092 * A few static variables and macros *
93 * *
94 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000095/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000096const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000097/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000098const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000099 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +0000100/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +0000101const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
102
Owen Taylor3473f882001-02-23 17:55:21 +0000103static int xmlCompressMode = 0;
104static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000105
Owen Taylor3473f882001-02-23 17:55:21 +0000106#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
107 xmlNodePtr ulccur = (n)->children; \
108 if (ulccur == NULL) { \
109 (n)->last = NULL; \
110 } else { \
111 while (ulccur->next != NULL) { \
112 ulccur->parent = (n); \
113 ulccur = ulccur->next; \
114 } \
115 ulccur->parent = (n); \
116 (n)->last = ulccur; \
117}}
118
119/* #define DEBUG_BUFFER */
120/* #define DEBUG_TREE */
121
122/************************************************************************
123 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000124 * Functions to move to entities.c once the *
125 * API freeze is smoothen and they can be made public. *
126 * *
127 ************************************************************************/
128#include <libxml/hash.h>
129
Daniel Veillard652327a2003-09-29 18:02:38 +0000130#ifdef LIBXML_TREE_ENABLED
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000131/**
132 * xmlGetEntityFromDtd:
133 * @dtd: A pointer to the DTD to search
134 * @name: The entity name
135 *
136 * Do an entity lookup in the DTD entity hash table and
137 * return the corresponding entity, if found.
138 *
139 * Returns A pointer to the entity structure or NULL if not found.
140 */
141static xmlEntityPtr
142xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
143 xmlEntitiesTablePtr table;
144
145 if((dtd != NULL) && (dtd->entities != NULL)) {
146 table = (xmlEntitiesTablePtr) dtd->entities;
147 return((xmlEntityPtr) xmlHashLookup(table, name));
148 /* return(xmlGetEntityFromTable(table, name)); */
149 }
150 return(NULL);
151}
152/**
153 * xmlGetParameterEntityFromDtd:
154 * @dtd: A pointer to the DTD to search
155 * @name: The entity name
156 *
157 * Do an entity lookup in the DTD pararmeter entity hash table and
158 * return the corresponding entity, if found.
159 *
160 * Returns A pointer to the entity structure or NULL if not found.
161 */
162static xmlEntityPtr
163xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
164 xmlEntitiesTablePtr table;
165
166 if ((dtd != NULL) && (dtd->pentities != NULL)) {
167 table = (xmlEntitiesTablePtr) dtd->pentities;
168 return((xmlEntityPtr) xmlHashLookup(table, name));
169 /* return(xmlGetEntityFromTable(table, name)); */
170 }
171 return(NULL);
172}
Daniel Veillard652327a2003-09-29 18:02:38 +0000173#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000174
175/************************************************************************
176 * *
Daniel Veillardc00cda82003-04-07 10:22:39 +0000177 * QName handling helper *
178 * *
179 ************************************************************************/
180
181/**
182 * xmlBuildQName:
183 * @ncname: the Name
184 * @prefix: the prefix
185 * @memory: preallocated memory
186 * @len: preallocated memory length
187 *
188 * Builds the QName @prefix:@ncname in @memory if there is enough space
189 * and prefix is not NULL nor empty, otherwise allocate a new string.
190 * If prefix is NULL or empty it returns ncname.
191 *
192 * Returns the new string which must be freed by the caller if different from
193 * @memory and @ncname or NULL in case of error
194 */
195xmlChar *
196xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
197 xmlChar *memory, int len) {
198 int lenn, lenp;
199 xmlChar *ret;
200
Daniel Veillard3b7840c2003-09-11 23:42:01 +0000201 if (ncname == NULL) return(NULL);
202 if (prefix == NULL) return((xmlChar *) ncname);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000203
204 lenn = strlen((char *) ncname);
205 lenp = strlen((char *) prefix);
206
207 if ((memory == NULL) || (len < lenn + lenp + 2)) {
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000208 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000209 if (ret == NULL) {
210 xmlTreeErrMemory("building QName");
211 return(NULL);
212 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000213 } else {
214 ret = memory;
215 }
216 memcpy(&ret[0], prefix, lenp);
217 ret[lenp] = ':';
218 memcpy(&ret[lenp + 1], ncname, lenn);
219 ret[lenn + lenp + 1] = 0;
220 return(ret);
221}
222
223/**
224 * xmlSplitQName2:
225 * @name: the full QName
226 * @prefix: a xmlChar **
227 *
228 * parse an XML qualified name string
229 *
230 * [NS 5] QName ::= (Prefix ':')? LocalPart
231 *
232 * [NS 6] Prefix ::= NCName
233 *
234 * [NS 7] LocalPart ::= NCName
235 *
236 * Returns NULL if not a QName, otherwise the local part, and prefix
237 * is updated to get the Prefix if any.
238 */
239
240xmlChar *
241xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
242 int len = 0;
243 xmlChar *ret = NULL;
244
245 *prefix = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000246 if (name == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000247
248#ifndef XML_XML_NAMESPACE
249 /* xml: prefix is not really a namespace */
250 if ((name[0] == 'x') && (name[1] == 'm') &&
251 (name[2] == 'l') && (name[3] == ':'))
252 return(NULL);
253#endif
254
255 /* nasty but valid */
256 if (name[0] == ':')
257 return(NULL);
258
259 /*
260 * we are not trying to validate but just to cut, and yes it will
261 * work even if this is as set of UTF-8 encoded chars
262 */
263 while ((name[len] != 0) && (name[len] != ':'))
264 len++;
265
266 if (name[len] == 0)
267 return(NULL);
268
269 *prefix = xmlStrndup(name, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000270 if (*prefix == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000271 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000272 return(NULL);
273 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000274 ret = xmlStrdup(&name[len + 1]);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000275 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000276 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000277 if (*prefix != NULL) {
278 xmlFree(*prefix);
279 *prefix = NULL;
280 }
281 return(NULL);
282 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000283
284 return(ret);
285}
286
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000287/**
288 * xmlSplitQName3:
289 * @name: the full QName
290 * @len: an int *
291 *
292 * parse an XML qualified name string,i
293 *
294 * returns NULL if it is not a Qualified Name, otherwise, update len
295 * with the lenght in byte of the prefix and return a pointer
296 */
297
298const xmlChar *
299xmlSplitQName3(const xmlChar *name, int *len) {
300 int l = 0;
301
302 if (name == NULL) return(NULL);
303 if (len == NULL) return(NULL);
304
305 /* nasty but valid */
306 if (name[0] == ':')
307 return(NULL);
308
309 /*
310 * we are not trying to validate but just to cut, and yes it will
311 * work even if this is as set of UTF-8 encoded chars
312 */
313 while ((name[l] != 0) && (name[l] != ':'))
314 l++;
315
316 if (name[l] == 0)
317 return(NULL);
318
319 *len = l;
320
321 return(&name[l+1]);
322}
323
Daniel Veillardc00cda82003-04-07 10:22:39 +0000324/************************************************************************
325 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000326 * Check Name, NCName and QName strings *
327 * *
328 ************************************************************************/
329
330#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
331
Daniel Veillard03a53c32004-10-26 16:06:51 +0000332#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000333/**
334 * xmlValidateNCName:
335 * @value: the value to check
336 * @space: allow spaces in front and end of the string
337 *
338 * Check that a value conforms to the lexical space of NCName
339 *
340 * Returns 0 if this validates, a positive error code number otherwise
341 * and -1 in case of internal or API error.
342 */
343int
344xmlValidateNCName(const xmlChar *value, int space) {
345 const xmlChar *cur = value;
346 int c,l;
347
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000348 if (value == NULL)
349 return(-1);
350
Daniel Veillardd2298792003-02-14 16:54:11 +0000351 /*
352 * First quick algorithm for ASCII range
353 */
354 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000355 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000356 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
357 (*cur == '_'))
358 cur++;
359 else
360 goto try_complex;
361 while (((*cur >= 'a') && (*cur <= 'z')) ||
362 ((*cur >= 'A') && (*cur <= 'Z')) ||
363 ((*cur >= '0') && (*cur <= '9')) ||
364 (*cur == '_') || (*cur == '-') || (*cur == '.'))
365 cur++;
366 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000367 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000368 if (*cur == 0)
369 return(0);
370
371try_complex:
372 /*
373 * Second check for chars outside the ASCII range
374 */
375 cur = value;
376 c = CUR_SCHAR(cur, l);
377 if (space) {
378 while (IS_BLANK(c)) {
379 cur += l;
380 c = CUR_SCHAR(cur, l);
381 }
382 }
William M. Brack871611b2003-10-18 04:53:14 +0000383 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000384 return(1);
385 cur += l;
386 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000387 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
388 (c == '-') || (c == '_') || IS_COMBINING(c) ||
389 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000390 cur += l;
391 c = CUR_SCHAR(cur, l);
392 }
393 if (space) {
394 while (IS_BLANK(c)) {
395 cur += l;
396 c = CUR_SCHAR(cur, l);
397 }
398 }
399 if (c != 0)
400 return(1);
401
402 return(0);
403}
Daniel Veillard2156d432004-03-04 15:59:36 +0000404#endif
Daniel Veillardd2298792003-02-14 16:54:11 +0000405
Daniel Veillard2156d432004-03-04 15:59:36 +0000406#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000407/**
408 * xmlValidateQName:
409 * @value: the value to check
410 * @space: allow spaces in front and end of the string
411 *
412 * Check that a value conforms to the lexical space of QName
413 *
414 * Returns 0 if this validates, a positive error code number otherwise
415 * and -1 in case of internal or API error.
416 */
417int
418xmlValidateQName(const xmlChar *value, int space) {
419 const xmlChar *cur = value;
420 int c,l;
421
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000422 if (value == NULL)
423 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +0000424 /*
425 * First quick algorithm for ASCII range
426 */
427 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000428 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000429 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
430 (*cur == '_'))
431 cur++;
432 else
433 goto try_complex;
434 while (((*cur >= 'a') && (*cur <= 'z')) ||
435 ((*cur >= 'A') && (*cur <= 'Z')) ||
436 ((*cur >= '0') && (*cur <= '9')) ||
437 (*cur == '_') || (*cur == '-') || (*cur == '.'))
438 cur++;
439 if (*cur == ':') {
440 cur++;
441 if (((*cur >= 'a') && (*cur <= 'z')) ||
442 ((*cur >= 'A') && (*cur <= 'Z')) ||
443 (*cur == '_'))
444 cur++;
445 else
446 goto try_complex;
447 while (((*cur >= 'a') && (*cur <= 'z')) ||
448 ((*cur >= 'A') && (*cur <= 'Z')) ||
449 ((*cur >= '0') && (*cur <= '9')) ||
450 (*cur == '_') || (*cur == '-') || (*cur == '.'))
451 cur++;
452 }
453 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000454 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000455 if (*cur == 0)
456 return(0);
457
458try_complex:
459 /*
460 * Second check for chars outside the ASCII range
461 */
462 cur = value;
463 c = CUR_SCHAR(cur, l);
464 if (space) {
465 while (IS_BLANK(c)) {
466 cur += l;
467 c = CUR_SCHAR(cur, l);
468 }
469 }
William M. Brack871611b2003-10-18 04:53:14 +0000470 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000471 return(1);
472 cur += l;
473 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000474 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
475 (c == '-') || (c == '_') || IS_COMBINING(c) ||
476 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000477 cur += l;
478 c = CUR_SCHAR(cur, l);
479 }
480 if (c == ':') {
481 cur += l;
482 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000483 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000484 return(1);
485 cur += l;
486 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000487 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
488 (c == '-') || (c == '_') || IS_COMBINING(c) ||
489 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000490 cur += l;
491 c = CUR_SCHAR(cur, l);
492 }
493 }
494 if (space) {
495 while (IS_BLANK(c)) {
496 cur += l;
497 c = CUR_SCHAR(cur, l);
498 }
499 }
500 if (c != 0)
501 return(1);
502 return(0);
503}
504
505/**
506 * xmlValidateName:
507 * @value: the value to check
508 * @space: allow spaces in front and end of the string
509 *
510 * Check that a value conforms to the lexical space of Name
511 *
512 * Returns 0 if this validates, a positive error code number otherwise
513 * and -1 in case of internal or API error.
514 */
515int
516xmlValidateName(const xmlChar *value, int space) {
517 const xmlChar *cur = value;
518 int c,l;
519
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000520 if (value == NULL)
521 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +0000522 /*
523 * First quick algorithm for ASCII range
524 */
525 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000526 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000527 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
528 (*cur == '_') || (*cur == ':'))
529 cur++;
530 else
531 goto try_complex;
532 while (((*cur >= 'a') && (*cur <= 'z')) ||
533 ((*cur >= 'A') && (*cur <= 'Z')) ||
534 ((*cur >= '0') && (*cur <= '9')) ||
535 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
536 cur++;
537 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000538 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000539 if (*cur == 0)
540 return(0);
541
542try_complex:
543 /*
544 * Second check for chars outside the ASCII range
545 */
546 cur = value;
547 c = CUR_SCHAR(cur, l);
548 if (space) {
549 while (IS_BLANK(c)) {
550 cur += l;
551 c = CUR_SCHAR(cur, l);
552 }
553 }
William M. Brack871611b2003-10-18 04:53:14 +0000554 if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000555 return(1);
556 cur += l;
557 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000558 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
559 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000560 cur += l;
561 c = CUR_SCHAR(cur, l);
562 }
563 if (space) {
564 while (IS_BLANK(c)) {
565 cur += l;
566 c = CUR_SCHAR(cur, l);
567 }
568 }
569 if (c != 0)
570 return(1);
571 return(0);
572}
573
Daniel Veillardd4310742003-02-18 21:12:46 +0000574/**
575 * xmlValidateNMToken:
576 * @value: the value to check
577 * @space: allow spaces in front and end of the string
578 *
579 * Check that a value conforms to the lexical space of NMToken
580 *
581 * Returns 0 if this validates, a positive error code number otherwise
582 * and -1 in case of internal or API error.
583 */
584int
585xmlValidateNMToken(const xmlChar *value, int space) {
586 const xmlChar *cur = value;
587 int c,l;
588
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000589 if (value == NULL)
590 return(-1);
Daniel Veillardd4310742003-02-18 21:12:46 +0000591 /*
592 * First quick algorithm for ASCII range
593 */
594 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000595 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000596 if (((*cur >= 'a') && (*cur <= 'z')) ||
597 ((*cur >= 'A') && (*cur <= 'Z')) ||
598 ((*cur >= '0') && (*cur <= '9')) ||
599 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
600 cur++;
601 else
602 goto try_complex;
603 while (((*cur >= 'a') && (*cur <= 'z')) ||
604 ((*cur >= 'A') && (*cur <= 'Z')) ||
605 ((*cur >= '0') && (*cur <= '9')) ||
606 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
607 cur++;
608 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000609 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000610 if (*cur == 0)
611 return(0);
612
613try_complex:
614 /*
615 * Second check for chars outside the ASCII range
616 */
617 cur = value;
618 c = CUR_SCHAR(cur, l);
619 if (space) {
620 while (IS_BLANK(c)) {
621 cur += l;
622 c = CUR_SCHAR(cur, l);
623 }
624 }
William M. Brack871611b2003-10-18 04:53:14 +0000625 if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
626 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
Daniel Veillardd4310742003-02-18 21:12:46 +0000627 return(1);
628 cur += l;
629 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000630 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
631 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd4310742003-02-18 21:12:46 +0000632 cur += l;
633 c = CUR_SCHAR(cur, l);
634 }
635 if (space) {
636 while (IS_BLANK(c)) {
637 cur += l;
638 c = CUR_SCHAR(cur, l);
639 }
640 }
641 if (c != 0)
642 return(1);
643 return(0);
644}
Daniel Veillard652327a2003-09-29 18:02:38 +0000645#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardd4310742003-02-18 21:12:46 +0000646
Daniel Veillardd2298792003-02-14 16:54:11 +0000647/************************************************************************
648 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000649 * Allocation and deallocation of basic structures *
650 * *
651 ************************************************************************/
652
653/**
654 * xmlSetBufferAllocationScheme:
655 * @scheme: allocation method to use
656 *
657 * Set the buffer allocation method. Types are
658 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
659 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
660 * improves performance
661 */
662void
663xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
664 xmlBufferAllocScheme = scheme;
665}
666
667/**
668 * xmlGetBufferAllocationScheme:
669 *
670 * Types are
671 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
672 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
673 * improves performance
674 *
675 * Returns the current allocation scheme
676 */
677xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000678xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000679 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000680}
681
682/**
683 * xmlNewNs:
684 * @node: the element carrying the namespace
685 * @href: the URI associated
686 * @prefix: the prefix for the namespace
687 *
688 * Creation of a new Namespace. This function will refuse to create
689 * a namespace with a similar prefix than an existing one present on this
690 * node.
691 * We use href==NULL in the case of an element creation where the namespace
692 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000693 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000694 */
695xmlNsPtr
696xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
697 xmlNsPtr cur;
698
699 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
700 return(NULL);
701
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000702 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
703 return(NULL);
704
Owen Taylor3473f882001-02-23 17:55:21 +0000705 /*
706 * Allocate a new Namespace and fill the fields.
707 */
708 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
709 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000710 xmlTreeErrMemory("building namespace");
Owen Taylor3473f882001-02-23 17:55:21 +0000711 return(NULL);
712 }
713 memset(cur, 0, sizeof(xmlNs));
714 cur->type = XML_LOCAL_NAMESPACE;
715
716 if (href != NULL)
717 cur->href = xmlStrdup(href);
718 if (prefix != NULL)
719 cur->prefix = xmlStrdup(prefix);
720
721 /*
722 * Add it at the end to preserve parsing order ...
723 * and checks for existing use of the prefix
724 */
725 if (node != NULL) {
726 if (node->nsDef == NULL) {
727 node->nsDef = cur;
728 } else {
729 xmlNsPtr prev = node->nsDef;
730
731 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
732 (xmlStrEqual(prev->prefix, cur->prefix))) {
733 xmlFreeNs(cur);
734 return(NULL);
735 }
736 while (prev->next != NULL) {
737 prev = prev->next;
738 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
739 (xmlStrEqual(prev->prefix, cur->prefix))) {
740 xmlFreeNs(cur);
741 return(NULL);
742 }
743 }
744 prev->next = cur;
745 }
746 }
747 return(cur);
748}
749
750/**
751 * xmlSetNs:
752 * @node: a node in the document
753 * @ns: a namespace pointer
754 *
755 * Associate a namespace to a node, a posteriori.
756 */
757void
758xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
759 if (node == NULL) {
760#ifdef DEBUG_TREE
761 xmlGenericError(xmlGenericErrorContext,
762 "xmlSetNs: node == NULL\n");
763#endif
764 return;
765 }
766 node->ns = ns;
767}
768
769/**
770 * xmlFreeNs:
771 * @cur: the namespace pointer
772 *
773 * Free up the structures associated to a namespace
774 */
775void
776xmlFreeNs(xmlNsPtr cur) {
777 if (cur == NULL) {
778#ifdef DEBUG_TREE
779 xmlGenericError(xmlGenericErrorContext,
780 "xmlFreeNs : ns == NULL\n");
781#endif
782 return;
783 }
784 if (cur->href != NULL) xmlFree((char *) cur->href);
785 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000786 xmlFree(cur);
787}
788
789/**
790 * xmlFreeNsList:
791 * @cur: the first namespace pointer
792 *
793 * Free up all the structures associated to the chained namespaces.
794 */
795void
796xmlFreeNsList(xmlNsPtr cur) {
797 xmlNsPtr next;
798 if (cur == NULL) {
799#ifdef DEBUG_TREE
800 xmlGenericError(xmlGenericErrorContext,
801 "xmlFreeNsList : ns == NULL\n");
802#endif
803 return;
804 }
805 while (cur != NULL) {
806 next = cur->next;
807 xmlFreeNs(cur);
808 cur = next;
809 }
810}
811
812/**
813 * xmlNewDtd:
814 * @doc: the document pointer
815 * @name: the DTD name
816 * @ExternalID: the external ID
817 * @SystemID: the system ID
818 *
819 * Creation of a new DTD for the external subset. To create an
820 * internal subset, use xmlCreateIntSubset().
821 *
822 * Returns a pointer to the new DTD structure
823 */
824xmlDtdPtr
825xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
826 const xmlChar *ExternalID, const xmlChar *SystemID) {
827 xmlDtdPtr cur;
828
829 if ((doc != NULL) && (doc->extSubset != NULL)) {
830#ifdef DEBUG_TREE
831 xmlGenericError(xmlGenericErrorContext,
832 "xmlNewDtd(%s): document %s already have a DTD %s\n",
833 /* !!! */ (char *) name, doc->name,
834 /* !!! */ (char *)doc->extSubset->name);
835#endif
836 return(NULL);
837 }
838
839 /*
840 * Allocate a new DTD and fill the fields.
841 */
842 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
843 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000844 xmlTreeErrMemory("building DTD");
Owen Taylor3473f882001-02-23 17:55:21 +0000845 return(NULL);
846 }
847 memset(cur, 0 , sizeof(xmlDtd));
848 cur->type = XML_DTD_NODE;
849
850 if (name != NULL)
851 cur->name = xmlStrdup(name);
852 if (ExternalID != NULL)
853 cur->ExternalID = xmlStrdup(ExternalID);
854 if (SystemID != NULL)
855 cur->SystemID = xmlStrdup(SystemID);
856 if (doc != NULL)
857 doc->extSubset = cur;
858 cur->doc = doc;
859
Daniel Veillarda880b122003-04-21 21:36:41 +0000860 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000861 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000862 return(cur);
863}
864
865/**
866 * xmlGetIntSubset:
867 * @doc: the document pointer
868 *
869 * Get the internal subset of a document
870 * Returns a pointer to the DTD structure or NULL if not found
871 */
872
873xmlDtdPtr
874xmlGetIntSubset(xmlDocPtr doc) {
875 xmlNodePtr cur;
876
877 if (doc == NULL)
878 return(NULL);
879 cur = doc->children;
880 while (cur != NULL) {
881 if (cur->type == XML_DTD_NODE)
882 return((xmlDtdPtr) cur);
883 cur = cur->next;
884 }
885 return((xmlDtdPtr) doc->intSubset);
886}
887
888/**
889 * xmlCreateIntSubset:
890 * @doc: the document pointer
891 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000892 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000893 * @SystemID: the system ID
894 *
895 * Create the internal subset of a document
896 * Returns a pointer to the new DTD structure
897 */
898xmlDtdPtr
899xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
900 const xmlChar *ExternalID, const xmlChar *SystemID) {
901 xmlDtdPtr cur;
902
903 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
904#ifdef DEBUG_TREE
905 xmlGenericError(xmlGenericErrorContext,
906
907 "xmlCreateIntSubset(): document %s already have an internal subset\n",
908 doc->name);
909#endif
910 return(NULL);
911 }
912
913 /*
914 * Allocate a new DTD and fill the fields.
915 */
916 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
917 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000918 xmlTreeErrMemory("building internal subset");
Owen Taylor3473f882001-02-23 17:55:21 +0000919 return(NULL);
920 }
921 memset(cur, 0, sizeof(xmlDtd));
922 cur->type = XML_DTD_NODE;
923
William M. Bracka3215c72004-07-31 16:24:01 +0000924 if (name != NULL) {
925 cur->name = xmlStrdup(name);
926 if (cur->name == NULL) {
927 xmlTreeErrMemory("building internal subset");
928 xmlFree(cur);
929 return(NULL);
930 }
931 }
932 if (ExternalID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000933 cur->ExternalID = xmlStrdup(ExternalID);
William M. Bracka3215c72004-07-31 16:24:01 +0000934 if (cur->ExternalID == NULL) {
935 xmlTreeErrMemory("building internal subset");
936 if (cur->name != NULL)
937 xmlFree((char *)cur->name);
938 xmlFree(cur);
939 return(NULL);
940 }
941 }
942 if (SystemID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000943 cur->SystemID = xmlStrdup(SystemID);
William M. Bracka3215c72004-07-31 16:24:01 +0000944 if (cur->SystemID == NULL) {
945 xmlTreeErrMemory("building internal subset");
946 if (cur->name != NULL)
947 xmlFree((char *)cur->name);
948 if (cur->ExternalID != NULL)
949 xmlFree((char *)cur->ExternalID);
950 xmlFree(cur);
951 return(NULL);
952 }
953 }
Owen Taylor3473f882001-02-23 17:55:21 +0000954 if (doc != NULL) {
955 doc->intSubset = cur;
956 cur->parent = doc;
957 cur->doc = doc;
958 if (doc->children == NULL) {
959 doc->children = (xmlNodePtr) cur;
960 doc->last = (xmlNodePtr) cur;
961 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000962 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000963 xmlNodePtr prev;
964
Owen Taylor3473f882001-02-23 17:55:21 +0000965 prev = doc->children;
966 prev->prev = (xmlNodePtr) cur;
967 cur->next = prev;
968 doc->children = (xmlNodePtr) cur;
969 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000970 xmlNodePtr next;
971
972 next = doc->children;
973 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
974 next = next->next;
975 if (next == NULL) {
976 cur->prev = doc->last;
977 cur->prev->next = (xmlNodePtr) cur;
978 cur->next = NULL;
979 doc->last = (xmlNodePtr) cur;
980 } else {
981 cur->next = next;
982 cur->prev = next->prev;
983 if (cur->prev == NULL)
984 doc->children = (xmlNodePtr) cur;
985 else
986 cur->prev->next = (xmlNodePtr) cur;
987 next->prev = (xmlNodePtr) cur;
988 }
Owen Taylor3473f882001-02-23 17:55:21 +0000989 }
990 }
991 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000992
Daniel Veillarda880b122003-04-21 21:36:41 +0000993 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000994 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000995 return(cur);
996}
997
998/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000999 * DICT_FREE:
1000 * @str: a string
1001 *
1002 * Free a string if it is not owned by the "dict" dictionnary in the
1003 * current scope
1004 */
1005#define DICT_FREE(str) \
1006 if ((str) && ((!dict) || \
1007 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
1008 xmlFree((char *)(str));
1009
1010/**
Owen Taylor3473f882001-02-23 17:55:21 +00001011 * xmlFreeDtd:
1012 * @cur: the DTD structure to free up
1013 *
1014 * Free a DTD structure.
1015 */
1016void
1017xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001018 xmlDictPtr dict = NULL;
1019
Owen Taylor3473f882001-02-23 17:55:21 +00001020 if (cur == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001021 return;
1022 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001023 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001024
Daniel Veillarda880b122003-04-21 21:36:41 +00001025 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001026 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1027
Owen Taylor3473f882001-02-23 17:55:21 +00001028 if (cur->children != NULL) {
1029 xmlNodePtr next, c = cur->children;
1030
1031 /*
William M. Brack18a04f22004-08-03 16:42:37 +00001032 * Cleanup all nodes which are not part of the specific lists
1033 * of notations, elements, attributes and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00001034 */
1035 while (c != NULL) {
1036 next = c->next;
William M. Brack18a04f22004-08-03 16:42:37 +00001037 if ((c->type != XML_NOTATION_NODE) &&
1038 (c->type != XML_ELEMENT_DECL) &&
1039 (c->type != XML_ATTRIBUTE_DECL) &&
1040 (c->type != XML_ENTITY_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001041 xmlUnlinkNode(c);
1042 xmlFreeNode(c);
1043 }
1044 c = next;
1045 }
1046 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001047 DICT_FREE(cur->name)
1048 DICT_FREE(cur->SystemID)
1049 DICT_FREE(cur->ExternalID)
Owen Taylor3473f882001-02-23 17:55:21 +00001050 /* TODO !!! */
1051 if (cur->notations != NULL)
1052 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1053
1054 if (cur->elements != NULL)
1055 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1056 if (cur->attributes != NULL)
1057 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1058 if (cur->entities != NULL)
1059 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1060 if (cur->pentities != NULL)
1061 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1062
Owen Taylor3473f882001-02-23 17:55:21 +00001063 xmlFree(cur);
1064}
1065
1066/**
1067 * xmlNewDoc:
1068 * @version: xmlChar string giving the version of XML "1.0"
1069 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001070 * Creates a new XML document
1071 *
Owen Taylor3473f882001-02-23 17:55:21 +00001072 * Returns a new document
1073 */
1074xmlDocPtr
1075xmlNewDoc(const xmlChar *version) {
1076 xmlDocPtr cur;
1077
1078 if (version == NULL)
1079 version = (const xmlChar *) "1.0";
1080
1081 /*
1082 * Allocate a new document and fill the fields.
1083 */
1084 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1085 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001086 xmlTreeErrMemory("building doc");
Owen Taylor3473f882001-02-23 17:55:21 +00001087 return(NULL);
1088 }
1089 memset(cur, 0, sizeof(xmlDoc));
1090 cur->type = XML_DOCUMENT_NODE;
1091
1092 cur->version = xmlStrdup(version);
William M. Bracka3215c72004-07-31 16:24:01 +00001093 if (cur->version == NULL) {
1094 xmlTreeErrMemory("building doc");
1095 xmlFree(cur);
1096 return(NULL);
1097 }
Owen Taylor3473f882001-02-23 17:55:21 +00001098 cur->standalone = -1;
1099 cur->compression = -1; /* not initialized */
1100 cur->doc = cur;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001101 /*
1102 * The in memory encoding is always UTF8
1103 * This field will never change and would
1104 * be obsolete if not for binary compatibility.
1105 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001106 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001107
Daniel Veillarda880b122003-04-21 21:36:41 +00001108 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001109 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001110 return(cur);
1111}
1112
1113/**
1114 * xmlFreeDoc:
1115 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001116 *
1117 * Free up all the structures used by a document, tree included.
1118 */
1119void
1120xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001121 xmlDtdPtr extSubset, intSubset;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001122 xmlDictPtr dict = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001123
Owen Taylor3473f882001-02-23 17:55:21 +00001124 if (cur == NULL) {
1125#ifdef DEBUG_TREE
1126 xmlGenericError(xmlGenericErrorContext,
1127 "xmlFreeDoc : document == NULL\n");
1128#endif
1129 return;
1130 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001131#ifdef LIBXML_DEBUG_RUNTIME
1132 xmlDebugCheckDocument(stderr, cur);
1133#endif
1134
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001135 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001136
Daniel Veillarda880b122003-04-21 21:36:41 +00001137 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001138 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1139
Daniel Veillard76d66f42001-05-16 21:05:17 +00001140 /*
1141 * Do this before freeing the children list to avoid ID lookups
1142 */
1143 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1144 cur->ids = NULL;
1145 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1146 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001147 extSubset = cur->extSubset;
1148 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001149 if (intSubset == extSubset)
1150 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001151 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001152 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001153 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001154 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001155 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001156 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001157 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001158 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001159 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001160 }
1161
1162 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001163 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001164
1165 DICT_FREE(cur->version)
1166 DICT_FREE(cur->name)
1167 DICT_FREE(cur->encoding)
1168 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001169 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001170 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001171}
1172
1173/**
1174 * xmlStringLenGetNodeList:
1175 * @doc: the document
1176 * @value: the value of the text
1177 * @len: the length of the string value
1178 *
1179 * Parse the value string and build the node list associated. Should
1180 * produce a flat tree with only TEXTs and ENTITY_REFs.
1181 * Returns a pointer to the first child
1182 */
1183xmlNodePtr
1184xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1185 xmlNodePtr ret = NULL, last = NULL;
1186 xmlNodePtr node;
1187 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001188 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001189 const xmlChar *q;
1190 xmlEntityPtr ent;
1191
1192 if (value == NULL) return(NULL);
1193
1194 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001195 while ((cur < end) && (*cur != 0)) {
1196 if (cur[0] == '&') {
1197 int charval = 0;
1198 xmlChar tmp;
1199
Owen Taylor3473f882001-02-23 17:55:21 +00001200 /*
1201 * Save the current text.
1202 */
1203 if (cur != q) {
1204 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1205 xmlNodeAddContentLen(last, q, cur - q);
1206 } else {
1207 node = xmlNewDocTextLen(doc, q, cur - q);
1208 if (node == NULL) return(ret);
1209 if (last == NULL)
1210 last = ret = node;
1211 else {
1212 last->next = node;
1213 node->prev = last;
1214 last = node;
1215 }
1216 }
1217 }
Owen Taylor3473f882001-02-23 17:55:21 +00001218 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001219 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1220 cur += 3;
1221 if (cur < end)
1222 tmp = *cur;
1223 else
1224 tmp = 0;
1225 while (tmp != ';') { /* Non input consuming loop */
1226 if ((tmp >= '0') && (tmp <= '9'))
1227 charval = charval * 16 + (tmp - '0');
1228 else if ((tmp >= 'a') && (tmp <= 'f'))
1229 charval = charval * 16 + (tmp - 'a') + 10;
1230 else if ((tmp >= 'A') && (tmp <= 'F'))
1231 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001232 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001233 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1234 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001235 charval = 0;
1236 break;
1237 }
1238 cur++;
1239 if (cur < end)
1240 tmp = *cur;
1241 else
1242 tmp = 0;
1243 }
1244 if (tmp == ';')
1245 cur++;
1246 q = cur;
1247 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1248 cur += 2;
1249 if (cur < end)
1250 tmp = *cur;
1251 else
1252 tmp = 0;
1253 while (tmp != ';') { /* Non input consuming loops */
1254 if ((tmp >= '0') && (tmp <= '9'))
1255 charval = charval * 10 + (tmp - '0');
1256 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001257 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1258 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001259 charval = 0;
1260 break;
1261 }
1262 cur++;
1263 if (cur < end)
1264 tmp = *cur;
1265 else
1266 tmp = 0;
1267 }
1268 if (tmp == ';')
1269 cur++;
1270 q = cur;
1271 } else {
1272 /*
1273 * Read the entity string
1274 */
1275 cur++;
1276 q = cur;
1277 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1278 if ((cur >= end) || (*cur == 0)) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001279 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1280 (const char *) q);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001281 return(ret);
1282 }
1283 if (cur != q) {
1284 /*
1285 * Predefined entities don't generate nodes
1286 */
1287 val = xmlStrndup(q, cur - q);
1288 ent = xmlGetDocEntity(doc, val);
1289 if ((ent != NULL) &&
1290 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1291 if (last == NULL) {
1292 node = xmlNewDocText(doc, ent->content);
1293 last = ret = node;
1294 } else if (last->type != XML_TEXT_NODE) {
1295 node = xmlNewDocText(doc, ent->content);
1296 last = xmlAddNextSibling(last, node);
1297 } else
1298 xmlNodeAddContent(last, ent->content);
1299
1300 } else {
1301 /*
1302 * Create a new REFERENCE_REF node
1303 */
1304 node = xmlNewReference(doc, val);
1305 if (node == NULL) {
1306 if (val != NULL) xmlFree(val);
1307 return(ret);
1308 }
1309 else if ((ent != NULL) && (ent->children == NULL)) {
1310 xmlNodePtr temp;
1311
1312 ent->children = xmlStringGetNodeList(doc,
1313 (const xmlChar*)node->content);
1314 ent->owner = 1;
1315 temp = ent->children;
1316 while (temp) {
1317 temp->parent = (xmlNodePtr)ent;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001318 ent->last = temp;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001319 temp = temp->next;
1320 }
1321 }
1322 if (last == NULL) {
1323 last = ret = node;
1324 } else {
1325 last = xmlAddNextSibling(last, node);
1326 }
1327 }
1328 xmlFree(val);
1329 }
1330 cur++;
1331 q = cur;
1332 }
1333 if (charval != 0) {
1334 xmlChar buf[10];
1335 int l;
1336
1337 l = xmlCopyCharMultiByte(buf, charval);
1338 buf[l] = 0;
1339 node = xmlNewDocText(doc, buf);
1340 if (node != NULL) {
1341 if (last == NULL) {
1342 last = ret = node;
1343 } else {
1344 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001345 }
1346 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001347 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001348 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001349 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001350 cur++;
1351 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001352 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001353 /*
1354 * Handle the last piece of text.
1355 */
1356 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1357 xmlNodeAddContentLen(last, q, cur - q);
1358 } else {
1359 node = xmlNewDocTextLen(doc, q, cur - q);
1360 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001361 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001362 last = ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001363 } else {
1364 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001365 }
1366 }
1367 }
1368 return(ret);
1369}
1370
1371/**
1372 * xmlStringGetNodeList:
1373 * @doc: the document
1374 * @value: the value of the attribute
1375 *
1376 * Parse the value string and build the node list associated. Should
1377 * produce a flat tree with only TEXTs and ENTITY_REFs.
1378 * Returns a pointer to the first child
1379 */
1380xmlNodePtr
1381xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1382 xmlNodePtr ret = NULL, last = NULL;
1383 xmlNodePtr node;
1384 xmlChar *val;
1385 const xmlChar *cur = value;
1386 const xmlChar *q;
1387 xmlEntityPtr ent;
1388
1389 if (value == NULL) return(NULL);
1390
1391 q = cur;
1392 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001393 if (cur[0] == '&') {
1394 int charval = 0;
1395 xmlChar tmp;
1396
Owen Taylor3473f882001-02-23 17:55:21 +00001397 /*
1398 * Save the current text.
1399 */
1400 if (cur != q) {
1401 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1402 xmlNodeAddContentLen(last, q, cur - q);
1403 } else {
1404 node = xmlNewDocTextLen(doc, q, cur - q);
1405 if (node == NULL) return(ret);
1406 if (last == NULL)
1407 last = ret = node;
1408 else {
1409 last->next = node;
1410 node->prev = last;
1411 last = node;
1412 }
1413 }
1414 }
Owen Taylor3473f882001-02-23 17:55:21 +00001415 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001416 if ((cur[1] == '#') && (cur[2] == 'x')) {
1417 cur += 3;
1418 tmp = *cur;
1419 while (tmp != ';') { /* Non input consuming loop */
1420 if ((tmp >= '0') && (tmp <= '9'))
1421 charval = charval * 16 + (tmp - '0');
1422 else if ((tmp >= 'a') && (tmp <= 'f'))
1423 charval = charval * 16 + (tmp - 'a') + 10;
1424 else if ((tmp >= 'A') && (tmp <= 'F'))
1425 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001426 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001427 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1428 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001429 charval = 0;
1430 break;
1431 }
1432 cur++;
1433 tmp = *cur;
1434 }
1435 if (tmp == ';')
1436 cur++;
1437 q = cur;
1438 } else if (cur[1] == '#') {
1439 cur += 2;
1440 tmp = *cur;
1441 while (tmp != ';') { /* Non input consuming loops */
1442 if ((tmp >= '0') && (tmp <= '9'))
1443 charval = charval * 10 + (tmp - '0');
1444 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001445 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1446 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001447 charval = 0;
1448 break;
1449 }
1450 cur++;
1451 tmp = *cur;
1452 }
1453 if (tmp == ';')
1454 cur++;
1455 q = cur;
1456 } else {
1457 /*
1458 * Read the entity string
1459 */
1460 cur++;
1461 q = cur;
1462 while ((*cur != 0) && (*cur != ';')) cur++;
1463 if (*cur == 0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001464 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1465 (xmlNodePtr) doc, (const char *) q);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001466 return(ret);
1467 }
1468 if (cur != q) {
1469 /*
1470 * Predefined entities don't generate nodes
1471 */
1472 val = xmlStrndup(q, cur - q);
1473 ent = xmlGetDocEntity(doc, val);
1474 if ((ent != NULL) &&
1475 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1476 if (last == NULL) {
1477 node = xmlNewDocText(doc, ent->content);
1478 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001479 } else if (last->type != XML_TEXT_NODE) {
1480 node = xmlNewDocText(doc, ent->content);
1481 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001482 } else
1483 xmlNodeAddContent(last, ent->content);
1484
1485 } else {
1486 /*
1487 * Create a new REFERENCE_REF node
1488 */
1489 node = xmlNewReference(doc, val);
1490 if (node == NULL) {
1491 if (val != NULL) xmlFree(val);
1492 return(ret);
1493 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001494 else if ((ent != NULL) && (ent->children == NULL)) {
1495 xmlNodePtr temp;
1496
1497 ent->children = xmlStringGetNodeList(doc,
1498 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001499 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001500 temp = ent->children;
1501 while (temp) {
1502 temp->parent = (xmlNodePtr)ent;
1503 temp = temp->next;
1504 }
1505 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001506 if (last == NULL) {
1507 last = ret = node;
1508 } else {
1509 last = xmlAddNextSibling(last, node);
1510 }
1511 }
1512 xmlFree(val);
1513 }
1514 cur++;
1515 q = cur;
1516 }
1517 if (charval != 0) {
1518 xmlChar buf[10];
1519 int len;
1520
1521 len = xmlCopyCharMultiByte(buf, charval);
1522 buf[len] = 0;
1523 node = xmlNewDocText(doc, buf);
1524 if (node != NULL) {
1525 if (last == NULL) {
1526 last = ret = node;
1527 } else {
1528 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001529 }
1530 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001531
1532 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001533 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001534 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001535 cur++;
1536 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001537 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001538 /*
1539 * Handle the last piece of text.
1540 */
1541 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1542 xmlNodeAddContentLen(last, q, cur - q);
1543 } else {
1544 node = xmlNewDocTextLen(doc, q, cur - q);
1545 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001546 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001547 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001548 } else {
1549 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001550 }
1551 }
1552 }
1553 return(ret);
1554}
1555
1556/**
1557 * xmlNodeListGetString:
1558 * @doc: the document
1559 * @list: a Node list
1560 * @inLine: should we replace entity contents or show their external form
1561 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001562 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001563 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001564 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001565 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001566 */
1567xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001568xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1569{
Owen Taylor3473f882001-02-23 17:55:21 +00001570 xmlNodePtr node = list;
1571 xmlChar *ret = NULL;
1572 xmlEntityPtr ent;
1573
Daniel Veillard7646b182002-04-20 06:41:40 +00001574 if (list == NULL)
1575 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001576
1577 while (node != NULL) {
1578 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001579 (node->type == XML_CDATA_SECTION_NODE)) {
1580 if (inLine) {
1581 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001582 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001583 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001584
Daniel Veillard7646b182002-04-20 06:41:40 +00001585 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1586 if (buffer != NULL) {
1587 ret = xmlStrcat(ret, buffer);
1588 xmlFree(buffer);
1589 }
1590 }
1591 } else if (node->type == XML_ENTITY_REF_NODE) {
1592 if (inLine) {
1593 ent = xmlGetDocEntity(doc, node->name);
1594 if (ent != NULL) {
1595 xmlChar *buffer;
1596
1597 /* an entity content can be any "well balanced chunk",
1598 * i.e. the result of the content [43] production:
1599 * http://www.w3.org/TR/REC-xml#NT-content.
1600 * So it can contain text, CDATA section or nested
1601 * entity reference nodes (among others).
1602 * -> we recursive call xmlNodeListGetString()
1603 * which handles these types */
1604 buffer = xmlNodeListGetString(doc, ent->children, 1);
1605 if (buffer != NULL) {
1606 ret = xmlStrcat(ret, buffer);
1607 xmlFree(buffer);
1608 }
1609 } else {
1610 ret = xmlStrcat(ret, node->content);
1611 }
1612 } else {
1613 xmlChar buf[2];
1614
1615 buf[0] = '&';
1616 buf[1] = 0;
1617 ret = xmlStrncat(ret, buf, 1);
1618 ret = xmlStrcat(ret, node->name);
1619 buf[0] = ';';
1620 buf[1] = 0;
1621 ret = xmlStrncat(ret, buf, 1);
1622 }
1623 }
1624#if 0
1625 else {
1626 xmlGenericError(xmlGenericErrorContext,
1627 "xmlGetNodeListString : invalid node type %d\n",
1628 node->type);
1629 }
1630#endif
1631 node = node->next;
1632 }
1633 return (ret);
1634}
Daniel Veillard652327a2003-09-29 18:02:38 +00001635
1636#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001637/**
1638 * xmlNodeListGetRawString:
1639 * @doc: the document
1640 * @list: a Node list
1641 * @inLine: should we replace entity contents or show their external form
1642 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001643 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001644 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1645 * this function doesn't do any character encoding handling.
1646 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001647 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001648 */
1649xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001650xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1651{
Owen Taylor3473f882001-02-23 17:55:21 +00001652 xmlNodePtr node = list;
1653 xmlChar *ret = NULL;
1654 xmlEntityPtr ent;
1655
Daniel Veillard7646b182002-04-20 06:41:40 +00001656 if (list == NULL)
1657 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001658
1659 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001660 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001661 (node->type == XML_CDATA_SECTION_NODE)) {
1662 if (inLine) {
1663 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001664 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001665 xmlChar *buffer;
1666
1667 buffer = xmlEncodeSpecialChars(doc, node->content);
1668 if (buffer != NULL) {
1669 ret = xmlStrcat(ret, buffer);
1670 xmlFree(buffer);
1671 }
1672 }
1673 } else if (node->type == XML_ENTITY_REF_NODE) {
1674 if (inLine) {
1675 ent = xmlGetDocEntity(doc, node->name);
1676 if (ent != NULL) {
1677 xmlChar *buffer;
1678
1679 /* an entity content can be any "well balanced chunk",
1680 * i.e. the result of the content [43] production:
1681 * http://www.w3.org/TR/REC-xml#NT-content.
1682 * So it can contain text, CDATA section or nested
1683 * entity reference nodes (among others).
1684 * -> we recursive call xmlNodeListGetRawString()
1685 * which handles these types */
1686 buffer =
1687 xmlNodeListGetRawString(doc, ent->children, 1);
1688 if (buffer != NULL) {
1689 ret = xmlStrcat(ret, buffer);
1690 xmlFree(buffer);
1691 }
1692 } else {
1693 ret = xmlStrcat(ret, node->content);
1694 }
1695 } else {
1696 xmlChar buf[2];
1697
1698 buf[0] = '&';
1699 buf[1] = 0;
1700 ret = xmlStrncat(ret, buf, 1);
1701 ret = xmlStrcat(ret, node->name);
1702 buf[0] = ';';
1703 buf[1] = 0;
1704 ret = xmlStrncat(ret, buf, 1);
1705 }
1706 }
Owen Taylor3473f882001-02-23 17:55:21 +00001707#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001708 else {
1709 xmlGenericError(xmlGenericErrorContext,
1710 "xmlGetNodeListString : invalid node type %d\n",
1711 node->type);
1712 }
Owen Taylor3473f882001-02-23 17:55:21 +00001713#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001714 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001715 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001716 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001717}
Daniel Veillard652327a2003-09-29 18:02:38 +00001718#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001719
Daniel Veillard2156d432004-03-04 15:59:36 +00001720#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00001721/**
1722 * xmlNewProp:
1723 * @node: the holding node
1724 * @name: the name of the attribute
1725 * @value: the value of the attribute
1726 *
1727 * Create a new property carried by a node.
1728 * Returns a pointer to the attribute
1729 */
1730xmlAttrPtr
1731xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1732 xmlAttrPtr cur;
1733 xmlDocPtr doc = NULL;
1734
1735 if (name == NULL) {
1736#ifdef DEBUG_TREE
1737 xmlGenericError(xmlGenericErrorContext,
1738 "xmlNewProp : name == NULL\n");
1739#endif
1740 return(NULL);
1741 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001742 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1743 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001744
1745 /*
1746 * Allocate a new property and fill the fields.
1747 */
1748 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1749 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001750 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001751 return(NULL);
1752 }
1753 memset(cur, 0, sizeof(xmlAttr));
1754 cur->type = XML_ATTRIBUTE_NODE;
1755
1756 cur->parent = node;
1757 if (node != NULL) {
1758 doc = node->doc;
1759 cur->doc = doc;
1760 }
Daniel Veillard03a53c32004-10-26 16:06:51 +00001761 if ((doc != NULL) && (doc->dict != NULL))
1762 cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
1763 else
1764 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00001765 if (value != NULL) {
1766 xmlChar *buffer;
1767 xmlNodePtr tmp;
1768
1769 buffer = xmlEncodeEntitiesReentrant(doc, value);
1770 cur->children = xmlStringGetNodeList(doc, buffer);
1771 cur->last = NULL;
1772 tmp = cur->children;
1773 while (tmp != NULL) {
1774 tmp->parent = (xmlNodePtr) cur;
1775 tmp->doc = doc;
1776 if (tmp->next == NULL)
1777 cur->last = tmp;
1778 tmp = tmp->next;
1779 }
1780 xmlFree(buffer);
1781 }
1782
1783 /*
1784 * Add it at the end to preserve parsing order ...
1785 */
1786 if (node != NULL) {
1787 if (node->properties == NULL) {
1788 node->properties = cur;
1789 } else {
1790 xmlAttrPtr prev = node->properties;
1791
1792 while (prev->next != NULL) prev = prev->next;
1793 prev->next = cur;
1794 cur->prev = prev;
1795 }
1796 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001797
Daniel Veillarda880b122003-04-21 21:36:41 +00001798 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001799 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001800 return(cur);
1801}
Daniel Veillard652327a2003-09-29 18:02:38 +00001802#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001803
1804/**
1805 * xmlNewNsProp:
1806 * @node: the holding node
1807 * @ns: the namespace
1808 * @name: the name of the attribute
1809 * @value: the value of the attribute
1810 *
1811 * Create a new property tagged with a namespace and carried by a node.
1812 * Returns a pointer to the attribute
1813 */
1814xmlAttrPtr
1815xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1816 const xmlChar *value) {
1817 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001818 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001819
1820 if (name == NULL) {
1821#ifdef DEBUG_TREE
1822 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001823 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001824#endif
1825 return(NULL);
1826 }
1827
1828 /*
1829 * Allocate a new property and fill the fields.
1830 */
1831 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1832 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001833 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001834 return(NULL);
1835 }
1836 memset(cur, 0, sizeof(xmlAttr));
1837 cur->type = XML_ATTRIBUTE_NODE;
1838
1839 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001840 if (node != NULL) {
1841 doc = node->doc;
1842 cur->doc = doc;
1843 }
Owen Taylor3473f882001-02-23 17:55:21 +00001844 cur->ns = ns;
Daniel Veillard03a53c32004-10-26 16:06:51 +00001845 if ((doc != NULL) && (doc->dict != NULL))
1846 cur->name = xmlDictLookup(doc->dict, name, -1);
1847 else
1848 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00001849 if (value != NULL) {
1850 xmlChar *buffer;
1851 xmlNodePtr tmp;
1852
Daniel Veillarda682b212001-06-07 19:59:42 +00001853 buffer = xmlEncodeEntitiesReentrant(doc, value);
1854 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001855 cur->last = NULL;
1856 tmp = cur->children;
1857 while (tmp != NULL) {
1858 tmp->parent = (xmlNodePtr) cur;
1859 if (tmp->next == NULL)
1860 cur->last = tmp;
1861 tmp = tmp->next;
1862 }
1863 xmlFree(buffer);
1864 }
1865
1866 /*
1867 * Add it at the end to preserve parsing order ...
1868 */
1869 if (node != NULL) {
1870 if (node->properties == NULL) {
1871 node->properties = cur;
1872 } else {
1873 xmlAttrPtr prev = node->properties;
1874
1875 while (prev->next != NULL) prev = prev->next;
1876 prev->next = cur;
1877 cur->prev = prev;
1878 }
1879 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001880
Daniel Veillarda880b122003-04-21 21:36:41 +00001881 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001882 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001883 return(cur);
1884}
1885
1886/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001887 * xmlNewNsPropEatName:
1888 * @node: the holding node
1889 * @ns: the namespace
1890 * @name: the name of the attribute
1891 * @value: the value of the attribute
1892 *
1893 * Create a new property tagged with a namespace and carried by a node.
1894 * Returns a pointer to the attribute
1895 */
1896xmlAttrPtr
1897xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1898 const xmlChar *value) {
1899 xmlAttrPtr cur;
1900 xmlDocPtr doc = NULL;
1901
1902 if (name == NULL) {
1903#ifdef DEBUG_TREE
1904 xmlGenericError(xmlGenericErrorContext,
1905 "xmlNewNsPropEatName : name == NULL\n");
1906#endif
1907 return(NULL);
1908 }
1909
1910 /*
1911 * Allocate a new property and fill the fields.
1912 */
1913 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1914 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001915 xmlTreeErrMemory("building attribute");
Daniel Veillard46de64e2002-05-29 08:21:33 +00001916 return(NULL);
1917 }
1918 memset(cur, 0, sizeof(xmlAttr));
1919 cur->type = XML_ATTRIBUTE_NODE;
1920
1921 cur->parent = node;
1922 if (node != NULL) {
1923 doc = node->doc;
1924 cur->doc = doc;
1925 }
1926 cur->ns = ns;
1927 cur->name = name;
1928 if (value != NULL) {
1929 xmlChar *buffer;
1930 xmlNodePtr tmp;
1931
1932 buffer = xmlEncodeEntitiesReentrant(doc, value);
1933 cur->children = xmlStringGetNodeList(doc, buffer);
1934 cur->last = NULL;
1935 tmp = cur->children;
1936 while (tmp != NULL) {
1937 tmp->parent = (xmlNodePtr) cur;
1938 if (tmp->next == NULL)
1939 cur->last = tmp;
1940 tmp = tmp->next;
1941 }
1942 xmlFree(buffer);
1943 }
1944
1945 /*
1946 * Add it at the end to preserve parsing order ...
1947 */
1948 if (node != NULL) {
1949 if (node->properties == NULL) {
1950 node->properties = cur;
1951 } else {
1952 xmlAttrPtr prev = node->properties;
1953
1954 while (prev->next != NULL) prev = prev->next;
1955 prev->next = cur;
1956 cur->prev = prev;
1957 }
1958 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001959
Daniel Veillarda880b122003-04-21 21:36:41 +00001960 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001961 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001962 return(cur);
1963}
1964
1965/**
Owen Taylor3473f882001-02-23 17:55:21 +00001966 * xmlNewDocProp:
1967 * @doc: the document
1968 * @name: the name of the attribute
1969 * @value: the value of the attribute
1970 *
1971 * Create a new property carried by a document.
1972 * Returns a pointer to the attribute
1973 */
1974xmlAttrPtr
1975xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1976 xmlAttrPtr cur;
1977
1978 if (name == NULL) {
1979#ifdef DEBUG_TREE
1980 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001981 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001982#endif
1983 return(NULL);
1984 }
1985
1986 /*
1987 * Allocate a new property and fill the fields.
1988 */
1989 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1990 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001991 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001992 return(NULL);
1993 }
1994 memset(cur, 0, sizeof(xmlAttr));
1995 cur->type = XML_ATTRIBUTE_NODE;
1996
Daniel Veillard03a53c32004-10-26 16:06:51 +00001997 if ((doc != NULL) && (doc->dict != NULL))
1998 cur->name = xmlDictLookup(doc->dict, name, -1);
1999 else
2000 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00002001 cur->doc = doc;
2002 if (value != NULL) {
2003 xmlNodePtr tmp;
2004
2005 cur->children = xmlStringGetNodeList(doc, value);
2006 cur->last = NULL;
2007
2008 tmp = cur->children;
2009 while (tmp != NULL) {
2010 tmp->parent = (xmlNodePtr) cur;
2011 if (tmp->next == NULL)
2012 cur->last = tmp;
2013 tmp = tmp->next;
2014 }
2015 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002016
Daniel Veillarda880b122003-04-21 21:36:41 +00002017 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002018 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002019 return(cur);
2020}
2021
2022/**
2023 * xmlFreePropList:
2024 * @cur: the first property in the list
2025 *
2026 * Free a property and all its siblings, all the children are freed too.
2027 */
2028void
2029xmlFreePropList(xmlAttrPtr cur) {
2030 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002031 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002032 while (cur != NULL) {
2033 next = cur->next;
2034 xmlFreeProp(cur);
2035 cur = next;
2036 }
2037}
2038
2039/**
2040 * xmlFreeProp:
2041 * @cur: an attribute
2042 *
2043 * Free one attribute, all the content is freed too
2044 */
2045void
2046xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002047 xmlDictPtr dict = NULL;
2048 if (cur == NULL) return;
2049
2050 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002051
Daniel Veillarda880b122003-04-21 21:36:41 +00002052 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002053 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
2054
Owen Taylor3473f882001-02-23 17:55:21 +00002055 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00002056 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
2057 ((cur->parent->doc->intSubset != NULL) ||
2058 (cur->parent->doc->extSubset != NULL))) {
2059 if (xmlIsID(cur->parent->doc, cur->parent, cur))
2060 xmlRemoveID(cur->parent->doc, cur);
2061 }
Owen Taylor3473f882001-02-23 17:55:21 +00002062 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002063 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002064 xmlFree(cur);
2065}
2066
Daniel Veillard652327a2003-09-29 18:02:38 +00002067#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002068/**
2069 * xmlRemoveProp:
2070 * @cur: an attribute
2071 *
2072 * Unlink and free one attribute, all the content is freed too
2073 * Note this doesn't work for namespace definition attributes
2074 *
2075 * Returns 0 if success and -1 in case of error.
2076 */
2077int
2078xmlRemoveProp(xmlAttrPtr cur) {
2079 xmlAttrPtr tmp;
2080 if (cur == NULL) {
2081#ifdef DEBUG_TREE
2082 xmlGenericError(xmlGenericErrorContext,
2083 "xmlRemoveProp : cur == NULL\n");
2084#endif
2085 return(-1);
2086 }
2087 if (cur->parent == NULL) {
2088#ifdef DEBUG_TREE
2089 xmlGenericError(xmlGenericErrorContext,
2090 "xmlRemoveProp : cur->parent == NULL\n");
2091#endif
2092 return(-1);
2093 }
2094 tmp = cur->parent->properties;
2095 if (tmp == cur) {
2096 cur->parent->properties = cur->next;
2097 xmlFreeProp(cur);
2098 return(0);
2099 }
2100 while (tmp != NULL) {
2101 if (tmp->next == cur) {
2102 tmp->next = cur->next;
2103 if (tmp->next != NULL)
2104 tmp->next->prev = tmp;
2105 xmlFreeProp(cur);
2106 return(0);
2107 }
2108 tmp = tmp->next;
2109 }
2110#ifdef DEBUG_TREE
2111 xmlGenericError(xmlGenericErrorContext,
2112 "xmlRemoveProp : attribute not owned by its node\n");
2113#endif
2114 return(-1);
2115}
Daniel Veillard652327a2003-09-29 18:02:38 +00002116#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002117
2118/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002119 * xmlNewDocPI:
2120 * @doc: the target document
Owen Taylor3473f882001-02-23 17:55:21 +00002121 * @name: the processing instruction name
2122 * @content: the PI content
2123 *
2124 * Creation of a processing instruction element.
2125 * Returns a pointer to the new node object.
2126 */
2127xmlNodePtr
Daniel Veillard03a53c32004-10-26 16:06:51 +00002128xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
Owen Taylor3473f882001-02-23 17:55:21 +00002129 xmlNodePtr cur;
2130
2131 if (name == NULL) {
2132#ifdef DEBUG_TREE
2133 xmlGenericError(xmlGenericErrorContext,
2134 "xmlNewPI : name == NULL\n");
2135#endif
2136 return(NULL);
2137 }
2138
2139 /*
2140 * Allocate a new node and fill the fields.
2141 */
2142 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2143 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002144 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002145 return(NULL);
2146 }
2147 memset(cur, 0, sizeof(xmlNode));
2148 cur->type = XML_PI_NODE;
2149
Daniel Veillard03a53c32004-10-26 16:06:51 +00002150 if ((doc != NULL) && (doc->dict != NULL))
2151 cur->name = xmlDictLookup(doc->dict, name, -1);
2152 else
2153 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00002154 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002155 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002156 }
Daniel Veillarda03e3652004-11-02 18:45:30 +00002157 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002158
Daniel Veillarda880b122003-04-21 21:36:41 +00002159 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002160 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002161 return(cur);
2162}
2163
2164/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002165 * xmlNewPI:
2166 * @name: the processing instruction name
2167 * @content: the PI content
2168 *
2169 * Creation of a processing instruction element.
2170 * Use xmlDocNewPI preferably to get string interning
2171 *
2172 * Returns a pointer to the new node object.
2173 */
2174xmlNodePtr
2175xmlNewPI(const xmlChar *name, const xmlChar *content) {
2176 return(xmlNewDocPI(NULL, name, content));
2177}
2178
2179/**
Owen Taylor3473f882001-02-23 17:55:21 +00002180 * xmlNewNode:
2181 * @ns: namespace if any
2182 * @name: the node name
2183 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002184 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002185 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002186 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2187 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002188 */
2189xmlNodePtr
2190xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2191 xmlNodePtr cur;
2192
2193 if (name == NULL) {
2194#ifdef DEBUG_TREE
2195 xmlGenericError(xmlGenericErrorContext,
2196 "xmlNewNode : name == NULL\n");
2197#endif
2198 return(NULL);
2199 }
2200
2201 /*
2202 * Allocate a new node and fill the fields.
2203 */
2204 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2205 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002206 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002207 return(NULL);
2208 }
2209 memset(cur, 0, sizeof(xmlNode));
2210 cur->type = XML_ELEMENT_NODE;
2211
2212 cur->name = xmlStrdup(name);
2213 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002214
Daniel Veillarda880b122003-04-21 21:36:41 +00002215 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002216 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002217 return(cur);
2218}
2219
2220/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002221 * xmlNewNodeEatName:
2222 * @ns: namespace if any
2223 * @name: the node name
2224 *
2225 * Creation of a new node element. @ns is optional (NULL).
2226 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002227 * Returns a pointer to the new node object, with pointer @name as
2228 * new node's name. Use xmlNewNode() if a copy of @name string is
2229 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002230 */
2231xmlNodePtr
2232xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2233 xmlNodePtr cur;
2234
2235 if (name == NULL) {
2236#ifdef DEBUG_TREE
2237 xmlGenericError(xmlGenericErrorContext,
2238 "xmlNewNode : name == NULL\n");
2239#endif
2240 return(NULL);
2241 }
2242
2243 /*
2244 * Allocate a new node and fill the fields.
2245 */
2246 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2247 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002248 xmlTreeErrMemory("building node");
Daniel Veillard46de64e2002-05-29 08:21:33 +00002249 return(NULL);
2250 }
2251 memset(cur, 0, sizeof(xmlNode));
2252 cur->type = XML_ELEMENT_NODE;
2253
2254 cur->name = name;
2255 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002256
Daniel Veillarda880b122003-04-21 21:36:41 +00002257 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002258 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002259 return(cur);
2260}
2261
2262/**
Owen Taylor3473f882001-02-23 17:55:21 +00002263 * xmlNewDocNode:
2264 * @doc: the document
2265 * @ns: namespace if any
2266 * @name: the node name
2267 * @content: the XML text content if any
2268 *
2269 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002270 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002271 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2272 * references, but XML special chars need to be escaped first by using
2273 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2274 * need entities support.
2275 *
2276 * Returns a pointer to the new node object.
2277 */
2278xmlNodePtr
2279xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2280 const xmlChar *name, const xmlChar *content) {
2281 xmlNodePtr cur;
2282
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002283 if ((doc != NULL) && (doc->dict != NULL))
Daniel Veillard03a53c32004-10-26 16:06:51 +00002284 cur = xmlNewNodeEatName(ns, (xmlChar *)
2285 xmlDictLookup(doc->dict, name, -1));
2286 else
2287 cur = xmlNewNode(ns, name);
Owen Taylor3473f882001-02-23 17:55:21 +00002288 if (cur != NULL) {
2289 cur->doc = doc;
2290 if (content != NULL) {
2291 cur->children = xmlStringGetNodeList(doc, content);
2292 UPDATE_LAST_CHILD_AND_PARENT(cur)
2293 }
2294 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002295
Owen Taylor3473f882001-02-23 17:55:21 +00002296 return(cur);
2297}
2298
Daniel Veillard46de64e2002-05-29 08:21:33 +00002299/**
2300 * xmlNewDocNodeEatName:
2301 * @doc: the document
2302 * @ns: namespace if any
2303 * @name: the node name
2304 * @content: the XML text content if any
2305 *
2306 * Creation of a new node element within a document. @ns and @content
2307 * are optional (NULL).
2308 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2309 * references, but XML special chars need to be escaped first by using
2310 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2311 * need entities support.
2312 *
2313 * Returns a pointer to the new node object.
2314 */
2315xmlNodePtr
2316xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2317 xmlChar *name, const xmlChar *content) {
2318 xmlNodePtr cur;
2319
2320 cur = xmlNewNodeEatName(ns, name);
2321 if (cur != NULL) {
2322 cur->doc = doc;
2323 if (content != NULL) {
2324 cur->children = xmlStringGetNodeList(doc, content);
2325 UPDATE_LAST_CHILD_AND_PARENT(cur)
2326 }
2327 }
2328 return(cur);
2329}
2330
Daniel Veillard652327a2003-09-29 18:02:38 +00002331#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002332/**
2333 * xmlNewDocRawNode:
2334 * @doc: the document
2335 * @ns: namespace if any
2336 * @name: the node name
2337 * @content: the text content if any
2338 *
2339 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002340 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002341 *
2342 * Returns a pointer to the new node object.
2343 */
2344xmlNodePtr
2345xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2346 const xmlChar *name, const xmlChar *content) {
2347 xmlNodePtr cur;
2348
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002349 cur = xmlNewDocNode(doc, ns, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002350 if (cur != NULL) {
2351 cur->doc = doc;
2352 if (content != NULL) {
2353 cur->children = xmlNewDocText(doc, content);
2354 UPDATE_LAST_CHILD_AND_PARENT(cur)
2355 }
2356 }
2357 return(cur);
2358}
2359
2360/**
2361 * xmlNewDocFragment:
2362 * @doc: the document owning the fragment
2363 *
2364 * Creation of a new Fragment node.
2365 * Returns a pointer to the new node object.
2366 */
2367xmlNodePtr
2368xmlNewDocFragment(xmlDocPtr doc) {
2369 xmlNodePtr cur;
2370
2371 /*
2372 * Allocate a new DocumentFragment node and fill the fields.
2373 */
2374 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2375 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002376 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002377 return(NULL);
2378 }
2379 memset(cur, 0, sizeof(xmlNode));
2380 cur->type = XML_DOCUMENT_FRAG_NODE;
2381
2382 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002383
Daniel Veillarda880b122003-04-21 21:36:41 +00002384 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002385 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002386 return(cur);
2387}
Daniel Veillard652327a2003-09-29 18:02:38 +00002388#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002389
2390/**
2391 * xmlNewText:
2392 * @content: the text content
2393 *
2394 * Creation of a new text node.
2395 * Returns a pointer to the new node object.
2396 */
2397xmlNodePtr
2398xmlNewText(const xmlChar *content) {
2399 xmlNodePtr cur;
2400
2401 /*
2402 * Allocate a new node and fill the fields.
2403 */
2404 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2405 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002406 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002407 return(NULL);
2408 }
2409 memset(cur, 0, sizeof(xmlNode));
2410 cur->type = XML_TEXT_NODE;
2411
2412 cur->name = xmlStringText;
2413 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002414 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002415 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002416
Daniel Veillarda880b122003-04-21 21:36:41 +00002417 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002418 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002419 return(cur);
2420}
2421
Daniel Veillard652327a2003-09-29 18:02:38 +00002422#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002423/**
2424 * xmlNewTextChild:
2425 * @parent: the parent node
2426 * @ns: a namespace if any
2427 * @name: the name of the child
2428 * @content: the text content of the child if any.
2429 *
2430 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002431 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2432 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002433 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002434 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2435 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2436 * reserved XML chars that might appear in @content, such as the ampersand,
2437 * greater-than or less-than signs, are automatically replaced by their XML
2438 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002439 *
2440 * Returns a pointer to the new node object.
2441 */
2442xmlNodePtr
2443xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2444 const xmlChar *name, const xmlChar *content) {
2445 xmlNodePtr cur, prev;
2446
2447 if (parent == NULL) {
2448#ifdef DEBUG_TREE
2449 xmlGenericError(xmlGenericErrorContext,
2450 "xmlNewTextChild : parent == NULL\n");
2451#endif
2452 return(NULL);
2453 }
2454
2455 if (name == NULL) {
2456#ifdef DEBUG_TREE
2457 xmlGenericError(xmlGenericErrorContext,
2458 "xmlNewTextChild : name == NULL\n");
2459#endif
2460 return(NULL);
2461 }
2462
2463 /*
2464 * Allocate a new node
2465 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002466 if (parent->type == XML_ELEMENT_NODE) {
2467 if (ns == NULL)
2468 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2469 else
2470 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2471 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2472 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2473 if (ns == NULL)
2474 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2475 else
2476 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2477 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2478 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2479 } else {
2480 return(NULL);
2481 }
Owen Taylor3473f882001-02-23 17:55:21 +00002482 if (cur == NULL) return(NULL);
2483
2484 /*
2485 * add the new element at the end of the children list.
2486 */
2487 cur->type = XML_ELEMENT_NODE;
2488 cur->parent = parent;
2489 cur->doc = parent->doc;
2490 if (parent->children == NULL) {
2491 parent->children = cur;
2492 parent->last = cur;
2493 } else {
2494 prev = parent->last;
2495 prev->next = cur;
2496 cur->prev = prev;
2497 parent->last = cur;
2498 }
2499
2500 return(cur);
2501}
Daniel Veillard652327a2003-09-29 18:02:38 +00002502#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002503
2504/**
2505 * xmlNewCharRef:
2506 * @doc: the document
2507 * @name: the char ref string, starting with # or "&# ... ;"
2508 *
2509 * Creation of a new character reference node.
2510 * Returns a pointer to the new node object.
2511 */
2512xmlNodePtr
2513xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2514 xmlNodePtr cur;
2515
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002516 if (name == NULL)
2517 return(NULL);
2518
Owen Taylor3473f882001-02-23 17:55:21 +00002519 /*
2520 * Allocate a new node and fill the fields.
2521 */
2522 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2523 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002524 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002525 return(NULL);
2526 }
2527 memset(cur, 0, sizeof(xmlNode));
2528 cur->type = XML_ENTITY_REF_NODE;
2529
2530 cur->doc = doc;
2531 if (name[0] == '&') {
2532 int len;
2533 name++;
2534 len = xmlStrlen(name);
2535 if (name[len - 1] == ';')
2536 cur->name = xmlStrndup(name, len - 1);
2537 else
2538 cur->name = xmlStrndup(name, len);
2539 } else
2540 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002541
Daniel Veillarda880b122003-04-21 21:36:41 +00002542 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002543 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002544 return(cur);
2545}
2546
2547/**
2548 * xmlNewReference:
2549 * @doc: the document
2550 * @name: the reference name, or the reference string with & and ;
2551 *
2552 * Creation of a new reference node.
2553 * Returns a pointer to the new node object.
2554 */
2555xmlNodePtr
2556xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2557 xmlNodePtr cur;
2558 xmlEntityPtr ent;
2559
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002560 if (name == NULL)
2561 return(NULL);
2562
Owen Taylor3473f882001-02-23 17:55:21 +00002563 /*
2564 * Allocate a new node and fill the fields.
2565 */
2566 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2567 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002568 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002569 return(NULL);
2570 }
2571 memset(cur, 0, sizeof(xmlNode));
2572 cur->type = XML_ENTITY_REF_NODE;
2573
2574 cur->doc = doc;
2575 if (name[0] == '&') {
2576 int len;
2577 name++;
2578 len = xmlStrlen(name);
2579 if (name[len - 1] == ';')
2580 cur->name = xmlStrndup(name, len - 1);
2581 else
2582 cur->name = xmlStrndup(name, len);
2583 } else
2584 cur->name = xmlStrdup(name);
2585
2586 ent = xmlGetDocEntity(doc, cur->name);
2587 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002588 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002589 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002590 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002591 * updated. Not sure if this is 100% correct.
2592 * -George
2593 */
2594 cur->children = (xmlNodePtr) ent;
2595 cur->last = (xmlNodePtr) ent;
2596 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002597
Daniel Veillarda880b122003-04-21 21:36:41 +00002598 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002599 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002600 return(cur);
2601}
2602
2603/**
2604 * xmlNewDocText:
2605 * @doc: the document
2606 * @content: the text content
2607 *
2608 * Creation of a new text node within a document.
2609 * Returns a pointer to the new node object.
2610 */
2611xmlNodePtr
2612xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2613 xmlNodePtr cur;
2614
2615 cur = xmlNewText(content);
2616 if (cur != NULL) cur->doc = doc;
2617 return(cur);
2618}
2619
2620/**
2621 * xmlNewTextLen:
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 parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002626 * Returns a pointer to the new node object.
2627 */
2628xmlNodePtr
2629xmlNewTextLen(const xmlChar *content, int len) {
2630 xmlNodePtr cur;
2631
2632 /*
2633 * Allocate a new node and fill the fields.
2634 */
2635 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2636 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002637 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002638 return(NULL);
2639 }
2640 memset(cur, 0, sizeof(xmlNode));
2641 cur->type = XML_TEXT_NODE;
2642
2643 cur->name = xmlStringText;
2644 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002645 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002646 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002647
Daniel Veillarda880b122003-04-21 21:36:41 +00002648 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002649 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002650 return(cur);
2651}
2652
2653/**
2654 * xmlNewDocTextLen:
2655 * @doc: the document
2656 * @content: the text content
2657 * @len: the text len.
2658 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002659 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002660 * text node pertain to a given document.
2661 * Returns a pointer to the new node object.
2662 */
2663xmlNodePtr
2664xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2665 xmlNodePtr cur;
2666
2667 cur = xmlNewTextLen(content, len);
2668 if (cur != NULL) cur->doc = doc;
2669 return(cur);
2670}
2671
2672/**
2673 * xmlNewComment:
2674 * @content: the comment content
2675 *
2676 * Creation of a new node containing a comment.
2677 * Returns a pointer to the new node object.
2678 */
2679xmlNodePtr
2680xmlNewComment(const xmlChar *content) {
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 comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002689 return(NULL);
2690 }
2691 memset(cur, 0, sizeof(xmlNode));
2692 cur->type = XML_COMMENT_NODE;
2693
2694 cur->name = xmlStringComment;
2695 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002696 cur->content = xmlStrdup(content);
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 * xmlNewCDataBlock:
2706 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002707 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002708 * @len: the length of the block
2709 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002710 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002711 * Returns a pointer to the new node object.
2712 */
2713xmlNodePtr
2714xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2715 xmlNodePtr cur;
2716
2717 /*
2718 * Allocate a new node and fill the fields.
2719 */
2720 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2721 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002722 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002723 return(NULL);
2724 }
2725 memset(cur, 0, sizeof(xmlNode));
2726 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002727 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002728
2729 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002730 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002731 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002732
Daniel Veillarda880b122003-04-21 21:36:41 +00002733 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002734 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002735 return(cur);
2736}
2737
2738/**
2739 * xmlNewDocComment:
2740 * @doc: the document
2741 * @content: the comment content
2742 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002743 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002744 * Returns a pointer to the new node object.
2745 */
2746xmlNodePtr
2747xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2748 xmlNodePtr cur;
2749
2750 cur = xmlNewComment(content);
2751 if (cur != NULL) cur->doc = doc;
2752 return(cur);
2753}
2754
2755/**
2756 * xmlSetTreeDoc:
2757 * @tree: the top element
2758 * @doc: the document
2759 *
2760 * update all nodes under the tree to point to the right document
2761 */
2762void
2763xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002764 xmlAttrPtr prop;
2765
Owen Taylor3473f882001-02-23 17:55:21 +00002766 if (tree == NULL)
2767 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002768 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002769 if(tree->type == XML_ELEMENT_NODE) {
2770 prop = tree->properties;
2771 while (prop != NULL) {
2772 prop->doc = doc;
2773 xmlSetListDoc(prop->children, doc);
2774 prop = prop->next;
2775 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002776 }
Owen Taylor3473f882001-02-23 17:55:21 +00002777 if (tree->children != NULL)
2778 xmlSetListDoc(tree->children, doc);
2779 tree->doc = doc;
2780 }
2781}
2782
2783/**
2784 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002785 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002786 * @doc: the document
2787 *
2788 * update all nodes in the list to point to the right document
2789 */
2790void
2791xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2792 xmlNodePtr cur;
2793
2794 if (list == NULL)
2795 return;
2796 cur = list;
2797 while (cur != NULL) {
2798 if (cur->doc != doc)
2799 xmlSetTreeDoc(cur, doc);
2800 cur = cur->next;
2801 }
2802}
2803
Daniel Veillard2156d432004-03-04 15:59:36 +00002804#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002805/**
2806 * xmlNewChild:
2807 * @parent: the parent node
2808 * @ns: a namespace if any
2809 * @name: the name of the child
2810 * @content: the XML content of the child if any.
2811 *
2812 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002813 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2814 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002815 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002816 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2817 * references. XML special chars must be escaped first by using
2818 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002819 *
2820 * Returns a pointer to the new node object.
2821 */
2822xmlNodePtr
2823xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2824 const xmlChar *name, const xmlChar *content) {
2825 xmlNodePtr cur, prev;
2826
2827 if (parent == NULL) {
2828#ifdef DEBUG_TREE
2829 xmlGenericError(xmlGenericErrorContext,
2830 "xmlNewChild : parent == NULL\n");
2831#endif
2832 return(NULL);
2833 }
2834
2835 if (name == NULL) {
2836#ifdef DEBUG_TREE
2837 xmlGenericError(xmlGenericErrorContext,
2838 "xmlNewChild : name == NULL\n");
2839#endif
2840 return(NULL);
2841 }
2842
2843 /*
2844 * Allocate a new node
2845 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002846 if (parent->type == XML_ELEMENT_NODE) {
2847 if (ns == NULL)
2848 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2849 else
2850 cur = xmlNewDocNode(parent->doc, ns, name, content);
2851 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2852 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2853 if (ns == NULL)
2854 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2855 else
2856 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002857 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2858 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002859 } else {
2860 return(NULL);
2861 }
Owen Taylor3473f882001-02-23 17:55:21 +00002862 if (cur == NULL) return(NULL);
2863
2864 /*
2865 * add the new element at the end of the children list.
2866 */
2867 cur->type = XML_ELEMENT_NODE;
2868 cur->parent = parent;
2869 cur->doc = parent->doc;
2870 if (parent->children == NULL) {
2871 parent->children = cur;
2872 parent->last = cur;
2873 } else {
2874 prev = parent->last;
2875 prev->next = cur;
2876 cur->prev = prev;
2877 parent->last = cur;
2878 }
2879
2880 return(cur);
2881}
Daniel Veillard652327a2003-09-29 18:02:38 +00002882#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002883
2884/**
2885 * xmlAddNextSibling:
2886 * @cur: the child node
2887 * @elem: the new node
2888 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002889 * Add a new node @elem as the next sibling of @cur
2890 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002891 * first unlinked from its existing context.
2892 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002893 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2894 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002895 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002896 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002897 */
2898xmlNodePtr
2899xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2900 if (cur == NULL) {
2901#ifdef DEBUG_TREE
2902 xmlGenericError(xmlGenericErrorContext,
2903 "xmlAddNextSibling : cur == NULL\n");
2904#endif
2905 return(NULL);
2906 }
2907 if (elem == NULL) {
2908#ifdef DEBUG_TREE
2909 xmlGenericError(xmlGenericErrorContext,
2910 "xmlAddNextSibling : elem == NULL\n");
2911#endif
2912 return(NULL);
2913 }
2914
2915 xmlUnlinkNode(elem);
2916
2917 if (elem->type == XML_TEXT_NODE) {
2918 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002919 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002920 xmlFreeNode(elem);
2921 return(cur);
2922 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002923 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2924 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002925 xmlChar *tmp;
2926
2927 tmp = xmlStrdup(elem->content);
2928 tmp = xmlStrcat(tmp, cur->next->content);
2929 xmlNodeSetContent(cur->next, tmp);
2930 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002931 xmlFreeNode(elem);
2932 return(cur->next);
2933 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002934 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2935 /* check if an attribute with the same name exists */
2936 xmlAttrPtr attr;
2937
2938 if (elem->ns == NULL)
2939 attr = xmlHasProp(cur->parent, elem->name);
2940 else
2941 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2942 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2943 /* different instance, destroy it (attributes must be unique) */
2944 xmlFreeProp(attr);
2945 }
Owen Taylor3473f882001-02-23 17:55:21 +00002946 }
2947
2948 if (elem->doc != cur->doc) {
2949 xmlSetTreeDoc(elem, cur->doc);
2950 }
2951 elem->parent = cur->parent;
2952 elem->prev = cur;
2953 elem->next = cur->next;
2954 cur->next = elem;
2955 if (elem->next != NULL)
2956 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002957 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002958 elem->parent->last = elem;
2959 return(elem);
2960}
2961
Daniel Veillard2156d432004-03-04 15:59:36 +00002962#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002963/**
2964 * xmlAddPrevSibling:
2965 * @cur: the child node
2966 * @elem: the new node
2967 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002968 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002969 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002970 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002971 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002972 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2973 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002974 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002975 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002976 */
2977xmlNodePtr
2978xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2979 if (cur == NULL) {
2980#ifdef DEBUG_TREE
2981 xmlGenericError(xmlGenericErrorContext,
2982 "xmlAddPrevSibling : cur == NULL\n");
2983#endif
2984 return(NULL);
2985 }
2986 if (elem == NULL) {
2987#ifdef DEBUG_TREE
2988 xmlGenericError(xmlGenericErrorContext,
2989 "xmlAddPrevSibling : elem == NULL\n");
2990#endif
2991 return(NULL);
2992 }
2993
2994 xmlUnlinkNode(elem);
2995
2996 if (elem->type == XML_TEXT_NODE) {
2997 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002998 xmlChar *tmp;
2999
3000 tmp = xmlStrdup(elem->content);
3001 tmp = xmlStrcat(tmp, cur->content);
3002 xmlNodeSetContent(cur, tmp);
3003 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00003004 xmlFreeNode(elem);
3005 return(cur);
3006 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00003007 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
3008 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003009 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003010 xmlFreeNode(elem);
3011 return(cur->prev);
3012 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003013 } else if (elem->type == XML_ATTRIBUTE_NODE) {
3014 /* check if an attribute with the same name exists */
3015 xmlAttrPtr attr;
3016
3017 if (elem->ns == NULL)
3018 attr = xmlHasProp(cur->parent, elem->name);
3019 else
3020 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
3021 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
3022 /* different instance, destroy it (attributes must be unique) */
3023 xmlFreeProp(attr);
3024 }
Owen Taylor3473f882001-02-23 17:55:21 +00003025 }
3026
3027 if (elem->doc != cur->doc) {
3028 xmlSetTreeDoc(elem, cur->doc);
3029 }
3030 elem->parent = cur->parent;
3031 elem->next = cur;
3032 elem->prev = cur->prev;
3033 cur->prev = elem;
3034 if (elem->prev != NULL)
3035 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003036 if (elem->parent != NULL) {
3037 if (elem->type == XML_ATTRIBUTE_NODE) {
3038 if (elem->parent->properties == (xmlAttrPtr) cur) {
3039 elem->parent->properties = (xmlAttrPtr) elem;
3040 }
3041 } else {
3042 if (elem->parent->children == cur) {
3043 elem->parent->children = elem;
3044 }
3045 }
3046 }
Owen Taylor3473f882001-02-23 17:55:21 +00003047 return(elem);
3048}
Daniel Veillard652327a2003-09-29 18:02:38 +00003049#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003050
3051/**
3052 * xmlAddSibling:
3053 * @cur: the child node
3054 * @elem: the new node
3055 *
3056 * Add a new element @elem to the list of siblings of @cur
3057 * merging adjacent TEXT nodes (@elem may be freed)
3058 * If the new element was already inserted in a document it is
3059 * first unlinked from its existing context.
3060 *
3061 * Returns the new element or NULL in case of error.
3062 */
3063xmlNodePtr
3064xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
3065 xmlNodePtr parent;
3066
3067 if (cur == NULL) {
3068#ifdef DEBUG_TREE
3069 xmlGenericError(xmlGenericErrorContext,
3070 "xmlAddSibling : cur == NULL\n");
3071#endif
3072 return(NULL);
3073 }
3074
3075 if (elem == NULL) {
3076#ifdef DEBUG_TREE
3077 xmlGenericError(xmlGenericErrorContext,
3078 "xmlAddSibling : elem == NULL\n");
3079#endif
3080 return(NULL);
3081 }
3082
3083 /*
3084 * Constant time is we can rely on the ->parent->last to find
3085 * the last sibling.
3086 */
3087 if ((cur->parent != NULL) &&
3088 (cur->parent->children != NULL) &&
3089 (cur->parent->last != NULL) &&
3090 (cur->parent->last->next == NULL)) {
3091 cur = cur->parent->last;
3092 } else {
3093 while (cur->next != NULL) cur = cur->next;
3094 }
3095
3096 xmlUnlinkNode(elem);
3097
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003098 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3099 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003100 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003101 xmlFreeNode(elem);
3102 return(cur);
3103 }
3104
3105 if (elem->doc != cur->doc) {
3106 xmlSetTreeDoc(elem, cur->doc);
3107 }
3108 parent = cur->parent;
3109 elem->prev = cur;
3110 elem->next = NULL;
3111 elem->parent = parent;
3112 cur->next = elem;
3113 if (parent != NULL)
3114 parent->last = elem;
3115
3116 return(elem);
3117}
3118
3119/**
3120 * xmlAddChildList:
3121 * @parent: the parent node
3122 * @cur: the first node in the list
3123 *
3124 * Add a list of node at the end of the child list of the parent
3125 * merging adjacent TEXT nodes (@cur may be freed)
3126 *
3127 * Returns the last child or NULL in case of error.
3128 */
3129xmlNodePtr
3130xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3131 xmlNodePtr prev;
3132
3133 if (parent == NULL) {
3134#ifdef DEBUG_TREE
3135 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003136 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003137#endif
3138 return(NULL);
3139 }
3140
3141 if (cur == NULL) {
3142#ifdef DEBUG_TREE
3143 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003144 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003145#endif
3146 return(NULL);
3147 }
3148
3149 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3150 (cur->doc != parent->doc)) {
3151#ifdef DEBUG_TREE
3152 xmlGenericError(xmlGenericErrorContext,
3153 "Elements moved to a different document\n");
3154#endif
3155 }
3156
3157 /*
3158 * add the first element at the end of the children list.
3159 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003160
Owen Taylor3473f882001-02-23 17:55:21 +00003161 if (parent->children == NULL) {
3162 parent->children = cur;
3163 } else {
3164 /*
3165 * If cur and parent->last both are TEXT nodes, then merge them.
3166 */
3167 if ((cur->type == XML_TEXT_NODE) &&
3168 (parent->last->type == XML_TEXT_NODE) &&
3169 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003170 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003171 /*
3172 * if it's the only child, nothing more to be done.
3173 */
3174 if (cur->next == NULL) {
3175 xmlFreeNode(cur);
3176 return(parent->last);
3177 }
3178 prev = cur;
3179 cur = cur->next;
3180 xmlFreeNode(prev);
3181 }
3182 prev = parent->last;
3183 prev->next = cur;
3184 cur->prev = prev;
3185 }
3186 while (cur->next != NULL) {
3187 cur->parent = parent;
3188 if (cur->doc != parent->doc) {
3189 xmlSetTreeDoc(cur, parent->doc);
3190 }
3191 cur = cur->next;
3192 }
3193 cur->parent = parent;
3194 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3195 parent->last = cur;
3196
3197 return(cur);
3198}
3199
3200/**
3201 * xmlAddChild:
3202 * @parent: the parent node
3203 * @cur: the child node
3204 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003205 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003206 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003207 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3208 * If there is an attribute with equal name, it is first destroyed.
3209 *
Owen Taylor3473f882001-02-23 17:55:21 +00003210 * Returns the child or NULL in case of error.
3211 */
3212xmlNodePtr
3213xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3214 xmlNodePtr prev;
3215
3216 if (parent == NULL) {
3217#ifdef DEBUG_TREE
3218 xmlGenericError(xmlGenericErrorContext,
3219 "xmlAddChild : parent == NULL\n");
3220#endif
3221 return(NULL);
3222 }
3223
3224 if (cur == NULL) {
3225#ifdef DEBUG_TREE
3226 xmlGenericError(xmlGenericErrorContext,
3227 "xmlAddChild : child == NULL\n");
3228#endif
3229 return(NULL);
3230 }
3231
Owen Taylor3473f882001-02-23 17:55:21 +00003232 /*
3233 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003234 * cur is then freed.
3235 */
3236 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003237 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003238 (parent->content != NULL) &&
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003239 (parent->name == cur->name) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003240 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003241 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003242 xmlFreeNode(cur);
3243 return(parent);
3244 }
3245 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003246 (parent->last->name == cur->name) &&
3247 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003248 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003249 xmlFreeNode(cur);
3250 return(parent->last);
3251 }
3252 }
3253
3254 /*
3255 * add the new element at the end of the children list.
3256 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003257 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003258 cur->parent = parent;
3259 if (cur->doc != parent->doc) {
3260 xmlSetTreeDoc(cur, parent->doc);
3261 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003262 /* this check prevents a loop on tree-traversions if a developer
3263 * tries to add a node to its parent multiple times
3264 */
3265 if (prev == parent)
3266 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003267
3268 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003269 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003270 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003271 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003272 (parent->content != NULL) &&
3273 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003274 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003275 xmlFreeNode(cur);
3276 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003277 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003278 if (cur->type == XML_ATTRIBUTE_NODE) {
3279 if (parent->properties == NULL) {
3280 parent->properties = (xmlAttrPtr) cur;
3281 } else {
3282 /* check if an attribute with the same name exists */
3283 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003284
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003285 if (cur->ns == NULL)
3286 lastattr = xmlHasProp(parent, cur->name);
3287 else
3288 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3289 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3290 /* different instance, destroy it (attributes must be unique) */
3291 xmlFreeProp(lastattr);
3292 }
3293 /* find the end */
3294 lastattr = parent->properties;
3295 while (lastattr->next != NULL) {
3296 lastattr = lastattr->next;
3297 }
3298 lastattr->next = (xmlAttrPtr) cur;
3299 ((xmlAttrPtr) cur)->prev = lastattr;
3300 }
3301 } else {
3302 if (parent->children == NULL) {
3303 parent->children = cur;
3304 parent->last = cur;
3305 } else {
3306 prev = parent->last;
3307 prev->next = cur;
3308 cur->prev = prev;
3309 parent->last = cur;
3310 }
3311 }
Owen Taylor3473f882001-02-23 17:55:21 +00003312 return(cur);
3313}
3314
3315/**
3316 * xmlGetLastChild:
3317 * @parent: the parent node
3318 *
3319 * Search the last child of a node.
3320 * Returns the last child or NULL if none.
3321 */
3322xmlNodePtr
3323xmlGetLastChild(xmlNodePtr parent) {
3324 if (parent == NULL) {
3325#ifdef DEBUG_TREE
3326 xmlGenericError(xmlGenericErrorContext,
3327 "xmlGetLastChild : parent == NULL\n");
3328#endif
3329 return(NULL);
3330 }
3331 return(parent->last);
3332}
3333
3334/**
3335 * xmlFreeNodeList:
3336 * @cur: the first node in the list
3337 *
3338 * Free a node and all its siblings, this is a recursive behaviour, all
3339 * the children are freed too.
3340 */
3341void
3342xmlFreeNodeList(xmlNodePtr cur) {
3343 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003344 xmlDictPtr dict = NULL;
3345
3346 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003347 if (cur->type == XML_NAMESPACE_DECL) {
3348 xmlFreeNsList((xmlNsPtr) cur);
3349 return;
3350 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003351 if ((cur->type == XML_DOCUMENT_NODE) ||
3352#ifdef LIBXML_DOCB_ENABLED
3353 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003354#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003355 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003356 xmlFreeDoc((xmlDocPtr) cur);
3357 return;
3358 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003359 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003360 while (cur != NULL) {
3361 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003362 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003363
Daniel Veillarda880b122003-04-21 21:36:41 +00003364 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003365 xmlDeregisterNodeDefaultValue(cur);
3366
Daniel Veillard02141ea2001-04-30 11:46:40 +00003367 if ((cur->children != NULL) &&
3368 (cur->type != XML_ENTITY_REF_NODE))
3369 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003370 if (((cur->type == XML_ELEMENT_NODE) ||
3371 (cur->type == XML_XINCLUDE_START) ||
3372 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003373 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003374 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003375 if ((cur->type != XML_ELEMENT_NODE) &&
3376 (cur->type != XML_XINCLUDE_START) &&
3377 (cur->type != XML_XINCLUDE_END) &&
3378 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003379 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003380 }
3381 if (((cur->type == XML_ELEMENT_NODE) ||
3382 (cur->type == XML_XINCLUDE_START) ||
3383 (cur->type == XML_XINCLUDE_END)) &&
3384 (cur->nsDef != NULL))
3385 xmlFreeNsList(cur->nsDef);
3386
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003387 /*
3388 * When a node is a text node or a comment, it uses a global static
3389 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003390 * Otherwise the node name might come from the document's
3391 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003392 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003393 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003394 (cur->type != XML_TEXT_NODE) &&
3395 (cur->type != XML_COMMENT_NODE))
3396 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003397 xmlFree(cur);
3398 }
Owen Taylor3473f882001-02-23 17:55:21 +00003399 cur = next;
3400 }
3401}
3402
3403/**
3404 * xmlFreeNode:
3405 * @cur: the node
3406 *
3407 * Free a node, this is a recursive behaviour, all the children are freed too.
3408 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3409 */
3410void
3411xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003412 xmlDictPtr dict = NULL;
3413
3414 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003415
Daniel Veillard02141ea2001-04-30 11:46:40 +00003416 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003417 if (cur->type == XML_DTD_NODE) {
3418 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003419 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003420 }
3421 if (cur->type == XML_NAMESPACE_DECL) {
3422 xmlFreeNs((xmlNsPtr) cur);
3423 return;
3424 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003425 if (cur->type == XML_ATTRIBUTE_NODE) {
3426 xmlFreeProp((xmlAttrPtr) cur);
3427 return;
3428 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003429
Daniel Veillarda880b122003-04-21 21:36:41 +00003430 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003431 xmlDeregisterNodeDefaultValue(cur);
3432
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003433 if (cur->doc != NULL) dict = cur->doc->dict;
3434
Owen Taylor3473f882001-02-23 17:55:21 +00003435 if ((cur->children != NULL) &&
3436 (cur->type != XML_ENTITY_REF_NODE))
3437 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003438 if (((cur->type == XML_ELEMENT_NODE) ||
3439 (cur->type == XML_XINCLUDE_START) ||
3440 (cur->type == XML_XINCLUDE_END)) &&
3441 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003442 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003443 if ((cur->type != XML_ELEMENT_NODE) &&
3444 (cur->content != NULL) &&
3445 (cur->type != XML_ENTITY_REF_NODE) &&
3446 (cur->type != XML_XINCLUDE_END) &&
3447 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003448 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003449 }
3450
Daniel Veillardacd370f2001-06-09 17:17:51 +00003451 /*
3452 * When a node is a text node or a comment, it uses a global static
3453 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003454 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003455 */
Owen Taylor3473f882001-02-23 17:55:21 +00003456 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003457 (cur->type != XML_TEXT_NODE) &&
3458 (cur->type != XML_COMMENT_NODE))
3459 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003460
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003461 if (((cur->type == XML_ELEMENT_NODE) ||
3462 (cur->type == XML_XINCLUDE_START) ||
3463 (cur->type == XML_XINCLUDE_END)) &&
3464 (cur->nsDef != NULL))
3465 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003466 xmlFree(cur);
3467}
3468
3469/**
3470 * xmlUnlinkNode:
3471 * @cur: the node
3472 *
3473 * Unlink a node from it's current context, the node is not freed
3474 */
3475void
3476xmlUnlinkNode(xmlNodePtr cur) {
3477 if (cur == NULL) {
3478#ifdef DEBUG_TREE
3479 xmlGenericError(xmlGenericErrorContext,
3480 "xmlUnlinkNode : node == NULL\n");
3481#endif
3482 return;
3483 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003484 if (cur->type == XML_DTD_NODE) {
3485 xmlDocPtr doc;
3486 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003487 if (doc != NULL) {
3488 if (doc->intSubset == (xmlDtdPtr) cur)
3489 doc->intSubset = NULL;
3490 if (doc->extSubset == (xmlDtdPtr) cur)
3491 doc->extSubset = NULL;
3492 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003493 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003494 if (cur->parent != NULL) {
3495 xmlNodePtr parent;
3496 parent = cur->parent;
3497 if (cur->type == XML_ATTRIBUTE_NODE) {
3498 if (parent->properties == (xmlAttrPtr) cur)
3499 parent->properties = ((xmlAttrPtr) cur)->next;
3500 } else {
3501 if (parent->children == cur)
3502 parent->children = cur->next;
3503 if (parent->last == cur)
3504 parent->last = cur->prev;
3505 }
3506 cur->parent = NULL;
3507 }
Owen Taylor3473f882001-02-23 17:55:21 +00003508 if (cur->next != NULL)
3509 cur->next->prev = cur->prev;
3510 if (cur->prev != NULL)
3511 cur->prev->next = cur->next;
3512 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003513}
3514
Daniel Veillard2156d432004-03-04 15:59:36 +00003515#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003516/**
3517 * xmlReplaceNode:
3518 * @old: the old node
3519 * @cur: the node
3520 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003521 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003522 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003523 * first unlinked from its existing context.
3524 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003525 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003526 */
3527xmlNodePtr
3528xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
Daniel Veillarda03e3652004-11-02 18:45:30 +00003529 if ((old == NULL) || (old->parent == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003530#ifdef DEBUG_TREE
3531 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda03e3652004-11-02 18:45:30 +00003532 "xmlReplaceNode : old == NULL or without parent\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003533#endif
3534 return(NULL);
3535 }
3536 if (cur == NULL) {
3537 xmlUnlinkNode(old);
3538 return(old);
3539 }
3540 if (cur == old) {
3541 return(old);
3542 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003543 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3544#ifdef DEBUG_TREE
3545 xmlGenericError(xmlGenericErrorContext,
3546 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3547#endif
3548 return(old);
3549 }
3550 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3551#ifdef DEBUG_TREE
3552 xmlGenericError(xmlGenericErrorContext,
3553 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3554#endif
3555 return(old);
3556 }
Owen Taylor3473f882001-02-23 17:55:21 +00003557 xmlUnlinkNode(cur);
3558 cur->doc = old->doc;
3559 cur->parent = old->parent;
3560 cur->next = old->next;
3561 if (cur->next != NULL)
3562 cur->next->prev = cur;
3563 cur->prev = old->prev;
3564 if (cur->prev != NULL)
3565 cur->prev->next = cur;
3566 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003567 if (cur->type == XML_ATTRIBUTE_NODE) {
3568 if (cur->parent->properties == (xmlAttrPtr)old)
3569 cur->parent->properties = ((xmlAttrPtr) cur);
3570 } else {
3571 if (cur->parent->children == old)
3572 cur->parent->children = cur;
3573 if (cur->parent->last == old)
3574 cur->parent->last = cur;
3575 }
Owen Taylor3473f882001-02-23 17:55:21 +00003576 }
3577 old->next = old->prev = NULL;
3578 old->parent = NULL;
3579 return(old);
3580}
Daniel Veillard652327a2003-09-29 18:02:38 +00003581#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003582
3583/************************************************************************
3584 * *
3585 * Copy operations *
3586 * *
3587 ************************************************************************/
3588
3589/**
3590 * xmlCopyNamespace:
3591 * @cur: the namespace
3592 *
3593 * Do a copy of the namespace.
3594 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003595 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003596 */
3597xmlNsPtr
3598xmlCopyNamespace(xmlNsPtr cur) {
3599 xmlNsPtr ret;
3600
3601 if (cur == NULL) return(NULL);
3602 switch (cur->type) {
3603 case XML_LOCAL_NAMESPACE:
3604 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3605 break;
3606 default:
3607#ifdef DEBUG_TREE
3608 xmlGenericError(xmlGenericErrorContext,
3609 "xmlCopyNamespace: invalid type %d\n", cur->type);
3610#endif
3611 return(NULL);
3612 }
3613 return(ret);
3614}
3615
3616/**
3617 * xmlCopyNamespaceList:
3618 * @cur: the first namespace
3619 *
3620 * Do a copy of an namespace list.
3621 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003622 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003623 */
3624xmlNsPtr
3625xmlCopyNamespaceList(xmlNsPtr cur) {
3626 xmlNsPtr ret = NULL;
3627 xmlNsPtr p = NULL,q;
3628
3629 while (cur != NULL) {
3630 q = xmlCopyNamespace(cur);
3631 if (p == NULL) {
3632 ret = p = q;
3633 } else {
3634 p->next = q;
3635 p = q;
3636 }
3637 cur = cur->next;
3638 }
3639 return(ret);
3640}
3641
3642static xmlNodePtr
3643xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3644/**
3645 * xmlCopyProp:
3646 * @target: the element where the attribute will be grafted
3647 * @cur: the attribute
3648 *
3649 * Do a copy of the attribute.
3650 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003651 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003652 */
3653xmlAttrPtr
3654xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3655 xmlAttrPtr ret;
3656
3657 if (cur == NULL) return(NULL);
3658 if (target != NULL)
3659 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3660 else if (cur->parent != NULL)
3661 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3662 else if (cur->children != NULL)
3663 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3664 else
3665 ret = xmlNewDocProp(NULL, cur->name, NULL);
3666 if (ret == NULL) return(NULL);
3667 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003668
Owen Taylor3473f882001-02-23 17:55:21 +00003669 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003670 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003671
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003672 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3673 if (ns == NULL) {
3674 /*
3675 * Humm, we are copying an element whose namespace is defined
3676 * out of the new tree scope. Search it in the original tree
3677 * and add it at the top of the new tree
3678 */
3679 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3680 if (ns != NULL) {
3681 xmlNodePtr root = target;
3682 xmlNodePtr pred = NULL;
3683
3684 while (root->parent != NULL) {
3685 pred = root;
3686 root = root->parent;
3687 }
3688 if (root == (xmlNodePtr) target->doc) {
3689 /* correct possibly cycling above the document elt */
3690 root = pred;
3691 }
3692 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3693 }
3694 } else {
3695 /*
3696 * we have to find something appropriate here since
3697 * we cant be sure, that the namespce we found is identified
3698 * by the prefix
3699 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003700 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003701 /* this is the nice case */
3702 ret->ns = ns;
3703 } else {
3704 /*
3705 * we are in trouble: we need a new reconcilied namespace.
3706 * This is expensive
3707 */
3708 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3709 }
3710 }
3711
Owen Taylor3473f882001-02-23 17:55:21 +00003712 } else
3713 ret->ns = NULL;
3714
3715 if (cur->children != NULL) {
3716 xmlNodePtr tmp;
3717
3718 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3719 ret->last = NULL;
3720 tmp = ret->children;
3721 while (tmp != NULL) {
3722 /* tmp->parent = (xmlNodePtr)ret; */
3723 if (tmp->next == NULL)
3724 ret->last = tmp;
3725 tmp = tmp->next;
3726 }
3727 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003728 /*
3729 * Try to handle IDs
3730 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003731 if ((target!= NULL) && (cur!= NULL) &&
3732 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003733 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3734 if (xmlIsID(cur->doc, cur->parent, cur)) {
3735 xmlChar *id;
3736
3737 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3738 if (id != NULL) {
3739 xmlAddID(NULL, target->doc, id, ret);
3740 xmlFree(id);
3741 }
3742 }
3743 }
Owen Taylor3473f882001-02-23 17:55:21 +00003744 return(ret);
3745}
3746
3747/**
3748 * xmlCopyPropList:
3749 * @target: the element where the attributes will be grafted
3750 * @cur: the first attribute
3751 *
3752 * Do a copy of an attribute list.
3753 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003754 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003755 */
3756xmlAttrPtr
3757xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3758 xmlAttrPtr ret = NULL;
3759 xmlAttrPtr p = NULL,q;
3760
3761 while (cur != NULL) {
3762 q = xmlCopyProp(target, cur);
William M. Brack13dfa872004-09-18 04:52:08 +00003763 if (q == NULL)
3764 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003765 if (p == NULL) {
3766 ret = p = q;
3767 } else {
3768 p->next = q;
3769 q->prev = p;
3770 p = q;
3771 }
3772 cur = cur->next;
3773 }
3774 return(ret);
3775}
3776
3777/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003778 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003779 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003780 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003781 * tricky reason: namespaces. Doing a direct copy of a node
3782 * say RPM:Copyright without changing the namespace pointer to
3783 * something else can produce stale links. One way to do it is
3784 * to keep a reference counter but this doesn't work as soon
3785 * as one move the element or the subtree out of the scope of
3786 * the existing namespace. The actual solution seems to add
3787 * a copy of the namespace at the top of the copied tree if
3788 * not available in the subtree.
3789 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00003790 * The argument "recursive" normally indicates a recursive copy
3791 * of the node with values 0 (no) and 1 (yes). For XInclude,
3792 * however, we allow a value of 2 to indicate copy properties and
3793 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00003794 */
3795
3796static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003797xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00003798 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003799 xmlNodePtr ret;
3800
3801 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003802 switch (node->type) {
3803 case XML_TEXT_NODE:
3804 case XML_CDATA_SECTION_NODE:
3805 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003806 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003807 case XML_ENTITY_REF_NODE:
3808 case XML_ENTITY_NODE:
3809 case XML_PI_NODE:
3810 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003811 case XML_XINCLUDE_START:
3812 case XML_XINCLUDE_END:
3813 break;
3814 case XML_ATTRIBUTE_NODE:
3815 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3816 case XML_NAMESPACE_DECL:
3817 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3818
Daniel Veillard39196eb2001-06-19 18:09:42 +00003819 case XML_DOCUMENT_NODE:
3820 case XML_HTML_DOCUMENT_NODE:
3821#ifdef LIBXML_DOCB_ENABLED
3822 case XML_DOCB_DOCUMENT_NODE:
3823#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003824#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00003825 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00003826#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003827 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003828 case XML_NOTATION_NODE:
3829 case XML_DTD_NODE:
3830 case XML_ELEMENT_DECL:
3831 case XML_ATTRIBUTE_DECL:
3832 case XML_ENTITY_DECL:
3833 return(NULL);
3834 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003835
Owen Taylor3473f882001-02-23 17:55:21 +00003836 /*
3837 * Allocate a new node and fill the fields.
3838 */
3839 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3840 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003841 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003842 return(NULL);
3843 }
3844 memset(ret, 0, sizeof(xmlNode));
3845 ret->type = node->type;
3846
3847 ret->doc = doc;
3848 ret->parent = parent;
3849 if (node->name == xmlStringText)
3850 ret->name = xmlStringText;
3851 else if (node->name == xmlStringTextNoenc)
3852 ret->name = xmlStringTextNoenc;
3853 else if (node->name == xmlStringComment)
3854 ret->name = xmlStringComment;
Daniel Veillard03a53c32004-10-26 16:06:51 +00003855 else if (node->name != NULL) {
3856 if ((doc != NULL) && (doc->dict != NULL))
3857 ret->name = xmlDictLookup(doc->dict, node->name, -1);
3858 else
3859 ret->name = xmlStrdup(node->name);
3860 }
Daniel Veillard7db37732001-07-12 01:20:08 +00003861 if ((node->type != XML_ELEMENT_NODE) &&
3862 (node->content != NULL) &&
3863 (node->type != XML_ENTITY_REF_NODE) &&
3864 (node->type != XML_XINCLUDE_END) &&
3865 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003866 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003867 }else{
3868 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003869 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003870 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003871 if (parent != NULL) {
3872 xmlNodePtr tmp;
3873
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003874 /*
3875 * this is a tricky part for the node register thing:
3876 * in case ret does get coalesced in xmlAddChild
3877 * the deregister-node callback is called; so we register ret now already
3878 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003879 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003880 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3881
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003882 tmp = xmlAddChild(parent, ret);
3883 /* node could have coalesced */
3884 if (tmp != ret)
3885 return(tmp);
3886 }
Owen Taylor3473f882001-02-23 17:55:21 +00003887
William M. Brack57e9e912004-03-09 16:19:02 +00003888 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003889 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003890 if (node->nsDef != NULL)
3891 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3892
3893 if (node->ns != NULL) {
3894 xmlNsPtr ns;
3895
3896 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3897 if (ns == NULL) {
3898 /*
3899 * Humm, we are copying an element whose namespace is defined
3900 * out of the new tree scope. Search it in the original tree
3901 * and add it at the top of the new tree
3902 */
3903 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3904 if (ns != NULL) {
3905 xmlNodePtr root = ret;
3906
3907 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003908 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003909 }
3910 } else {
3911 /*
3912 * reference the existing namespace definition in our own tree.
3913 */
3914 ret->ns = ns;
3915 }
3916 }
3917 if (node->properties != NULL)
3918 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003919 if (node->type == XML_ENTITY_REF_NODE) {
3920 if ((doc == NULL) || (node->doc != doc)) {
3921 /*
3922 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003923 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003924 * we cannot keep the reference. Try to find it in the
3925 * target document.
3926 */
3927 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3928 } else {
3929 ret->children = node->children;
3930 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003931 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00003932 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003933 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003934 UPDATE_LAST_CHILD_AND_PARENT(ret)
3935 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003936
3937out:
3938 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00003939 if ((parent == NULL) &&
3940 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003941 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003942 return(ret);
3943}
3944
3945static xmlNodePtr
3946xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3947 xmlNodePtr ret = NULL;
3948 xmlNodePtr p = NULL,q;
3949
3950 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003951#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003952 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003953 if (doc == NULL) {
3954 node = node->next;
3955 continue;
3956 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003957 if (doc->intSubset == NULL) {
3958 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3959 q->doc = doc;
3960 q->parent = parent;
3961 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003962 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003963 } else {
3964 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003965 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003966 }
3967 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003968#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003969 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003970 if (ret == NULL) {
3971 q->prev = NULL;
3972 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003973 } else if (p != q) {
3974 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003975 p->next = q;
3976 q->prev = p;
3977 p = q;
3978 }
3979 node = node->next;
3980 }
3981 return(ret);
3982}
3983
3984/**
3985 * xmlCopyNode:
3986 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00003987 * @extended: if 1 do a recursive copy (properties, namespaces and children
3988 * when applicable)
3989 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00003990 *
3991 * Do a copy of the node.
3992 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003993 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003994 */
3995xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003996xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003997 xmlNodePtr ret;
3998
William M. Brack57e9e912004-03-09 16:19:02 +00003999 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00004000 return(ret);
4001}
4002
4003/**
Daniel Veillard82daa812001-04-12 08:55:36 +00004004 * xmlDocCopyNode:
4005 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00004006 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004007 * @extended: if 1 do a recursive copy (properties, namespaces and children
4008 * when applicable)
4009 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00004010 *
4011 * Do a copy of the node to a given document.
4012 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004013 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00004014 */
4015xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00004016xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00004017 xmlNodePtr ret;
4018
William M. Brack57e9e912004-03-09 16:19:02 +00004019 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00004020 return(ret);
4021}
4022
4023/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00004024 * xmlDocCopyNodeList:
4025 * @doc: the target document
4026 * @node: the first node in the list.
4027 *
4028 * Do a recursive copy of the node list.
4029 *
4030 * Returns: a new #xmlNodePtr, or NULL in case of error.
4031 */
4032xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) {
4033 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
4034 return(ret);
4035}
4036
4037/**
Owen Taylor3473f882001-02-23 17:55:21 +00004038 * xmlCopyNodeList:
4039 * @node: the first node in the list.
4040 *
4041 * Do a recursive copy of the node list.
Daniel Veillard03a53c32004-10-26 16:06:51 +00004042 * Use xmlDocCopyNodeList() if possible to ensure string interning.
Owen Taylor3473f882001-02-23 17:55:21 +00004043 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004044 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004045 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00004046xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00004047 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
4048 return(ret);
4049}
4050
Daniel Veillard2156d432004-03-04 15:59:36 +00004051#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004052/**
Owen Taylor3473f882001-02-23 17:55:21 +00004053 * xmlCopyDtd:
4054 * @dtd: the dtd
4055 *
4056 * Do a copy of the dtd.
4057 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004058 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004059 */
4060xmlDtdPtr
4061xmlCopyDtd(xmlDtdPtr dtd) {
4062 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004063 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00004064
4065 if (dtd == NULL) return(NULL);
4066 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4067 if (ret == NULL) return(NULL);
4068 if (dtd->entities != NULL)
4069 ret->entities = (void *) xmlCopyEntitiesTable(
4070 (xmlEntitiesTablePtr) dtd->entities);
4071 if (dtd->notations != NULL)
4072 ret->notations = (void *) xmlCopyNotationTable(
4073 (xmlNotationTablePtr) dtd->notations);
4074 if (dtd->elements != NULL)
4075 ret->elements = (void *) xmlCopyElementTable(
4076 (xmlElementTablePtr) dtd->elements);
4077 if (dtd->attributes != NULL)
4078 ret->attributes = (void *) xmlCopyAttributeTable(
4079 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004080 if (dtd->pentities != NULL)
4081 ret->pentities = (void *) xmlCopyEntitiesTable(
4082 (xmlEntitiesTablePtr) dtd->pentities);
4083
4084 cur = dtd->children;
4085 while (cur != NULL) {
4086 q = NULL;
4087
4088 if (cur->type == XML_ENTITY_DECL) {
4089 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4090 switch (tmp->etype) {
4091 case XML_INTERNAL_GENERAL_ENTITY:
4092 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4093 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4094 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4095 break;
4096 case XML_INTERNAL_PARAMETER_ENTITY:
4097 case XML_EXTERNAL_PARAMETER_ENTITY:
4098 q = (xmlNodePtr)
4099 xmlGetParameterEntityFromDtd(ret, tmp->name);
4100 break;
4101 case XML_INTERNAL_PREDEFINED_ENTITY:
4102 break;
4103 }
4104 } else if (cur->type == XML_ELEMENT_DECL) {
4105 xmlElementPtr tmp = (xmlElementPtr) cur;
4106 q = (xmlNodePtr)
4107 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4108 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4109 xmlAttributePtr tmp = (xmlAttributePtr) cur;
4110 q = (xmlNodePtr)
4111 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4112 } else if (cur->type == XML_COMMENT_NODE) {
4113 q = xmlCopyNode(cur, 0);
4114 }
4115
4116 if (q == NULL) {
4117 cur = cur->next;
4118 continue;
4119 }
4120
4121 if (p == NULL)
4122 ret->children = q;
4123 else
4124 p->next = q;
4125
4126 q->prev = p;
4127 q->parent = (xmlNodePtr) ret;
4128 q->next = NULL;
4129 ret->last = q;
4130 p = q;
4131 cur = cur->next;
4132 }
4133
Owen Taylor3473f882001-02-23 17:55:21 +00004134 return(ret);
4135}
Daniel Veillard2156d432004-03-04 15:59:36 +00004136#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004137
Daniel Veillard2156d432004-03-04 15:59:36 +00004138#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004139/**
4140 * xmlCopyDoc:
4141 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004142 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004143 *
4144 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004145 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004146 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004147 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004148 */
4149xmlDocPtr
4150xmlCopyDoc(xmlDocPtr doc, int recursive) {
4151 xmlDocPtr ret;
4152
4153 if (doc == NULL) return(NULL);
4154 ret = xmlNewDoc(doc->version);
4155 if (ret == NULL) return(NULL);
4156 if (doc->name != NULL)
4157 ret->name = xmlMemStrdup(doc->name);
4158 if (doc->encoding != NULL)
4159 ret->encoding = xmlStrdup(doc->encoding);
4160 ret->charset = doc->charset;
4161 ret->compression = doc->compression;
4162 ret->standalone = doc->standalone;
4163 if (!recursive) return(ret);
4164
Daniel Veillardb33c2012001-04-25 12:59:04 +00004165 ret->last = NULL;
4166 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004167#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004168 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004169 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004170 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004171 ret->intSubset->parent = ret;
4172 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004173#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004174 if (doc->oldNs != NULL)
4175 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4176 if (doc->children != NULL) {
4177 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004178
4179 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4180 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004181 ret->last = NULL;
4182 tmp = ret->children;
4183 while (tmp != NULL) {
4184 if (tmp->next == NULL)
4185 ret->last = tmp;
4186 tmp = tmp->next;
4187 }
4188 }
4189 return(ret);
4190}
Daniel Veillard652327a2003-09-29 18:02:38 +00004191#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004192
4193/************************************************************************
4194 * *
4195 * Content access functions *
4196 * *
4197 ************************************************************************/
4198
4199/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004200 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004201 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004202 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004203 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004204 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004205 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004206 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004207 */
4208long
4209xmlGetLineNo(xmlNodePtr node)
4210{
4211 long result = -1;
4212
4213 if (!node)
4214 return result;
4215 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004216 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004217 else if ((node->prev != NULL) &&
4218 ((node->prev->type == XML_ELEMENT_NODE) ||
4219 (node->prev->type == XML_TEXT_NODE)))
4220 result = xmlGetLineNo(node->prev);
4221 else if ((node->parent != NULL) &&
4222 ((node->parent->type == XML_ELEMENT_NODE) ||
4223 (node->parent->type == XML_TEXT_NODE)))
4224 result = xmlGetLineNo(node->parent);
4225
4226 return result;
4227}
4228
Daniel Veillard2156d432004-03-04 15:59:36 +00004229#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004230/**
4231 * xmlGetNodePath:
4232 * @node: a node
4233 *
4234 * Build a structure based Path for the given node
4235 *
4236 * Returns the new path or NULL in case of error. The caller must free
4237 * the returned string
4238 */
4239xmlChar *
4240xmlGetNodePath(xmlNodePtr node)
4241{
4242 xmlNodePtr cur, tmp, next;
4243 xmlChar *buffer = NULL, *temp;
4244 size_t buf_len;
4245 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004246 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004247 const char *name;
4248 char nametemp[100];
4249 int occur = 0;
4250
4251 if (node == NULL)
4252 return (NULL);
4253
4254 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004255 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004256 if (buffer == NULL) {
4257 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004258 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004259 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004260 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004261 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004262 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004263 xmlFree(buffer);
4264 return (NULL);
4265 }
4266
4267 buffer[0] = 0;
4268 cur = node;
4269 do {
4270 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004271 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004272 occur = 0;
4273 if ((cur->type == XML_DOCUMENT_NODE) ||
4274 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4275 if (buffer[0] == '/')
4276 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004277 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004278 next = NULL;
4279 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004280 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004281 name = (const char *) cur->name;
4282 if (cur->ns) {
William M. Brack84d83e32003-12-23 03:45:17 +00004283 if (cur->ns->prefix != NULL)
William M. Brack13dfa872004-09-18 04:52:08 +00004284 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4285 (char *)cur->ns->prefix, (char *)cur->name);
William M. Brack84d83e32003-12-23 03:45:17 +00004286 else
William M. Brack13dfa872004-09-18 04:52:08 +00004287 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4288 (char *)cur->name);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004289 nametemp[sizeof(nametemp) - 1] = 0;
4290 name = nametemp;
4291 }
4292 next = cur->parent;
4293
4294 /*
4295 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004296 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004297 */
4298 tmp = cur->prev;
4299 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004300 if ((tmp->type == XML_ELEMENT_NODE) &&
4301 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004302 occur++;
4303 tmp = tmp->prev;
4304 }
4305 if (occur == 0) {
4306 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004307 while (tmp != NULL && occur == 0) {
4308 if ((tmp->type == XML_ELEMENT_NODE) &&
4309 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004310 occur++;
4311 tmp = tmp->next;
4312 }
4313 if (occur != 0)
4314 occur = 1;
4315 } else
4316 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004317 } else if (cur->type == XML_COMMENT_NODE) {
4318 sep = "/";
4319 name = "comment()";
4320 next = cur->parent;
4321
4322 /*
4323 * Thumbler index computation
4324 */
4325 tmp = cur->prev;
4326 while (tmp != NULL) {
4327 if (tmp->type == XML_COMMENT_NODE)
4328 occur++;
4329 tmp = tmp->prev;
4330 }
4331 if (occur == 0) {
4332 tmp = cur->next;
4333 while (tmp != NULL && occur == 0) {
4334 if (tmp->type == XML_COMMENT_NODE)
4335 occur++;
4336 tmp = tmp->next;
4337 }
4338 if (occur != 0)
4339 occur = 1;
4340 } else
4341 occur++;
4342 } else if ((cur->type == XML_TEXT_NODE) ||
4343 (cur->type == XML_CDATA_SECTION_NODE)) {
4344 sep = "/";
4345 name = "text()";
4346 next = cur->parent;
4347
4348 /*
4349 * Thumbler index computation
4350 */
4351 tmp = cur->prev;
4352 while (tmp != NULL) {
4353 if ((cur->type == XML_TEXT_NODE) ||
4354 (cur->type == XML_CDATA_SECTION_NODE))
4355 occur++;
4356 tmp = tmp->prev;
4357 }
4358 if (occur == 0) {
4359 tmp = cur->next;
4360 while (tmp != NULL && occur == 0) {
Daniel Veillard1f8658a2004-08-14 21:46:31 +00004361 if ((tmp->type == XML_TEXT_NODE) ||
4362 (tmp->type == XML_CDATA_SECTION_NODE))
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004363 occur++;
4364 tmp = tmp->next;
4365 }
4366 if (occur != 0)
4367 occur = 1;
4368 } else
4369 occur++;
4370 } else if (cur->type == XML_PI_NODE) {
4371 sep = "/";
4372 snprintf(nametemp, sizeof(nametemp) - 1,
William M. Brack13dfa872004-09-18 04:52:08 +00004373 "processing-instruction('%s')", (char *)cur->name);
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004374 nametemp[sizeof(nametemp) - 1] = 0;
4375 name = nametemp;
4376
4377 next = cur->parent;
4378
4379 /*
4380 * Thumbler index computation
4381 */
4382 tmp = cur->prev;
4383 while (tmp != NULL) {
4384 if ((tmp->type == XML_PI_NODE) &&
4385 (xmlStrEqual(cur->name, tmp->name)))
4386 occur++;
4387 tmp = tmp->prev;
4388 }
4389 if (occur == 0) {
4390 tmp = cur->next;
4391 while (tmp != NULL && occur == 0) {
4392 if ((tmp->type == XML_PI_NODE) &&
4393 (xmlStrEqual(cur->name, tmp->name)))
4394 occur++;
4395 tmp = tmp->next;
4396 }
4397 if (occur != 0)
4398 occur = 1;
4399 } else
4400 occur++;
4401
Daniel Veillard8faa7832001-11-26 15:58:08 +00004402 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004403 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004404 name = (const char *) (((xmlAttrPtr) cur)->name);
4405 next = ((xmlAttrPtr) cur)->parent;
4406 } else {
4407 next = cur->parent;
4408 }
4409
4410 /*
4411 * Make sure there is enough room
4412 */
4413 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4414 buf_len =
4415 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4416 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4417 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004418 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004419 xmlFree(buf);
4420 xmlFree(buffer);
4421 return (NULL);
4422 }
4423 buffer = temp;
4424 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4425 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004426 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004427 xmlFree(buf);
4428 xmlFree(buffer);
4429 return (NULL);
4430 }
4431 buf = temp;
4432 }
4433 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004434 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004435 sep, name, (char *) buffer);
4436 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004437 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004438 sep, name, occur, (char *) buffer);
William M. Brack13dfa872004-09-18 04:52:08 +00004439 snprintf((char *) buffer, buf_len, "%s", (char *)buf);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004440 cur = next;
4441 } while (cur != NULL);
4442 xmlFree(buf);
4443 return (buffer);
4444}
Daniel Veillard652327a2003-09-29 18:02:38 +00004445#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004446
4447/**
Owen Taylor3473f882001-02-23 17:55:21 +00004448 * xmlDocGetRootElement:
4449 * @doc: the document
4450 *
4451 * Get the root element of the document (doc->children is a list
4452 * containing possibly comments, PIs, etc ...).
4453 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004454 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004455 */
4456xmlNodePtr
4457xmlDocGetRootElement(xmlDocPtr doc) {
4458 xmlNodePtr ret;
4459
4460 if (doc == NULL) return(NULL);
4461 ret = doc->children;
4462 while (ret != NULL) {
4463 if (ret->type == XML_ELEMENT_NODE)
4464 return(ret);
4465 ret = ret->next;
4466 }
4467 return(ret);
4468}
4469
Daniel Veillard2156d432004-03-04 15:59:36 +00004470#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004471/**
4472 * xmlDocSetRootElement:
4473 * @doc: the document
4474 * @root: the new document root element
4475 *
4476 * Set the root element of the document (doc->children is a list
4477 * containing possibly comments, PIs, etc ...).
4478 *
4479 * Returns the old root element if any was found
4480 */
4481xmlNodePtr
4482xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4483 xmlNodePtr old = NULL;
4484
4485 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004486 if (root == NULL)
4487 return(NULL);
4488 xmlUnlinkNode(root);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00004489 xmlSetTreeDoc(root, doc);
Daniel Veillardc575b992002-02-08 13:28:40 +00004490 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004491 old = doc->children;
4492 while (old != NULL) {
4493 if (old->type == XML_ELEMENT_NODE)
4494 break;
4495 old = old->next;
4496 }
4497 if (old == NULL) {
4498 if (doc->children == NULL) {
4499 doc->children = root;
4500 doc->last = root;
4501 } else {
4502 xmlAddSibling(doc->children, root);
4503 }
4504 } else {
4505 xmlReplaceNode(old, root);
4506 }
4507 return(old);
4508}
Daniel Veillard2156d432004-03-04 15:59:36 +00004509#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004510
Daniel Veillard2156d432004-03-04 15:59:36 +00004511#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004512/**
4513 * xmlNodeSetLang:
4514 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004515 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004516 *
4517 * Set the language of a node, i.e. the values of the xml:lang
4518 * attribute.
4519 */
4520void
4521xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004522 xmlNsPtr ns;
4523
Owen Taylor3473f882001-02-23 17:55:21 +00004524 if (cur == NULL) return;
4525 switch(cur->type) {
4526 case XML_TEXT_NODE:
4527 case XML_CDATA_SECTION_NODE:
4528 case XML_COMMENT_NODE:
4529 case XML_DOCUMENT_NODE:
4530 case XML_DOCUMENT_TYPE_NODE:
4531 case XML_DOCUMENT_FRAG_NODE:
4532 case XML_NOTATION_NODE:
4533 case XML_HTML_DOCUMENT_NODE:
4534 case XML_DTD_NODE:
4535 case XML_ELEMENT_DECL:
4536 case XML_ATTRIBUTE_DECL:
4537 case XML_ENTITY_DECL:
4538 case XML_PI_NODE:
4539 case XML_ENTITY_REF_NODE:
4540 case XML_ENTITY_NODE:
4541 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004542#ifdef LIBXML_DOCB_ENABLED
4543 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004544#endif
4545 case XML_XINCLUDE_START:
4546 case XML_XINCLUDE_END:
4547 return;
4548 case XML_ELEMENT_NODE:
4549 case XML_ATTRIBUTE_NODE:
4550 break;
4551 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004552 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4553 if (ns == NULL)
4554 return;
4555 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004556}
Daniel Veillard652327a2003-09-29 18:02:38 +00004557#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004558
4559/**
4560 * xmlNodeGetLang:
4561 * @cur: the node being checked
4562 *
4563 * Searches the language of a node, i.e. the values of the xml:lang
4564 * attribute or the one carried by the nearest ancestor.
4565 *
4566 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004567 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004568 */
4569xmlChar *
4570xmlNodeGetLang(xmlNodePtr cur) {
4571 xmlChar *lang;
4572
4573 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004574 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004575 if (lang != NULL)
4576 return(lang);
4577 cur = cur->parent;
4578 }
4579 return(NULL);
4580}
4581
4582
Daniel Veillard652327a2003-09-29 18:02:38 +00004583#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004584/**
4585 * xmlNodeSetSpacePreserve:
4586 * @cur: the node being changed
4587 * @val: the xml:space value ("0": default, 1: "preserve")
4588 *
4589 * Set (or reset) the space preserving behaviour of a node, i.e. the
4590 * value of the xml:space attribute.
4591 */
4592void
4593xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004594 xmlNsPtr ns;
4595
Owen Taylor3473f882001-02-23 17:55:21 +00004596 if (cur == NULL) return;
4597 switch(cur->type) {
4598 case XML_TEXT_NODE:
4599 case XML_CDATA_SECTION_NODE:
4600 case XML_COMMENT_NODE:
4601 case XML_DOCUMENT_NODE:
4602 case XML_DOCUMENT_TYPE_NODE:
4603 case XML_DOCUMENT_FRAG_NODE:
4604 case XML_NOTATION_NODE:
4605 case XML_HTML_DOCUMENT_NODE:
4606 case XML_DTD_NODE:
4607 case XML_ELEMENT_DECL:
4608 case XML_ATTRIBUTE_DECL:
4609 case XML_ENTITY_DECL:
4610 case XML_PI_NODE:
4611 case XML_ENTITY_REF_NODE:
4612 case XML_ENTITY_NODE:
4613 case XML_NAMESPACE_DECL:
4614 case XML_XINCLUDE_START:
4615 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004616#ifdef LIBXML_DOCB_ENABLED
4617 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004618#endif
4619 return;
4620 case XML_ELEMENT_NODE:
4621 case XML_ATTRIBUTE_NODE:
4622 break;
4623 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004624 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4625 if (ns == NULL)
4626 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004627 switch (val) {
4628 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004629 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004630 break;
4631 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004632 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004633 break;
4634 }
4635}
Daniel Veillard652327a2003-09-29 18:02:38 +00004636#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004637
4638/**
4639 * xmlNodeGetSpacePreserve:
4640 * @cur: the node being checked
4641 *
4642 * Searches the space preserving behaviour of a node, i.e. the values
4643 * of the xml:space attribute or the one carried by the nearest
4644 * ancestor.
4645 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004646 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004647 */
4648int
4649xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4650 xmlChar *space;
4651
4652 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004653 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004654 if (space != NULL) {
4655 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4656 xmlFree(space);
4657 return(1);
4658 }
4659 if (xmlStrEqual(space, BAD_CAST "default")) {
4660 xmlFree(space);
4661 return(0);
4662 }
4663 xmlFree(space);
4664 }
4665 cur = cur->parent;
4666 }
4667 return(-1);
4668}
4669
Daniel Veillard652327a2003-09-29 18:02:38 +00004670#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004671/**
4672 * xmlNodeSetName:
4673 * @cur: the node being changed
4674 * @name: the new tag name
4675 *
4676 * Set (or reset) the name of a node.
4677 */
4678void
4679xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4680 if (cur == NULL) return;
4681 if (name == NULL) return;
4682 switch(cur->type) {
4683 case XML_TEXT_NODE:
4684 case XML_CDATA_SECTION_NODE:
4685 case XML_COMMENT_NODE:
4686 case XML_DOCUMENT_TYPE_NODE:
4687 case XML_DOCUMENT_FRAG_NODE:
4688 case XML_NOTATION_NODE:
4689 case XML_HTML_DOCUMENT_NODE:
4690 case XML_NAMESPACE_DECL:
4691 case XML_XINCLUDE_START:
4692 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004693#ifdef LIBXML_DOCB_ENABLED
4694 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004695#endif
4696 return;
4697 case XML_ELEMENT_NODE:
4698 case XML_ATTRIBUTE_NODE:
4699 case XML_PI_NODE:
4700 case XML_ENTITY_REF_NODE:
4701 case XML_ENTITY_NODE:
4702 case XML_DTD_NODE:
4703 case XML_DOCUMENT_NODE:
4704 case XML_ELEMENT_DECL:
4705 case XML_ATTRIBUTE_DECL:
4706 case XML_ENTITY_DECL:
4707 break;
4708 }
4709 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4710 cur->name = xmlStrdup(name);
4711}
Daniel Veillard2156d432004-03-04 15:59:36 +00004712#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004713
Daniel Veillard2156d432004-03-04 15:59:36 +00004714#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004715/**
4716 * xmlNodeSetBase:
4717 * @cur: the node being changed
4718 * @uri: the new base URI
4719 *
4720 * Set (or reset) the base URI of a node, i.e. the value of the
4721 * xml:base attribute.
4722 */
4723void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004724xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004725 xmlNsPtr ns;
4726
Owen Taylor3473f882001-02-23 17:55:21 +00004727 if (cur == NULL) return;
4728 switch(cur->type) {
4729 case XML_TEXT_NODE:
4730 case XML_CDATA_SECTION_NODE:
4731 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004732 case XML_DOCUMENT_TYPE_NODE:
4733 case XML_DOCUMENT_FRAG_NODE:
4734 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004735 case XML_DTD_NODE:
4736 case XML_ELEMENT_DECL:
4737 case XML_ATTRIBUTE_DECL:
4738 case XML_ENTITY_DECL:
4739 case XML_PI_NODE:
4740 case XML_ENTITY_REF_NODE:
4741 case XML_ENTITY_NODE:
4742 case XML_NAMESPACE_DECL:
4743 case XML_XINCLUDE_START:
4744 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004745 return;
4746 case XML_ELEMENT_NODE:
4747 case XML_ATTRIBUTE_NODE:
4748 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004749 case XML_DOCUMENT_NODE:
4750#ifdef LIBXML_DOCB_ENABLED
4751 case XML_DOCB_DOCUMENT_NODE:
4752#endif
4753 case XML_HTML_DOCUMENT_NODE: {
4754 xmlDocPtr doc = (xmlDocPtr) cur;
4755
4756 if (doc->URL != NULL)
4757 xmlFree((xmlChar *) doc->URL);
4758 if (uri == NULL)
4759 doc->URL = NULL;
4760 else
4761 doc->URL = xmlStrdup(uri);
4762 return;
4763 }
Owen Taylor3473f882001-02-23 17:55:21 +00004764 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004765
4766 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4767 if (ns == NULL)
4768 return;
4769 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004770}
Daniel Veillard652327a2003-09-29 18:02:38 +00004771#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004772
4773/**
Owen Taylor3473f882001-02-23 17:55:21 +00004774 * xmlNodeGetBase:
4775 * @doc: the document the node pertains to
4776 * @cur: the node being checked
4777 *
4778 * Searches for the BASE URL. The code should work on both XML
4779 * and HTML document even if base mechanisms are completely different.
4780 * It returns the base as defined in RFC 2396 sections
4781 * 5.1.1. Base URI within Document Content
4782 * and
4783 * 5.1.2. Base URI from the Encapsulating Entity
4784 * However it does not return the document base (5.1.3), use
4785 * xmlDocumentGetBase() for this
4786 *
4787 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004788 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004789 */
4790xmlChar *
4791xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004792 xmlChar *oldbase = NULL;
4793 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004794
4795 if ((cur == NULL) && (doc == NULL))
4796 return(NULL);
4797 if (doc == NULL) doc = cur->doc;
4798 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4799 cur = doc->children;
4800 while ((cur != NULL) && (cur->name != NULL)) {
4801 if (cur->type != XML_ELEMENT_NODE) {
4802 cur = cur->next;
4803 continue;
4804 }
4805 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4806 cur = cur->children;
4807 continue;
4808 }
4809 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4810 cur = cur->children;
4811 continue;
4812 }
4813 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4814 return(xmlGetProp(cur, BAD_CAST "href"));
4815 }
4816 cur = cur->next;
4817 }
4818 return(NULL);
4819 }
4820 while (cur != NULL) {
4821 if (cur->type == XML_ENTITY_DECL) {
4822 xmlEntityPtr ent = (xmlEntityPtr) cur;
4823 return(xmlStrdup(ent->URI));
4824 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004825 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004826 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004827 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004828 if (oldbase != NULL) {
4829 newbase = xmlBuildURI(oldbase, base);
4830 if (newbase != NULL) {
4831 xmlFree(oldbase);
4832 xmlFree(base);
4833 oldbase = newbase;
4834 } else {
4835 xmlFree(oldbase);
4836 xmlFree(base);
4837 return(NULL);
4838 }
4839 } else {
4840 oldbase = base;
4841 }
4842 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4843 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4844 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4845 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004846 }
4847 }
Owen Taylor3473f882001-02-23 17:55:21 +00004848 cur = cur->parent;
4849 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004850 if ((doc != NULL) && (doc->URL != NULL)) {
4851 if (oldbase == NULL)
4852 return(xmlStrdup(doc->URL));
4853 newbase = xmlBuildURI(oldbase, doc->URL);
4854 xmlFree(oldbase);
4855 return(newbase);
4856 }
4857 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004858}
4859
4860/**
Daniel Veillard78697292003-10-19 20:44:43 +00004861 * xmlNodeBufGetContent:
4862 * @buffer: a buffer
4863 * @cur: the node being read
4864 *
4865 * Read the value of a node @cur, this can be either the text carried
4866 * directly by this node if it's a TEXT node or the aggregate string
4867 * of the values carried by this node child's (TEXT and ENTITY_REF).
4868 * Entity references are substituted.
4869 * Fills up the buffer @buffer with this value
4870 *
4871 * Returns 0 in case of success and -1 in case of error.
4872 */
4873int
4874xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4875{
4876 if ((cur == NULL) || (buffer == NULL)) return(-1);
4877 switch (cur->type) {
4878 case XML_CDATA_SECTION_NODE:
4879 case XML_TEXT_NODE:
4880 xmlBufferCat(buffer, cur->content);
4881 break;
4882 case XML_DOCUMENT_FRAG_NODE:
4883 case XML_ELEMENT_NODE:{
4884 xmlNodePtr tmp = cur;
4885
4886 while (tmp != NULL) {
4887 switch (tmp->type) {
4888 case XML_CDATA_SECTION_NODE:
4889 case XML_TEXT_NODE:
4890 if (tmp->content != NULL)
4891 xmlBufferCat(buffer, tmp->content);
4892 break;
4893 case XML_ENTITY_REF_NODE:
4894 xmlNodeBufGetContent(buffer, tmp->children);
4895 break;
4896 default:
4897 break;
4898 }
4899 /*
4900 * Skip to next node
4901 */
4902 if (tmp->children != NULL) {
4903 if (tmp->children->type != XML_ENTITY_DECL) {
4904 tmp = tmp->children;
4905 continue;
4906 }
4907 }
4908 if (tmp == cur)
4909 break;
4910
4911 if (tmp->next != NULL) {
4912 tmp = tmp->next;
4913 continue;
4914 }
4915
4916 do {
4917 tmp = tmp->parent;
4918 if (tmp == NULL)
4919 break;
4920 if (tmp == cur) {
4921 tmp = NULL;
4922 break;
4923 }
4924 if (tmp->next != NULL) {
4925 tmp = tmp->next;
4926 break;
4927 }
4928 } while (tmp != NULL);
4929 }
4930 break;
4931 }
4932 case XML_ATTRIBUTE_NODE:{
4933 xmlAttrPtr attr = (xmlAttrPtr) cur;
4934 xmlNodePtr tmp = attr->children;
4935
4936 while (tmp != NULL) {
4937 if (tmp->type == XML_TEXT_NODE)
4938 xmlBufferCat(buffer, tmp->content);
4939 else
4940 xmlNodeBufGetContent(buffer, tmp);
4941 tmp = tmp->next;
4942 }
4943 break;
4944 }
4945 case XML_COMMENT_NODE:
4946 case XML_PI_NODE:
4947 xmlBufferCat(buffer, cur->content);
4948 break;
4949 case XML_ENTITY_REF_NODE:{
4950 xmlEntityPtr ent;
4951 xmlNodePtr tmp;
4952
4953 /* lookup entity declaration */
4954 ent = xmlGetDocEntity(cur->doc, cur->name);
4955 if (ent == NULL)
4956 return(-1);
4957
4958 /* an entity content can be any "well balanced chunk",
4959 * i.e. the result of the content [43] production:
4960 * http://www.w3.org/TR/REC-xml#NT-content
4961 * -> we iterate through child nodes and recursive call
4962 * xmlNodeGetContent() which handles all possible node types */
4963 tmp = ent->children;
4964 while (tmp) {
4965 xmlNodeBufGetContent(buffer, tmp);
4966 tmp = tmp->next;
4967 }
4968 break;
4969 }
4970 case XML_ENTITY_NODE:
4971 case XML_DOCUMENT_TYPE_NODE:
4972 case XML_NOTATION_NODE:
4973 case XML_DTD_NODE:
4974 case XML_XINCLUDE_START:
4975 case XML_XINCLUDE_END:
4976 break;
4977 case XML_DOCUMENT_NODE:
4978#ifdef LIBXML_DOCB_ENABLED
4979 case XML_DOCB_DOCUMENT_NODE:
4980#endif
4981 case XML_HTML_DOCUMENT_NODE:
4982 cur = cur->children;
4983 while (cur!= NULL) {
4984 if ((cur->type == XML_ELEMENT_NODE) ||
4985 (cur->type == XML_TEXT_NODE) ||
4986 (cur->type == XML_CDATA_SECTION_NODE)) {
4987 xmlNodeBufGetContent(buffer, cur);
4988 }
4989 cur = cur->next;
4990 }
4991 break;
4992 case XML_NAMESPACE_DECL:
4993 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
4994 break;
4995 case XML_ELEMENT_DECL:
4996 case XML_ATTRIBUTE_DECL:
4997 case XML_ENTITY_DECL:
4998 break;
4999 }
5000 return(0);
5001}
5002/**
Owen Taylor3473f882001-02-23 17:55:21 +00005003 * xmlNodeGetContent:
5004 * @cur: the node being read
5005 *
5006 * Read the value of a node, this can be either the text carried
5007 * directly by this node if it's a TEXT node or the aggregate string
5008 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00005009 * Entity references are substituted.
5010 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005011 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005012 */
5013xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00005014xmlNodeGetContent(xmlNodePtr cur)
5015{
5016 if (cur == NULL)
5017 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005018 switch (cur->type) {
5019 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005020 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00005021 xmlBufferPtr buffer;
5022 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00005023
Daniel Veillard814a76d2003-01-23 18:24:20 +00005024 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00005025 if (buffer == NULL)
5026 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00005027 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005028 ret = buffer->content;
5029 buffer->content = NULL;
5030 xmlBufferFree(buffer);
5031 return (ret);
5032 }
5033 case XML_ATTRIBUTE_NODE:{
5034 xmlAttrPtr attr = (xmlAttrPtr) cur;
5035
5036 if (attr->parent != NULL)
5037 return (xmlNodeListGetString
5038 (attr->parent->doc, attr->children, 1));
5039 else
5040 return (xmlNodeListGetString(NULL, attr->children, 1));
5041 break;
5042 }
Owen Taylor3473f882001-02-23 17:55:21 +00005043 case XML_COMMENT_NODE:
5044 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005045 if (cur->content != NULL)
5046 return (xmlStrdup(cur->content));
5047 return (NULL);
5048 case XML_ENTITY_REF_NODE:{
5049 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00005050 xmlBufferPtr buffer;
5051 xmlChar *ret;
5052
5053 /* lookup entity declaration */
5054 ent = xmlGetDocEntity(cur->doc, cur->name);
5055 if (ent == NULL)
5056 return (NULL);
5057
5058 buffer = xmlBufferCreate();
5059 if (buffer == NULL)
5060 return (NULL);
5061
Daniel Veillardc4696922003-10-19 21:47:14 +00005062 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005063
5064 ret = buffer->content;
5065 buffer->content = NULL;
5066 xmlBufferFree(buffer);
5067 return (ret);
5068 }
Owen Taylor3473f882001-02-23 17:55:21 +00005069 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005070 case XML_DOCUMENT_TYPE_NODE:
5071 case XML_NOTATION_NODE:
5072 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005073 case XML_XINCLUDE_START:
5074 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00005075 return (NULL);
5076 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005077#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005078 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005079#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005080 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00005081 xmlBufferPtr buffer;
5082 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005083
Daniel Veillardc4696922003-10-19 21:47:14 +00005084 buffer = xmlBufferCreate();
5085 if (buffer == NULL)
5086 return (NULL);
5087
5088 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5089
5090 ret = buffer->content;
5091 buffer->content = NULL;
5092 xmlBufferFree(buffer);
5093 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005094 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005095 case XML_NAMESPACE_DECL: {
5096 xmlChar *tmp;
5097
5098 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5099 return (tmp);
5100 }
Owen Taylor3473f882001-02-23 17:55:21 +00005101 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005102 /* TODO !!! */
5103 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005104 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005105 /* TODO !!! */
5106 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005107 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005108 /* TODO !!! */
5109 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005110 case XML_CDATA_SECTION_NODE:
5111 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005112 if (cur->content != NULL)
5113 return (xmlStrdup(cur->content));
5114 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005115 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005116 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005117}
Daniel Veillard652327a2003-09-29 18:02:38 +00005118
Owen Taylor3473f882001-02-23 17:55:21 +00005119/**
5120 * xmlNodeSetContent:
5121 * @cur: the node being modified
5122 * @content: the new value of the content
5123 *
5124 * Replace the content of a node.
5125 */
5126void
5127xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5128 if (cur == NULL) {
5129#ifdef DEBUG_TREE
5130 xmlGenericError(xmlGenericErrorContext,
5131 "xmlNodeSetContent : node == NULL\n");
5132#endif
5133 return;
5134 }
5135 switch (cur->type) {
5136 case XML_DOCUMENT_FRAG_NODE:
5137 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005138 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005139 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5140 cur->children = xmlStringGetNodeList(cur->doc, content);
5141 UPDATE_LAST_CHILD_AND_PARENT(cur)
5142 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005143 case XML_TEXT_NODE:
5144 case XML_CDATA_SECTION_NODE:
5145 case XML_ENTITY_REF_NODE:
5146 case XML_ENTITY_NODE:
5147 case XML_PI_NODE:
5148 case XML_COMMENT_NODE:
5149 if (cur->content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005150 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
Daniel Veillard370ba3d2004-10-25 16:23:56 +00005151 (!xmlDictOwns(cur->doc->dict, cur->content))))
William M. Brack7762bb12004-01-04 14:49:01 +00005152 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005153 }
5154 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5155 cur->last = cur->children = NULL;
5156 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005157 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005158 } else
5159 cur->content = NULL;
5160 break;
5161 case XML_DOCUMENT_NODE:
5162 case XML_HTML_DOCUMENT_NODE:
5163 case XML_DOCUMENT_TYPE_NODE:
5164 case XML_XINCLUDE_START:
5165 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005166#ifdef LIBXML_DOCB_ENABLED
5167 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005168#endif
5169 break;
5170 case XML_NOTATION_NODE:
5171 break;
5172 case XML_DTD_NODE:
5173 break;
5174 case XML_NAMESPACE_DECL:
5175 break;
5176 case XML_ELEMENT_DECL:
5177 /* TODO !!! */
5178 break;
5179 case XML_ATTRIBUTE_DECL:
5180 /* TODO !!! */
5181 break;
5182 case XML_ENTITY_DECL:
5183 /* TODO !!! */
5184 break;
5185 }
5186}
5187
Daniel Veillard652327a2003-09-29 18:02:38 +00005188#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005189/**
5190 * xmlNodeSetContentLen:
5191 * @cur: the node being modified
5192 * @content: the new value of the content
5193 * @len: the size of @content
5194 *
5195 * Replace the content of a node.
5196 */
5197void
5198xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5199 if (cur == NULL) {
5200#ifdef DEBUG_TREE
5201 xmlGenericError(xmlGenericErrorContext,
5202 "xmlNodeSetContentLen : node == NULL\n");
5203#endif
5204 return;
5205 }
5206 switch (cur->type) {
5207 case XML_DOCUMENT_FRAG_NODE:
5208 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005209 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005210 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5211 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5212 UPDATE_LAST_CHILD_AND_PARENT(cur)
5213 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005214 case XML_TEXT_NODE:
5215 case XML_CDATA_SECTION_NODE:
5216 case XML_ENTITY_REF_NODE:
5217 case XML_ENTITY_NODE:
5218 case XML_PI_NODE:
5219 case XML_COMMENT_NODE:
5220 case XML_NOTATION_NODE:
5221 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005222 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005223 }
5224 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5225 cur->children = cur->last = NULL;
5226 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005227 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005228 } else
5229 cur->content = NULL;
5230 break;
5231 case XML_DOCUMENT_NODE:
5232 case XML_DTD_NODE:
5233 case XML_HTML_DOCUMENT_NODE:
5234 case XML_DOCUMENT_TYPE_NODE:
5235 case XML_NAMESPACE_DECL:
5236 case XML_XINCLUDE_START:
5237 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005238#ifdef LIBXML_DOCB_ENABLED
5239 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005240#endif
5241 break;
5242 case XML_ELEMENT_DECL:
5243 /* TODO !!! */
5244 break;
5245 case XML_ATTRIBUTE_DECL:
5246 /* TODO !!! */
5247 break;
5248 case XML_ENTITY_DECL:
5249 /* TODO !!! */
5250 break;
5251 }
5252}
Daniel Veillard652327a2003-09-29 18:02:38 +00005253#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005254
5255/**
5256 * xmlNodeAddContentLen:
5257 * @cur: the node being modified
5258 * @content: extra content
5259 * @len: the size of @content
5260 *
5261 * Append the extra substring to the node content.
5262 */
5263void
5264xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5265 if (cur == NULL) {
5266#ifdef DEBUG_TREE
5267 xmlGenericError(xmlGenericErrorContext,
5268 "xmlNodeAddContentLen : node == NULL\n");
5269#endif
5270 return;
5271 }
5272 if (len <= 0) return;
5273 switch (cur->type) {
5274 case XML_DOCUMENT_FRAG_NODE:
5275 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005276 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005277
Daniel Veillard7db37732001-07-12 01:20:08 +00005278 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005279 newNode = xmlNewTextLen(content, len);
5280 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005281 tmp = xmlAddChild(cur, newNode);
5282 if (tmp != newNode)
5283 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005284 if ((last != NULL) && (last->next == newNode)) {
5285 xmlTextMerge(last, newNode);
5286 }
5287 }
5288 break;
5289 }
5290 case XML_ATTRIBUTE_NODE:
5291 break;
5292 case XML_TEXT_NODE:
5293 case XML_CDATA_SECTION_NODE:
5294 case XML_ENTITY_REF_NODE:
5295 case XML_ENTITY_NODE:
5296 case XML_PI_NODE:
5297 case XML_COMMENT_NODE:
5298 case XML_NOTATION_NODE:
5299 if (content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005300 if ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5301 xmlDictOwns(cur->doc->dict, cur->content)) {
5302 cur->content =
5303 xmlStrncatNew(cur->content, content, len);
5304 break;
5305 }
Owen Taylor3473f882001-02-23 17:55:21 +00005306 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005307 }
5308 case XML_DOCUMENT_NODE:
5309 case XML_DTD_NODE:
5310 case XML_HTML_DOCUMENT_NODE:
5311 case XML_DOCUMENT_TYPE_NODE:
5312 case XML_NAMESPACE_DECL:
5313 case XML_XINCLUDE_START:
5314 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005315#ifdef LIBXML_DOCB_ENABLED
5316 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005317#endif
5318 break;
5319 case XML_ELEMENT_DECL:
5320 case XML_ATTRIBUTE_DECL:
5321 case XML_ENTITY_DECL:
5322 break;
5323 }
5324}
5325
5326/**
5327 * xmlNodeAddContent:
5328 * @cur: the node being modified
5329 * @content: extra content
5330 *
5331 * Append the extra substring to the node content.
5332 */
5333void
5334xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5335 int len;
5336
5337 if (cur == NULL) {
5338#ifdef DEBUG_TREE
5339 xmlGenericError(xmlGenericErrorContext,
5340 "xmlNodeAddContent : node == NULL\n");
5341#endif
5342 return;
5343 }
5344 if (content == NULL) return;
5345 len = xmlStrlen(content);
5346 xmlNodeAddContentLen(cur, content, len);
5347}
5348
5349/**
5350 * xmlTextMerge:
5351 * @first: the first text node
5352 * @second: the second text node being merged
5353 *
5354 * Merge two text nodes into one
5355 * Returns the first text node augmented
5356 */
5357xmlNodePtr
5358xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5359 if (first == NULL) return(second);
5360 if (second == NULL) return(first);
5361 if (first->type != XML_TEXT_NODE) return(first);
5362 if (second->type != XML_TEXT_NODE) return(first);
5363 if (second->name != first->name)
5364 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005365 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005366 xmlUnlinkNode(second);
5367 xmlFreeNode(second);
5368 return(first);
5369}
5370
Daniel Veillard2156d432004-03-04 15:59:36 +00005371#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005372/**
5373 * xmlGetNsList:
5374 * @doc: the document
5375 * @node: the current node
5376 *
5377 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005378 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005379 * that need to be freed by the caller or NULL if no
5380 * namespace if defined
5381 */
5382xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005383xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5384{
Owen Taylor3473f882001-02-23 17:55:21 +00005385 xmlNsPtr cur;
5386 xmlNsPtr *ret = NULL;
5387 int nbns = 0;
5388 int maxns = 10;
5389 int i;
5390
5391 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005392 if (node->type == XML_ELEMENT_NODE) {
5393 cur = node->nsDef;
5394 while (cur != NULL) {
5395 if (ret == NULL) {
5396 ret =
5397 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5398 sizeof(xmlNsPtr));
5399 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005400 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005401 return (NULL);
5402 }
5403 ret[nbns] = NULL;
5404 }
5405 for (i = 0; i < nbns; i++) {
5406 if ((cur->prefix == ret[i]->prefix) ||
5407 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5408 break;
5409 }
5410 if (i >= nbns) {
5411 if (nbns >= maxns) {
5412 maxns *= 2;
5413 ret = (xmlNsPtr *) xmlRealloc(ret,
5414 (maxns +
5415 1) *
5416 sizeof(xmlNsPtr));
5417 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005418 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005419 return (NULL);
5420 }
5421 }
5422 ret[nbns++] = cur;
5423 ret[nbns] = NULL;
5424 }
Owen Taylor3473f882001-02-23 17:55:21 +00005425
Daniel Veillard77044732001-06-29 21:31:07 +00005426 cur = cur->next;
5427 }
5428 }
5429 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005430 }
Daniel Veillard77044732001-06-29 21:31:07 +00005431 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005432}
Daniel Veillard652327a2003-09-29 18:02:38 +00005433#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005434
5435/**
5436 * xmlSearchNs:
5437 * @doc: the document
5438 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005439 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005440 *
5441 * Search a Ns registered under a given name space for a document.
5442 * recurse on the parents until it finds the defined namespace
5443 * or return NULL otherwise.
5444 * @nameSpace can be NULL, this is a search for the default namespace.
5445 * We don't allow to cross entities boundaries. If you don't declare
5446 * the namespace within those you will be in troubles !!! A warning
5447 * is generated to cover this case.
5448 *
5449 * Returns the namespace pointer or NULL.
5450 */
5451xmlNsPtr
5452xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005453
Owen Taylor3473f882001-02-23 17:55:21 +00005454 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005455 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005456
5457 if (node == NULL) return(NULL);
5458 if ((nameSpace != NULL) &&
5459 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005460 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5461 /*
5462 * The XML-1.0 namespace is normally held on the root
5463 * element. In this case exceptionally create it on the
5464 * node element.
5465 */
5466 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5467 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005468 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005469 return(NULL);
5470 }
5471 memset(cur, 0, sizeof(xmlNs));
5472 cur->type = XML_LOCAL_NAMESPACE;
5473 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5474 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5475 cur->next = node->nsDef;
5476 node->nsDef = cur;
5477 return(cur);
5478 }
Owen Taylor3473f882001-02-23 17:55:21 +00005479 if (doc->oldNs == NULL) {
5480 /*
5481 * Allocate a new Namespace and fill the fields.
5482 */
5483 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5484 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005485 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005486 return(NULL);
5487 }
5488 memset(doc->oldNs, 0, sizeof(xmlNs));
5489 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5490
5491 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5492 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5493 }
5494 return(doc->oldNs);
5495 }
5496 while (node != NULL) {
5497 if ((node->type == XML_ENTITY_REF_NODE) ||
5498 (node->type == XML_ENTITY_NODE) ||
5499 (node->type == XML_ENTITY_DECL))
5500 return(NULL);
5501 if (node->type == XML_ELEMENT_NODE) {
5502 cur = node->nsDef;
5503 while (cur != NULL) {
5504 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5505 (cur->href != NULL))
5506 return(cur);
5507 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5508 (cur->href != NULL) &&
5509 (xmlStrEqual(cur->prefix, nameSpace)))
5510 return(cur);
5511 cur = cur->next;
5512 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005513 if (orig != node) {
5514 cur = node->ns;
5515 if (cur != NULL) {
5516 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5517 (cur->href != NULL))
5518 return(cur);
5519 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5520 (cur->href != NULL) &&
5521 (xmlStrEqual(cur->prefix, nameSpace)))
5522 return(cur);
5523 }
5524 }
Owen Taylor3473f882001-02-23 17:55:21 +00005525 }
5526 node = node->parent;
5527 }
5528 return(NULL);
5529}
5530
5531/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005532 * xmlNsInScope:
5533 * @doc: the document
5534 * @node: the current node
5535 * @ancestor: the ancestor carrying the namespace
5536 * @prefix: the namespace prefix
5537 *
5538 * Verify that the given namespace held on @ancestor is still in scope
5539 * on node.
5540 *
5541 * Returns 1 if true, 0 if false and -1 in case of error.
5542 */
5543static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005544xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5545 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005546{
5547 xmlNsPtr tst;
5548
5549 while ((node != NULL) && (node != ancestor)) {
5550 if ((node->type == XML_ENTITY_REF_NODE) ||
5551 (node->type == XML_ENTITY_NODE) ||
5552 (node->type == XML_ENTITY_DECL))
5553 return (-1);
5554 if (node->type == XML_ELEMENT_NODE) {
5555 tst = node->nsDef;
5556 while (tst != NULL) {
5557 if ((tst->prefix == NULL)
5558 && (prefix == NULL))
5559 return (0);
5560 if ((tst->prefix != NULL)
5561 && (prefix != NULL)
5562 && (xmlStrEqual(tst->prefix, prefix)))
5563 return (0);
5564 tst = tst->next;
5565 }
5566 }
5567 node = node->parent;
5568 }
5569 if (node != ancestor)
5570 return (-1);
5571 return (1);
5572}
5573
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005574/**
Owen Taylor3473f882001-02-23 17:55:21 +00005575 * xmlSearchNsByHref:
5576 * @doc: the document
5577 * @node: the current node
5578 * @href: the namespace value
5579 *
5580 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5581 * the defined namespace or return NULL otherwise.
5582 * Returns the namespace pointer or NULL.
5583 */
5584xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005585xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5586{
Owen Taylor3473f882001-02-23 17:55:21 +00005587 xmlNsPtr cur;
5588 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005589 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005590
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005591 if ((node == NULL) || (href == NULL))
5592 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005593 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005594 /*
5595 * Only the document can hold the XML spec namespace.
5596 */
5597 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5598 /*
5599 * The XML-1.0 namespace is normally held on the root
5600 * element. In this case exceptionally create it on the
5601 * node element.
5602 */
5603 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5604 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005605 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005606 return (NULL);
5607 }
5608 memset(cur, 0, sizeof(xmlNs));
5609 cur->type = XML_LOCAL_NAMESPACE;
5610 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5611 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5612 cur->next = node->nsDef;
5613 node->nsDef = cur;
5614 return (cur);
5615 }
5616 if (doc->oldNs == NULL) {
5617 /*
5618 * Allocate a new Namespace and fill the fields.
5619 */
5620 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5621 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005622 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005623 return (NULL);
5624 }
5625 memset(doc->oldNs, 0, sizeof(xmlNs));
5626 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005627
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005628 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5629 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5630 }
5631 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005632 }
Daniel Veillard62040be2004-05-17 03:17:26 +00005633 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00005634 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005635 if ((node->type == XML_ENTITY_REF_NODE) ||
5636 (node->type == XML_ENTITY_NODE) ||
5637 (node->type == XML_ENTITY_DECL))
5638 return (NULL);
5639 if (node->type == XML_ELEMENT_NODE) {
5640 cur = node->nsDef;
5641 while (cur != NULL) {
5642 if ((cur->href != NULL) && (href != NULL) &&
5643 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005644 if (((!is_attr) || (cur->prefix != NULL)) &&
5645 (xmlNsInScope(doc, orig, node, cur->href) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005646 return (cur);
5647 }
5648 cur = cur->next;
5649 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005650 if (orig != node) {
5651 cur = node->ns;
5652 if (cur != NULL) {
5653 if ((cur->href != NULL) && (href != NULL) &&
5654 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005655 if (((!is_attr) || (cur->prefix != NULL)) &&
5656 (xmlNsInScope(doc, orig, node, cur->href) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00005657 return (cur);
5658 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005659 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005660 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005661 }
5662 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005663 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005664 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005665}
5666
5667/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005668 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005669 * @doc: the document
5670 * @tree: a node expected to hold the new namespace
5671 * @ns: the original namespace
5672 *
5673 * This function tries to locate a namespace definition in a tree
5674 * ancestors, or create a new namespace definition node similar to
5675 * @ns trying to reuse the same prefix. However if the given prefix is
5676 * null (default namespace) or reused within the subtree defined by
5677 * @tree or on one of its ancestors then a new prefix is generated.
5678 * Returns the (new) namespace definition or NULL in case of error
5679 */
5680xmlNsPtr
5681xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5682 xmlNsPtr def;
5683 xmlChar prefix[50];
5684 int counter = 1;
5685
5686 if (tree == NULL) {
5687#ifdef DEBUG_TREE
5688 xmlGenericError(xmlGenericErrorContext,
5689 "xmlNewReconciliedNs : tree == NULL\n");
5690#endif
5691 return(NULL);
5692 }
5693 if (ns == NULL) {
5694#ifdef DEBUG_TREE
5695 xmlGenericError(xmlGenericErrorContext,
5696 "xmlNewReconciliedNs : ns == NULL\n");
5697#endif
5698 return(NULL);
5699 }
5700 /*
5701 * Search an existing namespace definition inherited.
5702 */
5703 def = xmlSearchNsByHref(doc, tree, ns->href);
5704 if (def != NULL)
5705 return(def);
5706
5707 /*
5708 * Find a close prefix which is not already in use.
5709 * Let's strip namespace prefixes longer than 20 chars !
5710 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005711 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005712 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005713 else
William M. Brack13dfa872004-09-18 04:52:08 +00005714 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005715
Owen Taylor3473f882001-02-23 17:55:21 +00005716 def = xmlSearchNs(doc, tree, prefix);
5717 while (def != NULL) {
5718 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005719 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005720 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005721 else
William M. Brack13dfa872004-09-18 04:52:08 +00005722 snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
5723 (char *)ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005724 def = xmlSearchNs(doc, tree, prefix);
5725 }
5726
5727 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005728 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005729 */
5730 def = xmlNewNs(tree, ns->href, prefix);
5731 return(def);
5732}
5733
Daniel Veillard652327a2003-09-29 18:02:38 +00005734#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005735/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005736 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005737 * @doc: the document
5738 * @tree: a node defining the subtree to reconciliate
5739 *
5740 * This function checks that all the namespaces declared within the given
5741 * tree are properly declared. This is needed for example after Copy or Cut
5742 * and then paste operations. The subtree may still hold pointers to
5743 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005744 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005745 * the new environment. If not possible the new namespaces are redeclared
5746 * on @tree at the top of the given subtree.
5747 * Returns the number of namespace declarations created or -1 in case of error.
5748 */
5749int
5750xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5751 xmlNsPtr *oldNs = NULL;
5752 xmlNsPtr *newNs = NULL;
5753 int sizeCache = 0;
5754 int nbCache = 0;
5755
5756 xmlNsPtr n;
5757 xmlNodePtr node = tree;
5758 xmlAttrPtr attr;
5759 int ret = 0, i;
5760
5761 while (node != NULL) {
5762 /*
5763 * Reconciliate the node namespace
5764 */
5765 if (node->ns != NULL) {
5766 /*
5767 * initialize the cache if needed
5768 */
5769 if (sizeCache == 0) {
5770 sizeCache = 10;
5771 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5772 sizeof(xmlNsPtr));
5773 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005774 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005775 return(-1);
5776 }
5777 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5778 sizeof(xmlNsPtr));
5779 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005780 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005781 xmlFree(oldNs);
5782 return(-1);
5783 }
5784 }
5785 for (i = 0;i < nbCache;i++) {
5786 if (oldNs[i] == node->ns) {
5787 node->ns = newNs[i];
5788 break;
5789 }
5790 }
5791 if (i == nbCache) {
5792 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005793 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005794 */
5795 n = xmlNewReconciliedNs(doc, tree, node->ns);
5796 if (n != NULL) { /* :-( what if else ??? */
5797 /*
5798 * check if we need to grow the cache buffers.
5799 */
5800 if (sizeCache <= nbCache) {
5801 sizeCache *= 2;
5802 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5803 sizeof(xmlNsPtr));
5804 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005805 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005806 xmlFree(newNs);
5807 return(-1);
5808 }
5809 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5810 sizeof(xmlNsPtr));
5811 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005812 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005813 xmlFree(oldNs);
5814 return(-1);
5815 }
5816 }
5817 newNs[nbCache] = n;
5818 oldNs[nbCache++] = node->ns;
5819 node->ns = n;
5820 }
5821 }
5822 }
5823 /*
5824 * now check for namespace hold by attributes on the node.
5825 */
5826 attr = node->properties;
5827 while (attr != NULL) {
5828 if (attr->ns != NULL) {
5829 /*
5830 * initialize the cache if needed
5831 */
5832 if (sizeCache == 0) {
5833 sizeCache = 10;
5834 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5835 sizeof(xmlNsPtr));
5836 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005837 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005838 return(-1);
5839 }
5840 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5841 sizeof(xmlNsPtr));
5842 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005843 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005844 xmlFree(oldNs);
5845 return(-1);
5846 }
5847 }
5848 for (i = 0;i < nbCache;i++) {
5849 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005850 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005851 break;
5852 }
5853 }
5854 if (i == nbCache) {
5855 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005856 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005857 */
5858 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5859 if (n != NULL) { /* :-( what if else ??? */
5860 /*
5861 * check if we need to grow the cache buffers.
5862 */
5863 if (sizeCache <= nbCache) {
5864 sizeCache *= 2;
5865 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5866 sizeof(xmlNsPtr));
5867 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005868 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005869 xmlFree(newNs);
5870 return(-1);
5871 }
5872 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5873 sizeof(xmlNsPtr));
5874 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005875 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005876 xmlFree(oldNs);
5877 return(-1);
5878 }
5879 }
5880 newNs[nbCache] = n;
5881 oldNs[nbCache++] = attr->ns;
5882 attr->ns = n;
5883 }
5884 }
5885 }
5886 attr = attr->next;
5887 }
5888
5889 /*
5890 * Browse the full subtree, deep first
5891 */
Daniel Veillardac996a12004-07-30 12:02:58 +00005892 if (node->children != NULL && node->type != XML_ENTITY_REF_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00005893 /* deep first */
5894 node = node->children;
5895 } else if ((node != tree) && (node->next != NULL)) {
5896 /* then siblings */
5897 node = node->next;
5898 } else if (node != tree) {
5899 /* go up to parents->next if needed */
5900 while (node != tree) {
5901 if (node->parent != NULL)
5902 node = node->parent;
5903 if ((node != tree) && (node->next != NULL)) {
5904 node = node->next;
5905 break;
5906 }
5907 if (node->parent == NULL) {
5908 node = NULL;
5909 break;
5910 }
5911 }
5912 /* exit condition */
5913 if (node == tree)
5914 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005915 } else
5916 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005917 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005918 if (oldNs != NULL)
5919 xmlFree(oldNs);
5920 if (newNs != NULL)
5921 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005922 return(ret);
5923}
Daniel Veillard652327a2003-09-29 18:02:38 +00005924#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005925
5926/**
5927 * xmlHasProp:
5928 * @node: the node
5929 * @name: the attribute name
5930 *
5931 * Search an attribute associated to a node
5932 * This function also looks in DTD attribute declaration for #FIXED or
5933 * default declaration values unless DTD use has been turned off.
5934 *
5935 * Returns the attribute or the attribute declaration or NULL if
5936 * neither was found.
5937 */
5938xmlAttrPtr
5939xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5940 xmlAttrPtr prop;
5941 xmlDocPtr doc;
5942
5943 if ((node == NULL) || (name == NULL)) return(NULL);
5944 /*
5945 * Check on the properties attached to the node
5946 */
5947 prop = node->properties;
5948 while (prop != NULL) {
5949 if (xmlStrEqual(prop->name, name)) {
5950 return(prop);
5951 }
5952 prop = prop->next;
5953 }
5954 if (!xmlCheckDTD) return(NULL);
5955
5956 /*
5957 * Check if there is a default declaration in the internal
5958 * or external subsets
5959 */
5960 doc = node->doc;
5961 if (doc != NULL) {
5962 xmlAttributePtr attrDecl;
5963 if (doc->intSubset != NULL) {
5964 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5965 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5966 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005967 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5968 /* return attribute declaration only if a default value is given
5969 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005970 return((xmlAttrPtr) attrDecl);
5971 }
5972 }
5973 return(NULL);
5974}
5975
5976/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005977 * xmlHasNsProp:
5978 * @node: the node
5979 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005980 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005981 *
5982 * Search for an attribute associated to a node
5983 * This attribute has to be anchored in the namespace specified.
5984 * This does the entity substitution.
5985 * This function looks in DTD attribute declaration for #FIXED or
5986 * default declaration values unless DTD use has been turned off.
William M. Brack2c228442004-10-03 04:10:00 +00005987 * Note that a namespace of NULL indicates to use the default namespace.
Daniel Veillarde95e2392001-06-06 10:46:28 +00005988 *
5989 * Returns the attribute or the attribute declaration or NULL
5990 * if neither was found.
5991 */
5992xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005993xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005994 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00005995#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005996 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00005997#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005998
5999 if (node == NULL)
6000 return(NULL);
6001
6002 prop = node->properties;
Daniel Veillarde95e2392001-06-06 10:46:28 +00006003 while (prop != NULL) {
6004 /*
6005 * One need to have
6006 * - same attribute names
6007 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00006008 */
William M. Brack2c228442004-10-03 04:10:00 +00006009 if (xmlStrEqual(prop->name, name)) {
6010 if (((prop->ns != NULL) &&
6011 (xmlStrEqual(prop->ns->href, nameSpace))) ||
6012 ((prop->ns == NULL) && (nameSpace == NULL))) {
6013 return(prop);
6014 }
Daniel Veillarde95e2392001-06-06 10:46:28 +00006015 }
6016 prop = prop->next;
6017 }
6018 if (!xmlCheckDTD) return(NULL);
6019
Daniel Veillard652327a2003-09-29 18:02:38 +00006020#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00006021 /*
6022 * Check if there is a default declaration in the internal
6023 * or external subsets
6024 */
6025 doc = node->doc;
6026 if (doc != NULL) {
6027 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006028 xmlAttributePtr attrDecl = NULL;
6029 xmlNsPtr *nsList, *cur;
6030 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00006031
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006032 nsList = xmlGetNsList(node->doc, node);
6033 if (nsList == NULL)
6034 return(NULL);
6035 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
6036 ename = xmlStrdup(node->ns->prefix);
6037 ename = xmlStrcat(ename, BAD_CAST ":");
6038 ename = xmlStrcat(ename, node->name);
6039 } else {
6040 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006041 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006042 if (ename == NULL) {
6043 xmlFree(nsList);
6044 return(NULL);
6045 }
6046
William M. Brack2c228442004-10-03 04:10:00 +00006047 if (nameSpace == NULL) {
6048 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
6049 name, NULL);
6050 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
6051 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6052 name, NULL);
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006053 }
William M. Brack2c228442004-10-03 04:10:00 +00006054 } else {
6055 cur = nsList;
6056 while (*cur != NULL) {
6057 if (xmlStrEqual((*cur)->href, nameSpace)) {
6058 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
6059 name, (*cur)->prefix);
6060 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6061 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6062 name, (*cur)->prefix);
6063 }
6064 cur++;
6065 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006066 }
6067 xmlFree(nsList);
6068 xmlFree(ename);
6069 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006070 }
6071 }
Daniel Veillard652327a2003-09-29 18:02:38 +00006072#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00006073 return(NULL);
6074}
6075
6076/**
Owen Taylor3473f882001-02-23 17:55:21 +00006077 * xmlGetProp:
6078 * @node: the node
6079 * @name: the attribute name
6080 *
6081 * Search and get the value of an attribute associated to a node
6082 * This does the entity substitution.
6083 * This function looks in DTD attribute declaration for #FIXED or
6084 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00006085 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00006086 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6087 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00006088 *
6089 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006090 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006091 */
6092xmlChar *
6093xmlGetProp(xmlNodePtr node, const xmlChar *name) {
6094 xmlAttrPtr prop;
6095 xmlDocPtr doc;
6096
6097 if ((node == NULL) || (name == NULL)) return(NULL);
6098 /*
6099 * Check on the properties attached to the node
6100 */
6101 prop = node->properties;
6102 while (prop != NULL) {
6103 if (xmlStrEqual(prop->name, name)) {
6104 xmlChar *ret;
6105
6106 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6107 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6108 return(ret);
6109 }
6110 prop = prop->next;
6111 }
6112 if (!xmlCheckDTD) return(NULL);
6113
6114 /*
6115 * Check if there is a default declaration in the internal
6116 * or external subsets
6117 */
6118 doc = node->doc;
6119 if (doc != NULL) {
6120 xmlAttributePtr attrDecl;
6121 if (doc->intSubset != NULL) {
6122 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6123 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6124 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006125 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6126 /* return attribute declaration only if a default value is given
6127 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006128 return(xmlStrdup(attrDecl->defaultValue));
6129 }
6130 }
6131 return(NULL);
6132}
6133
6134/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006135 * xmlGetNoNsProp:
6136 * @node: the node
6137 * @name: the attribute name
6138 *
6139 * Search and get the value of an attribute associated to a node
6140 * This does the entity substitution.
6141 * This function looks in DTD attribute declaration for #FIXED or
6142 * default declaration values unless DTD use has been turned off.
6143 * This function is similar to xmlGetProp except it will accept only
6144 * an attribute in no namespace.
6145 *
6146 * Returns the attribute value or NULL if not found.
6147 * It's up to the caller to free the memory with xmlFree().
6148 */
6149xmlChar *
6150xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6151 xmlAttrPtr prop;
6152 xmlDocPtr doc;
6153
6154 if ((node == NULL) || (name == NULL)) return(NULL);
6155 /*
6156 * Check on the properties attached to the node
6157 */
6158 prop = node->properties;
6159 while (prop != NULL) {
6160 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6161 xmlChar *ret;
6162
6163 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6164 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6165 return(ret);
6166 }
6167 prop = prop->next;
6168 }
6169 if (!xmlCheckDTD) return(NULL);
6170
6171 /*
6172 * Check if there is a default declaration in the internal
6173 * or external subsets
6174 */
6175 doc = node->doc;
6176 if (doc != NULL) {
6177 xmlAttributePtr attrDecl;
6178 if (doc->intSubset != NULL) {
6179 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6180 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6181 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006182 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6183 /* return attribute declaration only if a default value is given
6184 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006185 return(xmlStrdup(attrDecl->defaultValue));
6186 }
6187 }
6188 return(NULL);
6189}
6190
6191/**
Owen Taylor3473f882001-02-23 17:55:21 +00006192 * xmlGetNsProp:
6193 * @node: the node
6194 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006195 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006196 *
6197 * Search and get the value of an attribute associated to a node
6198 * This attribute has to be anchored in the namespace specified.
6199 * This does the entity substitution.
6200 * This function looks in DTD attribute declaration for #FIXED or
6201 * default declaration values unless DTD use has been turned off.
6202 *
6203 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006204 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006205 */
6206xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006207xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006208 xmlAttrPtr prop;
6209 xmlDocPtr doc;
6210 xmlNsPtr ns;
6211
6212 if (node == NULL)
6213 return(NULL);
6214
6215 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006216 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006217 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006218 while (prop != NULL) {
6219 /*
6220 * One need to have
6221 * - same attribute names
6222 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006223 */
6224 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006225 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006226 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006227 xmlChar *ret;
6228
6229 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6230 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6231 return(ret);
6232 }
6233 prop = prop->next;
6234 }
6235 if (!xmlCheckDTD) return(NULL);
6236
6237 /*
6238 * Check if there is a default declaration in the internal
6239 * or external subsets
6240 */
6241 doc = node->doc;
6242 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006243 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006244 xmlAttributePtr attrDecl;
6245
Owen Taylor3473f882001-02-23 17:55:21 +00006246 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6247 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6248 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6249
6250 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6251 /*
6252 * The DTD declaration only allows a prefix search
6253 */
6254 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006255 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006256 return(xmlStrdup(attrDecl->defaultValue));
6257 }
6258 }
6259 }
6260 return(NULL);
6261}
6262
Daniel Veillard2156d432004-03-04 15:59:36 +00006263#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6264/**
6265 * xmlUnsetProp:
6266 * @node: the node
6267 * @name: the attribute name
6268 *
6269 * Remove an attribute carried by a node.
6270 * Returns 0 if successful, -1 if not found
6271 */
6272int
6273xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
6274 xmlAttrPtr prop, prev = NULL;;
6275
6276 if ((node == NULL) || (name == NULL))
6277 return(-1);
6278 prop = node->properties;
6279 while (prop != NULL) {
6280 if ((xmlStrEqual(prop->name, name)) &&
6281 (prop->ns == NULL)) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006282 if (prev == NULL) {
Daniel Veillard2156d432004-03-04 15:59:36 +00006283 node->properties = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006284 if (prop->next != NULL)
6285 prop->next->prev = NULL;
6286 } else {
Daniel Veillard2156d432004-03-04 15:59:36 +00006287 prev->next = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006288 if (prop->next != NULL)
6289 prop->next->prev = NULL;
6290 }
6291 prop->next = NULL;
6292 prop->prev = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00006293 xmlFreeProp(prop);
6294 return(0);
6295 }
6296 prev = prop;
6297 prop = prop->next;
6298 }
6299 return(-1);
6300}
6301
6302/**
6303 * xmlUnsetNsProp:
6304 * @node: the node
6305 * @ns: the namespace definition
6306 * @name: the attribute name
6307 *
6308 * Remove an attribute carried by a node.
6309 * Returns 0 if successful, -1 if not found
6310 */
6311int
6312xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6313 xmlAttrPtr prop = node->properties, prev = NULL;;
6314
6315 if ((node == NULL) || (name == NULL))
6316 return(-1);
6317 if (ns == NULL)
6318 return(xmlUnsetProp(node, name));
6319 if (ns->href == NULL)
6320 return(-1);
6321 while (prop != NULL) {
6322 if ((xmlStrEqual(prop->name, name)) &&
6323 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006324 if (prev == NULL) {
Daniel Veillard2156d432004-03-04 15:59:36 +00006325 node->properties = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006326 if (prop->next != NULL)
6327 prop->next->prev = NULL;
6328 } else {
Daniel Veillard2156d432004-03-04 15:59:36 +00006329 prev->next = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006330 if (prop->next != NULL)
6331 prop->next->prev = NULL;
6332 }
6333 prop->next = NULL;
6334 prop->prev = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00006335 xmlFreeProp(prop);
6336 return(0);
6337 }
6338 prev = prop;
6339 prop = prop->next;
6340 }
6341 return(-1);
6342}
6343#endif
6344
6345#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006346/**
6347 * xmlSetProp:
6348 * @node: the node
6349 * @name: the attribute name
6350 * @value: the attribute value
6351 *
6352 * Set (or reset) an attribute carried by a node.
6353 * Returns the attribute pointer.
6354 */
6355xmlAttrPtr
6356xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006357 xmlAttrPtr prop;
6358 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006359
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006360 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006361 return(NULL);
6362 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006363 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006364 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006365 if ((xmlStrEqual(prop->name, name)) &&
6366 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006367 xmlNodePtr oldprop = prop->children;
6368
Owen Taylor3473f882001-02-23 17:55:21 +00006369 prop->children = NULL;
6370 prop->last = NULL;
6371 if (value != NULL) {
6372 xmlChar *buffer;
6373 xmlNodePtr tmp;
6374
6375 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6376 prop->children = xmlStringGetNodeList(node->doc, buffer);
6377 prop->last = NULL;
6378 prop->doc = doc;
6379 tmp = prop->children;
6380 while (tmp != NULL) {
6381 tmp->parent = (xmlNodePtr) prop;
6382 tmp->doc = doc;
6383 if (tmp->next == NULL)
6384 prop->last = tmp;
6385 tmp = tmp->next;
6386 }
6387 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006388 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006389 if (oldprop != NULL)
6390 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006391 return(prop);
6392 }
6393 prop = prop->next;
6394 }
6395 prop = xmlNewProp(node, name, value);
6396 return(prop);
6397}
6398
6399/**
6400 * xmlSetNsProp:
6401 * @node: the node
6402 * @ns: the namespace definition
6403 * @name: the attribute name
6404 * @value: the attribute value
6405 *
6406 * Set (or reset) an attribute carried by a node.
6407 * The ns structure must be in scope, this is not checked.
6408 *
6409 * Returns the attribute pointer.
6410 */
6411xmlAttrPtr
6412xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6413 const xmlChar *value) {
6414 xmlAttrPtr prop;
6415
6416 if ((node == NULL) || (name == NULL))
6417 return(NULL);
6418
6419 if (ns == NULL)
6420 return(xmlSetProp(node, name, value));
6421 if (ns->href == NULL)
6422 return(NULL);
6423 prop = node->properties;
6424
6425 while (prop != NULL) {
6426 /*
6427 * One need to have
6428 * - same attribute names
6429 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006430 */
6431 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006432 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006433 if (prop->children != NULL)
6434 xmlFreeNodeList(prop->children);
6435 prop->children = NULL;
6436 prop->last = NULL;
6437 prop->ns = ns;
6438 if (value != NULL) {
6439 xmlChar *buffer;
6440 xmlNodePtr tmp;
6441
6442 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6443 prop->children = xmlStringGetNodeList(node->doc, buffer);
6444 prop->last = NULL;
6445 tmp = prop->children;
6446 while (tmp != NULL) {
6447 tmp->parent = (xmlNodePtr) prop;
6448 if (tmp->next == NULL)
6449 prop->last = tmp;
6450 tmp = tmp->next;
6451 }
6452 xmlFree(buffer);
6453 }
6454 return(prop);
6455 }
6456 prop = prop->next;
6457 }
6458 prop = xmlNewNsProp(node, ns, name, value);
6459 return(prop);
6460}
6461
Daniel Veillard652327a2003-09-29 18:02:38 +00006462#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006463
6464/**
Owen Taylor3473f882001-02-23 17:55:21 +00006465 * xmlNodeIsText:
6466 * @node: the node
6467 *
6468 * Is this node a Text node ?
6469 * Returns 1 yes, 0 no
6470 */
6471int
6472xmlNodeIsText(xmlNodePtr node) {
6473 if (node == NULL) return(0);
6474
6475 if (node->type == XML_TEXT_NODE) return(1);
6476 return(0);
6477}
6478
6479/**
6480 * xmlIsBlankNode:
6481 * @node: the node
6482 *
6483 * Checks whether this node is an empty or whitespace only
6484 * (and possibly ignorable) text-node.
6485 *
6486 * Returns 1 yes, 0 no
6487 */
6488int
6489xmlIsBlankNode(xmlNodePtr node) {
6490 const xmlChar *cur;
6491 if (node == NULL) return(0);
6492
Daniel Veillard7db37732001-07-12 01:20:08 +00006493 if ((node->type != XML_TEXT_NODE) &&
6494 (node->type != XML_CDATA_SECTION_NODE))
6495 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006496 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006497 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006498 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006499 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006500 cur++;
6501 }
6502
6503 return(1);
6504}
6505
6506/**
6507 * xmlTextConcat:
6508 * @node: the node
6509 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006510 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006511 *
6512 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006513 *
6514 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006515 */
6516
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006517int
Owen Taylor3473f882001-02-23 17:55:21 +00006518xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006519 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006520
6521 if ((node->type != XML_TEXT_NODE) &&
6522 (node->type != XML_CDATA_SECTION_NODE)) {
6523#ifdef DEBUG_TREE
6524 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006525 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006526#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006527 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006528 }
William M. Brack7762bb12004-01-04 14:49:01 +00006529 /* need to check if content is currently in the dictionary */
6530 if ((node->doc != NULL) && (node->doc->dict != NULL) &&
6531 xmlDictOwns(node->doc->dict, node->content)) {
6532 node->content = xmlStrncatNew(node->content, content, len);
6533 } else {
6534 node->content = xmlStrncat(node->content, content, len);
6535 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006536 if (node->content == NULL)
6537 return(-1);
6538 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006539}
6540
6541/************************************************************************
6542 * *
6543 * Output : to a FILE or in memory *
6544 * *
6545 ************************************************************************/
6546
Owen Taylor3473f882001-02-23 17:55:21 +00006547/**
6548 * xmlBufferCreate:
6549 *
6550 * routine to create an XML buffer.
6551 * returns the new structure.
6552 */
6553xmlBufferPtr
6554xmlBufferCreate(void) {
6555 xmlBufferPtr ret;
6556
6557 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6558 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006559 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006560 return(NULL);
6561 }
6562 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006563 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006564 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006565 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006566 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006567 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006568 xmlFree(ret);
6569 return(NULL);
6570 }
6571 ret->content[0] = 0;
6572 return(ret);
6573}
6574
6575/**
6576 * xmlBufferCreateSize:
6577 * @size: initial size of buffer
6578 *
6579 * routine to create an XML buffer.
6580 * returns the new structure.
6581 */
6582xmlBufferPtr
6583xmlBufferCreateSize(size_t size) {
6584 xmlBufferPtr ret;
6585
6586 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6587 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006588 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006589 return(NULL);
6590 }
6591 ret->use = 0;
6592 ret->alloc = xmlBufferAllocScheme;
6593 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6594 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006595 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006596 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006597 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006598 xmlFree(ret);
6599 return(NULL);
6600 }
6601 ret->content[0] = 0;
6602 } else
6603 ret->content = NULL;
6604 return(ret);
6605}
6606
6607/**
Daniel Veillard53350552003-09-18 13:35:51 +00006608 * xmlBufferCreateStatic:
6609 * @mem: the memory area
6610 * @size: the size in byte
6611 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006612 * routine to create an XML buffer from an immutable memory area.
6613 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006614 * present until the end of the buffer lifetime.
6615 *
6616 * returns the new structure.
6617 */
6618xmlBufferPtr
6619xmlBufferCreateStatic(void *mem, size_t size) {
6620 xmlBufferPtr ret;
6621
6622 if ((mem == NULL) || (size == 0))
6623 return(NULL);
6624
6625 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6626 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006627 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006628 return(NULL);
6629 }
6630 ret->use = size;
6631 ret->size = size;
6632 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6633 ret->content = (xmlChar *) mem;
6634 return(ret);
6635}
6636
6637/**
Owen Taylor3473f882001-02-23 17:55:21 +00006638 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006639 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006640 * @scheme: allocation scheme to use
6641 *
6642 * Sets the allocation scheme for this buffer
6643 */
6644void
6645xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6646 xmlBufferAllocationScheme scheme) {
6647 if (buf == NULL) {
6648#ifdef DEBUG_BUFFER
6649 xmlGenericError(xmlGenericErrorContext,
6650 "xmlBufferSetAllocationScheme: buf == NULL\n");
6651#endif
6652 return;
6653 }
Daniel Veillard53350552003-09-18 13:35:51 +00006654 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006655
6656 buf->alloc = scheme;
6657}
6658
6659/**
6660 * xmlBufferFree:
6661 * @buf: the buffer to free
6662 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006663 * Frees an XML buffer. It frees both the content and the structure which
6664 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006665 */
6666void
6667xmlBufferFree(xmlBufferPtr buf) {
6668 if (buf == NULL) {
6669#ifdef DEBUG_BUFFER
6670 xmlGenericError(xmlGenericErrorContext,
6671 "xmlBufferFree: buf == NULL\n");
6672#endif
6673 return;
6674 }
Daniel Veillard53350552003-09-18 13:35:51 +00006675
6676 if ((buf->content != NULL) &&
6677 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006678 xmlFree(buf->content);
6679 }
Owen Taylor3473f882001-02-23 17:55:21 +00006680 xmlFree(buf);
6681}
6682
6683/**
6684 * xmlBufferEmpty:
6685 * @buf: the buffer
6686 *
6687 * empty a buffer.
6688 */
6689void
6690xmlBufferEmpty(xmlBufferPtr buf) {
6691 if (buf->content == NULL) return;
6692 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006693 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006694 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006695 } else {
6696 memset(buf->content, 0, buf->size);
6697 }
Owen Taylor3473f882001-02-23 17:55:21 +00006698}
6699
6700/**
6701 * xmlBufferShrink:
6702 * @buf: the buffer to dump
6703 * @len: the number of xmlChar to remove
6704 *
6705 * Remove the beginning of an XML buffer.
6706 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006707 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006708 */
6709int
6710xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6711 if (len == 0) return(0);
6712 if (len > buf->use) return(-1);
6713
6714 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006715 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6716 buf->content += len;
6717 } else {
6718 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6719 buf->content[buf->use] = 0;
6720 }
Owen Taylor3473f882001-02-23 17:55:21 +00006721 return(len);
6722}
6723
6724/**
6725 * xmlBufferGrow:
6726 * @buf: the buffer
6727 * @len: the minimum free size to allocate
6728 *
6729 * Grow the available space of an XML buffer.
6730 *
6731 * Returns the new available space or -1 in case of error
6732 */
6733int
6734xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6735 int size;
6736 xmlChar *newbuf;
6737
Daniel Veillard53350552003-09-18 13:35:51 +00006738 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006739 if (len + buf->use < buf->size) return(0);
6740
William M. Brack30fe43f2004-07-26 18:00:58 +00006741/*
6742 * Windows has a BIG problem on realloc timing, so we try to double
6743 * the buffer size (if that's enough) (bug 146697)
6744 */
6745#ifdef WIN32
6746 if (buf->size > len)
6747 size = buf->size * 2;
6748 else
6749 size = buf->use + len + 100;
6750#else
Owen Taylor3473f882001-02-23 17:55:21 +00006751 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00006752#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006753
6754 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006755 if (newbuf == NULL) {
6756 xmlTreeErrMemory("growing buffer");
6757 return(-1);
6758 }
Owen Taylor3473f882001-02-23 17:55:21 +00006759 buf->content = newbuf;
6760 buf->size = size;
6761 return(buf->size - buf->use);
6762}
6763
6764/**
6765 * xmlBufferDump:
6766 * @file: the file output
6767 * @buf: the buffer to dump
6768 *
6769 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006770 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006771 */
6772int
6773xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6774 int ret;
6775
6776 if (buf == NULL) {
6777#ifdef DEBUG_BUFFER
6778 xmlGenericError(xmlGenericErrorContext,
6779 "xmlBufferDump: buf == NULL\n");
6780#endif
6781 return(0);
6782 }
6783 if (buf->content == NULL) {
6784#ifdef DEBUG_BUFFER
6785 xmlGenericError(xmlGenericErrorContext,
6786 "xmlBufferDump: buf->content == NULL\n");
6787#endif
6788 return(0);
6789 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006790 if (file == NULL)
6791 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006792 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6793 return(ret);
6794}
6795
6796/**
6797 * xmlBufferContent:
6798 * @buf: the buffer
6799 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006800 * Function to extract the content of a buffer
6801 *
Owen Taylor3473f882001-02-23 17:55:21 +00006802 * Returns the internal content
6803 */
6804
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006805const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006806xmlBufferContent(const xmlBufferPtr buf)
6807{
6808 if(!buf)
6809 return NULL;
6810
6811 return buf->content;
6812}
6813
6814/**
6815 * xmlBufferLength:
6816 * @buf: the buffer
6817 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006818 * Function to get the length of a buffer
6819 *
Owen Taylor3473f882001-02-23 17:55:21 +00006820 * Returns the length of data in the internal content
6821 */
6822
6823int
6824xmlBufferLength(const xmlBufferPtr buf)
6825{
6826 if(!buf)
6827 return 0;
6828
6829 return buf->use;
6830}
6831
6832/**
6833 * xmlBufferResize:
6834 * @buf: the buffer to resize
6835 * @size: the desired size
6836 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006837 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006838 *
6839 * Returns 0 in case of problems, 1 otherwise
6840 */
6841int
6842xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6843{
6844 unsigned int newSize;
6845 xmlChar* rebuf = NULL;
6846
Daniel Veillard53350552003-09-18 13:35:51 +00006847 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6848
Owen Taylor3473f882001-02-23 17:55:21 +00006849 /* Don't resize if we don't have to */
6850 if (size < buf->size)
6851 return 1;
6852
6853 /* figure out new size */
6854 switch (buf->alloc){
6855 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillardbf629492004-04-20 22:20:59 +00006856 /*take care of empty case*/
6857 newSize = (buf->size ? buf->size*2 : size + 10);
Owen Taylor3473f882001-02-23 17:55:21 +00006858 while (size > newSize) newSize *= 2;
6859 break;
6860 case XML_BUFFER_ALLOC_EXACT:
6861 newSize = size+10;
6862 break;
6863 default:
6864 newSize = size+10;
6865 break;
6866 }
6867
6868 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006869 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006870 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006871 rebuf = (xmlChar *) xmlRealloc(buf->content,
6872 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006873 } else {
6874 /*
6875 * if we are reallocating a buffer far from being full, it's
6876 * better to make a new allocation and copy only the used range
6877 * and free the old one.
6878 */
6879 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6880 if (rebuf != NULL) {
6881 memcpy(rebuf, buf->content, buf->use);
6882 xmlFree(buf->content);
William M. Brack42331a92004-07-29 07:07:16 +00006883 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006884 }
6885 }
Owen Taylor3473f882001-02-23 17:55:21 +00006886 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006887 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006888 return 0;
6889 }
6890 buf->content = rebuf;
6891 buf->size = newSize;
6892
6893 return 1;
6894}
6895
6896/**
6897 * xmlBufferAdd:
6898 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006899 * @str: the #xmlChar string
6900 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006901 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006902 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006903 * str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006904 *
6905 * Returns 0 successful, a positive error code number otherwise
6906 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006907 */
William M. Bracka3215c72004-07-31 16:24:01 +00006908int
Owen Taylor3473f882001-02-23 17:55:21 +00006909xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6910 unsigned int needSize;
6911
6912 if (str == NULL) {
6913#ifdef DEBUG_BUFFER
6914 xmlGenericError(xmlGenericErrorContext,
6915 "xmlBufferAdd: str == NULL\n");
6916#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006917 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006918 }
William M. Bracka3215c72004-07-31 16:24:01 +00006919 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006920 if (len < -1) {
6921#ifdef DEBUG_BUFFER
6922 xmlGenericError(xmlGenericErrorContext,
6923 "xmlBufferAdd: len < 0\n");
6924#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006925 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006926 }
William M. Bracka3215c72004-07-31 16:24:01 +00006927 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006928
6929 if (len < 0)
6930 len = xmlStrlen(str);
6931
William M. Bracka3215c72004-07-31 16:24:01 +00006932 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006933
6934 needSize = buf->use + len + 2;
6935 if (needSize > buf->size){
6936 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006937 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006938 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006939 }
6940 }
6941
6942 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6943 buf->use += len;
6944 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006945 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006946}
6947
6948/**
6949 * xmlBufferAddHead:
6950 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006951 * @str: the #xmlChar string
6952 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006953 *
6954 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006955 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006956 *
6957 * Returns 0 successful, a positive error code number otherwise
6958 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006959 */
William M. Bracka3215c72004-07-31 16:24:01 +00006960int
Owen Taylor3473f882001-02-23 17:55:21 +00006961xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6962 unsigned int needSize;
6963
William M. Bracka3215c72004-07-31 16:24:01 +00006964 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006965 if (str == NULL) {
6966#ifdef DEBUG_BUFFER
6967 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006968 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006969#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006970 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006971 }
6972 if (len < -1) {
6973#ifdef DEBUG_BUFFER
6974 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006975 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006976#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006977 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006978 }
William M. Bracka3215c72004-07-31 16:24:01 +00006979 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006980
6981 if (len < 0)
6982 len = xmlStrlen(str);
6983
William M. Bracka3215c72004-07-31 16:24:01 +00006984 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006985
6986 needSize = buf->use + len + 2;
6987 if (needSize > buf->size){
6988 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006989 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006990 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006991 }
6992 }
6993
6994 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6995 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6996 buf->use += len;
6997 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006998 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006999}
7000
7001/**
7002 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00007003 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00007004 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00007005 *
7006 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007007 *
7008 * Returns 0 successful, a positive error code number otherwise
7009 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007010 */
William M. Bracka3215c72004-07-31 16:24:01 +00007011int
Owen Taylor3473f882001-02-23 17:55:21 +00007012xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
William M. Bracka3215c72004-07-31 16:24:01 +00007013 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
7014 if (str == NULL) return -1;
7015 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00007016}
7017
7018/**
7019 * xmlBufferCCat:
7020 * @buf: the buffer to dump
7021 * @str: the C char string
7022 *
7023 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007024 *
7025 * Returns 0 successful, a positive error code number otherwise
7026 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007027 */
William M. Bracka3215c72004-07-31 16:24:01 +00007028int
Owen Taylor3473f882001-02-23 17:55:21 +00007029xmlBufferCCat(xmlBufferPtr buf, const char *str) {
7030 const char *cur;
7031
William M. Bracka3215c72004-07-31 16:24:01 +00007032 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007033 if (str == NULL) {
7034#ifdef DEBUG_BUFFER
7035 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007036 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007037#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007038 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007039 }
7040 for (cur = str;*cur != 0;cur++) {
7041 if (buf->use + 10 >= buf->size) {
7042 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007043 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007044 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007045 }
7046 }
7047 buf->content[buf->use++] = *cur;
7048 }
7049 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007050 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007051}
7052
7053/**
7054 * xmlBufferWriteCHAR:
7055 * @buf: the XML buffer
7056 * @string: the string to add
7057 *
7058 * routine which manages and grows an output buffer. This one adds
7059 * xmlChars at the end of the buffer.
7060 */
7061void
Daniel Veillard53350552003-09-18 13:35:51 +00007062xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
7063 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007064 xmlBufferCat(buf, string);
7065}
7066
7067/**
7068 * xmlBufferWriteChar:
7069 * @buf: the XML buffer output
7070 * @string: the string to add
7071 *
7072 * routine which manage and grows an output buffer. This one add
7073 * C chars at the end of the array.
7074 */
7075void
7076xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillard53350552003-09-18 13:35:51 +00007077 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007078 xmlBufferCCat(buf, string);
7079}
7080
7081
7082/**
7083 * xmlBufferWriteQuotedString:
7084 * @buf: the XML buffer output
7085 * @string: the string to add
7086 *
7087 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00007088 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00007089 * quote or double-quotes internally
7090 */
7091void
7092xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00007093 const xmlChar *cur, *base;
Daniel Veillard53350552003-09-18 13:35:51 +00007094 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00007095 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00007096 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00007097#ifdef DEBUG_BUFFER
7098 xmlGenericError(xmlGenericErrorContext,
7099 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7100#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00007101 xmlBufferCCat(buf, "\"");
7102 base = cur = string;
7103 while(*cur != 0){
7104 if(*cur == '"'){
7105 if (base != cur)
7106 xmlBufferAdd(buf, base, cur - base);
7107 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7108 cur++;
7109 base = cur;
7110 }
7111 else {
7112 cur++;
7113 }
7114 }
7115 if (base != cur)
7116 xmlBufferAdd(buf, base, cur - base);
7117 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007118 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007119 else{
7120 xmlBufferCCat(buf, "\'");
7121 xmlBufferCat(buf, string);
7122 xmlBufferCCat(buf, "\'");
7123 }
Owen Taylor3473f882001-02-23 17:55:21 +00007124 } else {
7125 xmlBufferCCat(buf, "\"");
7126 xmlBufferCat(buf, string);
7127 xmlBufferCCat(buf, "\"");
7128 }
7129}
7130
7131
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007132/**
7133 * xmlGetDocCompressMode:
7134 * @doc: the document
7135 *
7136 * get the compression ratio for a document, ZLIB based
7137 * Returns 0 (uncompressed) to 9 (max compression)
7138 */
7139int
7140xmlGetDocCompressMode (xmlDocPtr doc) {
7141 if (doc == NULL) return(-1);
7142 return(doc->compression);
7143}
7144
7145/**
7146 * xmlSetDocCompressMode:
7147 * @doc: the document
7148 * @mode: the compression ratio
7149 *
7150 * set the compression ratio for a document, ZLIB based
7151 * Correct values: 0 (uncompressed) to 9 (max compression)
7152 */
7153void
7154xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7155 if (doc == NULL) return;
7156 if (mode < 0) doc->compression = 0;
7157 else if (mode > 9) doc->compression = 9;
7158 else doc->compression = mode;
7159}
7160
7161/**
7162 * xmlGetCompressMode:
7163 *
7164 * get the default compression mode used, ZLIB based.
7165 * Returns 0 (uncompressed) to 9 (max compression)
7166 */
7167int
7168xmlGetCompressMode(void)
7169{
7170 return (xmlCompressMode);
7171}
7172
7173/**
7174 * xmlSetCompressMode:
7175 * @mode: the compression ratio
7176 *
7177 * set the default compression mode used, ZLIB based
7178 * Correct values: 0 (uncompressed) to 9 (max compression)
7179 */
7180void
7181xmlSetCompressMode(int mode) {
7182 if (mode < 0) xmlCompressMode = 0;
7183 else if (mode > 9) xmlCompressMode = 9;
7184 else xmlCompressMode = mode;
7185}
7186