blob: 9de498d475da3a32efd9092207d83b2c5d649d19 [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
348 /*
349 * First quick algorithm for ASCII range
350 */
351 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000352 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000353 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
354 (*cur == '_'))
355 cur++;
356 else
357 goto try_complex;
358 while (((*cur >= 'a') && (*cur <= 'z')) ||
359 ((*cur >= 'A') && (*cur <= 'Z')) ||
360 ((*cur >= '0') && (*cur <= '9')) ||
361 (*cur == '_') || (*cur == '-') || (*cur == '.'))
362 cur++;
363 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000364 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000365 if (*cur == 0)
366 return(0);
367
368try_complex:
369 /*
370 * Second check for chars outside the ASCII range
371 */
372 cur = value;
373 c = CUR_SCHAR(cur, l);
374 if (space) {
375 while (IS_BLANK(c)) {
376 cur += l;
377 c = CUR_SCHAR(cur, l);
378 }
379 }
William M. Brack871611b2003-10-18 04:53:14 +0000380 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000381 return(1);
382 cur += l;
383 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000384 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
385 (c == '-') || (c == '_') || IS_COMBINING(c) ||
386 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000387 cur += l;
388 c = CUR_SCHAR(cur, l);
389 }
390 if (space) {
391 while (IS_BLANK(c)) {
392 cur += l;
393 c = CUR_SCHAR(cur, l);
394 }
395 }
396 if (c != 0)
397 return(1);
398
399 return(0);
400}
Daniel Veillard2156d432004-03-04 15:59:36 +0000401#endif
Daniel Veillardd2298792003-02-14 16:54:11 +0000402
Daniel Veillard2156d432004-03-04 15:59:36 +0000403#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000404/**
405 * xmlValidateQName:
406 * @value: the value to check
407 * @space: allow spaces in front and end of the string
408 *
409 * Check that a value conforms to the lexical space of QName
410 *
411 * Returns 0 if this validates, a positive error code number otherwise
412 * and -1 in case of internal or API error.
413 */
414int
415xmlValidateQName(const xmlChar *value, int space) {
416 const xmlChar *cur = value;
417 int c,l;
418
419 /*
420 * First quick algorithm for ASCII range
421 */
422 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000423 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000424 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
425 (*cur == '_'))
426 cur++;
427 else
428 goto try_complex;
429 while (((*cur >= 'a') && (*cur <= 'z')) ||
430 ((*cur >= 'A') && (*cur <= 'Z')) ||
431 ((*cur >= '0') && (*cur <= '9')) ||
432 (*cur == '_') || (*cur == '-') || (*cur == '.'))
433 cur++;
434 if (*cur == ':') {
435 cur++;
436 if (((*cur >= 'a') && (*cur <= 'z')) ||
437 ((*cur >= 'A') && (*cur <= 'Z')) ||
438 (*cur == '_'))
439 cur++;
440 else
441 goto try_complex;
442 while (((*cur >= 'a') && (*cur <= 'z')) ||
443 ((*cur >= 'A') && (*cur <= 'Z')) ||
444 ((*cur >= '0') && (*cur <= '9')) ||
445 (*cur == '_') || (*cur == '-') || (*cur == '.'))
446 cur++;
447 }
448 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000449 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000450 if (*cur == 0)
451 return(0);
452
453try_complex:
454 /*
455 * Second check for chars outside the ASCII range
456 */
457 cur = value;
458 c = CUR_SCHAR(cur, l);
459 if (space) {
460 while (IS_BLANK(c)) {
461 cur += l;
462 c = CUR_SCHAR(cur, l);
463 }
464 }
William M. Brack871611b2003-10-18 04:53:14 +0000465 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000466 return(1);
467 cur += l;
468 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000469 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
470 (c == '-') || (c == '_') || IS_COMBINING(c) ||
471 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000472 cur += l;
473 c = CUR_SCHAR(cur, l);
474 }
475 if (c == ':') {
476 cur += l;
477 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000478 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000479 return(1);
480 cur += l;
481 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000482 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
483 (c == '-') || (c == '_') || IS_COMBINING(c) ||
484 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000485 cur += l;
486 c = CUR_SCHAR(cur, l);
487 }
488 }
489 if (space) {
490 while (IS_BLANK(c)) {
491 cur += l;
492 c = CUR_SCHAR(cur, l);
493 }
494 }
495 if (c != 0)
496 return(1);
497 return(0);
498}
499
500/**
501 * xmlValidateName:
502 * @value: the value to check
503 * @space: allow spaces in front and end of the string
504 *
505 * Check that a value conforms to the lexical space of Name
506 *
507 * Returns 0 if this validates, a positive error code number otherwise
508 * and -1 in case of internal or API error.
509 */
510int
511xmlValidateName(const xmlChar *value, int space) {
512 const xmlChar *cur = value;
513 int c,l;
514
515 /*
516 * First quick algorithm for ASCII range
517 */
518 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000519 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000520 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
521 (*cur == '_') || (*cur == ':'))
522 cur++;
523 else
524 goto try_complex;
525 while (((*cur >= 'a') && (*cur <= 'z')) ||
526 ((*cur >= 'A') && (*cur <= 'Z')) ||
527 ((*cur >= '0') && (*cur <= '9')) ||
528 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
529 cur++;
530 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000531 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000532 if (*cur == 0)
533 return(0);
534
535try_complex:
536 /*
537 * Second check for chars outside the ASCII range
538 */
539 cur = value;
540 c = CUR_SCHAR(cur, l);
541 if (space) {
542 while (IS_BLANK(c)) {
543 cur += l;
544 c = CUR_SCHAR(cur, l);
545 }
546 }
William M. Brack871611b2003-10-18 04:53:14 +0000547 if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000548 return(1);
549 cur += l;
550 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000551 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
552 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000553 cur += l;
554 c = CUR_SCHAR(cur, l);
555 }
556 if (space) {
557 while (IS_BLANK(c)) {
558 cur += l;
559 c = CUR_SCHAR(cur, l);
560 }
561 }
562 if (c != 0)
563 return(1);
564 return(0);
565}
566
Daniel Veillardd4310742003-02-18 21:12:46 +0000567/**
568 * xmlValidateNMToken:
569 * @value: the value to check
570 * @space: allow spaces in front and end of the string
571 *
572 * Check that a value conforms to the lexical space of NMToken
573 *
574 * Returns 0 if this validates, a positive error code number otherwise
575 * and -1 in case of internal or API error.
576 */
577int
578xmlValidateNMToken(const xmlChar *value, int space) {
579 const xmlChar *cur = value;
580 int c,l;
581
582 /*
583 * First quick algorithm for ASCII range
584 */
585 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000586 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000587 if (((*cur >= 'a') && (*cur <= 'z')) ||
588 ((*cur >= 'A') && (*cur <= 'Z')) ||
589 ((*cur >= '0') && (*cur <= '9')) ||
590 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
591 cur++;
592 else
593 goto try_complex;
594 while (((*cur >= 'a') && (*cur <= 'z')) ||
595 ((*cur >= 'A') && (*cur <= 'Z')) ||
596 ((*cur >= '0') && (*cur <= '9')) ||
597 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
598 cur++;
599 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000600 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000601 if (*cur == 0)
602 return(0);
603
604try_complex:
605 /*
606 * Second check for chars outside the ASCII range
607 */
608 cur = value;
609 c = CUR_SCHAR(cur, l);
610 if (space) {
611 while (IS_BLANK(c)) {
612 cur += l;
613 c = CUR_SCHAR(cur, l);
614 }
615 }
William M. Brack871611b2003-10-18 04:53:14 +0000616 if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
617 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
Daniel Veillardd4310742003-02-18 21:12:46 +0000618 return(1);
619 cur += l;
620 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000621 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
622 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd4310742003-02-18 21:12:46 +0000623 cur += l;
624 c = CUR_SCHAR(cur, l);
625 }
626 if (space) {
627 while (IS_BLANK(c)) {
628 cur += l;
629 c = CUR_SCHAR(cur, l);
630 }
631 }
632 if (c != 0)
633 return(1);
634 return(0);
635}
Daniel Veillard652327a2003-09-29 18:02:38 +0000636#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardd4310742003-02-18 21:12:46 +0000637
Daniel Veillardd2298792003-02-14 16:54:11 +0000638/************************************************************************
639 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000640 * Allocation and deallocation of basic structures *
641 * *
642 ************************************************************************/
643
644/**
645 * xmlSetBufferAllocationScheme:
646 * @scheme: allocation method to use
647 *
648 * Set the buffer allocation method. Types are
649 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
650 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
651 * improves performance
652 */
653void
654xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
655 xmlBufferAllocScheme = scheme;
656}
657
658/**
659 * xmlGetBufferAllocationScheme:
660 *
661 * Types are
662 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
663 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
664 * improves performance
665 *
666 * Returns the current allocation scheme
667 */
668xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000669xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000670 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000671}
672
673/**
674 * xmlNewNs:
675 * @node: the element carrying the namespace
676 * @href: the URI associated
677 * @prefix: the prefix for the namespace
678 *
679 * Creation of a new Namespace. This function will refuse to create
680 * a namespace with a similar prefix than an existing one present on this
681 * node.
682 * We use href==NULL in the case of an element creation where the namespace
683 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000684 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000685 */
686xmlNsPtr
687xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
688 xmlNsPtr cur;
689
690 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
691 return(NULL);
692
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000693 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
694 return(NULL);
695
Owen Taylor3473f882001-02-23 17:55:21 +0000696 /*
697 * Allocate a new Namespace and fill the fields.
698 */
699 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
700 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000701 xmlTreeErrMemory("building namespace");
Owen Taylor3473f882001-02-23 17:55:21 +0000702 return(NULL);
703 }
704 memset(cur, 0, sizeof(xmlNs));
705 cur->type = XML_LOCAL_NAMESPACE;
706
707 if (href != NULL)
708 cur->href = xmlStrdup(href);
709 if (prefix != NULL)
710 cur->prefix = xmlStrdup(prefix);
711
712 /*
713 * Add it at the end to preserve parsing order ...
714 * and checks for existing use of the prefix
715 */
716 if (node != NULL) {
717 if (node->nsDef == NULL) {
718 node->nsDef = cur;
719 } else {
720 xmlNsPtr prev = node->nsDef;
721
722 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
723 (xmlStrEqual(prev->prefix, cur->prefix))) {
724 xmlFreeNs(cur);
725 return(NULL);
726 }
727 while (prev->next != NULL) {
728 prev = prev->next;
729 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
730 (xmlStrEqual(prev->prefix, cur->prefix))) {
731 xmlFreeNs(cur);
732 return(NULL);
733 }
734 }
735 prev->next = cur;
736 }
737 }
738 return(cur);
739}
740
741/**
742 * xmlSetNs:
743 * @node: a node in the document
744 * @ns: a namespace pointer
745 *
746 * Associate a namespace to a node, a posteriori.
747 */
748void
749xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
750 if (node == NULL) {
751#ifdef DEBUG_TREE
752 xmlGenericError(xmlGenericErrorContext,
753 "xmlSetNs: node == NULL\n");
754#endif
755 return;
756 }
757 node->ns = ns;
758}
759
760/**
761 * xmlFreeNs:
762 * @cur: the namespace pointer
763 *
764 * Free up the structures associated to a namespace
765 */
766void
767xmlFreeNs(xmlNsPtr cur) {
768 if (cur == NULL) {
769#ifdef DEBUG_TREE
770 xmlGenericError(xmlGenericErrorContext,
771 "xmlFreeNs : ns == NULL\n");
772#endif
773 return;
774 }
775 if (cur->href != NULL) xmlFree((char *) cur->href);
776 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000777 xmlFree(cur);
778}
779
780/**
781 * xmlFreeNsList:
782 * @cur: the first namespace pointer
783 *
784 * Free up all the structures associated to the chained namespaces.
785 */
786void
787xmlFreeNsList(xmlNsPtr cur) {
788 xmlNsPtr next;
789 if (cur == NULL) {
790#ifdef DEBUG_TREE
791 xmlGenericError(xmlGenericErrorContext,
792 "xmlFreeNsList : ns == NULL\n");
793#endif
794 return;
795 }
796 while (cur != NULL) {
797 next = cur->next;
798 xmlFreeNs(cur);
799 cur = next;
800 }
801}
802
803/**
804 * xmlNewDtd:
805 * @doc: the document pointer
806 * @name: the DTD name
807 * @ExternalID: the external ID
808 * @SystemID: the system ID
809 *
810 * Creation of a new DTD for the external subset. To create an
811 * internal subset, use xmlCreateIntSubset().
812 *
813 * Returns a pointer to the new DTD structure
814 */
815xmlDtdPtr
816xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
817 const xmlChar *ExternalID, const xmlChar *SystemID) {
818 xmlDtdPtr cur;
819
820 if ((doc != NULL) && (doc->extSubset != NULL)) {
821#ifdef DEBUG_TREE
822 xmlGenericError(xmlGenericErrorContext,
823 "xmlNewDtd(%s): document %s already have a DTD %s\n",
824 /* !!! */ (char *) name, doc->name,
825 /* !!! */ (char *)doc->extSubset->name);
826#endif
827 return(NULL);
828 }
829
830 /*
831 * Allocate a new DTD and fill the fields.
832 */
833 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
834 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000835 xmlTreeErrMemory("building DTD");
Owen Taylor3473f882001-02-23 17:55:21 +0000836 return(NULL);
837 }
838 memset(cur, 0 , sizeof(xmlDtd));
839 cur->type = XML_DTD_NODE;
840
841 if (name != NULL)
842 cur->name = xmlStrdup(name);
843 if (ExternalID != NULL)
844 cur->ExternalID = xmlStrdup(ExternalID);
845 if (SystemID != NULL)
846 cur->SystemID = xmlStrdup(SystemID);
847 if (doc != NULL)
848 doc->extSubset = cur;
849 cur->doc = doc;
850
Daniel Veillarda880b122003-04-21 21:36:41 +0000851 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000852 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000853 return(cur);
854}
855
856/**
857 * xmlGetIntSubset:
858 * @doc: the document pointer
859 *
860 * Get the internal subset of a document
861 * Returns a pointer to the DTD structure or NULL if not found
862 */
863
864xmlDtdPtr
865xmlGetIntSubset(xmlDocPtr doc) {
866 xmlNodePtr cur;
867
868 if (doc == NULL)
869 return(NULL);
870 cur = doc->children;
871 while (cur != NULL) {
872 if (cur->type == XML_DTD_NODE)
873 return((xmlDtdPtr) cur);
874 cur = cur->next;
875 }
876 return((xmlDtdPtr) doc->intSubset);
877}
878
879/**
880 * xmlCreateIntSubset:
881 * @doc: the document pointer
882 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000883 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000884 * @SystemID: the system ID
885 *
886 * Create the internal subset of a document
887 * Returns a pointer to the new DTD structure
888 */
889xmlDtdPtr
890xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
891 const xmlChar *ExternalID, const xmlChar *SystemID) {
892 xmlDtdPtr cur;
893
894 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
895#ifdef DEBUG_TREE
896 xmlGenericError(xmlGenericErrorContext,
897
898 "xmlCreateIntSubset(): document %s already have an internal subset\n",
899 doc->name);
900#endif
901 return(NULL);
902 }
903
904 /*
905 * Allocate a new DTD and fill the fields.
906 */
907 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
908 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000909 xmlTreeErrMemory("building internal subset");
Owen Taylor3473f882001-02-23 17:55:21 +0000910 return(NULL);
911 }
912 memset(cur, 0, sizeof(xmlDtd));
913 cur->type = XML_DTD_NODE;
914
William M. Bracka3215c72004-07-31 16:24:01 +0000915 if (name != NULL) {
916 cur->name = xmlStrdup(name);
917 if (cur->name == NULL) {
918 xmlTreeErrMemory("building internal subset");
919 xmlFree(cur);
920 return(NULL);
921 }
922 }
923 if (ExternalID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000924 cur->ExternalID = xmlStrdup(ExternalID);
William M. Bracka3215c72004-07-31 16:24:01 +0000925 if (cur->ExternalID == NULL) {
926 xmlTreeErrMemory("building internal subset");
927 if (cur->name != NULL)
928 xmlFree((char *)cur->name);
929 xmlFree(cur);
930 return(NULL);
931 }
932 }
933 if (SystemID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000934 cur->SystemID = xmlStrdup(SystemID);
William M. Bracka3215c72004-07-31 16:24:01 +0000935 if (cur->SystemID == NULL) {
936 xmlTreeErrMemory("building internal subset");
937 if (cur->name != NULL)
938 xmlFree((char *)cur->name);
939 if (cur->ExternalID != NULL)
940 xmlFree((char *)cur->ExternalID);
941 xmlFree(cur);
942 return(NULL);
943 }
944 }
Owen Taylor3473f882001-02-23 17:55:21 +0000945 if (doc != NULL) {
946 doc->intSubset = cur;
947 cur->parent = doc;
948 cur->doc = doc;
949 if (doc->children == NULL) {
950 doc->children = (xmlNodePtr) cur;
951 doc->last = (xmlNodePtr) cur;
952 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000953 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000954 xmlNodePtr prev;
955
Owen Taylor3473f882001-02-23 17:55:21 +0000956 prev = doc->children;
957 prev->prev = (xmlNodePtr) cur;
958 cur->next = prev;
959 doc->children = (xmlNodePtr) cur;
960 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000961 xmlNodePtr next;
962
963 next = doc->children;
964 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
965 next = next->next;
966 if (next == NULL) {
967 cur->prev = doc->last;
968 cur->prev->next = (xmlNodePtr) cur;
969 cur->next = NULL;
970 doc->last = (xmlNodePtr) cur;
971 } else {
972 cur->next = next;
973 cur->prev = next->prev;
974 if (cur->prev == NULL)
975 doc->children = (xmlNodePtr) cur;
976 else
977 cur->prev->next = (xmlNodePtr) cur;
978 next->prev = (xmlNodePtr) cur;
979 }
Owen Taylor3473f882001-02-23 17:55:21 +0000980 }
981 }
982 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000983
Daniel Veillarda880b122003-04-21 21:36:41 +0000984 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000985 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000986 return(cur);
987}
988
989/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000990 * DICT_FREE:
991 * @str: a string
992 *
993 * Free a string if it is not owned by the "dict" dictionnary in the
994 * current scope
995 */
996#define DICT_FREE(str) \
997 if ((str) && ((!dict) || \
998 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
999 xmlFree((char *)(str));
1000
1001/**
Owen Taylor3473f882001-02-23 17:55:21 +00001002 * xmlFreeDtd:
1003 * @cur: the DTD structure to free up
1004 *
1005 * Free a DTD structure.
1006 */
1007void
1008xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001009 xmlDictPtr dict = NULL;
1010
Owen Taylor3473f882001-02-23 17:55:21 +00001011 if (cur == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001012 return;
1013 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001014 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001015
Daniel Veillarda880b122003-04-21 21:36:41 +00001016 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001017 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1018
Owen Taylor3473f882001-02-23 17:55:21 +00001019 if (cur->children != NULL) {
1020 xmlNodePtr next, c = cur->children;
1021
1022 /*
William M. Brack18a04f22004-08-03 16:42:37 +00001023 * Cleanup all nodes which are not part of the specific lists
1024 * of notations, elements, attributes and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00001025 */
1026 while (c != NULL) {
1027 next = c->next;
William M. Brack18a04f22004-08-03 16:42:37 +00001028 if ((c->type != XML_NOTATION_NODE) &&
1029 (c->type != XML_ELEMENT_DECL) &&
1030 (c->type != XML_ATTRIBUTE_DECL) &&
1031 (c->type != XML_ENTITY_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001032 xmlUnlinkNode(c);
1033 xmlFreeNode(c);
1034 }
1035 c = next;
1036 }
1037 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001038 DICT_FREE(cur->name)
1039 DICT_FREE(cur->SystemID)
1040 DICT_FREE(cur->ExternalID)
Owen Taylor3473f882001-02-23 17:55:21 +00001041 /* TODO !!! */
1042 if (cur->notations != NULL)
1043 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1044
1045 if (cur->elements != NULL)
1046 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1047 if (cur->attributes != NULL)
1048 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1049 if (cur->entities != NULL)
1050 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1051 if (cur->pentities != NULL)
1052 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1053
Owen Taylor3473f882001-02-23 17:55:21 +00001054 xmlFree(cur);
1055}
1056
1057/**
1058 * xmlNewDoc:
1059 * @version: xmlChar string giving the version of XML "1.0"
1060 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001061 * Creates a new XML document
1062 *
Owen Taylor3473f882001-02-23 17:55:21 +00001063 * Returns a new document
1064 */
1065xmlDocPtr
1066xmlNewDoc(const xmlChar *version) {
1067 xmlDocPtr cur;
1068
1069 if (version == NULL)
1070 version = (const xmlChar *) "1.0";
1071
1072 /*
1073 * Allocate a new document and fill the fields.
1074 */
1075 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1076 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001077 xmlTreeErrMemory("building doc");
Owen Taylor3473f882001-02-23 17:55:21 +00001078 return(NULL);
1079 }
1080 memset(cur, 0, sizeof(xmlDoc));
1081 cur->type = XML_DOCUMENT_NODE;
1082
1083 cur->version = xmlStrdup(version);
William M. Bracka3215c72004-07-31 16:24:01 +00001084 if (cur->version == NULL) {
1085 xmlTreeErrMemory("building doc");
1086 xmlFree(cur);
1087 return(NULL);
1088 }
Owen Taylor3473f882001-02-23 17:55:21 +00001089 cur->standalone = -1;
1090 cur->compression = -1; /* not initialized */
1091 cur->doc = cur;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001092 /*
1093 * The in memory encoding is always UTF8
1094 * This field will never change and would
1095 * be obsolete if not for binary compatibility.
1096 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001097 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001098
Daniel Veillarda880b122003-04-21 21:36:41 +00001099 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001100 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001101 return(cur);
1102}
1103
1104/**
1105 * xmlFreeDoc:
1106 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001107 *
1108 * Free up all the structures used by a document, tree included.
1109 */
1110void
1111xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001112 xmlDtdPtr extSubset, intSubset;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001113 xmlDictPtr dict = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001114
Owen Taylor3473f882001-02-23 17:55:21 +00001115 if (cur == NULL) {
1116#ifdef DEBUG_TREE
1117 xmlGenericError(xmlGenericErrorContext,
1118 "xmlFreeDoc : document == NULL\n");
1119#endif
1120 return;
1121 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001122#ifdef LIBXML_DEBUG_RUNTIME
1123 xmlDebugCheckDocument(stderr, cur);
1124#endif
1125
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001126 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001127
Daniel Veillarda880b122003-04-21 21:36:41 +00001128 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001129 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1130
Daniel Veillard76d66f42001-05-16 21:05:17 +00001131 /*
1132 * Do this before freeing the children list to avoid ID lookups
1133 */
1134 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1135 cur->ids = NULL;
1136 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1137 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001138 extSubset = cur->extSubset;
1139 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001140 if (intSubset == extSubset)
1141 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001142 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001143 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001144 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001145 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001146 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001147 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001148 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001149 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001150 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001151 }
1152
1153 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001154 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001155
1156 DICT_FREE(cur->version)
1157 DICT_FREE(cur->name)
1158 DICT_FREE(cur->encoding)
1159 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001160 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001161 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001162}
1163
1164/**
1165 * xmlStringLenGetNodeList:
1166 * @doc: the document
1167 * @value: the value of the text
1168 * @len: the length of the string value
1169 *
1170 * Parse the value string and build the node list associated. Should
1171 * produce a flat tree with only TEXTs and ENTITY_REFs.
1172 * Returns a pointer to the first child
1173 */
1174xmlNodePtr
1175xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1176 xmlNodePtr ret = NULL, last = NULL;
1177 xmlNodePtr node;
1178 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001179 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001180 const xmlChar *q;
1181 xmlEntityPtr ent;
1182
1183 if (value == NULL) return(NULL);
1184
1185 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001186 while ((cur < end) && (*cur != 0)) {
1187 if (cur[0] == '&') {
1188 int charval = 0;
1189 xmlChar tmp;
1190
Owen Taylor3473f882001-02-23 17:55:21 +00001191 /*
1192 * Save the current text.
1193 */
1194 if (cur != q) {
1195 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1196 xmlNodeAddContentLen(last, q, cur - q);
1197 } else {
1198 node = xmlNewDocTextLen(doc, q, cur - q);
1199 if (node == NULL) return(ret);
1200 if (last == NULL)
1201 last = ret = node;
1202 else {
1203 last->next = node;
1204 node->prev = last;
1205 last = node;
1206 }
1207 }
1208 }
Owen Taylor3473f882001-02-23 17:55:21 +00001209 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001210 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1211 cur += 3;
1212 if (cur < end)
1213 tmp = *cur;
1214 else
1215 tmp = 0;
1216 while (tmp != ';') { /* Non input consuming loop */
1217 if ((tmp >= '0') && (tmp <= '9'))
1218 charval = charval * 16 + (tmp - '0');
1219 else if ((tmp >= 'a') && (tmp <= 'f'))
1220 charval = charval * 16 + (tmp - 'a') + 10;
1221 else if ((tmp >= 'A') && (tmp <= 'F'))
1222 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001223 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001224 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1225 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001226 charval = 0;
1227 break;
1228 }
1229 cur++;
1230 if (cur < end)
1231 tmp = *cur;
1232 else
1233 tmp = 0;
1234 }
1235 if (tmp == ';')
1236 cur++;
1237 q = cur;
1238 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1239 cur += 2;
1240 if (cur < end)
1241 tmp = *cur;
1242 else
1243 tmp = 0;
1244 while (tmp != ';') { /* Non input consuming loops */
1245 if ((tmp >= '0') && (tmp <= '9'))
1246 charval = charval * 10 + (tmp - '0');
1247 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001248 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1249 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001250 charval = 0;
1251 break;
1252 }
1253 cur++;
1254 if (cur < end)
1255 tmp = *cur;
1256 else
1257 tmp = 0;
1258 }
1259 if (tmp == ';')
1260 cur++;
1261 q = cur;
1262 } else {
1263 /*
1264 * Read the entity string
1265 */
1266 cur++;
1267 q = cur;
1268 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1269 if ((cur >= end) || (*cur == 0)) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001270 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1271 (const char *) q);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001272 return(ret);
1273 }
1274 if (cur != q) {
1275 /*
1276 * Predefined entities don't generate nodes
1277 */
1278 val = xmlStrndup(q, cur - q);
1279 ent = xmlGetDocEntity(doc, val);
1280 if ((ent != NULL) &&
1281 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1282 if (last == NULL) {
1283 node = xmlNewDocText(doc, ent->content);
1284 last = ret = node;
1285 } else if (last->type != XML_TEXT_NODE) {
1286 node = xmlNewDocText(doc, ent->content);
1287 last = xmlAddNextSibling(last, node);
1288 } else
1289 xmlNodeAddContent(last, ent->content);
1290
1291 } else {
1292 /*
1293 * Create a new REFERENCE_REF node
1294 */
1295 node = xmlNewReference(doc, val);
1296 if (node == NULL) {
1297 if (val != NULL) xmlFree(val);
1298 return(ret);
1299 }
1300 else if ((ent != NULL) && (ent->children == NULL)) {
1301 xmlNodePtr temp;
1302
1303 ent->children = xmlStringGetNodeList(doc,
1304 (const xmlChar*)node->content);
1305 ent->owner = 1;
1306 temp = ent->children;
1307 while (temp) {
1308 temp->parent = (xmlNodePtr)ent;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001309 ent->last = temp;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001310 temp = temp->next;
1311 }
1312 }
1313 if (last == NULL) {
1314 last = ret = node;
1315 } else {
1316 last = xmlAddNextSibling(last, node);
1317 }
1318 }
1319 xmlFree(val);
1320 }
1321 cur++;
1322 q = cur;
1323 }
1324 if (charval != 0) {
1325 xmlChar buf[10];
1326 int l;
1327
1328 l = xmlCopyCharMultiByte(buf, charval);
1329 buf[l] = 0;
1330 node = xmlNewDocText(doc, buf);
1331 if (node != NULL) {
1332 if (last == NULL) {
1333 last = ret = node;
1334 } else {
1335 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001336 }
1337 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001338 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001339 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001340 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001341 cur++;
1342 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001343 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001344 /*
1345 * Handle the last piece of text.
1346 */
1347 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1348 xmlNodeAddContentLen(last, q, cur - q);
1349 } else {
1350 node = xmlNewDocTextLen(doc, q, cur - q);
1351 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001352 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001353 last = ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001354 } else {
1355 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001356 }
1357 }
1358 }
1359 return(ret);
1360}
1361
1362/**
1363 * xmlStringGetNodeList:
1364 * @doc: the document
1365 * @value: the value of the attribute
1366 *
1367 * Parse the value string and build the node list associated. Should
1368 * produce a flat tree with only TEXTs and ENTITY_REFs.
1369 * Returns a pointer to the first child
1370 */
1371xmlNodePtr
1372xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1373 xmlNodePtr ret = NULL, last = NULL;
1374 xmlNodePtr node;
1375 xmlChar *val;
1376 const xmlChar *cur = value;
1377 const xmlChar *q;
1378 xmlEntityPtr ent;
1379
1380 if (value == NULL) return(NULL);
1381
1382 q = cur;
1383 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001384 if (cur[0] == '&') {
1385 int charval = 0;
1386 xmlChar tmp;
1387
Owen Taylor3473f882001-02-23 17:55:21 +00001388 /*
1389 * Save the current text.
1390 */
1391 if (cur != q) {
1392 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1393 xmlNodeAddContentLen(last, q, cur - q);
1394 } else {
1395 node = xmlNewDocTextLen(doc, q, cur - q);
1396 if (node == NULL) return(ret);
1397 if (last == NULL)
1398 last = ret = node;
1399 else {
1400 last->next = node;
1401 node->prev = last;
1402 last = node;
1403 }
1404 }
1405 }
Owen Taylor3473f882001-02-23 17:55:21 +00001406 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001407 if ((cur[1] == '#') && (cur[2] == 'x')) {
1408 cur += 3;
1409 tmp = *cur;
1410 while (tmp != ';') { /* Non input consuming loop */
1411 if ((tmp >= '0') && (tmp <= '9'))
1412 charval = charval * 16 + (tmp - '0');
1413 else if ((tmp >= 'a') && (tmp <= 'f'))
1414 charval = charval * 16 + (tmp - 'a') + 10;
1415 else if ((tmp >= 'A') && (tmp <= 'F'))
1416 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001417 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001418 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1419 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001420 charval = 0;
1421 break;
1422 }
1423 cur++;
1424 tmp = *cur;
1425 }
1426 if (tmp == ';')
1427 cur++;
1428 q = cur;
1429 } else if (cur[1] == '#') {
1430 cur += 2;
1431 tmp = *cur;
1432 while (tmp != ';') { /* Non input consuming loops */
1433 if ((tmp >= '0') && (tmp <= '9'))
1434 charval = charval * 10 + (tmp - '0');
1435 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001436 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1437 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001438 charval = 0;
1439 break;
1440 }
1441 cur++;
1442 tmp = *cur;
1443 }
1444 if (tmp == ';')
1445 cur++;
1446 q = cur;
1447 } else {
1448 /*
1449 * Read the entity string
1450 */
1451 cur++;
1452 q = cur;
1453 while ((*cur != 0) && (*cur != ';')) cur++;
1454 if (*cur == 0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001455 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1456 (xmlNodePtr) doc, (const char *) q);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001457 return(ret);
1458 }
1459 if (cur != q) {
1460 /*
1461 * Predefined entities don't generate nodes
1462 */
1463 val = xmlStrndup(q, cur - q);
1464 ent = xmlGetDocEntity(doc, val);
1465 if ((ent != NULL) &&
1466 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1467 if (last == NULL) {
1468 node = xmlNewDocText(doc, ent->content);
1469 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001470 } else if (last->type != XML_TEXT_NODE) {
1471 node = xmlNewDocText(doc, ent->content);
1472 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001473 } else
1474 xmlNodeAddContent(last, ent->content);
1475
1476 } else {
1477 /*
1478 * Create a new REFERENCE_REF node
1479 */
1480 node = xmlNewReference(doc, val);
1481 if (node == NULL) {
1482 if (val != NULL) xmlFree(val);
1483 return(ret);
1484 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001485 else if ((ent != NULL) && (ent->children == NULL)) {
1486 xmlNodePtr temp;
1487
1488 ent->children = xmlStringGetNodeList(doc,
1489 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001490 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001491 temp = ent->children;
1492 while (temp) {
1493 temp->parent = (xmlNodePtr)ent;
1494 temp = temp->next;
1495 }
1496 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001497 if (last == NULL) {
1498 last = ret = node;
1499 } else {
1500 last = xmlAddNextSibling(last, node);
1501 }
1502 }
1503 xmlFree(val);
1504 }
1505 cur++;
1506 q = cur;
1507 }
1508 if (charval != 0) {
1509 xmlChar buf[10];
1510 int len;
1511
1512 len = xmlCopyCharMultiByte(buf, charval);
1513 buf[len] = 0;
1514 node = xmlNewDocText(doc, buf);
1515 if (node != NULL) {
1516 if (last == NULL) {
1517 last = ret = node;
1518 } else {
1519 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001520 }
1521 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001522
1523 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001524 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001525 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001526 cur++;
1527 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001528 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001529 /*
1530 * Handle the last piece of text.
1531 */
1532 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1533 xmlNodeAddContentLen(last, q, cur - q);
1534 } else {
1535 node = xmlNewDocTextLen(doc, q, cur - q);
1536 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001537 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001538 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001539 } else {
1540 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001541 }
1542 }
1543 }
1544 return(ret);
1545}
1546
1547/**
1548 * xmlNodeListGetString:
1549 * @doc: the document
1550 * @list: a Node list
1551 * @inLine: should we replace entity contents or show their external form
1552 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001553 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001554 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001555 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001556 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001557 */
1558xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001559xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1560{
Owen Taylor3473f882001-02-23 17:55:21 +00001561 xmlNodePtr node = list;
1562 xmlChar *ret = NULL;
1563 xmlEntityPtr ent;
1564
Daniel Veillard7646b182002-04-20 06:41:40 +00001565 if (list == NULL)
1566 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001567
1568 while (node != NULL) {
1569 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001570 (node->type == XML_CDATA_SECTION_NODE)) {
1571 if (inLine) {
1572 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001573 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001574 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001575
Daniel Veillard7646b182002-04-20 06:41:40 +00001576 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1577 if (buffer != NULL) {
1578 ret = xmlStrcat(ret, buffer);
1579 xmlFree(buffer);
1580 }
1581 }
1582 } else if (node->type == XML_ENTITY_REF_NODE) {
1583 if (inLine) {
1584 ent = xmlGetDocEntity(doc, node->name);
1585 if (ent != NULL) {
1586 xmlChar *buffer;
1587
1588 /* an entity content can be any "well balanced chunk",
1589 * i.e. the result of the content [43] production:
1590 * http://www.w3.org/TR/REC-xml#NT-content.
1591 * So it can contain text, CDATA section or nested
1592 * entity reference nodes (among others).
1593 * -> we recursive call xmlNodeListGetString()
1594 * which handles these types */
1595 buffer = xmlNodeListGetString(doc, ent->children, 1);
1596 if (buffer != NULL) {
1597 ret = xmlStrcat(ret, buffer);
1598 xmlFree(buffer);
1599 }
1600 } else {
1601 ret = xmlStrcat(ret, node->content);
1602 }
1603 } else {
1604 xmlChar buf[2];
1605
1606 buf[0] = '&';
1607 buf[1] = 0;
1608 ret = xmlStrncat(ret, buf, 1);
1609 ret = xmlStrcat(ret, node->name);
1610 buf[0] = ';';
1611 buf[1] = 0;
1612 ret = xmlStrncat(ret, buf, 1);
1613 }
1614 }
1615#if 0
1616 else {
1617 xmlGenericError(xmlGenericErrorContext,
1618 "xmlGetNodeListString : invalid node type %d\n",
1619 node->type);
1620 }
1621#endif
1622 node = node->next;
1623 }
1624 return (ret);
1625}
Daniel Veillard652327a2003-09-29 18:02:38 +00001626
1627#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001628/**
1629 * xmlNodeListGetRawString:
1630 * @doc: the document
1631 * @list: a Node list
1632 * @inLine: should we replace entity contents or show their external form
1633 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001634 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001635 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1636 * this function doesn't do any character encoding handling.
1637 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001638 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001639 */
1640xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001641xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1642{
Owen Taylor3473f882001-02-23 17:55:21 +00001643 xmlNodePtr node = list;
1644 xmlChar *ret = NULL;
1645 xmlEntityPtr ent;
1646
Daniel Veillard7646b182002-04-20 06:41:40 +00001647 if (list == NULL)
1648 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001649
1650 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001651 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001652 (node->type == XML_CDATA_SECTION_NODE)) {
1653 if (inLine) {
1654 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001655 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001656 xmlChar *buffer;
1657
1658 buffer = xmlEncodeSpecialChars(doc, node->content);
1659 if (buffer != NULL) {
1660 ret = xmlStrcat(ret, buffer);
1661 xmlFree(buffer);
1662 }
1663 }
1664 } else if (node->type == XML_ENTITY_REF_NODE) {
1665 if (inLine) {
1666 ent = xmlGetDocEntity(doc, node->name);
1667 if (ent != NULL) {
1668 xmlChar *buffer;
1669
1670 /* an entity content can be any "well balanced chunk",
1671 * i.e. the result of the content [43] production:
1672 * http://www.w3.org/TR/REC-xml#NT-content.
1673 * So it can contain text, CDATA section or nested
1674 * entity reference nodes (among others).
1675 * -> we recursive call xmlNodeListGetRawString()
1676 * which handles these types */
1677 buffer =
1678 xmlNodeListGetRawString(doc, ent->children, 1);
1679 if (buffer != NULL) {
1680 ret = xmlStrcat(ret, buffer);
1681 xmlFree(buffer);
1682 }
1683 } else {
1684 ret = xmlStrcat(ret, node->content);
1685 }
1686 } else {
1687 xmlChar buf[2];
1688
1689 buf[0] = '&';
1690 buf[1] = 0;
1691 ret = xmlStrncat(ret, buf, 1);
1692 ret = xmlStrcat(ret, node->name);
1693 buf[0] = ';';
1694 buf[1] = 0;
1695 ret = xmlStrncat(ret, buf, 1);
1696 }
1697 }
Owen Taylor3473f882001-02-23 17:55:21 +00001698#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001699 else {
1700 xmlGenericError(xmlGenericErrorContext,
1701 "xmlGetNodeListString : invalid node type %d\n",
1702 node->type);
1703 }
Owen Taylor3473f882001-02-23 17:55:21 +00001704#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001705 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001706 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001707 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001708}
Daniel Veillard652327a2003-09-29 18:02:38 +00001709#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001710
Daniel Veillard2156d432004-03-04 15:59:36 +00001711#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00001712/**
1713 * xmlNewProp:
1714 * @node: the holding node
1715 * @name: the name of the attribute
1716 * @value: the value of the attribute
1717 *
1718 * Create a new property carried by a node.
1719 * Returns a pointer to the attribute
1720 */
1721xmlAttrPtr
1722xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1723 xmlAttrPtr cur;
1724 xmlDocPtr doc = NULL;
1725
1726 if (name == NULL) {
1727#ifdef DEBUG_TREE
1728 xmlGenericError(xmlGenericErrorContext,
1729 "xmlNewProp : name == NULL\n");
1730#endif
1731 return(NULL);
1732 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001733 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1734 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001735
1736 /*
1737 * Allocate a new property and fill the fields.
1738 */
1739 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1740 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001741 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001742 return(NULL);
1743 }
1744 memset(cur, 0, sizeof(xmlAttr));
1745 cur->type = XML_ATTRIBUTE_NODE;
1746
1747 cur->parent = node;
1748 if (node != NULL) {
1749 doc = node->doc;
1750 cur->doc = doc;
1751 }
Daniel Veillard03a53c32004-10-26 16:06:51 +00001752 if ((doc != NULL) && (doc->dict != NULL))
1753 cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
1754 else
1755 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00001756 if (value != NULL) {
1757 xmlChar *buffer;
1758 xmlNodePtr tmp;
1759
1760 buffer = xmlEncodeEntitiesReentrant(doc, value);
1761 cur->children = xmlStringGetNodeList(doc, buffer);
1762 cur->last = NULL;
1763 tmp = cur->children;
1764 while (tmp != NULL) {
1765 tmp->parent = (xmlNodePtr) cur;
1766 tmp->doc = doc;
1767 if (tmp->next == NULL)
1768 cur->last = tmp;
1769 tmp = tmp->next;
1770 }
1771 xmlFree(buffer);
1772 }
1773
1774 /*
1775 * Add it at the end to preserve parsing order ...
1776 */
1777 if (node != NULL) {
1778 if (node->properties == NULL) {
1779 node->properties = cur;
1780 } else {
1781 xmlAttrPtr prev = node->properties;
1782
1783 while (prev->next != NULL) prev = prev->next;
1784 prev->next = cur;
1785 cur->prev = prev;
1786 }
1787 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001788
Daniel Veillarda880b122003-04-21 21:36:41 +00001789 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001790 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001791 return(cur);
1792}
Daniel Veillard652327a2003-09-29 18:02:38 +00001793#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001794
1795/**
1796 * xmlNewNsProp:
1797 * @node: the holding node
1798 * @ns: the namespace
1799 * @name: the name of the attribute
1800 * @value: the value of the attribute
1801 *
1802 * Create a new property tagged with a namespace and carried by a node.
1803 * Returns a pointer to the attribute
1804 */
1805xmlAttrPtr
1806xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1807 const xmlChar *value) {
1808 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001809 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001810
1811 if (name == NULL) {
1812#ifdef DEBUG_TREE
1813 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001814 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001815#endif
1816 return(NULL);
1817 }
1818
1819 /*
1820 * Allocate a new property and fill the fields.
1821 */
1822 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1823 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001824 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001825 return(NULL);
1826 }
1827 memset(cur, 0, sizeof(xmlAttr));
1828 cur->type = XML_ATTRIBUTE_NODE;
1829
1830 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001831 if (node != NULL) {
1832 doc = node->doc;
1833 cur->doc = doc;
1834 }
Owen Taylor3473f882001-02-23 17:55:21 +00001835 cur->ns = ns;
Daniel Veillard03a53c32004-10-26 16:06:51 +00001836 if ((doc != NULL) && (doc->dict != NULL))
1837 cur->name = xmlDictLookup(doc->dict, name, -1);
1838 else
1839 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00001840 if (value != NULL) {
1841 xmlChar *buffer;
1842 xmlNodePtr tmp;
1843
Daniel Veillarda682b212001-06-07 19:59:42 +00001844 buffer = xmlEncodeEntitiesReentrant(doc, value);
1845 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001846 cur->last = NULL;
1847 tmp = cur->children;
1848 while (tmp != NULL) {
1849 tmp->parent = (xmlNodePtr) cur;
1850 if (tmp->next == NULL)
1851 cur->last = tmp;
1852 tmp = tmp->next;
1853 }
1854 xmlFree(buffer);
1855 }
1856
1857 /*
1858 * Add it at the end to preserve parsing order ...
1859 */
1860 if (node != NULL) {
1861 if (node->properties == NULL) {
1862 node->properties = cur;
1863 } else {
1864 xmlAttrPtr prev = node->properties;
1865
1866 while (prev->next != NULL) prev = prev->next;
1867 prev->next = cur;
1868 cur->prev = prev;
1869 }
1870 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001871
Daniel Veillarda880b122003-04-21 21:36:41 +00001872 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001873 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001874 return(cur);
1875}
1876
1877/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001878 * xmlNewNsPropEatName:
1879 * @node: the holding node
1880 * @ns: the namespace
1881 * @name: the name of the attribute
1882 * @value: the value of the attribute
1883 *
1884 * Create a new property tagged with a namespace and carried by a node.
1885 * Returns a pointer to the attribute
1886 */
1887xmlAttrPtr
1888xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1889 const xmlChar *value) {
1890 xmlAttrPtr cur;
1891 xmlDocPtr doc = NULL;
1892
1893 if (name == NULL) {
1894#ifdef DEBUG_TREE
1895 xmlGenericError(xmlGenericErrorContext,
1896 "xmlNewNsPropEatName : name == NULL\n");
1897#endif
1898 return(NULL);
1899 }
1900
1901 /*
1902 * Allocate a new property and fill the fields.
1903 */
1904 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1905 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001906 xmlTreeErrMemory("building attribute");
Daniel Veillard46de64e2002-05-29 08:21:33 +00001907 return(NULL);
1908 }
1909 memset(cur, 0, sizeof(xmlAttr));
1910 cur->type = XML_ATTRIBUTE_NODE;
1911
1912 cur->parent = node;
1913 if (node != NULL) {
1914 doc = node->doc;
1915 cur->doc = doc;
1916 }
1917 cur->ns = ns;
1918 cur->name = name;
1919 if (value != NULL) {
1920 xmlChar *buffer;
1921 xmlNodePtr tmp;
1922
1923 buffer = xmlEncodeEntitiesReentrant(doc, value);
1924 cur->children = xmlStringGetNodeList(doc, buffer);
1925 cur->last = NULL;
1926 tmp = cur->children;
1927 while (tmp != NULL) {
1928 tmp->parent = (xmlNodePtr) cur;
1929 if (tmp->next == NULL)
1930 cur->last = tmp;
1931 tmp = tmp->next;
1932 }
1933 xmlFree(buffer);
1934 }
1935
1936 /*
1937 * Add it at the end to preserve parsing order ...
1938 */
1939 if (node != NULL) {
1940 if (node->properties == NULL) {
1941 node->properties = cur;
1942 } else {
1943 xmlAttrPtr prev = node->properties;
1944
1945 while (prev->next != NULL) prev = prev->next;
1946 prev->next = cur;
1947 cur->prev = prev;
1948 }
1949 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001950
Daniel Veillarda880b122003-04-21 21:36:41 +00001951 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001952 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001953 return(cur);
1954}
1955
1956/**
Owen Taylor3473f882001-02-23 17:55:21 +00001957 * xmlNewDocProp:
1958 * @doc: the document
1959 * @name: the name of the attribute
1960 * @value: the value of the attribute
1961 *
1962 * Create a new property carried by a document.
1963 * Returns a pointer to the attribute
1964 */
1965xmlAttrPtr
1966xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1967 xmlAttrPtr cur;
1968
1969 if (name == NULL) {
1970#ifdef DEBUG_TREE
1971 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001972 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001973#endif
1974 return(NULL);
1975 }
1976
1977 /*
1978 * Allocate a new property and fill the fields.
1979 */
1980 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1981 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001982 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001983 return(NULL);
1984 }
1985 memset(cur, 0, sizeof(xmlAttr));
1986 cur->type = XML_ATTRIBUTE_NODE;
1987
Daniel Veillard03a53c32004-10-26 16:06:51 +00001988 if ((doc != NULL) && (doc->dict != NULL))
1989 cur->name = xmlDictLookup(doc->dict, name, -1);
1990 else
1991 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00001992 cur->doc = doc;
1993 if (value != NULL) {
1994 xmlNodePtr tmp;
1995
1996 cur->children = xmlStringGetNodeList(doc, value);
1997 cur->last = NULL;
1998
1999 tmp = cur->children;
2000 while (tmp != NULL) {
2001 tmp->parent = (xmlNodePtr) cur;
2002 if (tmp->next == NULL)
2003 cur->last = tmp;
2004 tmp = tmp->next;
2005 }
2006 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002007
Daniel Veillarda880b122003-04-21 21:36:41 +00002008 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002009 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002010 return(cur);
2011}
2012
2013/**
2014 * xmlFreePropList:
2015 * @cur: the first property in the list
2016 *
2017 * Free a property and all its siblings, all the children are freed too.
2018 */
2019void
2020xmlFreePropList(xmlAttrPtr cur) {
2021 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002022 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002023 while (cur != NULL) {
2024 next = cur->next;
2025 xmlFreeProp(cur);
2026 cur = next;
2027 }
2028}
2029
2030/**
2031 * xmlFreeProp:
2032 * @cur: an attribute
2033 *
2034 * Free one attribute, all the content is freed too
2035 */
2036void
2037xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002038 xmlDictPtr dict = NULL;
2039 if (cur == NULL) return;
2040
2041 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002042
Daniel Veillarda880b122003-04-21 21:36:41 +00002043 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002044 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
2045
Owen Taylor3473f882001-02-23 17:55:21 +00002046 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00002047 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
2048 ((cur->parent->doc->intSubset != NULL) ||
2049 (cur->parent->doc->extSubset != NULL))) {
2050 if (xmlIsID(cur->parent->doc, cur->parent, cur))
2051 xmlRemoveID(cur->parent->doc, cur);
2052 }
Owen Taylor3473f882001-02-23 17:55:21 +00002053 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002054 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002055 xmlFree(cur);
2056}
2057
Daniel Veillard652327a2003-09-29 18:02:38 +00002058#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002059/**
2060 * xmlRemoveProp:
2061 * @cur: an attribute
2062 *
2063 * Unlink and free one attribute, all the content is freed too
2064 * Note this doesn't work for namespace definition attributes
2065 *
2066 * Returns 0 if success and -1 in case of error.
2067 */
2068int
2069xmlRemoveProp(xmlAttrPtr cur) {
2070 xmlAttrPtr tmp;
2071 if (cur == NULL) {
2072#ifdef DEBUG_TREE
2073 xmlGenericError(xmlGenericErrorContext,
2074 "xmlRemoveProp : cur == NULL\n");
2075#endif
2076 return(-1);
2077 }
2078 if (cur->parent == NULL) {
2079#ifdef DEBUG_TREE
2080 xmlGenericError(xmlGenericErrorContext,
2081 "xmlRemoveProp : cur->parent == NULL\n");
2082#endif
2083 return(-1);
2084 }
2085 tmp = cur->parent->properties;
2086 if (tmp == cur) {
2087 cur->parent->properties = cur->next;
2088 xmlFreeProp(cur);
2089 return(0);
2090 }
2091 while (tmp != NULL) {
2092 if (tmp->next == cur) {
2093 tmp->next = cur->next;
2094 if (tmp->next != NULL)
2095 tmp->next->prev = tmp;
2096 xmlFreeProp(cur);
2097 return(0);
2098 }
2099 tmp = tmp->next;
2100 }
2101#ifdef DEBUG_TREE
2102 xmlGenericError(xmlGenericErrorContext,
2103 "xmlRemoveProp : attribute not owned by its node\n");
2104#endif
2105 return(-1);
2106}
Daniel Veillard652327a2003-09-29 18:02:38 +00002107#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002108
2109/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002110 * xmlNewDocPI:
2111 * @doc: the target document
Owen Taylor3473f882001-02-23 17:55:21 +00002112 * @name: the processing instruction name
2113 * @content: the PI content
2114 *
2115 * Creation of a processing instruction element.
2116 * Returns a pointer to the new node object.
2117 */
2118xmlNodePtr
Daniel Veillard03a53c32004-10-26 16:06:51 +00002119xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
Owen Taylor3473f882001-02-23 17:55:21 +00002120 xmlNodePtr cur;
2121
2122 if (name == NULL) {
2123#ifdef DEBUG_TREE
2124 xmlGenericError(xmlGenericErrorContext,
2125 "xmlNewPI : name == NULL\n");
2126#endif
2127 return(NULL);
2128 }
2129
2130 /*
2131 * Allocate a new node and fill the fields.
2132 */
2133 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2134 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002135 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002136 return(NULL);
2137 }
2138 memset(cur, 0, sizeof(xmlNode));
2139 cur->type = XML_PI_NODE;
2140
Daniel Veillard03a53c32004-10-26 16:06:51 +00002141 if ((doc != NULL) && (doc->dict != NULL))
2142 cur->name = xmlDictLookup(doc->dict, name, -1);
2143 else
2144 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00002145 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002146 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002147 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002148
Daniel Veillarda880b122003-04-21 21:36:41 +00002149 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002150 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002151 return(cur);
2152}
2153
2154/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002155 * xmlNewPI:
2156 * @name: the processing instruction name
2157 * @content: the PI content
2158 *
2159 * Creation of a processing instruction element.
2160 * Use xmlDocNewPI preferably to get string interning
2161 *
2162 * Returns a pointer to the new node object.
2163 */
2164xmlNodePtr
2165xmlNewPI(const xmlChar *name, const xmlChar *content) {
2166 return(xmlNewDocPI(NULL, name, content));
2167}
2168
2169/**
Owen Taylor3473f882001-02-23 17:55:21 +00002170 * xmlNewNode:
2171 * @ns: namespace if any
2172 * @name: the node name
2173 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002174 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002175 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002176 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2177 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002178 */
2179xmlNodePtr
2180xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2181 xmlNodePtr cur;
2182
2183 if (name == NULL) {
2184#ifdef DEBUG_TREE
2185 xmlGenericError(xmlGenericErrorContext,
2186 "xmlNewNode : name == NULL\n");
2187#endif
2188 return(NULL);
2189 }
2190
2191 /*
2192 * Allocate a new node and fill the fields.
2193 */
2194 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2195 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002196 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002197 return(NULL);
2198 }
2199 memset(cur, 0, sizeof(xmlNode));
2200 cur->type = XML_ELEMENT_NODE;
2201
2202 cur->name = xmlStrdup(name);
2203 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002204
Daniel Veillarda880b122003-04-21 21:36:41 +00002205 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002206 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002207 return(cur);
2208}
2209
2210/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002211 * xmlNewNodeEatName:
2212 * @ns: namespace if any
2213 * @name: the node name
2214 *
2215 * Creation of a new node element. @ns is optional (NULL).
2216 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002217 * Returns a pointer to the new node object, with pointer @name as
2218 * new node's name. Use xmlNewNode() if a copy of @name string is
2219 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002220 */
2221xmlNodePtr
2222xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2223 xmlNodePtr cur;
2224
2225 if (name == NULL) {
2226#ifdef DEBUG_TREE
2227 xmlGenericError(xmlGenericErrorContext,
2228 "xmlNewNode : name == NULL\n");
2229#endif
2230 return(NULL);
2231 }
2232
2233 /*
2234 * Allocate a new node and fill the fields.
2235 */
2236 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2237 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002238 xmlTreeErrMemory("building node");
Daniel Veillard46de64e2002-05-29 08:21:33 +00002239 return(NULL);
2240 }
2241 memset(cur, 0, sizeof(xmlNode));
2242 cur->type = XML_ELEMENT_NODE;
2243
2244 cur->name = name;
2245 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002246
Daniel Veillarda880b122003-04-21 21:36:41 +00002247 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002248 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002249 return(cur);
2250}
2251
2252/**
Owen Taylor3473f882001-02-23 17:55:21 +00002253 * xmlNewDocNode:
2254 * @doc: the document
2255 * @ns: namespace if any
2256 * @name: the node name
2257 * @content: the XML text content if any
2258 *
2259 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002260 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002261 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2262 * references, but XML special chars need to be escaped first by using
2263 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2264 * need entities support.
2265 *
2266 * Returns a pointer to the new node object.
2267 */
2268xmlNodePtr
2269xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2270 const xmlChar *name, const xmlChar *content) {
2271 xmlNodePtr cur;
2272
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002273 if ((doc != NULL) && (doc->dict != NULL))
Daniel Veillard03a53c32004-10-26 16:06:51 +00002274 cur = xmlNewNodeEatName(ns, (xmlChar *)
2275 xmlDictLookup(doc->dict, name, -1));
2276 else
2277 cur = xmlNewNode(ns, name);
Owen Taylor3473f882001-02-23 17:55:21 +00002278 if (cur != NULL) {
2279 cur->doc = doc;
2280 if (content != NULL) {
2281 cur->children = xmlStringGetNodeList(doc, content);
2282 UPDATE_LAST_CHILD_AND_PARENT(cur)
2283 }
2284 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002285
Owen Taylor3473f882001-02-23 17:55:21 +00002286 return(cur);
2287}
2288
Daniel Veillard46de64e2002-05-29 08:21:33 +00002289/**
2290 * xmlNewDocNodeEatName:
2291 * @doc: the document
2292 * @ns: namespace if any
2293 * @name: the node name
2294 * @content: the XML text content if any
2295 *
2296 * Creation of a new node element within a document. @ns and @content
2297 * are optional (NULL).
2298 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2299 * references, but XML special chars need to be escaped first by using
2300 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2301 * need entities support.
2302 *
2303 * Returns a pointer to the new node object.
2304 */
2305xmlNodePtr
2306xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2307 xmlChar *name, const xmlChar *content) {
2308 xmlNodePtr cur;
2309
2310 cur = xmlNewNodeEatName(ns, name);
2311 if (cur != NULL) {
2312 cur->doc = doc;
2313 if (content != NULL) {
2314 cur->children = xmlStringGetNodeList(doc, content);
2315 UPDATE_LAST_CHILD_AND_PARENT(cur)
2316 }
2317 }
2318 return(cur);
2319}
2320
Daniel Veillard652327a2003-09-29 18:02:38 +00002321#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002322/**
2323 * xmlNewDocRawNode:
2324 * @doc: the document
2325 * @ns: namespace if any
2326 * @name: the node name
2327 * @content: the text content if any
2328 *
2329 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002330 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002331 *
2332 * Returns a pointer to the new node object.
2333 */
2334xmlNodePtr
2335xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2336 const xmlChar *name, const xmlChar *content) {
2337 xmlNodePtr cur;
2338
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002339 cur = xmlNewDocNode(doc, ns, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002340 if (cur != NULL) {
2341 cur->doc = doc;
2342 if (content != NULL) {
2343 cur->children = xmlNewDocText(doc, content);
2344 UPDATE_LAST_CHILD_AND_PARENT(cur)
2345 }
2346 }
2347 return(cur);
2348}
2349
2350/**
2351 * xmlNewDocFragment:
2352 * @doc: the document owning the fragment
2353 *
2354 * Creation of a new Fragment node.
2355 * Returns a pointer to the new node object.
2356 */
2357xmlNodePtr
2358xmlNewDocFragment(xmlDocPtr doc) {
2359 xmlNodePtr cur;
2360
2361 /*
2362 * Allocate a new DocumentFragment node and fill the fields.
2363 */
2364 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2365 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002366 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002367 return(NULL);
2368 }
2369 memset(cur, 0, sizeof(xmlNode));
2370 cur->type = XML_DOCUMENT_FRAG_NODE;
2371
2372 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002373
Daniel Veillarda880b122003-04-21 21:36:41 +00002374 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002375 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002376 return(cur);
2377}
Daniel Veillard652327a2003-09-29 18:02:38 +00002378#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002379
2380/**
2381 * xmlNewText:
2382 * @content: the text content
2383 *
2384 * Creation of a new text node.
2385 * Returns a pointer to the new node object.
2386 */
2387xmlNodePtr
2388xmlNewText(const xmlChar *content) {
2389 xmlNodePtr cur;
2390
2391 /*
2392 * Allocate a new node and fill the fields.
2393 */
2394 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2395 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002396 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002397 return(NULL);
2398 }
2399 memset(cur, 0, sizeof(xmlNode));
2400 cur->type = XML_TEXT_NODE;
2401
2402 cur->name = xmlStringText;
2403 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002404 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002405 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002406
Daniel Veillarda880b122003-04-21 21:36:41 +00002407 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002408 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002409 return(cur);
2410}
2411
Daniel Veillard652327a2003-09-29 18:02:38 +00002412#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002413/**
2414 * xmlNewTextChild:
2415 * @parent: the parent node
2416 * @ns: a namespace if any
2417 * @name: the name of the child
2418 * @content: the text content of the child if any.
2419 *
2420 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002421 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2422 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002423 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002424 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2425 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2426 * reserved XML chars that might appear in @content, such as the ampersand,
2427 * greater-than or less-than signs, are automatically replaced by their XML
2428 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002429 *
2430 * Returns a pointer to the new node object.
2431 */
2432xmlNodePtr
2433xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2434 const xmlChar *name, const xmlChar *content) {
2435 xmlNodePtr cur, prev;
2436
2437 if (parent == NULL) {
2438#ifdef DEBUG_TREE
2439 xmlGenericError(xmlGenericErrorContext,
2440 "xmlNewTextChild : parent == NULL\n");
2441#endif
2442 return(NULL);
2443 }
2444
2445 if (name == NULL) {
2446#ifdef DEBUG_TREE
2447 xmlGenericError(xmlGenericErrorContext,
2448 "xmlNewTextChild : name == NULL\n");
2449#endif
2450 return(NULL);
2451 }
2452
2453 /*
2454 * Allocate a new node
2455 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002456 if (parent->type == XML_ELEMENT_NODE) {
2457 if (ns == NULL)
2458 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2459 else
2460 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2461 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2462 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2463 if (ns == NULL)
2464 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2465 else
2466 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2467 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2468 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2469 } else {
2470 return(NULL);
2471 }
Owen Taylor3473f882001-02-23 17:55:21 +00002472 if (cur == NULL) return(NULL);
2473
2474 /*
2475 * add the new element at the end of the children list.
2476 */
2477 cur->type = XML_ELEMENT_NODE;
2478 cur->parent = parent;
2479 cur->doc = parent->doc;
2480 if (parent->children == NULL) {
2481 parent->children = cur;
2482 parent->last = cur;
2483 } else {
2484 prev = parent->last;
2485 prev->next = cur;
2486 cur->prev = prev;
2487 parent->last = cur;
2488 }
2489
2490 return(cur);
2491}
Daniel Veillard652327a2003-09-29 18:02:38 +00002492#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002493
2494/**
2495 * xmlNewCharRef:
2496 * @doc: the document
2497 * @name: the char ref string, starting with # or "&# ... ;"
2498 *
2499 * Creation of a new character reference node.
2500 * Returns a pointer to the new node object.
2501 */
2502xmlNodePtr
2503xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2504 xmlNodePtr cur;
2505
2506 /*
2507 * Allocate a new node and fill the fields.
2508 */
2509 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2510 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002511 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002512 return(NULL);
2513 }
2514 memset(cur, 0, sizeof(xmlNode));
2515 cur->type = XML_ENTITY_REF_NODE;
2516
2517 cur->doc = doc;
2518 if (name[0] == '&') {
2519 int len;
2520 name++;
2521 len = xmlStrlen(name);
2522 if (name[len - 1] == ';')
2523 cur->name = xmlStrndup(name, len - 1);
2524 else
2525 cur->name = xmlStrndup(name, len);
2526 } else
2527 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002528
Daniel Veillarda880b122003-04-21 21:36:41 +00002529 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002530 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002531 return(cur);
2532}
2533
2534/**
2535 * xmlNewReference:
2536 * @doc: the document
2537 * @name: the reference name, or the reference string with & and ;
2538 *
2539 * Creation of a new reference node.
2540 * Returns a pointer to the new node object.
2541 */
2542xmlNodePtr
2543xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2544 xmlNodePtr cur;
2545 xmlEntityPtr ent;
2546
2547 /*
2548 * Allocate a new node and fill the fields.
2549 */
2550 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2551 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002552 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002553 return(NULL);
2554 }
2555 memset(cur, 0, sizeof(xmlNode));
2556 cur->type = XML_ENTITY_REF_NODE;
2557
2558 cur->doc = doc;
2559 if (name[0] == '&') {
2560 int len;
2561 name++;
2562 len = xmlStrlen(name);
2563 if (name[len - 1] == ';')
2564 cur->name = xmlStrndup(name, len - 1);
2565 else
2566 cur->name = xmlStrndup(name, len);
2567 } else
2568 cur->name = xmlStrdup(name);
2569
2570 ent = xmlGetDocEntity(doc, cur->name);
2571 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002572 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002573 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002574 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002575 * updated. Not sure if this is 100% correct.
2576 * -George
2577 */
2578 cur->children = (xmlNodePtr) ent;
2579 cur->last = (xmlNodePtr) ent;
2580 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002581
Daniel Veillarda880b122003-04-21 21:36:41 +00002582 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002583 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002584 return(cur);
2585}
2586
2587/**
2588 * xmlNewDocText:
2589 * @doc: the document
2590 * @content: the text content
2591 *
2592 * Creation of a new text node within a document.
2593 * Returns a pointer to the new node object.
2594 */
2595xmlNodePtr
2596xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2597 xmlNodePtr cur;
2598
2599 cur = xmlNewText(content);
2600 if (cur != NULL) cur->doc = doc;
2601 return(cur);
2602}
2603
2604/**
2605 * xmlNewTextLen:
2606 * @content: the text content
2607 * @len: the text len.
2608 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002609 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002610 * Returns a pointer to the new node object.
2611 */
2612xmlNodePtr
2613xmlNewTextLen(const xmlChar *content, int len) {
2614 xmlNodePtr cur;
2615
2616 /*
2617 * Allocate a new node and fill the fields.
2618 */
2619 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2620 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002621 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002622 return(NULL);
2623 }
2624 memset(cur, 0, sizeof(xmlNode));
2625 cur->type = XML_TEXT_NODE;
2626
2627 cur->name = xmlStringText;
2628 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002629 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002630 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002631
Daniel Veillarda880b122003-04-21 21:36:41 +00002632 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002633 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002634 return(cur);
2635}
2636
2637/**
2638 * xmlNewDocTextLen:
2639 * @doc: the document
2640 * @content: the text content
2641 * @len: the text len.
2642 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002643 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002644 * text node pertain to a given document.
2645 * Returns a pointer to the new node object.
2646 */
2647xmlNodePtr
2648xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2649 xmlNodePtr cur;
2650
2651 cur = xmlNewTextLen(content, len);
2652 if (cur != NULL) cur->doc = doc;
2653 return(cur);
2654}
2655
2656/**
2657 * xmlNewComment:
2658 * @content: the comment content
2659 *
2660 * Creation of a new node containing a comment.
2661 * Returns a pointer to the new node object.
2662 */
2663xmlNodePtr
2664xmlNewComment(const xmlChar *content) {
2665 xmlNodePtr cur;
2666
2667 /*
2668 * Allocate a new node and fill the fields.
2669 */
2670 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2671 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002672 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002673 return(NULL);
2674 }
2675 memset(cur, 0, sizeof(xmlNode));
2676 cur->type = XML_COMMENT_NODE;
2677
2678 cur->name = xmlStringComment;
2679 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002680 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002681 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002682
Daniel Veillarda880b122003-04-21 21:36:41 +00002683 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002684 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002685 return(cur);
2686}
2687
2688/**
2689 * xmlNewCDataBlock:
2690 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002691 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002692 * @len: the length of the block
2693 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002694 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002695 * Returns a pointer to the new node object.
2696 */
2697xmlNodePtr
2698xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2699 xmlNodePtr cur;
2700
2701 /*
2702 * Allocate a new node and fill the fields.
2703 */
2704 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2705 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002706 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002707 return(NULL);
2708 }
2709 memset(cur, 0, sizeof(xmlNode));
2710 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002711 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002712
2713 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002714 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002715 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002716
Daniel Veillarda880b122003-04-21 21:36:41 +00002717 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002718 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002719 return(cur);
2720}
2721
2722/**
2723 * xmlNewDocComment:
2724 * @doc: the document
2725 * @content: the comment content
2726 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002727 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002728 * Returns a pointer to the new node object.
2729 */
2730xmlNodePtr
2731xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2732 xmlNodePtr cur;
2733
2734 cur = xmlNewComment(content);
2735 if (cur != NULL) cur->doc = doc;
2736 return(cur);
2737}
2738
2739/**
2740 * xmlSetTreeDoc:
2741 * @tree: the top element
2742 * @doc: the document
2743 *
2744 * update all nodes under the tree to point to the right document
2745 */
2746void
2747xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002748 xmlAttrPtr prop;
2749
Owen Taylor3473f882001-02-23 17:55:21 +00002750 if (tree == NULL)
2751 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002752 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002753 if(tree->type == XML_ELEMENT_NODE) {
2754 prop = tree->properties;
2755 while (prop != NULL) {
2756 prop->doc = doc;
2757 xmlSetListDoc(prop->children, doc);
2758 prop = prop->next;
2759 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002760 }
Owen Taylor3473f882001-02-23 17:55:21 +00002761 if (tree->children != NULL)
2762 xmlSetListDoc(tree->children, doc);
2763 tree->doc = doc;
2764 }
2765}
2766
2767/**
2768 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002769 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002770 * @doc: the document
2771 *
2772 * update all nodes in the list to point to the right document
2773 */
2774void
2775xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2776 xmlNodePtr cur;
2777
2778 if (list == NULL)
2779 return;
2780 cur = list;
2781 while (cur != NULL) {
2782 if (cur->doc != doc)
2783 xmlSetTreeDoc(cur, doc);
2784 cur = cur->next;
2785 }
2786}
2787
Daniel Veillard2156d432004-03-04 15:59:36 +00002788#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002789/**
2790 * xmlNewChild:
2791 * @parent: the parent node
2792 * @ns: a namespace if any
2793 * @name: the name of the child
2794 * @content: the XML content of the child if any.
2795 *
2796 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002797 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2798 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002799 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002800 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2801 * references. XML special chars must be escaped first by using
2802 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002803 *
2804 * Returns a pointer to the new node object.
2805 */
2806xmlNodePtr
2807xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2808 const xmlChar *name, const xmlChar *content) {
2809 xmlNodePtr cur, prev;
2810
2811 if (parent == NULL) {
2812#ifdef DEBUG_TREE
2813 xmlGenericError(xmlGenericErrorContext,
2814 "xmlNewChild : parent == NULL\n");
2815#endif
2816 return(NULL);
2817 }
2818
2819 if (name == NULL) {
2820#ifdef DEBUG_TREE
2821 xmlGenericError(xmlGenericErrorContext,
2822 "xmlNewChild : name == NULL\n");
2823#endif
2824 return(NULL);
2825 }
2826
2827 /*
2828 * Allocate a new node
2829 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002830 if (parent->type == XML_ELEMENT_NODE) {
2831 if (ns == NULL)
2832 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2833 else
2834 cur = xmlNewDocNode(parent->doc, ns, name, content);
2835 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2836 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2837 if (ns == NULL)
2838 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2839 else
2840 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002841 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2842 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002843 } else {
2844 return(NULL);
2845 }
Owen Taylor3473f882001-02-23 17:55:21 +00002846 if (cur == NULL) return(NULL);
2847
2848 /*
2849 * add the new element at the end of the children list.
2850 */
2851 cur->type = XML_ELEMENT_NODE;
2852 cur->parent = parent;
2853 cur->doc = parent->doc;
2854 if (parent->children == NULL) {
2855 parent->children = cur;
2856 parent->last = cur;
2857 } else {
2858 prev = parent->last;
2859 prev->next = cur;
2860 cur->prev = prev;
2861 parent->last = cur;
2862 }
2863
2864 return(cur);
2865}
Daniel Veillard652327a2003-09-29 18:02:38 +00002866#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002867
2868/**
2869 * xmlAddNextSibling:
2870 * @cur: the child node
2871 * @elem: the new node
2872 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002873 * Add a new node @elem as the next sibling of @cur
2874 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002875 * first unlinked from its existing context.
2876 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002877 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2878 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002879 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002880 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002881 */
2882xmlNodePtr
2883xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2884 if (cur == NULL) {
2885#ifdef DEBUG_TREE
2886 xmlGenericError(xmlGenericErrorContext,
2887 "xmlAddNextSibling : cur == NULL\n");
2888#endif
2889 return(NULL);
2890 }
2891 if (elem == NULL) {
2892#ifdef DEBUG_TREE
2893 xmlGenericError(xmlGenericErrorContext,
2894 "xmlAddNextSibling : elem == NULL\n");
2895#endif
2896 return(NULL);
2897 }
2898
2899 xmlUnlinkNode(elem);
2900
2901 if (elem->type == XML_TEXT_NODE) {
2902 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002903 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002904 xmlFreeNode(elem);
2905 return(cur);
2906 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002907 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2908 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002909 xmlChar *tmp;
2910
2911 tmp = xmlStrdup(elem->content);
2912 tmp = xmlStrcat(tmp, cur->next->content);
2913 xmlNodeSetContent(cur->next, tmp);
2914 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002915 xmlFreeNode(elem);
2916 return(cur->next);
2917 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002918 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2919 /* check if an attribute with the same name exists */
2920 xmlAttrPtr attr;
2921
2922 if (elem->ns == NULL)
2923 attr = xmlHasProp(cur->parent, elem->name);
2924 else
2925 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2926 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2927 /* different instance, destroy it (attributes must be unique) */
2928 xmlFreeProp(attr);
2929 }
Owen Taylor3473f882001-02-23 17:55:21 +00002930 }
2931
2932 if (elem->doc != cur->doc) {
2933 xmlSetTreeDoc(elem, cur->doc);
2934 }
2935 elem->parent = cur->parent;
2936 elem->prev = cur;
2937 elem->next = cur->next;
2938 cur->next = elem;
2939 if (elem->next != NULL)
2940 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002941 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002942 elem->parent->last = elem;
2943 return(elem);
2944}
2945
Daniel Veillard2156d432004-03-04 15:59:36 +00002946#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002947/**
2948 * xmlAddPrevSibling:
2949 * @cur: the child node
2950 * @elem: the new node
2951 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002952 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002953 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002954 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002955 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002956 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2957 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002958 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002959 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002960 */
2961xmlNodePtr
2962xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2963 if (cur == NULL) {
2964#ifdef DEBUG_TREE
2965 xmlGenericError(xmlGenericErrorContext,
2966 "xmlAddPrevSibling : cur == NULL\n");
2967#endif
2968 return(NULL);
2969 }
2970 if (elem == NULL) {
2971#ifdef DEBUG_TREE
2972 xmlGenericError(xmlGenericErrorContext,
2973 "xmlAddPrevSibling : elem == NULL\n");
2974#endif
2975 return(NULL);
2976 }
2977
2978 xmlUnlinkNode(elem);
2979
2980 if (elem->type == XML_TEXT_NODE) {
2981 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002982 xmlChar *tmp;
2983
2984 tmp = xmlStrdup(elem->content);
2985 tmp = xmlStrcat(tmp, cur->content);
2986 xmlNodeSetContent(cur, tmp);
2987 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002988 xmlFreeNode(elem);
2989 return(cur);
2990 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002991 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2992 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002993 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002994 xmlFreeNode(elem);
2995 return(cur->prev);
2996 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002997 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2998 /* check if an attribute with the same name exists */
2999 xmlAttrPtr attr;
3000
3001 if (elem->ns == NULL)
3002 attr = xmlHasProp(cur->parent, elem->name);
3003 else
3004 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
3005 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
3006 /* different instance, destroy it (attributes must be unique) */
3007 xmlFreeProp(attr);
3008 }
Owen Taylor3473f882001-02-23 17:55:21 +00003009 }
3010
3011 if (elem->doc != cur->doc) {
3012 xmlSetTreeDoc(elem, cur->doc);
3013 }
3014 elem->parent = cur->parent;
3015 elem->next = cur;
3016 elem->prev = cur->prev;
3017 cur->prev = elem;
3018 if (elem->prev != NULL)
3019 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003020 if (elem->parent != NULL) {
3021 if (elem->type == XML_ATTRIBUTE_NODE) {
3022 if (elem->parent->properties == (xmlAttrPtr) cur) {
3023 elem->parent->properties = (xmlAttrPtr) elem;
3024 }
3025 } else {
3026 if (elem->parent->children == cur) {
3027 elem->parent->children = elem;
3028 }
3029 }
3030 }
Owen Taylor3473f882001-02-23 17:55:21 +00003031 return(elem);
3032}
Daniel Veillard652327a2003-09-29 18:02:38 +00003033#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003034
3035/**
3036 * xmlAddSibling:
3037 * @cur: the child node
3038 * @elem: the new node
3039 *
3040 * Add a new element @elem to the list of siblings of @cur
3041 * merging adjacent TEXT nodes (@elem may be freed)
3042 * If the new element was already inserted in a document it is
3043 * first unlinked from its existing context.
3044 *
3045 * Returns the new element or NULL in case of error.
3046 */
3047xmlNodePtr
3048xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
3049 xmlNodePtr parent;
3050
3051 if (cur == NULL) {
3052#ifdef DEBUG_TREE
3053 xmlGenericError(xmlGenericErrorContext,
3054 "xmlAddSibling : cur == NULL\n");
3055#endif
3056 return(NULL);
3057 }
3058
3059 if (elem == NULL) {
3060#ifdef DEBUG_TREE
3061 xmlGenericError(xmlGenericErrorContext,
3062 "xmlAddSibling : elem == NULL\n");
3063#endif
3064 return(NULL);
3065 }
3066
3067 /*
3068 * Constant time is we can rely on the ->parent->last to find
3069 * the last sibling.
3070 */
3071 if ((cur->parent != NULL) &&
3072 (cur->parent->children != NULL) &&
3073 (cur->parent->last != NULL) &&
3074 (cur->parent->last->next == NULL)) {
3075 cur = cur->parent->last;
3076 } else {
3077 while (cur->next != NULL) cur = cur->next;
3078 }
3079
3080 xmlUnlinkNode(elem);
3081
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003082 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3083 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003084 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003085 xmlFreeNode(elem);
3086 return(cur);
3087 }
3088
3089 if (elem->doc != cur->doc) {
3090 xmlSetTreeDoc(elem, cur->doc);
3091 }
3092 parent = cur->parent;
3093 elem->prev = cur;
3094 elem->next = NULL;
3095 elem->parent = parent;
3096 cur->next = elem;
3097 if (parent != NULL)
3098 parent->last = elem;
3099
3100 return(elem);
3101}
3102
3103/**
3104 * xmlAddChildList:
3105 * @parent: the parent node
3106 * @cur: the first node in the list
3107 *
3108 * Add a list of node at the end of the child list of the parent
3109 * merging adjacent TEXT nodes (@cur may be freed)
3110 *
3111 * Returns the last child or NULL in case of error.
3112 */
3113xmlNodePtr
3114xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3115 xmlNodePtr prev;
3116
3117 if (parent == NULL) {
3118#ifdef DEBUG_TREE
3119 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003120 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003121#endif
3122 return(NULL);
3123 }
3124
3125 if (cur == NULL) {
3126#ifdef DEBUG_TREE
3127 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003128 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003129#endif
3130 return(NULL);
3131 }
3132
3133 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3134 (cur->doc != parent->doc)) {
3135#ifdef DEBUG_TREE
3136 xmlGenericError(xmlGenericErrorContext,
3137 "Elements moved to a different document\n");
3138#endif
3139 }
3140
3141 /*
3142 * add the first element at the end of the children list.
3143 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003144
Owen Taylor3473f882001-02-23 17:55:21 +00003145 if (parent->children == NULL) {
3146 parent->children = cur;
3147 } else {
3148 /*
3149 * If cur and parent->last both are TEXT nodes, then merge them.
3150 */
3151 if ((cur->type == XML_TEXT_NODE) &&
3152 (parent->last->type == XML_TEXT_NODE) &&
3153 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003154 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003155 /*
3156 * if it's the only child, nothing more to be done.
3157 */
3158 if (cur->next == NULL) {
3159 xmlFreeNode(cur);
3160 return(parent->last);
3161 }
3162 prev = cur;
3163 cur = cur->next;
3164 xmlFreeNode(prev);
3165 }
3166 prev = parent->last;
3167 prev->next = cur;
3168 cur->prev = prev;
3169 }
3170 while (cur->next != NULL) {
3171 cur->parent = parent;
3172 if (cur->doc != parent->doc) {
3173 xmlSetTreeDoc(cur, parent->doc);
3174 }
3175 cur = cur->next;
3176 }
3177 cur->parent = parent;
3178 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3179 parent->last = cur;
3180
3181 return(cur);
3182}
3183
3184/**
3185 * xmlAddChild:
3186 * @parent: the parent node
3187 * @cur: the child node
3188 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003189 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003190 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003191 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3192 * If there is an attribute with equal name, it is first destroyed.
3193 *
Owen Taylor3473f882001-02-23 17:55:21 +00003194 * Returns the child or NULL in case of error.
3195 */
3196xmlNodePtr
3197xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3198 xmlNodePtr prev;
3199
3200 if (parent == NULL) {
3201#ifdef DEBUG_TREE
3202 xmlGenericError(xmlGenericErrorContext,
3203 "xmlAddChild : parent == NULL\n");
3204#endif
3205 return(NULL);
3206 }
3207
3208 if (cur == NULL) {
3209#ifdef DEBUG_TREE
3210 xmlGenericError(xmlGenericErrorContext,
3211 "xmlAddChild : child == NULL\n");
3212#endif
3213 return(NULL);
3214 }
3215
Owen Taylor3473f882001-02-23 17:55:21 +00003216 /*
3217 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003218 * cur is then freed.
3219 */
3220 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003221 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003222 (parent->content != NULL) &&
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003223 (parent->name == cur->name) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003224 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003225 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003226 xmlFreeNode(cur);
3227 return(parent);
3228 }
3229 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003230 (parent->last->name == cur->name) &&
3231 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003232 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003233 xmlFreeNode(cur);
3234 return(parent->last);
3235 }
3236 }
3237
3238 /*
3239 * add the new element at the end of the children list.
3240 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003241 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003242 cur->parent = parent;
3243 if (cur->doc != parent->doc) {
3244 xmlSetTreeDoc(cur, parent->doc);
3245 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003246 /* this check prevents a loop on tree-traversions if a developer
3247 * tries to add a node to its parent multiple times
3248 */
3249 if (prev == parent)
3250 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003251
3252 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003253 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003254 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003255 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003256 (parent->content != NULL) &&
3257 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003258 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003259 xmlFreeNode(cur);
3260 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003261 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003262 if (cur->type == XML_ATTRIBUTE_NODE) {
3263 if (parent->properties == NULL) {
3264 parent->properties = (xmlAttrPtr) cur;
3265 } else {
3266 /* check if an attribute with the same name exists */
3267 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003268
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003269 if (cur->ns == NULL)
3270 lastattr = xmlHasProp(parent, cur->name);
3271 else
3272 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3273 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3274 /* different instance, destroy it (attributes must be unique) */
3275 xmlFreeProp(lastattr);
3276 }
3277 /* find the end */
3278 lastattr = parent->properties;
3279 while (lastattr->next != NULL) {
3280 lastattr = lastattr->next;
3281 }
3282 lastattr->next = (xmlAttrPtr) cur;
3283 ((xmlAttrPtr) cur)->prev = lastattr;
3284 }
3285 } else {
3286 if (parent->children == NULL) {
3287 parent->children = cur;
3288 parent->last = cur;
3289 } else {
3290 prev = parent->last;
3291 prev->next = cur;
3292 cur->prev = prev;
3293 parent->last = cur;
3294 }
3295 }
Owen Taylor3473f882001-02-23 17:55:21 +00003296 return(cur);
3297}
3298
3299/**
3300 * xmlGetLastChild:
3301 * @parent: the parent node
3302 *
3303 * Search the last child of a node.
3304 * Returns the last child or NULL if none.
3305 */
3306xmlNodePtr
3307xmlGetLastChild(xmlNodePtr parent) {
3308 if (parent == NULL) {
3309#ifdef DEBUG_TREE
3310 xmlGenericError(xmlGenericErrorContext,
3311 "xmlGetLastChild : parent == NULL\n");
3312#endif
3313 return(NULL);
3314 }
3315 return(parent->last);
3316}
3317
3318/**
3319 * xmlFreeNodeList:
3320 * @cur: the first node in the list
3321 *
3322 * Free a node and all its siblings, this is a recursive behaviour, all
3323 * the children are freed too.
3324 */
3325void
3326xmlFreeNodeList(xmlNodePtr cur) {
3327 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003328 xmlDictPtr dict = NULL;
3329
3330 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003331 if (cur->type == XML_NAMESPACE_DECL) {
3332 xmlFreeNsList((xmlNsPtr) cur);
3333 return;
3334 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003335 if ((cur->type == XML_DOCUMENT_NODE) ||
3336#ifdef LIBXML_DOCB_ENABLED
3337 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003338#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003339 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003340 xmlFreeDoc((xmlDocPtr) cur);
3341 return;
3342 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003343 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003344 while (cur != NULL) {
3345 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003346 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003347
Daniel Veillarda880b122003-04-21 21:36:41 +00003348 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003349 xmlDeregisterNodeDefaultValue(cur);
3350
Daniel Veillard02141ea2001-04-30 11:46:40 +00003351 if ((cur->children != NULL) &&
3352 (cur->type != XML_ENTITY_REF_NODE))
3353 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003354 if (((cur->type == XML_ELEMENT_NODE) ||
3355 (cur->type == XML_XINCLUDE_START) ||
3356 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003357 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003358 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003359 if ((cur->type != XML_ELEMENT_NODE) &&
3360 (cur->type != XML_XINCLUDE_START) &&
3361 (cur->type != XML_XINCLUDE_END) &&
3362 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003363 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003364 }
3365 if (((cur->type == XML_ELEMENT_NODE) ||
3366 (cur->type == XML_XINCLUDE_START) ||
3367 (cur->type == XML_XINCLUDE_END)) &&
3368 (cur->nsDef != NULL))
3369 xmlFreeNsList(cur->nsDef);
3370
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003371 /*
3372 * When a node is a text node or a comment, it uses a global static
3373 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003374 * Otherwise the node name might come from the document's
3375 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003376 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003377 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003378 (cur->type != XML_TEXT_NODE) &&
3379 (cur->type != XML_COMMENT_NODE))
3380 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003381 xmlFree(cur);
3382 }
Owen Taylor3473f882001-02-23 17:55:21 +00003383 cur = next;
3384 }
3385}
3386
3387/**
3388 * xmlFreeNode:
3389 * @cur: the node
3390 *
3391 * Free a node, this is a recursive behaviour, all the children are freed too.
3392 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3393 */
3394void
3395xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003396 xmlDictPtr dict = NULL;
3397
3398 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003399
Daniel Veillard02141ea2001-04-30 11:46:40 +00003400 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003401 if (cur->type == XML_DTD_NODE) {
3402 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003403 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003404 }
3405 if (cur->type == XML_NAMESPACE_DECL) {
3406 xmlFreeNs((xmlNsPtr) cur);
3407 return;
3408 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003409 if (cur->type == XML_ATTRIBUTE_NODE) {
3410 xmlFreeProp((xmlAttrPtr) cur);
3411 return;
3412 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003413
Daniel Veillarda880b122003-04-21 21:36:41 +00003414 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003415 xmlDeregisterNodeDefaultValue(cur);
3416
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003417 if (cur->doc != NULL) dict = cur->doc->dict;
3418
Owen Taylor3473f882001-02-23 17:55:21 +00003419 if ((cur->children != NULL) &&
3420 (cur->type != XML_ENTITY_REF_NODE))
3421 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003422 if (((cur->type == XML_ELEMENT_NODE) ||
3423 (cur->type == XML_XINCLUDE_START) ||
3424 (cur->type == XML_XINCLUDE_END)) &&
3425 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003426 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003427 if ((cur->type != XML_ELEMENT_NODE) &&
3428 (cur->content != NULL) &&
3429 (cur->type != XML_ENTITY_REF_NODE) &&
3430 (cur->type != XML_XINCLUDE_END) &&
3431 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003432 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003433 }
3434
Daniel Veillardacd370f2001-06-09 17:17:51 +00003435 /*
3436 * When a node is a text node or a comment, it uses a global static
3437 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003438 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003439 */
Owen Taylor3473f882001-02-23 17:55:21 +00003440 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003441 (cur->type != XML_TEXT_NODE) &&
3442 (cur->type != XML_COMMENT_NODE))
3443 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003444
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003445 if (((cur->type == XML_ELEMENT_NODE) ||
3446 (cur->type == XML_XINCLUDE_START) ||
3447 (cur->type == XML_XINCLUDE_END)) &&
3448 (cur->nsDef != NULL))
3449 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003450 xmlFree(cur);
3451}
3452
3453/**
3454 * xmlUnlinkNode:
3455 * @cur: the node
3456 *
3457 * Unlink a node from it's current context, the node is not freed
3458 */
3459void
3460xmlUnlinkNode(xmlNodePtr cur) {
3461 if (cur == NULL) {
3462#ifdef DEBUG_TREE
3463 xmlGenericError(xmlGenericErrorContext,
3464 "xmlUnlinkNode : node == NULL\n");
3465#endif
3466 return;
3467 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003468 if (cur->type == XML_DTD_NODE) {
3469 xmlDocPtr doc;
3470 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003471 if (doc != NULL) {
3472 if (doc->intSubset == (xmlDtdPtr) cur)
3473 doc->intSubset = NULL;
3474 if (doc->extSubset == (xmlDtdPtr) cur)
3475 doc->extSubset = NULL;
3476 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003477 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003478 if (cur->parent != NULL) {
3479 xmlNodePtr parent;
3480 parent = cur->parent;
3481 if (cur->type == XML_ATTRIBUTE_NODE) {
3482 if (parent->properties == (xmlAttrPtr) cur)
3483 parent->properties = ((xmlAttrPtr) cur)->next;
3484 } else {
3485 if (parent->children == cur)
3486 parent->children = cur->next;
3487 if (parent->last == cur)
3488 parent->last = cur->prev;
3489 }
3490 cur->parent = NULL;
3491 }
Owen Taylor3473f882001-02-23 17:55:21 +00003492 if (cur->next != NULL)
3493 cur->next->prev = cur->prev;
3494 if (cur->prev != NULL)
3495 cur->prev->next = cur->next;
3496 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003497}
3498
Daniel Veillard2156d432004-03-04 15:59:36 +00003499#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003500/**
3501 * xmlReplaceNode:
3502 * @old: the old node
3503 * @cur: the node
3504 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003505 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003506 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003507 * first unlinked from its existing context.
3508 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003509 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003510 */
3511xmlNodePtr
3512xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3513 if (old == NULL) {
3514#ifdef DEBUG_TREE
3515 xmlGenericError(xmlGenericErrorContext,
3516 "xmlReplaceNode : old == NULL\n");
3517#endif
3518 return(NULL);
3519 }
3520 if (cur == NULL) {
3521 xmlUnlinkNode(old);
3522 return(old);
3523 }
3524 if (cur == old) {
3525 return(old);
3526 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003527 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3528#ifdef DEBUG_TREE
3529 xmlGenericError(xmlGenericErrorContext,
3530 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3531#endif
3532 return(old);
3533 }
3534 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3535#ifdef DEBUG_TREE
3536 xmlGenericError(xmlGenericErrorContext,
3537 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3538#endif
3539 return(old);
3540 }
Owen Taylor3473f882001-02-23 17:55:21 +00003541 xmlUnlinkNode(cur);
3542 cur->doc = old->doc;
3543 cur->parent = old->parent;
3544 cur->next = old->next;
3545 if (cur->next != NULL)
3546 cur->next->prev = cur;
3547 cur->prev = old->prev;
3548 if (cur->prev != NULL)
3549 cur->prev->next = cur;
3550 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003551 if (cur->type == XML_ATTRIBUTE_NODE) {
3552 if (cur->parent->properties == (xmlAttrPtr)old)
3553 cur->parent->properties = ((xmlAttrPtr) cur);
3554 } else {
3555 if (cur->parent->children == old)
3556 cur->parent->children = cur;
3557 if (cur->parent->last == old)
3558 cur->parent->last = cur;
3559 }
Owen Taylor3473f882001-02-23 17:55:21 +00003560 }
3561 old->next = old->prev = NULL;
3562 old->parent = NULL;
3563 return(old);
3564}
Daniel Veillard652327a2003-09-29 18:02:38 +00003565#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003566
3567/************************************************************************
3568 * *
3569 * Copy operations *
3570 * *
3571 ************************************************************************/
3572
3573/**
3574 * xmlCopyNamespace:
3575 * @cur: the namespace
3576 *
3577 * Do a copy of the namespace.
3578 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003579 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003580 */
3581xmlNsPtr
3582xmlCopyNamespace(xmlNsPtr cur) {
3583 xmlNsPtr ret;
3584
3585 if (cur == NULL) return(NULL);
3586 switch (cur->type) {
3587 case XML_LOCAL_NAMESPACE:
3588 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3589 break;
3590 default:
3591#ifdef DEBUG_TREE
3592 xmlGenericError(xmlGenericErrorContext,
3593 "xmlCopyNamespace: invalid type %d\n", cur->type);
3594#endif
3595 return(NULL);
3596 }
3597 return(ret);
3598}
3599
3600/**
3601 * xmlCopyNamespaceList:
3602 * @cur: the first namespace
3603 *
3604 * Do a copy of an namespace list.
3605 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003606 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003607 */
3608xmlNsPtr
3609xmlCopyNamespaceList(xmlNsPtr cur) {
3610 xmlNsPtr ret = NULL;
3611 xmlNsPtr p = NULL,q;
3612
3613 while (cur != NULL) {
3614 q = xmlCopyNamespace(cur);
3615 if (p == NULL) {
3616 ret = p = q;
3617 } else {
3618 p->next = q;
3619 p = q;
3620 }
3621 cur = cur->next;
3622 }
3623 return(ret);
3624}
3625
3626static xmlNodePtr
3627xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3628/**
3629 * xmlCopyProp:
3630 * @target: the element where the attribute will be grafted
3631 * @cur: the attribute
3632 *
3633 * Do a copy of the attribute.
3634 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003635 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003636 */
3637xmlAttrPtr
3638xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3639 xmlAttrPtr ret;
3640
3641 if (cur == NULL) return(NULL);
3642 if (target != NULL)
3643 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3644 else if (cur->parent != NULL)
3645 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3646 else if (cur->children != NULL)
3647 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3648 else
3649 ret = xmlNewDocProp(NULL, cur->name, NULL);
3650 if (ret == NULL) return(NULL);
3651 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003652
Owen Taylor3473f882001-02-23 17:55:21 +00003653 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003654 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003655
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003656 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3657 if (ns == NULL) {
3658 /*
3659 * Humm, we are copying an element whose namespace is defined
3660 * out of the new tree scope. Search it in the original tree
3661 * and add it at the top of the new tree
3662 */
3663 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3664 if (ns != NULL) {
3665 xmlNodePtr root = target;
3666 xmlNodePtr pred = NULL;
3667
3668 while (root->parent != NULL) {
3669 pred = root;
3670 root = root->parent;
3671 }
3672 if (root == (xmlNodePtr) target->doc) {
3673 /* correct possibly cycling above the document elt */
3674 root = pred;
3675 }
3676 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3677 }
3678 } else {
3679 /*
3680 * we have to find something appropriate here since
3681 * we cant be sure, that the namespce we found is identified
3682 * by the prefix
3683 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003684 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003685 /* this is the nice case */
3686 ret->ns = ns;
3687 } else {
3688 /*
3689 * we are in trouble: we need a new reconcilied namespace.
3690 * This is expensive
3691 */
3692 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3693 }
3694 }
3695
Owen Taylor3473f882001-02-23 17:55:21 +00003696 } else
3697 ret->ns = NULL;
3698
3699 if (cur->children != NULL) {
3700 xmlNodePtr tmp;
3701
3702 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3703 ret->last = NULL;
3704 tmp = ret->children;
3705 while (tmp != NULL) {
3706 /* tmp->parent = (xmlNodePtr)ret; */
3707 if (tmp->next == NULL)
3708 ret->last = tmp;
3709 tmp = tmp->next;
3710 }
3711 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003712 /*
3713 * Try to handle IDs
3714 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003715 if ((target!= NULL) && (cur!= NULL) &&
3716 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003717 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3718 if (xmlIsID(cur->doc, cur->parent, cur)) {
3719 xmlChar *id;
3720
3721 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3722 if (id != NULL) {
3723 xmlAddID(NULL, target->doc, id, ret);
3724 xmlFree(id);
3725 }
3726 }
3727 }
Owen Taylor3473f882001-02-23 17:55:21 +00003728 return(ret);
3729}
3730
3731/**
3732 * xmlCopyPropList:
3733 * @target: the element where the attributes will be grafted
3734 * @cur: the first attribute
3735 *
3736 * Do a copy of an attribute list.
3737 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003738 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003739 */
3740xmlAttrPtr
3741xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3742 xmlAttrPtr ret = NULL;
3743 xmlAttrPtr p = NULL,q;
3744
3745 while (cur != NULL) {
3746 q = xmlCopyProp(target, cur);
William M. Brack13dfa872004-09-18 04:52:08 +00003747 if (q == NULL)
3748 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003749 if (p == NULL) {
3750 ret = p = q;
3751 } else {
3752 p->next = q;
3753 q->prev = p;
3754 p = q;
3755 }
3756 cur = cur->next;
3757 }
3758 return(ret);
3759}
3760
3761/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003762 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003763 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003764 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003765 * tricky reason: namespaces. Doing a direct copy of a node
3766 * say RPM:Copyright without changing the namespace pointer to
3767 * something else can produce stale links. One way to do it is
3768 * to keep a reference counter but this doesn't work as soon
3769 * as one move the element or the subtree out of the scope of
3770 * the existing namespace. The actual solution seems to add
3771 * a copy of the namespace at the top of the copied tree if
3772 * not available in the subtree.
3773 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00003774 * The argument "recursive" normally indicates a recursive copy
3775 * of the node with values 0 (no) and 1 (yes). For XInclude,
3776 * however, we allow a value of 2 to indicate copy properties and
3777 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00003778 */
3779
3780static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003781xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00003782 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003783 xmlNodePtr ret;
3784
3785 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003786 switch (node->type) {
3787 case XML_TEXT_NODE:
3788 case XML_CDATA_SECTION_NODE:
3789 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003790 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003791 case XML_ENTITY_REF_NODE:
3792 case XML_ENTITY_NODE:
3793 case XML_PI_NODE:
3794 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003795 case XML_XINCLUDE_START:
3796 case XML_XINCLUDE_END:
3797 break;
3798 case XML_ATTRIBUTE_NODE:
3799 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3800 case XML_NAMESPACE_DECL:
3801 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3802
Daniel Veillard39196eb2001-06-19 18:09:42 +00003803 case XML_DOCUMENT_NODE:
3804 case XML_HTML_DOCUMENT_NODE:
3805#ifdef LIBXML_DOCB_ENABLED
3806 case XML_DOCB_DOCUMENT_NODE:
3807#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003808#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00003809 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00003810#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003811 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003812 case XML_NOTATION_NODE:
3813 case XML_DTD_NODE:
3814 case XML_ELEMENT_DECL:
3815 case XML_ATTRIBUTE_DECL:
3816 case XML_ENTITY_DECL:
3817 return(NULL);
3818 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003819
Owen Taylor3473f882001-02-23 17:55:21 +00003820 /*
3821 * Allocate a new node and fill the fields.
3822 */
3823 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3824 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003825 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003826 return(NULL);
3827 }
3828 memset(ret, 0, sizeof(xmlNode));
3829 ret->type = node->type;
3830
3831 ret->doc = doc;
3832 ret->parent = parent;
3833 if (node->name == xmlStringText)
3834 ret->name = xmlStringText;
3835 else if (node->name == xmlStringTextNoenc)
3836 ret->name = xmlStringTextNoenc;
3837 else if (node->name == xmlStringComment)
3838 ret->name = xmlStringComment;
Daniel Veillard03a53c32004-10-26 16:06:51 +00003839 else if (node->name != NULL) {
3840 if ((doc != NULL) && (doc->dict != NULL))
3841 ret->name = xmlDictLookup(doc->dict, node->name, -1);
3842 else
3843 ret->name = xmlStrdup(node->name);
3844 }
Daniel Veillard7db37732001-07-12 01:20:08 +00003845 if ((node->type != XML_ELEMENT_NODE) &&
3846 (node->content != NULL) &&
3847 (node->type != XML_ENTITY_REF_NODE) &&
3848 (node->type != XML_XINCLUDE_END) &&
3849 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003850 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003851 }else{
3852 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003853 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003854 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003855 if (parent != NULL) {
3856 xmlNodePtr tmp;
3857
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003858 /*
3859 * this is a tricky part for the node register thing:
3860 * in case ret does get coalesced in xmlAddChild
3861 * the deregister-node callback is called; so we register ret now already
3862 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003863 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003864 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3865
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003866 tmp = xmlAddChild(parent, ret);
3867 /* node could have coalesced */
3868 if (tmp != ret)
3869 return(tmp);
3870 }
Owen Taylor3473f882001-02-23 17:55:21 +00003871
William M. Brack57e9e912004-03-09 16:19:02 +00003872 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003873 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003874 if (node->nsDef != NULL)
3875 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3876
3877 if (node->ns != NULL) {
3878 xmlNsPtr ns;
3879
3880 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3881 if (ns == NULL) {
3882 /*
3883 * Humm, we are copying an element whose namespace is defined
3884 * out of the new tree scope. Search it in the original tree
3885 * and add it at the top of the new tree
3886 */
3887 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3888 if (ns != NULL) {
3889 xmlNodePtr root = ret;
3890
3891 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003892 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003893 }
3894 } else {
3895 /*
3896 * reference the existing namespace definition in our own tree.
3897 */
3898 ret->ns = ns;
3899 }
3900 }
3901 if (node->properties != NULL)
3902 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003903 if (node->type == XML_ENTITY_REF_NODE) {
3904 if ((doc == NULL) || (node->doc != doc)) {
3905 /*
3906 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003907 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003908 * we cannot keep the reference. Try to find it in the
3909 * target document.
3910 */
3911 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3912 } else {
3913 ret->children = node->children;
3914 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003915 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00003916 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003917 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003918 UPDATE_LAST_CHILD_AND_PARENT(ret)
3919 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003920
3921out:
3922 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00003923 if ((parent == NULL) &&
3924 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003925 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003926 return(ret);
3927}
3928
3929static xmlNodePtr
3930xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3931 xmlNodePtr ret = NULL;
3932 xmlNodePtr p = NULL,q;
3933
3934 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003935#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003936 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003937 if (doc == NULL) {
3938 node = node->next;
3939 continue;
3940 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003941 if (doc->intSubset == NULL) {
3942 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3943 q->doc = doc;
3944 q->parent = parent;
3945 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003946 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003947 } else {
3948 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003949 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003950 }
3951 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003952#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003953 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003954 if (ret == NULL) {
3955 q->prev = NULL;
3956 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003957 } else if (p != q) {
3958 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003959 p->next = q;
3960 q->prev = p;
3961 p = q;
3962 }
3963 node = node->next;
3964 }
3965 return(ret);
3966}
3967
3968/**
3969 * xmlCopyNode:
3970 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00003971 * @extended: if 1 do a recursive copy (properties, namespaces and children
3972 * when applicable)
3973 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00003974 *
3975 * Do a copy of the node.
3976 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003977 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003978 */
3979xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003980xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003981 xmlNodePtr ret;
3982
William M. Brack57e9e912004-03-09 16:19:02 +00003983 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00003984 return(ret);
3985}
3986
3987/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003988 * xmlDocCopyNode:
3989 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003990 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00003991 * @extended: if 1 do a recursive copy (properties, namespaces and children
3992 * when applicable)
3993 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00003994 *
3995 * Do a copy of the node to a given document.
3996 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003997 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003998 */
3999xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00004000xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00004001 xmlNodePtr ret;
4002
William M. Brack57e9e912004-03-09 16:19:02 +00004003 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00004004 return(ret);
4005}
4006
4007/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00004008 * xmlDocCopyNodeList:
4009 * @doc: the target document
4010 * @node: the first node in the list.
4011 *
4012 * Do a recursive copy of the node list.
4013 *
4014 * Returns: a new #xmlNodePtr, or NULL in case of error.
4015 */
4016xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) {
4017 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
4018 return(ret);
4019}
4020
4021/**
Owen Taylor3473f882001-02-23 17:55:21 +00004022 * xmlCopyNodeList:
4023 * @node: the first node in the list.
4024 *
4025 * Do a recursive copy of the node list.
Daniel Veillard03a53c32004-10-26 16:06:51 +00004026 * Use xmlDocCopyNodeList() if possible to ensure string interning.
Owen Taylor3473f882001-02-23 17:55:21 +00004027 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004028 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004029 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00004030xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00004031 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
4032 return(ret);
4033}
4034
Daniel Veillard2156d432004-03-04 15:59:36 +00004035#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004036/**
Owen Taylor3473f882001-02-23 17:55:21 +00004037 * xmlCopyDtd:
4038 * @dtd: the dtd
4039 *
4040 * Do a copy of the dtd.
4041 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004042 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004043 */
4044xmlDtdPtr
4045xmlCopyDtd(xmlDtdPtr dtd) {
4046 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004047 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00004048
4049 if (dtd == NULL) return(NULL);
4050 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4051 if (ret == NULL) return(NULL);
4052 if (dtd->entities != NULL)
4053 ret->entities = (void *) xmlCopyEntitiesTable(
4054 (xmlEntitiesTablePtr) dtd->entities);
4055 if (dtd->notations != NULL)
4056 ret->notations = (void *) xmlCopyNotationTable(
4057 (xmlNotationTablePtr) dtd->notations);
4058 if (dtd->elements != NULL)
4059 ret->elements = (void *) xmlCopyElementTable(
4060 (xmlElementTablePtr) dtd->elements);
4061 if (dtd->attributes != NULL)
4062 ret->attributes = (void *) xmlCopyAttributeTable(
4063 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004064 if (dtd->pentities != NULL)
4065 ret->pentities = (void *) xmlCopyEntitiesTable(
4066 (xmlEntitiesTablePtr) dtd->pentities);
4067
4068 cur = dtd->children;
4069 while (cur != NULL) {
4070 q = NULL;
4071
4072 if (cur->type == XML_ENTITY_DECL) {
4073 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4074 switch (tmp->etype) {
4075 case XML_INTERNAL_GENERAL_ENTITY:
4076 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4077 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4078 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4079 break;
4080 case XML_INTERNAL_PARAMETER_ENTITY:
4081 case XML_EXTERNAL_PARAMETER_ENTITY:
4082 q = (xmlNodePtr)
4083 xmlGetParameterEntityFromDtd(ret, tmp->name);
4084 break;
4085 case XML_INTERNAL_PREDEFINED_ENTITY:
4086 break;
4087 }
4088 } else if (cur->type == XML_ELEMENT_DECL) {
4089 xmlElementPtr tmp = (xmlElementPtr) cur;
4090 q = (xmlNodePtr)
4091 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4092 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4093 xmlAttributePtr tmp = (xmlAttributePtr) cur;
4094 q = (xmlNodePtr)
4095 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4096 } else if (cur->type == XML_COMMENT_NODE) {
4097 q = xmlCopyNode(cur, 0);
4098 }
4099
4100 if (q == NULL) {
4101 cur = cur->next;
4102 continue;
4103 }
4104
4105 if (p == NULL)
4106 ret->children = q;
4107 else
4108 p->next = q;
4109
4110 q->prev = p;
4111 q->parent = (xmlNodePtr) ret;
4112 q->next = NULL;
4113 ret->last = q;
4114 p = q;
4115 cur = cur->next;
4116 }
4117
Owen Taylor3473f882001-02-23 17:55:21 +00004118 return(ret);
4119}
Daniel Veillard2156d432004-03-04 15:59:36 +00004120#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004121
Daniel Veillard2156d432004-03-04 15:59:36 +00004122#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004123/**
4124 * xmlCopyDoc:
4125 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004126 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004127 *
4128 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004129 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004130 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004131 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004132 */
4133xmlDocPtr
4134xmlCopyDoc(xmlDocPtr doc, int recursive) {
4135 xmlDocPtr ret;
4136
4137 if (doc == NULL) return(NULL);
4138 ret = xmlNewDoc(doc->version);
4139 if (ret == NULL) return(NULL);
4140 if (doc->name != NULL)
4141 ret->name = xmlMemStrdup(doc->name);
4142 if (doc->encoding != NULL)
4143 ret->encoding = xmlStrdup(doc->encoding);
4144 ret->charset = doc->charset;
4145 ret->compression = doc->compression;
4146 ret->standalone = doc->standalone;
4147 if (!recursive) return(ret);
4148
Daniel Veillardb33c2012001-04-25 12:59:04 +00004149 ret->last = NULL;
4150 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004151#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004152 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004153 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004154 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004155 ret->intSubset->parent = ret;
4156 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004157#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004158 if (doc->oldNs != NULL)
4159 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4160 if (doc->children != NULL) {
4161 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004162
4163 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4164 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004165 ret->last = NULL;
4166 tmp = ret->children;
4167 while (tmp != NULL) {
4168 if (tmp->next == NULL)
4169 ret->last = tmp;
4170 tmp = tmp->next;
4171 }
4172 }
4173 return(ret);
4174}
Daniel Veillard652327a2003-09-29 18:02:38 +00004175#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004176
4177/************************************************************************
4178 * *
4179 * Content access functions *
4180 * *
4181 ************************************************************************/
4182
4183/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004184 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004185 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004186 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004187 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004188 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004189 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004190 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004191 */
4192long
4193xmlGetLineNo(xmlNodePtr node)
4194{
4195 long result = -1;
4196
4197 if (!node)
4198 return result;
4199 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004200 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004201 else if ((node->prev != NULL) &&
4202 ((node->prev->type == XML_ELEMENT_NODE) ||
4203 (node->prev->type == XML_TEXT_NODE)))
4204 result = xmlGetLineNo(node->prev);
4205 else if ((node->parent != NULL) &&
4206 ((node->parent->type == XML_ELEMENT_NODE) ||
4207 (node->parent->type == XML_TEXT_NODE)))
4208 result = xmlGetLineNo(node->parent);
4209
4210 return result;
4211}
4212
Daniel Veillard2156d432004-03-04 15:59:36 +00004213#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004214/**
4215 * xmlGetNodePath:
4216 * @node: a node
4217 *
4218 * Build a structure based Path for the given node
4219 *
4220 * Returns the new path or NULL in case of error. The caller must free
4221 * the returned string
4222 */
4223xmlChar *
4224xmlGetNodePath(xmlNodePtr node)
4225{
4226 xmlNodePtr cur, tmp, next;
4227 xmlChar *buffer = NULL, *temp;
4228 size_t buf_len;
4229 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004230 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004231 const char *name;
4232 char nametemp[100];
4233 int occur = 0;
4234
4235 if (node == NULL)
4236 return (NULL);
4237
4238 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004239 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004240 if (buffer == NULL) {
4241 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004242 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004243 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004244 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004245 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004246 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004247 xmlFree(buffer);
4248 return (NULL);
4249 }
4250
4251 buffer[0] = 0;
4252 cur = node;
4253 do {
4254 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004255 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004256 occur = 0;
4257 if ((cur->type == XML_DOCUMENT_NODE) ||
4258 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4259 if (buffer[0] == '/')
4260 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004261 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004262 next = NULL;
4263 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004264 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004265 name = (const char *) cur->name;
4266 if (cur->ns) {
William M. Brack84d83e32003-12-23 03:45:17 +00004267 if (cur->ns->prefix != NULL)
William M. Brack13dfa872004-09-18 04:52:08 +00004268 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4269 (char *)cur->ns->prefix, (char *)cur->name);
William M. Brack84d83e32003-12-23 03:45:17 +00004270 else
William M. Brack13dfa872004-09-18 04:52:08 +00004271 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4272 (char *)cur->name);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004273 nametemp[sizeof(nametemp) - 1] = 0;
4274 name = nametemp;
4275 }
4276 next = cur->parent;
4277
4278 /*
4279 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004280 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004281 */
4282 tmp = cur->prev;
4283 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004284 if ((tmp->type == XML_ELEMENT_NODE) &&
4285 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004286 occur++;
4287 tmp = tmp->prev;
4288 }
4289 if (occur == 0) {
4290 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004291 while (tmp != NULL && occur == 0) {
4292 if ((tmp->type == XML_ELEMENT_NODE) &&
4293 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004294 occur++;
4295 tmp = tmp->next;
4296 }
4297 if (occur != 0)
4298 occur = 1;
4299 } else
4300 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004301 } else if (cur->type == XML_COMMENT_NODE) {
4302 sep = "/";
4303 name = "comment()";
4304 next = cur->parent;
4305
4306 /*
4307 * Thumbler index computation
4308 */
4309 tmp = cur->prev;
4310 while (tmp != NULL) {
4311 if (tmp->type == XML_COMMENT_NODE)
4312 occur++;
4313 tmp = tmp->prev;
4314 }
4315 if (occur == 0) {
4316 tmp = cur->next;
4317 while (tmp != NULL && occur == 0) {
4318 if (tmp->type == XML_COMMENT_NODE)
4319 occur++;
4320 tmp = tmp->next;
4321 }
4322 if (occur != 0)
4323 occur = 1;
4324 } else
4325 occur++;
4326 } else if ((cur->type == XML_TEXT_NODE) ||
4327 (cur->type == XML_CDATA_SECTION_NODE)) {
4328 sep = "/";
4329 name = "text()";
4330 next = cur->parent;
4331
4332 /*
4333 * Thumbler index computation
4334 */
4335 tmp = cur->prev;
4336 while (tmp != NULL) {
4337 if ((cur->type == XML_TEXT_NODE) ||
4338 (cur->type == XML_CDATA_SECTION_NODE))
4339 occur++;
4340 tmp = tmp->prev;
4341 }
4342 if (occur == 0) {
4343 tmp = cur->next;
4344 while (tmp != NULL && occur == 0) {
Daniel Veillard1f8658a2004-08-14 21:46:31 +00004345 if ((tmp->type == XML_TEXT_NODE) ||
4346 (tmp->type == XML_CDATA_SECTION_NODE))
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004347 occur++;
4348 tmp = tmp->next;
4349 }
4350 if (occur != 0)
4351 occur = 1;
4352 } else
4353 occur++;
4354 } else if (cur->type == XML_PI_NODE) {
4355 sep = "/";
4356 snprintf(nametemp, sizeof(nametemp) - 1,
William M. Brack13dfa872004-09-18 04:52:08 +00004357 "processing-instruction('%s')", (char *)cur->name);
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004358 nametemp[sizeof(nametemp) - 1] = 0;
4359 name = nametemp;
4360
4361 next = cur->parent;
4362
4363 /*
4364 * Thumbler index computation
4365 */
4366 tmp = cur->prev;
4367 while (tmp != NULL) {
4368 if ((tmp->type == XML_PI_NODE) &&
4369 (xmlStrEqual(cur->name, tmp->name)))
4370 occur++;
4371 tmp = tmp->prev;
4372 }
4373 if (occur == 0) {
4374 tmp = cur->next;
4375 while (tmp != NULL && occur == 0) {
4376 if ((tmp->type == XML_PI_NODE) &&
4377 (xmlStrEqual(cur->name, tmp->name)))
4378 occur++;
4379 tmp = tmp->next;
4380 }
4381 if (occur != 0)
4382 occur = 1;
4383 } else
4384 occur++;
4385
Daniel Veillard8faa7832001-11-26 15:58:08 +00004386 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004387 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004388 name = (const char *) (((xmlAttrPtr) cur)->name);
4389 next = ((xmlAttrPtr) cur)->parent;
4390 } else {
4391 next = cur->parent;
4392 }
4393
4394 /*
4395 * Make sure there is enough room
4396 */
4397 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4398 buf_len =
4399 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4400 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4401 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004402 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004403 xmlFree(buf);
4404 xmlFree(buffer);
4405 return (NULL);
4406 }
4407 buffer = temp;
4408 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4409 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004410 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004411 xmlFree(buf);
4412 xmlFree(buffer);
4413 return (NULL);
4414 }
4415 buf = temp;
4416 }
4417 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004418 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004419 sep, name, (char *) buffer);
4420 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004421 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004422 sep, name, occur, (char *) buffer);
William M. Brack13dfa872004-09-18 04:52:08 +00004423 snprintf((char *) buffer, buf_len, "%s", (char *)buf);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004424 cur = next;
4425 } while (cur != NULL);
4426 xmlFree(buf);
4427 return (buffer);
4428}
Daniel Veillard652327a2003-09-29 18:02:38 +00004429#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004430
4431/**
Owen Taylor3473f882001-02-23 17:55:21 +00004432 * xmlDocGetRootElement:
4433 * @doc: the document
4434 *
4435 * Get the root element of the document (doc->children is a list
4436 * containing possibly comments, PIs, etc ...).
4437 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004438 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004439 */
4440xmlNodePtr
4441xmlDocGetRootElement(xmlDocPtr doc) {
4442 xmlNodePtr ret;
4443
4444 if (doc == NULL) return(NULL);
4445 ret = doc->children;
4446 while (ret != NULL) {
4447 if (ret->type == XML_ELEMENT_NODE)
4448 return(ret);
4449 ret = ret->next;
4450 }
4451 return(ret);
4452}
4453
Daniel Veillard2156d432004-03-04 15:59:36 +00004454#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004455/**
4456 * xmlDocSetRootElement:
4457 * @doc: the document
4458 * @root: the new document root element
4459 *
4460 * Set the root element of the document (doc->children is a list
4461 * containing possibly comments, PIs, etc ...).
4462 *
4463 * Returns the old root element if any was found
4464 */
4465xmlNodePtr
4466xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4467 xmlNodePtr old = NULL;
4468
4469 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004470 if (root == NULL)
4471 return(NULL);
4472 xmlUnlinkNode(root);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00004473 xmlSetTreeDoc(root, doc);
Daniel Veillardc575b992002-02-08 13:28:40 +00004474 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004475 old = doc->children;
4476 while (old != NULL) {
4477 if (old->type == XML_ELEMENT_NODE)
4478 break;
4479 old = old->next;
4480 }
4481 if (old == NULL) {
4482 if (doc->children == NULL) {
4483 doc->children = root;
4484 doc->last = root;
4485 } else {
4486 xmlAddSibling(doc->children, root);
4487 }
4488 } else {
4489 xmlReplaceNode(old, root);
4490 }
4491 return(old);
4492}
Daniel Veillard2156d432004-03-04 15:59:36 +00004493#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004494
Daniel Veillard2156d432004-03-04 15:59:36 +00004495#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004496/**
4497 * xmlNodeSetLang:
4498 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004499 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004500 *
4501 * Set the language of a node, i.e. the values of the xml:lang
4502 * attribute.
4503 */
4504void
4505xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004506 xmlNsPtr ns;
4507
Owen Taylor3473f882001-02-23 17:55:21 +00004508 if (cur == NULL) return;
4509 switch(cur->type) {
4510 case XML_TEXT_NODE:
4511 case XML_CDATA_SECTION_NODE:
4512 case XML_COMMENT_NODE:
4513 case XML_DOCUMENT_NODE:
4514 case XML_DOCUMENT_TYPE_NODE:
4515 case XML_DOCUMENT_FRAG_NODE:
4516 case XML_NOTATION_NODE:
4517 case XML_HTML_DOCUMENT_NODE:
4518 case XML_DTD_NODE:
4519 case XML_ELEMENT_DECL:
4520 case XML_ATTRIBUTE_DECL:
4521 case XML_ENTITY_DECL:
4522 case XML_PI_NODE:
4523 case XML_ENTITY_REF_NODE:
4524 case XML_ENTITY_NODE:
4525 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004526#ifdef LIBXML_DOCB_ENABLED
4527 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004528#endif
4529 case XML_XINCLUDE_START:
4530 case XML_XINCLUDE_END:
4531 return;
4532 case XML_ELEMENT_NODE:
4533 case XML_ATTRIBUTE_NODE:
4534 break;
4535 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004536 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4537 if (ns == NULL)
4538 return;
4539 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004540}
Daniel Veillard652327a2003-09-29 18:02:38 +00004541#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004542
4543/**
4544 * xmlNodeGetLang:
4545 * @cur: the node being checked
4546 *
4547 * Searches the language of a node, i.e. the values of the xml:lang
4548 * attribute or the one carried by the nearest ancestor.
4549 *
4550 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004551 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004552 */
4553xmlChar *
4554xmlNodeGetLang(xmlNodePtr cur) {
4555 xmlChar *lang;
4556
4557 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004558 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004559 if (lang != NULL)
4560 return(lang);
4561 cur = cur->parent;
4562 }
4563 return(NULL);
4564}
4565
4566
Daniel Veillard652327a2003-09-29 18:02:38 +00004567#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004568/**
4569 * xmlNodeSetSpacePreserve:
4570 * @cur: the node being changed
4571 * @val: the xml:space value ("0": default, 1: "preserve")
4572 *
4573 * Set (or reset) the space preserving behaviour of a node, i.e. the
4574 * value of the xml:space attribute.
4575 */
4576void
4577xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004578 xmlNsPtr ns;
4579
Owen Taylor3473f882001-02-23 17:55:21 +00004580 if (cur == NULL) return;
4581 switch(cur->type) {
4582 case XML_TEXT_NODE:
4583 case XML_CDATA_SECTION_NODE:
4584 case XML_COMMENT_NODE:
4585 case XML_DOCUMENT_NODE:
4586 case XML_DOCUMENT_TYPE_NODE:
4587 case XML_DOCUMENT_FRAG_NODE:
4588 case XML_NOTATION_NODE:
4589 case XML_HTML_DOCUMENT_NODE:
4590 case XML_DTD_NODE:
4591 case XML_ELEMENT_DECL:
4592 case XML_ATTRIBUTE_DECL:
4593 case XML_ENTITY_DECL:
4594 case XML_PI_NODE:
4595 case XML_ENTITY_REF_NODE:
4596 case XML_ENTITY_NODE:
4597 case XML_NAMESPACE_DECL:
4598 case XML_XINCLUDE_START:
4599 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004600#ifdef LIBXML_DOCB_ENABLED
4601 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004602#endif
4603 return;
4604 case XML_ELEMENT_NODE:
4605 case XML_ATTRIBUTE_NODE:
4606 break;
4607 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004608 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4609 if (ns == NULL)
4610 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004611 switch (val) {
4612 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004613 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004614 break;
4615 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004616 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004617 break;
4618 }
4619}
Daniel Veillard652327a2003-09-29 18:02:38 +00004620#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004621
4622/**
4623 * xmlNodeGetSpacePreserve:
4624 * @cur: the node being checked
4625 *
4626 * Searches the space preserving behaviour of a node, i.e. the values
4627 * of the xml:space attribute or the one carried by the nearest
4628 * ancestor.
4629 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004630 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004631 */
4632int
4633xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4634 xmlChar *space;
4635
4636 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004637 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004638 if (space != NULL) {
4639 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4640 xmlFree(space);
4641 return(1);
4642 }
4643 if (xmlStrEqual(space, BAD_CAST "default")) {
4644 xmlFree(space);
4645 return(0);
4646 }
4647 xmlFree(space);
4648 }
4649 cur = cur->parent;
4650 }
4651 return(-1);
4652}
4653
Daniel Veillard652327a2003-09-29 18:02:38 +00004654#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004655/**
4656 * xmlNodeSetName:
4657 * @cur: the node being changed
4658 * @name: the new tag name
4659 *
4660 * Set (or reset) the name of a node.
4661 */
4662void
4663xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4664 if (cur == NULL) return;
4665 if (name == NULL) return;
4666 switch(cur->type) {
4667 case XML_TEXT_NODE:
4668 case XML_CDATA_SECTION_NODE:
4669 case XML_COMMENT_NODE:
4670 case XML_DOCUMENT_TYPE_NODE:
4671 case XML_DOCUMENT_FRAG_NODE:
4672 case XML_NOTATION_NODE:
4673 case XML_HTML_DOCUMENT_NODE:
4674 case XML_NAMESPACE_DECL:
4675 case XML_XINCLUDE_START:
4676 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004677#ifdef LIBXML_DOCB_ENABLED
4678 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004679#endif
4680 return;
4681 case XML_ELEMENT_NODE:
4682 case XML_ATTRIBUTE_NODE:
4683 case XML_PI_NODE:
4684 case XML_ENTITY_REF_NODE:
4685 case XML_ENTITY_NODE:
4686 case XML_DTD_NODE:
4687 case XML_DOCUMENT_NODE:
4688 case XML_ELEMENT_DECL:
4689 case XML_ATTRIBUTE_DECL:
4690 case XML_ENTITY_DECL:
4691 break;
4692 }
4693 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4694 cur->name = xmlStrdup(name);
4695}
Daniel Veillard2156d432004-03-04 15:59:36 +00004696#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004697
Daniel Veillard2156d432004-03-04 15:59:36 +00004698#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004699/**
4700 * xmlNodeSetBase:
4701 * @cur: the node being changed
4702 * @uri: the new base URI
4703 *
4704 * Set (or reset) the base URI of a node, i.e. the value of the
4705 * xml:base attribute.
4706 */
4707void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004708xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004709 xmlNsPtr ns;
4710
Owen Taylor3473f882001-02-23 17:55:21 +00004711 if (cur == NULL) return;
4712 switch(cur->type) {
4713 case XML_TEXT_NODE:
4714 case XML_CDATA_SECTION_NODE:
4715 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004716 case XML_DOCUMENT_TYPE_NODE:
4717 case XML_DOCUMENT_FRAG_NODE:
4718 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004719 case XML_DTD_NODE:
4720 case XML_ELEMENT_DECL:
4721 case XML_ATTRIBUTE_DECL:
4722 case XML_ENTITY_DECL:
4723 case XML_PI_NODE:
4724 case XML_ENTITY_REF_NODE:
4725 case XML_ENTITY_NODE:
4726 case XML_NAMESPACE_DECL:
4727 case XML_XINCLUDE_START:
4728 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004729 return;
4730 case XML_ELEMENT_NODE:
4731 case XML_ATTRIBUTE_NODE:
4732 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004733 case XML_DOCUMENT_NODE:
4734#ifdef LIBXML_DOCB_ENABLED
4735 case XML_DOCB_DOCUMENT_NODE:
4736#endif
4737 case XML_HTML_DOCUMENT_NODE: {
4738 xmlDocPtr doc = (xmlDocPtr) cur;
4739
4740 if (doc->URL != NULL)
4741 xmlFree((xmlChar *) doc->URL);
4742 if (uri == NULL)
4743 doc->URL = NULL;
4744 else
4745 doc->URL = xmlStrdup(uri);
4746 return;
4747 }
Owen Taylor3473f882001-02-23 17:55:21 +00004748 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004749
4750 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4751 if (ns == NULL)
4752 return;
4753 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004754}
Daniel Veillard652327a2003-09-29 18:02:38 +00004755#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004756
4757/**
Owen Taylor3473f882001-02-23 17:55:21 +00004758 * xmlNodeGetBase:
4759 * @doc: the document the node pertains to
4760 * @cur: the node being checked
4761 *
4762 * Searches for the BASE URL. The code should work on both XML
4763 * and HTML document even if base mechanisms are completely different.
4764 * It returns the base as defined in RFC 2396 sections
4765 * 5.1.1. Base URI within Document Content
4766 * and
4767 * 5.1.2. Base URI from the Encapsulating Entity
4768 * However it does not return the document base (5.1.3), use
4769 * xmlDocumentGetBase() for this
4770 *
4771 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004772 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004773 */
4774xmlChar *
4775xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004776 xmlChar *oldbase = NULL;
4777 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004778
4779 if ((cur == NULL) && (doc == NULL))
4780 return(NULL);
4781 if (doc == NULL) doc = cur->doc;
4782 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4783 cur = doc->children;
4784 while ((cur != NULL) && (cur->name != NULL)) {
4785 if (cur->type != XML_ELEMENT_NODE) {
4786 cur = cur->next;
4787 continue;
4788 }
4789 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4790 cur = cur->children;
4791 continue;
4792 }
4793 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4794 cur = cur->children;
4795 continue;
4796 }
4797 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4798 return(xmlGetProp(cur, BAD_CAST "href"));
4799 }
4800 cur = cur->next;
4801 }
4802 return(NULL);
4803 }
4804 while (cur != NULL) {
4805 if (cur->type == XML_ENTITY_DECL) {
4806 xmlEntityPtr ent = (xmlEntityPtr) cur;
4807 return(xmlStrdup(ent->URI));
4808 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004809 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004810 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004811 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004812 if (oldbase != NULL) {
4813 newbase = xmlBuildURI(oldbase, base);
4814 if (newbase != NULL) {
4815 xmlFree(oldbase);
4816 xmlFree(base);
4817 oldbase = newbase;
4818 } else {
4819 xmlFree(oldbase);
4820 xmlFree(base);
4821 return(NULL);
4822 }
4823 } else {
4824 oldbase = base;
4825 }
4826 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4827 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4828 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4829 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004830 }
4831 }
Owen Taylor3473f882001-02-23 17:55:21 +00004832 cur = cur->parent;
4833 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004834 if ((doc != NULL) && (doc->URL != NULL)) {
4835 if (oldbase == NULL)
4836 return(xmlStrdup(doc->URL));
4837 newbase = xmlBuildURI(oldbase, doc->URL);
4838 xmlFree(oldbase);
4839 return(newbase);
4840 }
4841 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004842}
4843
4844/**
Daniel Veillard78697292003-10-19 20:44:43 +00004845 * xmlNodeBufGetContent:
4846 * @buffer: a buffer
4847 * @cur: the node being read
4848 *
4849 * Read the value of a node @cur, this can be either the text carried
4850 * directly by this node if it's a TEXT node or the aggregate string
4851 * of the values carried by this node child's (TEXT and ENTITY_REF).
4852 * Entity references are substituted.
4853 * Fills up the buffer @buffer with this value
4854 *
4855 * Returns 0 in case of success and -1 in case of error.
4856 */
4857int
4858xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4859{
4860 if ((cur == NULL) || (buffer == NULL)) return(-1);
4861 switch (cur->type) {
4862 case XML_CDATA_SECTION_NODE:
4863 case XML_TEXT_NODE:
4864 xmlBufferCat(buffer, cur->content);
4865 break;
4866 case XML_DOCUMENT_FRAG_NODE:
4867 case XML_ELEMENT_NODE:{
4868 xmlNodePtr tmp = cur;
4869
4870 while (tmp != NULL) {
4871 switch (tmp->type) {
4872 case XML_CDATA_SECTION_NODE:
4873 case XML_TEXT_NODE:
4874 if (tmp->content != NULL)
4875 xmlBufferCat(buffer, tmp->content);
4876 break;
4877 case XML_ENTITY_REF_NODE:
4878 xmlNodeBufGetContent(buffer, tmp->children);
4879 break;
4880 default:
4881 break;
4882 }
4883 /*
4884 * Skip to next node
4885 */
4886 if (tmp->children != NULL) {
4887 if (tmp->children->type != XML_ENTITY_DECL) {
4888 tmp = tmp->children;
4889 continue;
4890 }
4891 }
4892 if (tmp == cur)
4893 break;
4894
4895 if (tmp->next != NULL) {
4896 tmp = tmp->next;
4897 continue;
4898 }
4899
4900 do {
4901 tmp = tmp->parent;
4902 if (tmp == NULL)
4903 break;
4904 if (tmp == cur) {
4905 tmp = NULL;
4906 break;
4907 }
4908 if (tmp->next != NULL) {
4909 tmp = tmp->next;
4910 break;
4911 }
4912 } while (tmp != NULL);
4913 }
4914 break;
4915 }
4916 case XML_ATTRIBUTE_NODE:{
4917 xmlAttrPtr attr = (xmlAttrPtr) cur;
4918 xmlNodePtr tmp = attr->children;
4919
4920 while (tmp != NULL) {
4921 if (tmp->type == XML_TEXT_NODE)
4922 xmlBufferCat(buffer, tmp->content);
4923 else
4924 xmlNodeBufGetContent(buffer, tmp);
4925 tmp = tmp->next;
4926 }
4927 break;
4928 }
4929 case XML_COMMENT_NODE:
4930 case XML_PI_NODE:
4931 xmlBufferCat(buffer, cur->content);
4932 break;
4933 case XML_ENTITY_REF_NODE:{
4934 xmlEntityPtr ent;
4935 xmlNodePtr tmp;
4936
4937 /* lookup entity declaration */
4938 ent = xmlGetDocEntity(cur->doc, cur->name);
4939 if (ent == NULL)
4940 return(-1);
4941
4942 /* an entity content can be any "well balanced chunk",
4943 * i.e. the result of the content [43] production:
4944 * http://www.w3.org/TR/REC-xml#NT-content
4945 * -> we iterate through child nodes and recursive call
4946 * xmlNodeGetContent() which handles all possible node types */
4947 tmp = ent->children;
4948 while (tmp) {
4949 xmlNodeBufGetContent(buffer, tmp);
4950 tmp = tmp->next;
4951 }
4952 break;
4953 }
4954 case XML_ENTITY_NODE:
4955 case XML_DOCUMENT_TYPE_NODE:
4956 case XML_NOTATION_NODE:
4957 case XML_DTD_NODE:
4958 case XML_XINCLUDE_START:
4959 case XML_XINCLUDE_END:
4960 break;
4961 case XML_DOCUMENT_NODE:
4962#ifdef LIBXML_DOCB_ENABLED
4963 case XML_DOCB_DOCUMENT_NODE:
4964#endif
4965 case XML_HTML_DOCUMENT_NODE:
4966 cur = cur->children;
4967 while (cur!= NULL) {
4968 if ((cur->type == XML_ELEMENT_NODE) ||
4969 (cur->type == XML_TEXT_NODE) ||
4970 (cur->type == XML_CDATA_SECTION_NODE)) {
4971 xmlNodeBufGetContent(buffer, cur);
4972 }
4973 cur = cur->next;
4974 }
4975 break;
4976 case XML_NAMESPACE_DECL:
4977 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
4978 break;
4979 case XML_ELEMENT_DECL:
4980 case XML_ATTRIBUTE_DECL:
4981 case XML_ENTITY_DECL:
4982 break;
4983 }
4984 return(0);
4985}
4986/**
Owen Taylor3473f882001-02-23 17:55:21 +00004987 * xmlNodeGetContent:
4988 * @cur: the node being read
4989 *
4990 * Read the value of a node, this can be either the text carried
4991 * directly by this node if it's a TEXT node or the aggregate string
4992 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004993 * Entity references are substituted.
4994 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004995 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004996 */
4997xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004998xmlNodeGetContent(xmlNodePtr cur)
4999{
5000 if (cur == NULL)
5001 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005002 switch (cur->type) {
5003 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005004 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00005005 xmlBufferPtr buffer;
5006 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00005007
Daniel Veillard814a76d2003-01-23 18:24:20 +00005008 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00005009 if (buffer == NULL)
5010 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00005011 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005012 ret = buffer->content;
5013 buffer->content = NULL;
5014 xmlBufferFree(buffer);
5015 return (ret);
5016 }
5017 case XML_ATTRIBUTE_NODE:{
5018 xmlAttrPtr attr = (xmlAttrPtr) cur;
5019
5020 if (attr->parent != NULL)
5021 return (xmlNodeListGetString
5022 (attr->parent->doc, attr->children, 1));
5023 else
5024 return (xmlNodeListGetString(NULL, attr->children, 1));
5025 break;
5026 }
Owen Taylor3473f882001-02-23 17:55:21 +00005027 case XML_COMMENT_NODE:
5028 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005029 if (cur->content != NULL)
5030 return (xmlStrdup(cur->content));
5031 return (NULL);
5032 case XML_ENTITY_REF_NODE:{
5033 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00005034 xmlBufferPtr buffer;
5035 xmlChar *ret;
5036
5037 /* lookup entity declaration */
5038 ent = xmlGetDocEntity(cur->doc, cur->name);
5039 if (ent == NULL)
5040 return (NULL);
5041
5042 buffer = xmlBufferCreate();
5043 if (buffer == NULL)
5044 return (NULL);
5045
Daniel Veillardc4696922003-10-19 21:47:14 +00005046 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005047
5048 ret = buffer->content;
5049 buffer->content = NULL;
5050 xmlBufferFree(buffer);
5051 return (ret);
5052 }
Owen Taylor3473f882001-02-23 17:55:21 +00005053 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005054 case XML_DOCUMENT_TYPE_NODE:
5055 case XML_NOTATION_NODE:
5056 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005057 case XML_XINCLUDE_START:
5058 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00005059 return (NULL);
5060 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005061#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005062 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005063#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005064 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00005065 xmlBufferPtr buffer;
5066 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005067
Daniel Veillardc4696922003-10-19 21:47:14 +00005068 buffer = xmlBufferCreate();
5069 if (buffer == NULL)
5070 return (NULL);
5071
5072 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5073
5074 ret = buffer->content;
5075 buffer->content = NULL;
5076 xmlBufferFree(buffer);
5077 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005078 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005079 case XML_NAMESPACE_DECL: {
5080 xmlChar *tmp;
5081
5082 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5083 return (tmp);
5084 }
Owen Taylor3473f882001-02-23 17:55:21 +00005085 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005086 /* TODO !!! */
5087 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005088 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005089 /* TODO !!! */
5090 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005091 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005092 /* TODO !!! */
5093 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005094 case XML_CDATA_SECTION_NODE:
5095 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005096 if (cur->content != NULL)
5097 return (xmlStrdup(cur->content));
5098 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005099 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005100 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005101}
Daniel Veillard652327a2003-09-29 18:02:38 +00005102
Owen Taylor3473f882001-02-23 17:55:21 +00005103/**
5104 * xmlNodeSetContent:
5105 * @cur: the node being modified
5106 * @content: the new value of the content
5107 *
5108 * Replace the content of a node.
5109 */
5110void
5111xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5112 if (cur == NULL) {
5113#ifdef DEBUG_TREE
5114 xmlGenericError(xmlGenericErrorContext,
5115 "xmlNodeSetContent : node == NULL\n");
5116#endif
5117 return;
5118 }
5119 switch (cur->type) {
5120 case XML_DOCUMENT_FRAG_NODE:
5121 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005122 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005123 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5124 cur->children = xmlStringGetNodeList(cur->doc, content);
5125 UPDATE_LAST_CHILD_AND_PARENT(cur)
5126 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005127 case XML_TEXT_NODE:
5128 case XML_CDATA_SECTION_NODE:
5129 case XML_ENTITY_REF_NODE:
5130 case XML_ENTITY_NODE:
5131 case XML_PI_NODE:
5132 case XML_COMMENT_NODE:
5133 if (cur->content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005134 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
Daniel Veillard370ba3d2004-10-25 16:23:56 +00005135 (!xmlDictOwns(cur->doc->dict, cur->content))))
William M. Brack7762bb12004-01-04 14:49:01 +00005136 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005137 }
5138 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5139 cur->last = cur->children = NULL;
5140 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005141 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005142 } else
5143 cur->content = NULL;
5144 break;
5145 case XML_DOCUMENT_NODE:
5146 case XML_HTML_DOCUMENT_NODE:
5147 case XML_DOCUMENT_TYPE_NODE:
5148 case XML_XINCLUDE_START:
5149 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005150#ifdef LIBXML_DOCB_ENABLED
5151 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005152#endif
5153 break;
5154 case XML_NOTATION_NODE:
5155 break;
5156 case XML_DTD_NODE:
5157 break;
5158 case XML_NAMESPACE_DECL:
5159 break;
5160 case XML_ELEMENT_DECL:
5161 /* TODO !!! */
5162 break;
5163 case XML_ATTRIBUTE_DECL:
5164 /* TODO !!! */
5165 break;
5166 case XML_ENTITY_DECL:
5167 /* TODO !!! */
5168 break;
5169 }
5170}
5171
Daniel Veillard652327a2003-09-29 18:02:38 +00005172#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005173/**
5174 * xmlNodeSetContentLen:
5175 * @cur: the node being modified
5176 * @content: the new value of the content
5177 * @len: the size of @content
5178 *
5179 * Replace the content of a node.
5180 */
5181void
5182xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5183 if (cur == NULL) {
5184#ifdef DEBUG_TREE
5185 xmlGenericError(xmlGenericErrorContext,
5186 "xmlNodeSetContentLen : node == NULL\n");
5187#endif
5188 return;
5189 }
5190 switch (cur->type) {
5191 case XML_DOCUMENT_FRAG_NODE:
5192 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005193 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005194 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5195 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5196 UPDATE_LAST_CHILD_AND_PARENT(cur)
5197 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005198 case XML_TEXT_NODE:
5199 case XML_CDATA_SECTION_NODE:
5200 case XML_ENTITY_REF_NODE:
5201 case XML_ENTITY_NODE:
5202 case XML_PI_NODE:
5203 case XML_COMMENT_NODE:
5204 case XML_NOTATION_NODE:
5205 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005206 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005207 }
5208 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5209 cur->children = cur->last = NULL;
5210 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005211 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005212 } else
5213 cur->content = NULL;
5214 break;
5215 case XML_DOCUMENT_NODE:
5216 case XML_DTD_NODE:
5217 case XML_HTML_DOCUMENT_NODE:
5218 case XML_DOCUMENT_TYPE_NODE:
5219 case XML_NAMESPACE_DECL:
5220 case XML_XINCLUDE_START:
5221 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005222#ifdef LIBXML_DOCB_ENABLED
5223 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005224#endif
5225 break;
5226 case XML_ELEMENT_DECL:
5227 /* TODO !!! */
5228 break;
5229 case XML_ATTRIBUTE_DECL:
5230 /* TODO !!! */
5231 break;
5232 case XML_ENTITY_DECL:
5233 /* TODO !!! */
5234 break;
5235 }
5236}
Daniel Veillard652327a2003-09-29 18:02:38 +00005237#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005238
5239/**
5240 * xmlNodeAddContentLen:
5241 * @cur: the node being modified
5242 * @content: extra content
5243 * @len: the size of @content
5244 *
5245 * Append the extra substring to the node content.
5246 */
5247void
5248xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5249 if (cur == NULL) {
5250#ifdef DEBUG_TREE
5251 xmlGenericError(xmlGenericErrorContext,
5252 "xmlNodeAddContentLen : node == NULL\n");
5253#endif
5254 return;
5255 }
5256 if (len <= 0) return;
5257 switch (cur->type) {
5258 case XML_DOCUMENT_FRAG_NODE:
5259 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005260 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005261
Daniel Veillard7db37732001-07-12 01:20:08 +00005262 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005263 newNode = xmlNewTextLen(content, len);
5264 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005265 tmp = xmlAddChild(cur, newNode);
5266 if (tmp != newNode)
5267 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005268 if ((last != NULL) && (last->next == newNode)) {
5269 xmlTextMerge(last, newNode);
5270 }
5271 }
5272 break;
5273 }
5274 case XML_ATTRIBUTE_NODE:
5275 break;
5276 case XML_TEXT_NODE:
5277 case XML_CDATA_SECTION_NODE:
5278 case XML_ENTITY_REF_NODE:
5279 case XML_ENTITY_NODE:
5280 case XML_PI_NODE:
5281 case XML_COMMENT_NODE:
5282 case XML_NOTATION_NODE:
5283 if (content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005284 if ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5285 xmlDictOwns(cur->doc->dict, cur->content)) {
5286 cur->content =
5287 xmlStrncatNew(cur->content, content, len);
5288 break;
5289 }
Owen Taylor3473f882001-02-23 17:55:21 +00005290 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005291 }
5292 case XML_DOCUMENT_NODE:
5293 case XML_DTD_NODE:
5294 case XML_HTML_DOCUMENT_NODE:
5295 case XML_DOCUMENT_TYPE_NODE:
5296 case XML_NAMESPACE_DECL:
5297 case XML_XINCLUDE_START:
5298 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005299#ifdef LIBXML_DOCB_ENABLED
5300 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005301#endif
5302 break;
5303 case XML_ELEMENT_DECL:
5304 case XML_ATTRIBUTE_DECL:
5305 case XML_ENTITY_DECL:
5306 break;
5307 }
5308}
5309
5310/**
5311 * xmlNodeAddContent:
5312 * @cur: the node being modified
5313 * @content: extra content
5314 *
5315 * Append the extra substring to the node content.
5316 */
5317void
5318xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5319 int len;
5320
5321 if (cur == NULL) {
5322#ifdef DEBUG_TREE
5323 xmlGenericError(xmlGenericErrorContext,
5324 "xmlNodeAddContent : node == NULL\n");
5325#endif
5326 return;
5327 }
5328 if (content == NULL) return;
5329 len = xmlStrlen(content);
5330 xmlNodeAddContentLen(cur, content, len);
5331}
5332
5333/**
5334 * xmlTextMerge:
5335 * @first: the first text node
5336 * @second: the second text node being merged
5337 *
5338 * Merge two text nodes into one
5339 * Returns the first text node augmented
5340 */
5341xmlNodePtr
5342xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5343 if (first == NULL) return(second);
5344 if (second == NULL) return(first);
5345 if (first->type != XML_TEXT_NODE) return(first);
5346 if (second->type != XML_TEXT_NODE) return(first);
5347 if (second->name != first->name)
5348 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005349 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005350 xmlUnlinkNode(second);
5351 xmlFreeNode(second);
5352 return(first);
5353}
5354
Daniel Veillard2156d432004-03-04 15:59:36 +00005355#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005356/**
5357 * xmlGetNsList:
5358 * @doc: the document
5359 * @node: the current node
5360 *
5361 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005362 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005363 * that need to be freed by the caller or NULL if no
5364 * namespace if defined
5365 */
5366xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005367xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5368{
Owen Taylor3473f882001-02-23 17:55:21 +00005369 xmlNsPtr cur;
5370 xmlNsPtr *ret = NULL;
5371 int nbns = 0;
5372 int maxns = 10;
5373 int i;
5374
5375 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005376 if (node->type == XML_ELEMENT_NODE) {
5377 cur = node->nsDef;
5378 while (cur != NULL) {
5379 if (ret == NULL) {
5380 ret =
5381 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5382 sizeof(xmlNsPtr));
5383 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005384 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005385 return (NULL);
5386 }
5387 ret[nbns] = NULL;
5388 }
5389 for (i = 0; i < nbns; i++) {
5390 if ((cur->prefix == ret[i]->prefix) ||
5391 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5392 break;
5393 }
5394 if (i >= nbns) {
5395 if (nbns >= maxns) {
5396 maxns *= 2;
5397 ret = (xmlNsPtr *) xmlRealloc(ret,
5398 (maxns +
5399 1) *
5400 sizeof(xmlNsPtr));
5401 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005402 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005403 return (NULL);
5404 }
5405 }
5406 ret[nbns++] = cur;
5407 ret[nbns] = NULL;
5408 }
Owen Taylor3473f882001-02-23 17:55:21 +00005409
Daniel Veillard77044732001-06-29 21:31:07 +00005410 cur = cur->next;
5411 }
5412 }
5413 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005414 }
Daniel Veillard77044732001-06-29 21:31:07 +00005415 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005416}
Daniel Veillard652327a2003-09-29 18:02:38 +00005417#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005418
5419/**
5420 * xmlSearchNs:
5421 * @doc: the document
5422 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005423 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005424 *
5425 * Search a Ns registered under a given name space for a document.
5426 * recurse on the parents until it finds the defined namespace
5427 * or return NULL otherwise.
5428 * @nameSpace can be NULL, this is a search for the default namespace.
5429 * We don't allow to cross entities boundaries. If you don't declare
5430 * the namespace within those you will be in troubles !!! A warning
5431 * is generated to cover this case.
5432 *
5433 * Returns the namespace pointer or NULL.
5434 */
5435xmlNsPtr
5436xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005437
Owen Taylor3473f882001-02-23 17:55:21 +00005438 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005439 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005440
5441 if (node == NULL) return(NULL);
5442 if ((nameSpace != NULL) &&
5443 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005444 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5445 /*
5446 * The XML-1.0 namespace is normally held on the root
5447 * element. In this case exceptionally create it on the
5448 * node element.
5449 */
5450 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5451 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005452 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005453 return(NULL);
5454 }
5455 memset(cur, 0, sizeof(xmlNs));
5456 cur->type = XML_LOCAL_NAMESPACE;
5457 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5458 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5459 cur->next = node->nsDef;
5460 node->nsDef = cur;
5461 return(cur);
5462 }
Owen Taylor3473f882001-02-23 17:55:21 +00005463 if (doc->oldNs == NULL) {
5464 /*
5465 * Allocate a new Namespace and fill the fields.
5466 */
5467 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5468 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005469 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005470 return(NULL);
5471 }
5472 memset(doc->oldNs, 0, sizeof(xmlNs));
5473 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5474
5475 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5476 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5477 }
5478 return(doc->oldNs);
5479 }
5480 while (node != NULL) {
5481 if ((node->type == XML_ENTITY_REF_NODE) ||
5482 (node->type == XML_ENTITY_NODE) ||
5483 (node->type == XML_ENTITY_DECL))
5484 return(NULL);
5485 if (node->type == XML_ELEMENT_NODE) {
5486 cur = node->nsDef;
5487 while (cur != NULL) {
5488 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5489 (cur->href != NULL))
5490 return(cur);
5491 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5492 (cur->href != NULL) &&
5493 (xmlStrEqual(cur->prefix, nameSpace)))
5494 return(cur);
5495 cur = cur->next;
5496 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005497 if (orig != node) {
5498 cur = node->ns;
5499 if (cur != NULL) {
5500 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5501 (cur->href != NULL))
5502 return(cur);
5503 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5504 (cur->href != NULL) &&
5505 (xmlStrEqual(cur->prefix, nameSpace)))
5506 return(cur);
5507 }
5508 }
Owen Taylor3473f882001-02-23 17:55:21 +00005509 }
5510 node = node->parent;
5511 }
5512 return(NULL);
5513}
5514
5515/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005516 * xmlNsInScope:
5517 * @doc: the document
5518 * @node: the current node
5519 * @ancestor: the ancestor carrying the namespace
5520 * @prefix: the namespace prefix
5521 *
5522 * Verify that the given namespace held on @ancestor is still in scope
5523 * on node.
5524 *
5525 * Returns 1 if true, 0 if false and -1 in case of error.
5526 */
5527static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005528xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5529 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005530{
5531 xmlNsPtr tst;
5532
5533 while ((node != NULL) && (node != ancestor)) {
5534 if ((node->type == XML_ENTITY_REF_NODE) ||
5535 (node->type == XML_ENTITY_NODE) ||
5536 (node->type == XML_ENTITY_DECL))
5537 return (-1);
5538 if (node->type == XML_ELEMENT_NODE) {
5539 tst = node->nsDef;
5540 while (tst != NULL) {
5541 if ((tst->prefix == NULL)
5542 && (prefix == NULL))
5543 return (0);
5544 if ((tst->prefix != NULL)
5545 && (prefix != NULL)
5546 && (xmlStrEqual(tst->prefix, prefix)))
5547 return (0);
5548 tst = tst->next;
5549 }
5550 }
5551 node = node->parent;
5552 }
5553 if (node != ancestor)
5554 return (-1);
5555 return (1);
5556}
5557
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005558/**
Owen Taylor3473f882001-02-23 17:55:21 +00005559 * xmlSearchNsByHref:
5560 * @doc: the document
5561 * @node: the current node
5562 * @href: the namespace value
5563 *
5564 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5565 * the defined namespace or return NULL otherwise.
5566 * Returns the namespace pointer or NULL.
5567 */
5568xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005569xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5570{
Owen Taylor3473f882001-02-23 17:55:21 +00005571 xmlNsPtr cur;
5572 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005573 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005574
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005575 if ((node == NULL) || (href == NULL))
5576 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005577 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005578 /*
5579 * Only the document can hold the XML spec namespace.
5580 */
5581 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5582 /*
5583 * The XML-1.0 namespace is normally held on the root
5584 * element. In this case exceptionally create it on the
5585 * node element.
5586 */
5587 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5588 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005589 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005590 return (NULL);
5591 }
5592 memset(cur, 0, sizeof(xmlNs));
5593 cur->type = XML_LOCAL_NAMESPACE;
5594 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5595 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5596 cur->next = node->nsDef;
5597 node->nsDef = cur;
5598 return (cur);
5599 }
5600 if (doc->oldNs == NULL) {
5601 /*
5602 * Allocate a new Namespace and fill the fields.
5603 */
5604 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5605 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005606 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005607 return (NULL);
5608 }
5609 memset(doc->oldNs, 0, sizeof(xmlNs));
5610 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005611
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005612 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5613 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5614 }
5615 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005616 }
Daniel Veillard62040be2004-05-17 03:17:26 +00005617 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00005618 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005619 if ((node->type == XML_ENTITY_REF_NODE) ||
5620 (node->type == XML_ENTITY_NODE) ||
5621 (node->type == XML_ENTITY_DECL))
5622 return (NULL);
5623 if (node->type == XML_ELEMENT_NODE) {
5624 cur = node->nsDef;
5625 while (cur != NULL) {
5626 if ((cur->href != NULL) && (href != NULL) &&
5627 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005628 if (((!is_attr) || (cur->prefix != NULL)) &&
5629 (xmlNsInScope(doc, orig, node, cur->href) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005630 return (cur);
5631 }
5632 cur = cur->next;
5633 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005634 if (orig != node) {
5635 cur = node->ns;
5636 if (cur != NULL) {
5637 if ((cur->href != NULL) && (href != NULL) &&
5638 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005639 if (((!is_attr) || (cur->prefix != NULL)) &&
5640 (xmlNsInScope(doc, orig, node, cur->href) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00005641 return (cur);
5642 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005643 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005644 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005645 }
5646 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005647 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005648 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005649}
5650
5651/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005652 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005653 * @doc: the document
5654 * @tree: a node expected to hold the new namespace
5655 * @ns: the original namespace
5656 *
5657 * This function tries to locate a namespace definition in a tree
5658 * ancestors, or create a new namespace definition node similar to
5659 * @ns trying to reuse the same prefix. However if the given prefix is
5660 * null (default namespace) or reused within the subtree defined by
5661 * @tree or on one of its ancestors then a new prefix is generated.
5662 * Returns the (new) namespace definition or NULL in case of error
5663 */
5664xmlNsPtr
5665xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5666 xmlNsPtr def;
5667 xmlChar prefix[50];
5668 int counter = 1;
5669
5670 if (tree == NULL) {
5671#ifdef DEBUG_TREE
5672 xmlGenericError(xmlGenericErrorContext,
5673 "xmlNewReconciliedNs : tree == NULL\n");
5674#endif
5675 return(NULL);
5676 }
5677 if (ns == NULL) {
5678#ifdef DEBUG_TREE
5679 xmlGenericError(xmlGenericErrorContext,
5680 "xmlNewReconciliedNs : ns == NULL\n");
5681#endif
5682 return(NULL);
5683 }
5684 /*
5685 * Search an existing namespace definition inherited.
5686 */
5687 def = xmlSearchNsByHref(doc, tree, ns->href);
5688 if (def != NULL)
5689 return(def);
5690
5691 /*
5692 * Find a close prefix which is not already in use.
5693 * Let's strip namespace prefixes longer than 20 chars !
5694 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005695 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005696 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005697 else
William M. Brack13dfa872004-09-18 04:52:08 +00005698 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005699
Owen Taylor3473f882001-02-23 17:55:21 +00005700 def = xmlSearchNs(doc, tree, prefix);
5701 while (def != NULL) {
5702 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005703 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005704 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005705 else
William M. Brack13dfa872004-09-18 04:52:08 +00005706 snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
5707 (char *)ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005708 def = xmlSearchNs(doc, tree, prefix);
5709 }
5710
5711 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005712 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005713 */
5714 def = xmlNewNs(tree, ns->href, prefix);
5715 return(def);
5716}
5717
Daniel Veillard652327a2003-09-29 18:02:38 +00005718#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005719/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005720 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005721 * @doc: the document
5722 * @tree: a node defining the subtree to reconciliate
5723 *
5724 * This function checks that all the namespaces declared within the given
5725 * tree are properly declared. This is needed for example after Copy or Cut
5726 * and then paste operations. The subtree may still hold pointers to
5727 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005728 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005729 * the new environment. If not possible the new namespaces are redeclared
5730 * on @tree at the top of the given subtree.
5731 * Returns the number of namespace declarations created or -1 in case of error.
5732 */
5733int
5734xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5735 xmlNsPtr *oldNs = NULL;
5736 xmlNsPtr *newNs = NULL;
5737 int sizeCache = 0;
5738 int nbCache = 0;
5739
5740 xmlNsPtr n;
5741 xmlNodePtr node = tree;
5742 xmlAttrPtr attr;
5743 int ret = 0, i;
5744
5745 while (node != NULL) {
5746 /*
5747 * Reconciliate the node namespace
5748 */
5749 if (node->ns != NULL) {
5750 /*
5751 * initialize the cache if needed
5752 */
5753 if (sizeCache == 0) {
5754 sizeCache = 10;
5755 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5756 sizeof(xmlNsPtr));
5757 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005758 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005759 return(-1);
5760 }
5761 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5762 sizeof(xmlNsPtr));
5763 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005764 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005765 xmlFree(oldNs);
5766 return(-1);
5767 }
5768 }
5769 for (i = 0;i < nbCache;i++) {
5770 if (oldNs[i] == node->ns) {
5771 node->ns = newNs[i];
5772 break;
5773 }
5774 }
5775 if (i == nbCache) {
5776 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005777 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005778 */
5779 n = xmlNewReconciliedNs(doc, tree, node->ns);
5780 if (n != NULL) { /* :-( what if else ??? */
5781 /*
5782 * check if we need to grow the cache buffers.
5783 */
5784 if (sizeCache <= nbCache) {
5785 sizeCache *= 2;
5786 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5787 sizeof(xmlNsPtr));
5788 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005789 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005790 xmlFree(newNs);
5791 return(-1);
5792 }
5793 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5794 sizeof(xmlNsPtr));
5795 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005796 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005797 xmlFree(oldNs);
5798 return(-1);
5799 }
5800 }
5801 newNs[nbCache] = n;
5802 oldNs[nbCache++] = node->ns;
5803 node->ns = n;
5804 }
5805 }
5806 }
5807 /*
5808 * now check for namespace hold by attributes on the node.
5809 */
5810 attr = node->properties;
5811 while (attr != NULL) {
5812 if (attr->ns != NULL) {
5813 /*
5814 * initialize the cache if needed
5815 */
5816 if (sizeCache == 0) {
5817 sizeCache = 10;
5818 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5819 sizeof(xmlNsPtr));
5820 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005821 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005822 return(-1);
5823 }
5824 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5825 sizeof(xmlNsPtr));
5826 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005827 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005828 xmlFree(oldNs);
5829 return(-1);
5830 }
5831 }
5832 for (i = 0;i < nbCache;i++) {
5833 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005834 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005835 break;
5836 }
5837 }
5838 if (i == nbCache) {
5839 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005840 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005841 */
5842 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5843 if (n != NULL) { /* :-( what if else ??? */
5844 /*
5845 * check if we need to grow the cache buffers.
5846 */
5847 if (sizeCache <= nbCache) {
5848 sizeCache *= 2;
5849 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5850 sizeof(xmlNsPtr));
5851 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005852 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005853 xmlFree(newNs);
5854 return(-1);
5855 }
5856 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5857 sizeof(xmlNsPtr));
5858 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005859 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005860 xmlFree(oldNs);
5861 return(-1);
5862 }
5863 }
5864 newNs[nbCache] = n;
5865 oldNs[nbCache++] = attr->ns;
5866 attr->ns = n;
5867 }
5868 }
5869 }
5870 attr = attr->next;
5871 }
5872
5873 /*
5874 * Browse the full subtree, deep first
5875 */
Daniel Veillardac996a12004-07-30 12:02:58 +00005876 if (node->children != NULL && node->type != XML_ENTITY_REF_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00005877 /* deep first */
5878 node = node->children;
5879 } else if ((node != tree) && (node->next != NULL)) {
5880 /* then siblings */
5881 node = node->next;
5882 } else if (node != tree) {
5883 /* go up to parents->next if needed */
5884 while (node != tree) {
5885 if (node->parent != NULL)
5886 node = node->parent;
5887 if ((node != tree) && (node->next != NULL)) {
5888 node = node->next;
5889 break;
5890 }
5891 if (node->parent == NULL) {
5892 node = NULL;
5893 break;
5894 }
5895 }
5896 /* exit condition */
5897 if (node == tree)
5898 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005899 } else
5900 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005901 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005902 if (oldNs != NULL)
5903 xmlFree(oldNs);
5904 if (newNs != NULL)
5905 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005906 return(ret);
5907}
Daniel Veillard652327a2003-09-29 18:02:38 +00005908#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005909
5910/**
5911 * xmlHasProp:
5912 * @node: the node
5913 * @name: the attribute name
5914 *
5915 * Search an attribute associated to a node
5916 * This function also looks in DTD attribute declaration for #FIXED or
5917 * default declaration values unless DTD use has been turned off.
5918 *
5919 * Returns the attribute or the attribute declaration or NULL if
5920 * neither was found.
5921 */
5922xmlAttrPtr
5923xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5924 xmlAttrPtr prop;
5925 xmlDocPtr doc;
5926
5927 if ((node == NULL) || (name == NULL)) return(NULL);
5928 /*
5929 * Check on the properties attached to the node
5930 */
5931 prop = node->properties;
5932 while (prop != NULL) {
5933 if (xmlStrEqual(prop->name, name)) {
5934 return(prop);
5935 }
5936 prop = prop->next;
5937 }
5938 if (!xmlCheckDTD) return(NULL);
5939
5940 /*
5941 * Check if there is a default declaration in the internal
5942 * or external subsets
5943 */
5944 doc = node->doc;
5945 if (doc != NULL) {
5946 xmlAttributePtr attrDecl;
5947 if (doc->intSubset != NULL) {
5948 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5949 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5950 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005951 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5952 /* return attribute declaration only if a default value is given
5953 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005954 return((xmlAttrPtr) attrDecl);
5955 }
5956 }
5957 return(NULL);
5958}
5959
5960/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005961 * xmlHasNsProp:
5962 * @node: the node
5963 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005964 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005965 *
5966 * Search for an attribute associated to a node
5967 * This attribute has to be anchored in the namespace specified.
5968 * This does the entity substitution.
5969 * This function looks in DTD attribute declaration for #FIXED or
5970 * default declaration values unless DTD use has been turned off.
William M. Brack2c228442004-10-03 04:10:00 +00005971 * Note that a namespace of NULL indicates to use the default namespace.
Daniel Veillarde95e2392001-06-06 10:46:28 +00005972 *
5973 * Returns the attribute or the attribute declaration or NULL
5974 * if neither was found.
5975 */
5976xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005977xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005978 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00005979#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005980 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00005981#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005982
5983 if (node == NULL)
5984 return(NULL);
5985
5986 prop = node->properties;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005987 while (prop != NULL) {
5988 /*
5989 * One need to have
5990 * - same attribute names
5991 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005992 */
William M. Brack2c228442004-10-03 04:10:00 +00005993 if (xmlStrEqual(prop->name, name)) {
5994 if (((prop->ns != NULL) &&
5995 (xmlStrEqual(prop->ns->href, nameSpace))) ||
5996 ((prop->ns == NULL) && (nameSpace == NULL))) {
5997 return(prop);
5998 }
Daniel Veillarde95e2392001-06-06 10:46:28 +00005999 }
6000 prop = prop->next;
6001 }
6002 if (!xmlCheckDTD) return(NULL);
6003
Daniel Veillard652327a2003-09-29 18:02:38 +00006004#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00006005 /*
6006 * Check if there is a default declaration in the internal
6007 * or external subsets
6008 */
6009 doc = node->doc;
6010 if (doc != NULL) {
6011 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006012 xmlAttributePtr attrDecl = NULL;
6013 xmlNsPtr *nsList, *cur;
6014 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00006015
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006016 nsList = xmlGetNsList(node->doc, node);
6017 if (nsList == NULL)
6018 return(NULL);
6019 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
6020 ename = xmlStrdup(node->ns->prefix);
6021 ename = xmlStrcat(ename, BAD_CAST ":");
6022 ename = xmlStrcat(ename, node->name);
6023 } else {
6024 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006025 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006026 if (ename == NULL) {
6027 xmlFree(nsList);
6028 return(NULL);
6029 }
6030
William M. Brack2c228442004-10-03 04:10:00 +00006031 if (nameSpace == NULL) {
6032 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
6033 name, NULL);
6034 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
6035 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6036 name, NULL);
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006037 }
William M. Brack2c228442004-10-03 04:10:00 +00006038 } else {
6039 cur = nsList;
6040 while (*cur != NULL) {
6041 if (xmlStrEqual((*cur)->href, nameSpace)) {
6042 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
6043 name, (*cur)->prefix);
6044 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6045 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6046 name, (*cur)->prefix);
6047 }
6048 cur++;
6049 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006050 }
6051 xmlFree(nsList);
6052 xmlFree(ename);
6053 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006054 }
6055 }
Daniel Veillard652327a2003-09-29 18:02:38 +00006056#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00006057 return(NULL);
6058}
6059
6060/**
Owen Taylor3473f882001-02-23 17:55:21 +00006061 * xmlGetProp:
6062 * @node: the node
6063 * @name: the attribute name
6064 *
6065 * Search and get the value of an attribute associated to a node
6066 * This does the entity substitution.
6067 * This function looks in DTD attribute declaration for #FIXED or
6068 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00006069 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00006070 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6071 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00006072 *
6073 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006074 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006075 */
6076xmlChar *
6077xmlGetProp(xmlNodePtr node, const xmlChar *name) {
6078 xmlAttrPtr prop;
6079 xmlDocPtr doc;
6080
6081 if ((node == NULL) || (name == NULL)) return(NULL);
6082 /*
6083 * Check on the properties attached to the node
6084 */
6085 prop = node->properties;
6086 while (prop != NULL) {
6087 if (xmlStrEqual(prop->name, name)) {
6088 xmlChar *ret;
6089
6090 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6091 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6092 return(ret);
6093 }
6094 prop = prop->next;
6095 }
6096 if (!xmlCheckDTD) return(NULL);
6097
6098 /*
6099 * Check if there is a default declaration in the internal
6100 * or external subsets
6101 */
6102 doc = node->doc;
6103 if (doc != NULL) {
6104 xmlAttributePtr attrDecl;
6105 if (doc->intSubset != NULL) {
6106 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6107 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6108 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006109 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6110 /* return attribute declaration only if a default value is given
6111 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006112 return(xmlStrdup(attrDecl->defaultValue));
6113 }
6114 }
6115 return(NULL);
6116}
6117
6118/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006119 * xmlGetNoNsProp:
6120 * @node: the node
6121 * @name: the attribute name
6122 *
6123 * Search and get the value of an attribute associated to a node
6124 * This does the entity substitution.
6125 * This function looks in DTD attribute declaration for #FIXED or
6126 * default declaration values unless DTD use has been turned off.
6127 * This function is similar to xmlGetProp except it will accept only
6128 * an attribute in no namespace.
6129 *
6130 * Returns the attribute value or NULL if not found.
6131 * It's up to the caller to free the memory with xmlFree().
6132 */
6133xmlChar *
6134xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6135 xmlAttrPtr prop;
6136 xmlDocPtr doc;
6137
6138 if ((node == NULL) || (name == NULL)) return(NULL);
6139 /*
6140 * Check on the properties attached to the node
6141 */
6142 prop = node->properties;
6143 while (prop != NULL) {
6144 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6145 xmlChar *ret;
6146
6147 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6148 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6149 return(ret);
6150 }
6151 prop = prop->next;
6152 }
6153 if (!xmlCheckDTD) return(NULL);
6154
6155 /*
6156 * Check if there is a default declaration in the internal
6157 * or external subsets
6158 */
6159 doc = node->doc;
6160 if (doc != NULL) {
6161 xmlAttributePtr attrDecl;
6162 if (doc->intSubset != NULL) {
6163 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6164 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6165 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006166 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6167 /* return attribute declaration only if a default value is given
6168 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006169 return(xmlStrdup(attrDecl->defaultValue));
6170 }
6171 }
6172 return(NULL);
6173}
6174
6175/**
Owen Taylor3473f882001-02-23 17:55:21 +00006176 * xmlGetNsProp:
6177 * @node: the node
6178 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006179 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006180 *
6181 * Search and get the value of an attribute associated to a node
6182 * This attribute has to be anchored in the namespace specified.
6183 * This does the entity substitution.
6184 * This function looks in DTD attribute declaration for #FIXED or
6185 * default declaration values unless DTD use has been turned off.
6186 *
6187 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006188 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006189 */
6190xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006191xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006192 xmlAttrPtr prop;
6193 xmlDocPtr doc;
6194 xmlNsPtr ns;
6195
6196 if (node == NULL)
6197 return(NULL);
6198
6199 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006200 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006201 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006202 while (prop != NULL) {
6203 /*
6204 * One need to have
6205 * - same attribute names
6206 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006207 */
6208 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006209 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006210 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006211 xmlChar *ret;
6212
6213 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6214 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6215 return(ret);
6216 }
6217 prop = prop->next;
6218 }
6219 if (!xmlCheckDTD) return(NULL);
6220
6221 /*
6222 * Check if there is a default declaration in the internal
6223 * or external subsets
6224 */
6225 doc = node->doc;
6226 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006227 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006228 xmlAttributePtr attrDecl;
6229
Owen Taylor3473f882001-02-23 17:55:21 +00006230 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6231 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6232 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6233
6234 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6235 /*
6236 * The DTD declaration only allows a prefix search
6237 */
6238 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006239 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006240 return(xmlStrdup(attrDecl->defaultValue));
6241 }
6242 }
6243 }
6244 return(NULL);
6245}
6246
Daniel Veillard2156d432004-03-04 15:59:36 +00006247#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6248/**
6249 * xmlUnsetProp:
6250 * @node: the node
6251 * @name: the attribute name
6252 *
6253 * Remove an attribute carried by a node.
6254 * Returns 0 if successful, -1 if not found
6255 */
6256int
6257xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
6258 xmlAttrPtr prop, prev = NULL;;
6259
6260 if ((node == NULL) || (name == NULL))
6261 return(-1);
6262 prop = node->properties;
6263 while (prop != NULL) {
6264 if ((xmlStrEqual(prop->name, name)) &&
6265 (prop->ns == NULL)) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006266 if (prev == NULL) {
Daniel Veillard2156d432004-03-04 15:59:36 +00006267 node->properties = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006268 if (prop->next != NULL)
6269 prop->next->prev = NULL;
6270 } else {
Daniel Veillard2156d432004-03-04 15:59:36 +00006271 prev->next = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006272 if (prop->next != NULL)
6273 prop->next->prev = NULL;
6274 }
6275 prop->next = NULL;
6276 prop->prev = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00006277 xmlFreeProp(prop);
6278 return(0);
6279 }
6280 prev = prop;
6281 prop = prop->next;
6282 }
6283 return(-1);
6284}
6285
6286/**
6287 * xmlUnsetNsProp:
6288 * @node: the node
6289 * @ns: the namespace definition
6290 * @name: the attribute name
6291 *
6292 * Remove an attribute carried by a node.
6293 * Returns 0 if successful, -1 if not found
6294 */
6295int
6296xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6297 xmlAttrPtr prop = node->properties, prev = NULL;;
6298
6299 if ((node == NULL) || (name == NULL))
6300 return(-1);
6301 if (ns == NULL)
6302 return(xmlUnsetProp(node, name));
6303 if (ns->href == NULL)
6304 return(-1);
6305 while (prop != NULL) {
6306 if ((xmlStrEqual(prop->name, name)) &&
6307 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006308 if (prev == NULL) {
Daniel Veillard2156d432004-03-04 15:59:36 +00006309 node->properties = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006310 if (prop->next != NULL)
6311 prop->next->prev = NULL;
6312 } else {
Daniel Veillard2156d432004-03-04 15:59:36 +00006313 prev->next = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006314 if (prop->next != NULL)
6315 prop->next->prev = NULL;
6316 }
6317 prop->next = NULL;
6318 prop->prev = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00006319 xmlFreeProp(prop);
6320 return(0);
6321 }
6322 prev = prop;
6323 prop = prop->next;
6324 }
6325 return(-1);
6326}
6327#endif
6328
6329#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006330/**
6331 * xmlSetProp:
6332 * @node: the node
6333 * @name: the attribute name
6334 * @value: the attribute value
6335 *
6336 * Set (or reset) an attribute carried by a node.
6337 * Returns the attribute pointer.
6338 */
6339xmlAttrPtr
6340xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006341 xmlAttrPtr prop;
6342 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006343
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006344 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006345 return(NULL);
6346 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006347 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006348 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006349 if ((xmlStrEqual(prop->name, name)) &&
6350 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006351 xmlNodePtr oldprop = prop->children;
6352
Owen Taylor3473f882001-02-23 17:55:21 +00006353 prop->children = NULL;
6354 prop->last = NULL;
6355 if (value != NULL) {
6356 xmlChar *buffer;
6357 xmlNodePtr tmp;
6358
6359 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6360 prop->children = xmlStringGetNodeList(node->doc, buffer);
6361 prop->last = NULL;
6362 prop->doc = doc;
6363 tmp = prop->children;
6364 while (tmp != NULL) {
6365 tmp->parent = (xmlNodePtr) prop;
6366 tmp->doc = doc;
6367 if (tmp->next == NULL)
6368 prop->last = tmp;
6369 tmp = tmp->next;
6370 }
6371 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006372 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006373 if (oldprop != NULL)
6374 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006375 return(prop);
6376 }
6377 prop = prop->next;
6378 }
6379 prop = xmlNewProp(node, name, value);
6380 return(prop);
6381}
6382
6383/**
6384 * xmlSetNsProp:
6385 * @node: the node
6386 * @ns: the namespace definition
6387 * @name: the attribute name
6388 * @value: the attribute value
6389 *
6390 * Set (or reset) an attribute carried by a node.
6391 * The ns structure must be in scope, this is not checked.
6392 *
6393 * Returns the attribute pointer.
6394 */
6395xmlAttrPtr
6396xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6397 const xmlChar *value) {
6398 xmlAttrPtr prop;
6399
6400 if ((node == NULL) || (name == NULL))
6401 return(NULL);
6402
6403 if (ns == NULL)
6404 return(xmlSetProp(node, name, value));
6405 if (ns->href == NULL)
6406 return(NULL);
6407 prop = node->properties;
6408
6409 while (prop != NULL) {
6410 /*
6411 * One need to have
6412 * - same attribute names
6413 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006414 */
6415 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006416 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006417 if (prop->children != NULL)
6418 xmlFreeNodeList(prop->children);
6419 prop->children = NULL;
6420 prop->last = NULL;
6421 prop->ns = ns;
6422 if (value != NULL) {
6423 xmlChar *buffer;
6424 xmlNodePtr tmp;
6425
6426 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6427 prop->children = xmlStringGetNodeList(node->doc, buffer);
6428 prop->last = NULL;
6429 tmp = prop->children;
6430 while (tmp != NULL) {
6431 tmp->parent = (xmlNodePtr) prop;
6432 if (tmp->next == NULL)
6433 prop->last = tmp;
6434 tmp = tmp->next;
6435 }
6436 xmlFree(buffer);
6437 }
6438 return(prop);
6439 }
6440 prop = prop->next;
6441 }
6442 prop = xmlNewNsProp(node, ns, name, value);
6443 return(prop);
6444}
6445
Daniel Veillard652327a2003-09-29 18:02:38 +00006446#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006447
6448/**
Owen Taylor3473f882001-02-23 17:55:21 +00006449 * xmlNodeIsText:
6450 * @node: the node
6451 *
6452 * Is this node a Text node ?
6453 * Returns 1 yes, 0 no
6454 */
6455int
6456xmlNodeIsText(xmlNodePtr node) {
6457 if (node == NULL) return(0);
6458
6459 if (node->type == XML_TEXT_NODE) return(1);
6460 return(0);
6461}
6462
6463/**
6464 * xmlIsBlankNode:
6465 * @node: the node
6466 *
6467 * Checks whether this node is an empty or whitespace only
6468 * (and possibly ignorable) text-node.
6469 *
6470 * Returns 1 yes, 0 no
6471 */
6472int
6473xmlIsBlankNode(xmlNodePtr node) {
6474 const xmlChar *cur;
6475 if (node == NULL) return(0);
6476
Daniel Veillard7db37732001-07-12 01:20:08 +00006477 if ((node->type != XML_TEXT_NODE) &&
6478 (node->type != XML_CDATA_SECTION_NODE))
6479 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006480 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006481 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006482 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006483 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006484 cur++;
6485 }
6486
6487 return(1);
6488}
6489
6490/**
6491 * xmlTextConcat:
6492 * @node: the node
6493 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006494 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006495 *
6496 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006497 *
6498 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006499 */
6500
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006501int
Owen Taylor3473f882001-02-23 17:55:21 +00006502xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006503 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006504
6505 if ((node->type != XML_TEXT_NODE) &&
6506 (node->type != XML_CDATA_SECTION_NODE)) {
6507#ifdef DEBUG_TREE
6508 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006509 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006510#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006511 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006512 }
William M. Brack7762bb12004-01-04 14:49:01 +00006513 /* need to check if content is currently in the dictionary */
6514 if ((node->doc != NULL) && (node->doc->dict != NULL) &&
6515 xmlDictOwns(node->doc->dict, node->content)) {
6516 node->content = xmlStrncatNew(node->content, content, len);
6517 } else {
6518 node->content = xmlStrncat(node->content, content, len);
6519 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006520 if (node->content == NULL)
6521 return(-1);
6522 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006523}
6524
6525/************************************************************************
6526 * *
6527 * Output : to a FILE or in memory *
6528 * *
6529 ************************************************************************/
6530
Owen Taylor3473f882001-02-23 17:55:21 +00006531/**
6532 * xmlBufferCreate:
6533 *
6534 * routine to create an XML buffer.
6535 * returns the new structure.
6536 */
6537xmlBufferPtr
6538xmlBufferCreate(void) {
6539 xmlBufferPtr ret;
6540
6541 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6542 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006543 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006544 return(NULL);
6545 }
6546 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006547 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006548 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006549 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006550 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006551 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006552 xmlFree(ret);
6553 return(NULL);
6554 }
6555 ret->content[0] = 0;
6556 return(ret);
6557}
6558
6559/**
6560 * xmlBufferCreateSize:
6561 * @size: initial size of buffer
6562 *
6563 * routine to create an XML buffer.
6564 * returns the new structure.
6565 */
6566xmlBufferPtr
6567xmlBufferCreateSize(size_t size) {
6568 xmlBufferPtr ret;
6569
6570 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6571 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006572 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006573 return(NULL);
6574 }
6575 ret->use = 0;
6576 ret->alloc = xmlBufferAllocScheme;
6577 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6578 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006579 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006580 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006581 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006582 xmlFree(ret);
6583 return(NULL);
6584 }
6585 ret->content[0] = 0;
6586 } else
6587 ret->content = NULL;
6588 return(ret);
6589}
6590
6591/**
Daniel Veillard53350552003-09-18 13:35:51 +00006592 * xmlBufferCreateStatic:
6593 * @mem: the memory area
6594 * @size: the size in byte
6595 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006596 * routine to create an XML buffer from an immutable memory area.
6597 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006598 * present until the end of the buffer lifetime.
6599 *
6600 * returns the new structure.
6601 */
6602xmlBufferPtr
6603xmlBufferCreateStatic(void *mem, size_t size) {
6604 xmlBufferPtr ret;
6605
6606 if ((mem == NULL) || (size == 0))
6607 return(NULL);
6608
6609 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6610 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006611 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006612 return(NULL);
6613 }
6614 ret->use = size;
6615 ret->size = size;
6616 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6617 ret->content = (xmlChar *) mem;
6618 return(ret);
6619}
6620
6621/**
Owen Taylor3473f882001-02-23 17:55:21 +00006622 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006623 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006624 * @scheme: allocation scheme to use
6625 *
6626 * Sets the allocation scheme for this buffer
6627 */
6628void
6629xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6630 xmlBufferAllocationScheme scheme) {
6631 if (buf == NULL) {
6632#ifdef DEBUG_BUFFER
6633 xmlGenericError(xmlGenericErrorContext,
6634 "xmlBufferSetAllocationScheme: buf == NULL\n");
6635#endif
6636 return;
6637 }
Daniel Veillard53350552003-09-18 13:35:51 +00006638 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006639
6640 buf->alloc = scheme;
6641}
6642
6643/**
6644 * xmlBufferFree:
6645 * @buf: the buffer to free
6646 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006647 * Frees an XML buffer. It frees both the content and the structure which
6648 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006649 */
6650void
6651xmlBufferFree(xmlBufferPtr buf) {
6652 if (buf == NULL) {
6653#ifdef DEBUG_BUFFER
6654 xmlGenericError(xmlGenericErrorContext,
6655 "xmlBufferFree: buf == NULL\n");
6656#endif
6657 return;
6658 }
Daniel Veillard53350552003-09-18 13:35:51 +00006659
6660 if ((buf->content != NULL) &&
6661 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006662 xmlFree(buf->content);
6663 }
Owen Taylor3473f882001-02-23 17:55:21 +00006664 xmlFree(buf);
6665}
6666
6667/**
6668 * xmlBufferEmpty:
6669 * @buf: the buffer
6670 *
6671 * empty a buffer.
6672 */
6673void
6674xmlBufferEmpty(xmlBufferPtr buf) {
6675 if (buf->content == NULL) return;
6676 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006677 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006678 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006679 } else {
6680 memset(buf->content, 0, buf->size);
6681 }
Owen Taylor3473f882001-02-23 17:55:21 +00006682}
6683
6684/**
6685 * xmlBufferShrink:
6686 * @buf: the buffer to dump
6687 * @len: the number of xmlChar to remove
6688 *
6689 * Remove the beginning of an XML buffer.
6690 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006691 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006692 */
6693int
6694xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6695 if (len == 0) return(0);
6696 if (len > buf->use) return(-1);
6697
6698 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006699 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6700 buf->content += len;
6701 } else {
6702 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6703 buf->content[buf->use] = 0;
6704 }
Owen Taylor3473f882001-02-23 17:55:21 +00006705 return(len);
6706}
6707
6708/**
6709 * xmlBufferGrow:
6710 * @buf: the buffer
6711 * @len: the minimum free size to allocate
6712 *
6713 * Grow the available space of an XML buffer.
6714 *
6715 * Returns the new available space or -1 in case of error
6716 */
6717int
6718xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6719 int size;
6720 xmlChar *newbuf;
6721
Daniel Veillard53350552003-09-18 13:35:51 +00006722 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006723 if (len + buf->use < buf->size) return(0);
6724
William M. Brack30fe43f2004-07-26 18:00:58 +00006725/*
6726 * Windows has a BIG problem on realloc timing, so we try to double
6727 * the buffer size (if that's enough) (bug 146697)
6728 */
6729#ifdef WIN32
6730 if (buf->size > len)
6731 size = buf->size * 2;
6732 else
6733 size = buf->use + len + 100;
6734#else
Owen Taylor3473f882001-02-23 17:55:21 +00006735 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00006736#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006737
6738 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006739 if (newbuf == NULL) {
6740 xmlTreeErrMemory("growing buffer");
6741 return(-1);
6742 }
Owen Taylor3473f882001-02-23 17:55:21 +00006743 buf->content = newbuf;
6744 buf->size = size;
6745 return(buf->size - buf->use);
6746}
6747
6748/**
6749 * xmlBufferDump:
6750 * @file: the file output
6751 * @buf: the buffer to dump
6752 *
6753 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006754 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006755 */
6756int
6757xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6758 int ret;
6759
6760 if (buf == NULL) {
6761#ifdef DEBUG_BUFFER
6762 xmlGenericError(xmlGenericErrorContext,
6763 "xmlBufferDump: buf == NULL\n");
6764#endif
6765 return(0);
6766 }
6767 if (buf->content == NULL) {
6768#ifdef DEBUG_BUFFER
6769 xmlGenericError(xmlGenericErrorContext,
6770 "xmlBufferDump: buf->content == NULL\n");
6771#endif
6772 return(0);
6773 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006774 if (file == NULL)
6775 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006776 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6777 return(ret);
6778}
6779
6780/**
6781 * xmlBufferContent:
6782 * @buf: the buffer
6783 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006784 * Function to extract the content of a buffer
6785 *
Owen Taylor3473f882001-02-23 17:55:21 +00006786 * Returns the internal content
6787 */
6788
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006789const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006790xmlBufferContent(const xmlBufferPtr buf)
6791{
6792 if(!buf)
6793 return NULL;
6794
6795 return buf->content;
6796}
6797
6798/**
6799 * xmlBufferLength:
6800 * @buf: the buffer
6801 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006802 * Function to get the length of a buffer
6803 *
Owen Taylor3473f882001-02-23 17:55:21 +00006804 * Returns the length of data in the internal content
6805 */
6806
6807int
6808xmlBufferLength(const xmlBufferPtr buf)
6809{
6810 if(!buf)
6811 return 0;
6812
6813 return buf->use;
6814}
6815
6816/**
6817 * xmlBufferResize:
6818 * @buf: the buffer to resize
6819 * @size: the desired size
6820 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006821 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006822 *
6823 * Returns 0 in case of problems, 1 otherwise
6824 */
6825int
6826xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6827{
6828 unsigned int newSize;
6829 xmlChar* rebuf = NULL;
6830
Daniel Veillard53350552003-09-18 13:35:51 +00006831 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6832
Owen Taylor3473f882001-02-23 17:55:21 +00006833 /* Don't resize if we don't have to */
6834 if (size < buf->size)
6835 return 1;
6836
6837 /* figure out new size */
6838 switch (buf->alloc){
6839 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillardbf629492004-04-20 22:20:59 +00006840 /*take care of empty case*/
6841 newSize = (buf->size ? buf->size*2 : size + 10);
Owen Taylor3473f882001-02-23 17:55:21 +00006842 while (size > newSize) newSize *= 2;
6843 break;
6844 case XML_BUFFER_ALLOC_EXACT:
6845 newSize = size+10;
6846 break;
6847 default:
6848 newSize = size+10;
6849 break;
6850 }
6851
6852 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006853 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006854 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006855 rebuf = (xmlChar *) xmlRealloc(buf->content,
6856 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006857 } else {
6858 /*
6859 * if we are reallocating a buffer far from being full, it's
6860 * better to make a new allocation and copy only the used range
6861 * and free the old one.
6862 */
6863 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6864 if (rebuf != NULL) {
6865 memcpy(rebuf, buf->content, buf->use);
6866 xmlFree(buf->content);
William M. Brack42331a92004-07-29 07:07:16 +00006867 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006868 }
6869 }
Owen Taylor3473f882001-02-23 17:55:21 +00006870 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006871 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006872 return 0;
6873 }
6874 buf->content = rebuf;
6875 buf->size = newSize;
6876
6877 return 1;
6878}
6879
6880/**
6881 * xmlBufferAdd:
6882 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006883 * @str: the #xmlChar string
6884 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006885 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006886 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006887 * str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006888 *
6889 * Returns 0 successful, a positive error code number otherwise
6890 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006891 */
William M. Bracka3215c72004-07-31 16:24:01 +00006892int
Owen Taylor3473f882001-02-23 17:55:21 +00006893xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6894 unsigned int needSize;
6895
6896 if (str == NULL) {
6897#ifdef DEBUG_BUFFER
6898 xmlGenericError(xmlGenericErrorContext,
6899 "xmlBufferAdd: str == NULL\n");
6900#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006901 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006902 }
William M. Bracka3215c72004-07-31 16:24:01 +00006903 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006904 if (len < -1) {
6905#ifdef DEBUG_BUFFER
6906 xmlGenericError(xmlGenericErrorContext,
6907 "xmlBufferAdd: len < 0\n");
6908#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006909 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006910 }
William M. Bracka3215c72004-07-31 16:24:01 +00006911 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006912
6913 if (len < 0)
6914 len = xmlStrlen(str);
6915
William M. Bracka3215c72004-07-31 16:24:01 +00006916 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006917
6918 needSize = buf->use + len + 2;
6919 if (needSize > buf->size){
6920 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006921 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006922 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006923 }
6924 }
6925
6926 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6927 buf->use += len;
6928 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006929 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006930}
6931
6932/**
6933 * xmlBufferAddHead:
6934 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006935 * @str: the #xmlChar string
6936 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006937 *
6938 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006939 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006940 *
6941 * Returns 0 successful, a positive error code number otherwise
6942 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006943 */
William M. Bracka3215c72004-07-31 16:24:01 +00006944int
Owen Taylor3473f882001-02-23 17:55:21 +00006945xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6946 unsigned int needSize;
6947
William M. Bracka3215c72004-07-31 16:24:01 +00006948 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006949 if (str == NULL) {
6950#ifdef DEBUG_BUFFER
6951 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006952 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006953#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006954 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006955 }
6956 if (len < -1) {
6957#ifdef DEBUG_BUFFER
6958 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006959 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006960#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006961 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006962 }
William M. Bracka3215c72004-07-31 16:24:01 +00006963 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006964
6965 if (len < 0)
6966 len = xmlStrlen(str);
6967
William M. Bracka3215c72004-07-31 16:24:01 +00006968 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006969
6970 needSize = buf->use + len + 2;
6971 if (needSize > buf->size){
6972 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006973 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006974 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006975 }
6976 }
6977
6978 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6979 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6980 buf->use += len;
6981 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006982 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006983}
6984
6985/**
6986 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00006987 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00006988 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006989 *
6990 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00006991 *
6992 * Returns 0 successful, a positive error code number otherwise
6993 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006994 */
William M. Bracka3215c72004-07-31 16:24:01 +00006995int
Owen Taylor3473f882001-02-23 17:55:21 +00006996xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
William M. Bracka3215c72004-07-31 16:24:01 +00006997 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
6998 if (str == NULL) return -1;
6999 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00007000}
7001
7002/**
7003 * xmlBufferCCat:
7004 * @buf: the buffer to dump
7005 * @str: the C char string
7006 *
7007 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007008 *
7009 * Returns 0 successful, a positive error code number otherwise
7010 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007011 */
William M. Bracka3215c72004-07-31 16:24:01 +00007012int
Owen Taylor3473f882001-02-23 17:55:21 +00007013xmlBufferCCat(xmlBufferPtr buf, const char *str) {
7014 const char *cur;
7015
William M. Bracka3215c72004-07-31 16:24:01 +00007016 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007017 if (str == NULL) {
7018#ifdef DEBUG_BUFFER
7019 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007020 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007021#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007022 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007023 }
7024 for (cur = str;*cur != 0;cur++) {
7025 if (buf->use + 10 >= buf->size) {
7026 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007027 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007028 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007029 }
7030 }
7031 buf->content[buf->use++] = *cur;
7032 }
7033 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007034 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007035}
7036
7037/**
7038 * xmlBufferWriteCHAR:
7039 * @buf: the XML buffer
7040 * @string: the string to add
7041 *
7042 * routine which manages and grows an output buffer. This one adds
7043 * xmlChars at the end of the buffer.
7044 */
7045void
Daniel Veillard53350552003-09-18 13:35:51 +00007046xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
7047 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007048 xmlBufferCat(buf, string);
7049}
7050
7051/**
7052 * xmlBufferWriteChar:
7053 * @buf: the XML buffer output
7054 * @string: the string to add
7055 *
7056 * routine which manage and grows an output buffer. This one add
7057 * C chars at the end of the array.
7058 */
7059void
7060xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillard53350552003-09-18 13:35:51 +00007061 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007062 xmlBufferCCat(buf, string);
7063}
7064
7065
7066/**
7067 * xmlBufferWriteQuotedString:
7068 * @buf: the XML buffer output
7069 * @string: the string to add
7070 *
7071 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00007072 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00007073 * quote or double-quotes internally
7074 */
7075void
7076xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00007077 const xmlChar *cur, *base;
Daniel Veillard53350552003-09-18 13:35:51 +00007078 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00007079 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00007080 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00007081#ifdef DEBUG_BUFFER
7082 xmlGenericError(xmlGenericErrorContext,
7083 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7084#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00007085 xmlBufferCCat(buf, "\"");
7086 base = cur = string;
7087 while(*cur != 0){
7088 if(*cur == '"'){
7089 if (base != cur)
7090 xmlBufferAdd(buf, base, cur - base);
7091 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7092 cur++;
7093 base = cur;
7094 }
7095 else {
7096 cur++;
7097 }
7098 }
7099 if (base != cur)
7100 xmlBufferAdd(buf, base, cur - base);
7101 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007102 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007103 else{
7104 xmlBufferCCat(buf, "\'");
7105 xmlBufferCat(buf, string);
7106 xmlBufferCCat(buf, "\'");
7107 }
Owen Taylor3473f882001-02-23 17:55:21 +00007108 } else {
7109 xmlBufferCCat(buf, "\"");
7110 xmlBufferCat(buf, string);
7111 xmlBufferCCat(buf, "\"");
7112 }
7113}
7114
7115
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007116/**
7117 * xmlGetDocCompressMode:
7118 * @doc: the document
7119 *
7120 * get the compression ratio for a document, ZLIB based
7121 * Returns 0 (uncompressed) to 9 (max compression)
7122 */
7123int
7124xmlGetDocCompressMode (xmlDocPtr doc) {
7125 if (doc == NULL) return(-1);
7126 return(doc->compression);
7127}
7128
7129/**
7130 * xmlSetDocCompressMode:
7131 * @doc: the document
7132 * @mode: the compression ratio
7133 *
7134 * set the compression ratio for a document, ZLIB based
7135 * Correct values: 0 (uncompressed) to 9 (max compression)
7136 */
7137void
7138xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7139 if (doc == NULL) return;
7140 if (mode < 0) doc->compression = 0;
7141 else if (mode > 9) doc->compression = 9;
7142 else doc->compression = mode;
7143}
7144
7145/**
7146 * xmlGetCompressMode:
7147 *
7148 * get the default compression mode used, ZLIB based.
7149 * Returns 0 (uncompressed) to 9 (max compression)
7150 */
7151int
7152xmlGetCompressMode(void)
7153{
7154 return (xmlCompressMode);
7155}
7156
7157/**
7158 * xmlSetCompressMode:
7159 * @mode: the compression ratio
7160 *
7161 * set the default compression mode used, ZLIB based
7162 * Correct values: 0 (uncompressed) to 9 (max compression)
7163 */
7164void
7165xmlSetCompressMode(int mode) {
7166 if (mode < 0) xmlCompressMode = 0;
7167 else if (mode > 9) xmlCompressMode = 9;
7168 else xmlCompressMode = mode;
7169}
7170