blob: 4d18cffd447fb82d189b428dd2af5348af47d4b0 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
Daniel Veillardd5c2f922002-11-21 14:10:52 +00004 * References:
5 * XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
6 *
Owen Taylor3473f882001-02-23 17:55:21 +00007 * See Copyright for the status of this software.
8 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00009 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000010 *
Owen Taylor3473f882001-02-23 17:55:21 +000011 */
12
Daniel Veillard34ce8be2002-03-18 19:37:11 +000013#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000014#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000015
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24#ifdef HAVE_ZLIB_H
25#include <zlib.h>
26#endif
27
28#include <libxml/xmlmemory.h>
29#include <libxml/tree.h>
30#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000031#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000032#include <libxml/entities.h>
33#include <libxml/valid.h>
34#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000035#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000036#include <libxml/globals.h>
Daniel Veillardd5c2f922002-11-21 14:10:52 +000037#ifdef LIBXML_HTML_ENABLED
38#include <libxml/HTMLtree.h>
39#endif
Owen Taylor3473f882001-02-23 17:55:21 +000040
Daniel Veillarda880b122003-04-21 21:36:41 +000041int __xmlRegisterCallbacks = 0;
42
Daniel Veillard56a4cb82001-03-24 17:00:36 +000043xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
44
45/************************************************************************
46 * *
Daniel Veillard18ec16e2003-10-07 23:16:40 +000047 * Tree memory error handler *
48 * *
49 ************************************************************************/
50/**
51 * xmlTreeErrMemory:
52 * @extra: extra informations
53 *
54 * Handle an out of memory condition
55 */
56static void
57xmlTreeErrMemory(const char *extra)
58{
59 __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
60}
61
62/**
63 * xmlTreeErr:
64 * @code: the error number
65 * @extra: extra informations
66 *
67 * Handle an out of memory condition
68 */
69static void
70xmlTreeErr(int code, xmlNodePtr node, const char *extra)
71{
72 const char *msg = NULL;
73
74 switch(code) {
75 case XML_TREE_INVALID_HEX:
76 msg = "invalid hexadecimal character value";
77 break;
78 case XML_TREE_INVALID_DEC:
79 msg = "invalid decimal character value";
80 break;
81 case XML_TREE_UNTERMINATED_ENTITY:
82 msg = "unterminated entity reference %15s";
83 break;
84 default:
85 msg = "unexpected error number";
86 }
87 __xmlSimpleError(XML_FROM_TREE, code, node, msg, extra);
88}
89
90/************************************************************************
91 * *
Daniel Veillard56a4cb82001-03-24 17:00:36 +000092 * A few static variables and macros *
93 * *
94 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000095/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000096const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000097/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000098const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000099 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +0000100/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +0000101const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
102
Owen Taylor3473f882001-02-23 17:55:21 +0000103static int xmlCompressMode = 0;
104static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000105
Owen Taylor3473f882001-02-23 17:55:21 +0000106#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
107 xmlNodePtr ulccur = (n)->children; \
108 if (ulccur == NULL) { \
109 (n)->last = NULL; \
110 } else { \
111 while (ulccur->next != NULL) { \
112 ulccur->parent = (n); \
113 ulccur = ulccur->next; \
114 } \
115 ulccur->parent = (n); \
116 (n)->last = ulccur; \
117}}
118
119/* #define DEBUG_BUFFER */
120/* #define DEBUG_TREE */
121
122/************************************************************************
123 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000124 * Functions to move to entities.c once the *
125 * API freeze is smoothen and they can be made public. *
126 * *
127 ************************************************************************/
128#include <libxml/hash.h>
129
Daniel Veillard652327a2003-09-29 18:02:38 +0000130#ifdef LIBXML_TREE_ENABLED
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000131/**
132 * xmlGetEntityFromDtd:
133 * @dtd: A pointer to the DTD to search
134 * @name: The entity name
135 *
136 * Do an entity lookup in the DTD entity hash table and
137 * return the corresponding entity, if found.
138 *
139 * Returns A pointer to the entity structure or NULL if not found.
140 */
141static xmlEntityPtr
142xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
143 xmlEntitiesTablePtr table;
144
145 if((dtd != NULL) && (dtd->entities != NULL)) {
146 table = (xmlEntitiesTablePtr) dtd->entities;
147 return((xmlEntityPtr) xmlHashLookup(table, name));
148 /* return(xmlGetEntityFromTable(table, name)); */
149 }
150 return(NULL);
151}
152/**
153 * xmlGetParameterEntityFromDtd:
154 * @dtd: A pointer to the DTD to search
155 * @name: The entity name
156 *
157 * Do an entity lookup in the DTD pararmeter entity hash table and
158 * return the corresponding entity, if found.
159 *
160 * Returns A pointer to the entity structure or NULL if not found.
161 */
162static xmlEntityPtr
163xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
164 xmlEntitiesTablePtr table;
165
166 if ((dtd != NULL) && (dtd->pentities != NULL)) {
167 table = (xmlEntitiesTablePtr) dtd->pentities;
168 return((xmlEntityPtr) xmlHashLookup(table, name));
169 /* return(xmlGetEntityFromTable(table, name)); */
170 }
171 return(NULL);
172}
Daniel Veillard652327a2003-09-29 18:02:38 +0000173#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000174
175/************************************************************************
176 * *
Daniel Veillardc00cda82003-04-07 10:22:39 +0000177 * QName handling helper *
178 * *
179 ************************************************************************/
180
181/**
182 * xmlBuildQName:
183 * @ncname: the Name
184 * @prefix: the prefix
185 * @memory: preallocated memory
186 * @len: preallocated memory length
187 *
188 * Builds the QName @prefix:@ncname in @memory if there is enough space
189 * and prefix is not NULL nor empty, otherwise allocate a new string.
190 * If prefix is NULL or empty it returns ncname.
191 *
192 * Returns the new string which must be freed by the caller if different from
193 * @memory and @ncname or NULL in case of error
194 */
195xmlChar *
196xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
197 xmlChar *memory, int len) {
198 int lenn, lenp;
199 xmlChar *ret;
200
Daniel Veillard3b7840c2003-09-11 23:42:01 +0000201 if (ncname == NULL) return(NULL);
202 if (prefix == NULL) return((xmlChar *) ncname);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000203
204 lenn = strlen((char *) ncname);
205 lenp = strlen((char *) prefix);
206
207 if ((memory == NULL) || (len < lenn + lenp + 2)) {
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000208 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000209 if (ret == NULL) {
210 xmlTreeErrMemory("building QName");
211 return(NULL);
212 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000213 } else {
214 ret = memory;
215 }
216 memcpy(&ret[0], prefix, lenp);
217 ret[lenp] = ':';
218 memcpy(&ret[lenp + 1], ncname, lenn);
219 ret[lenn + lenp + 1] = 0;
220 return(ret);
221}
222
223/**
224 * xmlSplitQName2:
225 * @name: the full QName
226 * @prefix: a xmlChar **
227 *
228 * parse an XML qualified name string
229 *
230 * [NS 5] QName ::= (Prefix ':')? LocalPart
231 *
232 * [NS 6] Prefix ::= NCName
233 *
234 * [NS 7] LocalPart ::= NCName
235 *
236 * Returns NULL if not a QName, otherwise the local part, and prefix
237 * is updated to get the Prefix if any.
238 */
239
240xmlChar *
241xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
242 int len = 0;
243 xmlChar *ret = NULL;
244
245 *prefix = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000246 if (name == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000247
248#ifndef XML_XML_NAMESPACE
249 /* xml: prefix is not really a namespace */
250 if ((name[0] == 'x') && (name[1] == 'm') &&
251 (name[2] == 'l') && (name[3] == ':'))
252 return(NULL);
253#endif
254
255 /* nasty but valid */
256 if (name[0] == ':')
257 return(NULL);
258
259 /*
260 * we are not trying to validate but just to cut, and yes it will
261 * work even if this is as set of UTF-8 encoded chars
262 */
263 while ((name[len] != 0) && (name[len] != ':'))
264 len++;
265
266 if (name[len] == 0)
267 return(NULL);
268
269 *prefix = xmlStrndup(name, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000270 if (*prefix == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000271 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000272 return(NULL);
273 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000274 ret = xmlStrdup(&name[len + 1]);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000275 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000276 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000277 if (*prefix != NULL) {
278 xmlFree(*prefix);
279 *prefix = NULL;
280 }
281 return(NULL);
282 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000283
284 return(ret);
285}
286
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000287/**
288 * xmlSplitQName3:
289 * @name: the full QName
290 * @len: an int *
291 *
292 * parse an XML qualified name string,i
293 *
294 * returns NULL if it is not a Qualified Name, otherwise, update len
295 * with the lenght in byte of the prefix and return a pointer
296 */
297
298const xmlChar *
299xmlSplitQName3(const xmlChar *name, int *len) {
300 int l = 0;
301
302 if (name == NULL) return(NULL);
303 if (len == NULL) return(NULL);
304
305 /* nasty but valid */
306 if (name[0] == ':')
307 return(NULL);
308
309 /*
310 * we are not trying to validate but just to cut, and yes it will
311 * work even if this is as set of UTF-8 encoded chars
312 */
313 while ((name[l] != 0) && (name[l] != ':'))
314 l++;
315
316 if (name[l] == 0)
317 return(NULL);
318
319 *len = l;
320
321 return(&name[l+1]);
322}
323
Daniel Veillardc00cda82003-04-07 10:22:39 +0000324/************************************************************************
325 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000326 * Check Name, NCName and QName strings *
327 * *
328 ************************************************************************/
329
330#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
331
Daniel Veillard2156d432004-03-04 15:59:36 +0000332#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000333/**
334 * xmlValidateNCName:
335 * @value: the value to check
336 * @space: allow spaces in front and end of the string
337 *
338 * Check that a value conforms to the lexical space of NCName
339 *
340 * Returns 0 if this validates, a positive error code number otherwise
341 * and -1 in case of internal or API error.
342 */
343int
344xmlValidateNCName(const xmlChar *value, int space) {
345 const xmlChar *cur = value;
346 int c,l;
347
348 /*
349 * First quick algorithm for ASCII range
350 */
351 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000352 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000353 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
354 (*cur == '_'))
355 cur++;
356 else
357 goto try_complex;
358 while (((*cur >= 'a') && (*cur <= 'z')) ||
359 ((*cur >= 'A') && (*cur <= 'Z')) ||
360 ((*cur >= '0') && (*cur <= '9')) ||
361 (*cur == '_') || (*cur == '-') || (*cur == '.'))
362 cur++;
363 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000364 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000365 if (*cur == 0)
366 return(0);
367
368try_complex:
369 /*
370 * Second check for chars outside the ASCII range
371 */
372 cur = value;
373 c = CUR_SCHAR(cur, l);
374 if (space) {
375 while (IS_BLANK(c)) {
376 cur += l;
377 c = CUR_SCHAR(cur, l);
378 }
379 }
William M. Brack871611b2003-10-18 04:53:14 +0000380 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000381 return(1);
382 cur += l;
383 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000384 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
385 (c == '-') || (c == '_') || IS_COMBINING(c) ||
386 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000387 cur += l;
388 c = CUR_SCHAR(cur, l);
389 }
390 if (space) {
391 while (IS_BLANK(c)) {
392 cur += l;
393 c = CUR_SCHAR(cur, l);
394 }
395 }
396 if (c != 0)
397 return(1);
398
399 return(0);
400}
Daniel Veillard2156d432004-03-04 15:59:36 +0000401#endif
Daniel Veillardd2298792003-02-14 16:54:11 +0000402
Daniel Veillard2156d432004-03-04 15:59:36 +0000403#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000404/**
405 * xmlValidateQName:
406 * @value: the value to check
407 * @space: allow spaces in front and end of the string
408 *
409 * Check that a value conforms to the lexical space of QName
410 *
411 * Returns 0 if this validates, a positive error code number otherwise
412 * and -1 in case of internal or API error.
413 */
414int
415xmlValidateQName(const xmlChar *value, int space) {
416 const xmlChar *cur = value;
417 int c,l;
418
419 /*
420 * First quick algorithm for ASCII range
421 */
422 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000423 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000424 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
425 (*cur == '_'))
426 cur++;
427 else
428 goto try_complex;
429 while (((*cur >= 'a') && (*cur <= 'z')) ||
430 ((*cur >= 'A') && (*cur <= 'Z')) ||
431 ((*cur >= '0') && (*cur <= '9')) ||
432 (*cur == '_') || (*cur == '-') || (*cur == '.'))
433 cur++;
434 if (*cur == ':') {
435 cur++;
436 if (((*cur >= 'a') && (*cur <= 'z')) ||
437 ((*cur >= 'A') && (*cur <= 'Z')) ||
438 (*cur == '_'))
439 cur++;
440 else
441 goto try_complex;
442 while (((*cur >= 'a') && (*cur <= 'z')) ||
443 ((*cur >= 'A') && (*cur <= 'Z')) ||
444 ((*cur >= '0') && (*cur <= '9')) ||
445 (*cur == '_') || (*cur == '-') || (*cur == '.'))
446 cur++;
447 }
448 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000449 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000450 if (*cur == 0)
451 return(0);
452
453try_complex:
454 /*
455 * Second check for chars outside the ASCII range
456 */
457 cur = value;
458 c = CUR_SCHAR(cur, l);
459 if (space) {
460 while (IS_BLANK(c)) {
461 cur += l;
462 c = CUR_SCHAR(cur, l);
463 }
464 }
William M. Brack871611b2003-10-18 04:53:14 +0000465 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000466 return(1);
467 cur += l;
468 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000469 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
470 (c == '-') || (c == '_') || IS_COMBINING(c) ||
471 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000472 cur += l;
473 c = CUR_SCHAR(cur, l);
474 }
475 if (c == ':') {
476 cur += l;
477 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000478 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000479 return(1);
480 cur += l;
481 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000482 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
483 (c == '-') || (c == '_') || IS_COMBINING(c) ||
484 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000485 cur += l;
486 c = CUR_SCHAR(cur, l);
487 }
488 }
489 if (space) {
490 while (IS_BLANK(c)) {
491 cur += l;
492 c = CUR_SCHAR(cur, l);
493 }
494 }
495 if (c != 0)
496 return(1);
497 return(0);
498}
499
500/**
501 * xmlValidateName:
502 * @value: the value to check
503 * @space: allow spaces in front and end of the string
504 *
505 * Check that a value conforms to the lexical space of Name
506 *
507 * Returns 0 if this validates, a positive error code number otherwise
508 * and -1 in case of internal or API error.
509 */
510int
511xmlValidateName(const xmlChar *value, int space) {
512 const xmlChar *cur = value;
513 int c,l;
514
515 /*
516 * First quick algorithm for ASCII range
517 */
518 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000519 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000520 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
521 (*cur == '_') || (*cur == ':'))
522 cur++;
523 else
524 goto try_complex;
525 while (((*cur >= 'a') && (*cur <= 'z')) ||
526 ((*cur >= 'A') && (*cur <= 'Z')) ||
527 ((*cur >= '0') && (*cur <= '9')) ||
528 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
529 cur++;
530 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000531 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000532 if (*cur == 0)
533 return(0);
534
535try_complex:
536 /*
537 * Second check for chars outside the ASCII range
538 */
539 cur = value;
540 c = CUR_SCHAR(cur, l);
541 if (space) {
542 while (IS_BLANK(c)) {
543 cur += l;
544 c = CUR_SCHAR(cur, l);
545 }
546 }
William M. Brack871611b2003-10-18 04:53:14 +0000547 if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000548 return(1);
549 cur += l;
550 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000551 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
552 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000553 cur += l;
554 c = CUR_SCHAR(cur, l);
555 }
556 if (space) {
557 while (IS_BLANK(c)) {
558 cur += l;
559 c = CUR_SCHAR(cur, l);
560 }
561 }
562 if (c != 0)
563 return(1);
564 return(0);
565}
566
Daniel Veillardd4310742003-02-18 21:12:46 +0000567/**
568 * xmlValidateNMToken:
569 * @value: the value to check
570 * @space: allow spaces in front and end of the string
571 *
572 * Check that a value conforms to the lexical space of NMToken
573 *
574 * Returns 0 if this validates, a positive error code number otherwise
575 * and -1 in case of internal or API error.
576 */
577int
578xmlValidateNMToken(const xmlChar *value, int space) {
579 const xmlChar *cur = value;
580 int c,l;
581
582 /*
583 * First quick algorithm for ASCII range
584 */
585 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000586 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000587 if (((*cur >= 'a') && (*cur <= 'z')) ||
588 ((*cur >= 'A') && (*cur <= 'Z')) ||
589 ((*cur >= '0') && (*cur <= '9')) ||
590 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
591 cur++;
592 else
593 goto try_complex;
594 while (((*cur >= 'a') && (*cur <= 'z')) ||
595 ((*cur >= 'A') && (*cur <= 'Z')) ||
596 ((*cur >= '0') && (*cur <= '9')) ||
597 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
598 cur++;
599 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000600 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000601 if (*cur == 0)
602 return(0);
603
604try_complex:
605 /*
606 * Second check for chars outside the ASCII range
607 */
608 cur = value;
609 c = CUR_SCHAR(cur, l);
610 if (space) {
611 while (IS_BLANK(c)) {
612 cur += l;
613 c = CUR_SCHAR(cur, l);
614 }
615 }
William M. Brack871611b2003-10-18 04:53:14 +0000616 if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
617 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
Daniel Veillardd4310742003-02-18 21:12:46 +0000618 return(1);
619 cur += l;
620 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000621 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
622 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd4310742003-02-18 21:12:46 +0000623 cur += l;
624 c = CUR_SCHAR(cur, l);
625 }
626 if (space) {
627 while (IS_BLANK(c)) {
628 cur += l;
629 c = CUR_SCHAR(cur, l);
630 }
631 }
632 if (c != 0)
633 return(1);
634 return(0);
635}
Daniel Veillard652327a2003-09-29 18:02:38 +0000636#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardd4310742003-02-18 21:12:46 +0000637
Daniel Veillardd2298792003-02-14 16:54:11 +0000638/************************************************************************
639 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000640 * Allocation and deallocation of basic structures *
641 * *
642 ************************************************************************/
643
644/**
645 * xmlSetBufferAllocationScheme:
646 * @scheme: allocation method to use
647 *
648 * Set the buffer allocation method. Types are
649 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
650 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
651 * improves performance
652 */
653void
654xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
655 xmlBufferAllocScheme = scheme;
656}
657
658/**
659 * xmlGetBufferAllocationScheme:
660 *
661 * Types are
662 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
663 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
664 * improves performance
665 *
666 * Returns the current allocation scheme
667 */
668xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000669xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000670 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000671}
672
673/**
674 * xmlNewNs:
675 * @node: the element carrying the namespace
676 * @href: the URI associated
677 * @prefix: the prefix for the namespace
678 *
679 * Creation of a new Namespace. This function will refuse to create
680 * a namespace with a similar prefix than an existing one present on this
681 * node.
682 * We use href==NULL in the case of an element creation where the namespace
683 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000684 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000685 */
686xmlNsPtr
687xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
688 xmlNsPtr cur;
689
690 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
691 return(NULL);
692
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000693 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
694 return(NULL);
695
Owen Taylor3473f882001-02-23 17:55:21 +0000696 /*
697 * Allocate a new Namespace and fill the fields.
698 */
699 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
700 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000701 xmlTreeErrMemory("building namespace");
Owen Taylor3473f882001-02-23 17:55:21 +0000702 return(NULL);
703 }
704 memset(cur, 0, sizeof(xmlNs));
705 cur->type = XML_LOCAL_NAMESPACE;
706
707 if (href != NULL)
708 cur->href = xmlStrdup(href);
709 if (prefix != NULL)
710 cur->prefix = xmlStrdup(prefix);
711
712 /*
713 * Add it at the end to preserve parsing order ...
714 * and checks for existing use of the prefix
715 */
716 if (node != NULL) {
717 if (node->nsDef == NULL) {
718 node->nsDef = cur;
719 } else {
720 xmlNsPtr prev = node->nsDef;
721
722 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
723 (xmlStrEqual(prev->prefix, cur->prefix))) {
724 xmlFreeNs(cur);
725 return(NULL);
726 }
727 while (prev->next != NULL) {
728 prev = prev->next;
729 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
730 (xmlStrEqual(prev->prefix, cur->prefix))) {
731 xmlFreeNs(cur);
732 return(NULL);
733 }
734 }
735 prev->next = cur;
736 }
737 }
738 return(cur);
739}
740
741/**
742 * xmlSetNs:
743 * @node: a node in the document
744 * @ns: a namespace pointer
745 *
746 * Associate a namespace to a node, a posteriori.
747 */
748void
749xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
750 if (node == NULL) {
751#ifdef DEBUG_TREE
752 xmlGenericError(xmlGenericErrorContext,
753 "xmlSetNs: node == NULL\n");
754#endif
755 return;
756 }
757 node->ns = ns;
758}
759
760/**
761 * xmlFreeNs:
762 * @cur: the namespace pointer
763 *
764 * Free up the structures associated to a namespace
765 */
766void
767xmlFreeNs(xmlNsPtr cur) {
768 if (cur == NULL) {
769#ifdef DEBUG_TREE
770 xmlGenericError(xmlGenericErrorContext,
771 "xmlFreeNs : ns == NULL\n");
772#endif
773 return;
774 }
775 if (cur->href != NULL) xmlFree((char *) cur->href);
776 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000777 xmlFree(cur);
778}
779
780/**
781 * xmlFreeNsList:
782 * @cur: the first namespace pointer
783 *
784 * Free up all the structures associated to the chained namespaces.
785 */
786void
787xmlFreeNsList(xmlNsPtr cur) {
788 xmlNsPtr next;
789 if (cur == NULL) {
790#ifdef DEBUG_TREE
791 xmlGenericError(xmlGenericErrorContext,
792 "xmlFreeNsList : ns == NULL\n");
793#endif
794 return;
795 }
796 while (cur != NULL) {
797 next = cur->next;
798 xmlFreeNs(cur);
799 cur = next;
800 }
801}
802
803/**
804 * xmlNewDtd:
805 * @doc: the document pointer
806 * @name: the DTD name
807 * @ExternalID: the external ID
808 * @SystemID: the system ID
809 *
810 * Creation of a new DTD for the external subset. To create an
811 * internal subset, use xmlCreateIntSubset().
812 *
813 * Returns a pointer to the new DTD structure
814 */
815xmlDtdPtr
816xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
817 const xmlChar *ExternalID, const xmlChar *SystemID) {
818 xmlDtdPtr cur;
819
820 if ((doc != NULL) && (doc->extSubset != NULL)) {
821#ifdef DEBUG_TREE
822 xmlGenericError(xmlGenericErrorContext,
823 "xmlNewDtd(%s): document %s already have a DTD %s\n",
824 /* !!! */ (char *) name, doc->name,
825 /* !!! */ (char *)doc->extSubset->name);
826#endif
827 return(NULL);
828 }
829
830 /*
831 * Allocate a new DTD and fill the fields.
832 */
833 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
834 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000835 xmlTreeErrMemory("building DTD");
Owen Taylor3473f882001-02-23 17:55:21 +0000836 return(NULL);
837 }
838 memset(cur, 0 , sizeof(xmlDtd));
839 cur->type = XML_DTD_NODE;
840
841 if (name != NULL)
842 cur->name = xmlStrdup(name);
843 if (ExternalID != NULL)
844 cur->ExternalID = xmlStrdup(ExternalID);
845 if (SystemID != NULL)
846 cur->SystemID = xmlStrdup(SystemID);
847 if (doc != NULL)
848 doc->extSubset = cur;
849 cur->doc = doc;
850
Daniel Veillarda880b122003-04-21 21:36:41 +0000851 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000852 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000853 return(cur);
854}
855
856/**
857 * xmlGetIntSubset:
858 * @doc: the document pointer
859 *
860 * Get the internal subset of a document
861 * Returns a pointer to the DTD structure or NULL if not found
862 */
863
864xmlDtdPtr
865xmlGetIntSubset(xmlDocPtr doc) {
866 xmlNodePtr cur;
867
868 if (doc == NULL)
869 return(NULL);
870 cur = doc->children;
871 while (cur != NULL) {
872 if (cur->type == XML_DTD_NODE)
873 return((xmlDtdPtr) cur);
874 cur = cur->next;
875 }
876 return((xmlDtdPtr) doc->intSubset);
877}
878
879/**
880 * xmlCreateIntSubset:
881 * @doc: the document pointer
882 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000883 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000884 * @SystemID: the system ID
885 *
886 * Create the internal subset of a document
887 * Returns a pointer to the new DTD structure
888 */
889xmlDtdPtr
890xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
891 const xmlChar *ExternalID, const xmlChar *SystemID) {
892 xmlDtdPtr cur;
893
894 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
895#ifdef DEBUG_TREE
896 xmlGenericError(xmlGenericErrorContext,
897
898 "xmlCreateIntSubset(): document %s already have an internal subset\n",
899 doc->name);
900#endif
901 return(NULL);
902 }
903
904 /*
905 * Allocate a new DTD and fill the fields.
906 */
907 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
908 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000909 xmlTreeErrMemory("building internal subset");
Owen Taylor3473f882001-02-23 17:55:21 +0000910 return(NULL);
911 }
912 memset(cur, 0, sizeof(xmlDtd));
913 cur->type = XML_DTD_NODE;
914
915 if (name != NULL)
916 cur->name = xmlStrdup(name);
917 if (ExternalID != NULL)
918 cur->ExternalID = xmlStrdup(ExternalID);
919 if (SystemID != NULL)
920 cur->SystemID = xmlStrdup(SystemID);
921 if (doc != NULL) {
922 doc->intSubset = cur;
923 cur->parent = doc;
924 cur->doc = doc;
925 if (doc->children == NULL) {
926 doc->children = (xmlNodePtr) cur;
927 doc->last = (xmlNodePtr) cur;
928 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000929 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000930 xmlNodePtr prev;
931
Owen Taylor3473f882001-02-23 17:55:21 +0000932 prev = doc->children;
933 prev->prev = (xmlNodePtr) cur;
934 cur->next = prev;
935 doc->children = (xmlNodePtr) cur;
936 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000937 xmlNodePtr next;
938
939 next = doc->children;
940 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
941 next = next->next;
942 if (next == NULL) {
943 cur->prev = doc->last;
944 cur->prev->next = (xmlNodePtr) cur;
945 cur->next = NULL;
946 doc->last = (xmlNodePtr) cur;
947 } else {
948 cur->next = next;
949 cur->prev = next->prev;
950 if (cur->prev == NULL)
951 doc->children = (xmlNodePtr) cur;
952 else
953 cur->prev->next = (xmlNodePtr) cur;
954 next->prev = (xmlNodePtr) cur;
955 }
Owen Taylor3473f882001-02-23 17:55:21 +0000956 }
957 }
958 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000959
Daniel Veillarda880b122003-04-21 21:36:41 +0000960 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000961 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000962 return(cur);
963}
964
965/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000966 * DICT_FREE:
967 * @str: a string
968 *
969 * Free a string if it is not owned by the "dict" dictionnary in the
970 * current scope
971 */
972#define DICT_FREE(str) \
973 if ((str) && ((!dict) || \
974 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
975 xmlFree((char *)(str));
976
977/**
Owen Taylor3473f882001-02-23 17:55:21 +0000978 * xmlFreeDtd:
979 * @cur: the DTD structure to free up
980 *
981 * Free a DTD structure.
982 */
983void
984xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000985 xmlDictPtr dict = NULL;
986
Owen Taylor3473f882001-02-23 17:55:21 +0000987 if (cur == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000988 return;
989 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000990 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +0000991
Daniel Veillarda880b122003-04-21 21:36:41 +0000992 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000993 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
994
Owen Taylor3473f882001-02-23 17:55:21 +0000995 if (cur->children != NULL) {
996 xmlNodePtr next, c = cur->children;
997
998 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000999 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001000 * indexes.
1001 */
1002 while (c != NULL) {
1003 next = c->next;
Daniel Veillardd72c7e32003-05-12 21:55:03 +00001004 if ((c->type == XML_COMMENT_NODE) || (c->type == XML_PI_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001005 xmlUnlinkNode(c);
1006 xmlFreeNode(c);
1007 }
1008 c = next;
1009 }
1010 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001011 DICT_FREE(cur->name)
1012 DICT_FREE(cur->SystemID)
1013 DICT_FREE(cur->ExternalID)
Owen Taylor3473f882001-02-23 17:55:21 +00001014 /* TODO !!! */
1015 if (cur->notations != NULL)
1016 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1017
1018 if (cur->elements != NULL)
1019 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1020 if (cur->attributes != NULL)
1021 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1022 if (cur->entities != NULL)
1023 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1024 if (cur->pentities != NULL)
1025 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1026
Owen Taylor3473f882001-02-23 17:55:21 +00001027 xmlFree(cur);
1028}
1029
1030/**
1031 * xmlNewDoc:
1032 * @version: xmlChar string giving the version of XML "1.0"
1033 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001034 * Creates a new XML document
1035 *
Owen Taylor3473f882001-02-23 17:55:21 +00001036 * Returns a new document
1037 */
1038xmlDocPtr
1039xmlNewDoc(const xmlChar *version) {
1040 xmlDocPtr cur;
1041
1042 if (version == NULL)
1043 version = (const xmlChar *) "1.0";
1044
1045 /*
1046 * Allocate a new document and fill the fields.
1047 */
1048 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1049 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001050 xmlTreeErrMemory("building doc");
Owen Taylor3473f882001-02-23 17:55:21 +00001051 return(NULL);
1052 }
1053 memset(cur, 0, sizeof(xmlDoc));
1054 cur->type = XML_DOCUMENT_NODE;
1055
1056 cur->version = xmlStrdup(version);
1057 cur->standalone = -1;
1058 cur->compression = -1; /* not initialized */
1059 cur->doc = cur;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001060 /*
1061 * The in memory encoding is always UTF8
1062 * This field will never change and would
1063 * be obsolete if not for binary compatibility.
1064 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001065 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001066
Daniel Veillarda880b122003-04-21 21:36:41 +00001067 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001068 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001069 return(cur);
1070}
1071
1072/**
1073 * xmlFreeDoc:
1074 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001075 *
1076 * Free up all the structures used by a document, tree included.
1077 */
1078void
1079xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001080 xmlDtdPtr extSubset, intSubset;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001081 xmlDictPtr dict = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001082
Owen Taylor3473f882001-02-23 17:55:21 +00001083 if (cur == NULL) {
1084#ifdef DEBUG_TREE
1085 xmlGenericError(xmlGenericErrorContext,
1086 "xmlFreeDoc : document == NULL\n");
1087#endif
1088 return;
1089 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001090 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001091
Daniel Veillarda880b122003-04-21 21:36:41 +00001092 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001093 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1094
Daniel Veillard76d66f42001-05-16 21:05:17 +00001095 /*
1096 * Do this before freeing the children list to avoid ID lookups
1097 */
1098 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1099 cur->ids = NULL;
1100 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1101 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001102 extSubset = cur->extSubset;
1103 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001104 if (intSubset == extSubset)
1105 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001106 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001107 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001108 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001109 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001110 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001111 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001112 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001113 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001114 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001115 }
1116
1117 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001118 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001119
1120 DICT_FREE(cur->version)
1121 DICT_FREE(cur->name)
1122 DICT_FREE(cur->encoding)
1123 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001124 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001125 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001126}
1127
1128/**
1129 * xmlStringLenGetNodeList:
1130 * @doc: the document
1131 * @value: the value of the text
1132 * @len: the length of the string value
1133 *
1134 * Parse the value string and build the node list associated. Should
1135 * produce a flat tree with only TEXTs and ENTITY_REFs.
1136 * Returns a pointer to the first child
1137 */
1138xmlNodePtr
1139xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1140 xmlNodePtr ret = NULL, last = NULL;
1141 xmlNodePtr node;
1142 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001143 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001144 const xmlChar *q;
1145 xmlEntityPtr ent;
1146
1147 if (value == NULL) return(NULL);
1148
1149 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001150 while ((cur < end) && (*cur != 0)) {
1151 if (cur[0] == '&') {
1152 int charval = 0;
1153 xmlChar tmp;
1154
Owen Taylor3473f882001-02-23 17:55:21 +00001155 /*
1156 * Save the current text.
1157 */
1158 if (cur != q) {
1159 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1160 xmlNodeAddContentLen(last, q, cur - q);
1161 } else {
1162 node = xmlNewDocTextLen(doc, q, cur - q);
1163 if (node == NULL) return(ret);
1164 if (last == NULL)
1165 last = ret = node;
1166 else {
1167 last->next = node;
1168 node->prev = last;
1169 last = node;
1170 }
1171 }
1172 }
Owen Taylor3473f882001-02-23 17:55:21 +00001173 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001174 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1175 cur += 3;
1176 if (cur < end)
1177 tmp = *cur;
1178 else
1179 tmp = 0;
1180 while (tmp != ';') { /* Non input consuming loop */
1181 if ((tmp >= '0') && (tmp <= '9'))
1182 charval = charval * 16 + (tmp - '0');
1183 else if ((tmp >= 'a') && (tmp <= 'f'))
1184 charval = charval * 16 + (tmp - 'a') + 10;
1185 else if ((tmp >= 'A') && (tmp <= 'F'))
1186 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001187 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001188 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1189 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001190 charval = 0;
1191 break;
1192 }
1193 cur++;
1194 if (cur < end)
1195 tmp = *cur;
1196 else
1197 tmp = 0;
1198 }
1199 if (tmp == ';')
1200 cur++;
1201 q = cur;
1202 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1203 cur += 2;
1204 if (cur < end)
1205 tmp = *cur;
1206 else
1207 tmp = 0;
1208 while (tmp != ';') { /* Non input consuming loops */
1209 if ((tmp >= '0') && (tmp <= '9'))
1210 charval = charval * 10 + (tmp - '0');
1211 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001212 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1213 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001214 charval = 0;
1215 break;
1216 }
1217 cur++;
1218 if (cur < end)
1219 tmp = *cur;
1220 else
1221 tmp = 0;
1222 }
1223 if (tmp == ';')
1224 cur++;
1225 q = cur;
1226 } else {
1227 /*
1228 * Read the entity string
1229 */
1230 cur++;
1231 q = cur;
1232 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1233 if ((cur >= end) || (*cur == 0)) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001234 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1235 (const char *) q);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001236 return(ret);
1237 }
1238 if (cur != q) {
1239 /*
1240 * Predefined entities don't generate nodes
1241 */
1242 val = xmlStrndup(q, cur - q);
1243 ent = xmlGetDocEntity(doc, val);
1244 if ((ent != NULL) &&
1245 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1246 if (last == NULL) {
1247 node = xmlNewDocText(doc, ent->content);
1248 last = ret = node;
1249 } else if (last->type != XML_TEXT_NODE) {
1250 node = xmlNewDocText(doc, ent->content);
1251 last = xmlAddNextSibling(last, node);
1252 } else
1253 xmlNodeAddContent(last, ent->content);
1254
1255 } else {
1256 /*
1257 * Create a new REFERENCE_REF node
1258 */
1259 node = xmlNewReference(doc, val);
1260 if (node == NULL) {
1261 if (val != NULL) xmlFree(val);
1262 return(ret);
1263 }
1264 else if ((ent != NULL) && (ent->children == NULL)) {
1265 xmlNodePtr temp;
1266
1267 ent->children = xmlStringGetNodeList(doc,
1268 (const xmlChar*)node->content);
1269 ent->owner = 1;
1270 temp = ent->children;
1271 while (temp) {
1272 temp->parent = (xmlNodePtr)ent;
1273 temp = temp->next;
1274 }
1275 }
1276 if (last == NULL) {
1277 last = ret = node;
1278 } else {
1279 last = xmlAddNextSibling(last, node);
1280 }
1281 }
1282 xmlFree(val);
1283 }
1284 cur++;
1285 q = cur;
1286 }
1287 if (charval != 0) {
1288 xmlChar buf[10];
1289 int l;
1290
1291 l = xmlCopyCharMultiByte(buf, charval);
1292 buf[l] = 0;
1293 node = xmlNewDocText(doc, buf);
1294 if (node != NULL) {
1295 if (last == NULL) {
1296 last = ret = node;
1297 } else {
1298 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001299 }
1300 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001301 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001302 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001303 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001304 cur++;
1305 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001306 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001307 /*
1308 * Handle the last piece of text.
1309 */
1310 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1311 xmlNodeAddContentLen(last, q, cur - q);
1312 } else {
1313 node = xmlNewDocTextLen(doc, q, cur - q);
1314 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001315 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001316 last = ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001317 } else {
1318 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001319 }
1320 }
1321 }
1322 return(ret);
1323}
1324
1325/**
1326 * xmlStringGetNodeList:
1327 * @doc: the document
1328 * @value: the value of the attribute
1329 *
1330 * Parse the value string and build the node list associated. Should
1331 * produce a flat tree with only TEXTs and ENTITY_REFs.
1332 * Returns a pointer to the first child
1333 */
1334xmlNodePtr
1335xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1336 xmlNodePtr ret = NULL, last = NULL;
1337 xmlNodePtr node;
1338 xmlChar *val;
1339 const xmlChar *cur = value;
1340 const xmlChar *q;
1341 xmlEntityPtr ent;
1342
1343 if (value == NULL) return(NULL);
1344
1345 q = cur;
1346 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001347 if (cur[0] == '&') {
1348 int charval = 0;
1349 xmlChar tmp;
1350
Owen Taylor3473f882001-02-23 17:55:21 +00001351 /*
1352 * Save the current text.
1353 */
1354 if (cur != q) {
1355 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1356 xmlNodeAddContentLen(last, q, cur - q);
1357 } else {
1358 node = xmlNewDocTextLen(doc, q, cur - q);
1359 if (node == NULL) return(ret);
1360 if (last == NULL)
1361 last = ret = node;
1362 else {
1363 last->next = node;
1364 node->prev = last;
1365 last = node;
1366 }
1367 }
1368 }
Owen Taylor3473f882001-02-23 17:55:21 +00001369 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001370 if ((cur[1] == '#') && (cur[2] == 'x')) {
1371 cur += 3;
1372 tmp = *cur;
1373 while (tmp != ';') { /* Non input consuming loop */
1374 if ((tmp >= '0') && (tmp <= '9'))
1375 charval = charval * 16 + (tmp - '0');
1376 else if ((tmp >= 'a') && (tmp <= 'f'))
1377 charval = charval * 16 + (tmp - 'a') + 10;
1378 else if ((tmp >= 'A') && (tmp <= 'F'))
1379 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001380 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001381 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1382 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001383 charval = 0;
1384 break;
1385 }
1386 cur++;
1387 tmp = *cur;
1388 }
1389 if (tmp == ';')
1390 cur++;
1391 q = cur;
1392 } else if (cur[1] == '#') {
1393 cur += 2;
1394 tmp = *cur;
1395 while (tmp != ';') { /* Non input consuming loops */
1396 if ((tmp >= '0') && (tmp <= '9'))
1397 charval = charval * 10 + (tmp - '0');
1398 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001399 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1400 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001401 charval = 0;
1402 break;
1403 }
1404 cur++;
1405 tmp = *cur;
1406 }
1407 if (tmp == ';')
1408 cur++;
1409 q = cur;
1410 } else {
1411 /*
1412 * Read the entity string
1413 */
1414 cur++;
1415 q = cur;
1416 while ((*cur != 0) && (*cur != ';')) cur++;
1417 if (*cur == 0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001418 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1419 (xmlNodePtr) doc, (const char *) q);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001420 return(ret);
1421 }
1422 if (cur != q) {
1423 /*
1424 * Predefined entities don't generate nodes
1425 */
1426 val = xmlStrndup(q, cur - q);
1427 ent = xmlGetDocEntity(doc, val);
1428 if ((ent != NULL) &&
1429 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1430 if (last == NULL) {
1431 node = xmlNewDocText(doc, ent->content);
1432 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001433 } else if (last->type != XML_TEXT_NODE) {
1434 node = xmlNewDocText(doc, ent->content);
1435 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001436 } else
1437 xmlNodeAddContent(last, ent->content);
1438
1439 } else {
1440 /*
1441 * Create a new REFERENCE_REF node
1442 */
1443 node = xmlNewReference(doc, val);
1444 if (node == NULL) {
1445 if (val != NULL) xmlFree(val);
1446 return(ret);
1447 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001448 else if ((ent != NULL) && (ent->children == NULL)) {
1449 xmlNodePtr temp;
1450
1451 ent->children = xmlStringGetNodeList(doc,
1452 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001453 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001454 temp = ent->children;
1455 while (temp) {
1456 temp->parent = (xmlNodePtr)ent;
1457 temp = temp->next;
1458 }
1459 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001460 if (last == NULL) {
1461 last = ret = node;
1462 } else {
1463 last = xmlAddNextSibling(last, node);
1464 }
1465 }
1466 xmlFree(val);
1467 }
1468 cur++;
1469 q = cur;
1470 }
1471 if (charval != 0) {
1472 xmlChar buf[10];
1473 int len;
1474
1475 len = xmlCopyCharMultiByte(buf, charval);
1476 buf[len] = 0;
1477 node = xmlNewDocText(doc, buf);
1478 if (node != NULL) {
1479 if (last == NULL) {
1480 last = ret = node;
1481 } else {
1482 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001483 }
1484 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001485
1486 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001487 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001488 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001489 cur++;
1490 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001491 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001492 /*
1493 * Handle the last piece of text.
1494 */
1495 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1496 xmlNodeAddContentLen(last, q, cur - q);
1497 } else {
1498 node = xmlNewDocTextLen(doc, q, cur - q);
1499 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001500 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001501 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001502 } else {
1503 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001504 }
1505 }
1506 }
1507 return(ret);
1508}
1509
1510/**
1511 * xmlNodeListGetString:
1512 * @doc: the document
1513 * @list: a Node list
1514 * @inLine: should we replace entity contents or show their external form
1515 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001516 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001517 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001518 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001519 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001520 */
1521xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001522xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1523{
Owen Taylor3473f882001-02-23 17:55:21 +00001524 xmlNodePtr node = list;
1525 xmlChar *ret = NULL;
1526 xmlEntityPtr ent;
1527
Daniel Veillard7646b182002-04-20 06:41:40 +00001528 if (list == NULL)
1529 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001530
1531 while (node != NULL) {
1532 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001533 (node->type == XML_CDATA_SECTION_NODE)) {
1534 if (inLine) {
1535 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001536 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001537 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001538
Daniel Veillard7646b182002-04-20 06:41:40 +00001539 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1540 if (buffer != NULL) {
1541 ret = xmlStrcat(ret, buffer);
1542 xmlFree(buffer);
1543 }
1544 }
1545 } else if (node->type == XML_ENTITY_REF_NODE) {
1546 if (inLine) {
1547 ent = xmlGetDocEntity(doc, node->name);
1548 if (ent != NULL) {
1549 xmlChar *buffer;
1550
1551 /* an entity content can be any "well balanced chunk",
1552 * i.e. the result of the content [43] production:
1553 * http://www.w3.org/TR/REC-xml#NT-content.
1554 * So it can contain text, CDATA section or nested
1555 * entity reference nodes (among others).
1556 * -> we recursive call xmlNodeListGetString()
1557 * which handles these types */
1558 buffer = xmlNodeListGetString(doc, ent->children, 1);
1559 if (buffer != NULL) {
1560 ret = xmlStrcat(ret, buffer);
1561 xmlFree(buffer);
1562 }
1563 } else {
1564 ret = xmlStrcat(ret, node->content);
1565 }
1566 } else {
1567 xmlChar buf[2];
1568
1569 buf[0] = '&';
1570 buf[1] = 0;
1571 ret = xmlStrncat(ret, buf, 1);
1572 ret = xmlStrcat(ret, node->name);
1573 buf[0] = ';';
1574 buf[1] = 0;
1575 ret = xmlStrncat(ret, buf, 1);
1576 }
1577 }
1578#if 0
1579 else {
1580 xmlGenericError(xmlGenericErrorContext,
1581 "xmlGetNodeListString : invalid node type %d\n",
1582 node->type);
1583 }
1584#endif
1585 node = node->next;
1586 }
1587 return (ret);
1588}
Daniel Veillard652327a2003-09-29 18:02:38 +00001589
1590#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001591/**
1592 * xmlNodeListGetRawString:
1593 * @doc: the document
1594 * @list: a Node list
1595 * @inLine: should we replace entity contents or show their external form
1596 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001597 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001598 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1599 * this function doesn't do any character encoding handling.
1600 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001601 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001602 */
1603xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001604xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1605{
Owen Taylor3473f882001-02-23 17:55:21 +00001606 xmlNodePtr node = list;
1607 xmlChar *ret = NULL;
1608 xmlEntityPtr ent;
1609
Daniel Veillard7646b182002-04-20 06:41:40 +00001610 if (list == NULL)
1611 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001612
1613 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001614 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001615 (node->type == XML_CDATA_SECTION_NODE)) {
1616 if (inLine) {
1617 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001618 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001619 xmlChar *buffer;
1620
1621 buffer = xmlEncodeSpecialChars(doc, node->content);
1622 if (buffer != NULL) {
1623 ret = xmlStrcat(ret, buffer);
1624 xmlFree(buffer);
1625 }
1626 }
1627 } else if (node->type == XML_ENTITY_REF_NODE) {
1628 if (inLine) {
1629 ent = xmlGetDocEntity(doc, node->name);
1630 if (ent != NULL) {
1631 xmlChar *buffer;
1632
1633 /* an entity content can be any "well balanced chunk",
1634 * i.e. the result of the content [43] production:
1635 * http://www.w3.org/TR/REC-xml#NT-content.
1636 * So it can contain text, CDATA section or nested
1637 * entity reference nodes (among others).
1638 * -> we recursive call xmlNodeListGetRawString()
1639 * which handles these types */
1640 buffer =
1641 xmlNodeListGetRawString(doc, ent->children, 1);
1642 if (buffer != NULL) {
1643 ret = xmlStrcat(ret, buffer);
1644 xmlFree(buffer);
1645 }
1646 } else {
1647 ret = xmlStrcat(ret, node->content);
1648 }
1649 } else {
1650 xmlChar buf[2];
1651
1652 buf[0] = '&';
1653 buf[1] = 0;
1654 ret = xmlStrncat(ret, buf, 1);
1655 ret = xmlStrcat(ret, node->name);
1656 buf[0] = ';';
1657 buf[1] = 0;
1658 ret = xmlStrncat(ret, buf, 1);
1659 }
1660 }
Owen Taylor3473f882001-02-23 17:55:21 +00001661#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001662 else {
1663 xmlGenericError(xmlGenericErrorContext,
1664 "xmlGetNodeListString : invalid node type %d\n",
1665 node->type);
1666 }
Owen Taylor3473f882001-02-23 17:55:21 +00001667#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001668 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001669 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001670 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001671}
Daniel Veillard652327a2003-09-29 18:02:38 +00001672#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001673
Daniel Veillard2156d432004-03-04 15:59:36 +00001674#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00001675/**
1676 * xmlNewProp:
1677 * @node: the holding node
1678 * @name: the name of the attribute
1679 * @value: the value of the attribute
1680 *
1681 * Create a new property carried by a node.
1682 * Returns a pointer to the attribute
1683 */
1684xmlAttrPtr
1685xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1686 xmlAttrPtr cur;
1687 xmlDocPtr doc = NULL;
1688
1689 if (name == NULL) {
1690#ifdef DEBUG_TREE
1691 xmlGenericError(xmlGenericErrorContext,
1692 "xmlNewProp : name == NULL\n");
1693#endif
1694 return(NULL);
1695 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001696 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1697 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001698
1699 /*
1700 * Allocate a new property and fill the fields.
1701 */
1702 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1703 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001704 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001705 return(NULL);
1706 }
1707 memset(cur, 0, sizeof(xmlAttr));
1708 cur->type = XML_ATTRIBUTE_NODE;
1709
1710 cur->parent = node;
1711 if (node != NULL) {
1712 doc = node->doc;
1713 cur->doc = doc;
1714 }
1715 cur->name = xmlStrdup(name);
1716 if (value != NULL) {
1717 xmlChar *buffer;
1718 xmlNodePtr tmp;
1719
1720 buffer = xmlEncodeEntitiesReentrant(doc, value);
1721 cur->children = xmlStringGetNodeList(doc, buffer);
1722 cur->last = NULL;
1723 tmp = cur->children;
1724 while (tmp != NULL) {
1725 tmp->parent = (xmlNodePtr) cur;
1726 tmp->doc = doc;
1727 if (tmp->next == NULL)
1728 cur->last = tmp;
1729 tmp = tmp->next;
1730 }
1731 xmlFree(buffer);
1732 }
1733
1734 /*
1735 * Add it at the end to preserve parsing order ...
1736 */
1737 if (node != NULL) {
1738 if (node->properties == NULL) {
1739 node->properties = cur;
1740 } else {
1741 xmlAttrPtr prev = node->properties;
1742
1743 while (prev->next != NULL) prev = prev->next;
1744 prev->next = cur;
1745 cur->prev = prev;
1746 }
1747 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001748
Daniel Veillarda880b122003-04-21 21:36:41 +00001749 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001750 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001751 return(cur);
1752}
Daniel Veillard652327a2003-09-29 18:02:38 +00001753#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001754
1755/**
1756 * xmlNewNsProp:
1757 * @node: the holding node
1758 * @ns: the namespace
1759 * @name: the name of the attribute
1760 * @value: the value of the attribute
1761 *
1762 * Create a new property tagged with a namespace and carried by a node.
1763 * Returns a pointer to the attribute
1764 */
1765xmlAttrPtr
1766xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1767 const xmlChar *value) {
1768 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001769 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001770
1771 if (name == NULL) {
1772#ifdef DEBUG_TREE
1773 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001774 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001775#endif
1776 return(NULL);
1777 }
1778
1779 /*
1780 * Allocate a new property and fill the fields.
1781 */
1782 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1783 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001784 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001785 return(NULL);
1786 }
1787 memset(cur, 0, sizeof(xmlAttr));
1788 cur->type = XML_ATTRIBUTE_NODE;
1789
1790 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001791 if (node != NULL) {
1792 doc = node->doc;
1793 cur->doc = doc;
1794 }
Owen Taylor3473f882001-02-23 17:55:21 +00001795 cur->ns = ns;
1796 cur->name = xmlStrdup(name);
1797 if (value != NULL) {
1798 xmlChar *buffer;
1799 xmlNodePtr tmp;
1800
Daniel Veillarda682b212001-06-07 19:59:42 +00001801 buffer = xmlEncodeEntitiesReentrant(doc, value);
1802 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001803 cur->last = NULL;
1804 tmp = cur->children;
1805 while (tmp != NULL) {
1806 tmp->parent = (xmlNodePtr) cur;
1807 if (tmp->next == NULL)
1808 cur->last = tmp;
1809 tmp = tmp->next;
1810 }
1811 xmlFree(buffer);
1812 }
1813
1814 /*
1815 * Add it at the end to preserve parsing order ...
1816 */
1817 if (node != NULL) {
1818 if (node->properties == NULL) {
1819 node->properties = cur;
1820 } else {
1821 xmlAttrPtr prev = node->properties;
1822
1823 while (prev->next != NULL) prev = prev->next;
1824 prev->next = cur;
1825 cur->prev = prev;
1826 }
1827 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001828
Daniel Veillarda880b122003-04-21 21:36:41 +00001829 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001830 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001831 return(cur);
1832}
1833
1834/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001835 * xmlNewNsPropEatName:
1836 * @node: the holding node
1837 * @ns: the namespace
1838 * @name: the name of the attribute
1839 * @value: the value of the attribute
1840 *
1841 * Create a new property tagged with a namespace and carried by a node.
1842 * Returns a pointer to the attribute
1843 */
1844xmlAttrPtr
1845xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1846 const xmlChar *value) {
1847 xmlAttrPtr cur;
1848 xmlDocPtr doc = NULL;
1849
1850 if (name == NULL) {
1851#ifdef DEBUG_TREE
1852 xmlGenericError(xmlGenericErrorContext,
1853 "xmlNewNsPropEatName : name == NULL\n");
1854#endif
1855 return(NULL);
1856 }
1857
1858 /*
1859 * Allocate a new property and fill the fields.
1860 */
1861 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1862 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001863 xmlTreeErrMemory("building attribute");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001864 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001865 return(NULL);
1866 }
1867 memset(cur, 0, sizeof(xmlAttr));
1868 cur->type = XML_ATTRIBUTE_NODE;
1869
1870 cur->parent = node;
1871 if (node != NULL) {
1872 doc = node->doc;
1873 cur->doc = doc;
1874 }
1875 cur->ns = ns;
1876 cur->name = name;
1877 if (value != NULL) {
1878 xmlChar *buffer;
1879 xmlNodePtr tmp;
1880
1881 buffer = xmlEncodeEntitiesReentrant(doc, value);
1882 cur->children = xmlStringGetNodeList(doc, buffer);
1883 cur->last = NULL;
1884 tmp = cur->children;
1885 while (tmp != NULL) {
1886 tmp->parent = (xmlNodePtr) cur;
1887 if (tmp->next == NULL)
1888 cur->last = tmp;
1889 tmp = tmp->next;
1890 }
1891 xmlFree(buffer);
1892 }
1893
1894 /*
1895 * Add it at the end to preserve parsing order ...
1896 */
1897 if (node != NULL) {
1898 if (node->properties == NULL) {
1899 node->properties = cur;
1900 } else {
1901 xmlAttrPtr prev = node->properties;
1902
1903 while (prev->next != NULL) prev = prev->next;
1904 prev->next = cur;
1905 cur->prev = prev;
1906 }
1907 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001908
Daniel Veillarda880b122003-04-21 21:36:41 +00001909 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001910 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001911 return(cur);
1912}
1913
1914/**
Owen Taylor3473f882001-02-23 17:55:21 +00001915 * xmlNewDocProp:
1916 * @doc: the document
1917 * @name: the name of the attribute
1918 * @value: the value of the attribute
1919 *
1920 * Create a new property carried by a document.
1921 * Returns a pointer to the attribute
1922 */
1923xmlAttrPtr
1924xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1925 xmlAttrPtr cur;
1926
1927 if (name == NULL) {
1928#ifdef DEBUG_TREE
1929 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001930 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001931#endif
1932 return(NULL);
1933 }
1934
1935 /*
1936 * Allocate a new property and fill the fields.
1937 */
1938 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1939 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001940 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001941 return(NULL);
1942 }
1943 memset(cur, 0, sizeof(xmlAttr));
1944 cur->type = XML_ATTRIBUTE_NODE;
1945
1946 cur->name = xmlStrdup(name);
1947 cur->doc = doc;
1948 if (value != NULL) {
1949 xmlNodePtr tmp;
1950
1951 cur->children = xmlStringGetNodeList(doc, value);
1952 cur->last = NULL;
1953
1954 tmp = cur->children;
1955 while (tmp != NULL) {
1956 tmp->parent = (xmlNodePtr) cur;
1957 if (tmp->next == NULL)
1958 cur->last = tmp;
1959 tmp = tmp->next;
1960 }
1961 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001962
Daniel Veillarda880b122003-04-21 21:36:41 +00001963 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001964 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001965 return(cur);
1966}
1967
1968/**
1969 * xmlFreePropList:
1970 * @cur: the first property in the list
1971 *
1972 * Free a property and all its siblings, all the children are freed too.
1973 */
1974void
1975xmlFreePropList(xmlAttrPtr cur) {
1976 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001977 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001978 while (cur != NULL) {
1979 next = cur->next;
1980 xmlFreeProp(cur);
1981 cur = next;
1982 }
1983}
1984
1985/**
1986 * xmlFreeProp:
1987 * @cur: an attribute
1988 *
1989 * Free one attribute, all the content is freed too
1990 */
1991void
1992xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001993 xmlDictPtr dict = NULL;
1994 if (cur == NULL) return;
1995
1996 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001997
Daniel Veillarda880b122003-04-21 21:36:41 +00001998 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001999 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
2000
Owen Taylor3473f882001-02-23 17:55:21 +00002001 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00002002 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
2003 ((cur->parent->doc->intSubset != NULL) ||
2004 (cur->parent->doc->extSubset != NULL))) {
2005 if (xmlIsID(cur->parent->doc, cur->parent, cur))
2006 xmlRemoveID(cur->parent->doc, cur);
2007 }
Owen Taylor3473f882001-02-23 17:55:21 +00002008 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002009 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002010 xmlFree(cur);
2011}
2012
Daniel Veillard652327a2003-09-29 18:02:38 +00002013#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002014/**
2015 * xmlRemoveProp:
2016 * @cur: an attribute
2017 *
2018 * Unlink and free one attribute, all the content is freed too
2019 * Note this doesn't work for namespace definition attributes
2020 *
2021 * Returns 0 if success and -1 in case of error.
2022 */
2023int
2024xmlRemoveProp(xmlAttrPtr cur) {
2025 xmlAttrPtr tmp;
2026 if (cur == NULL) {
2027#ifdef DEBUG_TREE
2028 xmlGenericError(xmlGenericErrorContext,
2029 "xmlRemoveProp : cur == NULL\n");
2030#endif
2031 return(-1);
2032 }
2033 if (cur->parent == NULL) {
2034#ifdef DEBUG_TREE
2035 xmlGenericError(xmlGenericErrorContext,
2036 "xmlRemoveProp : cur->parent == NULL\n");
2037#endif
2038 return(-1);
2039 }
2040 tmp = cur->parent->properties;
2041 if (tmp == cur) {
2042 cur->parent->properties = cur->next;
2043 xmlFreeProp(cur);
2044 return(0);
2045 }
2046 while (tmp != NULL) {
2047 if (tmp->next == cur) {
2048 tmp->next = cur->next;
2049 if (tmp->next != NULL)
2050 tmp->next->prev = tmp;
2051 xmlFreeProp(cur);
2052 return(0);
2053 }
2054 tmp = tmp->next;
2055 }
2056#ifdef DEBUG_TREE
2057 xmlGenericError(xmlGenericErrorContext,
2058 "xmlRemoveProp : attribute not owned by its node\n");
2059#endif
2060 return(-1);
2061}
Daniel Veillard652327a2003-09-29 18:02:38 +00002062#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002063
2064/**
2065 * xmlNewPI:
2066 * @name: the processing instruction name
2067 * @content: the PI content
2068 *
2069 * Creation of a processing instruction element.
2070 * Returns a pointer to the new node object.
2071 */
2072xmlNodePtr
2073xmlNewPI(const xmlChar *name, const xmlChar *content) {
2074 xmlNodePtr cur;
2075
2076 if (name == NULL) {
2077#ifdef DEBUG_TREE
2078 xmlGenericError(xmlGenericErrorContext,
2079 "xmlNewPI : name == NULL\n");
2080#endif
2081 return(NULL);
2082 }
2083
2084 /*
2085 * Allocate a new node and fill the fields.
2086 */
2087 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2088 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002089 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002090 return(NULL);
2091 }
2092 memset(cur, 0, sizeof(xmlNode));
2093 cur->type = XML_PI_NODE;
2094
2095 cur->name = xmlStrdup(name);
2096 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002097 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002098 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002099
Daniel Veillarda880b122003-04-21 21:36:41 +00002100 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002101 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002102 return(cur);
2103}
2104
2105/**
2106 * xmlNewNode:
2107 * @ns: namespace if any
2108 * @name: the node name
2109 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002110 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002111 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002112 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2113 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002114 */
2115xmlNodePtr
2116xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2117 xmlNodePtr cur;
2118
2119 if (name == NULL) {
2120#ifdef DEBUG_TREE
2121 xmlGenericError(xmlGenericErrorContext,
2122 "xmlNewNode : name == NULL\n");
2123#endif
2124 return(NULL);
2125 }
2126
2127 /*
2128 * Allocate a new node and fill the fields.
2129 */
2130 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2131 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002132 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002133 return(NULL);
2134 }
2135 memset(cur, 0, sizeof(xmlNode));
2136 cur->type = XML_ELEMENT_NODE;
2137
2138 cur->name = xmlStrdup(name);
2139 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002140
Daniel Veillarda880b122003-04-21 21:36:41 +00002141 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002142 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002143 return(cur);
2144}
2145
2146/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002147 * xmlNewNodeEatName:
2148 * @ns: namespace if any
2149 * @name: the node name
2150 *
2151 * Creation of a new node element. @ns is optional (NULL).
2152 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002153 * Returns a pointer to the new node object, with pointer @name as
2154 * new node's name. Use xmlNewNode() if a copy of @name string is
2155 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002156 */
2157xmlNodePtr
2158xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2159 xmlNodePtr cur;
2160
2161 if (name == NULL) {
2162#ifdef DEBUG_TREE
2163 xmlGenericError(xmlGenericErrorContext,
2164 "xmlNewNode : name == NULL\n");
2165#endif
2166 return(NULL);
2167 }
2168
2169 /*
2170 * Allocate a new node and fill the fields.
2171 */
2172 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2173 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002174 xmlTreeErrMemory("building node");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002175 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002176 return(NULL);
2177 }
2178 memset(cur, 0, sizeof(xmlNode));
2179 cur->type = XML_ELEMENT_NODE;
2180
2181 cur->name = name;
2182 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002183
Daniel Veillarda880b122003-04-21 21:36:41 +00002184 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002185 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002186 return(cur);
2187}
2188
2189/**
Owen Taylor3473f882001-02-23 17:55:21 +00002190 * xmlNewDocNode:
2191 * @doc: the document
2192 * @ns: namespace if any
2193 * @name: the node name
2194 * @content: the XML text content if any
2195 *
2196 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002197 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002198 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2199 * references, but XML special chars need to be escaped first by using
2200 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2201 * need entities support.
2202 *
2203 * Returns a pointer to the new node object.
2204 */
2205xmlNodePtr
2206xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2207 const xmlChar *name, const xmlChar *content) {
2208 xmlNodePtr cur;
2209
2210 cur = xmlNewNode(ns, name);
2211 if (cur != NULL) {
2212 cur->doc = doc;
2213 if (content != NULL) {
2214 cur->children = xmlStringGetNodeList(doc, content);
2215 UPDATE_LAST_CHILD_AND_PARENT(cur)
2216 }
2217 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002218
Owen Taylor3473f882001-02-23 17:55:21 +00002219 return(cur);
2220}
2221
Daniel Veillard46de64e2002-05-29 08:21:33 +00002222/**
2223 * xmlNewDocNodeEatName:
2224 * @doc: the document
2225 * @ns: namespace if any
2226 * @name: the node name
2227 * @content: the XML text content if any
2228 *
2229 * Creation of a new node element within a document. @ns and @content
2230 * are optional (NULL).
2231 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2232 * references, but XML special chars need to be escaped first by using
2233 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2234 * need entities support.
2235 *
2236 * Returns a pointer to the new node object.
2237 */
2238xmlNodePtr
2239xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2240 xmlChar *name, const xmlChar *content) {
2241 xmlNodePtr cur;
2242
2243 cur = xmlNewNodeEatName(ns, name);
2244 if (cur != NULL) {
2245 cur->doc = doc;
2246 if (content != NULL) {
2247 cur->children = xmlStringGetNodeList(doc, content);
2248 UPDATE_LAST_CHILD_AND_PARENT(cur)
2249 }
2250 }
2251 return(cur);
2252}
2253
Daniel Veillard652327a2003-09-29 18:02:38 +00002254#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002255/**
2256 * xmlNewDocRawNode:
2257 * @doc: the document
2258 * @ns: namespace if any
2259 * @name: the node name
2260 * @content: the text content if any
2261 *
2262 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002263 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002264 *
2265 * Returns a pointer to the new node object.
2266 */
2267xmlNodePtr
2268xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2269 const xmlChar *name, const xmlChar *content) {
2270 xmlNodePtr cur;
2271
2272 cur = xmlNewNode(ns, name);
2273 if (cur != NULL) {
2274 cur->doc = doc;
2275 if (content != NULL) {
2276 cur->children = xmlNewDocText(doc, content);
2277 UPDATE_LAST_CHILD_AND_PARENT(cur)
2278 }
2279 }
2280 return(cur);
2281}
2282
2283/**
2284 * xmlNewDocFragment:
2285 * @doc: the document owning the fragment
2286 *
2287 * Creation of a new Fragment node.
2288 * Returns a pointer to the new node object.
2289 */
2290xmlNodePtr
2291xmlNewDocFragment(xmlDocPtr doc) {
2292 xmlNodePtr cur;
2293
2294 /*
2295 * Allocate a new DocumentFragment node and fill the fields.
2296 */
2297 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2298 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002299 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002300 return(NULL);
2301 }
2302 memset(cur, 0, sizeof(xmlNode));
2303 cur->type = XML_DOCUMENT_FRAG_NODE;
2304
2305 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002306
Daniel Veillarda880b122003-04-21 21:36:41 +00002307 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002308 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002309 return(cur);
2310}
Daniel Veillard652327a2003-09-29 18:02:38 +00002311#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002312
2313/**
2314 * xmlNewText:
2315 * @content: the text content
2316 *
2317 * Creation of a new text node.
2318 * Returns a pointer to the new node object.
2319 */
2320xmlNodePtr
2321xmlNewText(const xmlChar *content) {
2322 xmlNodePtr cur;
2323
2324 /*
2325 * Allocate a new node and fill the fields.
2326 */
2327 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2328 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002329 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002330 return(NULL);
2331 }
2332 memset(cur, 0, sizeof(xmlNode));
2333 cur->type = XML_TEXT_NODE;
2334
2335 cur->name = xmlStringText;
2336 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002337 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002338 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002339
Daniel Veillarda880b122003-04-21 21:36:41 +00002340 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002341 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002342 return(cur);
2343}
2344
Daniel Veillard652327a2003-09-29 18:02:38 +00002345#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002346/**
2347 * xmlNewTextChild:
2348 * @parent: the parent node
2349 * @ns: a namespace if any
2350 * @name: the name of the child
2351 * @content: the text content of the child if any.
2352 *
2353 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002354 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2355 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002356 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002357 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2358 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2359 * reserved XML chars that might appear in @content, such as the ampersand,
2360 * greater-than or less-than signs, are automatically replaced by their XML
2361 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002362 *
2363 * Returns a pointer to the new node object.
2364 */
2365xmlNodePtr
2366xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2367 const xmlChar *name, const xmlChar *content) {
2368 xmlNodePtr cur, prev;
2369
2370 if (parent == NULL) {
2371#ifdef DEBUG_TREE
2372 xmlGenericError(xmlGenericErrorContext,
2373 "xmlNewTextChild : parent == NULL\n");
2374#endif
2375 return(NULL);
2376 }
2377
2378 if (name == NULL) {
2379#ifdef DEBUG_TREE
2380 xmlGenericError(xmlGenericErrorContext,
2381 "xmlNewTextChild : name == NULL\n");
2382#endif
2383 return(NULL);
2384 }
2385
2386 /*
2387 * Allocate a new node
2388 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002389 if (parent->type == XML_ELEMENT_NODE) {
2390 if (ns == NULL)
2391 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2392 else
2393 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2394 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2395 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2396 if (ns == NULL)
2397 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2398 else
2399 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2400 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2401 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2402 } else {
2403 return(NULL);
2404 }
Owen Taylor3473f882001-02-23 17:55:21 +00002405 if (cur == NULL) return(NULL);
2406
2407 /*
2408 * add the new element at the end of the children list.
2409 */
2410 cur->type = XML_ELEMENT_NODE;
2411 cur->parent = parent;
2412 cur->doc = parent->doc;
2413 if (parent->children == NULL) {
2414 parent->children = cur;
2415 parent->last = cur;
2416 } else {
2417 prev = parent->last;
2418 prev->next = cur;
2419 cur->prev = prev;
2420 parent->last = cur;
2421 }
2422
2423 return(cur);
2424}
Daniel Veillard652327a2003-09-29 18:02:38 +00002425#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002426
2427/**
2428 * xmlNewCharRef:
2429 * @doc: the document
2430 * @name: the char ref string, starting with # or "&# ... ;"
2431 *
2432 * Creation of a new character reference node.
2433 * Returns a pointer to the new node object.
2434 */
2435xmlNodePtr
2436xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2437 xmlNodePtr cur;
2438
2439 /*
2440 * Allocate a new node and fill the fields.
2441 */
2442 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2443 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002444 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002445 return(NULL);
2446 }
2447 memset(cur, 0, sizeof(xmlNode));
2448 cur->type = XML_ENTITY_REF_NODE;
2449
2450 cur->doc = doc;
2451 if (name[0] == '&') {
2452 int len;
2453 name++;
2454 len = xmlStrlen(name);
2455 if (name[len - 1] == ';')
2456 cur->name = xmlStrndup(name, len - 1);
2457 else
2458 cur->name = xmlStrndup(name, len);
2459 } else
2460 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002461
Daniel Veillarda880b122003-04-21 21:36:41 +00002462 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002463 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002464 return(cur);
2465}
2466
2467/**
2468 * xmlNewReference:
2469 * @doc: the document
2470 * @name: the reference name, or the reference string with & and ;
2471 *
2472 * Creation of a new reference node.
2473 * Returns a pointer to the new node object.
2474 */
2475xmlNodePtr
2476xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2477 xmlNodePtr cur;
2478 xmlEntityPtr ent;
2479
2480 /*
2481 * Allocate a new node and fill the fields.
2482 */
2483 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2484 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002485 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002486 return(NULL);
2487 }
2488 memset(cur, 0, sizeof(xmlNode));
2489 cur->type = XML_ENTITY_REF_NODE;
2490
2491 cur->doc = doc;
2492 if (name[0] == '&') {
2493 int len;
2494 name++;
2495 len = xmlStrlen(name);
2496 if (name[len - 1] == ';')
2497 cur->name = xmlStrndup(name, len - 1);
2498 else
2499 cur->name = xmlStrndup(name, len);
2500 } else
2501 cur->name = xmlStrdup(name);
2502
2503 ent = xmlGetDocEntity(doc, cur->name);
2504 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002505 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002506 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002507 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002508 * updated. Not sure if this is 100% correct.
2509 * -George
2510 */
2511 cur->children = (xmlNodePtr) ent;
2512 cur->last = (xmlNodePtr) ent;
2513 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002514
Daniel Veillarda880b122003-04-21 21:36:41 +00002515 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002516 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002517 return(cur);
2518}
2519
2520/**
2521 * xmlNewDocText:
2522 * @doc: the document
2523 * @content: the text content
2524 *
2525 * Creation of a new text node within a document.
2526 * Returns a pointer to the new node object.
2527 */
2528xmlNodePtr
2529xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2530 xmlNodePtr cur;
2531
2532 cur = xmlNewText(content);
2533 if (cur != NULL) cur->doc = doc;
2534 return(cur);
2535}
2536
2537/**
2538 * xmlNewTextLen:
2539 * @content: the text content
2540 * @len: the text len.
2541 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002542 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002543 * Returns a pointer to the new node object.
2544 */
2545xmlNodePtr
2546xmlNewTextLen(const xmlChar *content, int len) {
2547 xmlNodePtr cur;
2548
2549 /*
2550 * Allocate a new node and fill the fields.
2551 */
2552 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2553 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002554 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002555 return(NULL);
2556 }
2557 memset(cur, 0, sizeof(xmlNode));
2558 cur->type = XML_TEXT_NODE;
2559
2560 cur->name = xmlStringText;
2561 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002562 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002563 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002564
Daniel Veillarda880b122003-04-21 21:36:41 +00002565 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002566 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002567 return(cur);
2568}
2569
2570/**
2571 * xmlNewDocTextLen:
2572 * @doc: the document
2573 * @content: the text content
2574 * @len: the text len.
2575 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002576 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002577 * text node pertain to a given document.
2578 * Returns a pointer to the new node object.
2579 */
2580xmlNodePtr
2581xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2582 xmlNodePtr cur;
2583
2584 cur = xmlNewTextLen(content, len);
2585 if (cur != NULL) cur->doc = doc;
2586 return(cur);
2587}
2588
2589/**
2590 * xmlNewComment:
2591 * @content: the comment content
2592 *
2593 * Creation of a new node containing a comment.
2594 * Returns a pointer to the new node object.
2595 */
2596xmlNodePtr
2597xmlNewComment(const xmlChar *content) {
2598 xmlNodePtr cur;
2599
2600 /*
2601 * Allocate a new node and fill the fields.
2602 */
2603 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2604 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002605 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002606 return(NULL);
2607 }
2608 memset(cur, 0, sizeof(xmlNode));
2609 cur->type = XML_COMMENT_NODE;
2610
2611 cur->name = xmlStringComment;
2612 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002613 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002614 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002615
Daniel Veillarda880b122003-04-21 21:36:41 +00002616 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002617 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002618 return(cur);
2619}
2620
2621/**
2622 * xmlNewCDataBlock:
2623 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002624 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002625 * @len: the length of the block
2626 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002627 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002628 * Returns a pointer to the new node object.
2629 */
2630xmlNodePtr
2631xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2632 xmlNodePtr cur;
2633
2634 /*
2635 * Allocate a new node and fill the fields.
2636 */
2637 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2638 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002639 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002640 return(NULL);
2641 }
2642 memset(cur, 0, sizeof(xmlNode));
2643 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002644 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002645
2646 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002647 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002648 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002649
Daniel Veillarda880b122003-04-21 21:36:41 +00002650 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002651 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002652 return(cur);
2653}
2654
2655/**
2656 * xmlNewDocComment:
2657 * @doc: the document
2658 * @content: the comment content
2659 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002660 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002661 * Returns a pointer to the new node object.
2662 */
2663xmlNodePtr
2664xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2665 xmlNodePtr cur;
2666
2667 cur = xmlNewComment(content);
2668 if (cur != NULL) cur->doc = doc;
2669 return(cur);
2670}
2671
2672/**
2673 * xmlSetTreeDoc:
2674 * @tree: the top element
2675 * @doc: the document
2676 *
2677 * update all nodes under the tree to point to the right document
2678 */
2679void
2680xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002681 xmlAttrPtr prop;
2682
Owen Taylor3473f882001-02-23 17:55:21 +00002683 if (tree == NULL)
2684 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002685 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002686 if(tree->type == XML_ELEMENT_NODE) {
2687 prop = tree->properties;
2688 while (prop != NULL) {
2689 prop->doc = doc;
2690 xmlSetListDoc(prop->children, doc);
2691 prop = prop->next;
2692 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002693 }
Owen Taylor3473f882001-02-23 17:55:21 +00002694 if (tree->children != NULL)
2695 xmlSetListDoc(tree->children, doc);
2696 tree->doc = doc;
2697 }
2698}
2699
2700/**
2701 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002702 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002703 * @doc: the document
2704 *
2705 * update all nodes in the list to point to the right document
2706 */
2707void
2708xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2709 xmlNodePtr cur;
2710
2711 if (list == NULL)
2712 return;
2713 cur = list;
2714 while (cur != NULL) {
2715 if (cur->doc != doc)
2716 xmlSetTreeDoc(cur, doc);
2717 cur = cur->next;
2718 }
2719}
2720
Daniel Veillard2156d432004-03-04 15:59:36 +00002721#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002722/**
2723 * xmlNewChild:
2724 * @parent: the parent node
2725 * @ns: a namespace if any
2726 * @name: the name of the child
2727 * @content: the XML content of the child if any.
2728 *
2729 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002730 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2731 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002732 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002733 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2734 * references. XML special chars must be escaped first by using
2735 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002736 *
2737 * Returns a pointer to the new node object.
2738 */
2739xmlNodePtr
2740xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2741 const xmlChar *name, const xmlChar *content) {
2742 xmlNodePtr cur, prev;
2743
2744 if (parent == NULL) {
2745#ifdef DEBUG_TREE
2746 xmlGenericError(xmlGenericErrorContext,
2747 "xmlNewChild : parent == NULL\n");
2748#endif
2749 return(NULL);
2750 }
2751
2752 if (name == NULL) {
2753#ifdef DEBUG_TREE
2754 xmlGenericError(xmlGenericErrorContext,
2755 "xmlNewChild : name == NULL\n");
2756#endif
2757 return(NULL);
2758 }
2759
2760 /*
2761 * Allocate a new node
2762 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002763 if (parent->type == XML_ELEMENT_NODE) {
2764 if (ns == NULL)
2765 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2766 else
2767 cur = xmlNewDocNode(parent->doc, ns, name, content);
2768 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2769 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2770 if (ns == NULL)
2771 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2772 else
2773 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002774 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2775 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002776 } else {
2777 return(NULL);
2778 }
Owen Taylor3473f882001-02-23 17:55:21 +00002779 if (cur == NULL) return(NULL);
2780
2781 /*
2782 * add the new element at the end of the children list.
2783 */
2784 cur->type = XML_ELEMENT_NODE;
2785 cur->parent = parent;
2786 cur->doc = parent->doc;
2787 if (parent->children == NULL) {
2788 parent->children = cur;
2789 parent->last = cur;
2790 } else {
2791 prev = parent->last;
2792 prev->next = cur;
2793 cur->prev = prev;
2794 parent->last = cur;
2795 }
2796
2797 return(cur);
2798}
Daniel Veillard652327a2003-09-29 18:02:38 +00002799#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002800
2801/**
2802 * xmlAddNextSibling:
2803 * @cur: the child node
2804 * @elem: the new node
2805 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002806 * Add a new node @elem as the next sibling of @cur
2807 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002808 * first unlinked from its existing context.
2809 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002810 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2811 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002812 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002813 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002814 */
2815xmlNodePtr
2816xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2817 if (cur == NULL) {
2818#ifdef DEBUG_TREE
2819 xmlGenericError(xmlGenericErrorContext,
2820 "xmlAddNextSibling : cur == NULL\n");
2821#endif
2822 return(NULL);
2823 }
2824 if (elem == NULL) {
2825#ifdef DEBUG_TREE
2826 xmlGenericError(xmlGenericErrorContext,
2827 "xmlAddNextSibling : elem == NULL\n");
2828#endif
2829 return(NULL);
2830 }
2831
2832 xmlUnlinkNode(elem);
2833
2834 if (elem->type == XML_TEXT_NODE) {
2835 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002836 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002837 xmlFreeNode(elem);
2838 return(cur);
2839 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002840 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2841 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002842 xmlChar *tmp;
2843
2844 tmp = xmlStrdup(elem->content);
2845 tmp = xmlStrcat(tmp, cur->next->content);
2846 xmlNodeSetContent(cur->next, tmp);
2847 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002848 xmlFreeNode(elem);
2849 return(cur->next);
2850 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002851 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2852 /* check if an attribute with the same name exists */
2853 xmlAttrPtr attr;
2854
2855 if (elem->ns == NULL)
2856 attr = xmlHasProp(cur->parent, elem->name);
2857 else
2858 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2859 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2860 /* different instance, destroy it (attributes must be unique) */
2861 xmlFreeProp(attr);
2862 }
Owen Taylor3473f882001-02-23 17:55:21 +00002863 }
2864
2865 if (elem->doc != cur->doc) {
2866 xmlSetTreeDoc(elem, cur->doc);
2867 }
2868 elem->parent = cur->parent;
2869 elem->prev = cur;
2870 elem->next = cur->next;
2871 cur->next = elem;
2872 if (elem->next != NULL)
2873 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002874 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002875 elem->parent->last = elem;
2876 return(elem);
2877}
2878
Daniel Veillard2156d432004-03-04 15:59:36 +00002879#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002880/**
2881 * xmlAddPrevSibling:
2882 * @cur: the child node
2883 * @elem: the new node
2884 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002885 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002886 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002887 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002888 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002889 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2890 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002891 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002892 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002893 */
2894xmlNodePtr
2895xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2896 if (cur == NULL) {
2897#ifdef DEBUG_TREE
2898 xmlGenericError(xmlGenericErrorContext,
2899 "xmlAddPrevSibling : cur == NULL\n");
2900#endif
2901 return(NULL);
2902 }
2903 if (elem == NULL) {
2904#ifdef DEBUG_TREE
2905 xmlGenericError(xmlGenericErrorContext,
2906 "xmlAddPrevSibling : elem == NULL\n");
2907#endif
2908 return(NULL);
2909 }
2910
2911 xmlUnlinkNode(elem);
2912
2913 if (elem->type == XML_TEXT_NODE) {
2914 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002915 xmlChar *tmp;
2916
2917 tmp = xmlStrdup(elem->content);
2918 tmp = xmlStrcat(tmp, cur->content);
2919 xmlNodeSetContent(cur, tmp);
2920 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002921 xmlFreeNode(elem);
2922 return(cur);
2923 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002924 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2925 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002926 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002927 xmlFreeNode(elem);
2928 return(cur->prev);
2929 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002930 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2931 /* check if an attribute with the same name exists */
2932 xmlAttrPtr attr;
2933
2934 if (elem->ns == NULL)
2935 attr = xmlHasProp(cur->parent, elem->name);
2936 else
2937 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2938 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2939 /* different instance, destroy it (attributes must be unique) */
2940 xmlFreeProp(attr);
2941 }
Owen Taylor3473f882001-02-23 17:55:21 +00002942 }
2943
2944 if (elem->doc != cur->doc) {
2945 xmlSetTreeDoc(elem, cur->doc);
2946 }
2947 elem->parent = cur->parent;
2948 elem->next = cur;
2949 elem->prev = cur->prev;
2950 cur->prev = elem;
2951 if (elem->prev != NULL)
2952 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002953 if (elem->parent != NULL) {
2954 if (elem->type == XML_ATTRIBUTE_NODE) {
2955 if (elem->parent->properties == (xmlAttrPtr) cur) {
2956 elem->parent->properties = (xmlAttrPtr) elem;
2957 }
2958 } else {
2959 if (elem->parent->children == cur) {
2960 elem->parent->children = elem;
2961 }
2962 }
2963 }
Owen Taylor3473f882001-02-23 17:55:21 +00002964 return(elem);
2965}
Daniel Veillard652327a2003-09-29 18:02:38 +00002966#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002967
2968/**
2969 * xmlAddSibling:
2970 * @cur: the child node
2971 * @elem: the new node
2972 *
2973 * Add a new element @elem to the list of siblings of @cur
2974 * merging adjacent TEXT nodes (@elem may be freed)
2975 * If the new element was already inserted in a document it is
2976 * first unlinked from its existing context.
2977 *
2978 * Returns the new element or NULL in case of error.
2979 */
2980xmlNodePtr
2981xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2982 xmlNodePtr parent;
2983
2984 if (cur == NULL) {
2985#ifdef DEBUG_TREE
2986 xmlGenericError(xmlGenericErrorContext,
2987 "xmlAddSibling : cur == NULL\n");
2988#endif
2989 return(NULL);
2990 }
2991
2992 if (elem == NULL) {
2993#ifdef DEBUG_TREE
2994 xmlGenericError(xmlGenericErrorContext,
2995 "xmlAddSibling : elem == NULL\n");
2996#endif
2997 return(NULL);
2998 }
2999
3000 /*
3001 * Constant time is we can rely on the ->parent->last to find
3002 * the last sibling.
3003 */
3004 if ((cur->parent != NULL) &&
3005 (cur->parent->children != NULL) &&
3006 (cur->parent->last != NULL) &&
3007 (cur->parent->last->next == NULL)) {
3008 cur = cur->parent->last;
3009 } else {
3010 while (cur->next != NULL) cur = cur->next;
3011 }
3012
3013 xmlUnlinkNode(elem);
3014
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003015 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3016 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003017 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003018 xmlFreeNode(elem);
3019 return(cur);
3020 }
3021
3022 if (elem->doc != cur->doc) {
3023 xmlSetTreeDoc(elem, cur->doc);
3024 }
3025 parent = cur->parent;
3026 elem->prev = cur;
3027 elem->next = NULL;
3028 elem->parent = parent;
3029 cur->next = elem;
3030 if (parent != NULL)
3031 parent->last = elem;
3032
3033 return(elem);
3034}
3035
3036/**
3037 * xmlAddChildList:
3038 * @parent: the parent node
3039 * @cur: the first node in the list
3040 *
3041 * Add a list of node at the end of the child list of the parent
3042 * merging adjacent TEXT nodes (@cur may be freed)
3043 *
3044 * Returns the last child or NULL in case of error.
3045 */
3046xmlNodePtr
3047xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3048 xmlNodePtr prev;
3049
3050 if (parent == NULL) {
3051#ifdef DEBUG_TREE
3052 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003053 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003054#endif
3055 return(NULL);
3056 }
3057
3058 if (cur == NULL) {
3059#ifdef DEBUG_TREE
3060 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003061 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003062#endif
3063 return(NULL);
3064 }
3065
3066 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3067 (cur->doc != parent->doc)) {
3068#ifdef DEBUG_TREE
3069 xmlGenericError(xmlGenericErrorContext,
3070 "Elements moved to a different document\n");
3071#endif
3072 }
3073
3074 /*
3075 * add the first element at the end of the children list.
3076 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003077
Owen Taylor3473f882001-02-23 17:55:21 +00003078 if (parent->children == NULL) {
3079 parent->children = cur;
3080 } else {
3081 /*
3082 * If cur and parent->last both are TEXT nodes, then merge them.
3083 */
3084 if ((cur->type == XML_TEXT_NODE) &&
3085 (parent->last->type == XML_TEXT_NODE) &&
3086 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003087 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003088 /*
3089 * if it's the only child, nothing more to be done.
3090 */
3091 if (cur->next == NULL) {
3092 xmlFreeNode(cur);
3093 return(parent->last);
3094 }
3095 prev = cur;
3096 cur = cur->next;
3097 xmlFreeNode(prev);
3098 }
3099 prev = parent->last;
3100 prev->next = cur;
3101 cur->prev = prev;
3102 }
3103 while (cur->next != NULL) {
3104 cur->parent = parent;
3105 if (cur->doc != parent->doc) {
3106 xmlSetTreeDoc(cur, parent->doc);
3107 }
3108 cur = cur->next;
3109 }
3110 cur->parent = parent;
3111 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3112 parent->last = cur;
3113
3114 return(cur);
3115}
3116
3117/**
3118 * xmlAddChild:
3119 * @parent: the parent node
3120 * @cur: the child node
3121 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003122 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003123 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003124 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3125 * If there is an attribute with equal name, it is first destroyed.
3126 *
Owen Taylor3473f882001-02-23 17:55:21 +00003127 * Returns the child or NULL in case of error.
3128 */
3129xmlNodePtr
3130xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3131 xmlNodePtr prev;
3132
3133 if (parent == NULL) {
3134#ifdef DEBUG_TREE
3135 xmlGenericError(xmlGenericErrorContext,
3136 "xmlAddChild : parent == NULL\n");
3137#endif
3138 return(NULL);
3139 }
3140
3141 if (cur == NULL) {
3142#ifdef DEBUG_TREE
3143 xmlGenericError(xmlGenericErrorContext,
3144 "xmlAddChild : child == NULL\n");
3145#endif
3146 return(NULL);
3147 }
3148
Owen Taylor3473f882001-02-23 17:55:21 +00003149 /*
3150 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003151 * cur is then freed.
3152 */
3153 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003154 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003155 (parent->content != NULL) &&
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003156 (parent->name == cur->name) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003157 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003158 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003159 xmlFreeNode(cur);
3160 return(parent);
3161 }
3162 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003163 (parent->last->name == cur->name) &&
3164 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003165 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003166 xmlFreeNode(cur);
3167 return(parent->last);
3168 }
3169 }
3170
3171 /*
3172 * add the new element at the end of the children list.
3173 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003174 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003175 cur->parent = parent;
3176 if (cur->doc != parent->doc) {
3177 xmlSetTreeDoc(cur, parent->doc);
3178 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003179 /* this check prevents a loop on tree-traversions if a developer
3180 * tries to add a node to its parent multiple times
3181 */
3182 if (prev == parent)
3183 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003184
3185 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003186 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003187 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003188 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003189 (parent->content != NULL) &&
3190 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003191 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003192 xmlFreeNode(cur);
3193 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003194 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003195 if (cur->type == XML_ATTRIBUTE_NODE) {
3196 if (parent->properties == NULL) {
3197 parent->properties = (xmlAttrPtr) cur;
3198 } else {
3199 /* check if an attribute with the same name exists */
3200 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003201
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003202 if (cur->ns == NULL)
3203 lastattr = xmlHasProp(parent, cur->name);
3204 else
3205 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3206 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3207 /* different instance, destroy it (attributes must be unique) */
3208 xmlFreeProp(lastattr);
3209 }
3210 /* find the end */
3211 lastattr = parent->properties;
3212 while (lastattr->next != NULL) {
3213 lastattr = lastattr->next;
3214 }
3215 lastattr->next = (xmlAttrPtr) cur;
3216 ((xmlAttrPtr) cur)->prev = lastattr;
3217 }
3218 } else {
3219 if (parent->children == NULL) {
3220 parent->children = cur;
3221 parent->last = cur;
3222 } else {
3223 prev = parent->last;
3224 prev->next = cur;
3225 cur->prev = prev;
3226 parent->last = cur;
3227 }
3228 }
Owen Taylor3473f882001-02-23 17:55:21 +00003229 return(cur);
3230}
3231
3232/**
3233 * xmlGetLastChild:
3234 * @parent: the parent node
3235 *
3236 * Search the last child of a node.
3237 * Returns the last child or NULL if none.
3238 */
3239xmlNodePtr
3240xmlGetLastChild(xmlNodePtr parent) {
3241 if (parent == NULL) {
3242#ifdef DEBUG_TREE
3243 xmlGenericError(xmlGenericErrorContext,
3244 "xmlGetLastChild : parent == NULL\n");
3245#endif
3246 return(NULL);
3247 }
3248 return(parent->last);
3249}
3250
3251/**
3252 * xmlFreeNodeList:
3253 * @cur: the first node in the list
3254 *
3255 * Free a node and all its siblings, this is a recursive behaviour, all
3256 * the children are freed too.
3257 */
3258void
3259xmlFreeNodeList(xmlNodePtr cur) {
3260 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003261 xmlDictPtr dict = NULL;
3262
3263 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003264 if (cur->type == XML_NAMESPACE_DECL) {
3265 xmlFreeNsList((xmlNsPtr) cur);
3266 return;
3267 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003268 if ((cur->type == XML_DOCUMENT_NODE) ||
3269#ifdef LIBXML_DOCB_ENABLED
3270 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003271#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003272 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003273 xmlFreeDoc((xmlDocPtr) cur);
3274 return;
3275 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003276 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003277 while (cur != NULL) {
3278 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003279 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003280
Daniel Veillarda880b122003-04-21 21:36:41 +00003281 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003282 xmlDeregisterNodeDefaultValue(cur);
3283
Daniel Veillard02141ea2001-04-30 11:46:40 +00003284 if ((cur->children != NULL) &&
3285 (cur->type != XML_ENTITY_REF_NODE))
3286 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003287 if (((cur->type == XML_ELEMENT_NODE) ||
3288 (cur->type == XML_XINCLUDE_START) ||
3289 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003290 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003291 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003292 if ((cur->type != XML_ELEMENT_NODE) &&
3293 (cur->type != XML_XINCLUDE_START) &&
3294 (cur->type != XML_XINCLUDE_END) &&
3295 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003296 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003297 }
3298 if (((cur->type == XML_ELEMENT_NODE) ||
3299 (cur->type == XML_XINCLUDE_START) ||
3300 (cur->type == XML_XINCLUDE_END)) &&
3301 (cur->nsDef != NULL))
3302 xmlFreeNsList(cur->nsDef);
3303
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003304 /*
3305 * When a node is a text node or a comment, it uses a global static
3306 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003307 * Otherwise the node name might come from the document's
3308 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003309 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003310 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003311 (cur->type != XML_TEXT_NODE) &&
3312 (cur->type != XML_COMMENT_NODE))
3313 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003314 xmlFree(cur);
3315 }
Owen Taylor3473f882001-02-23 17:55:21 +00003316 cur = next;
3317 }
3318}
3319
3320/**
3321 * xmlFreeNode:
3322 * @cur: the node
3323 *
3324 * Free a node, this is a recursive behaviour, all the children are freed too.
3325 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3326 */
3327void
3328xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003329 xmlDictPtr dict = NULL;
3330
3331 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003332
Daniel Veillard02141ea2001-04-30 11:46:40 +00003333 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003334 if (cur->type == XML_DTD_NODE) {
3335 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003336 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003337 }
3338 if (cur->type == XML_NAMESPACE_DECL) {
3339 xmlFreeNs((xmlNsPtr) cur);
3340 return;
3341 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003342 if (cur->type == XML_ATTRIBUTE_NODE) {
3343 xmlFreeProp((xmlAttrPtr) cur);
3344 return;
3345 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003346
Daniel Veillarda880b122003-04-21 21:36:41 +00003347 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003348 xmlDeregisterNodeDefaultValue(cur);
3349
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003350 if (cur->doc != NULL) dict = cur->doc->dict;
3351
Owen Taylor3473f882001-02-23 17:55:21 +00003352 if ((cur->children != NULL) &&
3353 (cur->type != XML_ENTITY_REF_NODE))
3354 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003355 if (((cur->type == XML_ELEMENT_NODE) ||
3356 (cur->type == XML_XINCLUDE_START) ||
3357 (cur->type == XML_XINCLUDE_END)) &&
3358 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003359 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003360 if ((cur->type != XML_ELEMENT_NODE) &&
3361 (cur->content != NULL) &&
3362 (cur->type != XML_ENTITY_REF_NODE) &&
3363 (cur->type != XML_XINCLUDE_END) &&
3364 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003365 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003366 }
3367
Daniel Veillardacd370f2001-06-09 17:17:51 +00003368 /*
3369 * When a node is a text node or a comment, it uses a global static
3370 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003371 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003372 */
Owen Taylor3473f882001-02-23 17:55:21 +00003373 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003374 (cur->type != XML_TEXT_NODE) &&
3375 (cur->type != XML_COMMENT_NODE))
3376 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003377
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003378 if (((cur->type == XML_ELEMENT_NODE) ||
3379 (cur->type == XML_XINCLUDE_START) ||
3380 (cur->type == XML_XINCLUDE_END)) &&
3381 (cur->nsDef != NULL))
3382 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003383 xmlFree(cur);
3384}
3385
3386/**
3387 * xmlUnlinkNode:
3388 * @cur: the node
3389 *
3390 * Unlink a node from it's current context, the node is not freed
3391 */
3392void
3393xmlUnlinkNode(xmlNodePtr cur) {
3394 if (cur == NULL) {
3395#ifdef DEBUG_TREE
3396 xmlGenericError(xmlGenericErrorContext,
3397 "xmlUnlinkNode : node == NULL\n");
3398#endif
3399 return;
3400 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003401 if (cur->type == XML_DTD_NODE) {
3402 xmlDocPtr doc;
3403 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003404 if (doc != NULL) {
3405 if (doc->intSubset == (xmlDtdPtr) cur)
3406 doc->intSubset = NULL;
3407 if (doc->extSubset == (xmlDtdPtr) cur)
3408 doc->extSubset = NULL;
3409 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003410 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003411 if (cur->parent != NULL) {
3412 xmlNodePtr parent;
3413 parent = cur->parent;
3414 if (cur->type == XML_ATTRIBUTE_NODE) {
3415 if (parent->properties == (xmlAttrPtr) cur)
3416 parent->properties = ((xmlAttrPtr) cur)->next;
3417 } else {
3418 if (parent->children == cur)
3419 parent->children = cur->next;
3420 if (parent->last == cur)
3421 parent->last = cur->prev;
3422 }
3423 cur->parent = NULL;
3424 }
Owen Taylor3473f882001-02-23 17:55:21 +00003425 if (cur->next != NULL)
3426 cur->next->prev = cur->prev;
3427 if (cur->prev != NULL)
3428 cur->prev->next = cur->next;
3429 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003430}
3431
Daniel Veillard2156d432004-03-04 15:59:36 +00003432#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003433/**
3434 * xmlReplaceNode:
3435 * @old: the old node
3436 * @cur: the node
3437 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003438 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003439 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003440 * first unlinked from its existing context.
3441 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003442 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003443 */
3444xmlNodePtr
3445xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3446 if (old == NULL) {
3447#ifdef DEBUG_TREE
3448 xmlGenericError(xmlGenericErrorContext,
3449 "xmlReplaceNode : old == NULL\n");
3450#endif
3451 return(NULL);
3452 }
3453 if (cur == NULL) {
3454 xmlUnlinkNode(old);
3455 return(old);
3456 }
3457 if (cur == old) {
3458 return(old);
3459 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003460 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3461#ifdef DEBUG_TREE
3462 xmlGenericError(xmlGenericErrorContext,
3463 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3464#endif
3465 return(old);
3466 }
3467 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3468#ifdef DEBUG_TREE
3469 xmlGenericError(xmlGenericErrorContext,
3470 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3471#endif
3472 return(old);
3473 }
Owen Taylor3473f882001-02-23 17:55:21 +00003474 xmlUnlinkNode(cur);
3475 cur->doc = old->doc;
3476 cur->parent = old->parent;
3477 cur->next = old->next;
3478 if (cur->next != NULL)
3479 cur->next->prev = cur;
3480 cur->prev = old->prev;
3481 if (cur->prev != NULL)
3482 cur->prev->next = cur;
3483 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003484 if (cur->type == XML_ATTRIBUTE_NODE) {
3485 if (cur->parent->properties == (xmlAttrPtr)old)
3486 cur->parent->properties = ((xmlAttrPtr) cur);
3487 } else {
3488 if (cur->parent->children == old)
3489 cur->parent->children = cur;
3490 if (cur->parent->last == old)
3491 cur->parent->last = cur;
3492 }
Owen Taylor3473f882001-02-23 17:55:21 +00003493 }
3494 old->next = old->prev = NULL;
3495 old->parent = NULL;
3496 return(old);
3497}
Daniel Veillard652327a2003-09-29 18:02:38 +00003498#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003499
3500/************************************************************************
3501 * *
3502 * Copy operations *
3503 * *
3504 ************************************************************************/
3505
3506/**
3507 * xmlCopyNamespace:
3508 * @cur: the namespace
3509 *
3510 * Do a copy of the namespace.
3511 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003512 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003513 */
3514xmlNsPtr
3515xmlCopyNamespace(xmlNsPtr cur) {
3516 xmlNsPtr ret;
3517
3518 if (cur == NULL) return(NULL);
3519 switch (cur->type) {
3520 case XML_LOCAL_NAMESPACE:
3521 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3522 break;
3523 default:
3524#ifdef DEBUG_TREE
3525 xmlGenericError(xmlGenericErrorContext,
3526 "xmlCopyNamespace: invalid type %d\n", cur->type);
3527#endif
3528 return(NULL);
3529 }
3530 return(ret);
3531}
3532
3533/**
3534 * xmlCopyNamespaceList:
3535 * @cur: the first namespace
3536 *
3537 * Do a copy of an namespace list.
3538 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003539 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003540 */
3541xmlNsPtr
3542xmlCopyNamespaceList(xmlNsPtr cur) {
3543 xmlNsPtr ret = NULL;
3544 xmlNsPtr p = NULL,q;
3545
3546 while (cur != NULL) {
3547 q = xmlCopyNamespace(cur);
3548 if (p == NULL) {
3549 ret = p = q;
3550 } else {
3551 p->next = q;
3552 p = q;
3553 }
3554 cur = cur->next;
3555 }
3556 return(ret);
3557}
3558
3559static xmlNodePtr
3560xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3561/**
3562 * xmlCopyProp:
3563 * @target: the element where the attribute will be grafted
3564 * @cur: the attribute
3565 *
3566 * Do a copy of the attribute.
3567 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003568 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003569 */
3570xmlAttrPtr
3571xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3572 xmlAttrPtr ret;
3573
3574 if (cur == NULL) return(NULL);
3575 if (target != NULL)
3576 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3577 else if (cur->parent != NULL)
3578 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3579 else if (cur->children != NULL)
3580 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3581 else
3582 ret = xmlNewDocProp(NULL, cur->name, NULL);
3583 if (ret == NULL) return(NULL);
3584 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003585
Owen Taylor3473f882001-02-23 17:55:21 +00003586 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003587 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003588
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003589 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3590 if (ns == NULL) {
3591 /*
3592 * Humm, we are copying an element whose namespace is defined
3593 * out of the new tree scope. Search it in the original tree
3594 * and add it at the top of the new tree
3595 */
3596 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3597 if (ns != NULL) {
3598 xmlNodePtr root = target;
3599 xmlNodePtr pred = NULL;
3600
3601 while (root->parent != NULL) {
3602 pred = root;
3603 root = root->parent;
3604 }
3605 if (root == (xmlNodePtr) target->doc) {
3606 /* correct possibly cycling above the document elt */
3607 root = pred;
3608 }
3609 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3610 }
3611 } else {
3612 /*
3613 * we have to find something appropriate here since
3614 * we cant be sure, that the namespce we found is identified
3615 * by the prefix
3616 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003617 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003618 /* this is the nice case */
3619 ret->ns = ns;
3620 } else {
3621 /*
3622 * we are in trouble: we need a new reconcilied namespace.
3623 * This is expensive
3624 */
3625 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3626 }
3627 }
3628
Owen Taylor3473f882001-02-23 17:55:21 +00003629 } else
3630 ret->ns = NULL;
3631
3632 if (cur->children != NULL) {
3633 xmlNodePtr tmp;
3634
3635 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3636 ret->last = NULL;
3637 tmp = ret->children;
3638 while (tmp != NULL) {
3639 /* tmp->parent = (xmlNodePtr)ret; */
3640 if (tmp->next == NULL)
3641 ret->last = tmp;
3642 tmp = tmp->next;
3643 }
3644 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003645 /*
3646 * Try to handle IDs
3647 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003648 if ((target!= NULL) && (cur!= NULL) &&
3649 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003650 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3651 if (xmlIsID(cur->doc, cur->parent, cur)) {
3652 xmlChar *id;
3653
3654 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3655 if (id != NULL) {
3656 xmlAddID(NULL, target->doc, id, ret);
3657 xmlFree(id);
3658 }
3659 }
3660 }
Owen Taylor3473f882001-02-23 17:55:21 +00003661 return(ret);
3662}
3663
3664/**
3665 * xmlCopyPropList:
3666 * @target: the element where the attributes will be grafted
3667 * @cur: the first attribute
3668 *
3669 * Do a copy of an attribute list.
3670 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003671 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003672 */
3673xmlAttrPtr
3674xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3675 xmlAttrPtr ret = NULL;
3676 xmlAttrPtr p = NULL,q;
3677
3678 while (cur != NULL) {
3679 q = xmlCopyProp(target, cur);
3680 if (p == NULL) {
3681 ret = p = q;
3682 } else {
3683 p->next = q;
3684 q->prev = p;
3685 p = q;
3686 }
3687 cur = cur->next;
3688 }
3689 return(ret);
3690}
3691
3692/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003693 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003694 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003695 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003696 * tricky reason: namespaces. Doing a direct copy of a node
3697 * say RPM:Copyright without changing the namespace pointer to
3698 * something else can produce stale links. One way to do it is
3699 * to keep a reference counter but this doesn't work as soon
3700 * as one move the element or the subtree out of the scope of
3701 * the existing namespace. The actual solution seems to add
3702 * a copy of the namespace at the top of the copied tree if
3703 * not available in the subtree.
3704 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00003705 * The argument "recursive" normally indicates a recursive copy
3706 * of the node with values 0 (no) and 1 (yes). For XInclude,
3707 * however, we allow a value of 2 to indicate copy properties and
3708 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00003709 */
3710
3711static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003712xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00003713 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003714 xmlNodePtr ret;
3715
3716 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003717 switch (node->type) {
3718 case XML_TEXT_NODE:
3719 case XML_CDATA_SECTION_NODE:
3720 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003721 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003722 case XML_ENTITY_REF_NODE:
3723 case XML_ENTITY_NODE:
3724 case XML_PI_NODE:
3725 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003726 case XML_XINCLUDE_START:
3727 case XML_XINCLUDE_END:
3728 break;
3729 case XML_ATTRIBUTE_NODE:
3730 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3731 case XML_NAMESPACE_DECL:
3732 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3733
Daniel Veillard39196eb2001-06-19 18:09:42 +00003734 case XML_DOCUMENT_NODE:
3735 case XML_HTML_DOCUMENT_NODE:
3736#ifdef LIBXML_DOCB_ENABLED
3737 case XML_DOCB_DOCUMENT_NODE:
3738#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003739#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00003740 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00003741#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003742 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003743 case XML_NOTATION_NODE:
3744 case XML_DTD_NODE:
3745 case XML_ELEMENT_DECL:
3746 case XML_ATTRIBUTE_DECL:
3747 case XML_ENTITY_DECL:
3748 return(NULL);
3749 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003750
Owen Taylor3473f882001-02-23 17:55:21 +00003751 /*
3752 * Allocate a new node and fill the fields.
3753 */
3754 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3755 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003756 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003757 return(NULL);
3758 }
3759 memset(ret, 0, sizeof(xmlNode));
3760 ret->type = node->type;
3761
3762 ret->doc = doc;
3763 ret->parent = parent;
3764 if (node->name == xmlStringText)
3765 ret->name = xmlStringText;
3766 else if (node->name == xmlStringTextNoenc)
3767 ret->name = xmlStringTextNoenc;
3768 else if (node->name == xmlStringComment)
3769 ret->name = xmlStringComment;
3770 else if (node->name != NULL)
3771 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003772 if ((node->type != XML_ELEMENT_NODE) &&
3773 (node->content != NULL) &&
3774 (node->type != XML_ENTITY_REF_NODE) &&
3775 (node->type != XML_XINCLUDE_END) &&
3776 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003777 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003778 }else{
3779 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003780 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003781 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003782 if (parent != NULL) {
3783 xmlNodePtr tmp;
3784
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003785 /*
3786 * this is a tricky part for the node register thing:
3787 * in case ret does get coalesced in xmlAddChild
3788 * the deregister-node callback is called; so we register ret now already
3789 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003790 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003791 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3792
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003793 tmp = xmlAddChild(parent, ret);
3794 /* node could have coalesced */
3795 if (tmp != ret)
3796 return(tmp);
3797 }
Owen Taylor3473f882001-02-23 17:55:21 +00003798
William M. Brack57e9e912004-03-09 16:19:02 +00003799 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003800 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003801 if (node->nsDef != NULL)
3802 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3803
3804 if (node->ns != NULL) {
3805 xmlNsPtr ns;
3806
3807 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3808 if (ns == NULL) {
3809 /*
3810 * Humm, we are copying an element whose namespace is defined
3811 * out of the new tree scope. Search it in the original tree
3812 * and add it at the top of the new tree
3813 */
3814 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3815 if (ns != NULL) {
3816 xmlNodePtr root = ret;
3817
3818 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003819 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003820 }
3821 } else {
3822 /*
3823 * reference the existing namespace definition in our own tree.
3824 */
3825 ret->ns = ns;
3826 }
3827 }
3828 if (node->properties != NULL)
3829 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003830 if (node->type == XML_ENTITY_REF_NODE) {
3831 if ((doc == NULL) || (node->doc != doc)) {
3832 /*
3833 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003834 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003835 * we cannot keep the reference. Try to find it in the
3836 * target document.
3837 */
3838 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3839 } else {
3840 ret->children = node->children;
3841 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003842 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00003843 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003844 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003845 UPDATE_LAST_CHILD_AND_PARENT(ret)
3846 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003847
3848out:
3849 /* if parent != NULL we already registered the node above */
3850 if (parent == NULL && xmlRegisterNodeDefaultValue)
3851 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003852 return(ret);
3853}
3854
3855static xmlNodePtr
3856xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3857 xmlNodePtr ret = NULL;
3858 xmlNodePtr p = NULL,q;
3859
3860 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003861#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003862 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003863 if (doc == NULL) {
3864 node = node->next;
3865 continue;
3866 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003867 if (doc->intSubset == NULL) {
3868 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3869 q->doc = doc;
3870 q->parent = parent;
3871 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003872 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003873 } else {
3874 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003875 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003876 }
3877 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003878#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003879 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003880 if (ret == NULL) {
3881 q->prev = NULL;
3882 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003883 } else if (p != q) {
3884 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003885 p->next = q;
3886 q->prev = p;
3887 p = q;
3888 }
3889 node = node->next;
3890 }
3891 return(ret);
3892}
3893
3894/**
3895 * xmlCopyNode:
3896 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00003897 * @extended: if 1 do a recursive copy (properties, namespaces and children
3898 * when applicable)
3899 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00003900 *
3901 * Do a copy of the node.
3902 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003903 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003904 */
3905xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003906xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003907 xmlNodePtr ret;
3908
William M. Brack57e9e912004-03-09 16:19:02 +00003909 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00003910 return(ret);
3911}
3912
3913/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003914 * xmlDocCopyNode:
3915 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003916 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00003917 * @extended: if 1 do a recursive copy (properties, namespaces and children
3918 * when applicable)
3919 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00003920 *
3921 * Do a copy of the node to a given document.
3922 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003923 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003924 */
3925xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003926xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003927 xmlNodePtr ret;
3928
William M. Brack57e9e912004-03-09 16:19:02 +00003929 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00003930 return(ret);
3931}
3932
3933/**
Owen Taylor3473f882001-02-23 17:55:21 +00003934 * xmlCopyNodeList:
3935 * @node: the first node in the list.
3936 *
3937 * Do a recursive copy of the node list.
3938 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003939 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003940 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003941xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003942 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3943 return(ret);
3944}
3945
Daniel Veillard2156d432004-03-04 15:59:36 +00003946#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003947/**
Owen Taylor3473f882001-02-23 17:55:21 +00003948 * xmlCopyDtd:
3949 * @dtd: the dtd
3950 *
3951 * Do a copy of the dtd.
3952 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003953 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003954 */
3955xmlDtdPtr
3956xmlCopyDtd(xmlDtdPtr dtd) {
3957 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003958 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003959
3960 if (dtd == NULL) return(NULL);
3961 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3962 if (ret == NULL) return(NULL);
3963 if (dtd->entities != NULL)
3964 ret->entities = (void *) xmlCopyEntitiesTable(
3965 (xmlEntitiesTablePtr) dtd->entities);
3966 if (dtd->notations != NULL)
3967 ret->notations = (void *) xmlCopyNotationTable(
3968 (xmlNotationTablePtr) dtd->notations);
3969 if (dtd->elements != NULL)
3970 ret->elements = (void *) xmlCopyElementTable(
3971 (xmlElementTablePtr) dtd->elements);
3972 if (dtd->attributes != NULL)
3973 ret->attributes = (void *) xmlCopyAttributeTable(
3974 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003975 if (dtd->pentities != NULL)
3976 ret->pentities = (void *) xmlCopyEntitiesTable(
3977 (xmlEntitiesTablePtr) dtd->pentities);
3978
3979 cur = dtd->children;
3980 while (cur != NULL) {
3981 q = NULL;
3982
3983 if (cur->type == XML_ENTITY_DECL) {
3984 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3985 switch (tmp->etype) {
3986 case XML_INTERNAL_GENERAL_ENTITY:
3987 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3988 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3989 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3990 break;
3991 case XML_INTERNAL_PARAMETER_ENTITY:
3992 case XML_EXTERNAL_PARAMETER_ENTITY:
3993 q = (xmlNodePtr)
3994 xmlGetParameterEntityFromDtd(ret, tmp->name);
3995 break;
3996 case XML_INTERNAL_PREDEFINED_ENTITY:
3997 break;
3998 }
3999 } else if (cur->type == XML_ELEMENT_DECL) {
4000 xmlElementPtr tmp = (xmlElementPtr) cur;
4001 q = (xmlNodePtr)
4002 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4003 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4004 xmlAttributePtr tmp = (xmlAttributePtr) cur;
4005 q = (xmlNodePtr)
4006 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4007 } else if (cur->type == XML_COMMENT_NODE) {
4008 q = xmlCopyNode(cur, 0);
4009 }
4010
4011 if (q == NULL) {
4012 cur = cur->next;
4013 continue;
4014 }
4015
4016 if (p == NULL)
4017 ret->children = q;
4018 else
4019 p->next = q;
4020
4021 q->prev = p;
4022 q->parent = (xmlNodePtr) ret;
4023 q->next = NULL;
4024 ret->last = q;
4025 p = q;
4026 cur = cur->next;
4027 }
4028
Owen Taylor3473f882001-02-23 17:55:21 +00004029 return(ret);
4030}
Daniel Veillard2156d432004-03-04 15:59:36 +00004031#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004032
Daniel Veillard2156d432004-03-04 15:59:36 +00004033#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004034/**
4035 * xmlCopyDoc:
4036 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004037 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004038 *
4039 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004040 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004041 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004042 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004043 */
4044xmlDocPtr
4045xmlCopyDoc(xmlDocPtr doc, int recursive) {
4046 xmlDocPtr ret;
4047
4048 if (doc == NULL) return(NULL);
4049 ret = xmlNewDoc(doc->version);
4050 if (ret == NULL) return(NULL);
4051 if (doc->name != NULL)
4052 ret->name = xmlMemStrdup(doc->name);
4053 if (doc->encoding != NULL)
4054 ret->encoding = xmlStrdup(doc->encoding);
4055 ret->charset = doc->charset;
4056 ret->compression = doc->compression;
4057 ret->standalone = doc->standalone;
4058 if (!recursive) return(ret);
4059
Daniel Veillardb33c2012001-04-25 12:59:04 +00004060 ret->last = NULL;
4061 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004062#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004063 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004064 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004065 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004066 ret->intSubset->parent = ret;
4067 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004068#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004069 if (doc->oldNs != NULL)
4070 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4071 if (doc->children != NULL) {
4072 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004073
4074 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4075 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004076 ret->last = NULL;
4077 tmp = ret->children;
4078 while (tmp != NULL) {
4079 if (tmp->next == NULL)
4080 ret->last = tmp;
4081 tmp = tmp->next;
4082 }
4083 }
4084 return(ret);
4085}
Daniel Veillard652327a2003-09-29 18:02:38 +00004086#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004087
4088/************************************************************************
4089 * *
4090 * Content access functions *
4091 * *
4092 ************************************************************************/
4093
4094/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004095 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004096 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004097 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004098 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004099 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004100 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004101 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004102 */
4103long
4104xmlGetLineNo(xmlNodePtr node)
4105{
4106 long result = -1;
4107
4108 if (!node)
4109 return result;
4110 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004111 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004112 else if ((node->prev != NULL) &&
4113 ((node->prev->type == XML_ELEMENT_NODE) ||
4114 (node->prev->type == XML_TEXT_NODE)))
4115 result = xmlGetLineNo(node->prev);
4116 else if ((node->parent != NULL) &&
4117 ((node->parent->type == XML_ELEMENT_NODE) ||
4118 (node->parent->type == XML_TEXT_NODE)))
4119 result = xmlGetLineNo(node->parent);
4120
4121 return result;
4122}
4123
Daniel Veillard2156d432004-03-04 15:59:36 +00004124#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004125/**
4126 * xmlGetNodePath:
4127 * @node: a node
4128 *
4129 * Build a structure based Path for the given node
4130 *
4131 * Returns the new path or NULL in case of error. The caller must free
4132 * the returned string
4133 */
4134xmlChar *
4135xmlGetNodePath(xmlNodePtr node)
4136{
4137 xmlNodePtr cur, tmp, next;
4138 xmlChar *buffer = NULL, *temp;
4139 size_t buf_len;
4140 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004141 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004142 const char *name;
4143 char nametemp[100];
4144 int occur = 0;
4145
4146 if (node == NULL)
4147 return (NULL);
4148
4149 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004150 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004151 if (buffer == NULL) {
4152 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004153 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004154 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004155 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004156 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004157 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004158 xmlFree(buffer);
4159 return (NULL);
4160 }
4161
4162 buffer[0] = 0;
4163 cur = node;
4164 do {
4165 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004166 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004167 occur = 0;
4168 if ((cur->type == XML_DOCUMENT_NODE) ||
4169 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4170 if (buffer[0] == '/')
4171 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004172 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004173 next = NULL;
4174 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004175 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004176 name = (const char *) cur->name;
4177 if (cur->ns) {
William M. Brack84d83e32003-12-23 03:45:17 +00004178 if (cur->ns->prefix != NULL)
4179 snprintf(nametemp, sizeof(nametemp) - 1,
Daniel Veillard8faa7832001-11-26 15:58:08 +00004180 "%s:%s", cur->ns->prefix, cur->name);
William M. Brack84d83e32003-12-23 03:45:17 +00004181 else
4182 snprintf(nametemp, sizeof(nametemp) - 1,
4183 "%s", cur->name);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004184 nametemp[sizeof(nametemp) - 1] = 0;
4185 name = nametemp;
4186 }
4187 next = cur->parent;
4188
4189 /*
4190 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004191 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004192 */
4193 tmp = cur->prev;
4194 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004195 if ((tmp->type == XML_ELEMENT_NODE) &&
4196 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004197 occur++;
4198 tmp = tmp->prev;
4199 }
4200 if (occur == 0) {
4201 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004202 while (tmp != NULL && occur == 0) {
4203 if ((tmp->type == XML_ELEMENT_NODE) &&
4204 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004205 occur++;
4206 tmp = tmp->next;
4207 }
4208 if (occur != 0)
4209 occur = 1;
4210 } else
4211 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004212 } else if (cur->type == XML_COMMENT_NODE) {
4213 sep = "/";
4214 name = "comment()";
4215 next = cur->parent;
4216
4217 /*
4218 * Thumbler index computation
4219 */
4220 tmp = cur->prev;
4221 while (tmp != NULL) {
4222 if (tmp->type == XML_COMMENT_NODE)
4223 occur++;
4224 tmp = tmp->prev;
4225 }
4226 if (occur == 0) {
4227 tmp = cur->next;
4228 while (tmp != NULL && occur == 0) {
4229 if (tmp->type == XML_COMMENT_NODE)
4230 occur++;
4231 tmp = tmp->next;
4232 }
4233 if (occur != 0)
4234 occur = 1;
4235 } else
4236 occur++;
4237 } else if ((cur->type == XML_TEXT_NODE) ||
4238 (cur->type == XML_CDATA_SECTION_NODE)) {
4239 sep = "/";
4240 name = "text()";
4241 next = cur->parent;
4242
4243 /*
4244 * Thumbler index computation
4245 */
4246 tmp = cur->prev;
4247 while (tmp != NULL) {
4248 if ((cur->type == XML_TEXT_NODE) ||
4249 (cur->type == XML_CDATA_SECTION_NODE))
4250 occur++;
4251 tmp = tmp->prev;
4252 }
4253 if (occur == 0) {
4254 tmp = cur->next;
4255 while (tmp != NULL && occur == 0) {
4256 if ((cur->type == XML_TEXT_NODE) ||
4257 (cur->type == XML_CDATA_SECTION_NODE))
4258 occur++;
4259 tmp = tmp->next;
4260 }
4261 if (occur != 0)
4262 occur = 1;
4263 } else
4264 occur++;
4265 } else if (cur->type == XML_PI_NODE) {
4266 sep = "/";
4267 snprintf(nametemp, sizeof(nametemp) - 1,
4268 "processing-instruction('%s')", cur->name);
4269 nametemp[sizeof(nametemp) - 1] = 0;
4270 name = nametemp;
4271
4272 next = cur->parent;
4273
4274 /*
4275 * Thumbler index computation
4276 */
4277 tmp = cur->prev;
4278 while (tmp != NULL) {
4279 if ((tmp->type == XML_PI_NODE) &&
4280 (xmlStrEqual(cur->name, tmp->name)))
4281 occur++;
4282 tmp = tmp->prev;
4283 }
4284 if (occur == 0) {
4285 tmp = cur->next;
4286 while (tmp != NULL && occur == 0) {
4287 if ((tmp->type == XML_PI_NODE) &&
4288 (xmlStrEqual(cur->name, tmp->name)))
4289 occur++;
4290 tmp = tmp->next;
4291 }
4292 if (occur != 0)
4293 occur = 1;
4294 } else
4295 occur++;
4296
Daniel Veillard8faa7832001-11-26 15:58:08 +00004297 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004298 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004299 name = (const char *) (((xmlAttrPtr) cur)->name);
4300 next = ((xmlAttrPtr) cur)->parent;
4301 } else {
4302 next = cur->parent;
4303 }
4304
4305 /*
4306 * Make sure there is enough room
4307 */
4308 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4309 buf_len =
4310 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4311 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4312 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004313 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004314 xmlFree(buf);
4315 xmlFree(buffer);
4316 return (NULL);
4317 }
4318 buffer = temp;
4319 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4320 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004321 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004322 xmlFree(buf);
4323 xmlFree(buffer);
4324 return (NULL);
4325 }
4326 buf = temp;
4327 }
4328 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004329 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004330 sep, name, (char *) buffer);
4331 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004332 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004333 sep, name, occur, (char *) buffer);
4334 snprintf((char *) buffer, buf_len, "%s", buf);
4335 cur = next;
4336 } while (cur != NULL);
4337 xmlFree(buf);
4338 return (buffer);
4339}
Daniel Veillard652327a2003-09-29 18:02:38 +00004340#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004341
4342/**
Owen Taylor3473f882001-02-23 17:55:21 +00004343 * xmlDocGetRootElement:
4344 * @doc: the document
4345 *
4346 * Get the root element of the document (doc->children is a list
4347 * containing possibly comments, PIs, etc ...).
4348 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004349 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004350 */
4351xmlNodePtr
4352xmlDocGetRootElement(xmlDocPtr doc) {
4353 xmlNodePtr ret;
4354
4355 if (doc == NULL) return(NULL);
4356 ret = doc->children;
4357 while (ret != NULL) {
4358 if (ret->type == XML_ELEMENT_NODE)
4359 return(ret);
4360 ret = ret->next;
4361 }
4362 return(ret);
4363}
4364
Daniel Veillard2156d432004-03-04 15:59:36 +00004365#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004366/**
4367 * xmlDocSetRootElement:
4368 * @doc: the document
4369 * @root: the new document root element
4370 *
4371 * Set the root element of the document (doc->children is a list
4372 * containing possibly comments, PIs, etc ...).
4373 *
4374 * Returns the old root element if any was found
4375 */
4376xmlNodePtr
4377xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4378 xmlNodePtr old = NULL;
4379
4380 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004381 if (root == NULL)
4382 return(NULL);
4383 xmlUnlinkNode(root);
4384 root->doc = doc;
4385 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004386 old = doc->children;
4387 while (old != NULL) {
4388 if (old->type == XML_ELEMENT_NODE)
4389 break;
4390 old = old->next;
4391 }
4392 if (old == NULL) {
4393 if (doc->children == NULL) {
4394 doc->children = root;
4395 doc->last = root;
4396 } else {
4397 xmlAddSibling(doc->children, root);
4398 }
4399 } else {
4400 xmlReplaceNode(old, root);
4401 }
4402 return(old);
4403}
Daniel Veillard2156d432004-03-04 15:59:36 +00004404#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004405
Daniel Veillard2156d432004-03-04 15:59:36 +00004406#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004407/**
4408 * xmlNodeSetLang:
4409 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004410 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004411 *
4412 * Set the language of a node, i.e. the values of the xml:lang
4413 * attribute.
4414 */
4415void
4416xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004417 xmlNsPtr ns;
4418
Owen Taylor3473f882001-02-23 17:55:21 +00004419 if (cur == NULL) return;
4420 switch(cur->type) {
4421 case XML_TEXT_NODE:
4422 case XML_CDATA_SECTION_NODE:
4423 case XML_COMMENT_NODE:
4424 case XML_DOCUMENT_NODE:
4425 case XML_DOCUMENT_TYPE_NODE:
4426 case XML_DOCUMENT_FRAG_NODE:
4427 case XML_NOTATION_NODE:
4428 case XML_HTML_DOCUMENT_NODE:
4429 case XML_DTD_NODE:
4430 case XML_ELEMENT_DECL:
4431 case XML_ATTRIBUTE_DECL:
4432 case XML_ENTITY_DECL:
4433 case XML_PI_NODE:
4434 case XML_ENTITY_REF_NODE:
4435 case XML_ENTITY_NODE:
4436 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004437#ifdef LIBXML_DOCB_ENABLED
4438 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004439#endif
4440 case XML_XINCLUDE_START:
4441 case XML_XINCLUDE_END:
4442 return;
4443 case XML_ELEMENT_NODE:
4444 case XML_ATTRIBUTE_NODE:
4445 break;
4446 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004447 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4448 if (ns == NULL)
4449 return;
4450 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004451}
Daniel Veillard652327a2003-09-29 18:02:38 +00004452#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004453
4454/**
4455 * xmlNodeGetLang:
4456 * @cur: the node being checked
4457 *
4458 * Searches the language of a node, i.e. the values of the xml:lang
4459 * attribute or the one carried by the nearest ancestor.
4460 *
4461 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004462 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004463 */
4464xmlChar *
4465xmlNodeGetLang(xmlNodePtr cur) {
4466 xmlChar *lang;
4467
4468 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004469 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004470 if (lang != NULL)
4471 return(lang);
4472 cur = cur->parent;
4473 }
4474 return(NULL);
4475}
4476
4477
Daniel Veillard652327a2003-09-29 18:02:38 +00004478#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004479/**
4480 * xmlNodeSetSpacePreserve:
4481 * @cur: the node being changed
4482 * @val: the xml:space value ("0": default, 1: "preserve")
4483 *
4484 * Set (or reset) the space preserving behaviour of a node, i.e. the
4485 * value of the xml:space attribute.
4486 */
4487void
4488xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004489 xmlNsPtr ns;
4490
Owen Taylor3473f882001-02-23 17:55:21 +00004491 if (cur == NULL) return;
4492 switch(cur->type) {
4493 case XML_TEXT_NODE:
4494 case XML_CDATA_SECTION_NODE:
4495 case XML_COMMENT_NODE:
4496 case XML_DOCUMENT_NODE:
4497 case XML_DOCUMENT_TYPE_NODE:
4498 case XML_DOCUMENT_FRAG_NODE:
4499 case XML_NOTATION_NODE:
4500 case XML_HTML_DOCUMENT_NODE:
4501 case XML_DTD_NODE:
4502 case XML_ELEMENT_DECL:
4503 case XML_ATTRIBUTE_DECL:
4504 case XML_ENTITY_DECL:
4505 case XML_PI_NODE:
4506 case XML_ENTITY_REF_NODE:
4507 case XML_ENTITY_NODE:
4508 case XML_NAMESPACE_DECL:
4509 case XML_XINCLUDE_START:
4510 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004511#ifdef LIBXML_DOCB_ENABLED
4512 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004513#endif
4514 return;
4515 case XML_ELEMENT_NODE:
4516 case XML_ATTRIBUTE_NODE:
4517 break;
4518 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004519 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4520 if (ns == NULL)
4521 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004522 switch (val) {
4523 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004524 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004525 break;
4526 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004527 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004528 break;
4529 }
4530}
Daniel Veillard652327a2003-09-29 18:02:38 +00004531#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004532
4533/**
4534 * xmlNodeGetSpacePreserve:
4535 * @cur: the node being checked
4536 *
4537 * Searches the space preserving behaviour of a node, i.e. the values
4538 * of the xml:space attribute or the one carried by the nearest
4539 * ancestor.
4540 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004541 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004542 */
4543int
4544xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4545 xmlChar *space;
4546
4547 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004548 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004549 if (space != NULL) {
4550 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4551 xmlFree(space);
4552 return(1);
4553 }
4554 if (xmlStrEqual(space, BAD_CAST "default")) {
4555 xmlFree(space);
4556 return(0);
4557 }
4558 xmlFree(space);
4559 }
4560 cur = cur->parent;
4561 }
4562 return(-1);
4563}
4564
Daniel Veillard652327a2003-09-29 18:02:38 +00004565#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004566/**
4567 * xmlNodeSetName:
4568 * @cur: the node being changed
4569 * @name: the new tag name
4570 *
4571 * Set (or reset) the name of a node.
4572 */
4573void
4574xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4575 if (cur == NULL) return;
4576 if (name == NULL) return;
4577 switch(cur->type) {
4578 case XML_TEXT_NODE:
4579 case XML_CDATA_SECTION_NODE:
4580 case XML_COMMENT_NODE:
4581 case XML_DOCUMENT_TYPE_NODE:
4582 case XML_DOCUMENT_FRAG_NODE:
4583 case XML_NOTATION_NODE:
4584 case XML_HTML_DOCUMENT_NODE:
4585 case XML_NAMESPACE_DECL:
4586 case XML_XINCLUDE_START:
4587 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004588#ifdef LIBXML_DOCB_ENABLED
4589 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004590#endif
4591 return;
4592 case XML_ELEMENT_NODE:
4593 case XML_ATTRIBUTE_NODE:
4594 case XML_PI_NODE:
4595 case XML_ENTITY_REF_NODE:
4596 case XML_ENTITY_NODE:
4597 case XML_DTD_NODE:
4598 case XML_DOCUMENT_NODE:
4599 case XML_ELEMENT_DECL:
4600 case XML_ATTRIBUTE_DECL:
4601 case XML_ENTITY_DECL:
4602 break;
4603 }
4604 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4605 cur->name = xmlStrdup(name);
4606}
Daniel Veillard2156d432004-03-04 15:59:36 +00004607#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004608
Daniel Veillard2156d432004-03-04 15:59:36 +00004609#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004610/**
4611 * xmlNodeSetBase:
4612 * @cur: the node being changed
4613 * @uri: the new base URI
4614 *
4615 * Set (or reset) the base URI of a node, i.e. the value of the
4616 * xml:base attribute.
4617 */
4618void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004619xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004620 xmlNsPtr ns;
4621
Owen Taylor3473f882001-02-23 17:55:21 +00004622 if (cur == NULL) return;
4623 switch(cur->type) {
4624 case XML_TEXT_NODE:
4625 case XML_CDATA_SECTION_NODE:
4626 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004627 case XML_DOCUMENT_TYPE_NODE:
4628 case XML_DOCUMENT_FRAG_NODE:
4629 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004630 case XML_DTD_NODE:
4631 case XML_ELEMENT_DECL:
4632 case XML_ATTRIBUTE_DECL:
4633 case XML_ENTITY_DECL:
4634 case XML_PI_NODE:
4635 case XML_ENTITY_REF_NODE:
4636 case XML_ENTITY_NODE:
4637 case XML_NAMESPACE_DECL:
4638 case XML_XINCLUDE_START:
4639 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004640 return;
4641 case XML_ELEMENT_NODE:
4642 case XML_ATTRIBUTE_NODE:
4643 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004644 case XML_DOCUMENT_NODE:
4645#ifdef LIBXML_DOCB_ENABLED
4646 case XML_DOCB_DOCUMENT_NODE:
4647#endif
4648 case XML_HTML_DOCUMENT_NODE: {
4649 xmlDocPtr doc = (xmlDocPtr) cur;
4650
4651 if (doc->URL != NULL)
4652 xmlFree((xmlChar *) doc->URL);
4653 if (uri == NULL)
4654 doc->URL = NULL;
4655 else
4656 doc->URL = xmlStrdup(uri);
4657 return;
4658 }
Owen Taylor3473f882001-02-23 17:55:21 +00004659 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004660
4661 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4662 if (ns == NULL)
4663 return;
4664 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004665}
Daniel Veillard652327a2003-09-29 18:02:38 +00004666#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004667
4668/**
Owen Taylor3473f882001-02-23 17:55:21 +00004669 * xmlNodeGetBase:
4670 * @doc: the document the node pertains to
4671 * @cur: the node being checked
4672 *
4673 * Searches for the BASE URL. The code should work on both XML
4674 * and HTML document even if base mechanisms are completely different.
4675 * It returns the base as defined in RFC 2396 sections
4676 * 5.1.1. Base URI within Document Content
4677 * and
4678 * 5.1.2. Base URI from the Encapsulating Entity
4679 * However it does not return the document base (5.1.3), use
4680 * xmlDocumentGetBase() for this
4681 *
4682 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004683 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004684 */
4685xmlChar *
4686xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004687 xmlChar *oldbase = NULL;
4688 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004689
4690 if ((cur == NULL) && (doc == NULL))
4691 return(NULL);
4692 if (doc == NULL) doc = cur->doc;
4693 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4694 cur = doc->children;
4695 while ((cur != NULL) && (cur->name != NULL)) {
4696 if (cur->type != XML_ELEMENT_NODE) {
4697 cur = cur->next;
4698 continue;
4699 }
4700 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4701 cur = cur->children;
4702 continue;
4703 }
4704 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4705 cur = cur->children;
4706 continue;
4707 }
4708 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4709 return(xmlGetProp(cur, BAD_CAST "href"));
4710 }
4711 cur = cur->next;
4712 }
4713 return(NULL);
4714 }
4715 while (cur != NULL) {
4716 if (cur->type == XML_ENTITY_DECL) {
4717 xmlEntityPtr ent = (xmlEntityPtr) cur;
4718 return(xmlStrdup(ent->URI));
4719 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004720 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004721 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004722 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004723 if (oldbase != NULL) {
4724 newbase = xmlBuildURI(oldbase, base);
4725 if (newbase != NULL) {
4726 xmlFree(oldbase);
4727 xmlFree(base);
4728 oldbase = newbase;
4729 } else {
4730 xmlFree(oldbase);
4731 xmlFree(base);
4732 return(NULL);
4733 }
4734 } else {
4735 oldbase = base;
4736 }
4737 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4738 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4739 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4740 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004741 }
4742 }
Owen Taylor3473f882001-02-23 17:55:21 +00004743 cur = cur->parent;
4744 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004745 if ((doc != NULL) && (doc->URL != NULL)) {
4746 if (oldbase == NULL)
4747 return(xmlStrdup(doc->URL));
4748 newbase = xmlBuildURI(oldbase, doc->URL);
4749 xmlFree(oldbase);
4750 return(newbase);
4751 }
4752 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004753}
4754
4755/**
Daniel Veillard78697292003-10-19 20:44:43 +00004756 * xmlNodeBufGetContent:
4757 * @buffer: a buffer
4758 * @cur: the node being read
4759 *
4760 * Read the value of a node @cur, this can be either the text carried
4761 * directly by this node if it's a TEXT node or the aggregate string
4762 * of the values carried by this node child's (TEXT and ENTITY_REF).
4763 * Entity references are substituted.
4764 * Fills up the buffer @buffer with this value
4765 *
4766 * Returns 0 in case of success and -1 in case of error.
4767 */
4768int
4769xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4770{
4771 if ((cur == NULL) || (buffer == NULL)) return(-1);
4772 switch (cur->type) {
4773 case XML_CDATA_SECTION_NODE:
4774 case XML_TEXT_NODE:
4775 xmlBufferCat(buffer, cur->content);
4776 break;
4777 case XML_DOCUMENT_FRAG_NODE:
4778 case XML_ELEMENT_NODE:{
4779 xmlNodePtr tmp = cur;
4780
4781 while (tmp != NULL) {
4782 switch (tmp->type) {
4783 case XML_CDATA_SECTION_NODE:
4784 case XML_TEXT_NODE:
4785 if (tmp->content != NULL)
4786 xmlBufferCat(buffer, tmp->content);
4787 break;
4788 case XML_ENTITY_REF_NODE:
4789 xmlNodeBufGetContent(buffer, tmp->children);
4790 break;
4791 default:
4792 break;
4793 }
4794 /*
4795 * Skip to next node
4796 */
4797 if (tmp->children != NULL) {
4798 if (tmp->children->type != XML_ENTITY_DECL) {
4799 tmp = tmp->children;
4800 continue;
4801 }
4802 }
4803 if (tmp == cur)
4804 break;
4805
4806 if (tmp->next != NULL) {
4807 tmp = tmp->next;
4808 continue;
4809 }
4810
4811 do {
4812 tmp = tmp->parent;
4813 if (tmp == NULL)
4814 break;
4815 if (tmp == cur) {
4816 tmp = NULL;
4817 break;
4818 }
4819 if (tmp->next != NULL) {
4820 tmp = tmp->next;
4821 break;
4822 }
4823 } while (tmp != NULL);
4824 }
4825 break;
4826 }
4827 case XML_ATTRIBUTE_NODE:{
4828 xmlAttrPtr attr = (xmlAttrPtr) cur;
4829 xmlNodePtr tmp = attr->children;
4830
4831 while (tmp != NULL) {
4832 if (tmp->type == XML_TEXT_NODE)
4833 xmlBufferCat(buffer, tmp->content);
4834 else
4835 xmlNodeBufGetContent(buffer, tmp);
4836 tmp = tmp->next;
4837 }
4838 break;
4839 }
4840 case XML_COMMENT_NODE:
4841 case XML_PI_NODE:
4842 xmlBufferCat(buffer, cur->content);
4843 break;
4844 case XML_ENTITY_REF_NODE:{
4845 xmlEntityPtr ent;
4846 xmlNodePtr tmp;
4847
4848 /* lookup entity declaration */
4849 ent = xmlGetDocEntity(cur->doc, cur->name);
4850 if (ent == NULL)
4851 return(-1);
4852
4853 /* an entity content can be any "well balanced chunk",
4854 * i.e. the result of the content [43] production:
4855 * http://www.w3.org/TR/REC-xml#NT-content
4856 * -> we iterate through child nodes and recursive call
4857 * xmlNodeGetContent() which handles all possible node types */
4858 tmp = ent->children;
4859 while (tmp) {
4860 xmlNodeBufGetContent(buffer, tmp);
4861 tmp = tmp->next;
4862 }
4863 break;
4864 }
4865 case XML_ENTITY_NODE:
4866 case XML_DOCUMENT_TYPE_NODE:
4867 case XML_NOTATION_NODE:
4868 case XML_DTD_NODE:
4869 case XML_XINCLUDE_START:
4870 case XML_XINCLUDE_END:
4871 break;
4872 case XML_DOCUMENT_NODE:
4873#ifdef LIBXML_DOCB_ENABLED
4874 case XML_DOCB_DOCUMENT_NODE:
4875#endif
4876 case XML_HTML_DOCUMENT_NODE:
4877 cur = cur->children;
4878 while (cur!= NULL) {
4879 if ((cur->type == XML_ELEMENT_NODE) ||
4880 (cur->type == XML_TEXT_NODE) ||
4881 (cur->type == XML_CDATA_SECTION_NODE)) {
4882 xmlNodeBufGetContent(buffer, cur);
4883 }
4884 cur = cur->next;
4885 }
4886 break;
4887 case XML_NAMESPACE_DECL:
4888 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
4889 break;
4890 case XML_ELEMENT_DECL:
4891 case XML_ATTRIBUTE_DECL:
4892 case XML_ENTITY_DECL:
4893 break;
4894 }
4895 return(0);
4896}
4897/**
Owen Taylor3473f882001-02-23 17:55:21 +00004898 * xmlNodeGetContent:
4899 * @cur: the node being read
4900 *
4901 * Read the value of a node, this can be either the text carried
4902 * directly by this node if it's a TEXT node or the aggregate string
4903 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004904 * Entity references are substituted.
4905 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004906 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004907 */
4908xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004909xmlNodeGetContent(xmlNodePtr cur)
4910{
4911 if (cur == NULL)
4912 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004913 switch (cur->type) {
4914 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004915 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00004916 xmlBufferPtr buffer;
4917 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004918
Daniel Veillard814a76d2003-01-23 18:24:20 +00004919 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004920 if (buffer == NULL)
4921 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00004922 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004923 ret = buffer->content;
4924 buffer->content = NULL;
4925 xmlBufferFree(buffer);
4926 return (ret);
4927 }
4928 case XML_ATTRIBUTE_NODE:{
4929 xmlAttrPtr attr = (xmlAttrPtr) cur;
4930
4931 if (attr->parent != NULL)
4932 return (xmlNodeListGetString
4933 (attr->parent->doc, attr->children, 1));
4934 else
4935 return (xmlNodeListGetString(NULL, attr->children, 1));
4936 break;
4937 }
Owen Taylor3473f882001-02-23 17:55:21 +00004938 case XML_COMMENT_NODE:
4939 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004940 if (cur->content != NULL)
4941 return (xmlStrdup(cur->content));
4942 return (NULL);
4943 case XML_ENTITY_REF_NODE:{
4944 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00004945 xmlBufferPtr buffer;
4946 xmlChar *ret;
4947
4948 /* lookup entity declaration */
4949 ent = xmlGetDocEntity(cur->doc, cur->name);
4950 if (ent == NULL)
4951 return (NULL);
4952
4953 buffer = xmlBufferCreate();
4954 if (buffer == NULL)
4955 return (NULL);
4956
Daniel Veillardc4696922003-10-19 21:47:14 +00004957 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004958
4959 ret = buffer->content;
4960 buffer->content = NULL;
4961 xmlBufferFree(buffer);
4962 return (ret);
4963 }
Owen Taylor3473f882001-02-23 17:55:21 +00004964 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004965 case XML_DOCUMENT_TYPE_NODE:
4966 case XML_NOTATION_NODE:
4967 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004968 case XML_XINCLUDE_START:
4969 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00004970 return (NULL);
4971 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004972#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004973 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004974#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00004975 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00004976 xmlBufferPtr buffer;
4977 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00004978
Daniel Veillardc4696922003-10-19 21:47:14 +00004979 buffer = xmlBufferCreate();
4980 if (buffer == NULL)
4981 return (NULL);
4982
4983 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
4984
4985 ret = buffer->content;
4986 buffer->content = NULL;
4987 xmlBufferFree(buffer);
4988 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004989 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004990 case XML_NAMESPACE_DECL: {
4991 xmlChar *tmp;
4992
4993 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4994 return (tmp);
4995 }
Owen Taylor3473f882001-02-23 17:55:21 +00004996 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004997 /* TODO !!! */
4998 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004999 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005000 /* TODO !!! */
5001 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005002 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005003 /* TODO !!! */
5004 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005005 case XML_CDATA_SECTION_NODE:
5006 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005007 if (cur->content != NULL)
5008 return (xmlStrdup(cur->content));
5009 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005010 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005011 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005012}
Daniel Veillard652327a2003-09-29 18:02:38 +00005013
Owen Taylor3473f882001-02-23 17:55:21 +00005014/**
5015 * xmlNodeSetContent:
5016 * @cur: the node being modified
5017 * @content: the new value of the content
5018 *
5019 * Replace the content of a node.
5020 */
5021void
5022xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5023 if (cur == NULL) {
5024#ifdef DEBUG_TREE
5025 xmlGenericError(xmlGenericErrorContext,
5026 "xmlNodeSetContent : node == NULL\n");
5027#endif
5028 return;
5029 }
5030 switch (cur->type) {
5031 case XML_DOCUMENT_FRAG_NODE:
5032 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005033 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005034 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5035 cur->children = xmlStringGetNodeList(cur->doc, content);
5036 UPDATE_LAST_CHILD_AND_PARENT(cur)
5037 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005038 case XML_TEXT_NODE:
5039 case XML_CDATA_SECTION_NODE:
5040 case XML_ENTITY_REF_NODE:
5041 case XML_ENTITY_NODE:
5042 case XML_PI_NODE:
5043 case XML_COMMENT_NODE:
5044 if (cur->content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005045 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5046 xmlDictOwns(cur->doc->dict, cur->content)))
5047 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005048 }
5049 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5050 cur->last = cur->children = NULL;
5051 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005052 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005053 } else
5054 cur->content = NULL;
5055 break;
5056 case XML_DOCUMENT_NODE:
5057 case XML_HTML_DOCUMENT_NODE:
5058 case XML_DOCUMENT_TYPE_NODE:
5059 case XML_XINCLUDE_START:
5060 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005061#ifdef LIBXML_DOCB_ENABLED
5062 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005063#endif
5064 break;
5065 case XML_NOTATION_NODE:
5066 break;
5067 case XML_DTD_NODE:
5068 break;
5069 case XML_NAMESPACE_DECL:
5070 break;
5071 case XML_ELEMENT_DECL:
5072 /* TODO !!! */
5073 break;
5074 case XML_ATTRIBUTE_DECL:
5075 /* TODO !!! */
5076 break;
5077 case XML_ENTITY_DECL:
5078 /* TODO !!! */
5079 break;
5080 }
5081}
5082
Daniel Veillard652327a2003-09-29 18:02:38 +00005083#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005084/**
5085 * xmlNodeSetContentLen:
5086 * @cur: the node being modified
5087 * @content: the new value of the content
5088 * @len: the size of @content
5089 *
5090 * Replace the content of a node.
5091 */
5092void
5093xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5094 if (cur == NULL) {
5095#ifdef DEBUG_TREE
5096 xmlGenericError(xmlGenericErrorContext,
5097 "xmlNodeSetContentLen : node == NULL\n");
5098#endif
5099 return;
5100 }
5101 switch (cur->type) {
5102 case XML_DOCUMENT_FRAG_NODE:
5103 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005104 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005105 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5106 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5107 UPDATE_LAST_CHILD_AND_PARENT(cur)
5108 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005109 case XML_TEXT_NODE:
5110 case XML_CDATA_SECTION_NODE:
5111 case XML_ENTITY_REF_NODE:
5112 case XML_ENTITY_NODE:
5113 case XML_PI_NODE:
5114 case XML_COMMENT_NODE:
5115 case XML_NOTATION_NODE:
5116 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005117 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005118 }
5119 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5120 cur->children = cur->last = NULL;
5121 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005122 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005123 } else
5124 cur->content = NULL;
5125 break;
5126 case XML_DOCUMENT_NODE:
5127 case XML_DTD_NODE:
5128 case XML_HTML_DOCUMENT_NODE:
5129 case XML_DOCUMENT_TYPE_NODE:
5130 case XML_NAMESPACE_DECL:
5131 case XML_XINCLUDE_START:
5132 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005133#ifdef LIBXML_DOCB_ENABLED
5134 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005135#endif
5136 break;
5137 case XML_ELEMENT_DECL:
5138 /* TODO !!! */
5139 break;
5140 case XML_ATTRIBUTE_DECL:
5141 /* TODO !!! */
5142 break;
5143 case XML_ENTITY_DECL:
5144 /* TODO !!! */
5145 break;
5146 }
5147}
Daniel Veillard652327a2003-09-29 18:02:38 +00005148#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005149
5150/**
5151 * xmlNodeAddContentLen:
5152 * @cur: the node being modified
5153 * @content: extra content
5154 * @len: the size of @content
5155 *
5156 * Append the extra substring to the node content.
5157 */
5158void
5159xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5160 if (cur == NULL) {
5161#ifdef DEBUG_TREE
5162 xmlGenericError(xmlGenericErrorContext,
5163 "xmlNodeAddContentLen : node == NULL\n");
5164#endif
5165 return;
5166 }
5167 if (len <= 0) return;
5168 switch (cur->type) {
5169 case XML_DOCUMENT_FRAG_NODE:
5170 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005171 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005172
Daniel Veillard7db37732001-07-12 01:20:08 +00005173 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005174 newNode = xmlNewTextLen(content, len);
5175 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005176 tmp = xmlAddChild(cur, newNode);
5177 if (tmp != newNode)
5178 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005179 if ((last != NULL) && (last->next == newNode)) {
5180 xmlTextMerge(last, newNode);
5181 }
5182 }
5183 break;
5184 }
5185 case XML_ATTRIBUTE_NODE:
5186 break;
5187 case XML_TEXT_NODE:
5188 case XML_CDATA_SECTION_NODE:
5189 case XML_ENTITY_REF_NODE:
5190 case XML_ENTITY_NODE:
5191 case XML_PI_NODE:
5192 case XML_COMMENT_NODE:
5193 case XML_NOTATION_NODE:
5194 if (content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005195 if ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5196 xmlDictOwns(cur->doc->dict, cur->content)) {
5197 cur->content =
5198 xmlStrncatNew(cur->content, content, len);
5199 break;
5200 }
Owen Taylor3473f882001-02-23 17:55:21 +00005201 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005202 }
5203 case XML_DOCUMENT_NODE:
5204 case XML_DTD_NODE:
5205 case XML_HTML_DOCUMENT_NODE:
5206 case XML_DOCUMENT_TYPE_NODE:
5207 case XML_NAMESPACE_DECL:
5208 case XML_XINCLUDE_START:
5209 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005210#ifdef LIBXML_DOCB_ENABLED
5211 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005212#endif
5213 break;
5214 case XML_ELEMENT_DECL:
5215 case XML_ATTRIBUTE_DECL:
5216 case XML_ENTITY_DECL:
5217 break;
5218 }
5219}
5220
5221/**
5222 * xmlNodeAddContent:
5223 * @cur: the node being modified
5224 * @content: extra content
5225 *
5226 * Append the extra substring to the node content.
5227 */
5228void
5229xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5230 int len;
5231
5232 if (cur == NULL) {
5233#ifdef DEBUG_TREE
5234 xmlGenericError(xmlGenericErrorContext,
5235 "xmlNodeAddContent : node == NULL\n");
5236#endif
5237 return;
5238 }
5239 if (content == NULL) return;
5240 len = xmlStrlen(content);
5241 xmlNodeAddContentLen(cur, content, len);
5242}
5243
5244/**
5245 * xmlTextMerge:
5246 * @first: the first text node
5247 * @second: the second text node being merged
5248 *
5249 * Merge two text nodes into one
5250 * Returns the first text node augmented
5251 */
5252xmlNodePtr
5253xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5254 if (first == NULL) return(second);
5255 if (second == NULL) return(first);
5256 if (first->type != XML_TEXT_NODE) return(first);
5257 if (second->type != XML_TEXT_NODE) return(first);
5258 if (second->name != first->name)
5259 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005260 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005261 xmlUnlinkNode(second);
5262 xmlFreeNode(second);
5263 return(first);
5264}
5265
Daniel Veillard2156d432004-03-04 15:59:36 +00005266#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005267/**
5268 * xmlGetNsList:
5269 * @doc: the document
5270 * @node: the current node
5271 *
5272 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005273 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005274 * that need to be freed by the caller or NULL if no
5275 * namespace if defined
5276 */
5277xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005278xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5279{
Owen Taylor3473f882001-02-23 17:55:21 +00005280 xmlNsPtr cur;
5281 xmlNsPtr *ret = NULL;
5282 int nbns = 0;
5283 int maxns = 10;
5284 int i;
5285
5286 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005287 if (node->type == XML_ELEMENT_NODE) {
5288 cur = node->nsDef;
5289 while (cur != NULL) {
5290 if (ret == NULL) {
5291 ret =
5292 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5293 sizeof(xmlNsPtr));
5294 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005295 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005296 return (NULL);
5297 }
5298 ret[nbns] = NULL;
5299 }
5300 for (i = 0; i < nbns; i++) {
5301 if ((cur->prefix == ret[i]->prefix) ||
5302 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5303 break;
5304 }
5305 if (i >= nbns) {
5306 if (nbns >= maxns) {
5307 maxns *= 2;
5308 ret = (xmlNsPtr *) xmlRealloc(ret,
5309 (maxns +
5310 1) *
5311 sizeof(xmlNsPtr));
5312 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005313 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005314 return (NULL);
5315 }
5316 }
5317 ret[nbns++] = cur;
5318 ret[nbns] = NULL;
5319 }
Owen Taylor3473f882001-02-23 17:55:21 +00005320
Daniel Veillard77044732001-06-29 21:31:07 +00005321 cur = cur->next;
5322 }
5323 }
5324 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005325 }
Daniel Veillard77044732001-06-29 21:31:07 +00005326 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005327}
Daniel Veillard652327a2003-09-29 18:02:38 +00005328#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005329
5330/**
5331 * xmlSearchNs:
5332 * @doc: the document
5333 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005334 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005335 *
5336 * Search a Ns registered under a given name space for a document.
5337 * recurse on the parents until it finds the defined namespace
5338 * or return NULL otherwise.
5339 * @nameSpace can be NULL, this is a search for the default namespace.
5340 * We don't allow to cross entities boundaries. If you don't declare
5341 * the namespace within those you will be in troubles !!! A warning
5342 * is generated to cover this case.
5343 *
5344 * Returns the namespace pointer or NULL.
5345 */
5346xmlNsPtr
5347xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005348
Owen Taylor3473f882001-02-23 17:55:21 +00005349 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005350 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005351
5352 if (node == NULL) return(NULL);
5353 if ((nameSpace != NULL) &&
5354 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005355 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5356 /*
5357 * The XML-1.0 namespace is normally held on the root
5358 * element. In this case exceptionally create it on the
5359 * node element.
5360 */
5361 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5362 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005363 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005364 return(NULL);
5365 }
5366 memset(cur, 0, sizeof(xmlNs));
5367 cur->type = XML_LOCAL_NAMESPACE;
5368 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5369 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5370 cur->next = node->nsDef;
5371 node->nsDef = cur;
5372 return(cur);
5373 }
Owen Taylor3473f882001-02-23 17:55:21 +00005374 if (doc->oldNs == NULL) {
5375 /*
5376 * Allocate a new Namespace and fill the fields.
5377 */
5378 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5379 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005380 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005381 return(NULL);
5382 }
5383 memset(doc->oldNs, 0, sizeof(xmlNs));
5384 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5385
5386 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5387 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5388 }
5389 return(doc->oldNs);
5390 }
5391 while (node != NULL) {
5392 if ((node->type == XML_ENTITY_REF_NODE) ||
5393 (node->type == XML_ENTITY_NODE) ||
5394 (node->type == XML_ENTITY_DECL))
5395 return(NULL);
5396 if (node->type == XML_ELEMENT_NODE) {
5397 cur = node->nsDef;
5398 while (cur != NULL) {
5399 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5400 (cur->href != NULL))
5401 return(cur);
5402 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5403 (cur->href != NULL) &&
5404 (xmlStrEqual(cur->prefix, nameSpace)))
5405 return(cur);
5406 cur = cur->next;
5407 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005408 if (orig != node) {
5409 cur = node->ns;
5410 if (cur != NULL) {
5411 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5412 (cur->href != NULL))
5413 return(cur);
5414 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5415 (cur->href != NULL) &&
5416 (xmlStrEqual(cur->prefix, nameSpace)))
5417 return(cur);
5418 }
5419 }
Owen Taylor3473f882001-02-23 17:55:21 +00005420 }
5421 node = node->parent;
5422 }
5423 return(NULL);
5424}
5425
5426/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005427 * xmlNsInScope:
5428 * @doc: the document
5429 * @node: the current node
5430 * @ancestor: the ancestor carrying the namespace
5431 * @prefix: the namespace prefix
5432 *
5433 * Verify that the given namespace held on @ancestor is still in scope
5434 * on node.
5435 *
5436 * Returns 1 if true, 0 if false and -1 in case of error.
5437 */
5438static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005439xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5440 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005441{
5442 xmlNsPtr tst;
5443
5444 while ((node != NULL) && (node != ancestor)) {
5445 if ((node->type == XML_ENTITY_REF_NODE) ||
5446 (node->type == XML_ENTITY_NODE) ||
5447 (node->type == XML_ENTITY_DECL))
5448 return (-1);
5449 if (node->type == XML_ELEMENT_NODE) {
5450 tst = node->nsDef;
5451 while (tst != NULL) {
5452 if ((tst->prefix == NULL)
5453 && (prefix == NULL))
5454 return (0);
5455 if ((tst->prefix != NULL)
5456 && (prefix != NULL)
5457 && (xmlStrEqual(tst->prefix, prefix)))
5458 return (0);
5459 tst = tst->next;
5460 }
5461 }
5462 node = node->parent;
5463 }
5464 if (node != ancestor)
5465 return (-1);
5466 return (1);
5467}
5468
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005469/**
Owen Taylor3473f882001-02-23 17:55:21 +00005470 * xmlSearchNsByHref:
5471 * @doc: the document
5472 * @node: the current node
5473 * @href: the namespace value
5474 *
5475 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5476 * the defined namespace or return NULL otherwise.
5477 * Returns the namespace pointer or NULL.
5478 */
5479xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005480xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5481{
Owen Taylor3473f882001-02-23 17:55:21 +00005482 xmlNsPtr cur;
5483 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005484 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005485
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005486 if ((node == NULL) || (href == NULL))
5487 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005488 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005489 /*
5490 * Only the document can hold the XML spec namespace.
5491 */
5492 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5493 /*
5494 * The XML-1.0 namespace is normally held on the root
5495 * element. In this case exceptionally create it on the
5496 * node element.
5497 */
5498 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5499 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005500 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005501 return (NULL);
5502 }
5503 memset(cur, 0, sizeof(xmlNs));
5504 cur->type = XML_LOCAL_NAMESPACE;
5505 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5506 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5507 cur->next = node->nsDef;
5508 node->nsDef = cur;
5509 return (cur);
5510 }
5511 if (doc->oldNs == NULL) {
5512 /*
5513 * Allocate a new Namespace and fill the fields.
5514 */
5515 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5516 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005517 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005518 return (NULL);
5519 }
5520 memset(doc->oldNs, 0, sizeof(xmlNs));
5521 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005522
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005523 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5524 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5525 }
5526 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005527 }
Daniel Veillard62040be2004-05-17 03:17:26 +00005528 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00005529 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005530 if ((node->type == XML_ENTITY_REF_NODE) ||
5531 (node->type == XML_ENTITY_NODE) ||
5532 (node->type == XML_ENTITY_DECL))
5533 return (NULL);
5534 if (node->type == XML_ELEMENT_NODE) {
5535 cur = node->nsDef;
5536 while (cur != NULL) {
5537 if ((cur->href != NULL) && (href != NULL) &&
5538 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005539 if (((!is_attr) || (cur->prefix != NULL)) &&
5540 (xmlNsInScope(doc, orig, node, cur->href) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005541 return (cur);
5542 }
5543 cur = cur->next;
5544 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005545 if (orig != node) {
5546 cur = node->ns;
5547 if (cur != NULL) {
5548 if ((cur->href != NULL) && (href != NULL) &&
5549 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005550 if (((!is_attr) || (cur->prefix != NULL)) &&
5551 (xmlNsInScope(doc, orig, node, cur->href) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00005552 return (cur);
5553 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005554 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005555 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005556 }
5557 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005558 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005559 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005560}
5561
5562/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005563 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005564 * @doc: the document
5565 * @tree: a node expected to hold the new namespace
5566 * @ns: the original namespace
5567 *
5568 * This function tries to locate a namespace definition in a tree
5569 * ancestors, or create a new namespace definition node similar to
5570 * @ns trying to reuse the same prefix. However if the given prefix is
5571 * null (default namespace) or reused within the subtree defined by
5572 * @tree or on one of its ancestors then a new prefix is generated.
5573 * Returns the (new) namespace definition or NULL in case of error
5574 */
5575xmlNsPtr
5576xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5577 xmlNsPtr def;
5578 xmlChar prefix[50];
5579 int counter = 1;
5580
5581 if (tree == NULL) {
5582#ifdef DEBUG_TREE
5583 xmlGenericError(xmlGenericErrorContext,
5584 "xmlNewReconciliedNs : tree == NULL\n");
5585#endif
5586 return(NULL);
5587 }
5588 if (ns == NULL) {
5589#ifdef DEBUG_TREE
5590 xmlGenericError(xmlGenericErrorContext,
5591 "xmlNewReconciliedNs : ns == NULL\n");
5592#endif
5593 return(NULL);
5594 }
5595 /*
5596 * Search an existing namespace definition inherited.
5597 */
5598 def = xmlSearchNsByHref(doc, tree, ns->href);
5599 if (def != NULL)
5600 return(def);
5601
5602 /*
5603 * Find a close prefix which is not already in use.
5604 * Let's strip namespace prefixes longer than 20 chars !
5605 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005606 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005607 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005608 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005609 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005610
Owen Taylor3473f882001-02-23 17:55:21 +00005611 def = xmlSearchNs(doc, tree, prefix);
5612 while (def != NULL) {
5613 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005614 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005615 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005616 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005617 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005618 def = xmlSearchNs(doc, tree, prefix);
5619 }
5620
5621 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005622 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005623 */
5624 def = xmlNewNs(tree, ns->href, prefix);
5625 return(def);
5626}
5627
Daniel Veillard652327a2003-09-29 18:02:38 +00005628#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005629/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005630 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005631 * @doc: the document
5632 * @tree: a node defining the subtree to reconciliate
5633 *
5634 * This function checks that all the namespaces declared within the given
5635 * tree are properly declared. This is needed for example after Copy or Cut
5636 * and then paste operations. The subtree may still hold pointers to
5637 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005638 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005639 * the new environment. If not possible the new namespaces are redeclared
5640 * on @tree at the top of the given subtree.
5641 * Returns the number of namespace declarations created or -1 in case of error.
5642 */
5643int
5644xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5645 xmlNsPtr *oldNs = NULL;
5646 xmlNsPtr *newNs = NULL;
5647 int sizeCache = 0;
5648 int nbCache = 0;
5649
5650 xmlNsPtr n;
5651 xmlNodePtr node = tree;
5652 xmlAttrPtr attr;
5653 int ret = 0, i;
5654
5655 while (node != NULL) {
5656 /*
5657 * Reconciliate the node namespace
5658 */
5659 if (node->ns != NULL) {
5660 /*
5661 * initialize the cache if needed
5662 */
5663 if (sizeCache == 0) {
5664 sizeCache = 10;
5665 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5666 sizeof(xmlNsPtr));
5667 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005668 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005669 return(-1);
5670 }
5671 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5672 sizeof(xmlNsPtr));
5673 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005674 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005675 xmlFree(oldNs);
5676 return(-1);
5677 }
5678 }
5679 for (i = 0;i < nbCache;i++) {
5680 if (oldNs[i] == node->ns) {
5681 node->ns = newNs[i];
5682 break;
5683 }
5684 }
5685 if (i == nbCache) {
5686 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005687 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005688 */
5689 n = xmlNewReconciliedNs(doc, tree, node->ns);
5690 if (n != NULL) { /* :-( what if else ??? */
5691 /*
5692 * check if we need to grow the cache buffers.
5693 */
5694 if (sizeCache <= nbCache) {
5695 sizeCache *= 2;
5696 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5697 sizeof(xmlNsPtr));
5698 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005699 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005700 xmlFree(newNs);
5701 return(-1);
5702 }
5703 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5704 sizeof(xmlNsPtr));
5705 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005706 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005707 xmlFree(oldNs);
5708 return(-1);
5709 }
5710 }
5711 newNs[nbCache] = n;
5712 oldNs[nbCache++] = node->ns;
5713 node->ns = n;
5714 }
5715 }
5716 }
5717 /*
5718 * now check for namespace hold by attributes on the node.
5719 */
5720 attr = node->properties;
5721 while (attr != NULL) {
5722 if (attr->ns != NULL) {
5723 /*
5724 * initialize the cache if needed
5725 */
5726 if (sizeCache == 0) {
5727 sizeCache = 10;
5728 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5729 sizeof(xmlNsPtr));
5730 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005731 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005732 return(-1);
5733 }
5734 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5735 sizeof(xmlNsPtr));
5736 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005737 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005738 xmlFree(oldNs);
5739 return(-1);
5740 }
5741 }
5742 for (i = 0;i < nbCache;i++) {
5743 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005744 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005745 break;
5746 }
5747 }
5748 if (i == nbCache) {
5749 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005750 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005751 */
5752 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5753 if (n != NULL) { /* :-( what if else ??? */
5754 /*
5755 * check if we need to grow the cache buffers.
5756 */
5757 if (sizeCache <= nbCache) {
5758 sizeCache *= 2;
5759 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5760 sizeof(xmlNsPtr));
5761 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005762 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005763 xmlFree(newNs);
5764 return(-1);
5765 }
5766 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5767 sizeof(xmlNsPtr));
5768 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005769 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005770 xmlFree(oldNs);
5771 return(-1);
5772 }
5773 }
5774 newNs[nbCache] = n;
5775 oldNs[nbCache++] = attr->ns;
5776 attr->ns = n;
5777 }
5778 }
5779 }
5780 attr = attr->next;
5781 }
5782
5783 /*
5784 * Browse the full subtree, deep first
5785 */
5786 if (node->children != NULL) {
5787 /* deep first */
5788 node = node->children;
5789 } else if ((node != tree) && (node->next != NULL)) {
5790 /* then siblings */
5791 node = node->next;
5792 } else if (node != tree) {
5793 /* go up to parents->next if needed */
5794 while (node != tree) {
5795 if (node->parent != NULL)
5796 node = node->parent;
5797 if ((node != tree) && (node->next != NULL)) {
5798 node = node->next;
5799 break;
5800 }
5801 if (node->parent == NULL) {
5802 node = NULL;
5803 break;
5804 }
5805 }
5806 /* exit condition */
5807 if (node == tree)
5808 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005809 } else
5810 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005811 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005812 if (oldNs != NULL)
5813 xmlFree(oldNs);
5814 if (newNs != NULL)
5815 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005816 return(ret);
5817}
Daniel Veillard652327a2003-09-29 18:02:38 +00005818#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005819
5820/**
5821 * xmlHasProp:
5822 * @node: the node
5823 * @name: the attribute name
5824 *
5825 * Search an attribute associated to a node
5826 * This function also looks in DTD attribute declaration for #FIXED or
5827 * default declaration values unless DTD use has been turned off.
5828 *
5829 * Returns the attribute or the attribute declaration or NULL if
5830 * neither was found.
5831 */
5832xmlAttrPtr
5833xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5834 xmlAttrPtr prop;
5835 xmlDocPtr doc;
5836
5837 if ((node == NULL) || (name == NULL)) return(NULL);
5838 /*
5839 * Check on the properties attached to the node
5840 */
5841 prop = node->properties;
5842 while (prop != NULL) {
5843 if (xmlStrEqual(prop->name, name)) {
5844 return(prop);
5845 }
5846 prop = prop->next;
5847 }
5848 if (!xmlCheckDTD) return(NULL);
5849
5850 /*
5851 * Check if there is a default declaration in the internal
5852 * or external subsets
5853 */
5854 doc = node->doc;
5855 if (doc != NULL) {
5856 xmlAttributePtr attrDecl;
5857 if (doc->intSubset != NULL) {
5858 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5859 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5860 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005861 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5862 /* return attribute declaration only if a default value is given
5863 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005864 return((xmlAttrPtr) attrDecl);
5865 }
5866 }
5867 return(NULL);
5868}
5869
5870/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005871 * xmlHasNsProp:
5872 * @node: the node
5873 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005874 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005875 *
5876 * Search for an attribute associated to a node
5877 * This attribute has to be anchored in the namespace specified.
5878 * This does the entity substitution.
5879 * This function looks in DTD attribute declaration for #FIXED or
5880 * default declaration values unless DTD use has been turned off.
5881 *
5882 * Returns the attribute or the attribute declaration or NULL
5883 * if neither was found.
5884 */
5885xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005886xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005887 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00005888#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005889 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00005890#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005891
5892 if (node == NULL)
5893 return(NULL);
5894
5895 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005896 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005897 return(xmlHasProp(node, name));
5898 while (prop != NULL) {
5899 /*
5900 * One need to have
5901 * - same attribute names
5902 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005903 */
5904 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005905 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5906 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005907 }
5908 prop = prop->next;
5909 }
5910 if (!xmlCheckDTD) return(NULL);
5911
Daniel Veillard652327a2003-09-29 18:02:38 +00005912#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005913 /*
5914 * Check if there is a default declaration in the internal
5915 * or external subsets
5916 */
5917 doc = node->doc;
5918 if (doc != NULL) {
5919 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005920 xmlAttributePtr attrDecl = NULL;
5921 xmlNsPtr *nsList, *cur;
5922 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005923
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005924 nsList = xmlGetNsList(node->doc, node);
5925 if (nsList == NULL)
5926 return(NULL);
5927 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5928 ename = xmlStrdup(node->ns->prefix);
5929 ename = xmlStrcat(ename, BAD_CAST ":");
5930 ename = xmlStrcat(ename, node->name);
5931 } else {
5932 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005933 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005934 if (ename == NULL) {
5935 xmlFree(nsList);
5936 return(NULL);
5937 }
5938
5939 cur = nsList;
5940 while (*cur != NULL) {
5941 if (xmlStrEqual((*cur)->href, nameSpace)) {
5942 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5943 name, (*cur)->prefix);
5944 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5945 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5946 name, (*cur)->prefix);
5947 }
5948 cur++;
5949 }
5950 xmlFree(nsList);
5951 xmlFree(ename);
5952 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005953 }
5954 }
Daniel Veillard652327a2003-09-29 18:02:38 +00005955#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005956 return(NULL);
5957}
5958
5959/**
Owen Taylor3473f882001-02-23 17:55:21 +00005960 * xmlGetProp:
5961 * @node: the node
5962 * @name: the attribute name
5963 *
5964 * Search and get the value of an attribute associated to a node
5965 * This does the entity substitution.
5966 * This function looks in DTD attribute declaration for #FIXED or
5967 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00005968 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00005969 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5970 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005971 *
5972 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005973 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005974 */
5975xmlChar *
5976xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5977 xmlAttrPtr prop;
5978 xmlDocPtr doc;
5979
5980 if ((node == NULL) || (name == NULL)) return(NULL);
5981 /*
5982 * Check on the properties attached to the node
5983 */
5984 prop = node->properties;
5985 while (prop != NULL) {
5986 if (xmlStrEqual(prop->name, name)) {
5987 xmlChar *ret;
5988
5989 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5990 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5991 return(ret);
5992 }
5993 prop = prop->next;
5994 }
5995 if (!xmlCheckDTD) return(NULL);
5996
5997 /*
5998 * Check if there is a default declaration in the internal
5999 * or external subsets
6000 */
6001 doc = node->doc;
6002 if (doc != NULL) {
6003 xmlAttributePtr attrDecl;
6004 if (doc->intSubset != NULL) {
6005 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6006 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6007 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006008 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6009 /* return attribute declaration only if a default value is given
6010 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006011 return(xmlStrdup(attrDecl->defaultValue));
6012 }
6013 }
6014 return(NULL);
6015}
6016
6017/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006018 * xmlGetNoNsProp:
6019 * @node: the node
6020 * @name: the attribute name
6021 *
6022 * Search and get the value of an attribute associated to a node
6023 * This does the entity substitution.
6024 * This function looks in DTD attribute declaration for #FIXED or
6025 * default declaration values unless DTD use has been turned off.
6026 * This function is similar to xmlGetProp except it will accept only
6027 * an attribute in no namespace.
6028 *
6029 * Returns the attribute value or NULL if not found.
6030 * It's up to the caller to free the memory with xmlFree().
6031 */
6032xmlChar *
6033xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6034 xmlAttrPtr prop;
6035 xmlDocPtr doc;
6036
6037 if ((node == NULL) || (name == NULL)) return(NULL);
6038 /*
6039 * Check on the properties attached to the node
6040 */
6041 prop = node->properties;
6042 while (prop != NULL) {
6043 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6044 xmlChar *ret;
6045
6046 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6047 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6048 return(ret);
6049 }
6050 prop = prop->next;
6051 }
6052 if (!xmlCheckDTD) return(NULL);
6053
6054 /*
6055 * Check if there is a default declaration in the internal
6056 * or external subsets
6057 */
6058 doc = node->doc;
6059 if (doc != NULL) {
6060 xmlAttributePtr attrDecl;
6061 if (doc->intSubset != NULL) {
6062 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6063 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6064 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006065 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6066 /* return attribute declaration only if a default value is given
6067 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006068 return(xmlStrdup(attrDecl->defaultValue));
6069 }
6070 }
6071 return(NULL);
6072}
6073
6074/**
Owen Taylor3473f882001-02-23 17:55:21 +00006075 * xmlGetNsProp:
6076 * @node: the node
6077 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006078 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006079 *
6080 * Search and get the value of an attribute associated to a node
6081 * This attribute has to be anchored in the namespace specified.
6082 * This does the entity substitution.
6083 * This function looks in DTD attribute declaration for #FIXED or
6084 * default declaration values unless DTD use has been turned off.
6085 *
6086 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006087 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006088 */
6089xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006090xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006091 xmlAttrPtr prop;
6092 xmlDocPtr doc;
6093 xmlNsPtr ns;
6094
6095 if (node == NULL)
6096 return(NULL);
6097
6098 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006099 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006100 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006101 while (prop != NULL) {
6102 /*
6103 * One need to have
6104 * - same attribute names
6105 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006106 */
6107 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006108 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006109 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006110 xmlChar *ret;
6111
6112 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6113 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6114 return(ret);
6115 }
6116 prop = prop->next;
6117 }
6118 if (!xmlCheckDTD) return(NULL);
6119
6120 /*
6121 * Check if there is a default declaration in the internal
6122 * or external subsets
6123 */
6124 doc = node->doc;
6125 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006126 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006127 xmlAttributePtr attrDecl;
6128
Owen Taylor3473f882001-02-23 17:55:21 +00006129 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6130 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6131 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6132
6133 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6134 /*
6135 * The DTD declaration only allows a prefix search
6136 */
6137 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006138 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006139 return(xmlStrdup(attrDecl->defaultValue));
6140 }
6141 }
6142 }
6143 return(NULL);
6144}
6145
Daniel Veillard2156d432004-03-04 15:59:36 +00006146#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6147/**
6148 * xmlUnsetProp:
6149 * @node: the node
6150 * @name: the attribute name
6151 *
6152 * Remove an attribute carried by a node.
6153 * Returns 0 if successful, -1 if not found
6154 */
6155int
6156xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
6157 xmlAttrPtr prop, prev = NULL;;
6158
6159 if ((node == NULL) || (name == NULL))
6160 return(-1);
6161 prop = node->properties;
6162 while (prop != NULL) {
6163 if ((xmlStrEqual(prop->name, name)) &&
6164 (prop->ns == NULL)) {
6165 if (prev == NULL)
6166 node->properties = prop->next;
6167 else
6168 prev->next = prop->next;
6169 xmlFreeProp(prop);
6170 return(0);
6171 }
6172 prev = prop;
6173 prop = prop->next;
6174 }
6175 return(-1);
6176}
6177
6178/**
6179 * xmlUnsetNsProp:
6180 * @node: the node
6181 * @ns: the namespace definition
6182 * @name: the attribute name
6183 *
6184 * Remove an attribute carried by a node.
6185 * Returns 0 if successful, -1 if not found
6186 */
6187int
6188xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6189 xmlAttrPtr prop = node->properties, prev = NULL;;
6190
6191 if ((node == NULL) || (name == NULL))
6192 return(-1);
6193 if (ns == NULL)
6194 return(xmlUnsetProp(node, name));
6195 if (ns->href == NULL)
6196 return(-1);
6197 while (prop != NULL) {
6198 if ((xmlStrEqual(prop->name, name)) &&
6199 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
6200 if (prev == NULL)
6201 node->properties = prop->next;
6202 else
6203 prev->next = prop->next;
6204 xmlFreeProp(prop);
6205 return(0);
6206 }
6207 prev = prop;
6208 prop = prop->next;
6209 }
6210 return(-1);
6211}
6212#endif
6213
6214#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006215/**
6216 * xmlSetProp:
6217 * @node: the node
6218 * @name: the attribute name
6219 * @value: the attribute value
6220 *
6221 * Set (or reset) an attribute carried by a node.
6222 * Returns the attribute pointer.
6223 */
6224xmlAttrPtr
6225xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006226 xmlAttrPtr prop;
6227 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006228
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006229 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006230 return(NULL);
6231 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006232 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006233 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006234 if ((xmlStrEqual(prop->name, name)) &&
6235 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006236 xmlNodePtr oldprop = prop->children;
6237
Owen Taylor3473f882001-02-23 17:55:21 +00006238 prop->children = NULL;
6239 prop->last = NULL;
6240 if (value != NULL) {
6241 xmlChar *buffer;
6242 xmlNodePtr tmp;
6243
6244 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6245 prop->children = xmlStringGetNodeList(node->doc, buffer);
6246 prop->last = NULL;
6247 prop->doc = doc;
6248 tmp = prop->children;
6249 while (tmp != NULL) {
6250 tmp->parent = (xmlNodePtr) prop;
6251 tmp->doc = doc;
6252 if (tmp->next == NULL)
6253 prop->last = tmp;
6254 tmp = tmp->next;
6255 }
6256 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006257 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006258 if (oldprop != NULL)
6259 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006260 return(prop);
6261 }
6262 prop = prop->next;
6263 }
6264 prop = xmlNewProp(node, name, value);
6265 return(prop);
6266}
6267
6268/**
6269 * xmlSetNsProp:
6270 * @node: the node
6271 * @ns: the namespace definition
6272 * @name: the attribute name
6273 * @value: the attribute value
6274 *
6275 * Set (or reset) an attribute carried by a node.
6276 * The ns structure must be in scope, this is not checked.
6277 *
6278 * Returns the attribute pointer.
6279 */
6280xmlAttrPtr
6281xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6282 const xmlChar *value) {
6283 xmlAttrPtr prop;
6284
6285 if ((node == NULL) || (name == NULL))
6286 return(NULL);
6287
6288 if (ns == NULL)
6289 return(xmlSetProp(node, name, value));
6290 if (ns->href == NULL)
6291 return(NULL);
6292 prop = node->properties;
6293
6294 while (prop != NULL) {
6295 /*
6296 * One need to have
6297 * - same attribute names
6298 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006299 */
6300 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006301 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006302 if (prop->children != NULL)
6303 xmlFreeNodeList(prop->children);
6304 prop->children = NULL;
6305 prop->last = NULL;
6306 prop->ns = ns;
6307 if (value != NULL) {
6308 xmlChar *buffer;
6309 xmlNodePtr tmp;
6310
6311 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6312 prop->children = xmlStringGetNodeList(node->doc, buffer);
6313 prop->last = NULL;
6314 tmp = prop->children;
6315 while (tmp != NULL) {
6316 tmp->parent = (xmlNodePtr) prop;
6317 if (tmp->next == NULL)
6318 prop->last = tmp;
6319 tmp = tmp->next;
6320 }
6321 xmlFree(buffer);
6322 }
6323 return(prop);
6324 }
6325 prop = prop->next;
6326 }
6327 prop = xmlNewNsProp(node, ns, name, value);
6328 return(prop);
6329}
6330
Daniel Veillard652327a2003-09-29 18:02:38 +00006331#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006332
6333/**
Owen Taylor3473f882001-02-23 17:55:21 +00006334 * xmlNodeIsText:
6335 * @node: the node
6336 *
6337 * Is this node a Text node ?
6338 * Returns 1 yes, 0 no
6339 */
6340int
6341xmlNodeIsText(xmlNodePtr node) {
6342 if (node == NULL) return(0);
6343
6344 if (node->type == XML_TEXT_NODE) return(1);
6345 return(0);
6346}
6347
6348/**
6349 * xmlIsBlankNode:
6350 * @node: the node
6351 *
6352 * Checks whether this node is an empty or whitespace only
6353 * (and possibly ignorable) text-node.
6354 *
6355 * Returns 1 yes, 0 no
6356 */
6357int
6358xmlIsBlankNode(xmlNodePtr node) {
6359 const xmlChar *cur;
6360 if (node == NULL) return(0);
6361
Daniel Veillard7db37732001-07-12 01:20:08 +00006362 if ((node->type != XML_TEXT_NODE) &&
6363 (node->type != XML_CDATA_SECTION_NODE))
6364 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006365 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006366 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006367 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006368 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006369 cur++;
6370 }
6371
6372 return(1);
6373}
6374
6375/**
6376 * xmlTextConcat:
6377 * @node: the node
6378 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006379 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006380 *
6381 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006382 *
6383 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006384 */
6385
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006386int
Owen Taylor3473f882001-02-23 17:55:21 +00006387xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006388 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006389
6390 if ((node->type != XML_TEXT_NODE) &&
6391 (node->type != XML_CDATA_SECTION_NODE)) {
6392#ifdef DEBUG_TREE
6393 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006394 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006395#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006396 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006397 }
William M. Brack7762bb12004-01-04 14:49:01 +00006398 /* need to check if content is currently in the dictionary */
6399 if ((node->doc != NULL) && (node->doc->dict != NULL) &&
6400 xmlDictOwns(node->doc->dict, node->content)) {
6401 node->content = xmlStrncatNew(node->content, content, len);
6402 } else {
6403 node->content = xmlStrncat(node->content, content, len);
6404 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006405 if (node->content == NULL)
6406 return(-1);
6407 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006408}
6409
6410/************************************************************************
6411 * *
6412 * Output : to a FILE or in memory *
6413 * *
6414 ************************************************************************/
6415
Owen Taylor3473f882001-02-23 17:55:21 +00006416/**
6417 * xmlBufferCreate:
6418 *
6419 * routine to create an XML buffer.
6420 * returns the new structure.
6421 */
6422xmlBufferPtr
6423xmlBufferCreate(void) {
6424 xmlBufferPtr ret;
6425
6426 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6427 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006428 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006429 return(NULL);
6430 }
6431 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006432 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006433 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006434 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006435 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006436 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006437 xmlFree(ret);
6438 return(NULL);
6439 }
6440 ret->content[0] = 0;
6441 return(ret);
6442}
6443
6444/**
6445 * xmlBufferCreateSize:
6446 * @size: initial size of buffer
6447 *
6448 * routine to create an XML buffer.
6449 * returns the new structure.
6450 */
6451xmlBufferPtr
6452xmlBufferCreateSize(size_t size) {
6453 xmlBufferPtr ret;
6454
6455 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6456 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006457 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006458 return(NULL);
6459 }
6460 ret->use = 0;
6461 ret->alloc = xmlBufferAllocScheme;
6462 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6463 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006464 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006465 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006466 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006467 xmlFree(ret);
6468 return(NULL);
6469 }
6470 ret->content[0] = 0;
6471 } else
6472 ret->content = NULL;
6473 return(ret);
6474}
6475
6476/**
Daniel Veillard53350552003-09-18 13:35:51 +00006477 * xmlBufferCreateStatic:
6478 * @mem: the memory area
6479 * @size: the size in byte
6480 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006481 * routine to create an XML buffer from an immutable memory area.
6482 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006483 * present until the end of the buffer lifetime.
6484 *
6485 * returns the new structure.
6486 */
6487xmlBufferPtr
6488xmlBufferCreateStatic(void *mem, size_t size) {
6489 xmlBufferPtr ret;
6490
6491 if ((mem == NULL) || (size == 0))
6492 return(NULL);
6493
6494 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6495 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006496 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006497 return(NULL);
6498 }
6499 ret->use = size;
6500 ret->size = size;
6501 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6502 ret->content = (xmlChar *) mem;
6503 return(ret);
6504}
6505
6506/**
Owen Taylor3473f882001-02-23 17:55:21 +00006507 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006508 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006509 * @scheme: allocation scheme to use
6510 *
6511 * Sets the allocation scheme for this buffer
6512 */
6513void
6514xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6515 xmlBufferAllocationScheme scheme) {
6516 if (buf == NULL) {
6517#ifdef DEBUG_BUFFER
6518 xmlGenericError(xmlGenericErrorContext,
6519 "xmlBufferSetAllocationScheme: buf == NULL\n");
6520#endif
6521 return;
6522 }
Daniel Veillard53350552003-09-18 13:35:51 +00006523 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006524
6525 buf->alloc = scheme;
6526}
6527
6528/**
6529 * xmlBufferFree:
6530 * @buf: the buffer to free
6531 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006532 * Frees an XML buffer. It frees both the content and the structure which
6533 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006534 */
6535void
6536xmlBufferFree(xmlBufferPtr buf) {
6537 if (buf == NULL) {
6538#ifdef DEBUG_BUFFER
6539 xmlGenericError(xmlGenericErrorContext,
6540 "xmlBufferFree: buf == NULL\n");
6541#endif
6542 return;
6543 }
Daniel Veillard53350552003-09-18 13:35:51 +00006544
6545 if ((buf->content != NULL) &&
6546 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006547 xmlFree(buf->content);
6548 }
Owen Taylor3473f882001-02-23 17:55:21 +00006549 xmlFree(buf);
6550}
6551
6552/**
6553 * xmlBufferEmpty:
6554 * @buf: the buffer
6555 *
6556 * empty a buffer.
6557 */
6558void
6559xmlBufferEmpty(xmlBufferPtr buf) {
6560 if (buf->content == NULL) return;
6561 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006562 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006563 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006564 } else {
6565 memset(buf->content, 0, buf->size);
6566 }
Owen Taylor3473f882001-02-23 17:55:21 +00006567}
6568
6569/**
6570 * xmlBufferShrink:
6571 * @buf: the buffer to dump
6572 * @len: the number of xmlChar to remove
6573 *
6574 * Remove the beginning of an XML buffer.
6575 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006576 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006577 */
6578int
6579xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6580 if (len == 0) return(0);
6581 if (len > buf->use) return(-1);
6582
6583 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006584 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6585 buf->content += len;
6586 } else {
6587 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6588 buf->content[buf->use] = 0;
6589 }
Owen Taylor3473f882001-02-23 17:55:21 +00006590 return(len);
6591}
6592
6593/**
6594 * xmlBufferGrow:
6595 * @buf: the buffer
6596 * @len: the minimum free size to allocate
6597 *
6598 * Grow the available space of an XML buffer.
6599 *
6600 * Returns the new available space or -1 in case of error
6601 */
6602int
6603xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6604 int size;
6605 xmlChar *newbuf;
6606
Daniel Veillard53350552003-09-18 13:35:51 +00006607 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006608 if (len + buf->use < buf->size) return(0);
6609
6610 size = buf->use + len + 100;
6611
6612 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006613 if (newbuf == NULL) {
6614 xmlTreeErrMemory("growing buffer");
6615 return(-1);
6616 }
Owen Taylor3473f882001-02-23 17:55:21 +00006617 buf->content = newbuf;
6618 buf->size = size;
6619 return(buf->size - buf->use);
6620}
6621
6622/**
6623 * xmlBufferDump:
6624 * @file: the file output
6625 * @buf: the buffer to dump
6626 *
6627 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006628 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006629 */
6630int
6631xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6632 int ret;
6633
6634 if (buf == NULL) {
6635#ifdef DEBUG_BUFFER
6636 xmlGenericError(xmlGenericErrorContext,
6637 "xmlBufferDump: buf == NULL\n");
6638#endif
6639 return(0);
6640 }
6641 if (buf->content == NULL) {
6642#ifdef DEBUG_BUFFER
6643 xmlGenericError(xmlGenericErrorContext,
6644 "xmlBufferDump: buf->content == NULL\n");
6645#endif
6646 return(0);
6647 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006648 if (file == NULL)
6649 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006650 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6651 return(ret);
6652}
6653
6654/**
6655 * xmlBufferContent:
6656 * @buf: the buffer
6657 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006658 * Function to extract the content of a buffer
6659 *
Owen Taylor3473f882001-02-23 17:55:21 +00006660 * Returns the internal content
6661 */
6662
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006663const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006664xmlBufferContent(const xmlBufferPtr buf)
6665{
6666 if(!buf)
6667 return NULL;
6668
6669 return buf->content;
6670}
6671
6672/**
6673 * xmlBufferLength:
6674 * @buf: the buffer
6675 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006676 * Function to get the length of a buffer
6677 *
Owen Taylor3473f882001-02-23 17:55:21 +00006678 * Returns the length of data in the internal content
6679 */
6680
6681int
6682xmlBufferLength(const xmlBufferPtr buf)
6683{
6684 if(!buf)
6685 return 0;
6686
6687 return buf->use;
6688}
6689
6690/**
6691 * xmlBufferResize:
6692 * @buf: the buffer to resize
6693 * @size: the desired size
6694 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006695 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006696 *
6697 * Returns 0 in case of problems, 1 otherwise
6698 */
6699int
6700xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6701{
6702 unsigned int newSize;
6703 xmlChar* rebuf = NULL;
6704
Daniel Veillard53350552003-09-18 13:35:51 +00006705 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6706
Owen Taylor3473f882001-02-23 17:55:21 +00006707 /* Don't resize if we don't have to */
6708 if (size < buf->size)
6709 return 1;
6710
6711 /* figure out new size */
6712 switch (buf->alloc){
6713 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillardbf629492004-04-20 22:20:59 +00006714 /*take care of empty case*/
6715 newSize = (buf->size ? buf->size*2 : size + 10);
Owen Taylor3473f882001-02-23 17:55:21 +00006716 while (size > newSize) newSize *= 2;
6717 break;
6718 case XML_BUFFER_ALLOC_EXACT:
6719 newSize = size+10;
6720 break;
6721 default:
6722 newSize = size+10;
6723 break;
6724 }
6725
6726 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006727 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006728 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006729 rebuf = (xmlChar *) xmlRealloc(buf->content,
6730 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006731 } else {
6732 /*
6733 * if we are reallocating a buffer far from being full, it's
6734 * better to make a new allocation and copy only the used range
6735 * and free the old one.
6736 */
6737 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6738 if (rebuf != NULL) {
6739 memcpy(rebuf, buf->content, buf->use);
6740 xmlFree(buf->content);
6741 }
Daniel Veillarde5984082003-08-19 22:21:13 +00006742 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006743 }
Owen Taylor3473f882001-02-23 17:55:21 +00006744 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006745 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006746 return 0;
6747 }
6748 buf->content = rebuf;
6749 buf->size = newSize;
6750
6751 return 1;
6752}
6753
6754/**
6755 * xmlBufferAdd:
6756 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006757 * @str: the #xmlChar string
6758 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006759 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006760 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006761 * str is recomputed.
6762 */
6763void
6764xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6765 unsigned int needSize;
6766
6767 if (str == NULL) {
6768#ifdef DEBUG_BUFFER
6769 xmlGenericError(xmlGenericErrorContext,
6770 "xmlBufferAdd: str == NULL\n");
6771#endif
6772 return;
6773 }
Daniel Veillard53350552003-09-18 13:35:51 +00006774 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006775 if (len < -1) {
6776#ifdef DEBUG_BUFFER
6777 xmlGenericError(xmlGenericErrorContext,
6778 "xmlBufferAdd: len < 0\n");
6779#endif
6780 return;
6781 }
6782 if (len == 0) return;
6783
6784 if (len < 0)
6785 len = xmlStrlen(str);
6786
6787 if (len <= 0) return;
6788
6789 needSize = buf->use + len + 2;
6790 if (needSize > buf->size){
6791 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006792 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006793 return;
6794 }
6795 }
6796
6797 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6798 buf->use += len;
6799 buf->content[buf->use] = 0;
6800}
6801
6802/**
6803 * xmlBufferAddHead:
6804 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006805 * @str: the #xmlChar string
6806 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006807 *
6808 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006809 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00006810 */
6811void
6812xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6813 unsigned int needSize;
6814
Daniel Veillard53350552003-09-18 13:35:51 +00006815 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006816 if (str == NULL) {
6817#ifdef DEBUG_BUFFER
6818 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006819 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006820#endif
6821 return;
6822 }
6823 if (len < -1) {
6824#ifdef DEBUG_BUFFER
6825 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006826 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006827#endif
6828 return;
6829 }
6830 if (len == 0) return;
6831
6832 if (len < 0)
6833 len = xmlStrlen(str);
6834
6835 if (len <= 0) return;
6836
6837 needSize = buf->use + len + 2;
6838 if (needSize > buf->size){
6839 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006840 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006841 return;
6842 }
6843 }
6844
6845 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6846 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6847 buf->use += len;
6848 buf->content[buf->use] = 0;
6849}
6850
6851/**
6852 * xmlBufferCat:
6853 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006854 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006855 *
6856 * Append a zero terminated string to an XML buffer.
6857 */
6858void
6859xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillard53350552003-09-18 13:35:51 +00006860 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006861 if (str != NULL)
6862 xmlBufferAdd(buf, str, -1);
6863}
6864
6865/**
6866 * xmlBufferCCat:
6867 * @buf: the buffer to dump
6868 * @str: the C char string
6869 *
6870 * Append a zero terminated C string to an XML buffer.
6871 */
6872void
6873xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6874 const char *cur;
6875
Daniel Veillard53350552003-09-18 13:35:51 +00006876 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006877 if (str == NULL) {
6878#ifdef DEBUG_BUFFER
6879 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006880 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006881#endif
6882 return;
6883 }
6884 for (cur = str;*cur != 0;cur++) {
6885 if (buf->use + 10 >= buf->size) {
6886 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006887 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006888 return;
6889 }
6890 }
6891 buf->content[buf->use++] = *cur;
6892 }
6893 buf->content[buf->use] = 0;
6894}
6895
6896/**
6897 * xmlBufferWriteCHAR:
6898 * @buf: the XML buffer
6899 * @string: the string to add
6900 *
6901 * routine which manages and grows an output buffer. This one adds
6902 * xmlChars at the end of the buffer.
6903 */
6904void
Daniel Veillard53350552003-09-18 13:35:51 +00006905xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
6906 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006907 xmlBufferCat(buf, string);
6908}
6909
6910/**
6911 * xmlBufferWriteChar:
6912 * @buf: the XML buffer output
6913 * @string: the string to add
6914 *
6915 * routine which manage and grows an output buffer. This one add
6916 * C chars at the end of the array.
6917 */
6918void
6919xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillard53350552003-09-18 13:35:51 +00006920 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006921 xmlBufferCCat(buf, string);
6922}
6923
6924
6925/**
6926 * xmlBufferWriteQuotedString:
6927 * @buf: the XML buffer output
6928 * @string: the string to add
6929 *
6930 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006931 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006932 * quote or double-quotes internally
6933 */
6934void
6935xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00006936 const xmlChar *cur, *base;
Daniel Veillard53350552003-09-18 13:35:51 +00006937 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00006938 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00006939 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00006940#ifdef DEBUG_BUFFER
6941 xmlGenericError(xmlGenericErrorContext,
6942 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6943#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00006944 xmlBufferCCat(buf, "\"");
6945 base = cur = string;
6946 while(*cur != 0){
6947 if(*cur == '"'){
6948 if (base != cur)
6949 xmlBufferAdd(buf, base, cur - base);
6950 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6951 cur++;
6952 base = cur;
6953 }
6954 else {
6955 cur++;
6956 }
6957 }
6958 if (base != cur)
6959 xmlBufferAdd(buf, base, cur - base);
6960 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006961 }
Daniel Veillard39057f42003-08-04 01:33:43 +00006962 else{
6963 xmlBufferCCat(buf, "\'");
6964 xmlBufferCat(buf, string);
6965 xmlBufferCCat(buf, "\'");
6966 }
Owen Taylor3473f882001-02-23 17:55:21 +00006967 } else {
6968 xmlBufferCCat(buf, "\"");
6969 xmlBufferCat(buf, string);
6970 xmlBufferCCat(buf, "\"");
6971 }
6972}
6973
6974
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00006975/**
6976 * xmlGetDocCompressMode:
6977 * @doc: the document
6978 *
6979 * get the compression ratio for a document, ZLIB based
6980 * Returns 0 (uncompressed) to 9 (max compression)
6981 */
6982int
6983xmlGetDocCompressMode (xmlDocPtr doc) {
6984 if (doc == NULL) return(-1);
6985 return(doc->compression);
6986}
6987
6988/**
6989 * xmlSetDocCompressMode:
6990 * @doc: the document
6991 * @mode: the compression ratio
6992 *
6993 * set the compression ratio for a document, ZLIB based
6994 * Correct values: 0 (uncompressed) to 9 (max compression)
6995 */
6996void
6997xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6998 if (doc == NULL) return;
6999 if (mode < 0) doc->compression = 0;
7000 else if (mode > 9) doc->compression = 9;
7001 else doc->compression = mode;
7002}
7003
7004/**
7005 * xmlGetCompressMode:
7006 *
7007 * get the default compression mode used, ZLIB based.
7008 * Returns 0 (uncompressed) to 9 (max compression)
7009 */
7010int
7011xmlGetCompressMode(void)
7012{
7013 return (xmlCompressMode);
7014}
7015
7016/**
7017 * xmlSetCompressMode:
7018 * @mode: the compression ratio
7019 *
7020 * set the default compression mode used, ZLIB based
7021 * Correct values: 0 (uncompressed) to 9 (max compression)
7022 */
7023void
7024xmlSetCompressMode(int mode) {
7025 if (mode < 0) xmlCompressMode = 0;
7026 else if (mode > 9) xmlCompressMode = 9;
7027 else xmlCompressMode = mode;
7028}
7029