blob: fb865d7941b186846785ad30dcb3bced419e8f0f [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 Veillardce244ad2004-11-05 10:03:46 +00003529 if (old == cur) return(NULL);
Daniel Veillarda03e3652004-11-02 18:45:30 +00003530 if ((old == NULL) || (old->parent == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003531#ifdef DEBUG_TREE
3532 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda03e3652004-11-02 18:45:30 +00003533 "xmlReplaceNode : old == NULL or without parent\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003534#endif
3535 return(NULL);
3536 }
3537 if (cur == NULL) {
3538 xmlUnlinkNode(old);
3539 return(old);
3540 }
3541 if (cur == old) {
3542 return(old);
3543 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003544 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3545#ifdef DEBUG_TREE
3546 xmlGenericError(xmlGenericErrorContext,
3547 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3548#endif
3549 return(old);
3550 }
3551 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3552#ifdef DEBUG_TREE
3553 xmlGenericError(xmlGenericErrorContext,
3554 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3555#endif
3556 return(old);
3557 }
Owen Taylor3473f882001-02-23 17:55:21 +00003558 xmlUnlinkNode(cur);
3559 cur->doc = old->doc;
3560 cur->parent = old->parent;
3561 cur->next = old->next;
3562 if (cur->next != NULL)
3563 cur->next->prev = cur;
3564 cur->prev = old->prev;
3565 if (cur->prev != NULL)
3566 cur->prev->next = cur;
3567 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003568 if (cur->type == XML_ATTRIBUTE_NODE) {
3569 if (cur->parent->properties == (xmlAttrPtr)old)
3570 cur->parent->properties = ((xmlAttrPtr) cur);
3571 } else {
3572 if (cur->parent->children == old)
3573 cur->parent->children = cur;
3574 if (cur->parent->last == old)
3575 cur->parent->last = cur;
3576 }
Owen Taylor3473f882001-02-23 17:55:21 +00003577 }
3578 old->next = old->prev = NULL;
3579 old->parent = NULL;
3580 return(old);
3581}
Daniel Veillard652327a2003-09-29 18:02:38 +00003582#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003583
3584/************************************************************************
3585 * *
3586 * Copy operations *
3587 * *
3588 ************************************************************************/
3589
3590/**
3591 * xmlCopyNamespace:
3592 * @cur: the namespace
3593 *
3594 * Do a copy of the namespace.
3595 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003596 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003597 */
3598xmlNsPtr
3599xmlCopyNamespace(xmlNsPtr cur) {
3600 xmlNsPtr ret;
3601
3602 if (cur == NULL) return(NULL);
3603 switch (cur->type) {
3604 case XML_LOCAL_NAMESPACE:
3605 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3606 break;
3607 default:
3608#ifdef DEBUG_TREE
3609 xmlGenericError(xmlGenericErrorContext,
3610 "xmlCopyNamespace: invalid type %d\n", cur->type);
3611#endif
3612 return(NULL);
3613 }
3614 return(ret);
3615}
3616
3617/**
3618 * xmlCopyNamespaceList:
3619 * @cur: the first namespace
3620 *
3621 * Do a copy of an namespace list.
3622 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003623 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003624 */
3625xmlNsPtr
3626xmlCopyNamespaceList(xmlNsPtr cur) {
3627 xmlNsPtr ret = NULL;
3628 xmlNsPtr p = NULL,q;
3629
3630 while (cur != NULL) {
3631 q = xmlCopyNamespace(cur);
3632 if (p == NULL) {
3633 ret = p = q;
3634 } else {
3635 p->next = q;
3636 p = q;
3637 }
3638 cur = cur->next;
3639 }
3640 return(ret);
3641}
3642
3643static xmlNodePtr
3644xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3645/**
3646 * xmlCopyProp:
3647 * @target: the element where the attribute will be grafted
3648 * @cur: the attribute
3649 *
3650 * Do a copy of the attribute.
3651 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003652 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003653 */
3654xmlAttrPtr
3655xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3656 xmlAttrPtr ret;
3657
3658 if (cur == NULL) return(NULL);
3659 if (target != NULL)
3660 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3661 else if (cur->parent != NULL)
3662 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3663 else if (cur->children != NULL)
3664 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3665 else
3666 ret = xmlNewDocProp(NULL, cur->name, NULL);
3667 if (ret == NULL) return(NULL);
3668 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003669
Owen Taylor3473f882001-02-23 17:55:21 +00003670 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003671 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003672
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003673 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3674 if (ns == NULL) {
3675 /*
3676 * Humm, we are copying an element whose namespace is defined
3677 * out of the new tree scope. Search it in the original tree
3678 * and add it at the top of the new tree
3679 */
3680 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3681 if (ns != NULL) {
3682 xmlNodePtr root = target;
3683 xmlNodePtr pred = NULL;
3684
3685 while (root->parent != NULL) {
3686 pred = root;
3687 root = root->parent;
3688 }
3689 if (root == (xmlNodePtr) target->doc) {
3690 /* correct possibly cycling above the document elt */
3691 root = pred;
3692 }
3693 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3694 }
3695 } else {
3696 /*
3697 * we have to find something appropriate here since
3698 * we cant be sure, that the namespce we found is identified
3699 * by the prefix
3700 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003701 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003702 /* this is the nice case */
3703 ret->ns = ns;
3704 } else {
3705 /*
3706 * we are in trouble: we need a new reconcilied namespace.
3707 * This is expensive
3708 */
3709 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3710 }
3711 }
3712
Owen Taylor3473f882001-02-23 17:55:21 +00003713 } else
3714 ret->ns = NULL;
3715
3716 if (cur->children != NULL) {
3717 xmlNodePtr tmp;
3718
3719 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3720 ret->last = NULL;
3721 tmp = ret->children;
3722 while (tmp != NULL) {
3723 /* tmp->parent = (xmlNodePtr)ret; */
3724 if (tmp->next == NULL)
3725 ret->last = tmp;
3726 tmp = tmp->next;
3727 }
3728 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003729 /*
3730 * Try to handle IDs
3731 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003732 if ((target!= NULL) && (cur!= NULL) &&
3733 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003734 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3735 if (xmlIsID(cur->doc, cur->parent, cur)) {
3736 xmlChar *id;
3737
3738 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3739 if (id != NULL) {
3740 xmlAddID(NULL, target->doc, id, ret);
3741 xmlFree(id);
3742 }
3743 }
3744 }
Owen Taylor3473f882001-02-23 17:55:21 +00003745 return(ret);
3746}
3747
3748/**
3749 * xmlCopyPropList:
3750 * @target: the element where the attributes will be grafted
3751 * @cur: the first attribute
3752 *
3753 * Do a copy of an attribute list.
3754 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003755 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003756 */
3757xmlAttrPtr
3758xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3759 xmlAttrPtr ret = NULL;
3760 xmlAttrPtr p = NULL,q;
3761
3762 while (cur != NULL) {
3763 q = xmlCopyProp(target, cur);
William M. Brack13dfa872004-09-18 04:52:08 +00003764 if (q == NULL)
3765 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003766 if (p == NULL) {
3767 ret = p = q;
3768 } else {
3769 p->next = q;
3770 q->prev = p;
3771 p = q;
3772 }
3773 cur = cur->next;
3774 }
3775 return(ret);
3776}
3777
3778/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003779 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003780 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003781 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003782 * tricky reason: namespaces. Doing a direct copy of a node
3783 * say RPM:Copyright without changing the namespace pointer to
3784 * something else can produce stale links. One way to do it is
3785 * to keep a reference counter but this doesn't work as soon
3786 * as one move the element or the subtree out of the scope of
3787 * the existing namespace. The actual solution seems to add
3788 * a copy of the namespace at the top of the copied tree if
3789 * not available in the subtree.
3790 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00003791 * The argument "recursive" normally indicates a recursive copy
3792 * of the node with values 0 (no) and 1 (yes). For XInclude,
3793 * however, we allow a value of 2 to indicate copy properties and
3794 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00003795 */
3796
3797static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003798xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00003799 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003800 xmlNodePtr ret;
3801
3802 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003803 switch (node->type) {
3804 case XML_TEXT_NODE:
3805 case XML_CDATA_SECTION_NODE:
3806 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003807 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003808 case XML_ENTITY_REF_NODE:
3809 case XML_ENTITY_NODE:
3810 case XML_PI_NODE:
3811 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003812 case XML_XINCLUDE_START:
3813 case XML_XINCLUDE_END:
3814 break;
3815 case XML_ATTRIBUTE_NODE:
3816 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3817 case XML_NAMESPACE_DECL:
3818 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3819
Daniel Veillard39196eb2001-06-19 18:09:42 +00003820 case XML_DOCUMENT_NODE:
3821 case XML_HTML_DOCUMENT_NODE:
3822#ifdef LIBXML_DOCB_ENABLED
3823 case XML_DOCB_DOCUMENT_NODE:
3824#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003825#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00003826 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00003827#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003828 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003829 case XML_NOTATION_NODE:
3830 case XML_DTD_NODE:
3831 case XML_ELEMENT_DECL:
3832 case XML_ATTRIBUTE_DECL:
3833 case XML_ENTITY_DECL:
3834 return(NULL);
3835 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003836
Owen Taylor3473f882001-02-23 17:55:21 +00003837 /*
3838 * Allocate a new node and fill the fields.
3839 */
3840 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3841 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003842 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003843 return(NULL);
3844 }
3845 memset(ret, 0, sizeof(xmlNode));
3846 ret->type = node->type;
3847
3848 ret->doc = doc;
3849 ret->parent = parent;
3850 if (node->name == xmlStringText)
3851 ret->name = xmlStringText;
3852 else if (node->name == xmlStringTextNoenc)
3853 ret->name = xmlStringTextNoenc;
3854 else if (node->name == xmlStringComment)
3855 ret->name = xmlStringComment;
Daniel Veillard03a53c32004-10-26 16:06:51 +00003856 else if (node->name != NULL) {
3857 if ((doc != NULL) && (doc->dict != NULL))
3858 ret->name = xmlDictLookup(doc->dict, node->name, -1);
3859 else
3860 ret->name = xmlStrdup(node->name);
3861 }
Daniel Veillard7db37732001-07-12 01:20:08 +00003862 if ((node->type != XML_ELEMENT_NODE) &&
3863 (node->content != NULL) &&
3864 (node->type != XML_ENTITY_REF_NODE) &&
3865 (node->type != XML_XINCLUDE_END) &&
3866 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003867 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003868 }else{
3869 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003870 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003871 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003872 if (parent != NULL) {
3873 xmlNodePtr tmp;
3874
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003875 /*
3876 * this is a tricky part for the node register thing:
3877 * in case ret does get coalesced in xmlAddChild
3878 * the deregister-node callback is called; so we register ret now already
3879 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003880 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003881 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3882
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003883 tmp = xmlAddChild(parent, ret);
3884 /* node could have coalesced */
3885 if (tmp != ret)
3886 return(tmp);
3887 }
Owen Taylor3473f882001-02-23 17:55:21 +00003888
William M. Brack57e9e912004-03-09 16:19:02 +00003889 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003890 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003891 if (node->nsDef != NULL)
3892 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3893
3894 if (node->ns != NULL) {
3895 xmlNsPtr ns;
3896
3897 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3898 if (ns == NULL) {
3899 /*
3900 * Humm, we are copying an element whose namespace is defined
3901 * out of the new tree scope. Search it in the original tree
3902 * and add it at the top of the new tree
3903 */
3904 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3905 if (ns != NULL) {
3906 xmlNodePtr root = ret;
3907
3908 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003909 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003910 }
3911 } else {
3912 /*
3913 * reference the existing namespace definition in our own tree.
3914 */
3915 ret->ns = ns;
3916 }
3917 }
3918 if (node->properties != NULL)
3919 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003920 if (node->type == XML_ENTITY_REF_NODE) {
3921 if ((doc == NULL) || (node->doc != doc)) {
3922 /*
3923 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003924 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003925 * we cannot keep the reference. Try to find it in the
3926 * target document.
3927 */
3928 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3929 } else {
3930 ret->children = node->children;
3931 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003932 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00003933 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003934 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003935 UPDATE_LAST_CHILD_AND_PARENT(ret)
3936 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003937
3938out:
3939 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00003940 if ((parent == NULL) &&
3941 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003942 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003943 return(ret);
3944}
3945
3946static xmlNodePtr
3947xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3948 xmlNodePtr ret = NULL;
3949 xmlNodePtr p = NULL,q;
3950
3951 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003952#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003953 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003954 if (doc == NULL) {
3955 node = node->next;
3956 continue;
3957 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003958 if (doc->intSubset == NULL) {
3959 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3960 q->doc = doc;
3961 q->parent = parent;
3962 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003963 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003964 } else {
3965 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003966 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003967 }
3968 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003969#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003970 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003971 if (ret == NULL) {
3972 q->prev = NULL;
3973 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003974 } else if (p != q) {
3975 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003976 p->next = q;
3977 q->prev = p;
3978 p = q;
3979 }
3980 node = node->next;
3981 }
3982 return(ret);
3983}
3984
3985/**
3986 * xmlCopyNode:
3987 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00003988 * @extended: if 1 do a recursive copy (properties, namespaces and children
3989 * when applicable)
3990 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00003991 *
3992 * Do a copy of the node.
3993 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003994 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003995 */
3996xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003997xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003998 xmlNodePtr ret;
3999
William M. Brack57e9e912004-03-09 16:19:02 +00004000 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00004001 return(ret);
4002}
4003
4004/**
Daniel Veillard82daa812001-04-12 08:55:36 +00004005 * xmlDocCopyNode:
4006 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00004007 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004008 * @extended: if 1 do a recursive copy (properties, namespaces and children
4009 * when applicable)
4010 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00004011 *
4012 * Do a copy of the node to a given document.
4013 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004014 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00004015 */
4016xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00004017xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00004018 xmlNodePtr ret;
4019
William M. Brack57e9e912004-03-09 16:19:02 +00004020 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00004021 return(ret);
4022}
4023
4024/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00004025 * xmlDocCopyNodeList:
4026 * @doc: the target document
4027 * @node: the first node in the list.
4028 *
4029 * Do a recursive copy of the node list.
4030 *
4031 * Returns: a new #xmlNodePtr, or NULL in case of error.
4032 */
4033xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) {
4034 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
4035 return(ret);
4036}
4037
4038/**
Owen Taylor3473f882001-02-23 17:55:21 +00004039 * xmlCopyNodeList:
4040 * @node: the first node in the list.
4041 *
4042 * Do a recursive copy of the node list.
Daniel Veillard03a53c32004-10-26 16:06:51 +00004043 * Use xmlDocCopyNodeList() if possible to ensure string interning.
Owen Taylor3473f882001-02-23 17:55:21 +00004044 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004045 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004046 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00004047xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00004048 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
4049 return(ret);
4050}
4051
Daniel Veillard2156d432004-03-04 15:59:36 +00004052#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004053/**
Owen Taylor3473f882001-02-23 17:55:21 +00004054 * xmlCopyDtd:
4055 * @dtd: the dtd
4056 *
4057 * Do a copy of the dtd.
4058 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004059 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004060 */
4061xmlDtdPtr
4062xmlCopyDtd(xmlDtdPtr dtd) {
4063 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004064 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00004065
4066 if (dtd == NULL) return(NULL);
4067 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4068 if (ret == NULL) return(NULL);
4069 if (dtd->entities != NULL)
4070 ret->entities = (void *) xmlCopyEntitiesTable(
4071 (xmlEntitiesTablePtr) dtd->entities);
4072 if (dtd->notations != NULL)
4073 ret->notations = (void *) xmlCopyNotationTable(
4074 (xmlNotationTablePtr) dtd->notations);
4075 if (dtd->elements != NULL)
4076 ret->elements = (void *) xmlCopyElementTable(
4077 (xmlElementTablePtr) dtd->elements);
4078 if (dtd->attributes != NULL)
4079 ret->attributes = (void *) xmlCopyAttributeTable(
4080 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004081 if (dtd->pentities != NULL)
4082 ret->pentities = (void *) xmlCopyEntitiesTable(
4083 (xmlEntitiesTablePtr) dtd->pentities);
4084
4085 cur = dtd->children;
4086 while (cur != NULL) {
4087 q = NULL;
4088
4089 if (cur->type == XML_ENTITY_DECL) {
4090 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4091 switch (tmp->etype) {
4092 case XML_INTERNAL_GENERAL_ENTITY:
4093 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4094 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4095 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4096 break;
4097 case XML_INTERNAL_PARAMETER_ENTITY:
4098 case XML_EXTERNAL_PARAMETER_ENTITY:
4099 q = (xmlNodePtr)
4100 xmlGetParameterEntityFromDtd(ret, tmp->name);
4101 break;
4102 case XML_INTERNAL_PREDEFINED_ENTITY:
4103 break;
4104 }
4105 } else if (cur->type == XML_ELEMENT_DECL) {
4106 xmlElementPtr tmp = (xmlElementPtr) cur;
4107 q = (xmlNodePtr)
4108 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4109 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4110 xmlAttributePtr tmp = (xmlAttributePtr) cur;
4111 q = (xmlNodePtr)
4112 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4113 } else if (cur->type == XML_COMMENT_NODE) {
4114 q = xmlCopyNode(cur, 0);
4115 }
4116
4117 if (q == NULL) {
4118 cur = cur->next;
4119 continue;
4120 }
4121
4122 if (p == NULL)
4123 ret->children = q;
4124 else
4125 p->next = q;
4126
4127 q->prev = p;
4128 q->parent = (xmlNodePtr) ret;
4129 q->next = NULL;
4130 ret->last = q;
4131 p = q;
4132 cur = cur->next;
4133 }
4134
Owen Taylor3473f882001-02-23 17:55:21 +00004135 return(ret);
4136}
Daniel Veillard2156d432004-03-04 15:59:36 +00004137#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004138
Daniel Veillard2156d432004-03-04 15:59:36 +00004139#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004140/**
4141 * xmlCopyDoc:
4142 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004143 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004144 *
4145 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004146 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004147 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004148 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004149 */
4150xmlDocPtr
4151xmlCopyDoc(xmlDocPtr doc, int recursive) {
4152 xmlDocPtr ret;
4153
4154 if (doc == NULL) return(NULL);
4155 ret = xmlNewDoc(doc->version);
4156 if (ret == NULL) return(NULL);
4157 if (doc->name != NULL)
4158 ret->name = xmlMemStrdup(doc->name);
4159 if (doc->encoding != NULL)
4160 ret->encoding = xmlStrdup(doc->encoding);
4161 ret->charset = doc->charset;
4162 ret->compression = doc->compression;
4163 ret->standalone = doc->standalone;
4164 if (!recursive) return(ret);
4165
Daniel Veillardb33c2012001-04-25 12:59:04 +00004166 ret->last = NULL;
4167 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004168#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004169 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004170 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004171 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004172 ret->intSubset->parent = ret;
4173 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004174#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004175 if (doc->oldNs != NULL)
4176 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4177 if (doc->children != NULL) {
4178 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004179
4180 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4181 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004182 ret->last = NULL;
4183 tmp = ret->children;
4184 while (tmp != NULL) {
4185 if (tmp->next == NULL)
4186 ret->last = tmp;
4187 tmp = tmp->next;
4188 }
4189 }
4190 return(ret);
4191}
Daniel Veillard652327a2003-09-29 18:02:38 +00004192#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004193
4194/************************************************************************
4195 * *
4196 * Content access functions *
4197 * *
4198 ************************************************************************/
4199
4200/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004201 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004202 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004203 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004204 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004205 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004206 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004207 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004208 */
4209long
4210xmlGetLineNo(xmlNodePtr node)
4211{
4212 long result = -1;
4213
4214 if (!node)
4215 return result;
4216 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004217 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004218 else if ((node->prev != NULL) &&
4219 ((node->prev->type == XML_ELEMENT_NODE) ||
4220 (node->prev->type == XML_TEXT_NODE)))
4221 result = xmlGetLineNo(node->prev);
4222 else if ((node->parent != NULL) &&
4223 ((node->parent->type == XML_ELEMENT_NODE) ||
4224 (node->parent->type == XML_TEXT_NODE)))
4225 result = xmlGetLineNo(node->parent);
4226
4227 return result;
4228}
4229
Daniel Veillard2156d432004-03-04 15:59:36 +00004230#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004231/**
4232 * xmlGetNodePath:
4233 * @node: a node
4234 *
4235 * Build a structure based Path for the given node
4236 *
4237 * Returns the new path or NULL in case of error. The caller must free
4238 * the returned string
4239 */
4240xmlChar *
4241xmlGetNodePath(xmlNodePtr node)
4242{
4243 xmlNodePtr cur, tmp, next;
4244 xmlChar *buffer = NULL, *temp;
4245 size_t buf_len;
4246 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004247 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004248 const char *name;
4249 char nametemp[100];
4250 int occur = 0;
4251
4252 if (node == NULL)
4253 return (NULL);
4254
4255 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004256 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004257 if (buffer == NULL) {
4258 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004259 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004260 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004261 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004262 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004263 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004264 xmlFree(buffer);
4265 return (NULL);
4266 }
4267
4268 buffer[0] = 0;
4269 cur = node;
4270 do {
4271 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004272 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004273 occur = 0;
4274 if ((cur->type == XML_DOCUMENT_NODE) ||
4275 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4276 if (buffer[0] == '/')
4277 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004278 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004279 next = NULL;
4280 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004281 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004282 name = (const char *) cur->name;
4283 if (cur->ns) {
William M. Brack84d83e32003-12-23 03:45:17 +00004284 if (cur->ns->prefix != NULL)
William M. Brack13dfa872004-09-18 04:52:08 +00004285 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4286 (char *)cur->ns->prefix, (char *)cur->name);
William M. Brack84d83e32003-12-23 03:45:17 +00004287 else
William M. Brack13dfa872004-09-18 04:52:08 +00004288 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4289 (char *)cur->name);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004290 nametemp[sizeof(nametemp) - 1] = 0;
4291 name = nametemp;
4292 }
4293 next = cur->parent;
4294
4295 /*
4296 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004297 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004298 */
4299 tmp = cur->prev;
4300 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004301 if ((tmp->type == XML_ELEMENT_NODE) &&
4302 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004303 occur++;
4304 tmp = tmp->prev;
4305 }
4306 if (occur == 0) {
4307 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004308 while (tmp != NULL && occur == 0) {
4309 if ((tmp->type == XML_ELEMENT_NODE) &&
4310 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004311 occur++;
4312 tmp = tmp->next;
4313 }
4314 if (occur != 0)
4315 occur = 1;
4316 } else
4317 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004318 } else if (cur->type == XML_COMMENT_NODE) {
4319 sep = "/";
4320 name = "comment()";
4321 next = cur->parent;
4322
4323 /*
4324 * Thumbler index computation
4325 */
4326 tmp = cur->prev;
4327 while (tmp != NULL) {
4328 if (tmp->type == XML_COMMENT_NODE)
4329 occur++;
4330 tmp = tmp->prev;
4331 }
4332 if (occur == 0) {
4333 tmp = cur->next;
4334 while (tmp != NULL && occur == 0) {
4335 if (tmp->type == XML_COMMENT_NODE)
4336 occur++;
4337 tmp = tmp->next;
4338 }
4339 if (occur != 0)
4340 occur = 1;
4341 } else
4342 occur++;
4343 } else if ((cur->type == XML_TEXT_NODE) ||
4344 (cur->type == XML_CDATA_SECTION_NODE)) {
4345 sep = "/";
4346 name = "text()";
4347 next = cur->parent;
4348
4349 /*
4350 * Thumbler index computation
4351 */
4352 tmp = cur->prev;
4353 while (tmp != NULL) {
4354 if ((cur->type == XML_TEXT_NODE) ||
4355 (cur->type == XML_CDATA_SECTION_NODE))
4356 occur++;
4357 tmp = tmp->prev;
4358 }
4359 if (occur == 0) {
4360 tmp = cur->next;
4361 while (tmp != NULL && occur == 0) {
Daniel Veillard1f8658a2004-08-14 21:46:31 +00004362 if ((tmp->type == XML_TEXT_NODE) ||
4363 (tmp->type == XML_CDATA_SECTION_NODE))
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004364 occur++;
4365 tmp = tmp->next;
4366 }
4367 if (occur != 0)
4368 occur = 1;
4369 } else
4370 occur++;
4371 } else if (cur->type == XML_PI_NODE) {
4372 sep = "/";
4373 snprintf(nametemp, sizeof(nametemp) - 1,
William M. Brack13dfa872004-09-18 04:52:08 +00004374 "processing-instruction('%s')", (char *)cur->name);
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004375 nametemp[sizeof(nametemp) - 1] = 0;
4376 name = nametemp;
4377
4378 next = cur->parent;
4379
4380 /*
4381 * Thumbler index computation
4382 */
4383 tmp = cur->prev;
4384 while (tmp != NULL) {
4385 if ((tmp->type == XML_PI_NODE) &&
4386 (xmlStrEqual(cur->name, tmp->name)))
4387 occur++;
4388 tmp = tmp->prev;
4389 }
4390 if (occur == 0) {
4391 tmp = cur->next;
4392 while (tmp != NULL && occur == 0) {
4393 if ((tmp->type == XML_PI_NODE) &&
4394 (xmlStrEqual(cur->name, tmp->name)))
4395 occur++;
4396 tmp = tmp->next;
4397 }
4398 if (occur != 0)
4399 occur = 1;
4400 } else
4401 occur++;
4402
Daniel Veillard8faa7832001-11-26 15:58:08 +00004403 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004404 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004405 name = (const char *) (((xmlAttrPtr) cur)->name);
4406 next = ((xmlAttrPtr) cur)->parent;
4407 } else {
4408 next = cur->parent;
4409 }
4410
4411 /*
4412 * Make sure there is enough room
4413 */
4414 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4415 buf_len =
4416 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4417 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4418 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004419 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004420 xmlFree(buf);
4421 xmlFree(buffer);
4422 return (NULL);
4423 }
4424 buffer = temp;
4425 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4426 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004427 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004428 xmlFree(buf);
4429 xmlFree(buffer);
4430 return (NULL);
4431 }
4432 buf = temp;
4433 }
4434 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004435 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004436 sep, name, (char *) buffer);
4437 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004438 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004439 sep, name, occur, (char *) buffer);
William M. Brack13dfa872004-09-18 04:52:08 +00004440 snprintf((char *) buffer, buf_len, "%s", (char *)buf);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004441 cur = next;
4442 } while (cur != NULL);
4443 xmlFree(buf);
4444 return (buffer);
4445}
Daniel Veillard652327a2003-09-29 18:02:38 +00004446#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004447
4448/**
Owen Taylor3473f882001-02-23 17:55:21 +00004449 * xmlDocGetRootElement:
4450 * @doc: the document
4451 *
4452 * Get the root element of the document (doc->children is a list
4453 * containing possibly comments, PIs, etc ...).
4454 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004455 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004456 */
4457xmlNodePtr
4458xmlDocGetRootElement(xmlDocPtr doc) {
4459 xmlNodePtr ret;
4460
4461 if (doc == NULL) return(NULL);
4462 ret = doc->children;
4463 while (ret != NULL) {
4464 if (ret->type == XML_ELEMENT_NODE)
4465 return(ret);
4466 ret = ret->next;
4467 }
4468 return(ret);
4469}
4470
Daniel Veillard2156d432004-03-04 15:59:36 +00004471#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004472/**
4473 * xmlDocSetRootElement:
4474 * @doc: the document
4475 * @root: the new document root element
4476 *
4477 * Set the root element of the document (doc->children is a list
4478 * containing possibly comments, PIs, etc ...).
4479 *
4480 * Returns the old root element if any was found
4481 */
4482xmlNodePtr
4483xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4484 xmlNodePtr old = NULL;
4485
4486 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004487 if (root == NULL)
4488 return(NULL);
4489 xmlUnlinkNode(root);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00004490 xmlSetTreeDoc(root, doc);
Daniel Veillardc575b992002-02-08 13:28:40 +00004491 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004492 old = doc->children;
4493 while (old != NULL) {
4494 if (old->type == XML_ELEMENT_NODE)
4495 break;
4496 old = old->next;
4497 }
4498 if (old == NULL) {
4499 if (doc->children == NULL) {
4500 doc->children = root;
4501 doc->last = root;
4502 } else {
4503 xmlAddSibling(doc->children, root);
4504 }
4505 } else {
4506 xmlReplaceNode(old, root);
4507 }
4508 return(old);
4509}
Daniel Veillard2156d432004-03-04 15:59:36 +00004510#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004511
Daniel Veillard2156d432004-03-04 15:59:36 +00004512#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004513/**
4514 * xmlNodeSetLang:
4515 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004516 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004517 *
4518 * Set the language of a node, i.e. the values of the xml:lang
4519 * attribute.
4520 */
4521void
4522xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004523 xmlNsPtr ns;
4524
Owen Taylor3473f882001-02-23 17:55:21 +00004525 if (cur == NULL) return;
4526 switch(cur->type) {
4527 case XML_TEXT_NODE:
4528 case XML_CDATA_SECTION_NODE:
4529 case XML_COMMENT_NODE:
4530 case XML_DOCUMENT_NODE:
4531 case XML_DOCUMENT_TYPE_NODE:
4532 case XML_DOCUMENT_FRAG_NODE:
4533 case XML_NOTATION_NODE:
4534 case XML_HTML_DOCUMENT_NODE:
4535 case XML_DTD_NODE:
4536 case XML_ELEMENT_DECL:
4537 case XML_ATTRIBUTE_DECL:
4538 case XML_ENTITY_DECL:
4539 case XML_PI_NODE:
4540 case XML_ENTITY_REF_NODE:
4541 case XML_ENTITY_NODE:
4542 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004543#ifdef LIBXML_DOCB_ENABLED
4544 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004545#endif
4546 case XML_XINCLUDE_START:
4547 case XML_XINCLUDE_END:
4548 return;
4549 case XML_ELEMENT_NODE:
4550 case XML_ATTRIBUTE_NODE:
4551 break;
4552 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004553 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4554 if (ns == NULL)
4555 return;
4556 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004557}
Daniel Veillard652327a2003-09-29 18:02:38 +00004558#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004559
4560/**
4561 * xmlNodeGetLang:
4562 * @cur: the node being checked
4563 *
4564 * Searches the language of a node, i.e. the values of the xml:lang
4565 * attribute or the one carried by the nearest ancestor.
4566 *
4567 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004568 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004569 */
4570xmlChar *
4571xmlNodeGetLang(xmlNodePtr cur) {
4572 xmlChar *lang;
4573
4574 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004575 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004576 if (lang != NULL)
4577 return(lang);
4578 cur = cur->parent;
4579 }
4580 return(NULL);
4581}
4582
4583
Daniel Veillard652327a2003-09-29 18:02:38 +00004584#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004585/**
4586 * xmlNodeSetSpacePreserve:
4587 * @cur: the node being changed
4588 * @val: the xml:space value ("0": default, 1: "preserve")
4589 *
4590 * Set (or reset) the space preserving behaviour of a node, i.e. the
4591 * value of the xml:space attribute.
4592 */
4593void
4594xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004595 xmlNsPtr ns;
4596
Owen Taylor3473f882001-02-23 17:55:21 +00004597 if (cur == NULL) return;
4598 switch(cur->type) {
4599 case XML_TEXT_NODE:
4600 case XML_CDATA_SECTION_NODE:
4601 case XML_COMMENT_NODE:
4602 case XML_DOCUMENT_NODE:
4603 case XML_DOCUMENT_TYPE_NODE:
4604 case XML_DOCUMENT_FRAG_NODE:
4605 case XML_NOTATION_NODE:
4606 case XML_HTML_DOCUMENT_NODE:
4607 case XML_DTD_NODE:
4608 case XML_ELEMENT_DECL:
4609 case XML_ATTRIBUTE_DECL:
4610 case XML_ENTITY_DECL:
4611 case XML_PI_NODE:
4612 case XML_ENTITY_REF_NODE:
4613 case XML_ENTITY_NODE:
4614 case XML_NAMESPACE_DECL:
4615 case XML_XINCLUDE_START:
4616 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004617#ifdef LIBXML_DOCB_ENABLED
4618 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004619#endif
4620 return;
4621 case XML_ELEMENT_NODE:
4622 case XML_ATTRIBUTE_NODE:
4623 break;
4624 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004625 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4626 if (ns == NULL)
4627 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004628 switch (val) {
4629 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004630 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004631 break;
4632 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004633 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004634 break;
4635 }
4636}
Daniel Veillard652327a2003-09-29 18:02:38 +00004637#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004638
4639/**
4640 * xmlNodeGetSpacePreserve:
4641 * @cur: the node being checked
4642 *
4643 * Searches the space preserving behaviour of a node, i.e. the values
4644 * of the xml:space attribute or the one carried by the nearest
4645 * ancestor.
4646 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004647 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004648 */
4649int
4650xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4651 xmlChar *space;
4652
4653 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004654 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004655 if (space != NULL) {
4656 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4657 xmlFree(space);
4658 return(1);
4659 }
4660 if (xmlStrEqual(space, BAD_CAST "default")) {
4661 xmlFree(space);
4662 return(0);
4663 }
4664 xmlFree(space);
4665 }
4666 cur = cur->parent;
4667 }
4668 return(-1);
4669}
4670
Daniel Veillard652327a2003-09-29 18:02:38 +00004671#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004672/**
4673 * xmlNodeSetName:
4674 * @cur: the node being changed
4675 * @name: the new tag name
4676 *
4677 * Set (or reset) the name of a node.
4678 */
4679void
4680xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00004681 xmlDocPtr doc;
4682 xmlDictPtr dict;
4683
Owen Taylor3473f882001-02-23 17:55:21 +00004684 if (cur == NULL) return;
4685 if (name == NULL) return;
4686 switch(cur->type) {
4687 case XML_TEXT_NODE:
4688 case XML_CDATA_SECTION_NODE:
4689 case XML_COMMENT_NODE:
4690 case XML_DOCUMENT_TYPE_NODE:
4691 case XML_DOCUMENT_FRAG_NODE:
4692 case XML_NOTATION_NODE:
4693 case XML_HTML_DOCUMENT_NODE:
4694 case XML_NAMESPACE_DECL:
4695 case XML_XINCLUDE_START:
4696 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004697#ifdef LIBXML_DOCB_ENABLED
4698 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004699#endif
4700 return;
4701 case XML_ELEMENT_NODE:
4702 case XML_ATTRIBUTE_NODE:
4703 case XML_PI_NODE:
4704 case XML_ENTITY_REF_NODE:
4705 case XML_ENTITY_NODE:
4706 case XML_DTD_NODE:
4707 case XML_DOCUMENT_NODE:
4708 case XML_ELEMENT_DECL:
4709 case XML_ATTRIBUTE_DECL:
4710 case XML_ENTITY_DECL:
4711 break;
4712 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00004713 doc = cur->doc;
4714 if (doc != NULL)
4715 dict = doc->dict;
4716 else
4717 dict = NULL;
4718 if (dict != NULL) {
4719 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
4720 xmlFree((xmlChar *) cur->name);
4721 cur->name = xmlDictLookup(dict, name, -1);
4722 } else {
4723 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4724 cur->name = xmlStrdup(name);
4725 }
Owen Taylor3473f882001-02-23 17:55:21 +00004726}
Daniel Veillard2156d432004-03-04 15:59:36 +00004727#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004728
Daniel Veillard2156d432004-03-04 15:59:36 +00004729#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004730/**
4731 * xmlNodeSetBase:
4732 * @cur: the node being changed
4733 * @uri: the new base URI
4734 *
4735 * Set (or reset) the base URI of a node, i.e. the value of the
4736 * xml:base attribute.
4737 */
4738void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004739xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004740 xmlNsPtr ns;
4741
Owen Taylor3473f882001-02-23 17:55:21 +00004742 if (cur == NULL) return;
4743 switch(cur->type) {
4744 case XML_TEXT_NODE:
4745 case XML_CDATA_SECTION_NODE:
4746 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004747 case XML_DOCUMENT_TYPE_NODE:
4748 case XML_DOCUMENT_FRAG_NODE:
4749 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004750 case XML_DTD_NODE:
4751 case XML_ELEMENT_DECL:
4752 case XML_ATTRIBUTE_DECL:
4753 case XML_ENTITY_DECL:
4754 case XML_PI_NODE:
4755 case XML_ENTITY_REF_NODE:
4756 case XML_ENTITY_NODE:
4757 case XML_NAMESPACE_DECL:
4758 case XML_XINCLUDE_START:
4759 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004760 return;
4761 case XML_ELEMENT_NODE:
4762 case XML_ATTRIBUTE_NODE:
4763 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004764 case XML_DOCUMENT_NODE:
4765#ifdef LIBXML_DOCB_ENABLED
4766 case XML_DOCB_DOCUMENT_NODE:
4767#endif
4768 case XML_HTML_DOCUMENT_NODE: {
4769 xmlDocPtr doc = (xmlDocPtr) cur;
4770
4771 if (doc->URL != NULL)
4772 xmlFree((xmlChar *) doc->URL);
4773 if (uri == NULL)
4774 doc->URL = NULL;
4775 else
4776 doc->URL = xmlStrdup(uri);
4777 return;
4778 }
Owen Taylor3473f882001-02-23 17:55:21 +00004779 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004780
4781 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4782 if (ns == NULL)
4783 return;
4784 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004785}
Daniel Veillard652327a2003-09-29 18:02:38 +00004786#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004787
4788/**
Owen Taylor3473f882001-02-23 17:55:21 +00004789 * xmlNodeGetBase:
4790 * @doc: the document the node pertains to
4791 * @cur: the node being checked
4792 *
4793 * Searches for the BASE URL. The code should work on both XML
4794 * and HTML document even if base mechanisms are completely different.
4795 * It returns the base as defined in RFC 2396 sections
4796 * 5.1.1. Base URI within Document Content
4797 * and
4798 * 5.1.2. Base URI from the Encapsulating Entity
4799 * However it does not return the document base (5.1.3), use
4800 * xmlDocumentGetBase() for this
4801 *
4802 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004803 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004804 */
4805xmlChar *
4806xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004807 xmlChar *oldbase = NULL;
4808 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004809
4810 if ((cur == NULL) && (doc == NULL))
4811 return(NULL);
4812 if (doc == NULL) doc = cur->doc;
4813 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4814 cur = doc->children;
4815 while ((cur != NULL) && (cur->name != NULL)) {
4816 if (cur->type != XML_ELEMENT_NODE) {
4817 cur = cur->next;
4818 continue;
4819 }
4820 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4821 cur = cur->children;
4822 continue;
4823 }
4824 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4825 cur = cur->children;
4826 continue;
4827 }
4828 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4829 return(xmlGetProp(cur, BAD_CAST "href"));
4830 }
4831 cur = cur->next;
4832 }
4833 return(NULL);
4834 }
4835 while (cur != NULL) {
4836 if (cur->type == XML_ENTITY_DECL) {
4837 xmlEntityPtr ent = (xmlEntityPtr) cur;
4838 return(xmlStrdup(ent->URI));
4839 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004840 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004841 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004842 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004843 if (oldbase != NULL) {
4844 newbase = xmlBuildURI(oldbase, base);
4845 if (newbase != NULL) {
4846 xmlFree(oldbase);
4847 xmlFree(base);
4848 oldbase = newbase;
4849 } else {
4850 xmlFree(oldbase);
4851 xmlFree(base);
4852 return(NULL);
4853 }
4854 } else {
4855 oldbase = base;
4856 }
4857 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4858 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4859 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4860 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004861 }
4862 }
Owen Taylor3473f882001-02-23 17:55:21 +00004863 cur = cur->parent;
4864 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004865 if ((doc != NULL) && (doc->URL != NULL)) {
4866 if (oldbase == NULL)
4867 return(xmlStrdup(doc->URL));
4868 newbase = xmlBuildURI(oldbase, doc->URL);
4869 xmlFree(oldbase);
4870 return(newbase);
4871 }
4872 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004873}
4874
4875/**
Daniel Veillard78697292003-10-19 20:44:43 +00004876 * xmlNodeBufGetContent:
4877 * @buffer: a buffer
4878 * @cur: the node being read
4879 *
4880 * Read the value of a node @cur, this can be either the text carried
4881 * directly by this node if it's a TEXT node or the aggregate string
4882 * of the values carried by this node child's (TEXT and ENTITY_REF).
4883 * Entity references are substituted.
4884 * Fills up the buffer @buffer with this value
4885 *
4886 * Returns 0 in case of success and -1 in case of error.
4887 */
4888int
4889xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4890{
4891 if ((cur == NULL) || (buffer == NULL)) return(-1);
4892 switch (cur->type) {
4893 case XML_CDATA_SECTION_NODE:
4894 case XML_TEXT_NODE:
4895 xmlBufferCat(buffer, cur->content);
4896 break;
4897 case XML_DOCUMENT_FRAG_NODE:
4898 case XML_ELEMENT_NODE:{
4899 xmlNodePtr tmp = cur;
4900
4901 while (tmp != NULL) {
4902 switch (tmp->type) {
4903 case XML_CDATA_SECTION_NODE:
4904 case XML_TEXT_NODE:
4905 if (tmp->content != NULL)
4906 xmlBufferCat(buffer, tmp->content);
4907 break;
4908 case XML_ENTITY_REF_NODE:
4909 xmlNodeBufGetContent(buffer, tmp->children);
4910 break;
4911 default:
4912 break;
4913 }
4914 /*
4915 * Skip to next node
4916 */
4917 if (tmp->children != NULL) {
4918 if (tmp->children->type != XML_ENTITY_DECL) {
4919 tmp = tmp->children;
4920 continue;
4921 }
4922 }
4923 if (tmp == cur)
4924 break;
4925
4926 if (tmp->next != NULL) {
4927 tmp = tmp->next;
4928 continue;
4929 }
4930
4931 do {
4932 tmp = tmp->parent;
4933 if (tmp == NULL)
4934 break;
4935 if (tmp == cur) {
4936 tmp = NULL;
4937 break;
4938 }
4939 if (tmp->next != NULL) {
4940 tmp = tmp->next;
4941 break;
4942 }
4943 } while (tmp != NULL);
4944 }
4945 break;
4946 }
4947 case XML_ATTRIBUTE_NODE:{
4948 xmlAttrPtr attr = (xmlAttrPtr) cur;
4949 xmlNodePtr tmp = attr->children;
4950
4951 while (tmp != NULL) {
4952 if (tmp->type == XML_TEXT_NODE)
4953 xmlBufferCat(buffer, tmp->content);
4954 else
4955 xmlNodeBufGetContent(buffer, tmp);
4956 tmp = tmp->next;
4957 }
4958 break;
4959 }
4960 case XML_COMMENT_NODE:
4961 case XML_PI_NODE:
4962 xmlBufferCat(buffer, cur->content);
4963 break;
4964 case XML_ENTITY_REF_NODE:{
4965 xmlEntityPtr ent;
4966 xmlNodePtr tmp;
4967
4968 /* lookup entity declaration */
4969 ent = xmlGetDocEntity(cur->doc, cur->name);
4970 if (ent == NULL)
4971 return(-1);
4972
4973 /* an entity content can be any "well balanced chunk",
4974 * i.e. the result of the content [43] production:
4975 * http://www.w3.org/TR/REC-xml#NT-content
4976 * -> we iterate through child nodes and recursive call
4977 * xmlNodeGetContent() which handles all possible node types */
4978 tmp = ent->children;
4979 while (tmp) {
4980 xmlNodeBufGetContent(buffer, tmp);
4981 tmp = tmp->next;
4982 }
4983 break;
4984 }
4985 case XML_ENTITY_NODE:
4986 case XML_DOCUMENT_TYPE_NODE:
4987 case XML_NOTATION_NODE:
4988 case XML_DTD_NODE:
4989 case XML_XINCLUDE_START:
4990 case XML_XINCLUDE_END:
4991 break;
4992 case XML_DOCUMENT_NODE:
4993#ifdef LIBXML_DOCB_ENABLED
4994 case XML_DOCB_DOCUMENT_NODE:
4995#endif
4996 case XML_HTML_DOCUMENT_NODE:
4997 cur = cur->children;
4998 while (cur!= NULL) {
4999 if ((cur->type == XML_ELEMENT_NODE) ||
5000 (cur->type == XML_TEXT_NODE) ||
5001 (cur->type == XML_CDATA_SECTION_NODE)) {
5002 xmlNodeBufGetContent(buffer, cur);
5003 }
5004 cur = cur->next;
5005 }
5006 break;
5007 case XML_NAMESPACE_DECL:
5008 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
5009 break;
5010 case XML_ELEMENT_DECL:
5011 case XML_ATTRIBUTE_DECL:
5012 case XML_ENTITY_DECL:
5013 break;
5014 }
5015 return(0);
5016}
5017/**
Owen Taylor3473f882001-02-23 17:55:21 +00005018 * xmlNodeGetContent:
5019 * @cur: the node being read
5020 *
5021 * Read the value of a node, this can be either the text carried
5022 * directly by this node if it's a TEXT node or the aggregate string
5023 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00005024 * Entity references are substituted.
5025 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005026 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005027 */
5028xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00005029xmlNodeGetContent(xmlNodePtr cur)
5030{
5031 if (cur == NULL)
5032 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005033 switch (cur->type) {
5034 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005035 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00005036 xmlBufferPtr buffer;
5037 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00005038
Daniel Veillard814a76d2003-01-23 18:24:20 +00005039 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00005040 if (buffer == NULL)
5041 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00005042 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005043 ret = buffer->content;
5044 buffer->content = NULL;
5045 xmlBufferFree(buffer);
5046 return (ret);
5047 }
5048 case XML_ATTRIBUTE_NODE:{
5049 xmlAttrPtr attr = (xmlAttrPtr) cur;
5050
5051 if (attr->parent != NULL)
5052 return (xmlNodeListGetString
5053 (attr->parent->doc, attr->children, 1));
5054 else
5055 return (xmlNodeListGetString(NULL, attr->children, 1));
5056 break;
5057 }
Owen Taylor3473f882001-02-23 17:55:21 +00005058 case XML_COMMENT_NODE:
5059 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005060 if (cur->content != NULL)
5061 return (xmlStrdup(cur->content));
5062 return (NULL);
5063 case XML_ENTITY_REF_NODE:{
5064 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00005065 xmlBufferPtr buffer;
5066 xmlChar *ret;
5067
5068 /* lookup entity declaration */
5069 ent = xmlGetDocEntity(cur->doc, cur->name);
5070 if (ent == NULL)
5071 return (NULL);
5072
5073 buffer = xmlBufferCreate();
5074 if (buffer == NULL)
5075 return (NULL);
5076
Daniel Veillardc4696922003-10-19 21:47:14 +00005077 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005078
5079 ret = buffer->content;
5080 buffer->content = NULL;
5081 xmlBufferFree(buffer);
5082 return (ret);
5083 }
Owen Taylor3473f882001-02-23 17:55:21 +00005084 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005085 case XML_DOCUMENT_TYPE_NODE:
5086 case XML_NOTATION_NODE:
5087 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005088 case XML_XINCLUDE_START:
5089 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00005090 return (NULL);
5091 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005092#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005093 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005094#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005095 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00005096 xmlBufferPtr buffer;
5097 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005098
Daniel Veillardc4696922003-10-19 21:47:14 +00005099 buffer = xmlBufferCreate();
5100 if (buffer == NULL)
5101 return (NULL);
5102
5103 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5104
5105 ret = buffer->content;
5106 buffer->content = NULL;
5107 xmlBufferFree(buffer);
5108 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005109 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005110 case XML_NAMESPACE_DECL: {
5111 xmlChar *tmp;
5112
5113 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5114 return (tmp);
5115 }
Owen Taylor3473f882001-02-23 17:55:21 +00005116 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005117 /* TODO !!! */
5118 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005119 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005120 /* TODO !!! */
5121 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005122 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005123 /* TODO !!! */
5124 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005125 case XML_CDATA_SECTION_NODE:
5126 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005127 if (cur->content != NULL)
5128 return (xmlStrdup(cur->content));
5129 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005130 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005131 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005132}
Daniel Veillard652327a2003-09-29 18:02:38 +00005133
Owen Taylor3473f882001-02-23 17:55:21 +00005134/**
5135 * xmlNodeSetContent:
5136 * @cur: the node being modified
5137 * @content: the new value of the content
5138 *
5139 * Replace the content of a node.
5140 */
5141void
5142xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5143 if (cur == NULL) {
5144#ifdef DEBUG_TREE
5145 xmlGenericError(xmlGenericErrorContext,
5146 "xmlNodeSetContent : node == NULL\n");
5147#endif
5148 return;
5149 }
5150 switch (cur->type) {
5151 case XML_DOCUMENT_FRAG_NODE:
5152 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005153 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005154 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5155 cur->children = xmlStringGetNodeList(cur->doc, content);
5156 UPDATE_LAST_CHILD_AND_PARENT(cur)
5157 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005158 case XML_TEXT_NODE:
5159 case XML_CDATA_SECTION_NODE:
5160 case XML_ENTITY_REF_NODE:
5161 case XML_ENTITY_NODE:
5162 case XML_PI_NODE:
5163 case XML_COMMENT_NODE:
5164 if (cur->content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005165 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
Daniel Veillard370ba3d2004-10-25 16:23:56 +00005166 (!xmlDictOwns(cur->doc->dict, cur->content))))
William M. Brack7762bb12004-01-04 14:49:01 +00005167 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005168 }
5169 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5170 cur->last = cur->children = NULL;
5171 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005172 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005173 } else
5174 cur->content = NULL;
5175 break;
5176 case XML_DOCUMENT_NODE:
5177 case XML_HTML_DOCUMENT_NODE:
5178 case XML_DOCUMENT_TYPE_NODE:
5179 case XML_XINCLUDE_START:
5180 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005181#ifdef LIBXML_DOCB_ENABLED
5182 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005183#endif
5184 break;
5185 case XML_NOTATION_NODE:
5186 break;
5187 case XML_DTD_NODE:
5188 break;
5189 case XML_NAMESPACE_DECL:
5190 break;
5191 case XML_ELEMENT_DECL:
5192 /* TODO !!! */
5193 break;
5194 case XML_ATTRIBUTE_DECL:
5195 /* TODO !!! */
5196 break;
5197 case XML_ENTITY_DECL:
5198 /* TODO !!! */
5199 break;
5200 }
5201}
5202
Daniel Veillard652327a2003-09-29 18:02:38 +00005203#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005204/**
5205 * xmlNodeSetContentLen:
5206 * @cur: the node being modified
5207 * @content: the new value of the content
5208 * @len: the size of @content
5209 *
5210 * Replace the content of a node.
5211 */
5212void
5213xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5214 if (cur == NULL) {
5215#ifdef DEBUG_TREE
5216 xmlGenericError(xmlGenericErrorContext,
5217 "xmlNodeSetContentLen : node == NULL\n");
5218#endif
5219 return;
5220 }
5221 switch (cur->type) {
5222 case XML_DOCUMENT_FRAG_NODE:
5223 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005224 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005225 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5226 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5227 UPDATE_LAST_CHILD_AND_PARENT(cur)
5228 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005229 case XML_TEXT_NODE:
5230 case XML_CDATA_SECTION_NODE:
5231 case XML_ENTITY_REF_NODE:
5232 case XML_ENTITY_NODE:
5233 case XML_PI_NODE:
5234 case XML_COMMENT_NODE:
5235 case XML_NOTATION_NODE:
5236 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005237 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005238 }
5239 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5240 cur->children = cur->last = NULL;
5241 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005242 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005243 } else
5244 cur->content = NULL;
5245 break;
5246 case XML_DOCUMENT_NODE:
5247 case XML_DTD_NODE:
5248 case XML_HTML_DOCUMENT_NODE:
5249 case XML_DOCUMENT_TYPE_NODE:
5250 case XML_NAMESPACE_DECL:
5251 case XML_XINCLUDE_START:
5252 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005253#ifdef LIBXML_DOCB_ENABLED
5254 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005255#endif
5256 break;
5257 case XML_ELEMENT_DECL:
5258 /* TODO !!! */
5259 break;
5260 case XML_ATTRIBUTE_DECL:
5261 /* TODO !!! */
5262 break;
5263 case XML_ENTITY_DECL:
5264 /* TODO !!! */
5265 break;
5266 }
5267}
Daniel Veillard652327a2003-09-29 18:02:38 +00005268#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005269
5270/**
5271 * xmlNodeAddContentLen:
5272 * @cur: the node being modified
5273 * @content: extra content
5274 * @len: the size of @content
5275 *
5276 * Append the extra substring to the node content.
5277 */
5278void
5279xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5280 if (cur == NULL) {
5281#ifdef DEBUG_TREE
5282 xmlGenericError(xmlGenericErrorContext,
5283 "xmlNodeAddContentLen : node == NULL\n");
5284#endif
5285 return;
5286 }
5287 if (len <= 0) return;
5288 switch (cur->type) {
5289 case XML_DOCUMENT_FRAG_NODE:
5290 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005291 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005292
Daniel Veillard7db37732001-07-12 01:20:08 +00005293 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005294 newNode = xmlNewTextLen(content, len);
5295 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005296 tmp = xmlAddChild(cur, newNode);
5297 if (tmp != newNode)
5298 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005299 if ((last != NULL) && (last->next == newNode)) {
5300 xmlTextMerge(last, newNode);
5301 }
5302 }
5303 break;
5304 }
5305 case XML_ATTRIBUTE_NODE:
5306 break;
5307 case XML_TEXT_NODE:
5308 case XML_CDATA_SECTION_NODE:
5309 case XML_ENTITY_REF_NODE:
5310 case XML_ENTITY_NODE:
5311 case XML_PI_NODE:
5312 case XML_COMMENT_NODE:
5313 case XML_NOTATION_NODE:
5314 if (content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005315 if ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5316 xmlDictOwns(cur->doc->dict, cur->content)) {
5317 cur->content =
5318 xmlStrncatNew(cur->content, content, len);
5319 break;
5320 }
Owen Taylor3473f882001-02-23 17:55:21 +00005321 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005322 }
5323 case XML_DOCUMENT_NODE:
5324 case XML_DTD_NODE:
5325 case XML_HTML_DOCUMENT_NODE:
5326 case XML_DOCUMENT_TYPE_NODE:
5327 case XML_NAMESPACE_DECL:
5328 case XML_XINCLUDE_START:
5329 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005330#ifdef LIBXML_DOCB_ENABLED
5331 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005332#endif
5333 break;
5334 case XML_ELEMENT_DECL:
5335 case XML_ATTRIBUTE_DECL:
5336 case XML_ENTITY_DECL:
5337 break;
5338 }
5339}
5340
5341/**
5342 * xmlNodeAddContent:
5343 * @cur: the node being modified
5344 * @content: extra content
5345 *
5346 * Append the extra substring to the node content.
5347 */
5348void
5349xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5350 int len;
5351
5352 if (cur == NULL) {
5353#ifdef DEBUG_TREE
5354 xmlGenericError(xmlGenericErrorContext,
5355 "xmlNodeAddContent : node == NULL\n");
5356#endif
5357 return;
5358 }
5359 if (content == NULL) return;
5360 len = xmlStrlen(content);
5361 xmlNodeAddContentLen(cur, content, len);
5362}
5363
5364/**
5365 * xmlTextMerge:
5366 * @first: the first text node
5367 * @second: the second text node being merged
5368 *
5369 * Merge two text nodes into one
5370 * Returns the first text node augmented
5371 */
5372xmlNodePtr
5373xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5374 if (first == NULL) return(second);
5375 if (second == NULL) return(first);
5376 if (first->type != XML_TEXT_NODE) return(first);
5377 if (second->type != XML_TEXT_NODE) return(first);
5378 if (second->name != first->name)
5379 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005380 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005381 xmlUnlinkNode(second);
5382 xmlFreeNode(second);
5383 return(first);
5384}
5385
Daniel Veillard2156d432004-03-04 15:59:36 +00005386#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005387/**
5388 * xmlGetNsList:
5389 * @doc: the document
5390 * @node: the current node
5391 *
5392 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005393 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005394 * that need to be freed by the caller or NULL if no
5395 * namespace if defined
5396 */
5397xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005398xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5399{
Owen Taylor3473f882001-02-23 17:55:21 +00005400 xmlNsPtr cur;
5401 xmlNsPtr *ret = NULL;
5402 int nbns = 0;
5403 int maxns = 10;
5404 int i;
5405
5406 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005407 if (node->type == XML_ELEMENT_NODE) {
5408 cur = node->nsDef;
5409 while (cur != NULL) {
5410 if (ret == NULL) {
5411 ret =
5412 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5413 sizeof(xmlNsPtr));
5414 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005415 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005416 return (NULL);
5417 }
5418 ret[nbns] = NULL;
5419 }
5420 for (i = 0; i < nbns; i++) {
5421 if ((cur->prefix == ret[i]->prefix) ||
5422 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5423 break;
5424 }
5425 if (i >= nbns) {
5426 if (nbns >= maxns) {
5427 maxns *= 2;
5428 ret = (xmlNsPtr *) xmlRealloc(ret,
5429 (maxns +
5430 1) *
5431 sizeof(xmlNsPtr));
5432 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005433 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005434 return (NULL);
5435 }
5436 }
5437 ret[nbns++] = cur;
5438 ret[nbns] = NULL;
5439 }
Owen Taylor3473f882001-02-23 17:55:21 +00005440
Daniel Veillard77044732001-06-29 21:31:07 +00005441 cur = cur->next;
5442 }
5443 }
5444 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005445 }
Daniel Veillard77044732001-06-29 21:31:07 +00005446 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005447}
Daniel Veillard652327a2003-09-29 18:02:38 +00005448#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005449
5450/**
5451 * xmlSearchNs:
5452 * @doc: the document
5453 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005454 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005455 *
5456 * Search a Ns registered under a given name space for a document.
5457 * recurse on the parents until it finds the defined namespace
5458 * or return NULL otherwise.
5459 * @nameSpace can be NULL, this is a search for the default namespace.
5460 * We don't allow to cross entities boundaries. If you don't declare
5461 * the namespace within those you will be in troubles !!! A warning
5462 * is generated to cover this case.
5463 *
5464 * Returns the namespace pointer or NULL.
5465 */
5466xmlNsPtr
5467xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005468
Owen Taylor3473f882001-02-23 17:55:21 +00005469 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005470 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005471
5472 if (node == NULL) return(NULL);
5473 if ((nameSpace != NULL) &&
5474 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005475 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5476 /*
5477 * The XML-1.0 namespace is normally held on the root
5478 * element. In this case exceptionally create it on the
5479 * node element.
5480 */
5481 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5482 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005483 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005484 return(NULL);
5485 }
5486 memset(cur, 0, sizeof(xmlNs));
5487 cur->type = XML_LOCAL_NAMESPACE;
5488 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5489 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5490 cur->next = node->nsDef;
5491 node->nsDef = cur;
5492 return(cur);
5493 }
Owen Taylor3473f882001-02-23 17:55:21 +00005494 if (doc->oldNs == NULL) {
5495 /*
5496 * Allocate a new Namespace and fill the fields.
5497 */
5498 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5499 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005500 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005501 return(NULL);
5502 }
5503 memset(doc->oldNs, 0, sizeof(xmlNs));
5504 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5505
5506 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5507 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5508 }
5509 return(doc->oldNs);
5510 }
5511 while (node != NULL) {
5512 if ((node->type == XML_ENTITY_REF_NODE) ||
5513 (node->type == XML_ENTITY_NODE) ||
5514 (node->type == XML_ENTITY_DECL))
5515 return(NULL);
5516 if (node->type == XML_ELEMENT_NODE) {
5517 cur = node->nsDef;
5518 while (cur != NULL) {
5519 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5520 (cur->href != NULL))
5521 return(cur);
5522 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5523 (cur->href != NULL) &&
5524 (xmlStrEqual(cur->prefix, nameSpace)))
5525 return(cur);
5526 cur = cur->next;
5527 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005528 if (orig != node) {
5529 cur = node->ns;
5530 if (cur != NULL) {
5531 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5532 (cur->href != NULL))
5533 return(cur);
5534 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5535 (cur->href != NULL) &&
5536 (xmlStrEqual(cur->prefix, nameSpace)))
5537 return(cur);
5538 }
5539 }
Owen Taylor3473f882001-02-23 17:55:21 +00005540 }
5541 node = node->parent;
5542 }
5543 return(NULL);
5544}
5545
5546/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005547 * xmlNsInScope:
5548 * @doc: the document
5549 * @node: the current node
5550 * @ancestor: the ancestor carrying the namespace
5551 * @prefix: the namespace prefix
5552 *
5553 * Verify that the given namespace held on @ancestor is still in scope
5554 * on node.
5555 *
5556 * Returns 1 if true, 0 if false and -1 in case of error.
5557 */
5558static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005559xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5560 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005561{
5562 xmlNsPtr tst;
5563
5564 while ((node != NULL) && (node != ancestor)) {
5565 if ((node->type == XML_ENTITY_REF_NODE) ||
5566 (node->type == XML_ENTITY_NODE) ||
5567 (node->type == XML_ENTITY_DECL))
5568 return (-1);
5569 if (node->type == XML_ELEMENT_NODE) {
5570 tst = node->nsDef;
5571 while (tst != NULL) {
5572 if ((tst->prefix == NULL)
5573 && (prefix == NULL))
5574 return (0);
5575 if ((tst->prefix != NULL)
5576 && (prefix != NULL)
5577 && (xmlStrEqual(tst->prefix, prefix)))
5578 return (0);
5579 tst = tst->next;
5580 }
5581 }
5582 node = node->parent;
5583 }
5584 if (node != ancestor)
5585 return (-1);
5586 return (1);
5587}
5588
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005589/**
Owen Taylor3473f882001-02-23 17:55:21 +00005590 * xmlSearchNsByHref:
5591 * @doc: the document
5592 * @node: the current node
5593 * @href: the namespace value
5594 *
5595 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5596 * the defined namespace or return NULL otherwise.
5597 * Returns the namespace pointer or NULL.
5598 */
5599xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005600xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5601{
Owen Taylor3473f882001-02-23 17:55:21 +00005602 xmlNsPtr cur;
5603 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005604 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005605
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005606 if ((node == NULL) || (href == NULL))
5607 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005608 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005609 /*
5610 * Only the document can hold the XML spec namespace.
5611 */
5612 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5613 /*
5614 * The XML-1.0 namespace is normally held on the root
5615 * element. In this case exceptionally create it on the
5616 * node element.
5617 */
5618 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5619 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005620 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005621 return (NULL);
5622 }
5623 memset(cur, 0, sizeof(xmlNs));
5624 cur->type = XML_LOCAL_NAMESPACE;
5625 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5626 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5627 cur->next = node->nsDef;
5628 node->nsDef = cur;
5629 return (cur);
5630 }
5631 if (doc->oldNs == NULL) {
5632 /*
5633 * Allocate a new Namespace and fill the fields.
5634 */
5635 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5636 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005637 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005638 return (NULL);
5639 }
5640 memset(doc->oldNs, 0, sizeof(xmlNs));
5641 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005642
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005643 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5644 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5645 }
5646 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005647 }
Daniel Veillard62040be2004-05-17 03:17:26 +00005648 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00005649 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005650 if ((node->type == XML_ENTITY_REF_NODE) ||
5651 (node->type == XML_ENTITY_NODE) ||
5652 (node->type == XML_ENTITY_DECL))
5653 return (NULL);
5654 if (node->type == XML_ELEMENT_NODE) {
5655 cur = node->nsDef;
5656 while (cur != NULL) {
5657 if ((cur->href != NULL) && (href != NULL) &&
5658 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005659 if (((!is_attr) || (cur->prefix != NULL)) &&
5660 (xmlNsInScope(doc, orig, node, cur->href) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005661 return (cur);
5662 }
5663 cur = cur->next;
5664 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005665 if (orig != node) {
5666 cur = node->ns;
5667 if (cur != NULL) {
5668 if ((cur->href != NULL) && (href != NULL) &&
5669 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005670 if (((!is_attr) || (cur->prefix != NULL)) &&
5671 (xmlNsInScope(doc, orig, node, cur->href) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00005672 return (cur);
5673 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005674 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005675 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005676 }
5677 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005678 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005679 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005680}
5681
5682/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005683 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005684 * @doc: the document
5685 * @tree: a node expected to hold the new namespace
5686 * @ns: the original namespace
5687 *
5688 * This function tries to locate a namespace definition in a tree
5689 * ancestors, or create a new namespace definition node similar to
5690 * @ns trying to reuse the same prefix. However if the given prefix is
5691 * null (default namespace) or reused within the subtree defined by
5692 * @tree or on one of its ancestors then a new prefix is generated.
5693 * Returns the (new) namespace definition or NULL in case of error
5694 */
5695xmlNsPtr
5696xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5697 xmlNsPtr def;
5698 xmlChar prefix[50];
5699 int counter = 1;
5700
5701 if (tree == NULL) {
5702#ifdef DEBUG_TREE
5703 xmlGenericError(xmlGenericErrorContext,
5704 "xmlNewReconciliedNs : tree == NULL\n");
5705#endif
5706 return(NULL);
5707 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00005708 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005709#ifdef DEBUG_TREE
5710 xmlGenericError(xmlGenericErrorContext,
5711 "xmlNewReconciliedNs : ns == NULL\n");
5712#endif
5713 return(NULL);
5714 }
5715 /*
5716 * Search an existing namespace definition inherited.
5717 */
5718 def = xmlSearchNsByHref(doc, tree, ns->href);
5719 if (def != NULL)
5720 return(def);
5721
5722 /*
5723 * Find a close prefix which is not already in use.
5724 * Let's strip namespace prefixes longer than 20 chars !
5725 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005726 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005727 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005728 else
William M. Brack13dfa872004-09-18 04:52:08 +00005729 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005730
Owen Taylor3473f882001-02-23 17:55:21 +00005731 def = xmlSearchNs(doc, tree, prefix);
5732 while (def != NULL) {
5733 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005734 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005735 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005736 else
William M. Brack13dfa872004-09-18 04:52:08 +00005737 snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
5738 (char *)ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005739 def = xmlSearchNs(doc, tree, prefix);
5740 }
5741
5742 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005743 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005744 */
5745 def = xmlNewNs(tree, ns->href, prefix);
5746 return(def);
5747}
5748
Daniel Veillard652327a2003-09-29 18:02:38 +00005749#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005750/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005751 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005752 * @doc: the document
5753 * @tree: a node defining the subtree to reconciliate
5754 *
5755 * This function checks that all the namespaces declared within the given
5756 * tree are properly declared. This is needed for example after Copy or Cut
5757 * and then paste operations. The subtree may still hold pointers to
5758 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005759 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005760 * the new environment. If not possible the new namespaces are redeclared
5761 * on @tree at the top of the given subtree.
5762 * Returns the number of namespace declarations created or -1 in case of error.
5763 */
5764int
5765xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5766 xmlNsPtr *oldNs = NULL;
5767 xmlNsPtr *newNs = NULL;
5768 int sizeCache = 0;
5769 int nbCache = 0;
5770
5771 xmlNsPtr n;
5772 xmlNodePtr node = tree;
5773 xmlAttrPtr attr;
5774 int ret = 0, i;
5775
Daniel Veillardce244ad2004-11-05 10:03:46 +00005776 if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1);
5777 if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1);
5778 if (node->doc != doc) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005779 while (node != NULL) {
5780 /*
5781 * Reconciliate the node namespace
5782 */
5783 if (node->ns != NULL) {
5784 /*
5785 * initialize the cache if needed
5786 */
5787 if (sizeCache == 0) {
5788 sizeCache = 10;
5789 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5790 sizeof(xmlNsPtr));
5791 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005792 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005793 return(-1);
5794 }
5795 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5796 sizeof(xmlNsPtr));
5797 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005798 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005799 xmlFree(oldNs);
5800 return(-1);
5801 }
5802 }
5803 for (i = 0;i < nbCache;i++) {
5804 if (oldNs[i] == node->ns) {
5805 node->ns = newNs[i];
5806 break;
5807 }
5808 }
5809 if (i == nbCache) {
5810 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005811 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005812 */
5813 n = xmlNewReconciliedNs(doc, tree, node->ns);
5814 if (n != NULL) { /* :-( what if else ??? */
5815 /*
5816 * check if we need to grow the cache buffers.
5817 */
5818 if (sizeCache <= nbCache) {
5819 sizeCache *= 2;
5820 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5821 sizeof(xmlNsPtr));
5822 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005823 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005824 xmlFree(newNs);
5825 return(-1);
5826 }
5827 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5828 sizeof(xmlNsPtr));
5829 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005830 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005831 xmlFree(oldNs);
5832 return(-1);
5833 }
5834 }
5835 newNs[nbCache] = n;
5836 oldNs[nbCache++] = node->ns;
5837 node->ns = n;
5838 }
5839 }
5840 }
5841 /*
5842 * now check for namespace hold by attributes on the node.
5843 */
5844 attr = node->properties;
5845 while (attr != NULL) {
5846 if (attr->ns != NULL) {
5847 /*
5848 * initialize the cache if needed
5849 */
5850 if (sizeCache == 0) {
5851 sizeCache = 10;
5852 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5853 sizeof(xmlNsPtr));
5854 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005855 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005856 return(-1);
5857 }
5858 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5859 sizeof(xmlNsPtr));
5860 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005861 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005862 xmlFree(oldNs);
5863 return(-1);
5864 }
5865 }
5866 for (i = 0;i < nbCache;i++) {
5867 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005868 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005869 break;
5870 }
5871 }
5872 if (i == nbCache) {
5873 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005874 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005875 */
5876 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5877 if (n != NULL) { /* :-( what if else ??? */
5878 /*
5879 * check if we need to grow the cache buffers.
5880 */
5881 if (sizeCache <= nbCache) {
5882 sizeCache *= 2;
5883 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5884 sizeof(xmlNsPtr));
5885 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005886 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005887 xmlFree(newNs);
5888 return(-1);
5889 }
5890 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5891 sizeof(xmlNsPtr));
5892 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005893 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005894 xmlFree(oldNs);
5895 return(-1);
5896 }
5897 }
5898 newNs[nbCache] = n;
5899 oldNs[nbCache++] = attr->ns;
5900 attr->ns = n;
5901 }
5902 }
5903 }
5904 attr = attr->next;
5905 }
5906
5907 /*
5908 * Browse the full subtree, deep first
5909 */
Daniel Veillardac996a12004-07-30 12:02:58 +00005910 if (node->children != NULL && node->type != XML_ENTITY_REF_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00005911 /* deep first */
5912 node = node->children;
5913 } else if ((node != tree) && (node->next != NULL)) {
5914 /* then siblings */
5915 node = node->next;
5916 } else if (node != tree) {
5917 /* go up to parents->next if needed */
5918 while (node != tree) {
5919 if (node->parent != NULL)
5920 node = node->parent;
5921 if ((node != tree) && (node->next != NULL)) {
5922 node = node->next;
5923 break;
5924 }
5925 if (node->parent == NULL) {
5926 node = NULL;
5927 break;
5928 }
5929 }
5930 /* exit condition */
5931 if (node == tree)
5932 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005933 } else
5934 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005935 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005936 if (oldNs != NULL)
5937 xmlFree(oldNs);
5938 if (newNs != NULL)
5939 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005940 return(ret);
5941}
Daniel Veillard652327a2003-09-29 18:02:38 +00005942#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005943
5944/**
5945 * xmlHasProp:
5946 * @node: the node
5947 * @name: the attribute name
5948 *
5949 * Search an attribute associated to a node
5950 * This function also looks in DTD attribute declaration for #FIXED or
5951 * default declaration values unless DTD use has been turned off.
5952 *
5953 * Returns the attribute or the attribute declaration or NULL if
5954 * neither was found.
5955 */
5956xmlAttrPtr
5957xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5958 xmlAttrPtr prop;
5959 xmlDocPtr doc;
5960
5961 if ((node == NULL) || (name == NULL)) return(NULL);
5962 /*
5963 * Check on the properties attached to the node
5964 */
5965 prop = node->properties;
5966 while (prop != NULL) {
5967 if (xmlStrEqual(prop->name, name)) {
5968 return(prop);
5969 }
5970 prop = prop->next;
5971 }
5972 if (!xmlCheckDTD) return(NULL);
5973
5974 /*
5975 * Check if there is a default declaration in the internal
5976 * or external subsets
5977 */
5978 doc = node->doc;
5979 if (doc != NULL) {
5980 xmlAttributePtr attrDecl;
5981 if (doc->intSubset != NULL) {
5982 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5983 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5984 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005985 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5986 /* return attribute declaration only if a default value is given
5987 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005988 return((xmlAttrPtr) attrDecl);
5989 }
5990 }
5991 return(NULL);
5992}
5993
5994/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005995 * xmlHasNsProp:
5996 * @node: the node
5997 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005998 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005999 *
6000 * Search for an attribute associated to a node
6001 * This attribute has to be anchored in the namespace specified.
6002 * This does the entity substitution.
6003 * This function looks in DTD attribute declaration for #FIXED or
6004 * default declaration values unless DTD use has been turned off.
William M. Brack2c228442004-10-03 04:10:00 +00006005 * Note that a namespace of NULL indicates to use the default namespace.
Daniel Veillarde95e2392001-06-06 10:46:28 +00006006 *
6007 * Returns the attribute or the attribute declaration or NULL
6008 * if neither was found.
6009 */
6010xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00006011xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00006012 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00006013#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00006014 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00006015#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00006016
6017 if (node == NULL)
6018 return(NULL);
6019
6020 prop = node->properties;
Daniel Veillarde95e2392001-06-06 10:46:28 +00006021 while (prop != NULL) {
6022 /*
6023 * One need to have
6024 * - same attribute names
6025 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00006026 */
William M. Brack2c228442004-10-03 04:10:00 +00006027 if (xmlStrEqual(prop->name, name)) {
6028 if (((prop->ns != NULL) &&
6029 (xmlStrEqual(prop->ns->href, nameSpace))) ||
6030 ((prop->ns == NULL) && (nameSpace == NULL))) {
6031 return(prop);
6032 }
Daniel Veillarde95e2392001-06-06 10:46:28 +00006033 }
6034 prop = prop->next;
6035 }
6036 if (!xmlCheckDTD) return(NULL);
6037
Daniel Veillard652327a2003-09-29 18:02:38 +00006038#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00006039 /*
6040 * Check if there is a default declaration in the internal
6041 * or external subsets
6042 */
6043 doc = node->doc;
6044 if (doc != NULL) {
6045 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006046 xmlAttributePtr attrDecl = NULL;
6047 xmlNsPtr *nsList, *cur;
6048 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00006049
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006050 nsList = xmlGetNsList(node->doc, node);
6051 if (nsList == NULL)
6052 return(NULL);
6053 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
6054 ename = xmlStrdup(node->ns->prefix);
6055 ename = xmlStrcat(ename, BAD_CAST ":");
6056 ename = xmlStrcat(ename, node->name);
6057 } else {
6058 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006059 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006060 if (ename == NULL) {
6061 xmlFree(nsList);
6062 return(NULL);
6063 }
6064
William M. Brack2c228442004-10-03 04:10:00 +00006065 if (nameSpace == NULL) {
6066 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
6067 name, NULL);
6068 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
6069 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6070 name, NULL);
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006071 }
William M. Brack2c228442004-10-03 04:10:00 +00006072 } else {
6073 cur = nsList;
6074 while (*cur != NULL) {
6075 if (xmlStrEqual((*cur)->href, nameSpace)) {
6076 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
6077 name, (*cur)->prefix);
6078 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6079 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6080 name, (*cur)->prefix);
6081 }
6082 cur++;
6083 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006084 }
6085 xmlFree(nsList);
6086 xmlFree(ename);
6087 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006088 }
6089 }
Daniel Veillard652327a2003-09-29 18:02:38 +00006090#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00006091 return(NULL);
6092}
6093
6094/**
Owen Taylor3473f882001-02-23 17:55:21 +00006095 * xmlGetProp:
6096 * @node: the node
6097 * @name: the attribute name
6098 *
6099 * Search and get the value of an attribute associated to a node
6100 * This does the entity substitution.
6101 * This function looks in DTD attribute declaration for #FIXED or
6102 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00006103 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00006104 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6105 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00006106 *
6107 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006108 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006109 */
6110xmlChar *
6111xmlGetProp(xmlNodePtr node, const xmlChar *name) {
6112 xmlAttrPtr prop;
6113 xmlDocPtr doc;
6114
6115 if ((node == NULL) || (name == NULL)) return(NULL);
6116 /*
6117 * Check on the properties attached to the node
6118 */
6119 prop = node->properties;
6120 while (prop != NULL) {
6121 if (xmlStrEqual(prop->name, name)) {
6122 xmlChar *ret;
6123
6124 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6125 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6126 return(ret);
6127 }
6128 prop = prop->next;
6129 }
6130 if (!xmlCheckDTD) return(NULL);
6131
6132 /*
6133 * Check if there is a default declaration in the internal
6134 * or external subsets
6135 */
6136 doc = node->doc;
6137 if (doc != NULL) {
6138 xmlAttributePtr attrDecl;
6139 if (doc->intSubset != NULL) {
6140 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6141 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6142 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006143 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6144 /* return attribute declaration only if a default value is given
6145 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006146 return(xmlStrdup(attrDecl->defaultValue));
6147 }
6148 }
6149 return(NULL);
6150}
6151
6152/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006153 * xmlGetNoNsProp:
6154 * @node: the node
6155 * @name: the attribute name
6156 *
6157 * Search and get the value of an attribute associated to a node
6158 * This does the entity substitution.
6159 * This function looks in DTD attribute declaration for #FIXED or
6160 * default declaration values unless DTD use has been turned off.
6161 * This function is similar to xmlGetProp except it will accept only
6162 * an attribute in no namespace.
6163 *
6164 * Returns the attribute value or NULL if not found.
6165 * It's up to the caller to free the memory with xmlFree().
6166 */
6167xmlChar *
6168xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6169 xmlAttrPtr prop;
6170 xmlDocPtr doc;
6171
6172 if ((node == NULL) || (name == NULL)) return(NULL);
6173 /*
6174 * Check on the properties attached to the node
6175 */
6176 prop = node->properties;
6177 while (prop != NULL) {
6178 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6179 xmlChar *ret;
6180
6181 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6182 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6183 return(ret);
6184 }
6185 prop = prop->next;
6186 }
6187 if (!xmlCheckDTD) return(NULL);
6188
6189 /*
6190 * Check if there is a default declaration in the internal
6191 * or external subsets
6192 */
6193 doc = node->doc;
6194 if (doc != NULL) {
6195 xmlAttributePtr attrDecl;
6196 if (doc->intSubset != NULL) {
6197 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6198 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6199 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006200 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6201 /* return attribute declaration only if a default value is given
6202 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006203 return(xmlStrdup(attrDecl->defaultValue));
6204 }
6205 }
6206 return(NULL);
6207}
6208
6209/**
Owen Taylor3473f882001-02-23 17:55:21 +00006210 * xmlGetNsProp:
6211 * @node: the node
6212 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006213 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006214 *
6215 * Search and get the value of an attribute associated to a node
6216 * This attribute has to be anchored in the namespace specified.
6217 * This does the entity substitution.
6218 * This function looks in DTD attribute declaration for #FIXED or
6219 * default declaration values unless DTD use has been turned off.
6220 *
6221 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006222 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006223 */
6224xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006225xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006226 xmlAttrPtr prop;
6227 xmlDocPtr doc;
6228 xmlNsPtr ns;
6229
6230 if (node == NULL)
6231 return(NULL);
6232
6233 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006234 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006235 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006236 while (prop != NULL) {
6237 /*
6238 * One need to have
6239 * - same attribute names
6240 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006241 */
6242 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006243 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006244 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006245 xmlChar *ret;
6246
6247 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6248 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6249 return(ret);
6250 }
6251 prop = prop->next;
6252 }
6253 if (!xmlCheckDTD) return(NULL);
6254
6255 /*
6256 * Check if there is a default declaration in the internal
6257 * or external subsets
6258 */
6259 doc = node->doc;
6260 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006261 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006262 xmlAttributePtr attrDecl;
6263
Owen Taylor3473f882001-02-23 17:55:21 +00006264 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6265 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6266 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6267
6268 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6269 /*
6270 * The DTD declaration only allows a prefix search
6271 */
6272 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006273 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006274 return(xmlStrdup(attrDecl->defaultValue));
6275 }
6276 }
6277 }
6278 return(NULL);
6279}
6280
Daniel Veillard2156d432004-03-04 15:59:36 +00006281#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6282/**
6283 * xmlUnsetProp:
6284 * @node: the node
6285 * @name: the attribute name
6286 *
6287 * Remove an attribute carried by a node.
6288 * Returns 0 if successful, -1 if not found
6289 */
6290int
6291xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
6292 xmlAttrPtr prop, prev = NULL;;
6293
6294 if ((node == NULL) || (name == NULL))
6295 return(-1);
6296 prop = node->properties;
6297 while (prop != NULL) {
6298 if ((xmlStrEqual(prop->name, name)) &&
6299 (prop->ns == NULL)) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006300 if (prev == NULL) {
Daniel Veillard2156d432004-03-04 15:59:36 +00006301 node->properties = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006302 if (prop->next != NULL)
6303 prop->next->prev = NULL;
6304 } else {
Daniel Veillard2156d432004-03-04 15:59:36 +00006305 prev->next = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006306 if (prop->next != NULL)
6307 prop->next->prev = NULL;
6308 }
6309 prop->next = NULL;
6310 prop->prev = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00006311 xmlFreeProp(prop);
6312 return(0);
6313 }
6314 prev = prop;
6315 prop = prop->next;
6316 }
6317 return(-1);
6318}
6319
6320/**
6321 * xmlUnsetNsProp:
6322 * @node: the node
6323 * @ns: the namespace definition
6324 * @name: the attribute name
6325 *
6326 * Remove an attribute carried by a node.
6327 * Returns 0 if successful, -1 if not found
6328 */
6329int
6330xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6331 xmlAttrPtr prop = node->properties, prev = NULL;;
6332
6333 if ((node == NULL) || (name == NULL))
6334 return(-1);
6335 if (ns == NULL)
6336 return(xmlUnsetProp(node, name));
6337 if (ns->href == NULL)
6338 return(-1);
6339 while (prop != NULL) {
6340 if ((xmlStrEqual(prop->name, name)) &&
6341 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006342 if (prev == NULL) {
Daniel Veillard2156d432004-03-04 15:59:36 +00006343 node->properties = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006344 if (prop->next != NULL)
6345 prop->next->prev = NULL;
6346 } else {
Daniel Veillard2156d432004-03-04 15:59:36 +00006347 prev->next = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006348 if (prop->next != NULL)
6349 prop->next->prev = NULL;
6350 }
6351 prop->next = NULL;
6352 prop->prev = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00006353 xmlFreeProp(prop);
6354 return(0);
6355 }
6356 prev = prop;
6357 prop = prop->next;
6358 }
6359 return(-1);
6360}
6361#endif
6362
6363#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006364/**
6365 * xmlSetProp:
6366 * @node: the node
6367 * @name: the attribute name
6368 * @value: the attribute value
6369 *
6370 * Set (or reset) an attribute carried by a node.
6371 * Returns the attribute pointer.
6372 */
6373xmlAttrPtr
6374xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006375 xmlAttrPtr prop;
6376 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006377
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006378 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006379 return(NULL);
6380 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006381 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006382 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006383 if ((xmlStrEqual(prop->name, name)) &&
6384 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006385 xmlNodePtr oldprop = prop->children;
6386
Owen Taylor3473f882001-02-23 17:55:21 +00006387 prop->children = NULL;
6388 prop->last = NULL;
6389 if (value != NULL) {
6390 xmlChar *buffer;
6391 xmlNodePtr tmp;
6392
6393 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6394 prop->children = xmlStringGetNodeList(node->doc, buffer);
6395 prop->last = NULL;
6396 prop->doc = doc;
6397 tmp = prop->children;
6398 while (tmp != NULL) {
6399 tmp->parent = (xmlNodePtr) prop;
6400 tmp->doc = doc;
6401 if (tmp->next == NULL)
6402 prop->last = tmp;
6403 tmp = tmp->next;
6404 }
6405 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006406 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006407 if (oldprop != NULL)
6408 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006409 return(prop);
6410 }
6411 prop = prop->next;
6412 }
6413 prop = xmlNewProp(node, name, value);
6414 return(prop);
6415}
6416
6417/**
6418 * xmlSetNsProp:
6419 * @node: the node
6420 * @ns: the namespace definition
6421 * @name: the attribute name
6422 * @value: the attribute value
6423 *
6424 * Set (or reset) an attribute carried by a node.
6425 * The ns structure must be in scope, this is not checked.
6426 *
6427 * Returns the attribute pointer.
6428 */
6429xmlAttrPtr
6430xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6431 const xmlChar *value) {
6432 xmlAttrPtr prop;
6433
6434 if ((node == NULL) || (name == NULL))
6435 return(NULL);
6436
6437 if (ns == NULL)
6438 return(xmlSetProp(node, name, value));
6439 if (ns->href == NULL)
6440 return(NULL);
6441 prop = node->properties;
6442
6443 while (prop != NULL) {
6444 /*
6445 * One need to have
6446 * - same attribute names
6447 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006448 */
6449 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006450 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006451 if (prop->children != NULL)
6452 xmlFreeNodeList(prop->children);
6453 prop->children = NULL;
6454 prop->last = NULL;
6455 prop->ns = ns;
6456 if (value != NULL) {
6457 xmlChar *buffer;
6458 xmlNodePtr tmp;
6459
6460 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6461 prop->children = xmlStringGetNodeList(node->doc, buffer);
6462 prop->last = NULL;
6463 tmp = prop->children;
6464 while (tmp != NULL) {
6465 tmp->parent = (xmlNodePtr) prop;
6466 if (tmp->next == NULL)
6467 prop->last = tmp;
6468 tmp = tmp->next;
6469 }
6470 xmlFree(buffer);
6471 }
6472 return(prop);
6473 }
6474 prop = prop->next;
6475 }
6476 prop = xmlNewNsProp(node, ns, name, value);
6477 return(prop);
6478}
6479
Daniel Veillard652327a2003-09-29 18:02:38 +00006480#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006481
6482/**
Owen Taylor3473f882001-02-23 17:55:21 +00006483 * xmlNodeIsText:
6484 * @node: the node
6485 *
6486 * Is this node a Text node ?
6487 * Returns 1 yes, 0 no
6488 */
6489int
6490xmlNodeIsText(xmlNodePtr node) {
6491 if (node == NULL) return(0);
6492
6493 if (node->type == XML_TEXT_NODE) return(1);
6494 return(0);
6495}
6496
6497/**
6498 * xmlIsBlankNode:
6499 * @node: the node
6500 *
6501 * Checks whether this node is an empty or whitespace only
6502 * (and possibly ignorable) text-node.
6503 *
6504 * Returns 1 yes, 0 no
6505 */
6506int
6507xmlIsBlankNode(xmlNodePtr node) {
6508 const xmlChar *cur;
6509 if (node == NULL) return(0);
6510
Daniel Veillard7db37732001-07-12 01:20:08 +00006511 if ((node->type != XML_TEXT_NODE) &&
6512 (node->type != XML_CDATA_SECTION_NODE))
6513 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006514 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006515 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006516 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006517 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006518 cur++;
6519 }
6520
6521 return(1);
6522}
6523
6524/**
6525 * xmlTextConcat:
6526 * @node: the node
6527 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006528 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006529 *
6530 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006531 *
6532 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006533 */
6534
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006535int
Owen Taylor3473f882001-02-23 17:55:21 +00006536xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006537 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006538
6539 if ((node->type != XML_TEXT_NODE) &&
6540 (node->type != XML_CDATA_SECTION_NODE)) {
6541#ifdef DEBUG_TREE
6542 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006543 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006544#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006545 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006546 }
William M. Brack7762bb12004-01-04 14:49:01 +00006547 /* need to check if content is currently in the dictionary */
6548 if ((node->doc != NULL) && (node->doc->dict != NULL) &&
6549 xmlDictOwns(node->doc->dict, node->content)) {
6550 node->content = xmlStrncatNew(node->content, content, len);
6551 } else {
6552 node->content = xmlStrncat(node->content, content, len);
6553 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006554 if (node->content == NULL)
6555 return(-1);
6556 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006557}
6558
6559/************************************************************************
6560 * *
6561 * Output : to a FILE or in memory *
6562 * *
6563 ************************************************************************/
6564
Owen Taylor3473f882001-02-23 17:55:21 +00006565/**
6566 * xmlBufferCreate:
6567 *
6568 * routine to create an XML buffer.
6569 * returns the new structure.
6570 */
6571xmlBufferPtr
6572xmlBufferCreate(void) {
6573 xmlBufferPtr ret;
6574
6575 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6576 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006577 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006578 return(NULL);
6579 }
6580 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006581 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006582 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006583 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006584 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006585 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006586 xmlFree(ret);
6587 return(NULL);
6588 }
6589 ret->content[0] = 0;
6590 return(ret);
6591}
6592
6593/**
6594 * xmlBufferCreateSize:
6595 * @size: initial size of buffer
6596 *
6597 * routine to create an XML buffer.
6598 * returns the new structure.
6599 */
6600xmlBufferPtr
6601xmlBufferCreateSize(size_t size) {
6602 xmlBufferPtr ret;
6603
6604 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6605 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006606 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006607 return(NULL);
6608 }
6609 ret->use = 0;
6610 ret->alloc = xmlBufferAllocScheme;
6611 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6612 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006613 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006614 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006615 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006616 xmlFree(ret);
6617 return(NULL);
6618 }
6619 ret->content[0] = 0;
6620 } else
6621 ret->content = NULL;
6622 return(ret);
6623}
6624
6625/**
Daniel Veillard53350552003-09-18 13:35:51 +00006626 * xmlBufferCreateStatic:
6627 * @mem: the memory area
6628 * @size: the size in byte
6629 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006630 * routine to create an XML buffer from an immutable memory area.
6631 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006632 * present until the end of the buffer lifetime.
6633 *
6634 * returns the new structure.
6635 */
6636xmlBufferPtr
6637xmlBufferCreateStatic(void *mem, size_t size) {
6638 xmlBufferPtr ret;
6639
6640 if ((mem == NULL) || (size == 0))
6641 return(NULL);
6642
6643 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6644 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006645 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006646 return(NULL);
6647 }
6648 ret->use = size;
6649 ret->size = size;
6650 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6651 ret->content = (xmlChar *) mem;
6652 return(ret);
6653}
6654
6655/**
Owen Taylor3473f882001-02-23 17:55:21 +00006656 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006657 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006658 * @scheme: allocation scheme to use
6659 *
6660 * Sets the allocation scheme for this buffer
6661 */
6662void
6663xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6664 xmlBufferAllocationScheme scheme) {
6665 if (buf == NULL) {
6666#ifdef DEBUG_BUFFER
6667 xmlGenericError(xmlGenericErrorContext,
6668 "xmlBufferSetAllocationScheme: buf == NULL\n");
6669#endif
6670 return;
6671 }
Daniel Veillard53350552003-09-18 13:35:51 +00006672 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006673
6674 buf->alloc = scheme;
6675}
6676
6677/**
6678 * xmlBufferFree:
6679 * @buf: the buffer to free
6680 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006681 * Frees an XML buffer. It frees both the content and the structure which
6682 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006683 */
6684void
6685xmlBufferFree(xmlBufferPtr buf) {
6686 if (buf == NULL) {
6687#ifdef DEBUG_BUFFER
6688 xmlGenericError(xmlGenericErrorContext,
6689 "xmlBufferFree: buf == NULL\n");
6690#endif
6691 return;
6692 }
Daniel Veillard53350552003-09-18 13:35:51 +00006693
6694 if ((buf->content != NULL) &&
6695 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006696 xmlFree(buf->content);
6697 }
Owen Taylor3473f882001-02-23 17:55:21 +00006698 xmlFree(buf);
6699}
6700
6701/**
6702 * xmlBufferEmpty:
6703 * @buf: the buffer
6704 *
6705 * empty a buffer.
6706 */
6707void
6708xmlBufferEmpty(xmlBufferPtr buf) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006709 if (buf == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006710 if (buf->content == NULL) return;
6711 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006712 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006713 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006714 } else {
6715 memset(buf->content, 0, buf->size);
6716 }
Owen Taylor3473f882001-02-23 17:55:21 +00006717}
6718
6719/**
6720 * xmlBufferShrink:
6721 * @buf: the buffer to dump
6722 * @len: the number of xmlChar to remove
6723 *
6724 * Remove the beginning of an XML buffer.
6725 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006726 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006727 */
6728int
6729xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
Daniel Veillard3d97e662004-11-04 10:49:00 +00006730 if (buf == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006731 if (len == 0) return(0);
6732 if (len > buf->use) return(-1);
6733
6734 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006735 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6736 buf->content += len;
6737 } else {
6738 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6739 buf->content[buf->use] = 0;
6740 }
Owen Taylor3473f882001-02-23 17:55:21 +00006741 return(len);
6742}
6743
6744/**
6745 * xmlBufferGrow:
6746 * @buf: the buffer
6747 * @len: the minimum free size to allocate
6748 *
6749 * Grow the available space of an XML buffer.
6750 *
6751 * Returns the new available space or -1 in case of error
6752 */
6753int
6754xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6755 int size;
6756 xmlChar *newbuf;
6757
Daniel Veillard3d97e662004-11-04 10:49:00 +00006758 if (buf == NULL) return(-1);
6759
Daniel Veillard53350552003-09-18 13:35:51 +00006760 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006761 if (len + buf->use < buf->size) return(0);
6762
William M. Brack30fe43f2004-07-26 18:00:58 +00006763/*
6764 * Windows has a BIG problem on realloc timing, so we try to double
6765 * the buffer size (if that's enough) (bug 146697)
6766 */
6767#ifdef WIN32
6768 if (buf->size > len)
6769 size = buf->size * 2;
6770 else
6771 size = buf->use + len + 100;
6772#else
Owen Taylor3473f882001-02-23 17:55:21 +00006773 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00006774#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006775
6776 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006777 if (newbuf == NULL) {
6778 xmlTreeErrMemory("growing buffer");
6779 return(-1);
6780 }
Owen Taylor3473f882001-02-23 17:55:21 +00006781 buf->content = newbuf;
6782 buf->size = size;
6783 return(buf->size - buf->use);
6784}
6785
6786/**
6787 * xmlBufferDump:
6788 * @file: the file output
6789 * @buf: the buffer to dump
6790 *
6791 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006792 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006793 */
6794int
6795xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6796 int ret;
6797
6798 if (buf == NULL) {
6799#ifdef DEBUG_BUFFER
6800 xmlGenericError(xmlGenericErrorContext,
6801 "xmlBufferDump: buf == NULL\n");
6802#endif
6803 return(0);
6804 }
6805 if (buf->content == NULL) {
6806#ifdef DEBUG_BUFFER
6807 xmlGenericError(xmlGenericErrorContext,
6808 "xmlBufferDump: buf->content == NULL\n");
6809#endif
6810 return(0);
6811 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006812 if (file == NULL)
6813 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006814 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6815 return(ret);
6816}
6817
6818/**
6819 * xmlBufferContent:
6820 * @buf: the buffer
6821 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006822 * Function to extract the content of a buffer
6823 *
Owen Taylor3473f882001-02-23 17:55:21 +00006824 * Returns the internal content
6825 */
6826
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006827const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006828xmlBufferContent(const xmlBufferPtr buf)
6829{
6830 if(!buf)
6831 return NULL;
6832
6833 return buf->content;
6834}
6835
6836/**
6837 * xmlBufferLength:
6838 * @buf: the buffer
6839 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006840 * Function to get the length of a buffer
6841 *
Owen Taylor3473f882001-02-23 17:55:21 +00006842 * Returns the length of data in the internal content
6843 */
6844
6845int
6846xmlBufferLength(const xmlBufferPtr buf)
6847{
6848 if(!buf)
6849 return 0;
6850
6851 return buf->use;
6852}
6853
6854/**
6855 * xmlBufferResize:
6856 * @buf: the buffer to resize
6857 * @size: the desired size
6858 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006859 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006860 *
6861 * Returns 0 in case of problems, 1 otherwise
6862 */
6863int
6864xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6865{
6866 unsigned int newSize;
6867 xmlChar* rebuf = NULL;
6868
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006869 if (buf == NULL)
6870 return(0);
6871
Daniel Veillard53350552003-09-18 13:35:51 +00006872 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6873
Owen Taylor3473f882001-02-23 17:55:21 +00006874 /* Don't resize if we don't have to */
6875 if (size < buf->size)
6876 return 1;
6877
6878 /* figure out new size */
6879 switch (buf->alloc){
6880 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillardbf629492004-04-20 22:20:59 +00006881 /*take care of empty case*/
6882 newSize = (buf->size ? buf->size*2 : size + 10);
Owen Taylor3473f882001-02-23 17:55:21 +00006883 while (size > newSize) newSize *= 2;
6884 break;
6885 case XML_BUFFER_ALLOC_EXACT:
6886 newSize = size+10;
6887 break;
6888 default:
6889 newSize = size+10;
6890 break;
6891 }
6892
6893 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006894 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006895 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006896 rebuf = (xmlChar *) xmlRealloc(buf->content,
6897 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006898 } else {
6899 /*
6900 * if we are reallocating a buffer far from being full, it's
6901 * better to make a new allocation and copy only the used range
6902 * and free the old one.
6903 */
6904 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6905 if (rebuf != NULL) {
6906 memcpy(rebuf, buf->content, buf->use);
6907 xmlFree(buf->content);
William M. Brack42331a92004-07-29 07:07:16 +00006908 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006909 }
6910 }
Owen Taylor3473f882001-02-23 17:55:21 +00006911 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006912 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006913 return 0;
6914 }
6915 buf->content = rebuf;
6916 buf->size = newSize;
6917
6918 return 1;
6919}
6920
6921/**
6922 * xmlBufferAdd:
6923 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006924 * @str: the #xmlChar string
6925 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006926 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006927 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006928 * str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006929 *
6930 * Returns 0 successful, a positive error code number otherwise
6931 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006932 */
William M. Bracka3215c72004-07-31 16:24:01 +00006933int
Owen Taylor3473f882001-02-23 17:55:21 +00006934xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6935 unsigned int needSize;
6936
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006937 if ((str == NULL) || (buf == NULL)) {
William M. Bracka3215c72004-07-31 16:24:01 +00006938 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006939 }
William M. Bracka3215c72004-07-31 16:24:01 +00006940 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006941 if (len < -1) {
6942#ifdef DEBUG_BUFFER
6943 xmlGenericError(xmlGenericErrorContext,
6944 "xmlBufferAdd: len < 0\n");
6945#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006946 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006947 }
William M. Bracka3215c72004-07-31 16:24:01 +00006948 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006949
6950 if (len < 0)
6951 len = xmlStrlen(str);
6952
William M. Bracka3215c72004-07-31 16:24:01 +00006953 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006954
6955 needSize = buf->use + len + 2;
6956 if (needSize > buf->size){
6957 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006958 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006959 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006960 }
6961 }
6962
6963 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6964 buf->use += len;
6965 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006966 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006967}
6968
6969/**
6970 * xmlBufferAddHead:
6971 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006972 * @str: the #xmlChar string
6973 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006974 *
6975 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006976 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006977 *
6978 * Returns 0 successful, a positive error code number otherwise
6979 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006980 */
William M. Bracka3215c72004-07-31 16:24:01 +00006981int
Owen Taylor3473f882001-02-23 17:55:21 +00006982xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6983 unsigned int needSize;
6984
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006985 if (buf == NULL)
6986 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00006987 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006988 if (str == NULL) {
6989#ifdef DEBUG_BUFFER
6990 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006991 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006992#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006993 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006994 }
6995 if (len < -1) {
6996#ifdef DEBUG_BUFFER
6997 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006998 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006999#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007000 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007001 }
William M. Bracka3215c72004-07-31 16:24:01 +00007002 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007003
7004 if (len < 0)
7005 len = xmlStrlen(str);
7006
William M. Bracka3215c72004-07-31 16:24:01 +00007007 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007008
7009 needSize = buf->use + len + 2;
7010 if (needSize > buf->size){
7011 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007012 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007013 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007014 }
7015 }
7016
7017 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
7018 memmove(&buf->content[0], str, len * sizeof(xmlChar));
7019 buf->use += len;
7020 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007021 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007022}
7023
7024/**
7025 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00007026 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00007027 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00007028 *
7029 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007030 *
7031 * Returns 0 successful, a positive error code number otherwise
7032 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007033 */
William M. Bracka3215c72004-07-31 16:24:01 +00007034int
Owen Taylor3473f882001-02-23 17:55:21 +00007035xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007036 if (buf == NULL)
7037 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007038 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
7039 if (str == NULL) return -1;
7040 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00007041}
7042
7043/**
7044 * xmlBufferCCat:
7045 * @buf: the buffer to dump
7046 * @str: the C char string
7047 *
7048 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007049 *
7050 * Returns 0 successful, a positive error code number otherwise
7051 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007052 */
William M. Bracka3215c72004-07-31 16:24:01 +00007053int
Owen Taylor3473f882001-02-23 17:55:21 +00007054xmlBufferCCat(xmlBufferPtr buf, const char *str) {
7055 const char *cur;
7056
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007057 if (buf == NULL)
7058 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007059 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007060 if (str == NULL) {
7061#ifdef DEBUG_BUFFER
7062 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007063 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007064#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007065 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007066 }
7067 for (cur = str;*cur != 0;cur++) {
7068 if (buf->use + 10 >= buf->size) {
7069 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007070 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007071 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007072 }
7073 }
7074 buf->content[buf->use++] = *cur;
7075 }
7076 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007077 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007078}
7079
7080/**
7081 * xmlBufferWriteCHAR:
7082 * @buf: the XML buffer
7083 * @string: the string to add
7084 *
7085 * routine which manages and grows an output buffer. This one adds
7086 * xmlChars at the end of the buffer.
7087 */
7088void
Daniel Veillard53350552003-09-18 13:35:51 +00007089xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007090 if (buf == NULL)
7091 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007092 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007093 xmlBufferCat(buf, string);
7094}
7095
7096/**
7097 * xmlBufferWriteChar:
7098 * @buf: the XML buffer output
7099 * @string: the string to add
7100 *
7101 * routine which manage and grows an output buffer. This one add
7102 * C chars at the end of the array.
7103 */
7104void
7105xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007106 if (buf == NULL)
7107 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007108 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007109 xmlBufferCCat(buf, string);
7110}
7111
7112
7113/**
7114 * xmlBufferWriteQuotedString:
7115 * @buf: the XML buffer output
7116 * @string: the string to add
7117 *
7118 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00007119 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00007120 * quote or double-quotes internally
7121 */
7122void
7123xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00007124 const xmlChar *cur, *base;
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007125 if (buf == NULL)
7126 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007127 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00007128 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00007129 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00007130#ifdef DEBUG_BUFFER
7131 xmlGenericError(xmlGenericErrorContext,
7132 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7133#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00007134 xmlBufferCCat(buf, "\"");
7135 base = cur = string;
7136 while(*cur != 0){
7137 if(*cur == '"'){
7138 if (base != cur)
7139 xmlBufferAdd(buf, base, cur - base);
7140 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7141 cur++;
7142 base = cur;
7143 }
7144 else {
7145 cur++;
7146 }
7147 }
7148 if (base != cur)
7149 xmlBufferAdd(buf, base, cur - base);
7150 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007151 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007152 else{
7153 xmlBufferCCat(buf, "\'");
7154 xmlBufferCat(buf, string);
7155 xmlBufferCCat(buf, "\'");
7156 }
Owen Taylor3473f882001-02-23 17:55:21 +00007157 } else {
7158 xmlBufferCCat(buf, "\"");
7159 xmlBufferCat(buf, string);
7160 xmlBufferCCat(buf, "\"");
7161 }
7162}
7163
7164
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007165/**
7166 * xmlGetDocCompressMode:
7167 * @doc: the document
7168 *
7169 * get the compression ratio for a document, ZLIB based
7170 * Returns 0 (uncompressed) to 9 (max compression)
7171 */
7172int
7173xmlGetDocCompressMode (xmlDocPtr doc) {
7174 if (doc == NULL) return(-1);
7175 return(doc->compression);
7176}
7177
7178/**
7179 * xmlSetDocCompressMode:
7180 * @doc: the document
7181 * @mode: the compression ratio
7182 *
7183 * set the compression ratio for a document, ZLIB based
7184 * Correct values: 0 (uncompressed) to 9 (max compression)
7185 */
7186void
7187xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7188 if (doc == NULL) return;
7189 if (mode < 0) doc->compression = 0;
7190 else if (mode > 9) doc->compression = 9;
7191 else doc->compression = mode;
7192}
7193
7194/**
7195 * xmlGetCompressMode:
7196 *
7197 * get the default compression mode used, ZLIB based.
7198 * Returns 0 (uncompressed) to 9 (max compression)
7199 */
7200int
7201xmlGetCompressMode(void)
7202{
7203 return (xmlCompressMode);
7204}
7205
7206/**
7207 * xmlSetCompressMode:
7208 * @mode: the compression ratio
7209 *
7210 * set the default compression mode used, ZLIB based
7211 * Correct values: 0 (uncompressed) to 9 (max compression)
7212 */
7213void
7214xmlSetCompressMode(int mode) {
7215 if (mode < 0) xmlCompressMode = 0;
7216 else if (mode > 9) xmlCompressMode = 9;
7217 else xmlCompressMode = mode;
7218}
7219