blob: 253132d7530ef1cf59a8038de28f91c3a9a9eb5f [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
Daniel Veillardd5c2f922002-11-21 14:10:52 +00004 * References:
5 * XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
6 *
Owen Taylor3473f882001-02-23 17:55:21 +00007 * See Copyright for the status of this software.
8 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00009 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000010 *
Owen Taylor3473f882001-02-23 17:55:21 +000011 */
12
Daniel Veillard34ce8be2002-03-18 19:37:11 +000013#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000014#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000015
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24#ifdef HAVE_ZLIB_H
25#include <zlib.h>
26#endif
27
28#include <libxml/xmlmemory.h>
29#include <libxml/tree.h>
30#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000031#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000032#include <libxml/entities.h>
33#include <libxml/valid.h>
34#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000035#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000036#include <libxml/globals.h>
Daniel Veillardd5c2f922002-11-21 14:10:52 +000037#ifdef LIBXML_HTML_ENABLED
38#include <libxml/HTMLtree.h>
39#endif
Owen Taylor3473f882001-02-23 17:55:21 +000040
Daniel Veillarda880b122003-04-21 21:36:41 +000041int __xmlRegisterCallbacks = 0;
42
Daniel Veillard56a4cb82001-03-24 17:00:36 +000043xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
44
45/************************************************************************
46 * *
Daniel Veillard18ec16e2003-10-07 23:16:40 +000047 * Tree memory error handler *
48 * *
49 ************************************************************************/
50/**
51 * xmlTreeErrMemory:
52 * @extra: extra informations
53 *
54 * Handle an out of memory condition
55 */
56static void
57xmlTreeErrMemory(const char *extra)
58{
59 __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
60}
61
62/**
63 * xmlTreeErr:
64 * @code: the error number
65 * @extra: extra informations
66 *
67 * Handle an out of memory condition
68 */
69static void
70xmlTreeErr(int code, xmlNodePtr node, const char *extra)
71{
72 const char *msg = NULL;
73
74 switch(code) {
75 case XML_TREE_INVALID_HEX:
Daniel Veillardac996a12004-07-30 12:02:58 +000076 msg = "invalid hexadecimal character value\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000077 break;
78 case XML_TREE_INVALID_DEC:
Daniel Veillardac996a12004-07-30 12:02:58 +000079 msg = "invalid decimal character value\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000080 break;
81 case XML_TREE_UNTERMINATED_ENTITY:
Daniel Veillardac996a12004-07-30 12:02:58 +000082 msg = "unterminated entity reference %15s\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000083 break;
84 default:
Daniel Veillardac996a12004-07-30 12:02:58 +000085 msg = "unexpected error number\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000086 }
87 __xmlSimpleError(XML_FROM_TREE, code, node, msg, extra);
88}
89
90/************************************************************************
91 * *
Daniel Veillard56a4cb82001-03-24 17:00:36 +000092 * A few static variables and macros *
93 * *
94 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000095/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000096const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000097/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000098const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000099 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +0000100/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +0000101const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
102
Owen Taylor3473f882001-02-23 17:55:21 +0000103static int xmlCompressMode = 0;
104static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000105
Owen Taylor3473f882001-02-23 17:55:21 +0000106#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
107 xmlNodePtr ulccur = (n)->children; \
108 if (ulccur == NULL) { \
109 (n)->last = NULL; \
110 } else { \
111 while (ulccur->next != NULL) { \
112 ulccur->parent = (n); \
113 ulccur = ulccur->next; \
114 } \
115 ulccur->parent = (n); \
116 (n)->last = ulccur; \
117}}
118
119/* #define DEBUG_BUFFER */
120/* #define DEBUG_TREE */
121
122/************************************************************************
123 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000124 * Functions to move to entities.c once the *
125 * API freeze is smoothen and they can be made public. *
126 * *
127 ************************************************************************/
128#include <libxml/hash.h>
129
Daniel Veillard652327a2003-09-29 18:02:38 +0000130#ifdef LIBXML_TREE_ENABLED
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000131/**
132 * xmlGetEntityFromDtd:
133 * @dtd: A pointer to the DTD to search
134 * @name: The entity name
135 *
136 * Do an entity lookup in the DTD entity hash table and
137 * return the corresponding entity, if found.
138 *
139 * Returns A pointer to the entity structure or NULL if not found.
140 */
141static xmlEntityPtr
142xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
143 xmlEntitiesTablePtr table;
144
145 if((dtd != NULL) && (dtd->entities != NULL)) {
146 table = (xmlEntitiesTablePtr) dtd->entities;
147 return((xmlEntityPtr) xmlHashLookup(table, name));
148 /* return(xmlGetEntityFromTable(table, name)); */
149 }
150 return(NULL);
151}
152/**
153 * xmlGetParameterEntityFromDtd:
154 * @dtd: A pointer to the DTD to search
155 * @name: The entity name
156 *
157 * Do an entity lookup in the DTD pararmeter entity hash table and
158 * return the corresponding entity, if found.
159 *
160 * Returns A pointer to the entity structure or NULL if not found.
161 */
162static xmlEntityPtr
163xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
164 xmlEntitiesTablePtr table;
165
166 if ((dtd != NULL) && (dtd->pentities != NULL)) {
167 table = (xmlEntitiesTablePtr) dtd->pentities;
168 return((xmlEntityPtr) xmlHashLookup(table, name));
169 /* return(xmlGetEntityFromTable(table, name)); */
170 }
171 return(NULL);
172}
Daniel Veillard652327a2003-09-29 18:02:38 +0000173#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000174
175/************************************************************************
176 * *
Daniel Veillardc00cda82003-04-07 10:22:39 +0000177 * QName handling helper *
178 * *
179 ************************************************************************/
180
181/**
182 * xmlBuildQName:
183 * @ncname: the Name
184 * @prefix: the prefix
185 * @memory: preallocated memory
186 * @len: preallocated memory length
187 *
188 * Builds the QName @prefix:@ncname in @memory if there is enough space
189 * and prefix is not NULL nor empty, otherwise allocate a new string.
190 * If prefix is NULL or empty it returns ncname.
191 *
192 * Returns the new string which must be freed by the caller if different from
193 * @memory and @ncname or NULL in case of error
194 */
195xmlChar *
196xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
197 xmlChar *memory, int len) {
198 int lenn, lenp;
199 xmlChar *ret;
200
Daniel Veillard3b7840c2003-09-11 23:42:01 +0000201 if (ncname == NULL) return(NULL);
202 if (prefix == NULL) return((xmlChar *) ncname);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000203
204 lenn = strlen((char *) ncname);
205 lenp = strlen((char *) prefix);
206
207 if ((memory == NULL) || (len < lenn + lenp + 2)) {
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000208 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000209 if (ret == NULL) {
210 xmlTreeErrMemory("building QName");
211 return(NULL);
212 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000213 } else {
214 ret = memory;
215 }
216 memcpy(&ret[0], prefix, lenp);
217 ret[lenp] = ':';
218 memcpy(&ret[lenp + 1], ncname, lenn);
219 ret[lenn + lenp + 1] = 0;
220 return(ret);
221}
222
223/**
224 * xmlSplitQName2:
225 * @name: the full QName
226 * @prefix: a xmlChar **
227 *
228 * parse an XML qualified name string
229 *
230 * [NS 5] QName ::= (Prefix ':')? LocalPart
231 *
232 * [NS 6] Prefix ::= NCName
233 *
234 * [NS 7] LocalPart ::= NCName
235 *
236 * Returns NULL if not a QName, otherwise the local part, and prefix
237 * is updated to get the Prefix if any.
238 */
239
240xmlChar *
241xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
242 int len = 0;
243 xmlChar *ret = NULL;
244
245 *prefix = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000246 if (name == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000247
248#ifndef XML_XML_NAMESPACE
249 /* xml: prefix is not really a namespace */
250 if ((name[0] == 'x') && (name[1] == 'm') &&
251 (name[2] == 'l') && (name[3] == ':'))
252 return(NULL);
253#endif
254
255 /* nasty but valid */
256 if (name[0] == ':')
257 return(NULL);
258
259 /*
260 * we are not trying to validate but just to cut, and yes it will
261 * work even if this is as set of UTF-8 encoded chars
262 */
263 while ((name[len] != 0) && (name[len] != ':'))
264 len++;
265
266 if (name[len] == 0)
267 return(NULL);
268
269 *prefix = xmlStrndup(name, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000270 if (*prefix == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000271 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000272 return(NULL);
273 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000274 ret = xmlStrdup(&name[len + 1]);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000275 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000276 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000277 if (*prefix != NULL) {
278 xmlFree(*prefix);
279 *prefix = NULL;
280 }
281 return(NULL);
282 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000283
284 return(ret);
285}
286
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000287/**
288 * xmlSplitQName3:
289 * @name: the full QName
290 * @len: an int *
291 *
292 * parse an XML qualified name string,i
293 *
294 * returns NULL if it is not a Qualified Name, otherwise, update len
295 * with the lenght in byte of the prefix and return a pointer
296 */
297
298const xmlChar *
299xmlSplitQName3(const xmlChar *name, int *len) {
300 int l = 0;
301
302 if (name == NULL) return(NULL);
303 if (len == NULL) return(NULL);
304
305 /* nasty but valid */
306 if (name[0] == ':')
307 return(NULL);
308
309 /*
310 * we are not trying to validate but just to cut, and yes it will
311 * work even if this is as set of UTF-8 encoded chars
312 */
313 while ((name[l] != 0) && (name[l] != ':'))
314 l++;
315
316 if (name[l] == 0)
317 return(NULL);
318
319 *len = l;
320
321 return(&name[l+1]);
322}
323
Daniel Veillardc00cda82003-04-07 10:22:39 +0000324/************************************************************************
325 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000326 * Check Name, NCName and QName strings *
327 * *
328 ************************************************************************/
329
330#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
331
Daniel 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 Veillard46de64e2002-05-29 08:21:33 +00001864 return(NULL);
1865 }
1866 memset(cur, 0, sizeof(xmlAttr));
1867 cur->type = XML_ATTRIBUTE_NODE;
1868
1869 cur->parent = node;
1870 if (node != NULL) {
1871 doc = node->doc;
1872 cur->doc = doc;
1873 }
1874 cur->ns = ns;
1875 cur->name = name;
1876 if (value != NULL) {
1877 xmlChar *buffer;
1878 xmlNodePtr tmp;
1879
1880 buffer = xmlEncodeEntitiesReentrant(doc, value);
1881 cur->children = xmlStringGetNodeList(doc, buffer);
1882 cur->last = NULL;
1883 tmp = cur->children;
1884 while (tmp != NULL) {
1885 tmp->parent = (xmlNodePtr) cur;
1886 if (tmp->next == NULL)
1887 cur->last = tmp;
1888 tmp = tmp->next;
1889 }
1890 xmlFree(buffer);
1891 }
1892
1893 /*
1894 * Add it at the end to preserve parsing order ...
1895 */
1896 if (node != NULL) {
1897 if (node->properties == NULL) {
1898 node->properties = cur;
1899 } else {
1900 xmlAttrPtr prev = node->properties;
1901
1902 while (prev->next != NULL) prev = prev->next;
1903 prev->next = cur;
1904 cur->prev = prev;
1905 }
1906 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001907
Daniel Veillarda880b122003-04-21 21:36:41 +00001908 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001909 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001910 return(cur);
1911}
1912
1913/**
Owen Taylor3473f882001-02-23 17:55:21 +00001914 * xmlNewDocProp:
1915 * @doc: the document
1916 * @name: the name of the attribute
1917 * @value: the value of the attribute
1918 *
1919 * Create a new property carried by a document.
1920 * Returns a pointer to the attribute
1921 */
1922xmlAttrPtr
1923xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1924 xmlAttrPtr cur;
1925
1926 if (name == NULL) {
1927#ifdef DEBUG_TREE
1928 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001929 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001930#endif
1931 return(NULL);
1932 }
1933
1934 /*
1935 * Allocate a new property and fill the fields.
1936 */
1937 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1938 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001939 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001940 return(NULL);
1941 }
1942 memset(cur, 0, sizeof(xmlAttr));
1943 cur->type = XML_ATTRIBUTE_NODE;
1944
1945 cur->name = xmlStrdup(name);
1946 cur->doc = doc;
1947 if (value != NULL) {
1948 xmlNodePtr tmp;
1949
1950 cur->children = xmlStringGetNodeList(doc, value);
1951 cur->last = NULL;
1952
1953 tmp = cur->children;
1954 while (tmp != NULL) {
1955 tmp->parent = (xmlNodePtr) cur;
1956 if (tmp->next == NULL)
1957 cur->last = tmp;
1958 tmp = tmp->next;
1959 }
1960 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001961
Daniel Veillarda880b122003-04-21 21:36:41 +00001962 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001963 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001964 return(cur);
1965}
1966
1967/**
1968 * xmlFreePropList:
1969 * @cur: the first property in the list
1970 *
1971 * Free a property and all its siblings, all the children are freed too.
1972 */
1973void
1974xmlFreePropList(xmlAttrPtr cur) {
1975 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001976 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001977 while (cur != NULL) {
1978 next = cur->next;
1979 xmlFreeProp(cur);
1980 cur = next;
1981 }
1982}
1983
1984/**
1985 * xmlFreeProp:
1986 * @cur: an attribute
1987 *
1988 * Free one attribute, all the content is freed too
1989 */
1990void
1991xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001992 xmlDictPtr dict = NULL;
1993 if (cur == NULL) return;
1994
1995 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001996
Daniel Veillarda880b122003-04-21 21:36:41 +00001997 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001998 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1999
Owen Taylor3473f882001-02-23 17:55:21 +00002000 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00002001 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
2002 ((cur->parent->doc->intSubset != NULL) ||
2003 (cur->parent->doc->extSubset != NULL))) {
2004 if (xmlIsID(cur->parent->doc, cur->parent, cur))
2005 xmlRemoveID(cur->parent->doc, cur);
2006 }
Owen Taylor3473f882001-02-23 17:55:21 +00002007 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002008 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002009 xmlFree(cur);
2010}
2011
Daniel Veillard652327a2003-09-29 18:02:38 +00002012#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002013/**
2014 * xmlRemoveProp:
2015 * @cur: an attribute
2016 *
2017 * Unlink and free one attribute, all the content is freed too
2018 * Note this doesn't work for namespace definition attributes
2019 *
2020 * Returns 0 if success and -1 in case of error.
2021 */
2022int
2023xmlRemoveProp(xmlAttrPtr cur) {
2024 xmlAttrPtr tmp;
2025 if (cur == NULL) {
2026#ifdef DEBUG_TREE
2027 xmlGenericError(xmlGenericErrorContext,
2028 "xmlRemoveProp : cur == NULL\n");
2029#endif
2030 return(-1);
2031 }
2032 if (cur->parent == NULL) {
2033#ifdef DEBUG_TREE
2034 xmlGenericError(xmlGenericErrorContext,
2035 "xmlRemoveProp : cur->parent == NULL\n");
2036#endif
2037 return(-1);
2038 }
2039 tmp = cur->parent->properties;
2040 if (tmp == cur) {
2041 cur->parent->properties = cur->next;
2042 xmlFreeProp(cur);
2043 return(0);
2044 }
2045 while (tmp != NULL) {
2046 if (tmp->next == cur) {
2047 tmp->next = cur->next;
2048 if (tmp->next != NULL)
2049 tmp->next->prev = tmp;
2050 xmlFreeProp(cur);
2051 return(0);
2052 }
2053 tmp = tmp->next;
2054 }
2055#ifdef DEBUG_TREE
2056 xmlGenericError(xmlGenericErrorContext,
2057 "xmlRemoveProp : attribute not owned by its node\n");
2058#endif
2059 return(-1);
2060}
Daniel Veillard652327a2003-09-29 18:02:38 +00002061#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002062
2063/**
2064 * xmlNewPI:
2065 * @name: the processing instruction name
2066 * @content: the PI content
2067 *
2068 * Creation of a processing instruction element.
2069 * Returns a pointer to the new node object.
2070 */
2071xmlNodePtr
2072xmlNewPI(const xmlChar *name, const xmlChar *content) {
2073 xmlNodePtr cur;
2074
2075 if (name == NULL) {
2076#ifdef DEBUG_TREE
2077 xmlGenericError(xmlGenericErrorContext,
2078 "xmlNewPI : name == NULL\n");
2079#endif
2080 return(NULL);
2081 }
2082
2083 /*
2084 * Allocate a new node and fill the fields.
2085 */
2086 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2087 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002088 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002089 return(NULL);
2090 }
2091 memset(cur, 0, sizeof(xmlNode));
2092 cur->type = XML_PI_NODE;
2093
2094 cur->name = xmlStrdup(name);
2095 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002096 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002097 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002098
Daniel Veillarda880b122003-04-21 21:36:41 +00002099 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002100 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002101 return(cur);
2102}
2103
2104/**
2105 * xmlNewNode:
2106 * @ns: namespace if any
2107 * @name: the node name
2108 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002109 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002110 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002111 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2112 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002113 */
2114xmlNodePtr
2115xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2116 xmlNodePtr cur;
2117
2118 if (name == NULL) {
2119#ifdef DEBUG_TREE
2120 xmlGenericError(xmlGenericErrorContext,
2121 "xmlNewNode : name == NULL\n");
2122#endif
2123 return(NULL);
2124 }
2125
2126 /*
2127 * Allocate a new node and fill the fields.
2128 */
2129 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2130 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002131 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002132 return(NULL);
2133 }
2134 memset(cur, 0, sizeof(xmlNode));
2135 cur->type = XML_ELEMENT_NODE;
2136
2137 cur->name = xmlStrdup(name);
2138 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002139
Daniel Veillarda880b122003-04-21 21:36:41 +00002140 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002141 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002142 return(cur);
2143}
2144
2145/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002146 * xmlNewNodeEatName:
2147 * @ns: namespace if any
2148 * @name: the node name
2149 *
2150 * Creation of a new node element. @ns is optional (NULL).
2151 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002152 * Returns a pointer to the new node object, with pointer @name as
2153 * new node's name. Use xmlNewNode() if a copy of @name string is
2154 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002155 */
2156xmlNodePtr
2157xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2158 xmlNodePtr cur;
2159
2160 if (name == NULL) {
2161#ifdef DEBUG_TREE
2162 xmlGenericError(xmlGenericErrorContext,
2163 "xmlNewNode : name == NULL\n");
2164#endif
2165 return(NULL);
2166 }
2167
2168 /*
2169 * Allocate a new node and fill the fields.
2170 */
2171 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2172 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002173 xmlTreeErrMemory("building node");
Daniel Veillard46de64e2002-05-29 08:21:33 +00002174 return(NULL);
2175 }
2176 memset(cur, 0, sizeof(xmlNode));
2177 cur->type = XML_ELEMENT_NODE;
2178
2179 cur->name = name;
2180 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002181
Daniel Veillarda880b122003-04-21 21:36:41 +00002182 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002183 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002184 return(cur);
2185}
2186
2187/**
Owen Taylor3473f882001-02-23 17:55:21 +00002188 * xmlNewDocNode:
2189 * @doc: the document
2190 * @ns: namespace if any
2191 * @name: the node name
2192 * @content: the XML text content if any
2193 *
2194 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002195 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002196 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2197 * references, but XML special chars need to be escaped first by using
2198 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2199 * need entities support.
2200 *
2201 * Returns a pointer to the new node object.
2202 */
2203xmlNodePtr
2204xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2205 const xmlChar *name, const xmlChar *content) {
2206 xmlNodePtr cur;
2207
2208 cur = xmlNewNode(ns, name);
2209 if (cur != NULL) {
2210 cur->doc = doc;
2211 if (content != NULL) {
2212 cur->children = xmlStringGetNodeList(doc, content);
2213 UPDATE_LAST_CHILD_AND_PARENT(cur)
2214 }
2215 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002216
Owen Taylor3473f882001-02-23 17:55:21 +00002217 return(cur);
2218}
2219
Daniel Veillard46de64e2002-05-29 08:21:33 +00002220/**
2221 * xmlNewDocNodeEatName:
2222 * @doc: the document
2223 * @ns: namespace if any
2224 * @name: the node name
2225 * @content: the XML text content if any
2226 *
2227 * Creation of a new node element within a document. @ns and @content
2228 * are optional (NULL).
2229 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2230 * references, but XML special chars need to be escaped first by using
2231 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2232 * need entities support.
2233 *
2234 * Returns a pointer to the new node object.
2235 */
2236xmlNodePtr
2237xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2238 xmlChar *name, const xmlChar *content) {
2239 xmlNodePtr cur;
2240
2241 cur = xmlNewNodeEatName(ns, name);
2242 if (cur != NULL) {
2243 cur->doc = doc;
2244 if (content != NULL) {
2245 cur->children = xmlStringGetNodeList(doc, content);
2246 UPDATE_LAST_CHILD_AND_PARENT(cur)
2247 }
2248 }
2249 return(cur);
2250}
2251
Daniel Veillard652327a2003-09-29 18:02:38 +00002252#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002253/**
2254 * xmlNewDocRawNode:
2255 * @doc: the document
2256 * @ns: namespace if any
2257 * @name: the node name
2258 * @content: the text content if any
2259 *
2260 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002261 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002262 *
2263 * Returns a pointer to the new node object.
2264 */
2265xmlNodePtr
2266xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2267 const xmlChar *name, const xmlChar *content) {
2268 xmlNodePtr cur;
2269
2270 cur = xmlNewNode(ns, name);
2271 if (cur != NULL) {
2272 cur->doc = doc;
2273 if (content != NULL) {
2274 cur->children = xmlNewDocText(doc, content);
2275 UPDATE_LAST_CHILD_AND_PARENT(cur)
2276 }
2277 }
2278 return(cur);
2279}
2280
2281/**
2282 * xmlNewDocFragment:
2283 * @doc: the document owning the fragment
2284 *
2285 * Creation of a new Fragment node.
2286 * Returns a pointer to the new node object.
2287 */
2288xmlNodePtr
2289xmlNewDocFragment(xmlDocPtr doc) {
2290 xmlNodePtr cur;
2291
2292 /*
2293 * Allocate a new DocumentFragment node and fill the fields.
2294 */
2295 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2296 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002297 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002298 return(NULL);
2299 }
2300 memset(cur, 0, sizeof(xmlNode));
2301 cur->type = XML_DOCUMENT_FRAG_NODE;
2302
2303 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002304
Daniel Veillarda880b122003-04-21 21:36:41 +00002305 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002306 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002307 return(cur);
2308}
Daniel Veillard652327a2003-09-29 18:02:38 +00002309#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002310
2311/**
2312 * xmlNewText:
2313 * @content: the text content
2314 *
2315 * Creation of a new text node.
2316 * Returns a pointer to the new node object.
2317 */
2318xmlNodePtr
2319xmlNewText(const xmlChar *content) {
2320 xmlNodePtr cur;
2321
2322 /*
2323 * Allocate a new node and fill the fields.
2324 */
2325 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2326 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002327 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002328 return(NULL);
2329 }
2330 memset(cur, 0, sizeof(xmlNode));
2331 cur->type = XML_TEXT_NODE;
2332
2333 cur->name = xmlStringText;
2334 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002335 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002336 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002337
Daniel Veillarda880b122003-04-21 21:36:41 +00002338 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002339 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002340 return(cur);
2341}
2342
Daniel Veillard652327a2003-09-29 18:02:38 +00002343#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002344/**
2345 * xmlNewTextChild:
2346 * @parent: the parent node
2347 * @ns: a namespace if any
2348 * @name: the name of the child
2349 * @content: the text content of the child if any.
2350 *
2351 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002352 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2353 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002354 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002355 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2356 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2357 * reserved XML chars that might appear in @content, such as the ampersand,
2358 * greater-than or less-than signs, are automatically replaced by their XML
2359 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002360 *
2361 * Returns a pointer to the new node object.
2362 */
2363xmlNodePtr
2364xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2365 const xmlChar *name, const xmlChar *content) {
2366 xmlNodePtr cur, prev;
2367
2368 if (parent == NULL) {
2369#ifdef DEBUG_TREE
2370 xmlGenericError(xmlGenericErrorContext,
2371 "xmlNewTextChild : parent == NULL\n");
2372#endif
2373 return(NULL);
2374 }
2375
2376 if (name == NULL) {
2377#ifdef DEBUG_TREE
2378 xmlGenericError(xmlGenericErrorContext,
2379 "xmlNewTextChild : name == NULL\n");
2380#endif
2381 return(NULL);
2382 }
2383
2384 /*
2385 * Allocate a new node
2386 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002387 if (parent->type == XML_ELEMENT_NODE) {
2388 if (ns == NULL)
2389 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2390 else
2391 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2392 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2393 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2394 if (ns == NULL)
2395 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2396 else
2397 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2398 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2399 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2400 } else {
2401 return(NULL);
2402 }
Owen Taylor3473f882001-02-23 17:55:21 +00002403 if (cur == NULL) return(NULL);
2404
2405 /*
2406 * add the new element at the end of the children list.
2407 */
2408 cur->type = XML_ELEMENT_NODE;
2409 cur->parent = parent;
2410 cur->doc = parent->doc;
2411 if (parent->children == NULL) {
2412 parent->children = cur;
2413 parent->last = cur;
2414 } else {
2415 prev = parent->last;
2416 prev->next = cur;
2417 cur->prev = prev;
2418 parent->last = cur;
2419 }
2420
2421 return(cur);
2422}
Daniel Veillard652327a2003-09-29 18:02:38 +00002423#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002424
2425/**
2426 * xmlNewCharRef:
2427 * @doc: the document
2428 * @name: the char ref string, starting with # or "&# ... ;"
2429 *
2430 * Creation of a new character reference node.
2431 * Returns a pointer to the new node object.
2432 */
2433xmlNodePtr
2434xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2435 xmlNodePtr cur;
2436
2437 /*
2438 * Allocate a new node and fill the fields.
2439 */
2440 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2441 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002442 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002443 return(NULL);
2444 }
2445 memset(cur, 0, sizeof(xmlNode));
2446 cur->type = XML_ENTITY_REF_NODE;
2447
2448 cur->doc = doc;
2449 if (name[0] == '&') {
2450 int len;
2451 name++;
2452 len = xmlStrlen(name);
2453 if (name[len - 1] == ';')
2454 cur->name = xmlStrndup(name, len - 1);
2455 else
2456 cur->name = xmlStrndup(name, len);
2457 } else
2458 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002459
Daniel Veillarda880b122003-04-21 21:36:41 +00002460 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002461 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002462 return(cur);
2463}
2464
2465/**
2466 * xmlNewReference:
2467 * @doc: the document
2468 * @name: the reference name, or the reference string with & and ;
2469 *
2470 * Creation of a new reference node.
2471 * Returns a pointer to the new node object.
2472 */
2473xmlNodePtr
2474xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2475 xmlNodePtr cur;
2476 xmlEntityPtr ent;
2477
2478 /*
2479 * Allocate a new node and fill the fields.
2480 */
2481 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2482 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002483 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002484 return(NULL);
2485 }
2486 memset(cur, 0, sizeof(xmlNode));
2487 cur->type = XML_ENTITY_REF_NODE;
2488
2489 cur->doc = doc;
2490 if (name[0] == '&') {
2491 int len;
2492 name++;
2493 len = xmlStrlen(name);
2494 if (name[len - 1] == ';')
2495 cur->name = xmlStrndup(name, len - 1);
2496 else
2497 cur->name = xmlStrndup(name, len);
2498 } else
2499 cur->name = xmlStrdup(name);
2500
2501 ent = xmlGetDocEntity(doc, cur->name);
2502 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002503 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002504 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002505 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002506 * updated. Not sure if this is 100% correct.
2507 * -George
2508 */
2509 cur->children = (xmlNodePtr) ent;
2510 cur->last = (xmlNodePtr) ent;
2511 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002512
Daniel Veillarda880b122003-04-21 21:36:41 +00002513 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002514 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002515 return(cur);
2516}
2517
2518/**
2519 * xmlNewDocText:
2520 * @doc: the document
2521 * @content: the text content
2522 *
2523 * Creation of a new text node within a document.
2524 * Returns a pointer to the new node object.
2525 */
2526xmlNodePtr
2527xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2528 xmlNodePtr cur;
2529
2530 cur = xmlNewText(content);
2531 if (cur != NULL) cur->doc = doc;
2532 return(cur);
2533}
2534
2535/**
2536 * xmlNewTextLen:
2537 * @content: the text content
2538 * @len: the text len.
2539 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002540 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002541 * Returns a pointer to the new node object.
2542 */
2543xmlNodePtr
2544xmlNewTextLen(const xmlChar *content, int len) {
2545 xmlNodePtr cur;
2546
2547 /*
2548 * Allocate a new node and fill the fields.
2549 */
2550 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2551 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002552 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002553 return(NULL);
2554 }
2555 memset(cur, 0, sizeof(xmlNode));
2556 cur->type = XML_TEXT_NODE;
2557
2558 cur->name = xmlStringText;
2559 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002560 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002561 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002562
Daniel Veillarda880b122003-04-21 21:36:41 +00002563 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002564 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002565 return(cur);
2566}
2567
2568/**
2569 * xmlNewDocTextLen:
2570 * @doc: the document
2571 * @content: the text content
2572 * @len: the text len.
2573 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002574 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002575 * text node pertain to a given document.
2576 * Returns a pointer to the new node object.
2577 */
2578xmlNodePtr
2579xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2580 xmlNodePtr cur;
2581
2582 cur = xmlNewTextLen(content, len);
2583 if (cur != NULL) cur->doc = doc;
2584 return(cur);
2585}
2586
2587/**
2588 * xmlNewComment:
2589 * @content: the comment content
2590 *
2591 * Creation of a new node containing a comment.
2592 * Returns a pointer to the new node object.
2593 */
2594xmlNodePtr
2595xmlNewComment(const xmlChar *content) {
2596 xmlNodePtr cur;
2597
2598 /*
2599 * Allocate a new node and fill the fields.
2600 */
2601 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2602 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002603 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002604 return(NULL);
2605 }
2606 memset(cur, 0, sizeof(xmlNode));
2607 cur->type = XML_COMMENT_NODE;
2608
2609 cur->name = xmlStringComment;
2610 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002611 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002612 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002613
Daniel Veillarda880b122003-04-21 21:36:41 +00002614 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002615 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002616 return(cur);
2617}
2618
2619/**
2620 * xmlNewCDataBlock:
2621 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002622 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002623 * @len: the length of the block
2624 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002625 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002626 * Returns a pointer to the new node object.
2627 */
2628xmlNodePtr
2629xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2630 xmlNodePtr cur;
2631
2632 /*
2633 * Allocate a new node and fill the fields.
2634 */
2635 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2636 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002637 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002638 return(NULL);
2639 }
2640 memset(cur, 0, sizeof(xmlNode));
2641 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002642 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002643
2644 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002645 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002646 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002647
Daniel Veillarda880b122003-04-21 21:36:41 +00002648 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002649 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002650 return(cur);
2651}
2652
2653/**
2654 * xmlNewDocComment:
2655 * @doc: the document
2656 * @content: the comment content
2657 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002658 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002659 * Returns a pointer to the new node object.
2660 */
2661xmlNodePtr
2662xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2663 xmlNodePtr cur;
2664
2665 cur = xmlNewComment(content);
2666 if (cur != NULL) cur->doc = doc;
2667 return(cur);
2668}
2669
2670/**
2671 * xmlSetTreeDoc:
2672 * @tree: the top element
2673 * @doc: the document
2674 *
2675 * update all nodes under the tree to point to the right document
2676 */
2677void
2678xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002679 xmlAttrPtr prop;
2680
Owen Taylor3473f882001-02-23 17:55:21 +00002681 if (tree == NULL)
2682 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002683 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002684 if(tree->type == XML_ELEMENT_NODE) {
2685 prop = tree->properties;
2686 while (prop != NULL) {
2687 prop->doc = doc;
2688 xmlSetListDoc(prop->children, doc);
2689 prop = prop->next;
2690 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002691 }
Owen Taylor3473f882001-02-23 17:55:21 +00002692 if (tree->children != NULL)
2693 xmlSetListDoc(tree->children, doc);
2694 tree->doc = doc;
2695 }
2696}
2697
2698/**
2699 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002700 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002701 * @doc: the document
2702 *
2703 * update all nodes in the list to point to the right document
2704 */
2705void
2706xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2707 xmlNodePtr cur;
2708
2709 if (list == NULL)
2710 return;
2711 cur = list;
2712 while (cur != NULL) {
2713 if (cur->doc != doc)
2714 xmlSetTreeDoc(cur, doc);
2715 cur = cur->next;
2716 }
2717}
2718
Daniel Veillard2156d432004-03-04 15:59:36 +00002719#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002720/**
2721 * xmlNewChild:
2722 * @parent: the parent node
2723 * @ns: a namespace if any
2724 * @name: the name of the child
2725 * @content: the XML content of the child if any.
2726 *
2727 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002728 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2729 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002730 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002731 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2732 * references. XML special chars must be escaped first by using
2733 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002734 *
2735 * Returns a pointer to the new node object.
2736 */
2737xmlNodePtr
2738xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2739 const xmlChar *name, const xmlChar *content) {
2740 xmlNodePtr cur, prev;
2741
2742 if (parent == NULL) {
2743#ifdef DEBUG_TREE
2744 xmlGenericError(xmlGenericErrorContext,
2745 "xmlNewChild : parent == NULL\n");
2746#endif
2747 return(NULL);
2748 }
2749
2750 if (name == NULL) {
2751#ifdef DEBUG_TREE
2752 xmlGenericError(xmlGenericErrorContext,
2753 "xmlNewChild : name == NULL\n");
2754#endif
2755 return(NULL);
2756 }
2757
2758 /*
2759 * Allocate a new node
2760 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002761 if (parent->type == XML_ELEMENT_NODE) {
2762 if (ns == NULL)
2763 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2764 else
2765 cur = xmlNewDocNode(parent->doc, ns, name, content);
2766 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2767 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2768 if (ns == NULL)
2769 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2770 else
2771 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002772 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2773 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002774 } else {
2775 return(NULL);
2776 }
Owen Taylor3473f882001-02-23 17:55:21 +00002777 if (cur == NULL) return(NULL);
2778
2779 /*
2780 * add the new element at the end of the children list.
2781 */
2782 cur->type = XML_ELEMENT_NODE;
2783 cur->parent = parent;
2784 cur->doc = parent->doc;
2785 if (parent->children == NULL) {
2786 parent->children = cur;
2787 parent->last = cur;
2788 } else {
2789 prev = parent->last;
2790 prev->next = cur;
2791 cur->prev = prev;
2792 parent->last = cur;
2793 }
2794
2795 return(cur);
2796}
Daniel Veillard652327a2003-09-29 18:02:38 +00002797#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002798
2799/**
2800 * xmlAddNextSibling:
2801 * @cur: the child node
2802 * @elem: the new node
2803 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002804 * Add a new node @elem as the next sibling of @cur
2805 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002806 * first unlinked from its existing context.
2807 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002808 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2809 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002810 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002811 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002812 */
2813xmlNodePtr
2814xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2815 if (cur == NULL) {
2816#ifdef DEBUG_TREE
2817 xmlGenericError(xmlGenericErrorContext,
2818 "xmlAddNextSibling : cur == NULL\n");
2819#endif
2820 return(NULL);
2821 }
2822 if (elem == NULL) {
2823#ifdef DEBUG_TREE
2824 xmlGenericError(xmlGenericErrorContext,
2825 "xmlAddNextSibling : elem == NULL\n");
2826#endif
2827 return(NULL);
2828 }
2829
2830 xmlUnlinkNode(elem);
2831
2832 if (elem->type == XML_TEXT_NODE) {
2833 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002834 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002835 xmlFreeNode(elem);
2836 return(cur);
2837 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002838 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2839 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002840 xmlChar *tmp;
2841
2842 tmp = xmlStrdup(elem->content);
2843 tmp = xmlStrcat(tmp, cur->next->content);
2844 xmlNodeSetContent(cur->next, tmp);
2845 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002846 xmlFreeNode(elem);
2847 return(cur->next);
2848 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002849 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2850 /* check if an attribute with the same name exists */
2851 xmlAttrPtr attr;
2852
2853 if (elem->ns == NULL)
2854 attr = xmlHasProp(cur->parent, elem->name);
2855 else
2856 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2857 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2858 /* different instance, destroy it (attributes must be unique) */
2859 xmlFreeProp(attr);
2860 }
Owen Taylor3473f882001-02-23 17:55:21 +00002861 }
2862
2863 if (elem->doc != cur->doc) {
2864 xmlSetTreeDoc(elem, cur->doc);
2865 }
2866 elem->parent = cur->parent;
2867 elem->prev = cur;
2868 elem->next = cur->next;
2869 cur->next = elem;
2870 if (elem->next != NULL)
2871 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002872 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002873 elem->parent->last = elem;
2874 return(elem);
2875}
2876
Daniel Veillard2156d432004-03-04 15:59:36 +00002877#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002878/**
2879 * xmlAddPrevSibling:
2880 * @cur: the child node
2881 * @elem: the new node
2882 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002883 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002884 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002885 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002886 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002887 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2888 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002889 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002890 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002891 */
2892xmlNodePtr
2893xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2894 if (cur == NULL) {
2895#ifdef DEBUG_TREE
2896 xmlGenericError(xmlGenericErrorContext,
2897 "xmlAddPrevSibling : cur == NULL\n");
2898#endif
2899 return(NULL);
2900 }
2901 if (elem == NULL) {
2902#ifdef DEBUG_TREE
2903 xmlGenericError(xmlGenericErrorContext,
2904 "xmlAddPrevSibling : elem == NULL\n");
2905#endif
2906 return(NULL);
2907 }
2908
2909 xmlUnlinkNode(elem);
2910
2911 if (elem->type == XML_TEXT_NODE) {
2912 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002913 xmlChar *tmp;
2914
2915 tmp = xmlStrdup(elem->content);
2916 tmp = xmlStrcat(tmp, cur->content);
2917 xmlNodeSetContent(cur, tmp);
2918 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002919 xmlFreeNode(elem);
2920 return(cur);
2921 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002922 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2923 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002924 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002925 xmlFreeNode(elem);
2926 return(cur->prev);
2927 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002928 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2929 /* check if an attribute with the same name exists */
2930 xmlAttrPtr attr;
2931
2932 if (elem->ns == NULL)
2933 attr = xmlHasProp(cur->parent, elem->name);
2934 else
2935 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2936 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2937 /* different instance, destroy it (attributes must be unique) */
2938 xmlFreeProp(attr);
2939 }
Owen Taylor3473f882001-02-23 17:55:21 +00002940 }
2941
2942 if (elem->doc != cur->doc) {
2943 xmlSetTreeDoc(elem, cur->doc);
2944 }
2945 elem->parent = cur->parent;
2946 elem->next = cur;
2947 elem->prev = cur->prev;
2948 cur->prev = elem;
2949 if (elem->prev != NULL)
2950 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002951 if (elem->parent != NULL) {
2952 if (elem->type == XML_ATTRIBUTE_NODE) {
2953 if (elem->parent->properties == (xmlAttrPtr) cur) {
2954 elem->parent->properties = (xmlAttrPtr) elem;
2955 }
2956 } else {
2957 if (elem->parent->children == cur) {
2958 elem->parent->children = elem;
2959 }
2960 }
2961 }
Owen Taylor3473f882001-02-23 17:55:21 +00002962 return(elem);
2963}
Daniel Veillard652327a2003-09-29 18:02:38 +00002964#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002965
2966/**
2967 * xmlAddSibling:
2968 * @cur: the child node
2969 * @elem: the new node
2970 *
2971 * Add a new element @elem to the list of siblings of @cur
2972 * merging adjacent TEXT nodes (@elem may be freed)
2973 * If the new element was already inserted in a document it is
2974 * first unlinked from its existing context.
2975 *
2976 * Returns the new element or NULL in case of error.
2977 */
2978xmlNodePtr
2979xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2980 xmlNodePtr parent;
2981
2982 if (cur == NULL) {
2983#ifdef DEBUG_TREE
2984 xmlGenericError(xmlGenericErrorContext,
2985 "xmlAddSibling : cur == NULL\n");
2986#endif
2987 return(NULL);
2988 }
2989
2990 if (elem == NULL) {
2991#ifdef DEBUG_TREE
2992 xmlGenericError(xmlGenericErrorContext,
2993 "xmlAddSibling : elem == NULL\n");
2994#endif
2995 return(NULL);
2996 }
2997
2998 /*
2999 * Constant time is we can rely on the ->parent->last to find
3000 * the last sibling.
3001 */
3002 if ((cur->parent != NULL) &&
3003 (cur->parent->children != NULL) &&
3004 (cur->parent->last != NULL) &&
3005 (cur->parent->last->next == NULL)) {
3006 cur = cur->parent->last;
3007 } else {
3008 while (cur->next != NULL) cur = cur->next;
3009 }
3010
3011 xmlUnlinkNode(elem);
3012
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003013 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3014 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003015 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003016 xmlFreeNode(elem);
3017 return(cur);
3018 }
3019
3020 if (elem->doc != cur->doc) {
3021 xmlSetTreeDoc(elem, cur->doc);
3022 }
3023 parent = cur->parent;
3024 elem->prev = cur;
3025 elem->next = NULL;
3026 elem->parent = parent;
3027 cur->next = elem;
3028 if (parent != NULL)
3029 parent->last = elem;
3030
3031 return(elem);
3032}
3033
3034/**
3035 * xmlAddChildList:
3036 * @parent: the parent node
3037 * @cur: the first node in the list
3038 *
3039 * Add a list of node at the end of the child list of the parent
3040 * merging adjacent TEXT nodes (@cur may be freed)
3041 *
3042 * Returns the last child or NULL in case of error.
3043 */
3044xmlNodePtr
3045xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3046 xmlNodePtr prev;
3047
3048 if (parent == NULL) {
3049#ifdef DEBUG_TREE
3050 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003051 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003052#endif
3053 return(NULL);
3054 }
3055
3056 if (cur == NULL) {
3057#ifdef DEBUG_TREE
3058 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003059 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003060#endif
3061 return(NULL);
3062 }
3063
3064 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3065 (cur->doc != parent->doc)) {
3066#ifdef DEBUG_TREE
3067 xmlGenericError(xmlGenericErrorContext,
3068 "Elements moved to a different document\n");
3069#endif
3070 }
3071
3072 /*
3073 * add the first element at the end of the children list.
3074 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003075
Owen Taylor3473f882001-02-23 17:55:21 +00003076 if (parent->children == NULL) {
3077 parent->children = cur;
3078 } else {
3079 /*
3080 * If cur and parent->last both are TEXT nodes, then merge them.
3081 */
3082 if ((cur->type == XML_TEXT_NODE) &&
3083 (parent->last->type == XML_TEXT_NODE) &&
3084 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003085 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003086 /*
3087 * if it's the only child, nothing more to be done.
3088 */
3089 if (cur->next == NULL) {
3090 xmlFreeNode(cur);
3091 return(parent->last);
3092 }
3093 prev = cur;
3094 cur = cur->next;
3095 xmlFreeNode(prev);
3096 }
3097 prev = parent->last;
3098 prev->next = cur;
3099 cur->prev = prev;
3100 }
3101 while (cur->next != NULL) {
3102 cur->parent = parent;
3103 if (cur->doc != parent->doc) {
3104 xmlSetTreeDoc(cur, parent->doc);
3105 }
3106 cur = cur->next;
3107 }
3108 cur->parent = parent;
3109 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3110 parent->last = cur;
3111
3112 return(cur);
3113}
3114
3115/**
3116 * xmlAddChild:
3117 * @parent: the parent node
3118 * @cur: the child node
3119 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003120 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003121 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003122 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3123 * If there is an attribute with equal name, it is first destroyed.
3124 *
Owen Taylor3473f882001-02-23 17:55:21 +00003125 * Returns the child or NULL in case of error.
3126 */
3127xmlNodePtr
3128xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3129 xmlNodePtr prev;
3130
3131 if (parent == NULL) {
3132#ifdef DEBUG_TREE
3133 xmlGenericError(xmlGenericErrorContext,
3134 "xmlAddChild : parent == NULL\n");
3135#endif
3136 return(NULL);
3137 }
3138
3139 if (cur == NULL) {
3140#ifdef DEBUG_TREE
3141 xmlGenericError(xmlGenericErrorContext,
3142 "xmlAddChild : child == NULL\n");
3143#endif
3144 return(NULL);
3145 }
3146
Owen Taylor3473f882001-02-23 17:55:21 +00003147 /*
3148 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003149 * cur is then freed.
3150 */
3151 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003152 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003153 (parent->content != NULL) &&
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003154 (parent->name == cur->name) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003155 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003156 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003157 xmlFreeNode(cur);
3158 return(parent);
3159 }
3160 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003161 (parent->last->name == cur->name) &&
3162 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003163 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003164 xmlFreeNode(cur);
3165 return(parent->last);
3166 }
3167 }
3168
3169 /*
3170 * add the new element at the end of the children list.
3171 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003172 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003173 cur->parent = parent;
3174 if (cur->doc != parent->doc) {
3175 xmlSetTreeDoc(cur, parent->doc);
3176 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003177 /* this check prevents a loop on tree-traversions if a developer
3178 * tries to add a node to its parent multiple times
3179 */
3180 if (prev == parent)
3181 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003182
3183 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003184 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003185 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003186 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003187 (parent->content != NULL) &&
3188 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003189 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003190 xmlFreeNode(cur);
3191 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003192 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003193 if (cur->type == XML_ATTRIBUTE_NODE) {
3194 if (parent->properties == NULL) {
3195 parent->properties = (xmlAttrPtr) cur;
3196 } else {
3197 /* check if an attribute with the same name exists */
3198 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003199
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003200 if (cur->ns == NULL)
3201 lastattr = xmlHasProp(parent, cur->name);
3202 else
3203 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3204 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3205 /* different instance, destroy it (attributes must be unique) */
3206 xmlFreeProp(lastattr);
3207 }
3208 /* find the end */
3209 lastattr = parent->properties;
3210 while (lastattr->next != NULL) {
3211 lastattr = lastattr->next;
3212 }
3213 lastattr->next = (xmlAttrPtr) cur;
3214 ((xmlAttrPtr) cur)->prev = lastattr;
3215 }
3216 } else {
3217 if (parent->children == NULL) {
3218 parent->children = cur;
3219 parent->last = cur;
3220 } else {
3221 prev = parent->last;
3222 prev->next = cur;
3223 cur->prev = prev;
3224 parent->last = cur;
3225 }
3226 }
Owen Taylor3473f882001-02-23 17:55:21 +00003227 return(cur);
3228}
3229
3230/**
3231 * xmlGetLastChild:
3232 * @parent: the parent node
3233 *
3234 * Search the last child of a node.
3235 * Returns the last child or NULL if none.
3236 */
3237xmlNodePtr
3238xmlGetLastChild(xmlNodePtr parent) {
3239 if (parent == NULL) {
3240#ifdef DEBUG_TREE
3241 xmlGenericError(xmlGenericErrorContext,
3242 "xmlGetLastChild : parent == NULL\n");
3243#endif
3244 return(NULL);
3245 }
3246 return(parent->last);
3247}
3248
3249/**
3250 * xmlFreeNodeList:
3251 * @cur: the first node in the list
3252 *
3253 * Free a node and all its siblings, this is a recursive behaviour, all
3254 * the children are freed too.
3255 */
3256void
3257xmlFreeNodeList(xmlNodePtr cur) {
3258 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003259 xmlDictPtr dict = NULL;
3260
3261 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003262 if (cur->type == XML_NAMESPACE_DECL) {
3263 xmlFreeNsList((xmlNsPtr) cur);
3264 return;
3265 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003266 if ((cur->type == XML_DOCUMENT_NODE) ||
3267#ifdef LIBXML_DOCB_ENABLED
3268 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003269#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003270 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003271 xmlFreeDoc((xmlDocPtr) cur);
3272 return;
3273 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003274 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003275 while (cur != NULL) {
3276 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003277 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003278
Daniel Veillarda880b122003-04-21 21:36:41 +00003279 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003280 xmlDeregisterNodeDefaultValue(cur);
3281
Daniel Veillard02141ea2001-04-30 11:46:40 +00003282 if ((cur->children != NULL) &&
3283 (cur->type != XML_ENTITY_REF_NODE))
3284 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003285 if (((cur->type == XML_ELEMENT_NODE) ||
3286 (cur->type == XML_XINCLUDE_START) ||
3287 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003288 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003289 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003290 if ((cur->type != XML_ELEMENT_NODE) &&
3291 (cur->type != XML_XINCLUDE_START) &&
3292 (cur->type != XML_XINCLUDE_END) &&
3293 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003294 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003295 }
3296 if (((cur->type == XML_ELEMENT_NODE) ||
3297 (cur->type == XML_XINCLUDE_START) ||
3298 (cur->type == XML_XINCLUDE_END)) &&
3299 (cur->nsDef != NULL))
3300 xmlFreeNsList(cur->nsDef);
3301
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003302 /*
3303 * When a node is a text node or a comment, it uses a global static
3304 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003305 * Otherwise the node name might come from the document's
3306 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003307 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003308 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003309 (cur->type != XML_TEXT_NODE) &&
3310 (cur->type != XML_COMMENT_NODE))
3311 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003312 xmlFree(cur);
3313 }
Owen Taylor3473f882001-02-23 17:55:21 +00003314 cur = next;
3315 }
3316}
3317
3318/**
3319 * xmlFreeNode:
3320 * @cur: the node
3321 *
3322 * Free a node, this is a recursive behaviour, all the children are freed too.
3323 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3324 */
3325void
3326xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003327 xmlDictPtr dict = NULL;
3328
3329 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003330
Daniel Veillard02141ea2001-04-30 11:46:40 +00003331 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003332 if (cur->type == XML_DTD_NODE) {
3333 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003334 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003335 }
3336 if (cur->type == XML_NAMESPACE_DECL) {
3337 xmlFreeNs((xmlNsPtr) cur);
3338 return;
3339 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003340 if (cur->type == XML_ATTRIBUTE_NODE) {
3341 xmlFreeProp((xmlAttrPtr) cur);
3342 return;
3343 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003344
Daniel Veillarda880b122003-04-21 21:36:41 +00003345 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003346 xmlDeregisterNodeDefaultValue(cur);
3347
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003348 if (cur->doc != NULL) dict = cur->doc->dict;
3349
Owen Taylor3473f882001-02-23 17:55:21 +00003350 if ((cur->children != NULL) &&
3351 (cur->type != XML_ENTITY_REF_NODE))
3352 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003353 if (((cur->type == XML_ELEMENT_NODE) ||
3354 (cur->type == XML_XINCLUDE_START) ||
3355 (cur->type == XML_XINCLUDE_END)) &&
3356 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003357 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003358 if ((cur->type != XML_ELEMENT_NODE) &&
3359 (cur->content != NULL) &&
3360 (cur->type != XML_ENTITY_REF_NODE) &&
3361 (cur->type != XML_XINCLUDE_END) &&
3362 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003363 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003364 }
3365
Daniel Veillardacd370f2001-06-09 17:17:51 +00003366 /*
3367 * When a node is a text node or a comment, it uses a global static
3368 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003369 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003370 */
Owen Taylor3473f882001-02-23 17:55:21 +00003371 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003372 (cur->type != XML_TEXT_NODE) &&
3373 (cur->type != XML_COMMENT_NODE))
3374 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003375
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003376 if (((cur->type == XML_ELEMENT_NODE) ||
3377 (cur->type == XML_XINCLUDE_START) ||
3378 (cur->type == XML_XINCLUDE_END)) &&
3379 (cur->nsDef != NULL))
3380 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003381 xmlFree(cur);
3382}
3383
3384/**
3385 * xmlUnlinkNode:
3386 * @cur: the node
3387 *
3388 * Unlink a node from it's current context, the node is not freed
3389 */
3390void
3391xmlUnlinkNode(xmlNodePtr cur) {
3392 if (cur == NULL) {
3393#ifdef DEBUG_TREE
3394 xmlGenericError(xmlGenericErrorContext,
3395 "xmlUnlinkNode : node == NULL\n");
3396#endif
3397 return;
3398 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003399 if (cur->type == XML_DTD_NODE) {
3400 xmlDocPtr doc;
3401 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003402 if (doc != NULL) {
3403 if (doc->intSubset == (xmlDtdPtr) cur)
3404 doc->intSubset = NULL;
3405 if (doc->extSubset == (xmlDtdPtr) cur)
3406 doc->extSubset = NULL;
3407 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003408 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003409 if (cur->parent != NULL) {
3410 xmlNodePtr parent;
3411 parent = cur->parent;
3412 if (cur->type == XML_ATTRIBUTE_NODE) {
3413 if (parent->properties == (xmlAttrPtr) cur)
3414 parent->properties = ((xmlAttrPtr) cur)->next;
3415 } else {
3416 if (parent->children == cur)
3417 parent->children = cur->next;
3418 if (parent->last == cur)
3419 parent->last = cur->prev;
3420 }
3421 cur->parent = NULL;
3422 }
Owen Taylor3473f882001-02-23 17:55:21 +00003423 if (cur->next != NULL)
3424 cur->next->prev = cur->prev;
3425 if (cur->prev != NULL)
3426 cur->prev->next = cur->next;
3427 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003428}
3429
Daniel Veillard2156d432004-03-04 15:59:36 +00003430#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003431/**
3432 * xmlReplaceNode:
3433 * @old: the old node
3434 * @cur: the node
3435 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003436 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003437 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003438 * first unlinked from its existing context.
3439 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003440 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003441 */
3442xmlNodePtr
3443xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3444 if (old == NULL) {
3445#ifdef DEBUG_TREE
3446 xmlGenericError(xmlGenericErrorContext,
3447 "xmlReplaceNode : old == NULL\n");
3448#endif
3449 return(NULL);
3450 }
3451 if (cur == NULL) {
3452 xmlUnlinkNode(old);
3453 return(old);
3454 }
3455 if (cur == old) {
3456 return(old);
3457 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003458 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3459#ifdef DEBUG_TREE
3460 xmlGenericError(xmlGenericErrorContext,
3461 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3462#endif
3463 return(old);
3464 }
3465 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3466#ifdef DEBUG_TREE
3467 xmlGenericError(xmlGenericErrorContext,
3468 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3469#endif
3470 return(old);
3471 }
Owen Taylor3473f882001-02-23 17:55:21 +00003472 xmlUnlinkNode(cur);
3473 cur->doc = old->doc;
3474 cur->parent = old->parent;
3475 cur->next = old->next;
3476 if (cur->next != NULL)
3477 cur->next->prev = cur;
3478 cur->prev = old->prev;
3479 if (cur->prev != NULL)
3480 cur->prev->next = cur;
3481 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003482 if (cur->type == XML_ATTRIBUTE_NODE) {
3483 if (cur->parent->properties == (xmlAttrPtr)old)
3484 cur->parent->properties = ((xmlAttrPtr) cur);
3485 } else {
3486 if (cur->parent->children == old)
3487 cur->parent->children = cur;
3488 if (cur->parent->last == old)
3489 cur->parent->last = cur;
3490 }
Owen Taylor3473f882001-02-23 17:55:21 +00003491 }
3492 old->next = old->prev = NULL;
3493 old->parent = NULL;
3494 return(old);
3495}
Daniel Veillard652327a2003-09-29 18:02:38 +00003496#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003497
3498/************************************************************************
3499 * *
3500 * Copy operations *
3501 * *
3502 ************************************************************************/
3503
3504/**
3505 * xmlCopyNamespace:
3506 * @cur: the namespace
3507 *
3508 * Do a copy of the namespace.
3509 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003510 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003511 */
3512xmlNsPtr
3513xmlCopyNamespace(xmlNsPtr cur) {
3514 xmlNsPtr ret;
3515
3516 if (cur == NULL) return(NULL);
3517 switch (cur->type) {
3518 case XML_LOCAL_NAMESPACE:
3519 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3520 break;
3521 default:
3522#ifdef DEBUG_TREE
3523 xmlGenericError(xmlGenericErrorContext,
3524 "xmlCopyNamespace: invalid type %d\n", cur->type);
3525#endif
3526 return(NULL);
3527 }
3528 return(ret);
3529}
3530
3531/**
3532 * xmlCopyNamespaceList:
3533 * @cur: the first namespace
3534 *
3535 * Do a copy of an namespace list.
3536 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003537 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003538 */
3539xmlNsPtr
3540xmlCopyNamespaceList(xmlNsPtr cur) {
3541 xmlNsPtr ret = NULL;
3542 xmlNsPtr p = NULL,q;
3543
3544 while (cur != NULL) {
3545 q = xmlCopyNamespace(cur);
3546 if (p == NULL) {
3547 ret = p = q;
3548 } else {
3549 p->next = q;
3550 p = q;
3551 }
3552 cur = cur->next;
3553 }
3554 return(ret);
3555}
3556
3557static xmlNodePtr
3558xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3559/**
3560 * xmlCopyProp:
3561 * @target: the element where the attribute will be grafted
3562 * @cur: the attribute
3563 *
3564 * Do a copy of the attribute.
3565 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003566 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003567 */
3568xmlAttrPtr
3569xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3570 xmlAttrPtr ret;
3571
3572 if (cur == NULL) return(NULL);
3573 if (target != NULL)
3574 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3575 else if (cur->parent != NULL)
3576 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3577 else if (cur->children != NULL)
3578 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3579 else
3580 ret = xmlNewDocProp(NULL, cur->name, NULL);
3581 if (ret == NULL) return(NULL);
3582 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003583
Owen Taylor3473f882001-02-23 17:55:21 +00003584 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003585 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003586
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003587 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3588 if (ns == NULL) {
3589 /*
3590 * Humm, we are copying an element whose namespace is defined
3591 * out of the new tree scope. Search it in the original tree
3592 * and add it at the top of the new tree
3593 */
3594 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3595 if (ns != NULL) {
3596 xmlNodePtr root = target;
3597 xmlNodePtr pred = NULL;
3598
3599 while (root->parent != NULL) {
3600 pred = root;
3601 root = root->parent;
3602 }
3603 if (root == (xmlNodePtr) target->doc) {
3604 /* correct possibly cycling above the document elt */
3605 root = pred;
3606 }
3607 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3608 }
3609 } else {
3610 /*
3611 * we have to find something appropriate here since
3612 * we cant be sure, that the namespce we found is identified
3613 * by the prefix
3614 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003615 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003616 /* this is the nice case */
3617 ret->ns = ns;
3618 } else {
3619 /*
3620 * we are in trouble: we need a new reconcilied namespace.
3621 * This is expensive
3622 */
3623 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3624 }
3625 }
3626
Owen Taylor3473f882001-02-23 17:55:21 +00003627 } else
3628 ret->ns = NULL;
3629
3630 if (cur->children != NULL) {
3631 xmlNodePtr tmp;
3632
3633 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3634 ret->last = NULL;
3635 tmp = ret->children;
3636 while (tmp != NULL) {
3637 /* tmp->parent = (xmlNodePtr)ret; */
3638 if (tmp->next == NULL)
3639 ret->last = tmp;
3640 tmp = tmp->next;
3641 }
3642 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003643 /*
3644 * Try to handle IDs
3645 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003646 if ((target!= NULL) && (cur!= NULL) &&
3647 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003648 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3649 if (xmlIsID(cur->doc, cur->parent, cur)) {
3650 xmlChar *id;
3651
3652 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3653 if (id != NULL) {
3654 xmlAddID(NULL, target->doc, id, ret);
3655 xmlFree(id);
3656 }
3657 }
3658 }
Owen Taylor3473f882001-02-23 17:55:21 +00003659 return(ret);
3660}
3661
3662/**
3663 * xmlCopyPropList:
3664 * @target: the element where the attributes will be grafted
3665 * @cur: the first attribute
3666 *
3667 * Do a copy of an attribute list.
3668 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003669 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003670 */
3671xmlAttrPtr
3672xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3673 xmlAttrPtr ret = NULL;
3674 xmlAttrPtr p = NULL,q;
3675
3676 while (cur != NULL) {
3677 q = xmlCopyProp(target, cur);
3678 if (p == NULL) {
3679 ret = p = q;
3680 } else {
3681 p->next = q;
3682 q->prev = p;
3683 p = q;
3684 }
3685 cur = cur->next;
3686 }
3687 return(ret);
3688}
3689
3690/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003691 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003692 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003693 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003694 * tricky reason: namespaces. Doing a direct copy of a node
3695 * say RPM:Copyright without changing the namespace pointer to
3696 * something else can produce stale links. One way to do it is
3697 * to keep a reference counter but this doesn't work as soon
3698 * as one move the element or the subtree out of the scope of
3699 * the existing namespace. The actual solution seems to add
3700 * a copy of the namespace at the top of the copied tree if
3701 * not available in the subtree.
3702 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00003703 * The argument "recursive" normally indicates a recursive copy
3704 * of the node with values 0 (no) and 1 (yes). For XInclude,
3705 * however, we allow a value of 2 to indicate copy properties and
3706 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00003707 */
3708
3709static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003710xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00003711 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003712 xmlNodePtr ret;
3713
3714 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003715 switch (node->type) {
3716 case XML_TEXT_NODE:
3717 case XML_CDATA_SECTION_NODE:
3718 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003719 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003720 case XML_ENTITY_REF_NODE:
3721 case XML_ENTITY_NODE:
3722 case XML_PI_NODE:
3723 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003724 case XML_XINCLUDE_START:
3725 case XML_XINCLUDE_END:
3726 break;
3727 case XML_ATTRIBUTE_NODE:
3728 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3729 case XML_NAMESPACE_DECL:
3730 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3731
Daniel Veillard39196eb2001-06-19 18:09:42 +00003732 case XML_DOCUMENT_NODE:
3733 case XML_HTML_DOCUMENT_NODE:
3734#ifdef LIBXML_DOCB_ENABLED
3735 case XML_DOCB_DOCUMENT_NODE:
3736#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003737#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00003738 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00003739#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003740 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003741 case XML_NOTATION_NODE:
3742 case XML_DTD_NODE:
3743 case XML_ELEMENT_DECL:
3744 case XML_ATTRIBUTE_DECL:
3745 case XML_ENTITY_DECL:
3746 return(NULL);
3747 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003748
Owen Taylor3473f882001-02-23 17:55:21 +00003749 /*
3750 * Allocate a new node and fill the fields.
3751 */
3752 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3753 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003754 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003755 return(NULL);
3756 }
3757 memset(ret, 0, sizeof(xmlNode));
3758 ret->type = node->type;
3759
3760 ret->doc = doc;
3761 ret->parent = parent;
3762 if (node->name == xmlStringText)
3763 ret->name = xmlStringText;
3764 else if (node->name == xmlStringTextNoenc)
3765 ret->name = xmlStringTextNoenc;
3766 else if (node->name == xmlStringComment)
3767 ret->name = xmlStringComment;
3768 else if (node->name != NULL)
3769 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003770 if ((node->type != XML_ELEMENT_NODE) &&
3771 (node->content != NULL) &&
3772 (node->type != XML_ENTITY_REF_NODE) &&
3773 (node->type != XML_XINCLUDE_END) &&
3774 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003775 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003776 }else{
3777 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003778 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003779 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003780 if (parent != NULL) {
3781 xmlNodePtr tmp;
3782
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003783 /*
3784 * this is a tricky part for the node register thing:
3785 * in case ret does get coalesced in xmlAddChild
3786 * the deregister-node callback is called; so we register ret now already
3787 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003788 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003789 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3790
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003791 tmp = xmlAddChild(parent, ret);
3792 /* node could have coalesced */
3793 if (tmp != ret)
3794 return(tmp);
3795 }
Owen Taylor3473f882001-02-23 17:55:21 +00003796
William M. Brack57e9e912004-03-09 16:19:02 +00003797 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003798 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003799 if (node->nsDef != NULL)
3800 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3801
3802 if (node->ns != NULL) {
3803 xmlNsPtr ns;
3804
3805 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3806 if (ns == NULL) {
3807 /*
3808 * Humm, we are copying an element whose namespace is defined
3809 * out of the new tree scope. Search it in the original tree
3810 * and add it at the top of the new tree
3811 */
3812 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3813 if (ns != NULL) {
3814 xmlNodePtr root = ret;
3815
3816 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003817 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003818 }
3819 } else {
3820 /*
3821 * reference the existing namespace definition in our own tree.
3822 */
3823 ret->ns = ns;
3824 }
3825 }
3826 if (node->properties != NULL)
3827 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003828 if (node->type == XML_ENTITY_REF_NODE) {
3829 if ((doc == NULL) || (node->doc != doc)) {
3830 /*
3831 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003832 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003833 * we cannot keep the reference. Try to find it in the
3834 * target document.
3835 */
3836 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3837 } else {
3838 ret->children = node->children;
3839 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003840 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00003841 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003842 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003843 UPDATE_LAST_CHILD_AND_PARENT(ret)
3844 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003845
3846out:
3847 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00003848 if ((parent == NULL) &&
3849 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003850 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003851 return(ret);
3852}
3853
3854static xmlNodePtr
3855xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3856 xmlNodePtr ret = NULL;
3857 xmlNodePtr p = NULL,q;
3858
3859 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003860#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003861 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003862 if (doc == NULL) {
3863 node = node->next;
3864 continue;
3865 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003866 if (doc->intSubset == NULL) {
3867 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3868 q->doc = doc;
3869 q->parent = parent;
3870 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003871 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003872 } else {
3873 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003874 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003875 }
3876 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003877#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003878 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003879 if (ret == NULL) {
3880 q->prev = NULL;
3881 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003882 } else if (p != q) {
3883 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003884 p->next = q;
3885 q->prev = p;
3886 p = q;
3887 }
3888 node = node->next;
3889 }
3890 return(ret);
3891}
3892
3893/**
3894 * xmlCopyNode:
3895 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00003896 * @extended: if 1 do a recursive copy (properties, namespaces and children
3897 * when applicable)
3898 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00003899 *
3900 * Do a copy of the node.
3901 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003902 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003903 */
3904xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003905xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003906 xmlNodePtr ret;
3907
William M. Brack57e9e912004-03-09 16:19:02 +00003908 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00003909 return(ret);
3910}
3911
3912/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003913 * xmlDocCopyNode:
3914 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003915 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00003916 * @extended: if 1 do a recursive copy (properties, namespaces and children
3917 * when applicable)
3918 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00003919 *
3920 * Do a copy of the node to a given document.
3921 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003922 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003923 */
3924xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003925xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003926 xmlNodePtr ret;
3927
William M. Brack57e9e912004-03-09 16:19:02 +00003928 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00003929 return(ret);
3930}
3931
3932/**
Owen Taylor3473f882001-02-23 17:55:21 +00003933 * xmlCopyNodeList:
3934 * @node: the first node in the list.
3935 *
3936 * Do a recursive copy of the node list.
3937 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003938 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003939 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003940xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003941 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3942 return(ret);
3943}
3944
Daniel Veillard2156d432004-03-04 15:59:36 +00003945#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003946/**
Owen Taylor3473f882001-02-23 17:55:21 +00003947 * xmlCopyDtd:
3948 * @dtd: the dtd
3949 *
3950 * Do a copy of the dtd.
3951 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003952 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003953 */
3954xmlDtdPtr
3955xmlCopyDtd(xmlDtdPtr dtd) {
3956 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003957 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003958
3959 if (dtd == NULL) return(NULL);
3960 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3961 if (ret == NULL) return(NULL);
3962 if (dtd->entities != NULL)
3963 ret->entities = (void *) xmlCopyEntitiesTable(
3964 (xmlEntitiesTablePtr) dtd->entities);
3965 if (dtd->notations != NULL)
3966 ret->notations = (void *) xmlCopyNotationTable(
3967 (xmlNotationTablePtr) dtd->notations);
3968 if (dtd->elements != NULL)
3969 ret->elements = (void *) xmlCopyElementTable(
3970 (xmlElementTablePtr) dtd->elements);
3971 if (dtd->attributes != NULL)
3972 ret->attributes = (void *) xmlCopyAttributeTable(
3973 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003974 if (dtd->pentities != NULL)
3975 ret->pentities = (void *) xmlCopyEntitiesTable(
3976 (xmlEntitiesTablePtr) dtd->pentities);
3977
3978 cur = dtd->children;
3979 while (cur != NULL) {
3980 q = NULL;
3981
3982 if (cur->type == XML_ENTITY_DECL) {
3983 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3984 switch (tmp->etype) {
3985 case XML_INTERNAL_GENERAL_ENTITY:
3986 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3987 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3988 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3989 break;
3990 case XML_INTERNAL_PARAMETER_ENTITY:
3991 case XML_EXTERNAL_PARAMETER_ENTITY:
3992 q = (xmlNodePtr)
3993 xmlGetParameterEntityFromDtd(ret, tmp->name);
3994 break;
3995 case XML_INTERNAL_PREDEFINED_ENTITY:
3996 break;
3997 }
3998 } else if (cur->type == XML_ELEMENT_DECL) {
3999 xmlElementPtr tmp = (xmlElementPtr) cur;
4000 q = (xmlNodePtr)
4001 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4002 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4003 xmlAttributePtr tmp = (xmlAttributePtr) cur;
4004 q = (xmlNodePtr)
4005 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4006 } else if (cur->type == XML_COMMENT_NODE) {
4007 q = xmlCopyNode(cur, 0);
4008 }
4009
4010 if (q == NULL) {
4011 cur = cur->next;
4012 continue;
4013 }
4014
4015 if (p == NULL)
4016 ret->children = q;
4017 else
4018 p->next = q;
4019
4020 q->prev = p;
4021 q->parent = (xmlNodePtr) ret;
4022 q->next = NULL;
4023 ret->last = q;
4024 p = q;
4025 cur = cur->next;
4026 }
4027
Owen Taylor3473f882001-02-23 17:55:21 +00004028 return(ret);
4029}
Daniel Veillard2156d432004-03-04 15:59:36 +00004030#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004031
Daniel Veillard2156d432004-03-04 15:59:36 +00004032#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004033/**
4034 * xmlCopyDoc:
4035 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004036 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004037 *
4038 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004039 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004040 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004041 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004042 */
4043xmlDocPtr
4044xmlCopyDoc(xmlDocPtr doc, int recursive) {
4045 xmlDocPtr ret;
4046
4047 if (doc == NULL) return(NULL);
4048 ret = xmlNewDoc(doc->version);
4049 if (ret == NULL) return(NULL);
4050 if (doc->name != NULL)
4051 ret->name = xmlMemStrdup(doc->name);
4052 if (doc->encoding != NULL)
4053 ret->encoding = xmlStrdup(doc->encoding);
4054 ret->charset = doc->charset;
4055 ret->compression = doc->compression;
4056 ret->standalone = doc->standalone;
4057 if (!recursive) return(ret);
4058
Daniel Veillardb33c2012001-04-25 12:59:04 +00004059 ret->last = NULL;
4060 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004061#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004062 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004063 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004064 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004065 ret->intSubset->parent = ret;
4066 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004067#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004068 if (doc->oldNs != NULL)
4069 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4070 if (doc->children != NULL) {
4071 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004072
4073 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4074 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004075 ret->last = NULL;
4076 tmp = ret->children;
4077 while (tmp != NULL) {
4078 if (tmp->next == NULL)
4079 ret->last = tmp;
4080 tmp = tmp->next;
4081 }
4082 }
4083 return(ret);
4084}
Daniel Veillard652327a2003-09-29 18:02:38 +00004085#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004086
4087/************************************************************************
4088 * *
4089 * Content access functions *
4090 * *
4091 ************************************************************************/
4092
4093/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004094 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004095 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004096 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004097 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004098 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004099 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004100 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004101 */
4102long
4103xmlGetLineNo(xmlNodePtr node)
4104{
4105 long result = -1;
4106
4107 if (!node)
4108 return result;
4109 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004110 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004111 else if ((node->prev != NULL) &&
4112 ((node->prev->type == XML_ELEMENT_NODE) ||
4113 (node->prev->type == XML_TEXT_NODE)))
4114 result = xmlGetLineNo(node->prev);
4115 else if ((node->parent != NULL) &&
4116 ((node->parent->type == XML_ELEMENT_NODE) ||
4117 (node->parent->type == XML_TEXT_NODE)))
4118 result = xmlGetLineNo(node->parent);
4119
4120 return result;
4121}
4122
Daniel Veillard2156d432004-03-04 15:59:36 +00004123#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004124/**
4125 * xmlGetNodePath:
4126 * @node: a node
4127 *
4128 * Build a structure based Path for the given node
4129 *
4130 * Returns the new path or NULL in case of error. The caller must free
4131 * the returned string
4132 */
4133xmlChar *
4134xmlGetNodePath(xmlNodePtr node)
4135{
4136 xmlNodePtr cur, tmp, next;
4137 xmlChar *buffer = NULL, *temp;
4138 size_t buf_len;
4139 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004140 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004141 const char *name;
4142 char nametemp[100];
4143 int occur = 0;
4144
4145 if (node == NULL)
4146 return (NULL);
4147
4148 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004149 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004150 if (buffer == NULL) {
4151 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004152 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004153 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004154 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004155 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004156 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004157 xmlFree(buffer);
4158 return (NULL);
4159 }
4160
4161 buffer[0] = 0;
4162 cur = node;
4163 do {
4164 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004165 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004166 occur = 0;
4167 if ((cur->type == XML_DOCUMENT_NODE) ||
4168 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4169 if (buffer[0] == '/')
4170 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004171 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004172 next = NULL;
4173 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004174 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004175 name = (const char *) cur->name;
4176 if (cur->ns) {
William M. Brack84d83e32003-12-23 03:45:17 +00004177 if (cur->ns->prefix != NULL)
4178 snprintf(nametemp, sizeof(nametemp) - 1,
Daniel Veillard8faa7832001-11-26 15:58:08 +00004179 "%s:%s", cur->ns->prefix, cur->name);
William M. Brack84d83e32003-12-23 03:45:17 +00004180 else
4181 snprintf(nametemp, sizeof(nametemp) - 1,
4182 "%s", cur->name);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004183 nametemp[sizeof(nametemp) - 1] = 0;
4184 name = nametemp;
4185 }
4186 next = cur->parent;
4187
4188 /*
4189 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004190 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004191 */
4192 tmp = cur->prev;
4193 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004194 if ((tmp->type == XML_ELEMENT_NODE) &&
4195 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004196 occur++;
4197 tmp = tmp->prev;
4198 }
4199 if (occur == 0) {
4200 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004201 while (tmp != NULL && occur == 0) {
4202 if ((tmp->type == XML_ELEMENT_NODE) &&
4203 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004204 occur++;
4205 tmp = tmp->next;
4206 }
4207 if (occur != 0)
4208 occur = 1;
4209 } else
4210 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004211 } else if (cur->type == XML_COMMENT_NODE) {
4212 sep = "/";
4213 name = "comment()";
4214 next = cur->parent;
4215
4216 /*
4217 * Thumbler index computation
4218 */
4219 tmp = cur->prev;
4220 while (tmp != NULL) {
4221 if (tmp->type == XML_COMMENT_NODE)
4222 occur++;
4223 tmp = tmp->prev;
4224 }
4225 if (occur == 0) {
4226 tmp = cur->next;
4227 while (tmp != NULL && occur == 0) {
4228 if (tmp->type == XML_COMMENT_NODE)
4229 occur++;
4230 tmp = tmp->next;
4231 }
4232 if (occur != 0)
4233 occur = 1;
4234 } else
4235 occur++;
4236 } else if ((cur->type == XML_TEXT_NODE) ||
4237 (cur->type == XML_CDATA_SECTION_NODE)) {
4238 sep = "/";
4239 name = "text()";
4240 next = cur->parent;
4241
4242 /*
4243 * Thumbler index computation
4244 */
4245 tmp = cur->prev;
4246 while (tmp != NULL) {
4247 if ((cur->type == XML_TEXT_NODE) ||
4248 (cur->type == XML_CDATA_SECTION_NODE))
4249 occur++;
4250 tmp = tmp->prev;
4251 }
4252 if (occur == 0) {
4253 tmp = cur->next;
4254 while (tmp != NULL && occur == 0) {
4255 if ((cur->type == XML_TEXT_NODE) ||
4256 (cur->type == XML_CDATA_SECTION_NODE))
4257 occur++;
4258 tmp = tmp->next;
4259 }
4260 if (occur != 0)
4261 occur = 1;
4262 } else
4263 occur++;
4264 } else if (cur->type == XML_PI_NODE) {
4265 sep = "/";
4266 snprintf(nametemp, sizeof(nametemp) - 1,
4267 "processing-instruction('%s')", cur->name);
4268 nametemp[sizeof(nametemp) - 1] = 0;
4269 name = nametemp;
4270
4271 next = cur->parent;
4272
4273 /*
4274 * Thumbler index computation
4275 */
4276 tmp = cur->prev;
4277 while (tmp != NULL) {
4278 if ((tmp->type == XML_PI_NODE) &&
4279 (xmlStrEqual(cur->name, tmp->name)))
4280 occur++;
4281 tmp = tmp->prev;
4282 }
4283 if (occur == 0) {
4284 tmp = cur->next;
4285 while (tmp != NULL && occur == 0) {
4286 if ((tmp->type == XML_PI_NODE) &&
4287 (xmlStrEqual(cur->name, tmp->name)))
4288 occur++;
4289 tmp = tmp->next;
4290 }
4291 if (occur != 0)
4292 occur = 1;
4293 } else
4294 occur++;
4295
Daniel Veillard8faa7832001-11-26 15:58:08 +00004296 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004297 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004298 name = (const char *) (((xmlAttrPtr) cur)->name);
4299 next = ((xmlAttrPtr) cur)->parent;
4300 } else {
4301 next = cur->parent;
4302 }
4303
4304 /*
4305 * Make sure there is enough room
4306 */
4307 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4308 buf_len =
4309 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4310 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4311 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004312 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004313 xmlFree(buf);
4314 xmlFree(buffer);
4315 return (NULL);
4316 }
4317 buffer = temp;
4318 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4319 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004320 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004321 xmlFree(buf);
4322 xmlFree(buffer);
4323 return (NULL);
4324 }
4325 buf = temp;
4326 }
4327 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004328 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004329 sep, name, (char *) buffer);
4330 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004331 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004332 sep, name, occur, (char *) buffer);
4333 snprintf((char *) buffer, buf_len, "%s", buf);
4334 cur = next;
4335 } while (cur != NULL);
4336 xmlFree(buf);
4337 return (buffer);
4338}
Daniel Veillard652327a2003-09-29 18:02:38 +00004339#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004340
4341/**
Owen Taylor3473f882001-02-23 17:55:21 +00004342 * xmlDocGetRootElement:
4343 * @doc: the document
4344 *
4345 * Get the root element of the document (doc->children is a list
4346 * containing possibly comments, PIs, etc ...).
4347 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004348 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004349 */
4350xmlNodePtr
4351xmlDocGetRootElement(xmlDocPtr doc) {
4352 xmlNodePtr ret;
4353
4354 if (doc == NULL) return(NULL);
4355 ret = doc->children;
4356 while (ret != NULL) {
4357 if (ret->type == XML_ELEMENT_NODE)
4358 return(ret);
4359 ret = ret->next;
4360 }
4361 return(ret);
4362}
4363
Daniel Veillard2156d432004-03-04 15:59:36 +00004364#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004365/**
4366 * xmlDocSetRootElement:
4367 * @doc: the document
4368 * @root: the new document root element
4369 *
4370 * Set the root element of the document (doc->children is a list
4371 * containing possibly comments, PIs, etc ...).
4372 *
4373 * Returns the old root element if any was found
4374 */
4375xmlNodePtr
4376xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4377 xmlNodePtr old = NULL;
4378
4379 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004380 if (root == NULL)
4381 return(NULL);
4382 xmlUnlinkNode(root);
4383 root->doc = doc;
4384 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004385 old = doc->children;
4386 while (old != NULL) {
4387 if (old->type == XML_ELEMENT_NODE)
4388 break;
4389 old = old->next;
4390 }
4391 if (old == NULL) {
4392 if (doc->children == NULL) {
4393 doc->children = root;
4394 doc->last = root;
4395 } else {
4396 xmlAddSibling(doc->children, root);
4397 }
4398 } else {
4399 xmlReplaceNode(old, root);
4400 }
4401 return(old);
4402}
Daniel Veillard2156d432004-03-04 15:59:36 +00004403#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004404
Daniel Veillard2156d432004-03-04 15:59:36 +00004405#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004406/**
4407 * xmlNodeSetLang:
4408 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004409 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004410 *
4411 * Set the language of a node, i.e. the values of the xml:lang
4412 * attribute.
4413 */
4414void
4415xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004416 xmlNsPtr ns;
4417
Owen Taylor3473f882001-02-23 17:55:21 +00004418 if (cur == NULL) return;
4419 switch(cur->type) {
4420 case XML_TEXT_NODE:
4421 case XML_CDATA_SECTION_NODE:
4422 case XML_COMMENT_NODE:
4423 case XML_DOCUMENT_NODE:
4424 case XML_DOCUMENT_TYPE_NODE:
4425 case XML_DOCUMENT_FRAG_NODE:
4426 case XML_NOTATION_NODE:
4427 case XML_HTML_DOCUMENT_NODE:
4428 case XML_DTD_NODE:
4429 case XML_ELEMENT_DECL:
4430 case XML_ATTRIBUTE_DECL:
4431 case XML_ENTITY_DECL:
4432 case XML_PI_NODE:
4433 case XML_ENTITY_REF_NODE:
4434 case XML_ENTITY_NODE:
4435 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004436#ifdef LIBXML_DOCB_ENABLED
4437 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004438#endif
4439 case XML_XINCLUDE_START:
4440 case XML_XINCLUDE_END:
4441 return;
4442 case XML_ELEMENT_NODE:
4443 case XML_ATTRIBUTE_NODE:
4444 break;
4445 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004446 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4447 if (ns == NULL)
4448 return;
4449 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004450}
Daniel Veillard652327a2003-09-29 18:02:38 +00004451#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004452
4453/**
4454 * xmlNodeGetLang:
4455 * @cur: the node being checked
4456 *
4457 * Searches the language of a node, i.e. the values of the xml:lang
4458 * attribute or the one carried by the nearest ancestor.
4459 *
4460 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004461 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004462 */
4463xmlChar *
4464xmlNodeGetLang(xmlNodePtr cur) {
4465 xmlChar *lang;
4466
4467 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004468 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004469 if (lang != NULL)
4470 return(lang);
4471 cur = cur->parent;
4472 }
4473 return(NULL);
4474}
4475
4476
Daniel Veillard652327a2003-09-29 18:02:38 +00004477#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004478/**
4479 * xmlNodeSetSpacePreserve:
4480 * @cur: the node being changed
4481 * @val: the xml:space value ("0": default, 1: "preserve")
4482 *
4483 * Set (or reset) the space preserving behaviour of a node, i.e. the
4484 * value of the xml:space attribute.
4485 */
4486void
4487xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004488 xmlNsPtr ns;
4489
Owen Taylor3473f882001-02-23 17:55:21 +00004490 if (cur == NULL) return;
4491 switch(cur->type) {
4492 case XML_TEXT_NODE:
4493 case XML_CDATA_SECTION_NODE:
4494 case XML_COMMENT_NODE:
4495 case XML_DOCUMENT_NODE:
4496 case XML_DOCUMENT_TYPE_NODE:
4497 case XML_DOCUMENT_FRAG_NODE:
4498 case XML_NOTATION_NODE:
4499 case XML_HTML_DOCUMENT_NODE:
4500 case XML_DTD_NODE:
4501 case XML_ELEMENT_DECL:
4502 case XML_ATTRIBUTE_DECL:
4503 case XML_ENTITY_DECL:
4504 case XML_PI_NODE:
4505 case XML_ENTITY_REF_NODE:
4506 case XML_ENTITY_NODE:
4507 case XML_NAMESPACE_DECL:
4508 case XML_XINCLUDE_START:
4509 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004510#ifdef LIBXML_DOCB_ENABLED
4511 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004512#endif
4513 return;
4514 case XML_ELEMENT_NODE:
4515 case XML_ATTRIBUTE_NODE:
4516 break;
4517 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004518 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4519 if (ns == NULL)
4520 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004521 switch (val) {
4522 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004523 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004524 break;
4525 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004526 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004527 break;
4528 }
4529}
Daniel Veillard652327a2003-09-29 18:02:38 +00004530#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004531
4532/**
4533 * xmlNodeGetSpacePreserve:
4534 * @cur: the node being checked
4535 *
4536 * Searches the space preserving behaviour of a node, i.e. the values
4537 * of the xml:space attribute or the one carried by the nearest
4538 * ancestor.
4539 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004540 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004541 */
4542int
4543xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4544 xmlChar *space;
4545
4546 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004547 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004548 if (space != NULL) {
4549 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4550 xmlFree(space);
4551 return(1);
4552 }
4553 if (xmlStrEqual(space, BAD_CAST "default")) {
4554 xmlFree(space);
4555 return(0);
4556 }
4557 xmlFree(space);
4558 }
4559 cur = cur->parent;
4560 }
4561 return(-1);
4562}
4563
Daniel Veillard652327a2003-09-29 18:02:38 +00004564#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004565/**
4566 * xmlNodeSetName:
4567 * @cur: the node being changed
4568 * @name: the new tag name
4569 *
4570 * Set (or reset) the name of a node.
4571 */
4572void
4573xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4574 if (cur == NULL) return;
4575 if (name == NULL) return;
4576 switch(cur->type) {
4577 case XML_TEXT_NODE:
4578 case XML_CDATA_SECTION_NODE:
4579 case XML_COMMENT_NODE:
4580 case XML_DOCUMENT_TYPE_NODE:
4581 case XML_DOCUMENT_FRAG_NODE:
4582 case XML_NOTATION_NODE:
4583 case XML_HTML_DOCUMENT_NODE:
4584 case XML_NAMESPACE_DECL:
4585 case XML_XINCLUDE_START:
4586 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004587#ifdef LIBXML_DOCB_ENABLED
4588 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004589#endif
4590 return;
4591 case XML_ELEMENT_NODE:
4592 case XML_ATTRIBUTE_NODE:
4593 case XML_PI_NODE:
4594 case XML_ENTITY_REF_NODE:
4595 case XML_ENTITY_NODE:
4596 case XML_DTD_NODE:
4597 case XML_DOCUMENT_NODE:
4598 case XML_ELEMENT_DECL:
4599 case XML_ATTRIBUTE_DECL:
4600 case XML_ENTITY_DECL:
4601 break;
4602 }
4603 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4604 cur->name = xmlStrdup(name);
4605}
Daniel Veillard2156d432004-03-04 15:59:36 +00004606#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004607
Daniel Veillard2156d432004-03-04 15:59:36 +00004608#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004609/**
4610 * xmlNodeSetBase:
4611 * @cur: the node being changed
4612 * @uri: the new base URI
4613 *
4614 * Set (or reset) the base URI of a node, i.e. the value of the
4615 * xml:base attribute.
4616 */
4617void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004618xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004619 xmlNsPtr ns;
4620
Owen Taylor3473f882001-02-23 17:55:21 +00004621 if (cur == NULL) return;
4622 switch(cur->type) {
4623 case XML_TEXT_NODE:
4624 case XML_CDATA_SECTION_NODE:
4625 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004626 case XML_DOCUMENT_TYPE_NODE:
4627 case XML_DOCUMENT_FRAG_NODE:
4628 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004629 case XML_DTD_NODE:
4630 case XML_ELEMENT_DECL:
4631 case XML_ATTRIBUTE_DECL:
4632 case XML_ENTITY_DECL:
4633 case XML_PI_NODE:
4634 case XML_ENTITY_REF_NODE:
4635 case XML_ENTITY_NODE:
4636 case XML_NAMESPACE_DECL:
4637 case XML_XINCLUDE_START:
4638 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004639 return;
4640 case XML_ELEMENT_NODE:
4641 case XML_ATTRIBUTE_NODE:
4642 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004643 case XML_DOCUMENT_NODE:
4644#ifdef LIBXML_DOCB_ENABLED
4645 case XML_DOCB_DOCUMENT_NODE:
4646#endif
4647 case XML_HTML_DOCUMENT_NODE: {
4648 xmlDocPtr doc = (xmlDocPtr) cur;
4649
4650 if (doc->URL != NULL)
4651 xmlFree((xmlChar *) doc->URL);
4652 if (uri == NULL)
4653 doc->URL = NULL;
4654 else
4655 doc->URL = xmlStrdup(uri);
4656 return;
4657 }
Owen Taylor3473f882001-02-23 17:55:21 +00004658 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004659
4660 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4661 if (ns == NULL)
4662 return;
4663 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004664}
Daniel Veillard652327a2003-09-29 18:02:38 +00004665#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004666
4667/**
Owen Taylor3473f882001-02-23 17:55:21 +00004668 * xmlNodeGetBase:
4669 * @doc: the document the node pertains to
4670 * @cur: the node being checked
4671 *
4672 * Searches for the BASE URL. The code should work on both XML
4673 * and HTML document even if base mechanisms are completely different.
4674 * It returns the base as defined in RFC 2396 sections
4675 * 5.1.1. Base URI within Document Content
4676 * and
4677 * 5.1.2. Base URI from the Encapsulating Entity
4678 * However it does not return the document base (5.1.3), use
4679 * xmlDocumentGetBase() for this
4680 *
4681 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004682 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004683 */
4684xmlChar *
4685xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004686 xmlChar *oldbase = NULL;
4687 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004688
4689 if ((cur == NULL) && (doc == NULL))
4690 return(NULL);
4691 if (doc == NULL) doc = cur->doc;
4692 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4693 cur = doc->children;
4694 while ((cur != NULL) && (cur->name != NULL)) {
4695 if (cur->type != XML_ELEMENT_NODE) {
4696 cur = cur->next;
4697 continue;
4698 }
4699 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4700 cur = cur->children;
4701 continue;
4702 }
4703 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4704 cur = cur->children;
4705 continue;
4706 }
4707 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4708 return(xmlGetProp(cur, BAD_CAST "href"));
4709 }
4710 cur = cur->next;
4711 }
4712 return(NULL);
4713 }
4714 while (cur != NULL) {
4715 if (cur->type == XML_ENTITY_DECL) {
4716 xmlEntityPtr ent = (xmlEntityPtr) cur;
4717 return(xmlStrdup(ent->URI));
4718 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004719 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004720 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004721 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004722 if (oldbase != NULL) {
4723 newbase = xmlBuildURI(oldbase, base);
4724 if (newbase != NULL) {
4725 xmlFree(oldbase);
4726 xmlFree(base);
4727 oldbase = newbase;
4728 } else {
4729 xmlFree(oldbase);
4730 xmlFree(base);
4731 return(NULL);
4732 }
4733 } else {
4734 oldbase = base;
4735 }
4736 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4737 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4738 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4739 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004740 }
4741 }
Owen Taylor3473f882001-02-23 17:55:21 +00004742 cur = cur->parent;
4743 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004744 if ((doc != NULL) && (doc->URL != NULL)) {
4745 if (oldbase == NULL)
4746 return(xmlStrdup(doc->URL));
4747 newbase = xmlBuildURI(oldbase, doc->URL);
4748 xmlFree(oldbase);
4749 return(newbase);
4750 }
4751 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004752}
4753
4754/**
Daniel Veillard78697292003-10-19 20:44:43 +00004755 * xmlNodeBufGetContent:
4756 * @buffer: a buffer
4757 * @cur: the node being read
4758 *
4759 * Read the value of a node @cur, this can be either the text carried
4760 * directly by this node if it's a TEXT node or the aggregate string
4761 * of the values carried by this node child's (TEXT and ENTITY_REF).
4762 * Entity references are substituted.
4763 * Fills up the buffer @buffer with this value
4764 *
4765 * Returns 0 in case of success and -1 in case of error.
4766 */
4767int
4768xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4769{
4770 if ((cur == NULL) || (buffer == NULL)) return(-1);
4771 switch (cur->type) {
4772 case XML_CDATA_SECTION_NODE:
4773 case XML_TEXT_NODE:
4774 xmlBufferCat(buffer, cur->content);
4775 break;
4776 case XML_DOCUMENT_FRAG_NODE:
4777 case XML_ELEMENT_NODE:{
4778 xmlNodePtr tmp = cur;
4779
4780 while (tmp != NULL) {
4781 switch (tmp->type) {
4782 case XML_CDATA_SECTION_NODE:
4783 case XML_TEXT_NODE:
4784 if (tmp->content != NULL)
4785 xmlBufferCat(buffer, tmp->content);
4786 break;
4787 case XML_ENTITY_REF_NODE:
4788 xmlNodeBufGetContent(buffer, tmp->children);
4789 break;
4790 default:
4791 break;
4792 }
4793 /*
4794 * Skip to next node
4795 */
4796 if (tmp->children != NULL) {
4797 if (tmp->children->type != XML_ENTITY_DECL) {
4798 tmp = tmp->children;
4799 continue;
4800 }
4801 }
4802 if (tmp == cur)
4803 break;
4804
4805 if (tmp->next != NULL) {
4806 tmp = tmp->next;
4807 continue;
4808 }
4809
4810 do {
4811 tmp = tmp->parent;
4812 if (tmp == NULL)
4813 break;
4814 if (tmp == cur) {
4815 tmp = NULL;
4816 break;
4817 }
4818 if (tmp->next != NULL) {
4819 tmp = tmp->next;
4820 break;
4821 }
4822 } while (tmp != NULL);
4823 }
4824 break;
4825 }
4826 case XML_ATTRIBUTE_NODE:{
4827 xmlAttrPtr attr = (xmlAttrPtr) cur;
4828 xmlNodePtr tmp = attr->children;
4829
4830 while (tmp != NULL) {
4831 if (tmp->type == XML_TEXT_NODE)
4832 xmlBufferCat(buffer, tmp->content);
4833 else
4834 xmlNodeBufGetContent(buffer, tmp);
4835 tmp = tmp->next;
4836 }
4837 break;
4838 }
4839 case XML_COMMENT_NODE:
4840 case XML_PI_NODE:
4841 xmlBufferCat(buffer, cur->content);
4842 break;
4843 case XML_ENTITY_REF_NODE:{
4844 xmlEntityPtr ent;
4845 xmlNodePtr tmp;
4846
4847 /* lookup entity declaration */
4848 ent = xmlGetDocEntity(cur->doc, cur->name);
4849 if (ent == NULL)
4850 return(-1);
4851
4852 /* an entity content can be any "well balanced chunk",
4853 * i.e. the result of the content [43] production:
4854 * http://www.w3.org/TR/REC-xml#NT-content
4855 * -> we iterate through child nodes and recursive call
4856 * xmlNodeGetContent() which handles all possible node types */
4857 tmp = ent->children;
4858 while (tmp) {
4859 xmlNodeBufGetContent(buffer, tmp);
4860 tmp = tmp->next;
4861 }
4862 break;
4863 }
4864 case XML_ENTITY_NODE:
4865 case XML_DOCUMENT_TYPE_NODE:
4866 case XML_NOTATION_NODE:
4867 case XML_DTD_NODE:
4868 case XML_XINCLUDE_START:
4869 case XML_XINCLUDE_END:
4870 break;
4871 case XML_DOCUMENT_NODE:
4872#ifdef LIBXML_DOCB_ENABLED
4873 case XML_DOCB_DOCUMENT_NODE:
4874#endif
4875 case XML_HTML_DOCUMENT_NODE:
4876 cur = cur->children;
4877 while (cur!= NULL) {
4878 if ((cur->type == XML_ELEMENT_NODE) ||
4879 (cur->type == XML_TEXT_NODE) ||
4880 (cur->type == XML_CDATA_SECTION_NODE)) {
4881 xmlNodeBufGetContent(buffer, cur);
4882 }
4883 cur = cur->next;
4884 }
4885 break;
4886 case XML_NAMESPACE_DECL:
4887 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
4888 break;
4889 case XML_ELEMENT_DECL:
4890 case XML_ATTRIBUTE_DECL:
4891 case XML_ENTITY_DECL:
4892 break;
4893 }
4894 return(0);
4895}
4896/**
Owen Taylor3473f882001-02-23 17:55:21 +00004897 * xmlNodeGetContent:
4898 * @cur: the node being read
4899 *
4900 * Read the value of a node, this can be either the text carried
4901 * directly by this node if it's a TEXT node or the aggregate string
4902 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004903 * Entity references are substituted.
4904 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004905 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004906 */
4907xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004908xmlNodeGetContent(xmlNodePtr cur)
4909{
4910 if (cur == NULL)
4911 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004912 switch (cur->type) {
4913 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004914 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00004915 xmlBufferPtr buffer;
4916 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004917
Daniel Veillard814a76d2003-01-23 18:24:20 +00004918 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004919 if (buffer == NULL)
4920 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00004921 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004922 ret = buffer->content;
4923 buffer->content = NULL;
4924 xmlBufferFree(buffer);
4925 return (ret);
4926 }
4927 case XML_ATTRIBUTE_NODE:{
4928 xmlAttrPtr attr = (xmlAttrPtr) cur;
4929
4930 if (attr->parent != NULL)
4931 return (xmlNodeListGetString
4932 (attr->parent->doc, attr->children, 1));
4933 else
4934 return (xmlNodeListGetString(NULL, attr->children, 1));
4935 break;
4936 }
Owen Taylor3473f882001-02-23 17:55:21 +00004937 case XML_COMMENT_NODE:
4938 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004939 if (cur->content != NULL)
4940 return (xmlStrdup(cur->content));
4941 return (NULL);
4942 case XML_ENTITY_REF_NODE:{
4943 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00004944 xmlBufferPtr buffer;
4945 xmlChar *ret;
4946
4947 /* lookup entity declaration */
4948 ent = xmlGetDocEntity(cur->doc, cur->name);
4949 if (ent == NULL)
4950 return (NULL);
4951
4952 buffer = xmlBufferCreate();
4953 if (buffer == NULL)
4954 return (NULL);
4955
Daniel Veillardc4696922003-10-19 21:47:14 +00004956 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004957
4958 ret = buffer->content;
4959 buffer->content = NULL;
4960 xmlBufferFree(buffer);
4961 return (ret);
4962 }
Owen Taylor3473f882001-02-23 17:55:21 +00004963 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004964 case XML_DOCUMENT_TYPE_NODE:
4965 case XML_NOTATION_NODE:
4966 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004967 case XML_XINCLUDE_START:
4968 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00004969 return (NULL);
4970 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004971#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004972 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004973#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00004974 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00004975 xmlBufferPtr buffer;
4976 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00004977
Daniel Veillardc4696922003-10-19 21:47:14 +00004978 buffer = xmlBufferCreate();
4979 if (buffer == NULL)
4980 return (NULL);
4981
4982 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
4983
4984 ret = buffer->content;
4985 buffer->content = NULL;
4986 xmlBufferFree(buffer);
4987 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004988 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004989 case XML_NAMESPACE_DECL: {
4990 xmlChar *tmp;
4991
4992 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4993 return (tmp);
4994 }
Owen Taylor3473f882001-02-23 17:55:21 +00004995 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004996 /* TODO !!! */
4997 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004998 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004999 /* TODO !!! */
5000 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005001 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005002 /* TODO !!! */
5003 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005004 case XML_CDATA_SECTION_NODE:
5005 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005006 if (cur->content != NULL)
5007 return (xmlStrdup(cur->content));
5008 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005009 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005010 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005011}
Daniel Veillard652327a2003-09-29 18:02:38 +00005012
Owen Taylor3473f882001-02-23 17:55:21 +00005013/**
5014 * xmlNodeSetContent:
5015 * @cur: the node being modified
5016 * @content: the new value of the content
5017 *
5018 * Replace the content of a node.
5019 */
5020void
5021xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5022 if (cur == NULL) {
5023#ifdef DEBUG_TREE
5024 xmlGenericError(xmlGenericErrorContext,
5025 "xmlNodeSetContent : node == NULL\n");
5026#endif
5027 return;
5028 }
5029 switch (cur->type) {
5030 case XML_DOCUMENT_FRAG_NODE:
5031 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005032 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005033 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5034 cur->children = xmlStringGetNodeList(cur->doc, content);
5035 UPDATE_LAST_CHILD_AND_PARENT(cur)
5036 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005037 case XML_TEXT_NODE:
5038 case XML_CDATA_SECTION_NODE:
5039 case XML_ENTITY_REF_NODE:
5040 case XML_ENTITY_NODE:
5041 case XML_PI_NODE:
5042 case XML_COMMENT_NODE:
5043 if (cur->content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005044 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5045 xmlDictOwns(cur->doc->dict, cur->content)))
5046 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005047 }
5048 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5049 cur->last = cur->children = NULL;
5050 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005051 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005052 } else
5053 cur->content = NULL;
5054 break;
5055 case XML_DOCUMENT_NODE:
5056 case XML_HTML_DOCUMENT_NODE:
5057 case XML_DOCUMENT_TYPE_NODE:
5058 case XML_XINCLUDE_START:
5059 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005060#ifdef LIBXML_DOCB_ENABLED
5061 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005062#endif
5063 break;
5064 case XML_NOTATION_NODE:
5065 break;
5066 case XML_DTD_NODE:
5067 break;
5068 case XML_NAMESPACE_DECL:
5069 break;
5070 case XML_ELEMENT_DECL:
5071 /* TODO !!! */
5072 break;
5073 case XML_ATTRIBUTE_DECL:
5074 /* TODO !!! */
5075 break;
5076 case XML_ENTITY_DECL:
5077 /* TODO !!! */
5078 break;
5079 }
5080}
5081
Daniel Veillard652327a2003-09-29 18:02:38 +00005082#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005083/**
5084 * xmlNodeSetContentLen:
5085 * @cur: the node being modified
5086 * @content: the new value of the content
5087 * @len: the size of @content
5088 *
5089 * Replace the content of a node.
5090 */
5091void
5092xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5093 if (cur == NULL) {
5094#ifdef DEBUG_TREE
5095 xmlGenericError(xmlGenericErrorContext,
5096 "xmlNodeSetContentLen : node == NULL\n");
5097#endif
5098 return;
5099 }
5100 switch (cur->type) {
5101 case XML_DOCUMENT_FRAG_NODE:
5102 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005103 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005104 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5105 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5106 UPDATE_LAST_CHILD_AND_PARENT(cur)
5107 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005108 case XML_TEXT_NODE:
5109 case XML_CDATA_SECTION_NODE:
5110 case XML_ENTITY_REF_NODE:
5111 case XML_ENTITY_NODE:
5112 case XML_PI_NODE:
5113 case XML_COMMENT_NODE:
5114 case XML_NOTATION_NODE:
5115 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005116 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005117 }
5118 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5119 cur->children = cur->last = NULL;
5120 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005121 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005122 } else
5123 cur->content = NULL;
5124 break;
5125 case XML_DOCUMENT_NODE:
5126 case XML_DTD_NODE:
5127 case XML_HTML_DOCUMENT_NODE:
5128 case XML_DOCUMENT_TYPE_NODE:
5129 case XML_NAMESPACE_DECL:
5130 case XML_XINCLUDE_START:
5131 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005132#ifdef LIBXML_DOCB_ENABLED
5133 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005134#endif
5135 break;
5136 case XML_ELEMENT_DECL:
5137 /* TODO !!! */
5138 break;
5139 case XML_ATTRIBUTE_DECL:
5140 /* TODO !!! */
5141 break;
5142 case XML_ENTITY_DECL:
5143 /* TODO !!! */
5144 break;
5145 }
5146}
Daniel Veillard652327a2003-09-29 18:02:38 +00005147#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005148
5149/**
5150 * xmlNodeAddContentLen:
5151 * @cur: the node being modified
5152 * @content: extra content
5153 * @len: the size of @content
5154 *
5155 * Append the extra substring to the node content.
5156 */
5157void
5158xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5159 if (cur == NULL) {
5160#ifdef DEBUG_TREE
5161 xmlGenericError(xmlGenericErrorContext,
5162 "xmlNodeAddContentLen : node == NULL\n");
5163#endif
5164 return;
5165 }
5166 if (len <= 0) return;
5167 switch (cur->type) {
5168 case XML_DOCUMENT_FRAG_NODE:
5169 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005170 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005171
Daniel Veillard7db37732001-07-12 01:20:08 +00005172 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005173 newNode = xmlNewTextLen(content, len);
5174 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005175 tmp = xmlAddChild(cur, newNode);
5176 if (tmp != newNode)
5177 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005178 if ((last != NULL) && (last->next == newNode)) {
5179 xmlTextMerge(last, newNode);
5180 }
5181 }
5182 break;
5183 }
5184 case XML_ATTRIBUTE_NODE:
5185 break;
5186 case XML_TEXT_NODE:
5187 case XML_CDATA_SECTION_NODE:
5188 case XML_ENTITY_REF_NODE:
5189 case XML_ENTITY_NODE:
5190 case XML_PI_NODE:
5191 case XML_COMMENT_NODE:
5192 case XML_NOTATION_NODE:
5193 if (content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005194 if ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5195 xmlDictOwns(cur->doc->dict, cur->content)) {
5196 cur->content =
5197 xmlStrncatNew(cur->content, content, len);
5198 break;
5199 }
Owen Taylor3473f882001-02-23 17:55:21 +00005200 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005201 }
5202 case XML_DOCUMENT_NODE:
5203 case XML_DTD_NODE:
5204 case XML_HTML_DOCUMENT_NODE:
5205 case XML_DOCUMENT_TYPE_NODE:
5206 case XML_NAMESPACE_DECL:
5207 case XML_XINCLUDE_START:
5208 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005209#ifdef LIBXML_DOCB_ENABLED
5210 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005211#endif
5212 break;
5213 case XML_ELEMENT_DECL:
5214 case XML_ATTRIBUTE_DECL:
5215 case XML_ENTITY_DECL:
5216 break;
5217 }
5218}
5219
5220/**
5221 * xmlNodeAddContent:
5222 * @cur: the node being modified
5223 * @content: extra content
5224 *
5225 * Append the extra substring to the node content.
5226 */
5227void
5228xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5229 int len;
5230
5231 if (cur == NULL) {
5232#ifdef DEBUG_TREE
5233 xmlGenericError(xmlGenericErrorContext,
5234 "xmlNodeAddContent : node == NULL\n");
5235#endif
5236 return;
5237 }
5238 if (content == NULL) return;
5239 len = xmlStrlen(content);
5240 xmlNodeAddContentLen(cur, content, len);
5241}
5242
5243/**
5244 * xmlTextMerge:
5245 * @first: the first text node
5246 * @second: the second text node being merged
5247 *
5248 * Merge two text nodes into one
5249 * Returns the first text node augmented
5250 */
5251xmlNodePtr
5252xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5253 if (first == NULL) return(second);
5254 if (second == NULL) return(first);
5255 if (first->type != XML_TEXT_NODE) return(first);
5256 if (second->type != XML_TEXT_NODE) return(first);
5257 if (second->name != first->name)
5258 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005259 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005260 xmlUnlinkNode(second);
5261 xmlFreeNode(second);
5262 return(first);
5263}
5264
Daniel Veillard2156d432004-03-04 15:59:36 +00005265#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005266/**
5267 * xmlGetNsList:
5268 * @doc: the document
5269 * @node: the current node
5270 *
5271 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005272 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005273 * that need to be freed by the caller or NULL if no
5274 * namespace if defined
5275 */
5276xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005277xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5278{
Owen Taylor3473f882001-02-23 17:55:21 +00005279 xmlNsPtr cur;
5280 xmlNsPtr *ret = NULL;
5281 int nbns = 0;
5282 int maxns = 10;
5283 int i;
5284
5285 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005286 if (node->type == XML_ELEMENT_NODE) {
5287 cur = node->nsDef;
5288 while (cur != NULL) {
5289 if (ret == NULL) {
5290 ret =
5291 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5292 sizeof(xmlNsPtr));
5293 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005294 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005295 return (NULL);
5296 }
5297 ret[nbns] = NULL;
5298 }
5299 for (i = 0; i < nbns; i++) {
5300 if ((cur->prefix == ret[i]->prefix) ||
5301 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5302 break;
5303 }
5304 if (i >= nbns) {
5305 if (nbns >= maxns) {
5306 maxns *= 2;
5307 ret = (xmlNsPtr *) xmlRealloc(ret,
5308 (maxns +
5309 1) *
5310 sizeof(xmlNsPtr));
5311 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005312 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005313 return (NULL);
5314 }
5315 }
5316 ret[nbns++] = cur;
5317 ret[nbns] = NULL;
5318 }
Owen Taylor3473f882001-02-23 17:55:21 +00005319
Daniel Veillard77044732001-06-29 21:31:07 +00005320 cur = cur->next;
5321 }
5322 }
5323 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005324 }
Daniel Veillard77044732001-06-29 21:31:07 +00005325 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005326}
Daniel Veillard652327a2003-09-29 18:02:38 +00005327#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005328
5329/**
5330 * xmlSearchNs:
5331 * @doc: the document
5332 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005333 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005334 *
5335 * Search a Ns registered under a given name space for a document.
5336 * recurse on the parents until it finds the defined namespace
5337 * or return NULL otherwise.
5338 * @nameSpace can be NULL, this is a search for the default namespace.
5339 * We don't allow to cross entities boundaries. If you don't declare
5340 * the namespace within those you will be in troubles !!! A warning
5341 * is generated to cover this case.
5342 *
5343 * Returns the namespace pointer or NULL.
5344 */
5345xmlNsPtr
5346xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005347
Owen Taylor3473f882001-02-23 17:55:21 +00005348 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005349 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005350
5351 if (node == NULL) return(NULL);
5352 if ((nameSpace != NULL) &&
5353 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005354 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5355 /*
5356 * The XML-1.0 namespace is normally held on the root
5357 * element. In this case exceptionally create it on the
5358 * node element.
5359 */
5360 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5361 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005362 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005363 return(NULL);
5364 }
5365 memset(cur, 0, sizeof(xmlNs));
5366 cur->type = XML_LOCAL_NAMESPACE;
5367 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5368 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5369 cur->next = node->nsDef;
5370 node->nsDef = cur;
5371 return(cur);
5372 }
Owen Taylor3473f882001-02-23 17:55:21 +00005373 if (doc->oldNs == NULL) {
5374 /*
5375 * Allocate a new Namespace and fill the fields.
5376 */
5377 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5378 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005379 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005380 return(NULL);
5381 }
5382 memset(doc->oldNs, 0, sizeof(xmlNs));
5383 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5384
5385 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5386 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5387 }
5388 return(doc->oldNs);
5389 }
5390 while (node != NULL) {
5391 if ((node->type == XML_ENTITY_REF_NODE) ||
5392 (node->type == XML_ENTITY_NODE) ||
5393 (node->type == XML_ENTITY_DECL))
5394 return(NULL);
5395 if (node->type == XML_ELEMENT_NODE) {
5396 cur = node->nsDef;
5397 while (cur != NULL) {
5398 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5399 (cur->href != NULL))
5400 return(cur);
5401 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5402 (cur->href != NULL) &&
5403 (xmlStrEqual(cur->prefix, nameSpace)))
5404 return(cur);
5405 cur = cur->next;
5406 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005407 if (orig != node) {
5408 cur = node->ns;
5409 if (cur != NULL) {
5410 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5411 (cur->href != NULL))
5412 return(cur);
5413 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5414 (cur->href != NULL) &&
5415 (xmlStrEqual(cur->prefix, nameSpace)))
5416 return(cur);
5417 }
5418 }
Owen Taylor3473f882001-02-23 17:55:21 +00005419 }
5420 node = node->parent;
5421 }
5422 return(NULL);
5423}
5424
5425/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005426 * xmlNsInScope:
5427 * @doc: the document
5428 * @node: the current node
5429 * @ancestor: the ancestor carrying the namespace
5430 * @prefix: the namespace prefix
5431 *
5432 * Verify that the given namespace held on @ancestor is still in scope
5433 * on node.
5434 *
5435 * Returns 1 if true, 0 if false and -1 in case of error.
5436 */
5437static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005438xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5439 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005440{
5441 xmlNsPtr tst;
5442
5443 while ((node != NULL) && (node != ancestor)) {
5444 if ((node->type == XML_ENTITY_REF_NODE) ||
5445 (node->type == XML_ENTITY_NODE) ||
5446 (node->type == XML_ENTITY_DECL))
5447 return (-1);
5448 if (node->type == XML_ELEMENT_NODE) {
5449 tst = node->nsDef;
5450 while (tst != NULL) {
5451 if ((tst->prefix == NULL)
5452 && (prefix == NULL))
5453 return (0);
5454 if ((tst->prefix != NULL)
5455 && (prefix != NULL)
5456 && (xmlStrEqual(tst->prefix, prefix)))
5457 return (0);
5458 tst = tst->next;
5459 }
5460 }
5461 node = node->parent;
5462 }
5463 if (node != ancestor)
5464 return (-1);
5465 return (1);
5466}
5467
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005468/**
Owen Taylor3473f882001-02-23 17:55:21 +00005469 * xmlSearchNsByHref:
5470 * @doc: the document
5471 * @node: the current node
5472 * @href: the namespace value
5473 *
5474 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5475 * the defined namespace or return NULL otherwise.
5476 * Returns the namespace pointer or NULL.
5477 */
5478xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005479xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5480{
Owen Taylor3473f882001-02-23 17:55:21 +00005481 xmlNsPtr cur;
5482 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005483 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005484
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005485 if ((node == NULL) || (href == NULL))
5486 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005487 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005488 /*
5489 * Only the document can hold the XML spec namespace.
5490 */
5491 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5492 /*
5493 * The XML-1.0 namespace is normally held on the root
5494 * element. In this case exceptionally create it on the
5495 * node element.
5496 */
5497 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5498 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005499 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005500 return (NULL);
5501 }
5502 memset(cur, 0, sizeof(xmlNs));
5503 cur->type = XML_LOCAL_NAMESPACE;
5504 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5505 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5506 cur->next = node->nsDef;
5507 node->nsDef = cur;
5508 return (cur);
5509 }
5510 if (doc->oldNs == NULL) {
5511 /*
5512 * Allocate a new Namespace and fill the fields.
5513 */
5514 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5515 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005516 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005517 return (NULL);
5518 }
5519 memset(doc->oldNs, 0, sizeof(xmlNs));
5520 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005521
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005522 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5523 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5524 }
5525 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005526 }
Daniel Veillard62040be2004-05-17 03:17:26 +00005527 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00005528 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005529 if ((node->type == XML_ENTITY_REF_NODE) ||
5530 (node->type == XML_ENTITY_NODE) ||
5531 (node->type == XML_ENTITY_DECL))
5532 return (NULL);
5533 if (node->type == XML_ELEMENT_NODE) {
5534 cur = node->nsDef;
5535 while (cur != NULL) {
5536 if ((cur->href != NULL) && (href != NULL) &&
5537 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005538 if (((!is_attr) || (cur->prefix != NULL)) &&
5539 (xmlNsInScope(doc, orig, node, cur->href) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005540 return (cur);
5541 }
5542 cur = cur->next;
5543 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005544 if (orig != node) {
5545 cur = node->ns;
5546 if (cur != NULL) {
5547 if ((cur->href != NULL) && (href != NULL) &&
5548 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005549 if (((!is_attr) || (cur->prefix != NULL)) &&
5550 (xmlNsInScope(doc, orig, node, cur->href) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00005551 return (cur);
5552 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005553 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005554 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005555 }
5556 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005557 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005558 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005559}
5560
5561/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005562 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005563 * @doc: the document
5564 * @tree: a node expected to hold the new namespace
5565 * @ns: the original namespace
5566 *
5567 * This function tries to locate a namespace definition in a tree
5568 * ancestors, or create a new namespace definition node similar to
5569 * @ns trying to reuse the same prefix. However if the given prefix is
5570 * null (default namespace) or reused within the subtree defined by
5571 * @tree or on one of its ancestors then a new prefix is generated.
5572 * Returns the (new) namespace definition or NULL in case of error
5573 */
5574xmlNsPtr
5575xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5576 xmlNsPtr def;
5577 xmlChar prefix[50];
5578 int counter = 1;
5579
5580 if (tree == NULL) {
5581#ifdef DEBUG_TREE
5582 xmlGenericError(xmlGenericErrorContext,
5583 "xmlNewReconciliedNs : tree == NULL\n");
5584#endif
5585 return(NULL);
5586 }
5587 if (ns == NULL) {
5588#ifdef DEBUG_TREE
5589 xmlGenericError(xmlGenericErrorContext,
5590 "xmlNewReconciliedNs : ns == NULL\n");
5591#endif
5592 return(NULL);
5593 }
5594 /*
5595 * Search an existing namespace definition inherited.
5596 */
5597 def = xmlSearchNsByHref(doc, tree, ns->href);
5598 if (def != NULL)
5599 return(def);
5600
5601 /*
5602 * Find a close prefix which is not already in use.
5603 * Let's strip namespace prefixes longer than 20 chars !
5604 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005605 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005606 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005607 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005608 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005609
Owen Taylor3473f882001-02-23 17:55:21 +00005610 def = xmlSearchNs(doc, tree, prefix);
5611 while (def != NULL) {
5612 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005613 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005614 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005615 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005616 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005617 def = xmlSearchNs(doc, tree, prefix);
5618 }
5619
5620 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005621 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005622 */
5623 def = xmlNewNs(tree, ns->href, prefix);
5624 return(def);
5625}
5626
Daniel Veillard652327a2003-09-29 18:02:38 +00005627#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005628/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005629 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005630 * @doc: the document
5631 * @tree: a node defining the subtree to reconciliate
5632 *
5633 * This function checks that all the namespaces declared within the given
5634 * tree are properly declared. This is needed for example after Copy or Cut
5635 * and then paste operations. The subtree may still hold pointers to
5636 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005637 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005638 * the new environment. If not possible the new namespaces are redeclared
5639 * on @tree at the top of the given subtree.
5640 * Returns the number of namespace declarations created or -1 in case of error.
5641 */
5642int
5643xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5644 xmlNsPtr *oldNs = NULL;
5645 xmlNsPtr *newNs = NULL;
5646 int sizeCache = 0;
5647 int nbCache = 0;
5648
5649 xmlNsPtr n;
5650 xmlNodePtr node = tree;
5651 xmlAttrPtr attr;
5652 int ret = 0, i;
5653
5654 while (node != NULL) {
5655 /*
5656 * Reconciliate the node namespace
5657 */
5658 if (node->ns != NULL) {
5659 /*
5660 * initialize the cache if needed
5661 */
5662 if (sizeCache == 0) {
5663 sizeCache = 10;
5664 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5665 sizeof(xmlNsPtr));
5666 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005667 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005668 return(-1);
5669 }
5670 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5671 sizeof(xmlNsPtr));
5672 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005673 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005674 xmlFree(oldNs);
5675 return(-1);
5676 }
5677 }
5678 for (i = 0;i < nbCache;i++) {
5679 if (oldNs[i] == node->ns) {
5680 node->ns = newNs[i];
5681 break;
5682 }
5683 }
5684 if (i == nbCache) {
5685 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005686 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005687 */
5688 n = xmlNewReconciliedNs(doc, tree, node->ns);
5689 if (n != NULL) { /* :-( what if else ??? */
5690 /*
5691 * check if we need to grow the cache buffers.
5692 */
5693 if (sizeCache <= nbCache) {
5694 sizeCache *= 2;
5695 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5696 sizeof(xmlNsPtr));
5697 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005698 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005699 xmlFree(newNs);
5700 return(-1);
5701 }
5702 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5703 sizeof(xmlNsPtr));
5704 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005705 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005706 xmlFree(oldNs);
5707 return(-1);
5708 }
5709 }
5710 newNs[nbCache] = n;
5711 oldNs[nbCache++] = node->ns;
5712 node->ns = n;
5713 }
5714 }
5715 }
5716 /*
5717 * now check for namespace hold by attributes on the node.
5718 */
5719 attr = node->properties;
5720 while (attr != NULL) {
5721 if (attr->ns != NULL) {
5722 /*
5723 * initialize the cache if needed
5724 */
5725 if (sizeCache == 0) {
5726 sizeCache = 10;
5727 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5728 sizeof(xmlNsPtr));
5729 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005730 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005731 return(-1);
5732 }
5733 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5734 sizeof(xmlNsPtr));
5735 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005736 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005737 xmlFree(oldNs);
5738 return(-1);
5739 }
5740 }
5741 for (i = 0;i < nbCache;i++) {
5742 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005743 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005744 break;
5745 }
5746 }
5747 if (i == nbCache) {
5748 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005749 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005750 */
5751 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5752 if (n != NULL) { /* :-( what if else ??? */
5753 /*
5754 * check if we need to grow the cache buffers.
5755 */
5756 if (sizeCache <= nbCache) {
5757 sizeCache *= 2;
5758 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5759 sizeof(xmlNsPtr));
5760 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005761 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005762 xmlFree(newNs);
5763 return(-1);
5764 }
5765 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5766 sizeof(xmlNsPtr));
5767 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005768 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005769 xmlFree(oldNs);
5770 return(-1);
5771 }
5772 }
5773 newNs[nbCache] = n;
5774 oldNs[nbCache++] = attr->ns;
5775 attr->ns = n;
5776 }
5777 }
5778 }
5779 attr = attr->next;
5780 }
5781
5782 /*
5783 * Browse the full subtree, deep first
5784 */
Daniel Veillardac996a12004-07-30 12:02:58 +00005785 if (node->children != NULL && node->type != XML_ENTITY_REF_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00005786 /* deep first */
5787 node = node->children;
5788 } else if ((node != tree) && (node->next != NULL)) {
5789 /* then siblings */
5790 node = node->next;
5791 } else if (node != tree) {
5792 /* go up to parents->next if needed */
5793 while (node != tree) {
5794 if (node->parent != NULL)
5795 node = node->parent;
5796 if ((node != tree) && (node->next != NULL)) {
5797 node = node->next;
5798 break;
5799 }
5800 if (node->parent == NULL) {
5801 node = NULL;
5802 break;
5803 }
5804 }
5805 /* exit condition */
5806 if (node == tree)
5807 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005808 } else
5809 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005810 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005811 if (oldNs != NULL)
5812 xmlFree(oldNs);
5813 if (newNs != NULL)
5814 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005815 return(ret);
5816}
Daniel Veillard652327a2003-09-29 18:02:38 +00005817#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005818
5819/**
5820 * xmlHasProp:
5821 * @node: the node
5822 * @name: the attribute name
5823 *
5824 * Search an attribute associated to a node
5825 * This function also looks in DTD attribute declaration for #FIXED or
5826 * default declaration values unless DTD use has been turned off.
5827 *
5828 * Returns the attribute or the attribute declaration or NULL if
5829 * neither was found.
5830 */
5831xmlAttrPtr
5832xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5833 xmlAttrPtr prop;
5834 xmlDocPtr doc;
5835
5836 if ((node == NULL) || (name == NULL)) return(NULL);
5837 /*
5838 * Check on the properties attached to the node
5839 */
5840 prop = node->properties;
5841 while (prop != NULL) {
5842 if (xmlStrEqual(prop->name, name)) {
5843 return(prop);
5844 }
5845 prop = prop->next;
5846 }
5847 if (!xmlCheckDTD) return(NULL);
5848
5849 /*
5850 * Check if there is a default declaration in the internal
5851 * or external subsets
5852 */
5853 doc = node->doc;
5854 if (doc != NULL) {
5855 xmlAttributePtr attrDecl;
5856 if (doc->intSubset != NULL) {
5857 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5858 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5859 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005860 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5861 /* return attribute declaration only if a default value is given
5862 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005863 return((xmlAttrPtr) attrDecl);
5864 }
5865 }
5866 return(NULL);
5867}
5868
5869/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005870 * xmlHasNsProp:
5871 * @node: the node
5872 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005873 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005874 *
5875 * Search for an attribute associated to a node
5876 * This attribute has to be anchored in the namespace specified.
5877 * This does the entity substitution.
5878 * This function looks in DTD attribute declaration for #FIXED or
5879 * default declaration values unless DTD use has been turned off.
5880 *
5881 * Returns the attribute or the attribute declaration or NULL
5882 * if neither was found.
5883 */
5884xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005885xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005886 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00005887#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005888 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00005889#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005890
5891 if (node == NULL)
5892 return(NULL);
5893
5894 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005895 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005896 return(xmlHasProp(node, name));
5897 while (prop != NULL) {
5898 /*
5899 * One need to have
5900 * - same attribute names
5901 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005902 */
5903 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005904 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5905 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005906 }
5907 prop = prop->next;
5908 }
5909 if (!xmlCheckDTD) return(NULL);
5910
Daniel Veillard652327a2003-09-29 18:02:38 +00005911#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005912 /*
5913 * Check if there is a default declaration in the internal
5914 * or external subsets
5915 */
5916 doc = node->doc;
5917 if (doc != NULL) {
5918 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005919 xmlAttributePtr attrDecl = NULL;
5920 xmlNsPtr *nsList, *cur;
5921 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005922
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005923 nsList = xmlGetNsList(node->doc, node);
5924 if (nsList == NULL)
5925 return(NULL);
5926 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5927 ename = xmlStrdup(node->ns->prefix);
5928 ename = xmlStrcat(ename, BAD_CAST ":");
5929 ename = xmlStrcat(ename, node->name);
5930 } else {
5931 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005932 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005933 if (ename == NULL) {
5934 xmlFree(nsList);
5935 return(NULL);
5936 }
5937
5938 cur = nsList;
5939 while (*cur != NULL) {
5940 if (xmlStrEqual((*cur)->href, nameSpace)) {
5941 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5942 name, (*cur)->prefix);
5943 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5944 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5945 name, (*cur)->prefix);
5946 }
5947 cur++;
5948 }
5949 xmlFree(nsList);
5950 xmlFree(ename);
5951 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005952 }
5953 }
Daniel Veillard652327a2003-09-29 18:02:38 +00005954#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005955 return(NULL);
5956}
5957
5958/**
Owen Taylor3473f882001-02-23 17:55:21 +00005959 * xmlGetProp:
5960 * @node: the node
5961 * @name: the attribute name
5962 *
5963 * Search and get the value of an attribute associated to a node
5964 * This does the entity substitution.
5965 * This function looks in DTD attribute declaration for #FIXED or
5966 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00005967 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00005968 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5969 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005970 *
5971 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005972 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005973 */
5974xmlChar *
5975xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5976 xmlAttrPtr prop;
5977 xmlDocPtr doc;
5978
5979 if ((node == NULL) || (name == NULL)) return(NULL);
5980 /*
5981 * Check on the properties attached to the node
5982 */
5983 prop = node->properties;
5984 while (prop != NULL) {
5985 if (xmlStrEqual(prop->name, name)) {
5986 xmlChar *ret;
5987
5988 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5989 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5990 return(ret);
5991 }
5992 prop = prop->next;
5993 }
5994 if (!xmlCheckDTD) return(NULL);
5995
5996 /*
5997 * Check if there is a default declaration in the internal
5998 * or external subsets
5999 */
6000 doc = node->doc;
6001 if (doc != NULL) {
6002 xmlAttributePtr attrDecl;
6003 if (doc->intSubset != NULL) {
6004 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6005 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6006 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006007 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6008 /* return attribute declaration only if a default value is given
6009 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006010 return(xmlStrdup(attrDecl->defaultValue));
6011 }
6012 }
6013 return(NULL);
6014}
6015
6016/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006017 * xmlGetNoNsProp:
6018 * @node: the node
6019 * @name: the attribute name
6020 *
6021 * Search and get the value of an attribute associated to a node
6022 * This does the entity substitution.
6023 * This function looks in DTD attribute declaration for #FIXED or
6024 * default declaration values unless DTD use has been turned off.
6025 * This function is similar to xmlGetProp except it will accept only
6026 * an attribute in no namespace.
6027 *
6028 * Returns the attribute value or NULL if not found.
6029 * It's up to the caller to free the memory with xmlFree().
6030 */
6031xmlChar *
6032xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6033 xmlAttrPtr prop;
6034 xmlDocPtr doc;
6035
6036 if ((node == NULL) || (name == NULL)) return(NULL);
6037 /*
6038 * Check on the properties attached to the node
6039 */
6040 prop = node->properties;
6041 while (prop != NULL) {
6042 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6043 xmlChar *ret;
6044
6045 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6046 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6047 return(ret);
6048 }
6049 prop = prop->next;
6050 }
6051 if (!xmlCheckDTD) return(NULL);
6052
6053 /*
6054 * Check if there is a default declaration in the internal
6055 * or external subsets
6056 */
6057 doc = node->doc;
6058 if (doc != NULL) {
6059 xmlAttributePtr attrDecl;
6060 if (doc->intSubset != NULL) {
6061 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6062 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6063 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006064 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6065 /* return attribute declaration only if a default value is given
6066 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006067 return(xmlStrdup(attrDecl->defaultValue));
6068 }
6069 }
6070 return(NULL);
6071}
6072
6073/**
Owen Taylor3473f882001-02-23 17:55:21 +00006074 * xmlGetNsProp:
6075 * @node: the node
6076 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006077 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006078 *
6079 * Search and get the value of an attribute associated to a node
6080 * This attribute has to be anchored in the namespace specified.
6081 * This does the entity substitution.
6082 * This function looks in DTD attribute declaration for #FIXED or
6083 * default declaration values unless DTD use has been turned off.
6084 *
6085 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006086 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006087 */
6088xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006089xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006090 xmlAttrPtr prop;
6091 xmlDocPtr doc;
6092 xmlNsPtr ns;
6093
6094 if (node == NULL)
6095 return(NULL);
6096
6097 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006098 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006099 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006100 while (prop != NULL) {
6101 /*
6102 * One need to have
6103 * - same attribute names
6104 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006105 */
6106 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006107 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006108 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006109 xmlChar *ret;
6110
6111 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6112 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6113 return(ret);
6114 }
6115 prop = prop->next;
6116 }
6117 if (!xmlCheckDTD) return(NULL);
6118
6119 /*
6120 * Check if there is a default declaration in the internal
6121 * or external subsets
6122 */
6123 doc = node->doc;
6124 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006125 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006126 xmlAttributePtr attrDecl;
6127
Owen Taylor3473f882001-02-23 17:55:21 +00006128 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6129 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6130 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6131
6132 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6133 /*
6134 * The DTD declaration only allows a prefix search
6135 */
6136 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006137 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006138 return(xmlStrdup(attrDecl->defaultValue));
6139 }
6140 }
6141 }
6142 return(NULL);
6143}
6144
Daniel Veillard2156d432004-03-04 15:59:36 +00006145#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6146/**
6147 * xmlUnsetProp:
6148 * @node: the node
6149 * @name: the attribute name
6150 *
6151 * Remove an attribute carried by a node.
6152 * Returns 0 if successful, -1 if not found
6153 */
6154int
6155xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
6156 xmlAttrPtr prop, prev = NULL;;
6157
6158 if ((node == NULL) || (name == NULL))
6159 return(-1);
6160 prop = node->properties;
6161 while (prop != NULL) {
6162 if ((xmlStrEqual(prop->name, name)) &&
6163 (prop->ns == NULL)) {
6164 if (prev == NULL)
6165 node->properties = prop->next;
6166 else
6167 prev->next = prop->next;
6168 xmlFreeProp(prop);
6169 return(0);
6170 }
6171 prev = prop;
6172 prop = prop->next;
6173 }
6174 return(-1);
6175}
6176
6177/**
6178 * xmlUnsetNsProp:
6179 * @node: the node
6180 * @ns: the namespace definition
6181 * @name: the attribute name
6182 *
6183 * Remove an attribute carried by a node.
6184 * Returns 0 if successful, -1 if not found
6185 */
6186int
6187xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6188 xmlAttrPtr prop = node->properties, prev = NULL;;
6189
6190 if ((node == NULL) || (name == NULL))
6191 return(-1);
6192 if (ns == NULL)
6193 return(xmlUnsetProp(node, name));
6194 if (ns->href == NULL)
6195 return(-1);
6196 while (prop != NULL) {
6197 if ((xmlStrEqual(prop->name, name)) &&
6198 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
6199 if (prev == NULL)
6200 node->properties = prop->next;
6201 else
6202 prev->next = prop->next;
6203 xmlFreeProp(prop);
6204 return(0);
6205 }
6206 prev = prop;
6207 prop = prop->next;
6208 }
6209 return(-1);
6210}
6211#endif
6212
6213#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006214/**
6215 * xmlSetProp:
6216 * @node: the node
6217 * @name: the attribute name
6218 * @value: the attribute value
6219 *
6220 * Set (or reset) an attribute carried by a node.
6221 * Returns the attribute pointer.
6222 */
6223xmlAttrPtr
6224xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006225 xmlAttrPtr prop;
6226 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006227
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006228 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006229 return(NULL);
6230 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006231 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006232 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006233 if ((xmlStrEqual(prop->name, name)) &&
6234 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006235 xmlNodePtr oldprop = prop->children;
6236
Owen Taylor3473f882001-02-23 17:55:21 +00006237 prop->children = NULL;
6238 prop->last = NULL;
6239 if (value != NULL) {
6240 xmlChar *buffer;
6241 xmlNodePtr tmp;
6242
6243 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6244 prop->children = xmlStringGetNodeList(node->doc, buffer);
6245 prop->last = NULL;
6246 prop->doc = doc;
6247 tmp = prop->children;
6248 while (tmp != NULL) {
6249 tmp->parent = (xmlNodePtr) prop;
6250 tmp->doc = doc;
6251 if (tmp->next == NULL)
6252 prop->last = tmp;
6253 tmp = tmp->next;
6254 }
6255 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006256 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006257 if (oldprop != NULL)
6258 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006259 return(prop);
6260 }
6261 prop = prop->next;
6262 }
6263 prop = xmlNewProp(node, name, value);
6264 return(prop);
6265}
6266
6267/**
6268 * xmlSetNsProp:
6269 * @node: the node
6270 * @ns: the namespace definition
6271 * @name: the attribute name
6272 * @value: the attribute value
6273 *
6274 * Set (or reset) an attribute carried by a node.
6275 * The ns structure must be in scope, this is not checked.
6276 *
6277 * Returns the attribute pointer.
6278 */
6279xmlAttrPtr
6280xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6281 const xmlChar *value) {
6282 xmlAttrPtr prop;
6283
6284 if ((node == NULL) || (name == NULL))
6285 return(NULL);
6286
6287 if (ns == NULL)
6288 return(xmlSetProp(node, name, value));
6289 if (ns->href == NULL)
6290 return(NULL);
6291 prop = node->properties;
6292
6293 while (prop != NULL) {
6294 /*
6295 * One need to have
6296 * - same attribute names
6297 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006298 */
6299 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006300 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006301 if (prop->children != NULL)
6302 xmlFreeNodeList(prop->children);
6303 prop->children = NULL;
6304 prop->last = NULL;
6305 prop->ns = ns;
6306 if (value != NULL) {
6307 xmlChar *buffer;
6308 xmlNodePtr tmp;
6309
6310 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6311 prop->children = xmlStringGetNodeList(node->doc, buffer);
6312 prop->last = NULL;
6313 tmp = prop->children;
6314 while (tmp != NULL) {
6315 tmp->parent = (xmlNodePtr) prop;
6316 if (tmp->next == NULL)
6317 prop->last = tmp;
6318 tmp = tmp->next;
6319 }
6320 xmlFree(buffer);
6321 }
6322 return(prop);
6323 }
6324 prop = prop->next;
6325 }
6326 prop = xmlNewNsProp(node, ns, name, value);
6327 return(prop);
6328}
6329
Daniel Veillard652327a2003-09-29 18:02:38 +00006330#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006331
6332/**
Owen Taylor3473f882001-02-23 17:55:21 +00006333 * xmlNodeIsText:
6334 * @node: the node
6335 *
6336 * Is this node a Text node ?
6337 * Returns 1 yes, 0 no
6338 */
6339int
6340xmlNodeIsText(xmlNodePtr node) {
6341 if (node == NULL) return(0);
6342
6343 if (node->type == XML_TEXT_NODE) return(1);
6344 return(0);
6345}
6346
6347/**
6348 * xmlIsBlankNode:
6349 * @node: the node
6350 *
6351 * Checks whether this node is an empty or whitespace only
6352 * (and possibly ignorable) text-node.
6353 *
6354 * Returns 1 yes, 0 no
6355 */
6356int
6357xmlIsBlankNode(xmlNodePtr node) {
6358 const xmlChar *cur;
6359 if (node == NULL) return(0);
6360
Daniel Veillard7db37732001-07-12 01:20:08 +00006361 if ((node->type != XML_TEXT_NODE) &&
6362 (node->type != XML_CDATA_SECTION_NODE))
6363 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006364 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006365 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006366 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006367 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006368 cur++;
6369 }
6370
6371 return(1);
6372}
6373
6374/**
6375 * xmlTextConcat:
6376 * @node: the node
6377 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006378 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006379 *
6380 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006381 *
6382 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006383 */
6384
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006385int
Owen Taylor3473f882001-02-23 17:55:21 +00006386xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006387 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006388
6389 if ((node->type != XML_TEXT_NODE) &&
6390 (node->type != XML_CDATA_SECTION_NODE)) {
6391#ifdef DEBUG_TREE
6392 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006393 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006394#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006395 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006396 }
William M. Brack7762bb12004-01-04 14:49:01 +00006397 /* need to check if content is currently in the dictionary */
6398 if ((node->doc != NULL) && (node->doc->dict != NULL) &&
6399 xmlDictOwns(node->doc->dict, node->content)) {
6400 node->content = xmlStrncatNew(node->content, content, len);
6401 } else {
6402 node->content = xmlStrncat(node->content, content, len);
6403 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006404 if (node->content == NULL)
6405 return(-1);
6406 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006407}
6408
6409/************************************************************************
6410 * *
6411 * Output : to a FILE or in memory *
6412 * *
6413 ************************************************************************/
6414
Owen Taylor3473f882001-02-23 17:55:21 +00006415/**
6416 * xmlBufferCreate:
6417 *
6418 * routine to create an XML buffer.
6419 * returns the new structure.
6420 */
6421xmlBufferPtr
6422xmlBufferCreate(void) {
6423 xmlBufferPtr ret;
6424
6425 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6426 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006427 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006428 return(NULL);
6429 }
6430 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006431 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006432 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006433 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006434 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006435 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006436 xmlFree(ret);
6437 return(NULL);
6438 }
6439 ret->content[0] = 0;
6440 return(ret);
6441}
6442
6443/**
6444 * xmlBufferCreateSize:
6445 * @size: initial size of buffer
6446 *
6447 * routine to create an XML buffer.
6448 * returns the new structure.
6449 */
6450xmlBufferPtr
6451xmlBufferCreateSize(size_t size) {
6452 xmlBufferPtr ret;
6453
6454 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6455 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006456 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006457 return(NULL);
6458 }
6459 ret->use = 0;
6460 ret->alloc = xmlBufferAllocScheme;
6461 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6462 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006463 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006464 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006465 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006466 xmlFree(ret);
6467 return(NULL);
6468 }
6469 ret->content[0] = 0;
6470 } else
6471 ret->content = NULL;
6472 return(ret);
6473}
6474
6475/**
Daniel Veillard53350552003-09-18 13:35:51 +00006476 * xmlBufferCreateStatic:
6477 * @mem: the memory area
6478 * @size: the size in byte
6479 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006480 * routine to create an XML buffer from an immutable memory area.
6481 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006482 * present until the end of the buffer lifetime.
6483 *
6484 * returns the new structure.
6485 */
6486xmlBufferPtr
6487xmlBufferCreateStatic(void *mem, size_t size) {
6488 xmlBufferPtr ret;
6489
6490 if ((mem == NULL) || (size == 0))
6491 return(NULL);
6492
6493 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6494 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006495 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006496 return(NULL);
6497 }
6498 ret->use = size;
6499 ret->size = size;
6500 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6501 ret->content = (xmlChar *) mem;
6502 return(ret);
6503}
6504
6505/**
Owen Taylor3473f882001-02-23 17:55:21 +00006506 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006507 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006508 * @scheme: allocation scheme to use
6509 *
6510 * Sets the allocation scheme for this buffer
6511 */
6512void
6513xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6514 xmlBufferAllocationScheme scheme) {
6515 if (buf == NULL) {
6516#ifdef DEBUG_BUFFER
6517 xmlGenericError(xmlGenericErrorContext,
6518 "xmlBufferSetAllocationScheme: buf == NULL\n");
6519#endif
6520 return;
6521 }
Daniel Veillard53350552003-09-18 13:35:51 +00006522 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006523
6524 buf->alloc = scheme;
6525}
6526
6527/**
6528 * xmlBufferFree:
6529 * @buf: the buffer to free
6530 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006531 * Frees an XML buffer. It frees both the content and the structure which
6532 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006533 */
6534void
6535xmlBufferFree(xmlBufferPtr buf) {
6536 if (buf == NULL) {
6537#ifdef DEBUG_BUFFER
6538 xmlGenericError(xmlGenericErrorContext,
6539 "xmlBufferFree: buf == NULL\n");
6540#endif
6541 return;
6542 }
Daniel Veillard53350552003-09-18 13:35:51 +00006543
6544 if ((buf->content != NULL) &&
6545 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006546 xmlFree(buf->content);
6547 }
Owen Taylor3473f882001-02-23 17:55:21 +00006548 xmlFree(buf);
6549}
6550
6551/**
6552 * xmlBufferEmpty:
6553 * @buf: the buffer
6554 *
6555 * empty a buffer.
6556 */
6557void
6558xmlBufferEmpty(xmlBufferPtr buf) {
6559 if (buf->content == NULL) return;
6560 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006561 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006562 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006563 } else {
6564 memset(buf->content, 0, buf->size);
6565 }
Owen Taylor3473f882001-02-23 17:55:21 +00006566}
6567
6568/**
6569 * xmlBufferShrink:
6570 * @buf: the buffer to dump
6571 * @len: the number of xmlChar to remove
6572 *
6573 * Remove the beginning of an XML buffer.
6574 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006575 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006576 */
6577int
6578xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6579 if (len == 0) return(0);
6580 if (len > buf->use) return(-1);
6581
6582 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006583 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6584 buf->content += len;
6585 } else {
6586 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6587 buf->content[buf->use] = 0;
6588 }
Owen Taylor3473f882001-02-23 17:55:21 +00006589 return(len);
6590}
6591
6592/**
6593 * xmlBufferGrow:
6594 * @buf: the buffer
6595 * @len: the minimum free size to allocate
6596 *
6597 * Grow the available space of an XML buffer.
6598 *
6599 * Returns the new available space or -1 in case of error
6600 */
6601int
6602xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6603 int size;
6604 xmlChar *newbuf;
6605
Daniel Veillard53350552003-09-18 13:35:51 +00006606 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006607 if (len + buf->use < buf->size) return(0);
6608
William M. Brack30fe43f2004-07-26 18:00:58 +00006609/*
6610 * Windows has a BIG problem on realloc timing, so we try to double
6611 * the buffer size (if that's enough) (bug 146697)
6612 */
6613#ifdef WIN32
6614 if (buf->size > len)
6615 size = buf->size * 2;
6616 else
6617 size = buf->use + len + 100;
6618#else
Owen Taylor3473f882001-02-23 17:55:21 +00006619 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00006620#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006621
6622 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006623 if (newbuf == NULL) {
6624 xmlTreeErrMemory("growing buffer");
6625 return(-1);
6626 }
Owen Taylor3473f882001-02-23 17:55:21 +00006627 buf->content = newbuf;
6628 buf->size = size;
6629 return(buf->size - buf->use);
6630}
6631
6632/**
6633 * xmlBufferDump:
6634 * @file: the file output
6635 * @buf: the buffer to dump
6636 *
6637 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006638 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006639 */
6640int
6641xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6642 int ret;
6643
6644 if (buf == NULL) {
6645#ifdef DEBUG_BUFFER
6646 xmlGenericError(xmlGenericErrorContext,
6647 "xmlBufferDump: buf == NULL\n");
6648#endif
6649 return(0);
6650 }
6651 if (buf->content == NULL) {
6652#ifdef DEBUG_BUFFER
6653 xmlGenericError(xmlGenericErrorContext,
6654 "xmlBufferDump: buf->content == NULL\n");
6655#endif
6656 return(0);
6657 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006658 if (file == NULL)
6659 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006660 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6661 return(ret);
6662}
6663
6664/**
6665 * xmlBufferContent:
6666 * @buf: the buffer
6667 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006668 * Function to extract the content of a buffer
6669 *
Owen Taylor3473f882001-02-23 17:55:21 +00006670 * Returns the internal content
6671 */
6672
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006673const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006674xmlBufferContent(const xmlBufferPtr buf)
6675{
6676 if(!buf)
6677 return NULL;
6678
6679 return buf->content;
6680}
6681
6682/**
6683 * xmlBufferLength:
6684 * @buf: the buffer
6685 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006686 * Function to get the length of a buffer
6687 *
Owen Taylor3473f882001-02-23 17:55:21 +00006688 * Returns the length of data in the internal content
6689 */
6690
6691int
6692xmlBufferLength(const xmlBufferPtr buf)
6693{
6694 if(!buf)
6695 return 0;
6696
6697 return buf->use;
6698}
6699
6700/**
6701 * xmlBufferResize:
6702 * @buf: the buffer to resize
6703 * @size: the desired size
6704 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006705 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006706 *
6707 * Returns 0 in case of problems, 1 otherwise
6708 */
6709int
6710xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6711{
6712 unsigned int newSize;
6713 xmlChar* rebuf = NULL;
6714
Daniel Veillard53350552003-09-18 13:35:51 +00006715 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6716
Owen Taylor3473f882001-02-23 17:55:21 +00006717 /* Don't resize if we don't have to */
6718 if (size < buf->size)
6719 return 1;
6720
6721 /* figure out new size */
6722 switch (buf->alloc){
6723 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillardbf629492004-04-20 22:20:59 +00006724 /*take care of empty case*/
6725 newSize = (buf->size ? buf->size*2 : size + 10);
Owen Taylor3473f882001-02-23 17:55:21 +00006726 while (size > newSize) newSize *= 2;
6727 break;
6728 case XML_BUFFER_ALLOC_EXACT:
6729 newSize = size+10;
6730 break;
6731 default:
6732 newSize = size+10;
6733 break;
6734 }
6735
6736 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006737 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006738 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006739 rebuf = (xmlChar *) xmlRealloc(buf->content,
6740 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006741 } else {
6742 /*
6743 * if we are reallocating a buffer far from being full, it's
6744 * better to make a new allocation and copy only the used range
6745 * and free the old one.
6746 */
6747 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6748 if (rebuf != NULL) {
6749 memcpy(rebuf, buf->content, buf->use);
6750 xmlFree(buf->content);
William M. Brack42331a92004-07-29 07:07:16 +00006751 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006752 }
6753 }
Owen Taylor3473f882001-02-23 17:55:21 +00006754 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006755 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006756 return 0;
6757 }
6758 buf->content = rebuf;
6759 buf->size = newSize;
6760
6761 return 1;
6762}
6763
6764/**
6765 * xmlBufferAdd:
6766 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006767 * @str: the #xmlChar string
6768 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006769 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006770 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006771 * str is recomputed.
6772 */
6773void
6774xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6775 unsigned int needSize;
6776
6777 if (str == NULL) {
6778#ifdef DEBUG_BUFFER
6779 xmlGenericError(xmlGenericErrorContext,
6780 "xmlBufferAdd: str == NULL\n");
6781#endif
6782 return;
6783 }
Daniel Veillard53350552003-09-18 13:35:51 +00006784 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006785 if (len < -1) {
6786#ifdef DEBUG_BUFFER
6787 xmlGenericError(xmlGenericErrorContext,
6788 "xmlBufferAdd: len < 0\n");
6789#endif
6790 return;
6791 }
6792 if (len == 0) return;
6793
6794 if (len < 0)
6795 len = xmlStrlen(str);
6796
6797 if (len <= 0) return;
6798
6799 needSize = buf->use + len + 2;
6800 if (needSize > buf->size){
6801 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006802 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006803 return;
6804 }
6805 }
6806
6807 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6808 buf->use += len;
6809 buf->content[buf->use] = 0;
6810}
6811
6812/**
6813 * xmlBufferAddHead:
6814 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006815 * @str: the #xmlChar string
6816 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006817 *
6818 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006819 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00006820 */
6821void
6822xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6823 unsigned int needSize;
6824
Daniel Veillard53350552003-09-18 13:35:51 +00006825 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006826 if (str == NULL) {
6827#ifdef DEBUG_BUFFER
6828 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006829 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006830#endif
6831 return;
6832 }
6833 if (len < -1) {
6834#ifdef DEBUG_BUFFER
6835 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006836 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006837#endif
6838 return;
6839 }
6840 if (len == 0) return;
6841
6842 if (len < 0)
6843 len = xmlStrlen(str);
6844
6845 if (len <= 0) return;
6846
6847 needSize = buf->use + len + 2;
6848 if (needSize > buf->size){
6849 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006850 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006851 return;
6852 }
6853 }
6854
6855 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6856 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6857 buf->use += len;
6858 buf->content[buf->use] = 0;
6859}
6860
6861/**
6862 * xmlBufferCat:
6863 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006864 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006865 *
6866 * Append a zero terminated string to an XML buffer.
6867 */
6868void
6869xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillard53350552003-09-18 13:35:51 +00006870 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006871 if (str != NULL)
6872 xmlBufferAdd(buf, str, -1);
6873}
6874
6875/**
6876 * xmlBufferCCat:
6877 * @buf: the buffer to dump
6878 * @str: the C char string
6879 *
6880 * Append a zero terminated C string to an XML buffer.
6881 */
6882void
6883xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6884 const char *cur;
6885
Daniel Veillard53350552003-09-18 13:35:51 +00006886 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006887 if (str == NULL) {
6888#ifdef DEBUG_BUFFER
6889 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006890 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006891#endif
6892 return;
6893 }
6894 for (cur = str;*cur != 0;cur++) {
6895 if (buf->use + 10 >= buf->size) {
6896 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006897 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006898 return;
6899 }
6900 }
6901 buf->content[buf->use++] = *cur;
6902 }
6903 buf->content[buf->use] = 0;
6904}
6905
6906/**
6907 * xmlBufferWriteCHAR:
6908 * @buf: the XML buffer
6909 * @string: the string to add
6910 *
6911 * routine which manages and grows an output buffer. This one adds
6912 * xmlChars at the end of the buffer.
6913 */
6914void
Daniel Veillard53350552003-09-18 13:35:51 +00006915xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
6916 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006917 xmlBufferCat(buf, string);
6918}
6919
6920/**
6921 * xmlBufferWriteChar:
6922 * @buf: the XML buffer output
6923 * @string: the string to add
6924 *
6925 * routine which manage and grows an output buffer. This one add
6926 * C chars at the end of the array.
6927 */
6928void
6929xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillard53350552003-09-18 13:35:51 +00006930 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006931 xmlBufferCCat(buf, string);
6932}
6933
6934
6935/**
6936 * xmlBufferWriteQuotedString:
6937 * @buf: the XML buffer output
6938 * @string: the string to add
6939 *
6940 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006941 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006942 * quote or double-quotes internally
6943 */
6944void
6945xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00006946 const xmlChar *cur, *base;
Daniel Veillard53350552003-09-18 13:35:51 +00006947 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00006948 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00006949 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00006950#ifdef DEBUG_BUFFER
6951 xmlGenericError(xmlGenericErrorContext,
6952 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6953#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00006954 xmlBufferCCat(buf, "\"");
6955 base = cur = string;
6956 while(*cur != 0){
6957 if(*cur == '"'){
6958 if (base != cur)
6959 xmlBufferAdd(buf, base, cur - base);
6960 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6961 cur++;
6962 base = cur;
6963 }
6964 else {
6965 cur++;
6966 }
6967 }
6968 if (base != cur)
6969 xmlBufferAdd(buf, base, cur - base);
6970 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006971 }
Daniel Veillard39057f42003-08-04 01:33:43 +00006972 else{
6973 xmlBufferCCat(buf, "\'");
6974 xmlBufferCat(buf, string);
6975 xmlBufferCCat(buf, "\'");
6976 }
Owen Taylor3473f882001-02-23 17:55:21 +00006977 } else {
6978 xmlBufferCCat(buf, "\"");
6979 xmlBufferCat(buf, string);
6980 xmlBufferCCat(buf, "\"");
6981 }
6982}
6983
6984
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00006985/**
6986 * xmlGetDocCompressMode:
6987 * @doc: the document
6988 *
6989 * get the compression ratio for a document, ZLIB based
6990 * Returns 0 (uncompressed) to 9 (max compression)
6991 */
6992int
6993xmlGetDocCompressMode (xmlDocPtr doc) {
6994 if (doc == NULL) return(-1);
6995 return(doc->compression);
6996}
6997
6998/**
6999 * xmlSetDocCompressMode:
7000 * @doc: the document
7001 * @mode: the compression ratio
7002 *
7003 * set the compression ratio for a document, ZLIB based
7004 * Correct values: 0 (uncompressed) to 9 (max compression)
7005 */
7006void
7007xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7008 if (doc == NULL) return;
7009 if (mode < 0) doc->compression = 0;
7010 else if (mode > 9) doc->compression = 9;
7011 else doc->compression = mode;
7012}
7013
7014/**
7015 * xmlGetCompressMode:
7016 *
7017 * get the default compression mode used, ZLIB based.
7018 * Returns 0 (uncompressed) to 9 (max compression)
7019 */
7020int
7021xmlGetCompressMode(void)
7022{
7023 return (xmlCompressMode);
7024}
7025
7026/**
7027 * xmlSetCompressMode:
7028 * @mode: the compression ratio
7029 *
7030 * set the default compression mode used, ZLIB based
7031 * Correct values: 0 (uncompressed) to 9 (max compression)
7032 */
7033void
7034xmlSetCompressMode(int mode) {
7035 if (mode < 0) xmlCompressMode = 0;
7036 else if (mode > 9) xmlCompressMode = 9;
7037 else xmlCompressMode = mode;
7038}
7039