blob: bd18fb6b35c32d71476827018d7d717ffed33695 [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:
76 msg = "invalid hexadecimal character value";
77 break;
78 case XML_TREE_INVALID_DEC:
79 msg = "invalid decimal character value";
80 break;
81 case XML_TREE_UNTERMINATED_ENTITY:
82 msg = "unterminated entity reference %15s";
83 break;
84 default:
85 msg = "unexpected error number";
86 }
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 Veillard2156d432004-03-04 15:59:36 +0000332#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_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
915 if (name != NULL)
916 cur->name = xmlStrdup(name);
917 if (ExternalID != NULL)
918 cur->ExternalID = xmlStrdup(ExternalID);
919 if (SystemID != NULL)
920 cur->SystemID = xmlStrdup(SystemID);
921 if (doc != NULL) {
922 doc->intSubset = cur;
923 cur->parent = doc;
924 cur->doc = doc;
925 if (doc->children == NULL) {
926 doc->children = (xmlNodePtr) cur;
927 doc->last = (xmlNodePtr) cur;
928 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000929 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000930 xmlNodePtr prev;
931
Owen Taylor3473f882001-02-23 17:55:21 +0000932 prev = doc->children;
933 prev->prev = (xmlNodePtr) cur;
934 cur->next = prev;
935 doc->children = (xmlNodePtr) cur;
936 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000937 xmlNodePtr next;
938
939 next = doc->children;
940 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
941 next = next->next;
942 if (next == NULL) {
943 cur->prev = doc->last;
944 cur->prev->next = (xmlNodePtr) cur;
945 cur->next = NULL;
946 doc->last = (xmlNodePtr) cur;
947 } else {
948 cur->next = next;
949 cur->prev = next->prev;
950 if (cur->prev == NULL)
951 doc->children = (xmlNodePtr) cur;
952 else
953 cur->prev->next = (xmlNodePtr) cur;
954 next->prev = (xmlNodePtr) cur;
955 }
Owen Taylor3473f882001-02-23 17:55:21 +0000956 }
957 }
958 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000959
Daniel Veillarda880b122003-04-21 21:36:41 +0000960 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000961 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000962 return(cur);
963}
964
965/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000966 * DICT_FREE:
967 * @str: a string
968 *
969 * Free a string if it is not owned by the "dict" dictionnary in the
970 * current scope
971 */
972#define DICT_FREE(str) \
973 if ((str) && ((!dict) || \
974 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
975 xmlFree((char *)(str));
976
977/**
Owen Taylor3473f882001-02-23 17:55:21 +0000978 * xmlFreeDtd:
979 * @cur: the DTD structure to free up
980 *
981 * Free a DTD structure.
982 */
983void
984xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000985 xmlDictPtr dict = NULL;
986
Owen Taylor3473f882001-02-23 17:55:21 +0000987 if (cur == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000988 return;
989 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000990 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +0000991
Daniel Veillarda880b122003-04-21 21:36:41 +0000992 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000993 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
994
Owen Taylor3473f882001-02-23 17:55:21 +0000995 if (cur->children != NULL) {
996 xmlNodePtr next, c = cur->children;
997
998 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000999 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001000 * indexes.
1001 */
1002 while (c != NULL) {
1003 next = c->next;
Daniel Veillardd72c7e32003-05-12 21:55:03 +00001004 if ((c->type == XML_COMMENT_NODE) || (c->type == XML_PI_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001005 xmlUnlinkNode(c);
1006 xmlFreeNode(c);
1007 }
1008 c = next;
1009 }
1010 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001011 DICT_FREE(cur->name)
1012 DICT_FREE(cur->SystemID)
1013 DICT_FREE(cur->ExternalID)
Owen Taylor3473f882001-02-23 17:55:21 +00001014 /* TODO !!! */
1015 if (cur->notations != NULL)
1016 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1017
1018 if (cur->elements != NULL)
1019 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1020 if (cur->attributes != NULL)
1021 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1022 if (cur->entities != NULL)
1023 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1024 if (cur->pentities != NULL)
1025 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1026
Owen Taylor3473f882001-02-23 17:55:21 +00001027 xmlFree(cur);
1028}
1029
1030/**
1031 * xmlNewDoc:
1032 * @version: xmlChar string giving the version of XML "1.0"
1033 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001034 * Creates a new XML document
1035 *
Owen Taylor3473f882001-02-23 17:55:21 +00001036 * Returns a new document
1037 */
1038xmlDocPtr
1039xmlNewDoc(const xmlChar *version) {
1040 xmlDocPtr cur;
1041
1042 if (version == NULL)
1043 version = (const xmlChar *) "1.0";
1044
1045 /*
1046 * Allocate a new document and fill the fields.
1047 */
1048 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1049 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001050 xmlTreeErrMemory("building doc");
Owen Taylor3473f882001-02-23 17:55:21 +00001051 return(NULL);
1052 }
1053 memset(cur, 0, sizeof(xmlDoc));
1054 cur->type = XML_DOCUMENT_NODE;
1055
1056 cur->version = xmlStrdup(version);
1057 cur->standalone = -1;
1058 cur->compression = -1; /* not initialized */
1059 cur->doc = cur;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001060 /*
1061 * The in memory encoding is always UTF8
1062 * This field will never change and would
1063 * be obsolete if not for binary compatibility.
1064 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001065 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001066
Daniel Veillarda880b122003-04-21 21:36:41 +00001067 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001068 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001069 return(cur);
1070}
1071
1072/**
1073 * xmlFreeDoc:
1074 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001075 *
1076 * Free up all the structures used by a document, tree included.
1077 */
1078void
1079xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001080 xmlDtdPtr extSubset, intSubset;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001081 xmlDictPtr dict = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001082
Owen Taylor3473f882001-02-23 17:55:21 +00001083 if (cur == NULL) {
1084#ifdef DEBUG_TREE
1085 xmlGenericError(xmlGenericErrorContext,
1086 "xmlFreeDoc : document == NULL\n");
1087#endif
1088 return;
1089 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001090 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001091
Daniel Veillarda880b122003-04-21 21:36:41 +00001092 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001093 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1094
Daniel Veillard76d66f42001-05-16 21:05:17 +00001095 /*
1096 * Do this before freeing the children list to avoid ID lookups
1097 */
1098 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1099 cur->ids = NULL;
1100 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1101 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001102 extSubset = cur->extSubset;
1103 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001104 if (intSubset == extSubset)
1105 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001106 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001107 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001108 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001109 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001110 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001111 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001112 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001113 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001114 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001115 }
1116
1117 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001118 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001119
1120 DICT_FREE(cur->version)
1121 DICT_FREE(cur->name)
1122 DICT_FREE(cur->encoding)
1123 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001124 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001125 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001126}
1127
1128/**
1129 * xmlStringLenGetNodeList:
1130 * @doc: the document
1131 * @value: the value of the text
1132 * @len: the length of the string value
1133 *
1134 * Parse the value string and build the node list associated. Should
1135 * produce a flat tree with only TEXTs and ENTITY_REFs.
1136 * Returns a pointer to the first child
1137 */
1138xmlNodePtr
1139xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1140 xmlNodePtr ret = NULL, last = NULL;
1141 xmlNodePtr node;
1142 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001143 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001144 const xmlChar *q;
1145 xmlEntityPtr ent;
1146
1147 if (value == NULL) return(NULL);
1148
1149 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001150 while ((cur < end) && (*cur != 0)) {
1151 if (cur[0] == '&') {
1152 int charval = 0;
1153 xmlChar tmp;
1154
Owen Taylor3473f882001-02-23 17:55:21 +00001155 /*
1156 * Save the current text.
1157 */
1158 if (cur != q) {
1159 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1160 xmlNodeAddContentLen(last, q, cur - q);
1161 } else {
1162 node = xmlNewDocTextLen(doc, q, cur - q);
1163 if (node == NULL) return(ret);
1164 if (last == NULL)
1165 last = ret = node;
1166 else {
1167 last->next = node;
1168 node->prev = last;
1169 last = node;
1170 }
1171 }
1172 }
Owen Taylor3473f882001-02-23 17:55:21 +00001173 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001174 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1175 cur += 3;
1176 if (cur < end)
1177 tmp = *cur;
1178 else
1179 tmp = 0;
1180 while (tmp != ';') { /* Non input consuming loop */
1181 if ((tmp >= '0') && (tmp <= '9'))
1182 charval = charval * 16 + (tmp - '0');
1183 else if ((tmp >= 'a') && (tmp <= 'f'))
1184 charval = charval * 16 + (tmp - 'a') + 10;
1185 else if ((tmp >= 'A') && (tmp <= 'F'))
1186 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001187 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001188 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1189 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001190 charval = 0;
1191 break;
1192 }
1193 cur++;
1194 if (cur < end)
1195 tmp = *cur;
1196 else
1197 tmp = 0;
1198 }
1199 if (tmp == ';')
1200 cur++;
1201 q = cur;
1202 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1203 cur += 2;
1204 if (cur < end)
1205 tmp = *cur;
1206 else
1207 tmp = 0;
1208 while (tmp != ';') { /* Non input consuming loops */
1209 if ((tmp >= '0') && (tmp <= '9'))
1210 charval = charval * 10 + (tmp - '0');
1211 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001212 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1213 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001214 charval = 0;
1215 break;
1216 }
1217 cur++;
1218 if (cur < end)
1219 tmp = *cur;
1220 else
1221 tmp = 0;
1222 }
1223 if (tmp == ';')
1224 cur++;
1225 q = cur;
1226 } else {
1227 /*
1228 * Read the entity string
1229 */
1230 cur++;
1231 q = cur;
1232 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1233 if ((cur >= end) || (*cur == 0)) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001234 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1235 (const char *) q);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001236 return(ret);
1237 }
1238 if (cur != q) {
1239 /*
1240 * Predefined entities don't generate nodes
1241 */
1242 val = xmlStrndup(q, cur - q);
1243 ent = xmlGetDocEntity(doc, val);
1244 if ((ent != NULL) &&
1245 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1246 if (last == NULL) {
1247 node = xmlNewDocText(doc, ent->content);
1248 last = ret = node;
1249 } else if (last->type != XML_TEXT_NODE) {
1250 node = xmlNewDocText(doc, ent->content);
1251 last = xmlAddNextSibling(last, node);
1252 } else
1253 xmlNodeAddContent(last, ent->content);
1254
1255 } else {
1256 /*
1257 * Create a new REFERENCE_REF node
1258 */
1259 node = xmlNewReference(doc, val);
1260 if (node == NULL) {
1261 if (val != NULL) xmlFree(val);
1262 return(ret);
1263 }
1264 else if ((ent != NULL) && (ent->children == NULL)) {
1265 xmlNodePtr temp;
1266
1267 ent->children = xmlStringGetNodeList(doc,
1268 (const xmlChar*)node->content);
1269 ent->owner = 1;
1270 temp = ent->children;
1271 while (temp) {
1272 temp->parent = (xmlNodePtr)ent;
1273 temp = temp->next;
1274 }
1275 }
1276 if (last == NULL) {
1277 last = ret = node;
1278 } else {
1279 last = xmlAddNextSibling(last, node);
1280 }
1281 }
1282 xmlFree(val);
1283 }
1284 cur++;
1285 q = cur;
1286 }
1287 if (charval != 0) {
1288 xmlChar buf[10];
1289 int l;
1290
1291 l = xmlCopyCharMultiByte(buf, charval);
1292 buf[l] = 0;
1293 node = xmlNewDocText(doc, buf);
1294 if (node != NULL) {
1295 if (last == NULL) {
1296 last = ret = node;
1297 } else {
1298 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001299 }
1300 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001301 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001302 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001303 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001304 cur++;
1305 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001306 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001307 /*
1308 * Handle the last piece of text.
1309 */
1310 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1311 xmlNodeAddContentLen(last, q, cur - q);
1312 } else {
1313 node = xmlNewDocTextLen(doc, q, cur - q);
1314 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001315 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001316 last = ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001317 } else {
1318 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001319 }
1320 }
1321 }
1322 return(ret);
1323}
1324
1325/**
1326 * xmlStringGetNodeList:
1327 * @doc: the document
1328 * @value: the value of the attribute
1329 *
1330 * Parse the value string and build the node list associated. Should
1331 * produce a flat tree with only TEXTs and ENTITY_REFs.
1332 * Returns a pointer to the first child
1333 */
1334xmlNodePtr
1335xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1336 xmlNodePtr ret = NULL, last = NULL;
1337 xmlNodePtr node;
1338 xmlChar *val;
1339 const xmlChar *cur = value;
1340 const xmlChar *q;
1341 xmlEntityPtr ent;
1342
1343 if (value == NULL) return(NULL);
1344
1345 q = cur;
1346 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001347 if (cur[0] == '&') {
1348 int charval = 0;
1349 xmlChar tmp;
1350
Owen Taylor3473f882001-02-23 17:55:21 +00001351 /*
1352 * Save the current text.
1353 */
1354 if (cur != q) {
1355 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1356 xmlNodeAddContentLen(last, q, cur - q);
1357 } else {
1358 node = xmlNewDocTextLen(doc, q, cur - q);
1359 if (node == NULL) return(ret);
1360 if (last == NULL)
1361 last = ret = node;
1362 else {
1363 last->next = node;
1364 node->prev = last;
1365 last = node;
1366 }
1367 }
1368 }
Owen Taylor3473f882001-02-23 17:55:21 +00001369 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001370 if ((cur[1] == '#') && (cur[2] == 'x')) {
1371 cur += 3;
1372 tmp = *cur;
1373 while (tmp != ';') { /* Non input consuming loop */
1374 if ((tmp >= '0') && (tmp <= '9'))
1375 charval = charval * 16 + (tmp - '0');
1376 else if ((tmp >= 'a') && (tmp <= 'f'))
1377 charval = charval * 16 + (tmp - 'a') + 10;
1378 else if ((tmp >= 'A') && (tmp <= 'F'))
1379 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001380 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001381 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1382 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001383 charval = 0;
1384 break;
1385 }
1386 cur++;
1387 tmp = *cur;
1388 }
1389 if (tmp == ';')
1390 cur++;
1391 q = cur;
1392 } else if (cur[1] == '#') {
1393 cur += 2;
1394 tmp = *cur;
1395 while (tmp != ';') { /* Non input consuming loops */
1396 if ((tmp >= '0') && (tmp <= '9'))
1397 charval = charval * 10 + (tmp - '0');
1398 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001399 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1400 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001401 charval = 0;
1402 break;
1403 }
1404 cur++;
1405 tmp = *cur;
1406 }
1407 if (tmp == ';')
1408 cur++;
1409 q = cur;
1410 } else {
1411 /*
1412 * Read the entity string
1413 */
1414 cur++;
1415 q = cur;
1416 while ((*cur != 0) && (*cur != ';')) cur++;
1417 if (*cur == 0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001418 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1419 (xmlNodePtr) doc, (const char *) q);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001420 return(ret);
1421 }
1422 if (cur != q) {
1423 /*
1424 * Predefined entities don't generate nodes
1425 */
1426 val = xmlStrndup(q, cur - q);
1427 ent = xmlGetDocEntity(doc, val);
1428 if ((ent != NULL) &&
1429 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1430 if (last == NULL) {
1431 node = xmlNewDocText(doc, ent->content);
1432 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001433 } else if (last->type != XML_TEXT_NODE) {
1434 node = xmlNewDocText(doc, ent->content);
1435 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001436 } else
1437 xmlNodeAddContent(last, ent->content);
1438
1439 } else {
1440 /*
1441 * Create a new REFERENCE_REF node
1442 */
1443 node = xmlNewReference(doc, val);
1444 if (node == NULL) {
1445 if (val != NULL) xmlFree(val);
1446 return(ret);
1447 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001448 else if ((ent != NULL) && (ent->children == NULL)) {
1449 xmlNodePtr temp;
1450
1451 ent->children = xmlStringGetNodeList(doc,
1452 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001453 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001454 temp = ent->children;
1455 while (temp) {
1456 temp->parent = (xmlNodePtr)ent;
1457 temp = temp->next;
1458 }
1459 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001460 if (last == NULL) {
1461 last = ret = node;
1462 } else {
1463 last = xmlAddNextSibling(last, node);
1464 }
1465 }
1466 xmlFree(val);
1467 }
1468 cur++;
1469 q = cur;
1470 }
1471 if (charval != 0) {
1472 xmlChar buf[10];
1473 int len;
1474
1475 len = xmlCopyCharMultiByte(buf, charval);
1476 buf[len] = 0;
1477 node = xmlNewDocText(doc, buf);
1478 if (node != NULL) {
1479 if (last == NULL) {
1480 last = ret = node;
1481 } else {
1482 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001483 }
1484 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001485
1486 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001487 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001488 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001489 cur++;
1490 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001491 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001492 /*
1493 * Handle the last piece of text.
1494 */
1495 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1496 xmlNodeAddContentLen(last, q, cur - q);
1497 } else {
1498 node = xmlNewDocTextLen(doc, q, cur - q);
1499 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001500 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001501 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001502 } else {
1503 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001504 }
1505 }
1506 }
1507 return(ret);
1508}
1509
1510/**
1511 * xmlNodeListGetString:
1512 * @doc: the document
1513 * @list: a Node list
1514 * @inLine: should we replace entity contents or show their external form
1515 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001516 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001517 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001518 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001519 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001520 */
1521xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001522xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1523{
Owen Taylor3473f882001-02-23 17:55:21 +00001524 xmlNodePtr node = list;
1525 xmlChar *ret = NULL;
1526 xmlEntityPtr ent;
1527
Daniel Veillard7646b182002-04-20 06:41:40 +00001528 if (list == NULL)
1529 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001530
1531 while (node != NULL) {
1532 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001533 (node->type == XML_CDATA_SECTION_NODE)) {
1534 if (inLine) {
1535 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001536 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001537 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001538
Daniel Veillard7646b182002-04-20 06:41:40 +00001539 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1540 if (buffer != NULL) {
1541 ret = xmlStrcat(ret, buffer);
1542 xmlFree(buffer);
1543 }
1544 }
1545 } else if (node->type == XML_ENTITY_REF_NODE) {
1546 if (inLine) {
1547 ent = xmlGetDocEntity(doc, node->name);
1548 if (ent != NULL) {
1549 xmlChar *buffer;
1550
1551 /* an entity content can be any "well balanced chunk",
1552 * i.e. the result of the content [43] production:
1553 * http://www.w3.org/TR/REC-xml#NT-content.
1554 * So it can contain text, CDATA section or nested
1555 * entity reference nodes (among others).
1556 * -> we recursive call xmlNodeListGetString()
1557 * which handles these types */
1558 buffer = xmlNodeListGetString(doc, ent->children, 1);
1559 if (buffer != NULL) {
1560 ret = xmlStrcat(ret, buffer);
1561 xmlFree(buffer);
1562 }
1563 } else {
1564 ret = xmlStrcat(ret, node->content);
1565 }
1566 } else {
1567 xmlChar buf[2];
1568
1569 buf[0] = '&';
1570 buf[1] = 0;
1571 ret = xmlStrncat(ret, buf, 1);
1572 ret = xmlStrcat(ret, node->name);
1573 buf[0] = ';';
1574 buf[1] = 0;
1575 ret = xmlStrncat(ret, buf, 1);
1576 }
1577 }
1578#if 0
1579 else {
1580 xmlGenericError(xmlGenericErrorContext,
1581 "xmlGetNodeListString : invalid node type %d\n",
1582 node->type);
1583 }
1584#endif
1585 node = node->next;
1586 }
1587 return (ret);
1588}
Daniel Veillard652327a2003-09-29 18:02:38 +00001589
1590#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001591/**
1592 * xmlNodeListGetRawString:
1593 * @doc: the document
1594 * @list: a Node list
1595 * @inLine: should we replace entity contents or show their external form
1596 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001597 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001598 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1599 * this function doesn't do any character encoding handling.
1600 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001601 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001602 */
1603xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001604xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1605{
Owen Taylor3473f882001-02-23 17:55:21 +00001606 xmlNodePtr node = list;
1607 xmlChar *ret = NULL;
1608 xmlEntityPtr ent;
1609
Daniel Veillard7646b182002-04-20 06:41:40 +00001610 if (list == NULL)
1611 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001612
1613 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001614 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001615 (node->type == XML_CDATA_SECTION_NODE)) {
1616 if (inLine) {
1617 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001618 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001619 xmlChar *buffer;
1620
1621 buffer = xmlEncodeSpecialChars(doc, node->content);
1622 if (buffer != NULL) {
1623 ret = xmlStrcat(ret, buffer);
1624 xmlFree(buffer);
1625 }
1626 }
1627 } else if (node->type == XML_ENTITY_REF_NODE) {
1628 if (inLine) {
1629 ent = xmlGetDocEntity(doc, node->name);
1630 if (ent != NULL) {
1631 xmlChar *buffer;
1632
1633 /* an entity content can be any "well balanced chunk",
1634 * i.e. the result of the content [43] production:
1635 * http://www.w3.org/TR/REC-xml#NT-content.
1636 * So it can contain text, CDATA section or nested
1637 * entity reference nodes (among others).
1638 * -> we recursive call xmlNodeListGetRawString()
1639 * which handles these types */
1640 buffer =
1641 xmlNodeListGetRawString(doc, ent->children, 1);
1642 if (buffer != NULL) {
1643 ret = xmlStrcat(ret, buffer);
1644 xmlFree(buffer);
1645 }
1646 } else {
1647 ret = xmlStrcat(ret, node->content);
1648 }
1649 } else {
1650 xmlChar buf[2];
1651
1652 buf[0] = '&';
1653 buf[1] = 0;
1654 ret = xmlStrncat(ret, buf, 1);
1655 ret = xmlStrcat(ret, node->name);
1656 buf[0] = ';';
1657 buf[1] = 0;
1658 ret = xmlStrncat(ret, buf, 1);
1659 }
1660 }
Owen Taylor3473f882001-02-23 17:55:21 +00001661#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001662 else {
1663 xmlGenericError(xmlGenericErrorContext,
1664 "xmlGetNodeListString : invalid node type %d\n",
1665 node->type);
1666 }
Owen Taylor3473f882001-02-23 17:55:21 +00001667#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001668 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001669 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001670 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001671}
Daniel Veillard652327a2003-09-29 18:02:38 +00001672#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001673
Daniel Veillard2156d432004-03-04 15:59:36 +00001674#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00001675/**
1676 * xmlNewProp:
1677 * @node: the holding node
1678 * @name: the name of the attribute
1679 * @value: the value of the attribute
1680 *
1681 * Create a new property carried by a node.
1682 * Returns a pointer to the attribute
1683 */
1684xmlAttrPtr
1685xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1686 xmlAttrPtr cur;
1687 xmlDocPtr doc = NULL;
1688
1689 if (name == NULL) {
1690#ifdef DEBUG_TREE
1691 xmlGenericError(xmlGenericErrorContext,
1692 "xmlNewProp : name == NULL\n");
1693#endif
1694 return(NULL);
1695 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001696 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1697 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001698
1699 /*
1700 * Allocate a new property and fill the fields.
1701 */
1702 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1703 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001704 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001705 return(NULL);
1706 }
1707 memset(cur, 0, sizeof(xmlAttr));
1708 cur->type = XML_ATTRIBUTE_NODE;
1709
1710 cur->parent = node;
1711 if (node != NULL) {
1712 doc = node->doc;
1713 cur->doc = doc;
1714 }
1715 cur->name = xmlStrdup(name);
1716 if (value != NULL) {
1717 xmlChar *buffer;
1718 xmlNodePtr tmp;
1719
1720 buffer = xmlEncodeEntitiesReentrant(doc, value);
1721 cur->children = xmlStringGetNodeList(doc, buffer);
1722 cur->last = NULL;
1723 tmp = cur->children;
1724 while (tmp != NULL) {
1725 tmp->parent = (xmlNodePtr) cur;
1726 tmp->doc = doc;
1727 if (tmp->next == NULL)
1728 cur->last = tmp;
1729 tmp = tmp->next;
1730 }
1731 xmlFree(buffer);
1732 }
1733
1734 /*
1735 * Add it at the end to preserve parsing order ...
1736 */
1737 if (node != NULL) {
1738 if (node->properties == NULL) {
1739 node->properties = cur;
1740 } else {
1741 xmlAttrPtr prev = node->properties;
1742
1743 while (prev->next != NULL) prev = prev->next;
1744 prev->next = cur;
1745 cur->prev = prev;
1746 }
1747 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001748
Daniel Veillarda880b122003-04-21 21:36:41 +00001749 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001750 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001751 return(cur);
1752}
Daniel Veillard652327a2003-09-29 18:02:38 +00001753#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001754
1755/**
1756 * xmlNewNsProp:
1757 * @node: the holding node
1758 * @ns: the namespace
1759 * @name: the name of the attribute
1760 * @value: the value of the attribute
1761 *
1762 * Create a new property tagged with a namespace and carried by a node.
1763 * Returns a pointer to the attribute
1764 */
1765xmlAttrPtr
1766xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1767 const xmlChar *value) {
1768 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001769 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001770
1771 if (name == NULL) {
1772#ifdef DEBUG_TREE
1773 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001774 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001775#endif
1776 return(NULL);
1777 }
1778
1779 /*
1780 * Allocate a new property and fill the fields.
1781 */
1782 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1783 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001784 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001785 return(NULL);
1786 }
1787 memset(cur, 0, sizeof(xmlAttr));
1788 cur->type = XML_ATTRIBUTE_NODE;
1789
1790 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001791 if (node != NULL) {
1792 doc = node->doc;
1793 cur->doc = doc;
1794 }
Owen Taylor3473f882001-02-23 17:55:21 +00001795 cur->ns = ns;
1796 cur->name = xmlStrdup(name);
1797 if (value != NULL) {
1798 xmlChar *buffer;
1799 xmlNodePtr tmp;
1800
Daniel Veillarda682b212001-06-07 19:59:42 +00001801 buffer = xmlEncodeEntitiesReentrant(doc, value);
1802 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001803 cur->last = NULL;
1804 tmp = cur->children;
1805 while (tmp != NULL) {
1806 tmp->parent = (xmlNodePtr) cur;
1807 if (tmp->next == NULL)
1808 cur->last = tmp;
1809 tmp = tmp->next;
1810 }
1811 xmlFree(buffer);
1812 }
1813
1814 /*
1815 * Add it at the end to preserve parsing order ...
1816 */
1817 if (node != NULL) {
1818 if (node->properties == NULL) {
1819 node->properties = cur;
1820 } else {
1821 xmlAttrPtr prev = node->properties;
1822
1823 while (prev->next != NULL) prev = prev->next;
1824 prev->next = cur;
1825 cur->prev = prev;
1826 }
1827 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001828
Daniel Veillarda880b122003-04-21 21:36:41 +00001829 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001830 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001831 return(cur);
1832}
1833
1834/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001835 * xmlNewNsPropEatName:
1836 * @node: the holding node
1837 * @ns: the namespace
1838 * @name: the name of the attribute
1839 * @value: the value of the attribute
1840 *
1841 * Create a new property tagged with a namespace and carried by a node.
1842 * Returns a pointer to the attribute
1843 */
1844xmlAttrPtr
1845xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1846 const xmlChar *value) {
1847 xmlAttrPtr cur;
1848 xmlDocPtr doc = NULL;
1849
1850 if (name == NULL) {
1851#ifdef DEBUG_TREE
1852 xmlGenericError(xmlGenericErrorContext,
1853 "xmlNewNsPropEatName : name == NULL\n");
1854#endif
1855 return(NULL);
1856 }
1857
1858 /*
1859 * Allocate a new property and fill the fields.
1860 */
1861 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1862 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001863 xmlTreeErrMemory("building attribute");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001864 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001865 return(NULL);
1866 }
1867 memset(cur, 0, sizeof(xmlAttr));
1868 cur->type = XML_ATTRIBUTE_NODE;
1869
1870 cur->parent = node;
1871 if (node != NULL) {
1872 doc = node->doc;
1873 cur->doc = doc;
1874 }
1875 cur->ns = ns;
1876 cur->name = name;
1877 if (value != NULL) {
1878 xmlChar *buffer;
1879 xmlNodePtr tmp;
1880
1881 buffer = xmlEncodeEntitiesReentrant(doc, value);
1882 cur->children = xmlStringGetNodeList(doc, buffer);
1883 cur->last = NULL;
1884 tmp = cur->children;
1885 while (tmp != NULL) {
1886 tmp->parent = (xmlNodePtr) cur;
1887 if (tmp->next == NULL)
1888 cur->last = tmp;
1889 tmp = tmp->next;
1890 }
1891 xmlFree(buffer);
1892 }
1893
1894 /*
1895 * Add it at the end to preserve parsing order ...
1896 */
1897 if (node != NULL) {
1898 if (node->properties == NULL) {
1899 node->properties = cur;
1900 } else {
1901 xmlAttrPtr prev = node->properties;
1902
1903 while (prev->next != NULL) prev = prev->next;
1904 prev->next = cur;
1905 cur->prev = prev;
1906 }
1907 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001908
Daniel Veillarda880b122003-04-21 21:36:41 +00001909 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001910 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001911 return(cur);
1912}
1913
1914/**
Owen Taylor3473f882001-02-23 17:55:21 +00001915 * xmlNewDocProp:
1916 * @doc: the document
1917 * @name: the name of the attribute
1918 * @value: the value of the attribute
1919 *
1920 * Create a new property carried by a document.
1921 * Returns a pointer to the attribute
1922 */
1923xmlAttrPtr
1924xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1925 xmlAttrPtr cur;
1926
1927 if (name == NULL) {
1928#ifdef DEBUG_TREE
1929 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001930 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001931#endif
1932 return(NULL);
1933 }
1934
1935 /*
1936 * Allocate a new property and fill the fields.
1937 */
1938 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1939 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001940 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001941 return(NULL);
1942 }
1943 memset(cur, 0, sizeof(xmlAttr));
1944 cur->type = XML_ATTRIBUTE_NODE;
1945
1946 cur->name = xmlStrdup(name);
1947 cur->doc = doc;
1948 if (value != NULL) {
1949 xmlNodePtr tmp;
1950
1951 cur->children = xmlStringGetNodeList(doc, value);
1952 cur->last = NULL;
1953
1954 tmp = cur->children;
1955 while (tmp != NULL) {
1956 tmp->parent = (xmlNodePtr) cur;
1957 if (tmp->next == NULL)
1958 cur->last = tmp;
1959 tmp = tmp->next;
1960 }
1961 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001962
Daniel Veillarda880b122003-04-21 21:36:41 +00001963 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001964 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001965 return(cur);
1966}
1967
1968/**
1969 * xmlFreePropList:
1970 * @cur: the first property in the list
1971 *
1972 * Free a property and all its siblings, all the children are freed too.
1973 */
1974void
1975xmlFreePropList(xmlAttrPtr cur) {
1976 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001977 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001978 while (cur != NULL) {
1979 next = cur->next;
1980 xmlFreeProp(cur);
1981 cur = next;
1982 }
1983}
1984
1985/**
1986 * xmlFreeProp:
1987 * @cur: an attribute
1988 *
1989 * Free one attribute, all the content is freed too
1990 */
1991void
1992xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001993 xmlDictPtr dict = NULL;
1994 if (cur == NULL) return;
1995
1996 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001997
Daniel Veillarda880b122003-04-21 21:36:41 +00001998 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001999 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
2000
Owen Taylor3473f882001-02-23 17:55:21 +00002001 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00002002 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
2003 ((cur->parent->doc->intSubset != NULL) ||
2004 (cur->parent->doc->extSubset != NULL))) {
2005 if (xmlIsID(cur->parent->doc, cur->parent, cur))
2006 xmlRemoveID(cur->parent->doc, cur);
2007 }
Owen Taylor3473f882001-02-23 17:55:21 +00002008 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002009 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002010 xmlFree(cur);
2011}
2012
Daniel Veillard652327a2003-09-29 18:02:38 +00002013#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002014/**
2015 * xmlRemoveProp:
2016 * @cur: an attribute
2017 *
2018 * Unlink and free one attribute, all the content is freed too
2019 * Note this doesn't work for namespace definition attributes
2020 *
2021 * Returns 0 if success and -1 in case of error.
2022 */
2023int
2024xmlRemoveProp(xmlAttrPtr cur) {
2025 xmlAttrPtr tmp;
2026 if (cur == NULL) {
2027#ifdef DEBUG_TREE
2028 xmlGenericError(xmlGenericErrorContext,
2029 "xmlRemoveProp : cur == NULL\n");
2030#endif
2031 return(-1);
2032 }
2033 if (cur->parent == NULL) {
2034#ifdef DEBUG_TREE
2035 xmlGenericError(xmlGenericErrorContext,
2036 "xmlRemoveProp : cur->parent == NULL\n");
2037#endif
2038 return(-1);
2039 }
2040 tmp = cur->parent->properties;
2041 if (tmp == cur) {
2042 cur->parent->properties = cur->next;
2043 xmlFreeProp(cur);
2044 return(0);
2045 }
2046 while (tmp != NULL) {
2047 if (tmp->next == cur) {
2048 tmp->next = cur->next;
2049 if (tmp->next != NULL)
2050 tmp->next->prev = tmp;
2051 xmlFreeProp(cur);
2052 return(0);
2053 }
2054 tmp = tmp->next;
2055 }
2056#ifdef DEBUG_TREE
2057 xmlGenericError(xmlGenericErrorContext,
2058 "xmlRemoveProp : attribute not owned by its node\n");
2059#endif
2060 return(-1);
2061}
Daniel Veillard652327a2003-09-29 18:02:38 +00002062#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002063
2064/**
2065 * xmlNewPI:
2066 * @name: the processing instruction name
2067 * @content: the PI content
2068 *
2069 * Creation of a processing instruction element.
2070 * Returns a pointer to the new node object.
2071 */
2072xmlNodePtr
2073xmlNewPI(const xmlChar *name, const xmlChar *content) {
2074 xmlNodePtr cur;
2075
2076 if (name == NULL) {
2077#ifdef DEBUG_TREE
2078 xmlGenericError(xmlGenericErrorContext,
2079 "xmlNewPI : name == NULL\n");
2080#endif
2081 return(NULL);
2082 }
2083
2084 /*
2085 * Allocate a new node and fill the fields.
2086 */
2087 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2088 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002089 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002090 return(NULL);
2091 }
2092 memset(cur, 0, sizeof(xmlNode));
2093 cur->type = XML_PI_NODE;
2094
2095 cur->name = xmlStrdup(name);
2096 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002097 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002098 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002099
Daniel Veillarda880b122003-04-21 21:36:41 +00002100 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002101 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002102 return(cur);
2103}
2104
2105/**
2106 * xmlNewNode:
2107 * @ns: namespace if any
2108 * @name: the node name
2109 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002110 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002111 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002112 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2113 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002114 */
2115xmlNodePtr
2116xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2117 xmlNodePtr cur;
2118
2119 if (name == NULL) {
2120#ifdef DEBUG_TREE
2121 xmlGenericError(xmlGenericErrorContext,
2122 "xmlNewNode : name == NULL\n");
2123#endif
2124 return(NULL);
2125 }
2126
2127 /*
2128 * Allocate a new node and fill the fields.
2129 */
2130 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2131 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002132 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002133 return(NULL);
2134 }
2135 memset(cur, 0, sizeof(xmlNode));
2136 cur->type = XML_ELEMENT_NODE;
2137
2138 cur->name = xmlStrdup(name);
2139 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002140
Daniel Veillarda880b122003-04-21 21:36:41 +00002141 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002142 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002143 return(cur);
2144}
2145
2146/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002147 * xmlNewNodeEatName:
2148 * @ns: namespace if any
2149 * @name: the node name
2150 *
2151 * Creation of a new node element. @ns is optional (NULL).
2152 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002153 * Returns a pointer to the new node object, with pointer @name as
2154 * new node's name. Use xmlNewNode() if a copy of @name string is
2155 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002156 */
2157xmlNodePtr
2158xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2159 xmlNodePtr cur;
2160
2161 if (name == NULL) {
2162#ifdef DEBUG_TREE
2163 xmlGenericError(xmlGenericErrorContext,
2164 "xmlNewNode : name == NULL\n");
2165#endif
2166 return(NULL);
2167 }
2168
2169 /*
2170 * Allocate a new node and fill the fields.
2171 */
2172 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2173 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002174 xmlTreeErrMemory("building node");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002175 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002176 return(NULL);
2177 }
2178 memset(cur, 0, sizeof(xmlNode));
2179 cur->type = XML_ELEMENT_NODE;
2180
2181 cur->name = name;
2182 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002183
Daniel Veillarda880b122003-04-21 21:36:41 +00002184 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002185 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002186 return(cur);
2187}
2188
2189/**
Owen Taylor3473f882001-02-23 17:55:21 +00002190 * xmlNewDocNode:
2191 * @doc: the document
2192 * @ns: namespace if any
2193 * @name: the node name
2194 * @content: the XML text content if any
2195 *
2196 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002197 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002198 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2199 * references, but XML special chars need to be escaped first by using
2200 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2201 * need entities support.
2202 *
2203 * Returns a pointer to the new node object.
2204 */
2205xmlNodePtr
2206xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2207 const xmlChar *name, const xmlChar *content) {
2208 xmlNodePtr cur;
2209
2210 cur = xmlNewNode(ns, name);
2211 if (cur != NULL) {
2212 cur->doc = doc;
2213 if (content != NULL) {
2214 cur->children = xmlStringGetNodeList(doc, content);
2215 UPDATE_LAST_CHILD_AND_PARENT(cur)
2216 }
2217 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002218
Owen Taylor3473f882001-02-23 17:55:21 +00002219 return(cur);
2220}
2221
Daniel Veillard46de64e2002-05-29 08:21:33 +00002222/**
2223 * xmlNewDocNodeEatName:
2224 * @doc: the document
2225 * @ns: namespace if any
2226 * @name: the node name
2227 * @content: the XML text content if any
2228 *
2229 * Creation of a new node element within a document. @ns and @content
2230 * are optional (NULL).
2231 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2232 * references, but XML special chars need to be escaped first by using
2233 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2234 * need entities support.
2235 *
2236 * Returns a pointer to the new node object.
2237 */
2238xmlNodePtr
2239xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2240 xmlChar *name, const xmlChar *content) {
2241 xmlNodePtr cur;
2242
2243 cur = xmlNewNodeEatName(ns, name);
2244 if (cur != NULL) {
2245 cur->doc = doc;
2246 if (content != NULL) {
2247 cur->children = xmlStringGetNodeList(doc, content);
2248 UPDATE_LAST_CHILD_AND_PARENT(cur)
2249 }
2250 }
2251 return(cur);
2252}
2253
Daniel Veillard652327a2003-09-29 18:02:38 +00002254#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002255/**
2256 * xmlNewDocRawNode:
2257 * @doc: the document
2258 * @ns: namespace if any
2259 * @name: the node name
2260 * @content: the text content if any
2261 *
2262 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002263 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002264 *
2265 * Returns a pointer to the new node object.
2266 */
2267xmlNodePtr
2268xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2269 const xmlChar *name, const xmlChar *content) {
2270 xmlNodePtr cur;
2271
2272 cur = xmlNewNode(ns, name);
2273 if (cur != NULL) {
2274 cur->doc = doc;
2275 if (content != NULL) {
2276 cur->children = xmlNewDocText(doc, content);
2277 UPDATE_LAST_CHILD_AND_PARENT(cur)
2278 }
2279 }
2280 return(cur);
2281}
2282
2283/**
2284 * xmlNewDocFragment:
2285 * @doc: the document owning the fragment
2286 *
2287 * Creation of a new Fragment node.
2288 * Returns a pointer to the new node object.
2289 */
2290xmlNodePtr
2291xmlNewDocFragment(xmlDocPtr doc) {
2292 xmlNodePtr cur;
2293
2294 /*
2295 * Allocate a new DocumentFragment node and fill the fields.
2296 */
2297 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2298 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002299 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002300 return(NULL);
2301 }
2302 memset(cur, 0, sizeof(xmlNode));
2303 cur->type = XML_DOCUMENT_FRAG_NODE;
2304
2305 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002306
Daniel Veillarda880b122003-04-21 21:36:41 +00002307 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002308 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002309 return(cur);
2310}
Daniel Veillard652327a2003-09-29 18:02:38 +00002311#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002312
2313/**
2314 * xmlNewText:
2315 * @content: the text content
2316 *
2317 * Creation of a new text node.
2318 * Returns a pointer to the new node object.
2319 */
2320xmlNodePtr
2321xmlNewText(const xmlChar *content) {
2322 xmlNodePtr cur;
2323
2324 /*
2325 * Allocate a new node and fill the fields.
2326 */
2327 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2328 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002329 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002330 return(NULL);
2331 }
2332 memset(cur, 0, sizeof(xmlNode));
2333 cur->type = XML_TEXT_NODE;
2334
2335 cur->name = xmlStringText;
2336 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002337 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002338 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002339
Daniel Veillarda880b122003-04-21 21:36:41 +00002340 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002341 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002342 return(cur);
2343}
2344
Daniel Veillard652327a2003-09-29 18:02:38 +00002345#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002346/**
2347 * xmlNewTextChild:
2348 * @parent: the parent node
2349 * @ns: a namespace if any
2350 * @name: the name of the child
2351 * @content: the text content of the child if any.
2352 *
2353 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002354 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2355 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002356 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002357 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2358 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2359 * reserved XML chars that might appear in @content, such as the ampersand,
2360 * greater-than or less-than signs, are automatically replaced by their XML
2361 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002362 *
2363 * Returns a pointer to the new node object.
2364 */
2365xmlNodePtr
2366xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2367 const xmlChar *name, const xmlChar *content) {
2368 xmlNodePtr cur, prev;
2369
2370 if (parent == NULL) {
2371#ifdef DEBUG_TREE
2372 xmlGenericError(xmlGenericErrorContext,
2373 "xmlNewTextChild : parent == NULL\n");
2374#endif
2375 return(NULL);
2376 }
2377
2378 if (name == NULL) {
2379#ifdef DEBUG_TREE
2380 xmlGenericError(xmlGenericErrorContext,
2381 "xmlNewTextChild : name == NULL\n");
2382#endif
2383 return(NULL);
2384 }
2385
2386 /*
2387 * Allocate a new node
2388 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002389 if (parent->type == XML_ELEMENT_NODE) {
2390 if (ns == NULL)
2391 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2392 else
2393 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2394 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2395 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2396 if (ns == NULL)
2397 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2398 else
2399 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2400 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2401 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2402 } else {
2403 return(NULL);
2404 }
Owen Taylor3473f882001-02-23 17:55:21 +00002405 if (cur == NULL) return(NULL);
2406
2407 /*
2408 * add the new element at the end of the children list.
2409 */
2410 cur->type = XML_ELEMENT_NODE;
2411 cur->parent = parent;
2412 cur->doc = parent->doc;
2413 if (parent->children == NULL) {
2414 parent->children = cur;
2415 parent->last = cur;
2416 } else {
2417 prev = parent->last;
2418 prev->next = cur;
2419 cur->prev = prev;
2420 parent->last = cur;
2421 }
2422
2423 return(cur);
2424}
Daniel Veillard652327a2003-09-29 18:02:38 +00002425#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002426
2427/**
2428 * xmlNewCharRef:
2429 * @doc: the document
2430 * @name: the char ref string, starting with # or "&# ... ;"
2431 *
2432 * Creation of a new character reference node.
2433 * Returns a pointer to the new node object.
2434 */
2435xmlNodePtr
2436xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2437 xmlNodePtr cur;
2438
2439 /*
2440 * Allocate a new node and fill the fields.
2441 */
2442 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2443 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002444 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002445 return(NULL);
2446 }
2447 memset(cur, 0, sizeof(xmlNode));
2448 cur->type = XML_ENTITY_REF_NODE;
2449
2450 cur->doc = doc;
2451 if (name[0] == '&') {
2452 int len;
2453 name++;
2454 len = xmlStrlen(name);
2455 if (name[len - 1] == ';')
2456 cur->name = xmlStrndup(name, len - 1);
2457 else
2458 cur->name = xmlStrndup(name, len);
2459 } else
2460 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002461
Daniel Veillarda880b122003-04-21 21:36:41 +00002462 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002463 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002464 return(cur);
2465}
2466
2467/**
2468 * xmlNewReference:
2469 * @doc: the document
2470 * @name: the reference name, or the reference string with & and ;
2471 *
2472 * Creation of a new reference node.
2473 * Returns a pointer to the new node object.
2474 */
2475xmlNodePtr
2476xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2477 xmlNodePtr cur;
2478 xmlEntityPtr ent;
2479
2480 /*
2481 * Allocate a new node and fill the fields.
2482 */
2483 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2484 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002485 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002486 return(NULL);
2487 }
2488 memset(cur, 0, sizeof(xmlNode));
2489 cur->type = XML_ENTITY_REF_NODE;
2490
2491 cur->doc = doc;
2492 if (name[0] == '&') {
2493 int len;
2494 name++;
2495 len = xmlStrlen(name);
2496 if (name[len - 1] == ';')
2497 cur->name = xmlStrndup(name, len - 1);
2498 else
2499 cur->name = xmlStrndup(name, len);
2500 } else
2501 cur->name = xmlStrdup(name);
2502
2503 ent = xmlGetDocEntity(doc, cur->name);
2504 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002505 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002506 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002507 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002508 * updated. Not sure if this is 100% correct.
2509 * -George
2510 */
2511 cur->children = (xmlNodePtr) ent;
2512 cur->last = (xmlNodePtr) ent;
2513 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002514
Daniel Veillarda880b122003-04-21 21:36:41 +00002515 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002516 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002517 return(cur);
2518}
2519
2520/**
2521 * xmlNewDocText:
2522 * @doc: the document
2523 * @content: the text content
2524 *
2525 * Creation of a new text node within a document.
2526 * Returns a pointer to the new node object.
2527 */
2528xmlNodePtr
2529xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2530 xmlNodePtr cur;
2531
2532 cur = xmlNewText(content);
2533 if (cur != NULL) cur->doc = doc;
2534 return(cur);
2535}
2536
2537/**
2538 * xmlNewTextLen:
2539 * @content: the text content
2540 * @len: the text len.
2541 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002542 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002543 * Returns a pointer to the new node object.
2544 */
2545xmlNodePtr
2546xmlNewTextLen(const xmlChar *content, int len) {
2547 xmlNodePtr cur;
2548
2549 /*
2550 * Allocate a new node and fill the fields.
2551 */
2552 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2553 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002554 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002555 return(NULL);
2556 }
2557 memset(cur, 0, sizeof(xmlNode));
2558 cur->type = XML_TEXT_NODE;
2559
2560 cur->name = xmlStringText;
2561 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002562 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002563 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002564
Daniel Veillarda880b122003-04-21 21:36:41 +00002565 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002566 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002567 return(cur);
2568}
2569
2570/**
2571 * xmlNewDocTextLen:
2572 * @doc: the document
2573 * @content: the text content
2574 * @len: the text len.
2575 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002576 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002577 * text node pertain to a given document.
2578 * Returns a pointer to the new node object.
2579 */
2580xmlNodePtr
2581xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2582 xmlNodePtr cur;
2583
2584 cur = xmlNewTextLen(content, len);
2585 if (cur != NULL) cur->doc = doc;
2586 return(cur);
2587}
2588
2589/**
2590 * xmlNewComment:
2591 * @content: the comment content
2592 *
2593 * Creation of a new node containing a comment.
2594 * Returns a pointer to the new node object.
2595 */
2596xmlNodePtr
2597xmlNewComment(const xmlChar *content) {
2598 xmlNodePtr cur;
2599
2600 /*
2601 * Allocate a new node and fill the fields.
2602 */
2603 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2604 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002605 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002606 return(NULL);
2607 }
2608 memset(cur, 0, sizeof(xmlNode));
2609 cur->type = XML_COMMENT_NODE;
2610
2611 cur->name = xmlStringComment;
2612 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002613 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002614 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002615
Daniel Veillarda880b122003-04-21 21:36:41 +00002616 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002617 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002618 return(cur);
2619}
2620
2621/**
2622 * xmlNewCDataBlock:
2623 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002624 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002625 * @len: the length of the block
2626 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002627 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002628 * Returns a pointer to the new node object.
2629 */
2630xmlNodePtr
2631xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2632 xmlNodePtr cur;
2633
2634 /*
2635 * Allocate a new node and fill the fields.
2636 */
2637 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2638 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002639 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002640 return(NULL);
2641 }
2642 memset(cur, 0, sizeof(xmlNode));
2643 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002644 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002645
2646 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002647 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002648 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002649
Daniel Veillarda880b122003-04-21 21:36:41 +00002650 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002651 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002652 return(cur);
2653}
2654
2655/**
2656 * xmlNewDocComment:
2657 * @doc: the document
2658 * @content: the comment content
2659 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002660 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002661 * Returns a pointer to the new node object.
2662 */
2663xmlNodePtr
2664xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2665 xmlNodePtr cur;
2666
2667 cur = xmlNewComment(content);
2668 if (cur != NULL) cur->doc = doc;
2669 return(cur);
2670}
2671
2672/**
2673 * xmlSetTreeDoc:
2674 * @tree: the top element
2675 * @doc: the document
2676 *
2677 * update all nodes under the tree to point to the right document
2678 */
2679void
2680xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002681 xmlAttrPtr prop;
2682
Owen Taylor3473f882001-02-23 17:55:21 +00002683 if (tree == NULL)
2684 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002685 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002686 if(tree->type == XML_ELEMENT_NODE) {
2687 prop = tree->properties;
2688 while (prop != NULL) {
2689 prop->doc = doc;
2690 xmlSetListDoc(prop->children, doc);
2691 prop = prop->next;
2692 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002693 }
Owen Taylor3473f882001-02-23 17:55:21 +00002694 if (tree->children != NULL)
2695 xmlSetListDoc(tree->children, doc);
2696 tree->doc = doc;
2697 }
2698}
2699
2700/**
2701 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002702 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002703 * @doc: the document
2704 *
2705 * update all nodes in the list to point to the right document
2706 */
2707void
2708xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2709 xmlNodePtr cur;
2710
2711 if (list == NULL)
2712 return;
2713 cur = list;
2714 while (cur != NULL) {
2715 if (cur->doc != doc)
2716 xmlSetTreeDoc(cur, doc);
2717 cur = cur->next;
2718 }
2719}
2720
Daniel Veillard2156d432004-03-04 15:59:36 +00002721#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002722/**
2723 * xmlNewChild:
2724 * @parent: the parent node
2725 * @ns: a namespace if any
2726 * @name: the name of the child
2727 * @content: the XML content of the child if any.
2728 *
2729 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002730 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2731 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002732 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002733 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2734 * references. XML special chars must be escaped first by using
2735 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002736 *
2737 * Returns a pointer to the new node object.
2738 */
2739xmlNodePtr
2740xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2741 const xmlChar *name, const xmlChar *content) {
2742 xmlNodePtr cur, prev;
2743
2744 if (parent == NULL) {
2745#ifdef DEBUG_TREE
2746 xmlGenericError(xmlGenericErrorContext,
2747 "xmlNewChild : parent == NULL\n");
2748#endif
2749 return(NULL);
2750 }
2751
2752 if (name == NULL) {
2753#ifdef DEBUG_TREE
2754 xmlGenericError(xmlGenericErrorContext,
2755 "xmlNewChild : name == NULL\n");
2756#endif
2757 return(NULL);
2758 }
2759
2760 /*
2761 * Allocate a new node
2762 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002763 if (parent->type == XML_ELEMENT_NODE) {
2764 if (ns == NULL)
2765 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2766 else
2767 cur = xmlNewDocNode(parent->doc, ns, name, content);
2768 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2769 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2770 if (ns == NULL)
2771 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2772 else
2773 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002774 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2775 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002776 } else {
2777 return(NULL);
2778 }
Owen Taylor3473f882001-02-23 17:55:21 +00002779 if (cur == NULL) return(NULL);
2780
2781 /*
2782 * add the new element at the end of the children list.
2783 */
2784 cur->type = XML_ELEMENT_NODE;
2785 cur->parent = parent;
2786 cur->doc = parent->doc;
2787 if (parent->children == NULL) {
2788 parent->children = cur;
2789 parent->last = cur;
2790 } else {
2791 prev = parent->last;
2792 prev->next = cur;
2793 cur->prev = prev;
2794 parent->last = cur;
2795 }
2796
2797 return(cur);
2798}
Daniel Veillard652327a2003-09-29 18:02:38 +00002799#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002800
2801/**
2802 * xmlAddNextSibling:
2803 * @cur: the child node
2804 * @elem: the new node
2805 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002806 * Add a new node @elem as the next sibling of @cur
2807 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002808 * first unlinked from its existing context.
2809 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002810 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2811 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002812 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002813 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002814 */
2815xmlNodePtr
2816xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2817 if (cur == NULL) {
2818#ifdef DEBUG_TREE
2819 xmlGenericError(xmlGenericErrorContext,
2820 "xmlAddNextSibling : cur == NULL\n");
2821#endif
2822 return(NULL);
2823 }
2824 if (elem == NULL) {
2825#ifdef DEBUG_TREE
2826 xmlGenericError(xmlGenericErrorContext,
2827 "xmlAddNextSibling : elem == NULL\n");
2828#endif
2829 return(NULL);
2830 }
2831
2832 xmlUnlinkNode(elem);
2833
2834 if (elem->type == XML_TEXT_NODE) {
2835 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002836 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002837 xmlFreeNode(elem);
2838 return(cur);
2839 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002840 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2841 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002842 xmlChar *tmp;
2843
2844 tmp = xmlStrdup(elem->content);
2845 tmp = xmlStrcat(tmp, cur->next->content);
2846 xmlNodeSetContent(cur->next, tmp);
2847 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002848 xmlFreeNode(elem);
2849 return(cur->next);
2850 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002851 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2852 /* check if an attribute with the same name exists */
2853 xmlAttrPtr attr;
2854
2855 if (elem->ns == NULL)
2856 attr = xmlHasProp(cur->parent, elem->name);
2857 else
2858 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2859 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2860 /* different instance, destroy it (attributes must be unique) */
2861 xmlFreeProp(attr);
2862 }
Owen Taylor3473f882001-02-23 17:55:21 +00002863 }
2864
2865 if (elem->doc != cur->doc) {
2866 xmlSetTreeDoc(elem, cur->doc);
2867 }
2868 elem->parent = cur->parent;
2869 elem->prev = cur;
2870 elem->next = cur->next;
2871 cur->next = elem;
2872 if (elem->next != NULL)
2873 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002874 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002875 elem->parent->last = elem;
2876 return(elem);
2877}
2878
Daniel Veillard2156d432004-03-04 15:59:36 +00002879#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002880/**
2881 * xmlAddPrevSibling:
2882 * @cur: the child node
2883 * @elem: the new node
2884 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002885 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002886 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002887 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002888 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002889 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2890 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002891 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002892 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002893 */
2894xmlNodePtr
2895xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2896 if (cur == NULL) {
2897#ifdef DEBUG_TREE
2898 xmlGenericError(xmlGenericErrorContext,
2899 "xmlAddPrevSibling : cur == NULL\n");
2900#endif
2901 return(NULL);
2902 }
2903 if (elem == NULL) {
2904#ifdef DEBUG_TREE
2905 xmlGenericError(xmlGenericErrorContext,
2906 "xmlAddPrevSibling : elem == NULL\n");
2907#endif
2908 return(NULL);
2909 }
2910
2911 xmlUnlinkNode(elem);
2912
2913 if (elem->type == XML_TEXT_NODE) {
2914 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002915 xmlChar *tmp;
2916
2917 tmp = xmlStrdup(elem->content);
2918 tmp = xmlStrcat(tmp, cur->content);
2919 xmlNodeSetContent(cur, tmp);
2920 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002921 xmlFreeNode(elem);
2922 return(cur);
2923 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002924 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2925 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002926 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002927 xmlFreeNode(elem);
2928 return(cur->prev);
2929 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002930 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2931 /* check if an attribute with the same name exists */
2932 xmlAttrPtr attr;
2933
2934 if (elem->ns == NULL)
2935 attr = xmlHasProp(cur->parent, elem->name);
2936 else
2937 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2938 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2939 /* different instance, destroy it (attributes must be unique) */
2940 xmlFreeProp(attr);
2941 }
Owen Taylor3473f882001-02-23 17:55:21 +00002942 }
2943
2944 if (elem->doc != cur->doc) {
2945 xmlSetTreeDoc(elem, cur->doc);
2946 }
2947 elem->parent = cur->parent;
2948 elem->next = cur;
2949 elem->prev = cur->prev;
2950 cur->prev = elem;
2951 if (elem->prev != NULL)
2952 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002953 if (elem->parent != NULL) {
2954 if (elem->type == XML_ATTRIBUTE_NODE) {
2955 if (elem->parent->properties == (xmlAttrPtr) cur) {
2956 elem->parent->properties = (xmlAttrPtr) elem;
2957 }
2958 } else {
2959 if (elem->parent->children == cur) {
2960 elem->parent->children = elem;
2961 }
2962 }
2963 }
Owen Taylor3473f882001-02-23 17:55:21 +00002964 return(elem);
2965}
Daniel Veillard652327a2003-09-29 18:02:38 +00002966#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002967
2968/**
2969 * xmlAddSibling:
2970 * @cur: the child node
2971 * @elem: the new node
2972 *
2973 * Add a new element @elem to the list of siblings of @cur
2974 * merging adjacent TEXT nodes (@elem may be freed)
2975 * If the new element was already inserted in a document it is
2976 * first unlinked from its existing context.
2977 *
2978 * Returns the new element or NULL in case of error.
2979 */
2980xmlNodePtr
2981xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2982 xmlNodePtr parent;
2983
2984 if (cur == NULL) {
2985#ifdef DEBUG_TREE
2986 xmlGenericError(xmlGenericErrorContext,
2987 "xmlAddSibling : cur == NULL\n");
2988#endif
2989 return(NULL);
2990 }
2991
2992 if (elem == NULL) {
2993#ifdef DEBUG_TREE
2994 xmlGenericError(xmlGenericErrorContext,
2995 "xmlAddSibling : elem == NULL\n");
2996#endif
2997 return(NULL);
2998 }
2999
3000 /*
3001 * Constant time is we can rely on the ->parent->last to find
3002 * the last sibling.
3003 */
3004 if ((cur->parent != NULL) &&
3005 (cur->parent->children != NULL) &&
3006 (cur->parent->last != NULL) &&
3007 (cur->parent->last->next == NULL)) {
3008 cur = cur->parent->last;
3009 } else {
3010 while (cur->next != NULL) cur = cur->next;
3011 }
3012
3013 xmlUnlinkNode(elem);
3014
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003015 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3016 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003017 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003018 xmlFreeNode(elem);
3019 return(cur);
3020 }
3021
3022 if (elem->doc != cur->doc) {
3023 xmlSetTreeDoc(elem, cur->doc);
3024 }
3025 parent = cur->parent;
3026 elem->prev = cur;
3027 elem->next = NULL;
3028 elem->parent = parent;
3029 cur->next = elem;
3030 if (parent != NULL)
3031 parent->last = elem;
3032
3033 return(elem);
3034}
3035
3036/**
3037 * xmlAddChildList:
3038 * @parent: the parent node
3039 * @cur: the first node in the list
3040 *
3041 * Add a list of node at the end of the child list of the parent
3042 * merging adjacent TEXT nodes (@cur may be freed)
3043 *
3044 * Returns the last child or NULL in case of error.
3045 */
3046xmlNodePtr
3047xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3048 xmlNodePtr prev;
3049
3050 if (parent == NULL) {
3051#ifdef DEBUG_TREE
3052 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003053 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003054#endif
3055 return(NULL);
3056 }
3057
3058 if (cur == NULL) {
3059#ifdef DEBUG_TREE
3060 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003061 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003062#endif
3063 return(NULL);
3064 }
3065
3066 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3067 (cur->doc != parent->doc)) {
3068#ifdef DEBUG_TREE
3069 xmlGenericError(xmlGenericErrorContext,
3070 "Elements moved to a different document\n");
3071#endif
3072 }
3073
3074 /*
3075 * add the first element at the end of the children list.
3076 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003077
Owen Taylor3473f882001-02-23 17:55:21 +00003078 if (parent->children == NULL) {
3079 parent->children = cur;
3080 } else {
3081 /*
3082 * If cur and parent->last both are TEXT nodes, then merge them.
3083 */
3084 if ((cur->type == XML_TEXT_NODE) &&
3085 (parent->last->type == XML_TEXT_NODE) &&
3086 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003087 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003088 /*
3089 * if it's the only child, nothing more to be done.
3090 */
3091 if (cur->next == NULL) {
3092 xmlFreeNode(cur);
3093 return(parent->last);
3094 }
3095 prev = cur;
3096 cur = cur->next;
3097 xmlFreeNode(prev);
3098 }
3099 prev = parent->last;
3100 prev->next = cur;
3101 cur->prev = prev;
3102 }
3103 while (cur->next != NULL) {
3104 cur->parent = parent;
3105 if (cur->doc != parent->doc) {
3106 xmlSetTreeDoc(cur, parent->doc);
3107 }
3108 cur = cur->next;
3109 }
3110 cur->parent = parent;
3111 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3112 parent->last = cur;
3113
3114 return(cur);
3115}
3116
3117/**
3118 * xmlAddChild:
3119 * @parent: the parent node
3120 * @cur: the child node
3121 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003122 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003123 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003124 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3125 * If there is an attribute with equal name, it is first destroyed.
3126 *
Owen Taylor3473f882001-02-23 17:55:21 +00003127 * Returns the child or NULL in case of error.
3128 */
3129xmlNodePtr
3130xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3131 xmlNodePtr prev;
3132
3133 if (parent == NULL) {
3134#ifdef DEBUG_TREE
3135 xmlGenericError(xmlGenericErrorContext,
3136 "xmlAddChild : parent == NULL\n");
3137#endif
3138 return(NULL);
3139 }
3140
3141 if (cur == NULL) {
3142#ifdef DEBUG_TREE
3143 xmlGenericError(xmlGenericErrorContext,
3144 "xmlAddChild : child == NULL\n");
3145#endif
3146 return(NULL);
3147 }
3148
Owen Taylor3473f882001-02-23 17:55:21 +00003149 /*
3150 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003151 * cur is then freed.
3152 */
3153 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003154 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003155 (parent->content != NULL) &&
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003156 (parent->name == cur->name) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003157 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003158 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003159 xmlFreeNode(cur);
3160 return(parent);
3161 }
3162 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003163 (parent->last->name == cur->name) &&
3164 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003165 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003166 xmlFreeNode(cur);
3167 return(parent->last);
3168 }
3169 }
3170
3171 /*
3172 * add the new element at the end of the children list.
3173 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003174 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003175 cur->parent = parent;
3176 if (cur->doc != parent->doc) {
3177 xmlSetTreeDoc(cur, parent->doc);
3178 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003179 /* this check prevents a loop on tree-traversions if a developer
3180 * tries to add a node to its parent multiple times
3181 */
3182 if (prev == parent)
3183 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003184
3185 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003186 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003187 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003188 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003189 (parent->content != NULL) &&
3190 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003191 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003192 xmlFreeNode(cur);
3193 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003194 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003195 if (cur->type == XML_ATTRIBUTE_NODE) {
3196 if (parent->properties == NULL) {
3197 parent->properties = (xmlAttrPtr) cur;
3198 } else {
3199 /* check if an attribute with the same name exists */
3200 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003201
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003202 if (cur->ns == NULL)
3203 lastattr = xmlHasProp(parent, cur->name);
3204 else
3205 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3206 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3207 /* different instance, destroy it (attributes must be unique) */
3208 xmlFreeProp(lastattr);
3209 }
3210 /* find the end */
3211 lastattr = parent->properties;
3212 while (lastattr->next != NULL) {
3213 lastattr = lastattr->next;
3214 }
3215 lastattr->next = (xmlAttrPtr) cur;
3216 ((xmlAttrPtr) cur)->prev = lastattr;
3217 }
3218 } else {
3219 if (parent->children == NULL) {
3220 parent->children = cur;
3221 parent->last = cur;
3222 } else {
3223 prev = parent->last;
3224 prev->next = cur;
3225 cur->prev = prev;
3226 parent->last = cur;
3227 }
3228 }
Owen Taylor3473f882001-02-23 17:55:21 +00003229 return(cur);
3230}
3231
3232/**
3233 * xmlGetLastChild:
3234 * @parent: the parent node
3235 *
3236 * Search the last child of a node.
3237 * Returns the last child or NULL if none.
3238 */
3239xmlNodePtr
3240xmlGetLastChild(xmlNodePtr parent) {
3241 if (parent == NULL) {
3242#ifdef DEBUG_TREE
3243 xmlGenericError(xmlGenericErrorContext,
3244 "xmlGetLastChild : parent == NULL\n");
3245#endif
3246 return(NULL);
3247 }
3248 return(parent->last);
3249}
3250
3251/**
3252 * xmlFreeNodeList:
3253 * @cur: the first node in the list
3254 *
3255 * Free a node and all its siblings, this is a recursive behaviour, all
3256 * the children are freed too.
3257 */
3258void
3259xmlFreeNodeList(xmlNodePtr cur) {
3260 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003261 xmlDictPtr dict = NULL;
3262
3263 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003264 if (cur->type == XML_NAMESPACE_DECL) {
3265 xmlFreeNsList((xmlNsPtr) cur);
3266 return;
3267 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003268 if ((cur->type == XML_DOCUMENT_NODE) ||
3269#ifdef LIBXML_DOCB_ENABLED
3270 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003271#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003272 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003273 xmlFreeDoc((xmlDocPtr) cur);
3274 return;
3275 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003276 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003277 while (cur != NULL) {
3278 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003279 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003280
Daniel Veillarda880b122003-04-21 21:36:41 +00003281 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003282 xmlDeregisterNodeDefaultValue(cur);
3283
Daniel Veillard02141ea2001-04-30 11:46:40 +00003284 if ((cur->children != NULL) &&
3285 (cur->type != XML_ENTITY_REF_NODE))
3286 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003287 if (((cur->type == XML_ELEMENT_NODE) ||
3288 (cur->type == XML_XINCLUDE_START) ||
3289 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003290 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003291 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003292 if ((cur->type != XML_ELEMENT_NODE) &&
3293 (cur->type != XML_XINCLUDE_START) &&
3294 (cur->type != XML_XINCLUDE_END) &&
3295 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003296 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003297 }
3298 if (((cur->type == XML_ELEMENT_NODE) ||
3299 (cur->type == XML_XINCLUDE_START) ||
3300 (cur->type == XML_XINCLUDE_END)) &&
3301 (cur->nsDef != NULL))
3302 xmlFreeNsList(cur->nsDef);
3303
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003304 /*
3305 * When a node is a text node or a comment, it uses a global static
3306 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003307 * Otherwise the node name might come from the document's
3308 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003309 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003310 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003311 (cur->type != XML_TEXT_NODE) &&
3312 (cur->type != XML_COMMENT_NODE))
3313 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003314 xmlFree(cur);
3315 }
Owen Taylor3473f882001-02-23 17:55:21 +00003316 cur = next;
3317 }
3318}
3319
3320/**
3321 * xmlFreeNode:
3322 * @cur: the node
3323 *
3324 * Free a node, this is a recursive behaviour, all the children are freed too.
3325 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3326 */
3327void
3328xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003329 xmlDictPtr dict = NULL;
3330
3331 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003332
Daniel Veillard02141ea2001-04-30 11:46:40 +00003333 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003334 if (cur->type == XML_DTD_NODE) {
3335 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003336 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003337 }
3338 if (cur->type == XML_NAMESPACE_DECL) {
3339 xmlFreeNs((xmlNsPtr) cur);
3340 return;
3341 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003342 if (cur->type == XML_ATTRIBUTE_NODE) {
3343 xmlFreeProp((xmlAttrPtr) cur);
3344 return;
3345 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003346
Daniel Veillarda880b122003-04-21 21:36:41 +00003347 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003348 xmlDeregisterNodeDefaultValue(cur);
3349
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003350 if (cur->doc != NULL) dict = cur->doc->dict;
3351
Owen Taylor3473f882001-02-23 17:55:21 +00003352 if ((cur->children != NULL) &&
3353 (cur->type != XML_ENTITY_REF_NODE))
3354 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003355 if (((cur->type == XML_ELEMENT_NODE) ||
3356 (cur->type == XML_XINCLUDE_START) ||
3357 (cur->type == XML_XINCLUDE_END)) &&
3358 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003359 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003360 if ((cur->type != XML_ELEMENT_NODE) &&
3361 (cur->content != NULL) &&
3362 (cur->type != XML_ENTITY_REF_NODE) &&
3363 (cur->type != XML_XINCLUDE_END) &&
3364 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003365 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003366 }
3367
Daniel Veillardacd370f2001-06-09 17:17:51 +00003368 /*
3369 * When a node is a text node or a comment, it uses a global static
3370 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003371 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003372 */
Owen Taylor3473f882001-02-23 17:55:21 +00003373 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003374 (cur->type != XML_TEXT_NODE) &&
3375 (cur->type != XML_COMMENT_NODE))
3376 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003377
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003378 if (((cur->type == XML_ELEMENT_NODE) ||
3379 (cur->type == XML_XINCLUDE_START) ||
3380 (cur->type == XML_XINCLUDE_END)) &&
3381 (cur->nsDef != NULL))
3382 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003383 xmlFree(cur);
3384}
3385
3386/**
3387 * xmlUnlinkNode:
3388 * @cur: the node
3389 *
3390 * Unlink a node from it's current context, the node is not freed
3391 */
3392void
3393xmlUnlinkNode(xmlNodePtr cur) {
3394 if (cur == NULL) {
3395#ifdef DEBUG_TREE
3396 xmlGenericError(xmlGenericErrorContext,
3397 "xmlUnlinkNode : node == NULL\n");
3398#endif
3399 return;
3400 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003401 if (cur->type == XML_DTD_NODE) {
3402 xmlDocPtr doc;
3403 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003404 if (doc != NULL) {
3405 if (doc->intSubset == (xmlDtdPtr) cur)
3406 doc->intSubset = NULL;
3407 if (doc->extSubset == (xmlDtdPtr) cur)
3408 doc->extSubset = NULL;
3409 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003410 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003411 if (cur->parent != NULL) {
3412 xmlNodePtr parent;
3413 parent = cur->parent;
3414 if (cur->type == XML_ATTRIBUTE_NODE) {
3415 if (parent->properties == (xmlAttrPtr) cur)
3416 parent->properties = ((xmlAttrPtr) cur)->next;
3417 } else {
3418 if (parent->children == cur)
3419 parent->children = cur->next;
3420 if (parent->last == cur)
3421 parent->last = cur->prev;
3422 }
3423 cur->parent = NULL;
3424 }
Owen Taylor3473f882001-02-23 17:55:21 +00003425 if (cur->next != NULL)
3426 cur->next->prev = cur->prev;
3427 if (cur->prev != NULL)
3428 cur->prev->next = cur->next;
3429 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003430}
3431
Daniel Veillard2156d432004-03-04 15:59:36 +00003432#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003433/**
3434 * xmlReplaceNode:
3435 * @old: the old node
3436 * @cur: the node
3437 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003438 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003439 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003440 * first unlinked from its existing context.
3441 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003442 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003443 */
3444xmlNodePtr
3445xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3446 if (old == NULL) {
3447#ifdef DEBUG_TREE
3448 xmlGenericError(xmlGenericErrorContext,
3449 "xmlReplaceNode : old == NULL\n");
3450#endif
3451 return(NULL);
3452 }
3453 if (cur == NULL) {
3454 xmlUnlinkNode(old);
3455 return(old);
3456 }
3457 if (cur == old) {
3458 return(old);
3459 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003460 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3461#ifdef DEBUG_TREE
3462 xmlGenericError(xmlGenericErrorContext,
3463 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3464#endif
3465 return(old);
3466 }
3467 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3468#ifdef DEBUG_TREE
3469 xmlGenericError(xmlGenericErrorContext,
3470 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3471#endif
3472 return(old);
3473 }
Owen Taylor3473f882001-02-23 17:55:21 +00003474 xmlUnlinkNode(cur);
3475 cur->doc = old->doc;
3476 cur->parent = old->parent;
3477 cur->next = old->next;
3478 if (cur->next != NULL)
3479 cur->next->prev = cur;
3480 cur->prev = old->prev;
3481 if (cur->prev != NULL)
3482 cur->prev->next = cur;
3483 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003484 if (cur->type == XML_ATTRIBUTE_NODE) {
3485 if (cur->parent->properties == (xmlAttrPtr)old)
3486 cur->parent->properties = ((xmlAttrPtr) cur);
3487 } else {
3488 if (cur->parent->children == old)
3489 cur->parent->children = cur;
3490 if (cur->parent->last == old)
3491 cur->parent->last = cur;
3492 }
Owen Taylor3473f882001-02-23 17:55:21 +00003493 }
3494 old->next = old->prev = NULL;
3495 old->parent = NULL;
3496 return(old);
3497}
Daniel Veillard652327a2003-09-29 18:02:38 +00003498#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003499
3500/************************************************************************
3501 * *
3502 * Copy operations *
3503 * *
3504 ************************************************************************/
3505
3506/**
3507 * xmlCopyNamespace:
3508 * @cur: the namespace
3509 *
3510 * Do a copy of the namespace.
3511 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003512 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003513 */
3514xmlNsPtr
3515xmlCopyNamespace(xmlNsPtr cur) {
3516 xmlNsPtr ret;
3517
3518 if (cur == NULL) return(NULL);
3519 switch (cur->type) {
3520 case XML_LOCAL_NAMESPACE:
3521 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3522 break;
3523 default:
3524#ifdef DEBUG_TREE
3525 xmlGenericError(xmlGenericErrorContext,
3526 "xmlCopyNamespace: invalid type %d\n", cur->type);
3527#endif
3528 return(NULL);
3529 }
3530 return(ret);
3531}
3532
3533/**
3534 * xmlCopyNamespaceList:
3535 * @cur: the first namespace
3536 *
3537 * Do a copy of an namespace list.
3538 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003539 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003540 */
3541xmlNsPtr
3542xmlCopyNamespaceList(xmlNsPtr cur) {
3543 xmlNsPtr ret = NULL;
3544 xmlNsPtr p = NULL,q;
3545
3546 while (cur != NULL) {
3547 q = xmlCopyNamespace(cur);
3548 if (p == NULL) {
3549 ret = p = q;
3550 } else {
3551 p->next = q;
3552 p = q;
3553 }
3554 cur = cur->next;
3555 }
3556 return(ret);
3557}
3558
3559static xmlNodePtr
3560xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3561/**
3562 * xmlCopyProp:
3563 * @target: the element where the attribute will be grafted
3564 * @cur: the attribute
3565 *
3566 * Do a copy of the attribute.
3567 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003568 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003569 */
3570xmlAttrPtr
3571xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3572 xmlAttrPtr ret;
3573
3574 if (cur == NULL) return(NULL);
3575 if (target != NULL)
3576 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3577 else if (cur->parent != NULL)
3578 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3579 else if (cur->children != NULL)
3580 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3581 else
3582 ret = xmlNewDocProp(NULL, cur->name, NULL);
3583 if (ret == NULL) return(NULL);
3584 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003585
Owen Taylor3473f882001-02-23 17:55:21 +00003586 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003587 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003588
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003589 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3590 if (ns == NULL) {
3591 /*
3592 * Humm, we are copying an element whose namespace is defined
3593 * out of the new tree scope. Search it in the original tree
3594 * and add it at the top of the new tree
3595 */
3596 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3597 if (ns != NULL) {
3598 xmlNodePtr root = target;
3599 xmlNodePtr pred = NULL;
3600
3601 while (root->parent != NULL) {
3602 pred = root;
3603 root = root->parent;
3604 }
3605 if (root == (xmlNodePtr) target->doc) {
3606 /* correct possibly cycling above the document elt */
3607 root = pred;
3608 }
3609 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3610 }
3611 } else {
3612 /*
3613 * we have to find something appropriate here since
3614 * we cant be sure, that the namespce we found is identified
3615 * by the prefix
3616 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003617 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003618 /* this is the nice case */
3619 ret->ns = ns;
3620 } else {
3621 /*
3622 * we are in trouble: we need a new reconcilied namespace.
3623 * This is expensive
3624 */
3625 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3626 }
3627 }
3628
Owen Taylor3473f882001-02-23 17:55:21 +00003629 } else
3630 ret->ns = NULL;
3631
3632 if (cur->children != NULL) {
3633 xmlNodePtr tmp;
3634
3635 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3636 ret->last = NULL;
3637 tmp = ret->children;
3638 while (tmp != NULL) {
3639 /* tmp->parent = (xmlNodePtr)ret; */
3640 if (tmp->next == NULL)
3641 ret->last = tmp;
3642 tmp = tmp->next;
3643 }
3644 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003645 /*
3646 * Try to handle IDs
3647 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003648 if ((target!= NULL) && (cur!= NULL) &&
3649 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003650 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3651 if (xmlIsID(cur->doc, cur->parent, cur)) {
3652 xmlChar *id;
3653
3654 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3655 if (id != NULL) {
3656 xmlAddID(NULL, target->doc, id, ret);
3657 xmlFree(id);
3658 }
3659 }
3660 }
Owen Taylor3473f882001-02-23 17:55:21 +00003661 return(ret);
3662}
3663
3664/**
3665 * xmlCopyPropList:
3666 * @target: the element where the attributes will be grafted
3667 * @cur: the first attribute
3668 *
3669 * Do a copy of an attribute list.
3670 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003671 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003672 */
3673xmlAttrPtr
3674xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3675 xmlAttrPtr ret = NULL;
3676 xmlAttrPtr p = NULL,q;
3677
3678 while (cur != NULL) {
3679 q = xmlCopyProp(target, cur);
3680 if (p == NULL) {
3681 ret = p = q;
3682 } else {
3683 p->next = q;
3684 q->prev = p;
3685 p = q;
3686 }
3687 cur = cur->next;
3688 }
3689 return(ret);
3690}
3691
3692/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003693 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003694 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003695 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003696 * tricky reason: namespaces. Doing a direct copy of a node
3697 * say RPM:Copyright without changing the namespace pointer to
3698 * something else can produce stale links. One way to do it is
3699 * to keep a reference counter but this doesn't work as soon
3700 * as one move the element or the subtree out of the scope of
3701 * the existing namespace. The actual solution seems to add
3702 * a copy of the namespace at the top of the copied tree if
3703 * not available in the subtree.
3704 * Hence two functions, the public front-end call the inner ones
3705 */
3706
3707static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003708xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003709 int recursive) {
3710 xmlNodePtr ret;
3711
3712 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003713 switch (node->type) {
3714 case XML_TEXT_NODE:
3715 case XML_CDATA_SECTION_NODE:
3716 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003717 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003718 case XML_ENTITY_REF_NODE:
3719 case XML_ENTITY_NODE:
3720 case XML_PI_NODE:
3721 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003722 case XML_XINCLUDE_START:
3723 case XML_XINCLUDE_END:
3724 break;
3725 case XML_ATTRIBUTE_NODE:
3726 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3727 case XML_NAMESPACE_DECL:
3728 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3729
Daniel Veillard39196eb2001-06-19 18:09:42 +00003730 case XML_DOCUMENT_NODE:
3731 case XML_HTML_DOCUMENT_NODE:
3732#ifdef LIBXML_DOCB_ENABLED
3733 case XML_DOCB_DOCUMENT_NODE:
3734#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003735#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003736 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard652327a2003-09-29 18:02:38 +00003737#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003738 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003739 case XML_NOTATION_NODE:
3740 case XML_DTD_NODE:
3741 case XML_ELEMENT_DECL:
3742 case XML_ATTRIBUTE_DECL:
3743 case XML_ENTITY_DECL:
3744 return(NULL);
3745 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003746
Owen Taylor3473f882001-02-23 17:55:21 +00003747 /*
3748 * Allocate a new node and fill the fields.
3749 */
3750 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3751 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003752 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003753 return(NULL);
3754 }
3755 memset(ret, 0, sizeof(xmlNode));
3756 ret->type = node->type;
3757
3758 ret->doc = doc;
3759 ret->parent = parent;
3760 if (node->name == xmlStringText)
3761 ret->name = xmlStringText;
3762 else if (node->name == xmlStringTextNoenc)
3763 ret->name = xmlStringTextNoenc;
3764 else if (node->name == xmlStringComment)
3765 ret->name = xmlStringComment;
3766 else if (node->name != NULL)
3767 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003768 if ((node->type != XML_ELEMENT_NODE) &&
3769 (node->content != NULL) &&
3770 (node->type != XML_ENTITY_REF_NODE) &&
3771 (node->type != XML_XINCLUDE_END) &&
3772 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003773 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003774 }else{
3775 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003776 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003777 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003778 if (parent != NULL) {
3779 xmlNodePtr tmp;
3780
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003781 /*
3782 * this is a tricky part for the node register thing:
3783 * in case ret does get coalesced in xmlAddChild
3784 * the deregister-node callback is called; so we register ret now already
3785 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003786 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003787 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3788
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003789 tmp = xmlAddChild(parent, ret);
3790 /* node could have coalesced */
3791 if (tmp != ret)
3792 return(tmp);
3793 }
Owen Taylor3473f882001-02-23 17:55:21 +00003794
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003795 if (!recursive)
3796 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003797 if (node->nsDef != NULL)
3798 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3799
3800 if (node->ns != NULL) {
3801 xmlNsPtr ns;
3802
3803 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3804 if (ns == NULL) {
3805 /*
3806 * Humm, we are copying an element whose namespace is defined
3807 * out of the new tree scope. Search it in the original tree
3808 * and add it at the top of the new tree
3809 */
3810 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3811 if (ns != NULL) {
3812 xmlNodePtr root = ret;
3813
3814 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003815 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003816 }
3817 } else {
3818 /*
3819 * reference the existing namespace definition in our own tree.
3820 */
3821 ret->ns = ns;
3822 }
3823 }
3824 if (node->properties != NULL)
3825 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003826 if (node->type == XML_ENTITY_REF_NODE) {
3827 if ((doc == NULL) || (node->doc != doc)) {
3828 /*
3829 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003830 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003831 * we cannot keep the reference. Try to find it in the
3832 * target document.
3833 */
3834 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3835 } else {
3836 ret->children = node->children;
3837 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003838 ret->last = ret->children;
3839 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003840 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003841 UPDATE_LAST_CHILD_AND_PARENT(ret)
3842 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003843
3844out:
3845 /* if parent != NULL we already registered the node above */
3846 if (parent == NULL && xmlRegisterNodeDefaultValue)
3847 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003848 return(ret);
3849}
3850
3851static xmlNodePtr
3852xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3853 xmlNodePtr ret = NULL;
3854 xmlNodePtr p = NULL,q;
3855
3856 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003857#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003858 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003859 if (doc == NULL) {
3860 node = node->next;
3861 continue;
3862 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003863 if (doc->intSubset == NULL) {
3864 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3865 q->doc = doc;
3866 q->parent = parent;
3867 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003868 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003869 } else {
3870 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003871 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003872 }
3873 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003874#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003875 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003876 if (ret == NULL) {
3877 q->prev = NULL;
3878 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003879 } else if (p != q) {
3880 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003881 p->next = q;
3882 q->prev = p;
3883 p = q;
3884 }
3885 node = node->next;
3886 }
3887 return(ret);
3888}
3889
3890/**
3891 * xmlCopyNode:
3892 * @node: the node
3893 * @recursive: if 1 do a recursive copy.
3894 *
3895 * Do a copy of the node.
3896 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003897 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003898 */
3899xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003900xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003901 xmlNodePtr ret;
3902
3903 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3904 return(ret);
3905}
3906
3907/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003908 * xmlDocCopyNode:
3909 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003910 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003911 * @recursive: if 1 do a recursive copy.
3912 *
3913 * Do a copy of the node to a given document.
3914 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003915 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003916 */
3917xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003918xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003919 xmlNodePtr ret;
3920
3921 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3922 return(ret);
3923}
3924
3925/**
Owen Taylor3473f882001-02-23 17:55:21 +00003926 * xmlCopyNodeList:
3927 * @node: the first node in the list.
3928 *
3929 * Do a recursive copy of the node list.
3930 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003931 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003932 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003933xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003934 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3935 return(ret);
3936}
3937
Daniel Veillard2156d432004-03-04 15:59:36 +00003938#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003939/**
Owen Taylor3473f882001-02-23 17:55:21 +00003940 * xmlCopyDtd:
3941 * @dtd: the dtd
3942 *
3943 * Do a copy of the dtd.
3944 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003945 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003946 */
3947xmlDtdPtr
3948xmlCopyDtd(xmlDtdPtr dtd) {
3949 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003950 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003951
3952 if (dtd == NULL) return(NULL);
3953 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3954 if (ret == NULL) return(NULL);
3955 if (dtd->entities != NULL)
3956 ret->entities = (void *) xmlCopyEntitiesTable(
3957 (xmlEntitiesTablePtr) dtd->entities);
3958 if (dtd->notations != NULL)
3959 ret->notations = (void *) xmlCopyNotationTable(
3960 (xmlNotationTablePtr) dtd->notations);
3961 if (dtd->elements != NULL)
3962 ret->elements = (void *) xmlCopyElementTable(
3963 (xmlElementTablePtr) dtd->elements);
3964 if (dtd->attributes != NULL)
3965 ret->attributes = (void *) xmlCopyAttributeTable(
3966 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003967 if (dtd->pentities != NULL)
3968 ret->pentities = (void *) xmlCopyEntitiesTable(
3969 (xmlEntitiesTablePtr) dtd->pentities);
3970
3971 cur = dtd->children;
3972 while (cur != NULL) {
3973 q = NULL;
3974
3975 if (cur->type == XML_ENTITY_DECL) {
3976 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3977 switch (tmp->etype) {
3978 case XML_INTERNAL_GENERAL_ENTITY:
3979 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3980 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3981 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3982 break;
3983 case XML_INTERNAL_PARAMETER_ENTITY:
3984 case XML_EXTERNAL_PARAMETER_ENTITY:
3985 q = (xmlNodePtr)
3986 xmlGetParameterEntityFromDtd(ret, tmp->name);
3987 break;
3988 case XML_INTERNAL_PREDEFINED_ENTITY:
3989 break;
3990 }
3991 } else if (cur->type == XML_ELEMENT_DECL) {
3992 xmlElementPtr tmp = (xmlElementPtr) cur;
3993 q = (xmlNodePtr)
3994 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3995 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3996 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3997 q = (xmlNodePtr)
3998 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3999 } else if (cur->type == XML_COMMENT_NODE) {
4000 q = xmlCopyNode(cur, 0);
4001 }
4002
4003 if (q == NULL) {
4004 cur = cur->next;
4005 continue;
4006 }
4007
4008 if (p == NULL)
4009 ret->children = q;
4010 else
4011 p->next = q;
4012
4013 q->prev = p;
4014 q->parent = (xmlNodePtr) ret;
4015 q->next = NULL;
4016 ret->last = q;
4017 p = q;
4018 cur = cur->next;
4019 }
4020
Owen Taylor3473f882001-02-23 17:55:21 +00004021 return(ret);
4022}
Daniel Veillard2156d432004-03-04 15:59:36 +00004023#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004024
Daniel Veillard2156d432004-03-04 15:59:36 +00004025#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004026/**
4027 * xmlCopyDoc:
4028 * @doc: the document
4029 * @recursive: if 1 do a recursive copy.
4030 *
4031 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004032 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004033 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004034 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004035 */
4036xmlDocPtr
4037xmlCopyDoc(xmlDocPtr doc, int recursive) {
4038 xmlDocPtr ret;
4039
4040 if (doc == NULL) return(NULL);
4041 ret = xmlNewDoc(doc->version);
4042 if (ret == NULL) return(NULL);
4043 if (doc->name != NULL)
4044 ret->name = xmlMemStrdup(doc->name);
4045 if (doc->encoding != NULL)
4046 ret->encoding = xmlStrdup(doc->encoding);
4047 ret->charset = doc->charset;
4048 ret->compression = doc->compression;
4049 ret->standalone = doc->standalone;
4050 if (!recursive) return(ret);
4051
Daniel Veillardb33c2012001-04-25 12:59:04 +00004052 ret->last = NULL;
4053 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004054#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004055 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004056 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004057 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004058 ret->intSubset->parent = ret;
4059 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004060#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004061 if (doc->oldNs != NULL)
4062 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4063 if (doc->children != NULL) {
4064 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004065
4066 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4067 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004068 ret->last = NULL;
4069 tmp = ret->children;
4070 while (tmp != NULL) {
4071 if (tmp->next == NULL)
4072 ret->last = tmp;
4073 tmp = tmp->next;
4074 }
4075 }
4076 return(ret);
4077}
Daniel Veillard652327a2003-09-29 18:02:38 +00004078#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004079
4080/************************************************************************
4081 * *
4082 * Content access functions *
4083 * *
4084 ************************************************************************/
4085
4086/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004087 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004088 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004089 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004090 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004091 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004092 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004093 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004094 */
4095long
4096xmlGetLineNo(xmlNodePtr node)
4097{
4098 long result = -1;
4099
4100 if (!node)
4101 return result;
4102 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004103 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004104 else if ((node->prev != NULL) &&
4105 ((node->prev->type == XML_ELEMENT_NODE) ||
4106 (node->prev->type == XML_TEXT_NODE)))
4107 result = xmlGetLineNo(node->prev);
4108 else if ((node->parent != NULL) &&
4109 ((node->parent->type == XML_ELEMENT_NODE) ||
4110 (node->parent->type == XML_TEXT_NODE)))
4111 result = xmlGetLineNo(node->parent);
4112
4113 return result;
4114}
4115
Daniel Veillard2156d432004-03-04 15:59:36 +00004116#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004117/**
4118 * xmlGetNodePath:
4119 * @node: a node
4120 *
4121 * Build a structure based Path for the given node
4122 *
4123 * Returns the new path or NULL in case of error. The caller must free
4124 * the returned string
4125 */
4126xmlChar *
4127xmlGetNodePath(xmlNodePtr node)
4128{
4129 xmlNodePtr cur, tmp, next;
4130 xmlChar *buffer = NULL, *temp;
4131 size_t buf_len;
4132 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004133 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004134 const char *name;
4135 char nametemp[100];
4136 int occur = 0;
4137
4138 if (node == NULL)
4139 return (NULL);
4140
4141 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004142 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004143 if (buffer == NULL) {
4144 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004145 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004146 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004147 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004148 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004149 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004150 xmlFree(buffer);
4151 return (NULL);
4152 }
4153
4154 buffer[0] = 0;
4155 cur = node;
4156 do {
4157 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004158 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004159 occur = 0;
4160 if ((cur->type == XML_DOCUMENT_NODE) ||
4161 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4162 if (buffer[0] == '/')
4163 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004164 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004165 next = NULL;
4166 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004167 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004168 name = (const char *) cur->name;
4169 if (cur->ns) {
William M. Brack84d83e32003-12-23 03:45:17 +00004170 if (cur->ns->prefix != NULL)
4171 snprintf(nametemp, sizeof(nametemp) - 1,
Daniel Veillard8faa7832001-11-26 15:58:08 +00004172 "%s:%s", cur->ns->prefix, cur->name);
William M. Brack84d83e32003-12-23 03:45:17 +00004173 else
4174 snprintf(nametemp, sizeof(nametemp) - 1,
4175 "%s", cur->name);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004176 nametemp[sizeof(nametemp) - 1] = 0;
4177 name = nametemp;
4178 }
4179 next = cur->parent;
4180
4181 /*
4182 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004183 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004184 */
4185 tmp = cur->prev;
4186 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004187 if ((tmp->type == XML_ELEMENT_NODE) &&
4188 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004189 occur++;
4190 tmp = tmp->prev;
4191 }
4192 if (occur == 0) {
4193 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004194 while (tmp != NULL && occur == 0) {
4195 if ((tmp->type == XML_ELEMENT_NODE) &&
4196 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004197 occur++;
4198 tmp = tmp->next;
4199 }
4200 if (occur != 0)
4201 occur = 1;
4202 } else
4203 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004204 } else if (cur->type == XML_COMMENT_NODE) {
4205 sep = "/";
4206 name = "comment()";
4207 next = cur->parent;
4208
4209 /*
4210 * Thumbler index computation
4211 */
4212 tmp = cur->prev;
4213 while (tmp != NULL) {
4214 if (tmp->type == XML_COMMENT_NODE)
4215 occur++;
4216 tmp = tmp->prev;
4217 }
4218 if (occur == 0) {
4219 tmp = cur->next;
4220 while (tmp != NULL && occur == 0) {
4221 if (tmp->type == XML_COMMENT_NODE)
4222 occur++;
4223 tmp = tmp->next;
4224 }
4225 if (occur != 0)
4226 occur = 1;
4227 } else
4228 occur++;
4229 } else if ((cur->type == XML_TEXT_NODE) ||
4230 (cur->type == XML_CDATA_SECTION_NODE)) {
4231 sep = "/";
4232 name = "text()";
4233 next = cur->parent;
4234
4235 /*
4236 * Thumbler index computation
4237 */
4238 tmp = cur->prev;
4239 while (tmp != NULL) {
4240 if ((cur->type == XML_TEXT_NODE) ||
4241 (cur->type == XML_CDATA_SECTION_NODE))
4242 occur++;
4243 tmp = tmp->prev;
4244 }
4245 if (occur == 0) {
4246 tmp = cur->next;
4247 while (tmp != NULL && occur == 0) {
4248 if ((cur->type == XML_TEXT_NODE) ||
4249 (cur->type == XML_CDATA_SECTION_NODE))
4250 occur++;
4251 tmp = tmp->next;
4252 }
4253 if (occur != 0)
4254 occur = 1;
4255 } else
4256 occur++;
4257 } else if (cur->type == XML_PI_NODE) {
4258 sep = "/";
4259 snprintf(nametemp, sizeof(nametemp) - 1,
4260 "processing-instruction('%s')", cur->name);
4261 nametemp[sizeof(nametemp) - 1] = 0;
4262 name = nametemp;
4263
4264 next = cur->parent;
4265
4266 /*
4267 * Thumbler index computation
4268 */
4269 tmp = cur->prev;
4270 while (tmp != NULL) {
4271 if ((tmp->type == XML_PI_NODE) &&
4272 (xmlStrEqual(cur->name, tmp->name)))
4273 occur++;
4274 tmp = tmp->prev;
4275 }
4276 if (occur == 0) {
4277 tmp = cur->next;
4278 while (tmp != NULL && occur == 0) {
4279 if ((tmp->type == XML_PI_NODE) &&
4280 (xmlStrEqual(cur->name, tmp->name)))
4281 occur++;
4282 tmp = tmp->next;
4283 }
4284 if (occur != 0)
4285 occur = 1;
4286 } else
4287 occur++;
4288
Daniel Veillard8faa7832001-11-26 15:58:08 +00004289 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004290 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004291 name = (const char *) (((xmlAttrPtr) cur)->name);
4292 next = ((xmlAttrPtr) cur)->parent;
4293 } else {
4294 next = cur->parent;
4295 }
4296
4297 /*
4298 * Make sure there is enough room
4299 */
4300 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4301 buf_len =
4302 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4303 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4304 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004305 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004306 xmlFree(buf);
4307 xmlFree(buffer);
4308 return (NULL);
4309 }
4310 buffer = temp;
4311 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4312 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004313 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004314 xmlFree(buf);
4315 xmlFree(buffer);
4316 return (NULL);
4317 }
4318 buf = temp;
4319 }
4320 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004321 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004322 sep, name, (char *) buffer);
4323 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004324 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004325 sep, name, occur, (char *) buffer);
4326 snprintf((char *) buffer, buf_len, "%s", buf);
4327 cur = next;
4328 } while (cur != NULL);
4329 xmlFree(buf);
4330 return (buffer);
4331}
Daniel Veillard652327a2003-09-29 18:02:38 +00004332#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004333
4334/**
Owen Taylor3473f882001-02-23 17:55:21 +00004335 * xmlDocGetRootElement:
4336 * @doc: the document
4337 *
4338 * Get the root element of the document (doc->children is a list
4339 * containing possibly comments, PIs, etc ...).
4340 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004341 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004342 */
4343xmlNodePtr
4344xmlDocGetRootElement(xmlDocPtr doc) {
4345 xmlNodePtr ret;
4346
4347 if (doc == NULL) return(NULL);
4348 ret = doc->children;
4349 while (ret != NULL) {
4350 if (ret->type == XML_ELEMENT_NODE)
4351 return(ret);
4352 ret = ret->next;
4353 }
4354 return(ret);
4355}
4356
Daniel Veillard2156d432004-03-04 15:59:36 +00004357#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004358/**
4359 * xmlDocSetRootElement:
4360 * @doc: the document
4361 * @root: the new document root element
4362 *
4363 * Set the root element of the document (doc->children is a list
4364 * containing possibly comments, PIs, etc ...).
4365 *
4366 * Returns the old root element if any was found
4367 */
4368xmlNodePtr
4369xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4370 xmlNodePtr old = NULL;
4371
4372 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004373 if (root == NULL)
4374 return(NULL);
4375 xmlUnlinkNode(root);
4376 root->doc = doc;
4377 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004378 old = doc->children;
4379 while (old != NULL) {
4380 if (old->type == XML_ELEMENT_NODE)
4381 break;
4382 old = old->next;
4383 }
4384 if (old == NULL) {
4385 if (doc->children == NULL) {
4386 doc->children = root;
4387 doc->last = root;
4388 } else {
4389 xmlAddSibling(doc->children, root);
4390 }
4391 } else {
4392 xmlReplaceNode(old, root);
4393 }
4394 return(old);
4395}
Daniel Veillard2156d432004-03-04 15:59:36 +00004396#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004397
Daniel Veillard2156d432004-03-04 15:59:36 +00004398#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004399/**
4400 * xmlNodeSetLang:
4401 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004402 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004403 *
4404 * Set the language of a node, i.e. the values of the xml:lang
4405 * attribute.
4406 */
4407void
4408xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004409 xmlNsPtr ns;
4410
Owen Taylor3473f882001-02-23 17:55:21 +00004411 if (cur == NULL) return;
4412 switch(cur->type) {
4413 case XML_TEXT_NODE:
4414 case XML_CDATA_SECTION_NODE:
4415 case XML_COMMENT_NODE:
4416 case XML_DOCUMENT_NODE:
4417 case XML_DOCUMENT_TYPE_NODE:
4418 case XML_DOCUMENT_FRAG_NODE:
4419 case XML_NOTATION_NODE:
4420 case XML_HTML_DOCUMENT_NODE:
4421 case XML_DTD_NODE:
4422 case XML_ELEMENT_DECL:
4423 case XML_ATTRIBUTE_DECL:
4424 case XML_ENTITY_DECL:
4425 case XML_PI_NODE:
4426 case XML_ENTITY_REF_NODE:
4427 case XML_ENTITY_NODE:
4428 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004429#ifdef LIBXML_DOCB_ENABLED
4430 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004431#endif
4432 case XML_XINCLUDE_START:
4433 case XML_XINCLUDE_END:
4434 return;
4435 case XML_ELEMENT_NODE:
4436 case XML_ATTRIBUTE_NODE:
4437 break;
4438 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004439 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4440 if (ns == NULL)
4441 return;
4442 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004443}
Daniel Veillard652327a2003-09-29 18:02:38 +00004444#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004445
4446/**
4447 * xmlNodeGetLang:
4448 * @cur: the node being checked
4449 *
4450 * Searches the language of a node, i.e. the values of the xml:lang
4451 * attribute or the one carried by the nearest ancestor.
4452 *
4453 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004454 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004455 */
4456xmlChar *
4457xmlNodeGetLang(xmlNodePtr cur) {
4458 xmlChar *lang;
4459
4460 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004461 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004462 if (lang != NULL)
4463 return(lang);
4464 cur = cur->parent;
4465 }
4466 return(NULL);
4467}
4468
4469
Daniel Veillard652327a2003-09-29 18:02:38 +00004470#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004471/**
4472 * xmlNodeSetSpacePreserve:
4473 * @cur: the node being changed
4474 * @val: the xml:space value ("0": default, 1: "preserve")
4475 *
4476 * Set (or reset) the space preserving behaviour of a node, i.e. the
4477 * value of the xml:space attribute.
4478 */
4479void
4480xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004481 xmlNsPtr ns;
4482
Owen Taylor3473f882001-02-23 17:55:21 +00004483 if (cur == NULL) return;
4484 switch(cur->type) {
4485 case XML_TEXT_NODE:
4486 case XML_CDATA_SECTION_NODE:
4487 case XML_COMMENT_NODE:
4488 case XML_DOCUMENT_NODE:
4489 case XML_DOCUMENT_TYPE_NODE:
4490 case XML_DOCUMENT_FRAG_NODE:
4491 case XML_NOTATION_NODE:
4492 case XML_HTML_DOCUMENT_NODE:
4493 case XML_DTD_NODE:
4494 case XML_ELEMENT_DECL:
4495 case XML_ATTRIBUTE_DECL:
4496 case XML_ENTITY_DECL:
4497 case XML_PI_NODE:
4498 case XML_ENTITY_REF_NODE:
4499 case XML_ENTITY_NODE:
4500 case XML_NAMESPACE_DECL:
4501 case XML_XINCLUDE_START:
4502 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004503#ifdef LIBXML_DOCB_ENABLED
4504 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004505#endif
4506 return;
4507 case XML_ELEMENT_NODE:
4508 case XML_ATTRIBUTE_NODE:
4509 break;
4510 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004511 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4512 if (ns == NULL)
4513 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004514 switch (val) {
4515 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004516 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004517 break;
4518 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004519 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004520 break;
4521 }
4522}
Daniel Veillard652327a2003-09-29 18:02:38 +00004523#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004524
4525/**
4526 * xmlNodeGetSpacePreserve:
4527 * @cur: the node being checked
4528 *
4529 * Searches the space preserving behaviour of a node, i.e. the values
4530 * of the xml:space attribute or the one carried by the nearest
4531 * ancestor.
4532 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004533 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004534 */
4535int
4536xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4537 xmlChar *space;
4538
4539 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004540 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004541 if (space != NULL) {
4542 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4543 xmlFree(space);
4544 return(1);
4545 }
4546 if (xmlStrEqual(space, BAD_CAST "default")) {
4547 xmlFree(space);
4548 return(0);
4549 }
4550 xmlFree(space);
4551 }
4552 cur = cur->parent;
4553 }
4554 return(-1);
4555}
4556
Daniel Veillard652327a2003-09-29 18:02:38 +00004557#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004558/**
4559 * xmlNodeSetName:
4560 * @cur: the node being changed
4561 * @name: the new tag name
4562 *
4563 * Set (or reset) the name of a node.
4564 */
4565void
4566xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4567 if (cur == NULL) return;
4568 if (name == NULL) return;
4569 switch(cur->type) {
4570 case XML_TEXT_NODE:
4571 case XML_CDATA_SECTION_NODE:
4572 case XML_COMMENT_NODE:
4573 case XML_DOCUMENT_TYPE_NODE:
4574 case XML_DOCUMENT_FRAG_NODE:
4575 case XML_NOTATION_NODE:
4576 case XML_HTML_DOCUMENT_NODE:
4577 case XML_NAMESPACE_DECL:
4578 case XML_XINCLUDE_START:
4579 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004580#ifdef LIBXML_DOCB_ENABLED
4581 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004582#endif
4583 return;
4584 case XML_ELEMENT_NODE:
4585 case XML_ATTRIBUTE_NODE:
4586 case XML_PI_NODE:
4587 case XML_ENTITY_REF_NODE:
4588 case XML_ENTITY_NODE:
4589 case XML_DTD_NODE:
4590 case XML_DOCUMENT_NODE:
4591 case XML_ELEMENT_DECL:
4592 case XML_ATTRIBUTE_DECL:
4593 case XML_ENTITY_DECL:
4594 break;
4595 }
4596 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4597 cur->name = xmlStrdup(name);
4598}
Daniel Veillard2156d432004-03-04 15:59:36 +00004599#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004600
Daniel Veillard2156d432004-03-04 15:59:36 +00004601#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004602/**
4603 * xmlNodeSetBase:
4604 * @cur: the node being changed
4605 * @uri: the new base URI
4606 *
4607 * Set (or reset) the base URI of a node, i.e. the value of the
4608 * xml:base attribute.
4609 */
4610void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004611xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004612 xmlNsPtr ns;
4613
Owen Taylor3473f882001-02-23 17:55:21 +00004614 if (cur == NULL) return;
4615 switch(cur->type) {
4616 case XML_TEXT_NODE:
4617 case XML_CDATA_SECTION_NODE:
4618 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004619 case XML_DOCUMENT_TYPE_NODE:
4620 case XML_DOCUMENT_FRAG_NODE:
4621 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004622 case XML_DTD_NODE:
4623 case XML_ELEMENT_DECL:
4624 case XML_ATTRIBUTE_DECL:
4625 case XML_ENTITY_DECL:
4626 case XML_PI_NODE:
4627 case XML_ENTITY_REF_NODE:
4628 case XML_ENTITY_NODE:
4629 case XML_NAMESPACE_DECL:
4630 case XML_XINCLUDE_START:
4631 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004632 return;
4633 case XML_ELEMENT_NODE:
4634 case XML_ATTRIBUTE_NODE:
4635 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004636 case XML_DOCUMENT_NODE:
4637#ifdef LIBXML_DOCB_ENABLED
4638 case XML_DOCB_DOCUMENT_NODE:
4639#endif
4640 case XML_HTML_DOCUMENT_NODE: {
4641 xmlDocPtr doc = (xmlDocPtr) cur;
4642
4643 if (doc->URL != NULL)
4644 xmlFree((xmlChar *) doc->URL);
4645 if (uri == NULL)
4646 doc->URL = NULL;
4647 else
4648 doc->URL = xmlStrdup(uri);
4649 return;
4650 }
Owen Taylor3473f882001-02-23 17:55:21 +00004651 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004652
4653 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4654 if (ns == NULL)
4655 return;
4656 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004657}
Daniel Veillard652327a2003-09-29 18:02:38 +00004658#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004659
4660/**
Owen Taylor3473f882001-02-23 17:55:21 +00004661 * xmlNodeGetBase:
4662 * @doc: the document the node pertains to
4663 * @cur: the node being checked
4664 *
4665 * Searches for the BASE URL. The code should work on both XML
4666 * and HTML document even if base mechanisms are completely different.
4667 * It returns the base as defined in RFC 2396 sections
4668 * 5.1.1. Base URI within Document Content
4669 * and
4670 * 5.1.2. Base URI from the Encapsulating Entity
4671 * However it does not return the document base (5.1.3), use
4672 * xmlDocumentGetBase() for this
4673 *
4674 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004675 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004676 */
4677xmlChar *
4678xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004679 xmlChar *oldbase = NULL;
4680 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004681
4682 if ((cur == NULL) && (doc == NULL))
4683 return(NULL);
4684 if (doc == NULL) doc = cur->doc;
4685 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4686 cur = doc->children;
4687 while ((cur != NULL) && (cur->name != NULL)) {
4688 if (cur->type != XML_ELEMENT_NODE) {
4689 cur = cur->next;
4690 continue;
4691 }
4692 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4693 cur = cur->children;
4694 continue;
4695 }
4696 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4697 cur = cur->children;
4698 continue;
4699 }
4700 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4701 return(xmlGetProp(cur, BAD_CAST "href"));
4702 }
4703 cur = cur->next;
4704 }
4705 return(NULL);
4706 }
4707 while (cur != NULL) {
4708 if (cur->type == XML_ENTITY_DECL) {
4709 xmlEntityPtr ent = (xmlEntityPtr) cur;
4710 return(xmlStrdup(ent->URI));
4711 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004712 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004713 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004714 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004715 if (oldbase != NULL) {
4716 newbase = xmlBuildURI(oldbase, base);
4717 if (newbase != NULL) {
4718 xmlFree(oldbase);
4719 xmlFree(base);
4720 oldbase = newbase;
4721 } else {
4722 xmlFree(oldbase);
4723 xmlFree(base);
4724 return(NULL);
4725 }
4726 } else {
4727 oldbase = base;
4728 }
4729 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4730 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4731 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4732 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004733 }
4734 }
Owen Taylor3473f882001-02-23 17:55:21 +00004735 cur = cur->parent;
4736 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004737 if ((doc != NULL) && (doc->URL != NULL)) {
4738 if (oldbase == NULL)
4739 return(xmlStrdup(doc->URL));
4740 newbase = xmlBuildURI(oldbase, doc->URL);
4741 xmlFree(oldbase);
4742 return(newbase);
4743 }
4744 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004745}
4746
4747/**
Daniel Veillard78697292003-10-19 20:44:43 +00004748 * xmlNodeBufGetContent:
4749 * @buffer: a buffer
4750 * @cur: the node being read
4751 *
4752 * Read the value of a node @cur, this can be either the text carried
4753 * directly by this node if it's a TEXT node or the aggregate string
4754 * of the values carried by this node child's (TEXT and ENTITY_REF).
4755 * Entity references are substituted.
4756 * Fills up the buffer @buffer with this value
4757 *
4758 * Returns 0 in case of success and -1 in case of error.
4759 */
4760int
4761xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4762{
4763 if ((cur == NULL) || (buffer == NULL)) return(-1);
4764 switch (cur->type) {
4765 case XML_CDATA_SECTION_NODE:
4766 case XML_TEXT_NODE:
4767 xmlBufferCat(buffer, cur->content);
4768 break;
4769 case XML_DOCUMENT_FRAG_NODE:
4770 case XML_ELEMENT_NODE:{
4771 xmlNodePtr tmp = cur;
4772
4773 while (tmp != NULL) {
4774 switch (tmp->type) {
4775 case XML_CDATA_SECTION_NODE:
4776 case XML_TEXT_NODE:
4777 if (tmp->content != NULL)
4778 xmlBufferCat(buffer, tmp->content);
4779 break;
4780 case XML_ENTITY_REF_NODE:
4781 xmlNodeBufGetContent(buffer, tmp->children);
4782 break;
4783 default:
4784 break;
4785 }
4786 /*
4787 * Skip to next node
4788 */
4789 if (tmp->children != NULL) {
4790 if (tmp->children->type != XML_ENTITY_DECL) {
4791 tmp = tmp->children;
4792 continue;
4793 }
4794 }
4795 if (tmp == cur)
4796 break;
4797
4798 if (tmp->next != NULL) {
4799 tmp = tmp->next;
4800 continue;
4801 }
4802
4803 do {
4804 tmp = tmp->parent;
4805 if (tmp == NULL)
4806 break;
4807 if (tmp == cur) {
4808 tmp = NULL;
4809 break;
4810 }
4811 if (tmp->next != NULL) {
4812 tmp = tmp->next;
4813 break;
4814 }
4815 } while (tmp != NULL);
4816 }
4817 break;
4818 }
4819 case XML_ATTRIBUTE_NODE:{
4820 xmlAttrPtr attr = (xmlAttrPtr) cur;
4821 xmlNodePtr tmp = attr->children;
4822
4823 while (tmp != NULL) {
4824 if (tmp->type == XML_TEXT_NODE)
4825 xmlBufferCat(buffer, tmp->content);
4826 else
4827 xmlNodeBufGetContent(buffer, tmp);
4828 tmp = tmp->next;
4829 }
4830 break;
4831 }
4832 case XML_COMMENT_NODE:
4833 case XML_PI_NODE:
4834 xmlBufferCat(buffer, cur->content);
4835 break;
4836 case XML_ENTITY_REF_NODE:{
4837 xmlEntityPtr ent;
4838 xmlNodePtr tmp;
4839
4840 /* lookup entity declaration */
4841 ent = xmlGetDocEntity(cur->doc, cur->name);
4842 if (ent == NULL)
4843 return(-1);
4844
4845 /* an entity content can be any "well balanced chunk",
4846 * i.e. the result of the content [43] production:
4847 * http://www.w3.org/TR/REC-xml#NT-content
4848 * -> we iterate through child nodes and recursive call
4849 * xmlNodeGetContent() which handles all possible node types */
4850 tmp = ent->children;
4851 while (tmp) {
4852 xmlNodeBufGetContent(buffer, tmp);
4853 tmp = tmp->next;
4854 }
4855 break;
4856 }
4857 case XML_ENTITY_NODE:
4858 case XML_DOCUMENT_TYPE_NODE:
4859 case XML_NOTATION_NODE:
4860 case XML_DTD_NODE:
4861 case XML_XINCLUDE_START:
4862 case XML_XINCLUDE_END:
4863 break;
4864 case XML_DOCUMENT_NODE:
4865#ifdef LIBXML_DOCB_ENABLED
4866 case XML_DOCB_DOCUMENT_NODE:
4867#endif
4868 case XML_HTML_DOCUMENT_NODE:
4869 cur = cur->children;
4870 while (cur!= NULL) {
4871 if ((cur->type == XML_ELEMENT_NODE) ||
4872 (cur->type == XML_TEXT_NODE) ||
4873 (cur->type == XML_CDATA_SECTION_NODE)) {
4874 xmlNodeBufGetContent(buffer, cur);
4875 }
4876 cur = cur->next;
4877 }
4878 break;
4879 case XML_NAMESPACE_DECL:
4880 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
4881 break;
4882 case XML_ELEMENT_DECL:
4883 case XML_ATTRIBUTE_DECL:
4884 case XML_ENTITY_DECL:
4885 break;
4886 }
4887 return(0);
4888}
4889/**
Owen Taylor3473f882001-02-23 17:55:21 +00004890 * xmlNodeGetContent:
4891 * @cur: the node being read
4892 *
4893 * Read the value of a node, this can be either the text carried
4894 * directly by this node if it's a TEXT node or the aggregate string
4895 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004896 * Entity references are substituted.
4897 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004898 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004899 */
4900xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004901xmlNodeGetContent(xmlNodePtr cur)
4902{
4903 if (cur == NULL)
4904 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004905 switch (cur->type) {
4906 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004907 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00004908 xmlBufferPtr buffer;
4909 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004910
Daniel Veillard814a76d2003-01-23 18:24:20 +00004911 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004912 if (buffer == NULL)
4913 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00004914 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004915 ret = buffer->content;
4916 buffer->content = NULL;
4917 xmlBufferFree(buffer);
4918 return (ret);
4919 }
4920 case XML_ATTRIBUTE_NODE:{
4921 xmlAttrPtr attr = (xmlAttrPtr) cur;
4922
4923 if (attr->parent != NULL)
4924 return (xmlNodeListGetString
4925 (attr->parent->doc, attr->children, 1));
4926 else
4927 return (xmlNodeListGetString(NULL, attr->children, 1));
4928 break;
4929 }
Owen Taylor3473f882001-02-23 17:55:21 +00004930 case XML_COMMENT_NODE:
4931 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004932 if (cur->content != NULL)
4933 return (xmlStrdup(cur->content));
4934 return (NULL);
4935 case XML_ENTITY_REF_NODE:{
4936 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00004937 xmlBufferPtr buffer;
4938 xmlChar *ret;
4939
4940 /* lookup entity declaration */
4941 ent = xmlGetDocEntity(cur->doc, cur->name);
4942 if (ent == NULL)
4943 return (NULL);
4944
4945 buffer = xmlBufferCreate();
4946 if (buffer == NULL)
4947 return (NULL);
4948
Daniel Veillardc4696922003-10-19 21:47:14 +00004949 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004950
4951 ret = buffer->content;
4952 buffer->content = NULL;
4953 xmlBufferFree(buffer);
4954 return (ret);
4955 }
Owen Taylor3473f882001-02-23 17:55:21 +00004956 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004957 case XML_DOCUMENT_TYPE_NODE:
4958 case XML_NOTATION_NODE:
4959 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004960 case XML_XINCLUDE_START:
4961 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00004962 return (NULL);
4963 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004964#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004965 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004966#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00004967 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00004968 xmlBufferPtr buffer;
4969 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00004970
Daniel Veillardc4696922003-10-19 21:47:14 +00004971 buffer = xmlBufferCreate();
4972 if (buffer == NULL)
4973 return (NULL);
4974
4975 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
4976
4977 ret = buffer->content;
4978 buffer->content = NULL;
4979 xmlBufferFree(buffer);
4980 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004981 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004982 case XML_NAMESPACE_DECL: {
4983 xmlChar *tmp;
4984
4985 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4986 return (tmp);
4987 }
Owen Taylor3473f882001-02-23 17:55:21 +00004988 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004989 /* TODO !!! */
4990 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004991 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004992 /* TODO !!! */
4993 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004994 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004995 /* TODO !!! */
4996 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004997 case XML_CDATA_SECTION_NODE:
4998 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004999 if (cur->content != NULL)
5000 return (xmlStrdup(cur->content));
5001 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005002 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005003 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005004}
Daniel Veillard652327a2003-09-29 18:02:38 +00005005
Owen Taylor3473f882001-02-23 17:55:21 +00005006/**
5007 * xmlNodeSetContent:
5008 * @cur: the node being modified
5009 * @content: the new value of the content
5010 *
5011 * Replace the content of a node.
5012 */
5013void
5014xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5015 if (cur == NULL) {
5016#ifdef DEBUG_TREE
5017 xmlGenericError(xmlGenericErrorContext,
5018 "xmlNodeSetContent : node == NULL\n");
5019#endif
5020 return;
5021 }
5022 switch (cur->type) {
5023 case XML_DOCUMENT_FRAG_NODE:
5024 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005025 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005026 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5027 cur->children = xmlStringGetNodeList(cur->doc, content);
5028 UPDATE_LAST_CHILD_AND_PARENT(cur)
5029 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005030 case XML_TEXT_NODE:
5031 case XML_CDATA_SECTION_NODE:
5032 case XML_ENTITY_REF_NODE:
5033 case XML_ENTITY_NODE:
5034 case XML_PI_NODE:
5035 case XML_COMMENT_NODE:
5036 if (cur->content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005037 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5038 xmlDictOwns(cur->doc->dict, cur->content)))
5039 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005040 }
5041 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5042 cur->last = cur->children = NULL;
5043 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005044 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005045 } else
5046 cur->content = NULL;
5047 break;
5048 case XML_DOCUMENT_NODE:
5049 case XML_HTML_DOCUMENT_NODE:
5050 case XML_DOCUMENT_TYPE_NODE:
5051 case XML_XINCLUDE_START:
5052 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005053#ifdef LIBXML_DOCB_ENABLED
5054 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005055#endif
5056 break;
5057 case XML_NOTATION_NODE:
5058 break;
5059 case XML_DTD_NODE:
5060 break;
5061 case XML_NAMESPACE_DECL:
5062 break;
5063 case XML_ELEMENT_DECL:
5064 /* TODO !!! */
5065 break;
5066 case XML_ATTRIBUTE_DECL:
5067 /* TODO !!! */
5068 break;
5069 case XML_ENTITY_DECL:
5070 /* TODO !!! */
5071 break;
5072 }
5073}
5074
Daniel Veillard652327a2003-09-29 18:02:38 +00005075#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005076/**
5077 * xmlNodeSetContentLen:
5078 * @cur: the node being modified
5079 * @content: the new value of the content
5080 * @len: the size of @content
5081 *
5082 * Replace the content of a node.
5083 */
5084void
5085xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5086 if (cur == NULL) {
5087#ifdef DEBUG_TREE
5088 xmlGenericError(xmlGenericErrorContext,
5089 "xmlNodeSetContentLen : node == NULL\n");
5090#endif
5091 return;
5092 }
5093 switch (cur->type) {
5094 case XML_DOCUMENT_FRAG_NODE:
5095 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005096 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005097 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5098 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5099 UPDATE_LAST_CHILD_AND_PARENT(cur)
5100 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005101 case XML_TEXT_NODE:
5102 case XML_CDATA_SECTION_NODE:
5103 case XML_ENTITY_REF_NODE:
5104 case XML_ENTITY_NODE:
5105 case XML_PI_NODE:
5106 case XML_COMMENT_NODE:
5107 case XML_NOTATION_NODE:
5108 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005109 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005110 }
5111 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5112 cur->children = cur->last = NULL;
5113 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005114 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005115 } else
5116 cur->content = NULL;
5117 break;
5118 case XML_DOCUMENT_NODE:
5119 case XML_DTD_NODE:
5120 case XML_HTML_DOCUMENT_NODE:
5121 case XML_DOCUMENT_TYPE_NODE:
5122 case XML_NAMESPACE_DECL:
5123 case XML_XINCLUDE_START:
5124 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005125#ifdef LIBXML_DOCB_ENABLED
5126 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005127#endif
5128 break;
5129 case XML_ELEMENT_DECL:
5130 /* TODO !!! */
5131 break;
5132 case XML_ATTRIBUTE_DECL:
5133 /* TODO !!! */
5134 break;
5135 case XML_ENTITY_DECL:
5136 /* TODO !!! */
5137 break;
5138 }
5139}
Daniel Veillard652327a2003-09-29 18:02:38 +00005140#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005141
5142/**
5143 * xmlNodeAddContentLen:
5144 * @cur: the node being modified
5145 * @content: extra content
5146 * @len: the size of @content
5147 *
5148 * Append the extra substring to the node content.
5149 */
5150void
5151xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5152 if (cur == NULL) {
5153#ifdef DEBUG_TREE
5154 xmlGenericError(xmlGenericErrorContext,
5155 "xmlNodeAddContentLen : node == NULL\n");
5156#endif
5157 return;
5158 }
5159 if (len <= 0) return;
5160 switch (cur->type) {
5161 case XML_DOCUMENT_FRAG_NODE:
5162 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005163 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005164
Daniel Veillard7db37732001-07-12 01:20:08 +00005165 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005166 newNode = xmlNewTextLen(content, len);
5167 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005168 tmp = xmlAddChild(cur, newNode);
5169 if (tmp != newNode)
5170 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005171 if ((last != NULL) && (last->next == newNode)) {
5172 xmlTextMerge(last, newNode);
5173 }
5174 }
5175 break;
5176 }
5177 case XML_ATTRIBUTE_NODE:
5178 break;
5179 case XML_TEXT_NODE:
5180 case XML_CDATA_SECTION_NODE:
5181 case XML_ENTITY_REF_NODE:
5182 case XML_ENTITY_NODE:
5183 case XML_PI_NODE:
5184 case XML_COMMENT_NODE:
5185 case XML_NOTATION_NODE:
5186 if (content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005187 if ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5188 xmlDictOwns(cur->doc->dict, cur->content)) {
5189 cur->content =
5190 xmlStrncatNew(cur->content, content, len);
5191 break;
5192 }
Owen Taylor3473f882001-02-23 17:55:21 +00005193 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005194 }
5195 case XML_DOCUMENT_NODE:
5196 case XML_DTD_NODE:
5197 case XML_HTML_DOCUMENT_NODE:
5198 case XML_DOCUMENT_TYPE_NODE:
5199 case XML_NAMESPACE_DECL:
5200 case XML_XINCLUDE_START:
5201 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005202#ifdef LIBXML_DOCB_ENABLED
5203 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005204#endif
5205 break;
5206 case XML_ELEMENT_DECL:
5207 case XML_ATTRIBUTE_DECL:
5208 case XML_ENTITY_DECL:
5209 break;
5210 }
5211}
5212
5213/**
5214 * xmlNodeAddContent:
5215 * @cur: the node being modified
5216 * @content: extra content
5217 *
5218 * Append the extra substring to the node content.
5219 */
5220void
5221xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5222 int len;
5223
5224 if (cur == NULL) {
5225#ifdef DEBUG_TREE
5226 xmlGenericError(xmlGenericErrorContext,
5227 "xmlNodeAddContent : node == NULL\n");
5228#endif
5229 return;
5230 }
5231 if (content == NULL) return;
5232 len = xmlStrlen(content);
5233 xmlNodeAddContentLen(cur, content, len);
5234}
5235
5236/**
5237 * xmlTextMerge:
5238 * @first: the first text node
5239 * @second: the second text node being merged
5240 *
5241 * Merge two text nodes into one
5242 * Returns the first text node augmented
5243 */
5244xmlNodePtr
5245xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5246 if (first == NULL) return(second);
5247 if (second == NULL) return(first);
5248 if (first->type != XML_TEXT_NODE) return(first);
5249 if (second->type != XML_TEXT_NODE) return(first);
5250 if (second->name != first->name)
5251 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005252 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005253 xmlUnlinkNode(second);
5254 xmlFreeNode(second);
5255 return(first);
5256}
5257
Daniel Veillard2156d432004-03-04 15:59:36 +00005258#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005259/**
5260 * xmlGetNsList:
5261 * @doc: the document
5262 * @node: the current node
5263 *
5264 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005265 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005266 * that need to be freed by the caller or NULL if no
5267 * namespace if defined
5268 */
5269xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005270xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5271{
Owen Taylor3473f882001-02-23 17:55:21 +00005272 xmlNsPtr cur;
5273 xmlNsPtr *ret = NULL;
5274 int nbns = 0;
5275 int maxns = 10;
5276 int i;
5277
5278 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005279 if (node->type == XML_ELEMENT_NODE) {
5280 cur = node->nsDef;
5281 while (cur != NULL) {
5282 if (ret == NULL) {
5283 ret =
5284 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5285 sizeof(xmlNsPtr));
5286 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005287 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005288 return (NULL);
5289 }
5290 ret[nbns] = NULL;
5291 }
5292 for (i = 0; i < nbns; i++) {
5293 if ((cur->prefix == ret[i]->prefix) ||
5294 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5295 break;
5296 }
5297 if (i >= nbns) {
5298 if (nbns >= maxns) {
5299 maxns *= 2;
5300 ret = (xmlNsPtr *) xmlRealloc(ret,
5301 (maxns +
5302 1) *
5303 sizeof(xmlNsPtr));
5304 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005305 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005306 return (NULL);
5307 }
5308 }
5309 ret[nbns++] = cur;
5310 ret[nbns] = NULL;
5311 }
Owen Taylor3473f882001-02-23 17:55:21 +00005312
Daniel Veillard77044732001-06-29 21:31:07 +00005313 cur = cur->next;
5314 }
5315 }
5316 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005317 }
Daniel Veillard77044732001-06-29 21:31:07 +00005318 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005319}
Daniel Veillard652327a2003-09-29 18:02:38 +00005320#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005321
5322/**
5323 * xmlSearchNs:
5324 * @doc: the document
5325 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005326 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005327 *
5328 * Search a Ns registered under a given name space for a document.
5329 * recurse on the parents until it finds the defined namespace
5330 * or return NULL otherwise.
5331 * @nameSpace can be NULL, this is a search for the default namespace.
5332 * We don't allow to cross entities boundaries. If you don't declare
5333 * the namespace within those you will be in troubles !!! A warning
5334 * is generated to cover this case.
5335 *
5336 * Returns the namespace pointer or NULL.
5337 */
5338xmlNsPtr
5339xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005340
Owen Taylor3473f882001-02-23 17:55:21 +00005341 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005342 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005343
5344 if (node == NULL) return(NULL);
5345 if ((nameSpace != NULL) &&
5346 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005347 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5348 /*
5349 * The XML-1.0 namespace is normally held on the root
5350 * element. In this case exceptionally create it on the
5351 * node element.
5352 */
5353 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5354 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005355 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005356 return(NULL);
5357 }
5358 memset(cur, 0, sizeof(xmlNs));
5359 cur->type = XML_LOCAL_NAMESPACE;
5360 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5361 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5362 cur->next = node->nsDef;
5363 node->nsDef = cur;
5364 return(cur);
5365 }
Owen Taylor3473f882001-02-23 17:55:21 +00005366 if (doc->oldNs == NULL) {
5367 /*
5368 * Allocate a new Namespace and fill the fields.
5369 */
5370 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5371 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005372 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005373 return(NULL);
5374 }
5375 memset(doc->oldNs, 0, sizeof(xmlNs));
5376 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5377
5378 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5379 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5380 }
5381 return(doc->oldNs);
5382 }
5383 while (node != NULL) {
5384 if ((node->type == XML_ENTITY_REF_NODE) ||
5385 (node->type == XML_ENTITY_NODE) ||
5386 (node->type == XML_ENTITY_DECL))
5387 return(NULL);
5388 if (node->type == XML_ELEMENT_NODE) {
5389 cur = node->nsDef;
5390 while (cur != NULL) {
5391 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5392 (cur->href != NULL))
5393 return(cur);
5394 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5395 (cur->href != NULL) &&
5396 (xmlStrEqual(cur->prefix, nameSpace)))
5397 return(cur);
5398 cur = cur->next;
5399 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005400 if (orig != node) {
5401 cur = node->ns;
5402 if (cur != NULL) {
5403 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5404 (cur->href != NULL))
5405 return(cur);
5406 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5407 (cur->href != NULL) &&
5408 (xmlStrEqual(cur->prefix, nameSpace)))
5409 return(cur);
5410 }
5411 }
Owen Taylor3473f882001-02-23 17:55:21 +00005412 }
5413 node = node->parent;
5414 }
5415 return(NULL);
5416}
5417
5418/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005419 * xmlNsInScope:
5420 * @doc: the document
5421 * @node: the current node
5422 * @ancestor: the ancestor carrying the namespace
5423 * @prefix: the namespace prefix
5424 *
5425 * Verify that the given namespace held on @ancestor is still in scope
5426 * on node.
5427 *
5428 * Returns 1 if true, 0 if false and -1 in case of error.
5429 */
5430static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005431xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5432 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005433{
5434 xmlNsPtr tst;
5435
5436 while ((node != NULL) && (node != ancestor)) {
5437 if ((node->type == XML_ENTITY_REF_NODE) ||
5438 (node->type == XML_ENTITY_NODE) ||
5439 (node->type == XML_ENTITY_DECL))
5440 return (-1);
5441 if (node->type == XML_ELEMENT_NODE) {
5442 tst = node->nsDef;
5443 while (tst != NULL) {
5444 if ((tst->prefix == NULL)
5445 && (prefix == NULL))
5446 return (0);
5447 if ((tst->prefix != NULL)
5448 && (prefix != NULL)
5449 && (xmlStrEqual(tst->prefix, prefix)))
5450 return (0);
5451 tst = tst->next;
5452 }
5453 }
5454 node = node->parent;
5455 }
5456 if (node != ancestor)
5457 return (-1);
5458 return (1);
5459}
5460
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005461/**
Owen Taylor3473f882001-02-23 17:55:21 +00005462 * xmlSearchNsByHref:
5463 * @doc: the document
5464 * @node: the current node
5465 * @href: the namespace value
5466 *
5467 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5468 * the defined namespace or return NULL otherwise.
5469 * Returns the namespace pointer or NULL.
5470 */
5471xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005472xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5473{
Owen Taylor3473f882001-02-23 17:55:21 +00005474 xmlNsPtr cur;
5475 xmlNodePtr orig = node;
5476
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005477 if ((node == NULL) || (href == NULL))
5478 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005479 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005480 /*
5481 * Only the document can hold the XML spec namespace.
5482 */
5483 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5484 /*
5485 * The XML-1.0 namespace is normally held on the root
5486 * element. In this case exceptionally create it on the
5487 * node element.
5488 */
5489 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5490 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005491 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005492 return (NULL);
5493 }
5494 memset(cur, 0, sizeof(xmlNs));
5495 cur->type = XML_LOCAL_NAMESPACE;
5496 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5497 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5498 cur->next = node->nsDef;
5499 node->nsDef = cur;
5500 return (cur);
5501 }
5502 if (doc->oldNs == NULL) {
5503 /*
5504 * Allocate a new Namespace and fill the fields.
5505 */
5506 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5507 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005508 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005509 return (NULL);
5510 }
5511 memset(doc->oldNs, 0, sizeof(xmlNs));
5512 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005513
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005514 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5515 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5516 }
5517 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005518 }
5519 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005520 if ((node->type == XML_ENTITY_REF_NODE) ||
5521 (node->type == XML_ENTITY_NODE) ||
5522 (node->type == XML_ENTITY_DECL))
5523 return (NULL);
5524 if (node->type == XML_ELEMENT_NODE) {
5525 cur = node->nsDef;
5526 while (cur != NULL) {
5527 if ((cur->href != NULL) && (href != NULL) &&
5528 (xmlStrEqual(cur->href, href))) {
5529 if (xmlNsInScope(doc, orig, node, cur->href) == 1)
5530 return (cur);
5531 }
5532 cur = cur->next;
5533 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005534 if (orig != node) {
5535 cur = node->ns;
5536 if (cur != NULL) {
5537 if ((cur->href != NULL) && (href != NULL) &&
5538 (xmlStrEqual(cur->href, href))) {
5539 if (xmlNsInScope(doc, orig, node, cur->href) == 1)
5540 return (cur);
5541 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005542 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005543 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005544 }
5545 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005546 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005547 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005548}
5549
5550/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005551 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005552 * @doc: the document
5553 * @tree: a node expected to hold the new namespace
5554 * @ns: the original namespace
5555 *
5556 * This function tries to locate a namespace definition in a tree
5557 * ancestors, or create a new namespace definition node similar to
5558 * @ns trying to reuse the same prefix. However if the given prefix is
5559 * null (default namespace) or reused within the subtree defined by
5560 * @tree or on one of its ancestors then a new prefix is generated.
5561 * Returns the (new) namespace definition or NULL in case of error
5562 */
5563xmlNsPtr
5564xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5565 xmlNsPtr def;
5566 xmlChar prefix[50];
5567 int counter = 1;
5568
5569 if (tree == NULL) {
5570#ifdef DEBUG_TREE
5571 xmlGenericError(xmlGenericErrorContext,
5572 "xmlNewReconciliedNs : tree == NULL\n");
5573#endif
5574 return(NULL);
5575 }
5576 if (ns == NULL) {
5577#ifdef DEBUG_TREE
5578 xmlGenericError(xmlGenericErrorContext,
5579 "xmlNewReconciliedNs : ns == NULL\n");
5580#endif
5581 return(NULL);
5582 }
5583 /*
5584 * Search an existing namespace definition inherited.
5585 */
5586 def = xmlSearchNsByHref(doc, tree, ns->href);
5587 if (def != NULL)
5588 return(def);
5589
5590 /*
5591 * Find a close prefix which is not already in use.
5592 * Let's strip namespace prefixes longer than 20 chars !
5593 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005594 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005595 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005596 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005597 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005598
Owen Taylor3473f882001-02-23 17:55:21 +00005599 def = xmlSearchNs(doc, tree, prefix);
5600 while (def != NULL) {
5601 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005602 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005603 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005604 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005605 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005606 def = xmlSearchNs(doc, tree, prefix);
5607 }
5608
5609 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005610 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005611 */
5612 def = xmlNewNs(tree, ns->href, prefix);
5613 return(def);
5614}
5615
Daniel Veillard652327a2003-09-29 18:02:38 +00005616#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005617/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005618 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005619 * @doc: the document
5620 * @tree: a node defining the subtree to reconciliate
5621 *
5622 * This function checks that all the namespaces declared within the given
5623 * tree are properly declared. This is needed for example after Copy or Cut
5624 * and then paste operations. The subtree may still hold pointers to
5625 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005626 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005627 * the new environment. If not possible the new namespaces are redeclared
5628 * on @tree at the top of the given subtree.
5629 * Returns the number of namespace declarations created or -1 in case of error.
5630 */
5631int
5632xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5633 xmlNsPtr *oldNs = NULL;
5634 xmlNsPtr *newNs = NULL;
5635 int sizeCache = 0;
5636 int nbCache = 0;
5637
5638 xmlNsPtr n;
5639 xmlNodePtr node = tree;
5640 xmlAttrPtr attr;
5641 int ret = 0, i;
5642
5643 while (node != NULL) {
5644 /*
5645 * Reconciliate the node namespace
5646 */
5647 if (node->ns != NULL) {
5648 /*
5649 * initialize the cache if needed
5650 */
5651 if (sizeCache == 0) {
5652 sizeCache = 10;
5653 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5654 sizeof(xmlNsPtr));
5655 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005656 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005657 return(-1);
5658 }
5659 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5660 sizeof(xmlNsPtr));
5661 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005662 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005663 xmlFree(oldNs);
5664 return(-1);
5665 }
5666 }
5667 for (i = 0;i < nbCache;i++) {
5668 if (oldNs[i] == node->ns) {
5669 node->ns = newNs[i];
5670 break;
5671 }
5672 }
5673 if (i == nbCache) {
5674 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005675 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005676 */
5677 n = xmlNewReconciliedNs(doc, tree, node->ns);
5678 if (n != NULL) { /* :-( what if else ??? */
5679 /*
5680 * check if we need to grow the cache buffers.
5681 */
5682 if (sizeCache <= nbCache) {
5683 sizeCache *= 2;
5684 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5685 sizeof(xmlNsPtr));
5686 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005687 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005688 xmlFree(newNs);
5689 return(-1);
5690 }
5691 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5692 sizeof(xmlNsPtr));
5693 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005694 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005695 xmlFree(oldNs);
5696 return(-1);
5697 }
5698 }
5699 newNs[nbCache] = n;
5700 oldNs[nbCache++] = node->ns;
5701 node->ns = n;
5702 }
5703 }
5704 }
5705 /*
5706 * now check for namespace hold by attributes on the node.
5707 */
5708 attr = node->properties;
5709 while (attr != NULL) {
5710 if (attr->ns != NULL) {
5711 /*
5712 * initialize the cache if needed
5713 */
5714 if (sizeCache == 0) {
5715 sizeCache = 10;
5716 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5717 sizeof(xmlNsPtr));
5718 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005719 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005720 return(-1);
5721 }
5722 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5723 sizeof(xmlNsPtr));
5724 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005725 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005726 xmlFree(oldNs);
5727 return(-1);
5728 }
5729 }
5730 for (i = 0;i < nbCache;i++) {
5731 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005732 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005733 break;
5734 }
5735 }
5736 if (i == nbCache) {
5737 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005738 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005739 */
5740 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5741 if (n != NULL) { /* :-( what if else ??? */
5742 /*
5743 * check if we need to grow the cache buffers.
5744 */
5745 if (sizeCache <= nbCache) {
5746 sizeCache *= 2;
5747 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5748 sizeof(xmlNsPtr));
5749 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005750 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005751 xmlFree(newNs);
5752 return(-1);
5753 }
5754 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5755 sizeof(xmlNsPtr));
5756 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005757 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005758 xmlFree(oldNs);
5759 return(-1);
5760 }
5761 }
5762 newNs[nbCache] = n;
5763 oldNs[nbCache++] = attr->ns;
5764 attr->ns = n;
5765 }
5766 }
5767 }
5768 attr = attr->next;
5769 }
5770
5771 /*
5772 * Browse the full subtree, deep first
5773 */
5774 if (node->children != NULL) {
5775 /* deep first */
5776 node = node->children;
5777 } else if ((node != tree) && (node->next != NULL)) {
5778 /* then siblings */
5779 node = node->next;
5780 } else if (node != tree) {
5781 /* go up to parents->next if needed */
5782 while (node != tree) {
5783 if (node->parent != NULL)
5784 node = node->parent;
5785 if ((node != tree) && (node->next != NULL)) {
5786 node = node->next;
5787 break;
5788 }
5789 if (node->parent == NULL) {
5790 node = NULL;
5791 break;
5792 }
5793 }
5794 /* exit condition */
5795 if (node == tree)
5796 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005797 } else
5798 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005799 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005800 if (oldNs != NULL)
5801 xmlFree(oldNs);
5802 if (newNs != NULL)
5803 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005804 return(ret);
5805}
Daniel Veillard652327a2003-09-29 18:02:38 +00005806#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005807
5808/**
5809 * xmlHasProp:
5810 * @node: the node
5811 * @name: the attribute name
5812 *
5813 * Search an attribute associated to a node
5814 * This function also looks in DTD attribute declaration for #FIXED or
5815 * default declaration values unless DTD use has been turned off.
5816 *
5817 * Returns the attribute or the attribute declaration or NULL if
5818 * neither was found.
5819 */
5820xmlAttrPtr
5821xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5822 xmlAttrPtr prop;
5823 xmlDocPtr doc;
5824
5825 if ((node == NULL) || (name == NULL)) return(NULL);
5826 /*
5827 * Check on the properties attached to the node
5828 */
5829 prop = node->properties;
5830 while (prop != NULL) {
5831 if (xmlStrEqual(prop->name, name)) {
5832 return(prop);
5833 }
5834 prop = prop->next;
5835 }
5836 if (!xmlCheckDTD) return(NULL);
5837
5838 /*
5839 * Check if there is a default declaration in the internal
5840 * or external subsets
5841 */
5842 doc = node->doc;
5843 if (doc != NULL) {
5844 xmlAttributePtr attrDecl;
5845 if (doc->intSubset != NULL) {
5846 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5847 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5848 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005849 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5850 /* return attribute declaration only if a default value is given
5851 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005852 return((xmlAttrPtr) attrDecl);
5853 }
5854 }
5855 return(NULL);
5856}
5857
5858/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005859 * xmlHasNsProp:
5860 * @node: the node
5861 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005862 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005863 *
5864 * Search for an attribute associated to a node
5865 * This attribute has to be anchored in the namespace specified.
5866 * This does the entity substitution.
5867 * This function looks in DTD attribute declaration for #FIXED or
5868 * default declaration values unless DTD use has been turned off.
5869 *
5870 * Returns the attribute or the attribute declaration or NULL
5871 * if neither was found.
5872 */
5873xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005874xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005875 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00005876#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005877 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00005878#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005879
5880 if (node == NULL)
5881 return(NULL);
5882
5883 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005884 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005885 return(xmlHasProp(node, name));
5886 while (prop != NULL) {
5887 /*
5888 * One need to have
5889 * - same attribute names
5890 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005891 */
5892 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005893 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5894 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005895 }
5896 prop = prop->next;
5897 }
5898 if (!xmlCheckDTD) return(NULL);
5899
Daniel Veillard652327a2003-09-29 18:02:38 +00005900#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005901 /*
5902 * Check if there is a default declaration in the internal
5903 * or external subsets
5904 */
5905 doc = node->doc;
5906 if (doc != NULL) {
5907 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005908 xmlAttributePtr attrDecl = NULL;
5909 xmlNsPtr *nsList, *cur;
5910 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005911
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005912 nsList = xmlGetNsList(node->doc, node);
5913 if (nsList == NULL)
5914 return(NULL);
5915 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5916 ename = xmlStrdup(node->ns->prefix);
5917 ename = xmlStrcat(ename, BAD_CAST ":");
5918 ename = xmlStrcat(ename, node->name);
5919 } else {
5920 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005921 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005922 if (ename == NULL) {
5923 xmlFree(nsList);
5924 return(NULL);
5925 }
5926
5927 cur = nsList;
5928 while (*cur != NULL) {
5929 if (xmlStrEqual((*cur)->href, nameSpace)) {
5930 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5931 name, (*cur)->prefix);
5932 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5933 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5934 name, (*cur)->prefix);
5935 }
5936 cur++;
5937 }
5938 xmlFree(nsList);
5939 xmlFree(ename);
5940 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005941 }
5942 }
Daniel Veillard652327a2003-09-29 18:02:38 +00005943#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005944 return(NULL);
5945}
5946
5947/**
Owen Taylor3473f882001-02-23 17:55:21 +00005948 * xmlGetProp:
5949 * @node: the node
5950 * @name: the attribute name
5951 *
5952 * Search and get the value of an attribute associated to a node
5953 * This does the entity substitution.
5954 * This function looks in DTD attribute declaration for #FIXED or
5955 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00005956 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00005957 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5958 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005959 *
5960 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005961 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005962 */
5963xmlChar *
5964xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5965 xmlAttrPtr prop;
5966 xmlDocPtr doc;
5967
5968 if ((node == NULL) || (name == NULL)) return(NULL);
5969 /*
5970 * Check on the properties attached to the node
5971 */
5972 prop = node->properties;
5973 while (prop != NULL) {
5974 if (xmlStrEqual(prop->name, name)) {
5975 xmlChar *ret;
5976
5977 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5978 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5979 return(ret);
5980 }
5981 prop = prop->next;
5982 }
5983 if (!xmlCheckDTD) return(NULL);
5984
5985 /*
5986 * Check if there is a default declaration in the internal
5987 * or external subsets
5988 */
5989 doc = node->doc;
5990 if (doc != NULL) {
5991 xmlAttributePtr attrDecl;
5992 if (doc->intSubset != NULL) {
5993 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5994 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5995 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005996 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5997 /* return attribute declaration only if a default value is given
5998 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005999 return(xmlStrdup(attrDecl->defaultValue));
6000 }
6001 }
6002 return(NULL);
6003}
6004
6005/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006006 * xmlGetNoNsProp:
6007 * @node: the node
6008 * @name: the attribute name
6009 *
6010 * Search and get the value of an attribute associated to a node
6011 * This does the entity substitution.
6012 * This function looks in DTD attribute declaration for #FIXED or
6013 * default declaration values unless DTD use has been turned off.
6014 * This function is similar to xmlGetProp except it will accept only
6015 * an attribute in no namespace.
6016 *
6017 * Returns the attribute value or NULL if not found.
6018 * It's up to the caller to free the memory with xmlFree().
6019 */
6020xmlChar *
6021xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6022 xmlAttrPtr prop;
6023 xmlDocPtr doc;
6024
6025 if ((node == NULL) || (name == NULL)) return(NULL);
6026 /*
6027 * Check on the properties attached to the node
6028 */
6029 prop = node->properties;
6030 while (prop != NULL) {
6031 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6032 xmlChar *ret;
6033
6034 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6035 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6036 return(ret);
6037 }
6038 prop = prop->next;
6039 }
6040 if (!xmlCheckDTD) return(NULL);
6041
6042 /*
6043 * Check if there is a default declaration in the internal
6044 * or external subsets
6045 */
6046 doc = node->doc;
6047 if (doc != NULL) {
6048 xmlAttributePtr attrDecl;
6049 if (doc->intSubset != NULL) {
6050 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6051 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6052 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006053 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6054 /* return attribute declaration only if a default value is given
6055 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006056 return(xmlStrdup(attrDecl->defaultValue));
6057 }
6058 }
6059 return(NULL);
6060}
6061
6062/**
Owen Taylor3473f882001-02-23 17:55:21 +00006063 * xmlGetNsProp:
6064 * @node: the node
6065 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006066 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006067 *
6068 * Search and get the value of an attribute associated to a node
6069 * This attribute has to be anchored in the namespace specified.
6070 * This does the entity substitution.
6071 * This function looks in DTD attribute declaration for #FIXED or
6072 * default declaration values unless DTD use has been turned off.
6073 *
6074 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006075 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006076 */
6077xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006078xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006079 xmlAttrPtr prop;
6080 xmlDocPtr doc;
6081 xmlNsPtr ns;
6082
6083 if (node == NULL)
6084 return(NULL);
6085
6086 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006087 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006088 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006089 while (prop != NULL) {
6090 /*
6091 * One need to have
6092 * - same attribute names
6093 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006094 */
6095 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006096 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006097 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006098 xmlChar *ret;
6099
6100 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6101 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6102 return(ret);
6103 }
6104 prop = prop->next;
6105 }
6106 if (!xmlCheckDTD) return(NULL);
6107
6108 /*
6109 * Check if there is a default declaration in the internal
6110 * or external subsets
6111 */
6112 doc = node->doc;
6113 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006114 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006115 xmlAttributePtr attrDecl;
6116
Owen Taylor3473f882001-02-23 17:55:21 +00006117 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6118 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6119 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6120
6121 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6122 /*
6123 * The DTD declaration only allows a prefix search
6124 */
6125 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006126 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006127 return(xmlStrdup(attrDecl->defaultValue));
6128 }
6129 }
6130 }
6131 return(NULL);
6132}
6133
Daniel Veillard2156d432004-03-04 15:59:36 +00006134#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6135/**
6136 * xmlUnsetProp:
6137 * @node: the node
6138 * @name: the attribute name
6139 *
6140 * Remove an attribute carried by a node.
6141 * Returns 0 if successful, -1 if not found
6142 */
6143int
6144xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
6145 xmlAttrPtr prop, prev = NULL;;
6146
6147 if ((node == NULL) || (name == NULL))
6148 return(-1);
6149 prop = node->properties;
6150 while (prop != NULL) {
6151 if ((xmlStrEqual(prop->name, name)) &&
6152 (prop->ns == NULL)) {
6153 if (prev == NULL)
6154 node->properties = prop->next;
6155 else
6156 prev->next = prop->next;
6157 xmlFreeProp(prop);
6158 return(0);
6159 }
6160 prev = prop;
6161 prop = prop->next;
6162 }
6163 return(-1);
6164}
6165
6166/**
6167 * xmlUnsetNsProp:
6168 * @node: the node
6169 * @ns: the namespace definition
6170 * @name: the attribute name
6171 *
6172 * Remove an attribute carried by a node.
6173 * Returns 0 if successful, -1 if not found
6174 */
6175int
6176xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6177 xmlAttrPtr prop = node->properties, prev = NULL;;
6178
6179 if ((node == NULL) || (name == NULL))
6180 return(-1);
6181 if (ns == NULL)
6182 return(xmlUnsetProp(node, name));
6183 if (ns->href == NULL)
6184 return(-1);
6185 while (prop != NULL) {
6186 if ((xmlStrEqual(prop->name, name)) &&
6187 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
6188 if (prev == NULL)
6189 node->properties = prop->next;
6190 else
6191 prev->next = prop->next;
6192 xmlFreeProp(prop);
6193 return(0);
6194 }
6195 prev = prop;
6196 prop = prop->next;
6197 }
6198 return(-1);
6199}
6200#endif
6201
6202#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006203/**
6204 * xmlSetProp:
6205 * @node: the node
6206 * @name: the attribute name
6207 * @value: the attribute value
6208 *
6209 * Set (or reset) an attribute carried by a node.
6210 * Returns the attribute pointer.
6211 */
6212xmlAttrPtr
6213xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006214 xmlAttrPtr prop;
6215 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006216
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006217 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006218 return(NULL);
6219 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006220 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006221 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006222 if ((xmlStrEqual(prop->name, name)) &&
6223 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006224 xmlNodePtr oldprop = prop->children;
6225
Owen Taylor3473f882001-02-23 17:55:21 +00006226 prop->children = NULL;
6227 prop->last = NULL;
6228 if (value != NULL) {
6229 xmlChar *buffer;
6230 xmlNodePtr tmp;
6231
6232 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6233 prop->children = xmlStringGetNodeList(node->doc, buffer);
6234 prop->last = NULL;
6235 prop->doc = doc;
6236 tmp = prop->children;
6237 while (tmp != NULL) {
6238 tmp->parent = (xmlNodePtr) prop;
6239 tmp->doc = doc;
6240 if (tmp->next == NULL)
6241 prop->last = tmp;
6242 tmp = tmp->next;
6243 }
6244 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006245 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006246 if (oldprop != NULL)
6247 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006248 return(prop);
6249 }
6250 prop = prop->next;
6251 }
6252 prop = xmlNewProp(node, name, value);
6253 return(prop);
6254}
6255
6256/**
6257 * xmlSetNsProp:
6258 * @node: the node
6259 * @ns: the namespace definition
6260 * @name: the attribute name
6261 * @value: the attribute value
6262 *
6263 * Set (or reset) an attribute carried by a node.
6264 * The ns structure must be in scope, this is not checked.
6265 *
6266 * Returns the attribute pointer.
6267 */
6268xmlAttrPtr
6269xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6270 const xmlChar *value) {
6271 xmlAttrPtr prop;
6272
6273 if ((node == NULL) || (name == NULL))
6274 return(NULL);
6275
6276 if (ns == NULL)
6277 return(xmlSetProp(node, name, value));
6278 if (ns->href == NULL)
6279 return(NULL);
6280 prop = node->properties;
6281
6282 while (prop != NULL) {
6283 /*
6284 * One need to have
6285 * - same attribute names
6286 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006287 */
6288 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006289 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006290 if (prop->children != NULL)
6291 xmlFreeNodeList(prop->children);
6292 prop->children = NULL;
6293 prop->last = NULL;
6294 prop->ns = ns;
6295 if (value != NULL) {
6296 xmlChar *buffer;
6297 xmlNodePtr tmp;
6298
6299 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6300 prop->children = xmlStringGetNodeList(node->doc, buffer);
6301 prop->last = NULL;
6302 tmp = prop->children;
6303 while (tmp != NULL) {
6304 tmp->parent = (xmlNodePtr) prop;
6305 if (tmp->next == NULL)
6306 prop->last = tmp;
6307 tmp = tmp->next;
6308 }
6309 xmlFree(buffer);
6310 }
6311 return(prop);
6312 }
6313 prop = prop->next;
6314 }
6315 prop = xmlNewNsProp(node, ns, name, value);
6316 return(prop);
6317}
6318
Daniel Veillard652327a2003-09-29 18:02:38 +00006319#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006320
6321/**
Owen Taylor3473f882001-02-23 17:55:21 +00006322 * xmlNodeIsText:
6323 * @node: the node
6324 *
6325 * Is this node a Text node ?
6326 * Returns 1 yes, 0 no
6327 */
6328int
6329xmlNodeIsText(xmlNodePtr node) {
6330 if (node == NULL) return(0);
6331
6332 if (node->type == XML_TEXT_NODE) return(1);
6333 return(0);
6334}
6335
6336/**
6337 * xmlIsBlankNode:
6338 * @node: the node
6339 *
6340 * Checks whether this node is an empty or whitespace only
6341 * (and possibly ignorable) text-node.
6342 *
6343 * Returns 1 yes, 0 no
6344 */
6345int
6346xmlIsBlankNode(xmlNodePtr node) {
6347 const xmlChar *cur;
6348 if (node == NULL) return(0);
6349
Daniel Veillard7db37732001-07-12 01:20:08 +00006350 if ((node->type != XML_TEXT_NODE) &&
6351 (node->type != XML_CDATA_SECTION_NODE))
6352 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006353 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006354 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006355 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006356 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006357 cur++;
6358 }
6359
6360 return(1);
6361}
6362
6363/**
6364 * xmlTextConcat:
6365 * @node: the node
6366 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006367 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006368 *
6369 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006370 *
6371 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006372 */
6373
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006374int
Owen Taylor3473f882001-02-23 17:55:21 +00006375xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006376 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006377
6378 if ((node->type != XML_TEXT_NODE) &&
6379 (node->type != XML_CDATA_SECTION_NODE)) {
6380#ifdef DEBUG_TREE
6381 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006382 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006383#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006384 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006385 }
William M. Brack7762bb12004-01-04 14:49:01 +00006386 /* need to check if content is currently in the dictionary */
6387 if ((node->doc != NULL) && (node->doc->dict != NULL) &&
6388 xmlDictOwns(node->doc->dict, node->content)) {
6389 node->content = xmlStrncatNew(node->content, content, len);
6390 } else {
6391 node->content = xmlStrncat(node->content, content, len);
6392 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006393 if (node->content == NULL)
6394 return(-1);
6395 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006396}
6397
6398/************************************************************************
6399 * *
6400 * Output : to a FILE or in memory *
6401 * *
6402 ************************************************************************/
6403
Owen Taylor3473f882001-02-23 17:55:21 +00006404/**
6405 * xmlBufferCreate:
6406 *
6407 * routine to create an XML buffer.
6408 * returns the new structure.
6409 */
6410xmlBufferPtr
6411xmlBufferCreate(void) {
6412 xmlBufferPtr ret;
6413
6414 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6415 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006416 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006417 return(NULL);
6418 }
6419 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006420 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006421 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006422 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006423 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006424 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006425 xmlFree(ret);
6426 return(NULL);
6427 }
6428 ret->content[0] = 0;
6429 return(ret);
6430}
6431
6432/**
6433 * xmlBufferCreateSize:
6434 * @size: initial size of buffer
6435 *
6436 * routine to create an XML buffer.
6437 * returns the new structure.
6438 */
6439xmlBufferPtr
6440xmlBufferCreateSize(size_t size) {
6441 xmlBufferPtr ret;
6442
6443 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6444 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006445 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006446 return(NULL);
6447 }
6448 ret->use = 0;
6449 ret->alloc = xmlBufferAllocScheme;
6450 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6451 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006452 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006453 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006454 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006455 xmlFree(ret);
6456 return(NULL);
6457 }
6458 ret->content[0] = 0;
6459 } else
6460 ret->content = NULL;
6461 return(ret);
6462}
6463
6464/**
Daniel Veillard53350552003-09-18 13:35:51 +00006465 * xmlBufferCreateStatic:
6466 * @mem: the memory area
6467 * @size: the size in byte
6468 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006469 * routine to create an XML buffer from an immutable memory area.
6470 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006471 * present until the end of the buffer lifetime.
6472 *
6473 * returns the new structure.
6474 */
6475xmlBufferPtr
6476xmlBufferCreateStatic(void *mem, size_t size) {
6477 xmlBufferPtr ret;
6478
6479 if ((mem == NULL) || (size == 0))
6480 return(NULL);
6481
6482 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6483 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006484 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006485 return(NULL);
6486 }
6487 ret->use = size;
6488 ret->size = size;
6489 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6490 ret->content = (xmlChar *) mem;
6491 return(ret);
6492}
6493
6494/**
Owen Taylor3473f882001-02-23 17:55:21 +00006495 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006496 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006497 * @scheme: allocation scheme to use
6498 *
6499 * Sets the allocation scheme for this buffer
6500 */
6501void
6502xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6503 xmlBufferAllocationScheme scheme) {
6504 if (buf == NULL) {
6505#ifdef DEBUG_BUFFER
6506 xmlGenericError(xmlGenericErrorContext,
6507 "xmlBufferSetAllocationScheme: buf == NULL\n");
6508#endif
6509 return;
6510 }
Daniel Veillard53350552003-09-18 13:35:51 +00006511 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006512
6513 buf->alloc = scheme;
6514}
6515
6516/**
6517 * xmlBufferFree:
6518 * @buf: the buffer to free
6519 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006520 * Frees an XML buffer. It frees both the content and the structure which
6521 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006522 */
6523void
6524xmlBufferFree(xmlBufferPtr buf) {
6525 if (buf == NULL) {
6526#ifdef DEBUG_BUFFER
6527 xmlGenericError(xmlGenericErrorContext,
6528 "xmlBufferFree: buf == NULL\n");
6529#endif
6530 return;
6531 }
Daniel Veillard53350552003-09-18 13:35:51 +00006532
6533 if ((buf->content != NULL) &&
6534 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006535 xmlFree(buf->content);
6536 }
Owen Taylor3473f882001-02-23 17:55:21 +00006537 xmlFree(buf);
6538}
6539
6540/**
6541 * xmlBufferEmpty:
6542 * @buf: the buffer
6543 *
6544 * empty a buffer.
6545 */
6546void
6547xmlBufferEmpty(xmlBufferPtr buf) {
6548 if (buf->content == NULL) return;
6549 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006550 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006551 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006552 } else {
6553 memset(buf->content, 0, buf->size);
6554 }
Owen Taylor3473f882001-02-23 17:55:21 +00006555}
6556
6557/**
6558 * xmlBufferShrink:
6559 * @buf: the buffer to dump
6560 * @len: the number of xmlChar to remove
6561 *
6562 * Remove the beginning of an XML buffer.
6563 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006564 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006565 */
6566int
6567xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6568 if (len == 0) return(0);
6569 if (len > buf->use) return(-1);
6570
6571 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006572 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6573 buf->content += len;
6574 } else {
6575 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6576 buf->content[buf->use] = 0;
6577 }
Owen Taylor3473f882001-02-23 17:55:21 +00006578 return(len);
6579}
6580
6581/**
6582 * xmlBufferGrow:
6583 * @buf: the buffer
6584 * @len: the minimum free size to allocate
6585 *
6586 * Grow the available space of an XML buffer.
6587 *
6588 * Returns the new available space or -1 in case of error
6589 */
6590int
6591xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6592 int size;
6593 xmlChar *newbuf;
6594
Daniel Veillard53350552003-09-18 13:35:51 +00006595 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006596 if (len + buf->use < buf->size) return(0);
6597
6598 size = buf->use + len + 100;
6599
6600 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006601 if (newbuf == NULL) {
6602 xmlTreeErrMemory("growing buffer");
6603 return(-1);
6604 }
Owen Taylor3473f882001-02-23 17:55:21 +00006605 buf->content = newbuf;
6606 buf->size = size;
6607 return(buf->size - buf->use);
6608}
6609
6610/**
6611 * xmlBufferDump:
6612 * @file: the file output
6613 * @buf: the buffer to dump
6614 *
6615 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006616 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006617 */
6618int
6619xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6620 int ret;
6621
6622 if (buf == NULL) {
6623#ifdef DEBUG_BUFFER
6624 xmlGenericError(xmlGenericErrorContext,
6625 "xmlBufferDump: buf == NULL\n");
6626#endif
6627 return(0);
6628 }
6629 if (buf->content == NULL) {
6630#ifdef DEBUG_BUFFER
6631 xmlGenericError(xmlGenericErrorContext,
6632 "xmlBufferDump: buf->content == NULL\n");
6633#endif
6634 return(0);
6635 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006636 if (file == NULL)
6637 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006638 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6639 return(ret);
6640}
6641
6642/**
6643 * xmlBufferContent:
6644 * @buf: the buffer
6645 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006646 * Function to extract the content of a buffer
6647 *
Owen Taylor3473f882001-02-23 17:55:21 +00006648 * Returns the internal content
6649 */
6650
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006651const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006652xmlBufferContent(const xmlBufferPtr buf)
6653{
6654 if(!buf)
6655 return NULL;
6656
6657 return buf->content;
6658}
6659
6660/**
6661 * xmlBufferLength:
6662 * @buf: the buffer
6663 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006664 * Function to get the length of a buffer
6665 *
Owen Taylor3473f882001-02-23 17:55:21 +00006666 * Returns the length of data in the internal content
6667 */
6668
6669int
6670xmlBufferLength(const xmlBufferPtr buf)
6671{
6672 if(!buf)
6673 return 0;
6674
6675 return buf->use;
6676}
6677
6678/**
6679 * xmlBufferResize:
6680 * @buf: the buffer to resize
6681 * @size: the desired size
6682 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006683 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006684 *
6685 * Returns 0 in case of problems, 1 otherwise
6686 */
6687int
6688xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6689{
6690 unsigned int newSize;
6691 xmlChar* rebuf = NULL;
6692
Daniel Veillard53350552003-09-18 13:35:51 +00006693 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6694
Owen Taylor3473f882001-02-23 17:55:21 +00006695 /*take care of empty case*/
6696 newSize = (buf->size ? buf->size*2 : size);
6697
6698 /* Don't resize if we don't have to */
6699 if (size < buf->size)
6700 return 1;
6701
6702 /* figure out new size */
6703 switch (buf->alloc){
6704 case XML_BUFFER_ALLOC_DOUBLEIT:
6705 while (size > newSize) newSize *= 2;
6706 break;
6707 case XML_BUFFER_ALLOC_EXACT:
6708 newSize = size+10;
6709 break;
6710 default:
6711 newSize = size+10;
6712 break;
6713 }
6714
6715 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006716 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006717 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006718 rebuf = (xmlChar *) xmlRealloc(buf->content,
6719 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006720 } else {
6721 /*
6722 * if we are reallocating a buffer far from being full, it's
6723 * better to make a new allocation and copy only the used range
6724 * and free the old one.
6725 */
6726 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6727 if (rebuf != NULL) {
6728 memcpy(rebuf, buf->content, buf->use);
6729 xmlFree(buf->content);
6730 }
Daniel Veillarde5984082003-08-19 22:21:13 +00006731 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006732 }
Owen Taylor3473f882001-02-23 17:55:21 +00006733 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006734 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006735 return 0;
6736 }
6737 buf->content = rebuf;
6738 buf->size = newSize;
6739
6740 return 1;
6741}
6742
6743/**
6744 * xmlBufferAdd:
6745 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006746 * @str: the #xmlChar string
6747 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006748 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006749 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006750 * str is recomputed.
6751 */
6752void
6753xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6754 unsigned int needSize;
6755
6756 if (str == NULL) {
6757#ifdef DEBUG_BUFFER
6758 xmlGenericError(xmlGenericErrorContext,
6759 "xmlBufferAdd: str == NULL\n");
6760#endif
6761 return;
6762 }
Daniel Veillard53350552003-09-18 13:35:51 +00006763 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006764 if (len < -1) {
6765#ifdef DEBUG_BUFFER
6766 xmlGenericError(xmlGenericErrorContext,
6767 "xmlBufferAdd: len < 0\n");
6768#endif
6769 return;
6770 }
6771 if (len == 0) return;
6772
6773 if (len < 0)
6774 len = xmlStrlen(str);
6775
6776 if (len <= 0) return;
6777
6778 needSize = buf->use + len + 2;
6779 if (needSize > buf->size){
6780 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006781 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006782 return;
6783 }
6784 }
6785
6786 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6787 buf->use += len;
6788 buf->content[buf->use] = 0;
6789}
6790
6791/**
6792 * xmlBufferAddHead:
6793 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006794 * @str: the #xmlChar string
6795 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006796 *
6797 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006798 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00006799 */
6800void
6801xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6802 unsigned int needSize;
6803
Daniel Veillard53350552003-09-18 13:35:51 +00006804 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006805 if (str == NULL) {
6806#ifdef DEBUG_BUFFER
6807 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006808 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006809#endif
6810 return;
6811 }
6812 if (len < -1) {
6813#ifdef DEBUG_BUFFER
6814 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006815 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006816#endif
6817 return;
6818 }
6819 if (len == 0) return;
6820
6821 if (len < 0)
6822 len = xmlStrlen(str);
6823
6824 if (len <= 0) return;
6825
6826 needSize = buf->use + len + 2;
6827 if (needSize > buf->size){
6828 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006829 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006830 return;
6831 }
6832 }
6833
6834 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6835 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6836 buf->use += len;
6837 buf->content[buf->use] = 0;
6838}
6839
6840/**
6841 * xmlBufferCat:
6842 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006843 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006844 *
6845 * Append a zero terminated string to an XML buffer.
6846 */
6847void
6848xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillard53350552003-09-18 13:35:51 +00006849 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006850 if (str != NULL)
6851 xmlBufferAdd(buf, str, -1);
6852}
6853
6854/**
6855 * xmlBufferCCat:
6856 * @buf: the buffer to dump
6857 * @str: the C char string
6858 *
6859 * Append a zero terminated C string to an XML buffer.
6860 */
6861void
6862xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6863 const char *cur;
6864
Daniel Veillard53350552003-09-18 13:35:51 +00006865 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006866 if (str == NULL) {
6867#ifdef DEBUG_BUFFER
6868 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006869 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006870#endif
6871 return;
6872 }
6873 for (cur = str;*cur != 0;cur++) {
6874 if (buf->use + 10 >= buf->size) {
6875 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006876 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006877 return;
6878 }
6879 }
6880 buf->content[buf->use++] = *cur;
6881 }
6882 buf->content[buf->use] = 0;
6883}
6884
6885/**
6886 * xmlBufferWriteCHAR:
6887 * @buf: the XML buffer
6888 * @string: the string to add
6889 *
6890 * routine which manages and grows an output buffer. This one adds
6891 * xmlChars at the end of the buffer.
6892 */
6893void
Daniel Veillard53350552003-09-18 13:35:51 +00006894xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
6895 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006896 xmlBufferCat(buf, string);
6897}
6898
6899/**
6900 * xmlBufferWriteChar:
6901 * @buf: the XML buffer output
6902 * @string: the string to add
6903 *
6904 * routine which manage and grows an output buffer. This one add
6905 * C chars at the end of the array.
6906 */
6907void
6908xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillard53350552003-09-18 13:35:51 +00006909 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006910 xmlBufferCCat(buf, string);
6911}
6912
6913
6914/**
6915 * xmlBufferWriteQuotedString:
6916 * @buf: the XML buffer output
6917 * @string: the string to add
6918 *
6919 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006920 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006921 * quote or double-quotes internally
6922 */
6923void
6924xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00006925 const xmlChar *cur, *base;
Daniel Veillard53350552003-09-18 13:35:51 +00006926 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00006927 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00006928 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00006929#ifdef DEBUG_BUFFER
6930 xmlGenericError(xmlGenericErrorContext,
6931 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6932#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00006933 xmlBufferCCat(buf, "\"");
6934 base = cur = string;
6935 while(*cur != 0){
6936 if(*cur == '"'){
6937 if (base != cur)
6938 xmlBufferAdd(buf, base, cur - base);
6939 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6940 cur++;
6941 base = cur;
6942 }
6943 else {
6944 cur++;
6945 }
6946 }
6947 if (base != cur)
6948 xmlBufferAdd(buf, base, cur - base);
6949 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006950 }
Daniel Veillard39057f42003-08-04 01:33:43 +00006951 else{
6952 xmlBufferCCat(buf, "\'");
6953 xmlBufferCat(buf, string);
6954 xmlBufferCCat(buf, "\'");
6955 }
Owen Taylor3473f882001-02-23 17:55:21 +00006956 } else {
6957 xmlBufferCCat(buf, "\"");
6958 xmlBufferCat(buf, string);
6959 xmlBufferCCat(buf, "\"");
6960 }
6961}
6962
6963
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00006964/**
6965 * xmlGetDocCompressMode:
6966 * @doc: the document
6967 *
6968 * get the compression ratio for a document, ZLIB based
6969 * Returns 0 (uncompressed) to 9 (max compression)
6970 */
6971int
6972xmlGetDocCompressMode (xmlDocPtr doc) {
6973 if (doc == NULL) return(-1);
6974 return(doc->compression);
6975}
6976
6977/**
6978 * xmlSetDocCompressMode:
6979 * @doc: the document
6980 * @mode: the compression ratio
6981 *
6982 * set the compression ratio for a document, ZLIB based
6983 * Correct values: 0 (uncompressed) to 9 (max compression)
6984 */
6985void
6986xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6987 if (doc == NULL) return;
6988 if (mode < 0) doc->compression = 0;
6989 else if (mode > 9) doc->compression = 9;
6990 else doc->compression = mode;
6991}
6992
6993/**
6994 * xmlGetCompressMode:
6995 *
6996 * get the default compression mode used, ZLIB based.
6997 * Returns 0 (uncompressed) to 9 (max compression)
6998 */
6999int
7000xmlGetCompressMode(void)
7001{
7002 return (xmlCompressMode);
7003}
7004
7005/**
7006 * xmlSetCompressMode:
7007 * @mode: the compression ratio
7008 *
7009 * set the default compression mode used, ZLIB based
7010 * Correct values: 0 (uncompressed) to 9 (max compression)
7011 */
7012void
7013xmlSetCompressMode(int mode) {
7014 if (mode < 0) xmlCompressMode = 0;
7015 else if (mode > 9) xmlCompressMode = 9;
7016 else xmlCompressMode = mode;
7017}
7018